Exemple #1
0
class StateDataset:
    def __init__(self, db, state_root):
        self.db = db
        if isinstance(state_root, str):
            self.state_root = decode_hex(state_root)
        else:
            self.state_root = state_root

        try:
            self.trie = Trie(db, self.state_root)
            self.is_in_db = True
        except KeyError:
            self.state_root = None
            self.is_in_db = False
            logging.warning('State root %s not in database', self.state_root)

        logging.info('State created')

    def to_dict(self):
        state_dict = dict()
        for k in self.trie:
            try:
                acc = Account.from_trie(self.db, k, self.trie[k])
            except KeyError:
                logging.error('value in trie for %s not found', k)
            state_dict[acc.address] = (acc.nonce, acc.balance, acc.storage_root, acc.contract_code,
                                       acc.is_address_in_db)
        return state_dict

    def to_panda_dataframe(self):
        trie_dict = self.trie.to_dict()
        size = len(trie_dict)
        dtype = [('sha3_account', np.str, ACCOUNT_LENGTH), ('account', np.str, ACCOUNT_LENGTH), ('nonce', np.float),
                 ('balance', np.float),
                 ('is_contract', np.bool), ('code_size', np.float), ('storage_size', np.float), ('key_in_db', np.bool)]
        arr = np.zeros(size, dtype=dtype)
        i = 0
        for k in self.trie:
            try:
                account = Account.from_trie(self.db, k, self.trie[k])
            except KeyError:
                logging.error('value in trie for %s not found', k)
                continue
            arr[i] = (encode_hex(k), account.address, account.nonce, account.balance, account.is_contract,
                      account.code_size(self.db), account.storage_size(self.db), account.is_address_in_db)
            i += 1
        df = pd.DataFrame.from_records(arr, index='sha3_account')

        return df

    def get_account(self, address):
        key = utils.sha3(to_canonical_address(address))
        try:
            rlp_data = self.trie.get(key)
            acc = Account.from_trie(self.db, key, rlp_data)
        except KeyError:
            acc = Account.notFound(address)
        return acc
Exemple #2
0
    def __init__(self, db, root):
        """

        :param db:
        :param root:
        """
        self.db = db
        self.trie = Trie(self.db, root)
        self.secure_trie = SecureTrie(self.trie)
        self.journal = []
        self.cache = {}
Exemple #3
0
    def __init__(self, db, state_root):
        self.db = db
        if isinstance(state_root, str):
            self.state_root = decode_hex(state_root)
        else:
            self.state_root = state_root

        try:
            self.trie = Trie(db, self.state_root)
            self.is_in_db = True
        except KeyError:
            self.state_root = None
            self.is_in_db = False
            logging.warning('State root %s not in database', self.state_root)

        logging.info('State created')
Exemple #4
0
 def __init__(self, root=b'', env=Env(), **kwargs):
     self.env = env
     self.trie = SecureTrie(Trie(self.db, root))
     for k, v in STATE_DEFAULTS.items():
         setattr(self, k, kwargs.get(k, copy.copy(v)))
     self.journal = []
     self.cache = {}
     self.log_listeners = []
Exemple #5
0
    def storage_size(self, db):
        size = 0

        if self.is_contract:
            try:
                storage_trie = Trie(db, decode_hex(self.storage_root))
            except KeyError:
                logging.warning('storage root %s not in database', self.storage_root)
                return size

            try:
                trie_dict = storage_trie.to_dict()
            except KeyError:
                logging.warning('storage root %s integrity error in database', self.storage_root)
                return size

            size = len(trie_dict)

        return size
 def __init__(self, root=b'', env=Env(), executing_on_head=False, **kwargs):
     self.env = env
     self.trie = SecureTrie(Trie(RefcountDB(self.db), root))
     for k, v in STATE_DEFAULTS.items():
         setattr(self, k, kwargs.get(k, copy.copy(v)))
     self.journal = []
     self.cache = {}
     self.log_listeners = []
     self.deletes = []
     self.changed = {}
     self.executing_on_head = executing_on_head
Exemple #7
0
 def __init__(self, nonce, balance, storage, code_hash, db, address):
     self.db = db
     self.address = address
     super(Account, self).__init__(nonce, balance, storage, code_hash)
     self.storage_cache = {}
     self.storage_trie = SecureTrie(Trie(self.db))
     self.storage_trie.root_hash = self.storage
     self.touched = False
     self.existent_at_start = True
     self._mutable = True
     self.deleted = False
Exemple #8
0
 def __init__(self, nonce, balance, storage, code_hash, env):
     assert isinstance(env.db, BaseDB)
     self.env = env
     super(Account, self).__init__(nonce, balance, storage, code_hash)
     self.storage_cache = {}
     self.storage_trie = SecureTrie(Trie(self.env.db))
     self.storage_trie.root_hash = self.storage
     self.touched = False
     self.existent_at_start = True
     self._mutable = True
     self.deleted = False
Exemple #9
0
class State:
    """adjusted state from ethereum.state."""
    def __init__(self, db, root):
        """

        :param db:
        :param root:
        """
        self.db = db
        self.trie = Trie(self.db, root)
        self.secure_trie = SecureTrie(self.trie)
        self.journal = []
        self.cache = {}

    def get_and_cache_account(self, addr):
        """Gets and caches an account for an addres, creates blank if not
        found.

        :param addr:
        :return:
        """

        if addr in self.cache:
            return self.cache[addr]
        rlpdata = self.secure_trie.get(addr)
        if (rlpdata == trie.BLANK_NODE
                and len(addr) == 32):  # support for hashed addresses
            rlpdata = self.trie.get(addr)

        if rlpdata != trie.BLANK_NODE:
            o = rlp.decode(rlpdata, Account, db=self.db, address=addr)
        else:
            o = Account.blank_account(self.db, addr, 0)
        self.cache[addr] = o
        o._mutable = True
        o._cached_rlp = None
        return o

    def get_all_accounts(self):
        """iterates through trie to and yields non-blank leafs as accounts."""
        for address_hash, rlpdata in self.secure_trie.trie.iter_branch():
            if rlpdata != trie.BLANK_NODE:
                yield rlp.decode(rlpdata,
                                 Account,
                                 db=self.db,
                                 address=address_hash)
    def __init__(self, nonce, balance, storage, code_hash, env, address):
        assert isinstance(env.db, BaseDB)
        self.env = env
        self.address = address

        acc = _Account(nonce, balance, storage, code_hash)
        self.nonce = acc.nonce
        self.balance = acc.balance
        self.storage = acc.storage
        self.code_hash = acc.code_hash

        self.storage_cache = {}
        self.storage_trie = SecureTrie(Trie(RefcountDB(self.env.db)))
        self.storage_trie.root_hash = self.storage
        self.touched = False
        self.existent_at_start = True
        self._mutable = True
        self.deleted = False
Exemple #11
0
class State():
    '''
    adjusted state from ethereum.state
    '''
    def __init__(self, db, root):
        self.db = db
        self.trie = Trie(self.db, root)
        self.secureTrie = SecureTrie(self.trie)
        self.journal = []
        self.cache = {}

    def get_and_cache_account(self, address):
        '''
        gets and caches an account for an addres, creates blank if not found
        '''
        if address in self.cache:
            return self.cache[address]
        rlpdata = self.secureTrie.get(address)
        if rlpdata == trie.BLANK_NODE and len(
                address) == 32:  # support for hashed addresses
            rlpdata = self.trie.get(address)
        if rlpdata != trie.BLANK_NODE:
            o = rlp.decode(rlpdata, Account, db=self.db, address=address)
        else:
            o = Account.blank_account(self.db, address, 0)
        self.cache[address] = o
        o._mutable = True
        o._cached_rlp = None
        return o

    def get_all_accounts(self):
        '''
        iterates through trie to get all items
        '''
        accounts = []
        for addressHash, rlpdata in self.secureTrie.trie.to_dict().items():
            if rlpdata != trie.BLANK_NODE:
                accounts.append(
                    rlp.decode(rlpdata,
                               Account,
                               db=self.db,
                               address=addressHash))
        return accounts
Exemple #12
0
 def __init__(self, db, root):
     self.db = db
     self.trie = Trie(self.db, root)
     self.secure_trie = SecureTrie(self.trie)
     self.journal = []
     self.cache = {}
Exemple #13
0
 def receipts_root(self, value):
     self.receipts = Trie(self.db, value)
Exemple #14
0
 def tx_list_root(self, value):
     self.transactions = Trie(self.db, value)
Exemple #15
0
    def __init__(self, header, transaction_list=[], uncles=[], db=None,
                 parent=None, making=False):
        if db is None:
            raise TypeError("No database object given")
        self.db = db
        self.header = header
        self.uncles = uncles

        self.uncles = uncles
        self.suicides = []
        self.logs = []
        self.log_listeners = []
        self.refunds = 0

        self.ether_delta = 0

        # Journaling cache for state tree updates
        self.caches = {
            'balance': {},
            'nonce': {},
            'code': {},
            'storage': {},
            'all': {}
        }
        self.journal = []

        if self.number > 0:
            self.ancestor_hashes = [self.prevhash]
        else:
            self.ancestor_hashes = [None] * 256

        # do some consistency checks on parent if given
        if parent:
            if hasattr(parent, 'db') and self.db != parent.db:
                raise ValueError("Parent lives in different database")
            if self.prevhash != parent.header.hash:
                raise ValueError("Block's prevhash and parent's hash do not match")
            if self.number != parent.header.number + 1:
                raise ValueError("Block's number is not the successor of its parent number")
            if not check_gaslimit(parent, self.gas_limit):
                raise ValueError("Block's gaslimit is inconsistent with its parent's gaslimit")
            if self.difficulty != calc_difficulty(parent, self.timestamp):
                raise ValueError("Block's difficulty is inconsistent with its parent's difficulty")

        for uncle in uncles:
            assert isinstance(uncle, BlockHeader)

        original_values = {
            'gas_used': header.gas_used,
            'timestamp': header.timestamp,
            'difficulty': header.difficulty,
            'uncles_hash': header.uncles_hash,
            'bloom': header.bloom,
        }

        self.transactions = Trie(db, trie.BLANK_ROOT)
        self.receipts = Trie(db, trie.BLANK_ROOT)
        # replay transactions if state is unknown
        state_unknown = (header.prevhash != GENESIS_PREVHASH and
                         header.state_root != trie.BLANK_ROOT and
                         (len(header.state_root) != 32 or
                          b'validated:' + self.hash not in db) and
                         not making)
        if state_unknown:
            assert transaction_list is not None
            if not parent:
                parent = self.get_parent_header()
            self.state = SecureTrie(Trie(db, parent.state_root))
            self.transaction_count = 0
            self.gas_used = 0
            # replay
            for tx in transaction_list:
                success, output = processblock.apply_transaction(self, tx)
            self.finalize()
        else:
            # trust the state root in the header
            self.state = SecureTrie(Trie(self.db, header._state_root))
            self.transaction_count = 0
            if transaction_list:
                for tx in transaction_list:
                    self.add_transaction_to_list(tx)
            if self.transactions.root_hash != header.tx_list_root:
                raise ValueError("Transaction list root hash does not match")
            # receipts trie populated by add_transaction_to_list is incorrect
            # (it doesn't know intermediate states), so reset it
            self.receipts = Trie(self.db, header.receipts_root)

        if self.number < 40000:
            assert len(self.transactions) == 0

        # checks ##############################

        def must(what, f, symb, a, b):
            if not f(a, b):
                if dump_block_on_failed_verification:
                    sys.stderr.write('%r' % self.to_dict())
                raise VerificationFailed(what, a, symb, b)

        def must_equal(what, a, b):
            return must(what, lambda x, y: x == y, "==", a, b)

        def must_ge(what, a, b):
            return must(what, lambda x, y: x >= y, ">=", a, b)

        def must_le(what, a, b):
            return must(what, lambda x, y: x <= y, "<=", a, b)

        if parent:
            must_equal('prev_hash', self.prevhash, parent.hash)
            must_ge('gas_limit', self.gas_limit,
                    parent.gas_limit * (GASLIMIT_ADJMAX_FACTOR - 1) // GASLIMIT_ADJMAX_FACTOR)
            must_le('gas_limit', self.gas_limit,
                    parent.gas_limit * (GASLIMIT_ADJMAX_FACTOR + 1) // GASLIMIT_ADJMAX_FACTOR)
        must_equal('gas_used', original_values['gas_used'], self.gas_used)
        must_equal('timestamp', self.timestamp, original_values['timestamp'])
        must_equal('difficulty', self.difficulty, original_values['difficulty'])
        must_equal('uncles_hash', utils.sha3(rlp.encode(uncles)), original_values['uncles_hash'])
        assert header.block is None
        must_equal('state_root', self.state.root_hash, header.state_root)
        must_equal('tx_list_root', self.transactions.root_hash, header.tx_list_root)
        must_equal('receipts_root', self.receipts.root_hash, header.receipts_root)
        must_equal('bloom', self.bloom, original_values['bloom'])

        # from now on, trie roots refer to block instead of header
        header.block = self

        # Basic consistency verifications
        if not self.check_fields():
            raise ValueError("Block is invalid")
        if len(self.header.extra_data) > 1024:
            raise ValueError("Extra data cannot exceed 1024 bytes")
        if self.header.coinbase == '':
            raise ValueError("Coinbase cannot be empty address")
        if not self.state.root_hash_valid():
            raise ValueError("State Merkle root of block %r not found in "
                             "database" % self)
        if (not self.is_genesis() and self.nonce and not self.header.check_pow()):
            raise ValueError("PoW check failed")
        self.db.put(b'validated:' + self.hash, '1')
Exemple #16
0
class Block(rlp.Serializable):

    """A block.

    All attributes from the block header are accessible via properties
    (i.e. ``block.prevhash`` is equivalent to ``block.header.prevhash``). It
    is ensured that no discrepancies between header and block occur.

    :param header: the block header
    :param transaction_list: a list of transactions which are replayed if the
                             state given by the header is not known. If the
                             state is known, `None` can be used instead of the
                             empty list.
    :param uncles: a list of the headers of the uncles of this block
    :param db: the database in which the block's  state, transactions and
               receipts are stored (required)
    :param parent: optional parent which if not given may have to be loaded from
                   the database for replay
    """

    fields = [
        ('header', BlockHeader),
        ('transaction_list', CountableList(Transaction)),
        ('uncles', CountableList(BlockHeader))
    ]

    def __init__(self, header, transaction_list=[], uncles=[], db=None,
                 parent=None, making=False):
        if db is None:
            raise TypeError("No database object given")
        self.db = db
        self.header = header
        self.uncles = uncles

        self.uncles = uncles
        self.suicides = []
        self.logs = []
        self.log_listeners = []
        self.refunds = 0

        self.ether_delta = 0

        # Journaling cache for state tree updates
        self.caches = {
            'balance': {},
            'nonce': {},
            'code': {},
            'storage': {},
            'all': {}
        }
        self.journal = []

        if self.number > 0:
            self.ancestor_hashes = [self.prevhash]
        else:
            self.ancestor_hashes = [None] * 256

        # do some consistency checks on parent if given
        if parent:
            if hasattr(parent, 'db') and self.db != parent.db:
                raise ValueError("Parent lives in different database")
            if self.prevhash != parent.header.hash:
                raise ValueError("Block's prevhash and parent's hash do not match")
            if self.number != parent.header.number + 1:
                raise ValueError("Block's number is not the successor of its parent number")
            if not check_gaslimit(parent, self.gas_limit):
                raise ValueError("Block's gaslimit is inconsistent with its parent's gaslimit")
            if self.difficulty != calc_difficulty(parent, self.timestamp):
                raise ValueError("Block's difficulty is inconsistent with its parent's difficulty")

        for uncle in uncles:
            assert isinstance(uncle, BlockHeader)

        original_values = {
            'gas_used': header.gas_used,
            'timestamp': header.timestamp,
            'difficulty': header.difficulty,
            'uncles_hash': header.uncles_hash,
            'bloom': header.bloom,
        }

        self.transactions = Trie(db, trie.BLANK_ROOT)
        self.receipts = Trie(db, trie.BLANK_ROOT)
        # replay transactions if state is unknown
        state_unknown = (header.prevhash != GENESIS_PREVHASH and
                         header.state_root != trie.BLANK_ROOT and
                         (len(header.state_root) != 32 or
                          b'validated:' + self.hash not in db) and
                         not making)
        if state_unknown:
            assert transaction_list is not None
            if not parent:
                parent = self.get_parent_header()
            self.state = SecureTrie(Trie(db, parent.state_root))
            self.transaction_count = 0
            self.gas_used = 0
            # replay
            for tx in transaction_list:
                success, output = processblock.apply_transaction(self, tx)
            self.finalize()
        else:
            # trust the state root in the header
            self.state = SecureTrie(Trie(self.db, header._state_root))
            self.transaction_count = 0
            if transaction_list:
                for tx in transaction_list:
                    self.add_transaction_to_list(tx)
            if self.transactions.root_hash != header.tx_list_root:
                raise ValueError("Transaction list root hash does not match")
            # receipts trie populated by add_transaction_to_list is incorrect
            # (it doesn't know intermediate states), so reset it
            self.receipts = Trie(self.db, header.receipts_root)

        if self.number < 40000:
            assert len(self.transactions) == 0

        # checks ##############################

        def must(what, f, symb, a, b):
            if not f(a, b):
                if dump_block_on_failed_verification:
                    sys.stderr.write('%r' % self.to_dict())
                raise VerificationFailed(what, a, symb, b)

        def must_equal(what, a, b):
            return must(what, lambda x, y: x == y, "==", a, b)

        def must_ge(what, a, b):
            return must(what, lambda x, y: x >= y, ">=", a, b)

        def must_le(what, a, b):
            return must(what, lambda x, y: x <= y, "<=", a, b)

        if parent:
            must_equal('prev_hash', self.prevhash, parent.hash)
            must_ge('gas_limit', self.gas_limit,
                    parent.gas_limit * (GASLIMIT_ADJMAX_FACTOR - 1) // GASLIMIT_ADJMAX_FACTOR)
            must_le('gas_limit', self.gas_limit,
                    parent.gas_limit * (GASLIMIT_ADJMAX_FACTOR + 1) // GASLIMIT_ADJMAX_FACTOR)
        must_equal('gas_used', original_values['gas_used'], self.gas_used)
        must_equal('timestamp', self.timestamp, original_values['timestamp'])
        must_equal('difficulty', self.difficulty, original_values['difficulty'])
        must_equal('uncles_hash', utils.sha3(rlp.encode(uncles)), original_values['uncles_hash'])
        assert header.block is None
        must_equal('state_root', self.state.root_hash, header.state_root)
        must_equal('tx_list_root', self.transactions.root_hash, header.tx_list_root)
        must_equal('receipts_root', self.receipts.root_hash, header.receipts_root)
        must_equal('bloom', self.bloom, original_values['bloom'])

        # from now on, trie roots refer to block instead of header
        header.block = self

        # Basic consistency verifications
        if not self.check_fields():
            raise ValueError("Block is invalid")
        if len(self.header.extra_data) > 1024:
            raise ValueError("Extra data cannot exceed 1024 bytes")
        if self.header.coinbase == '':
            raise ValueError("Coinbase cannot be empty address")
        if not self.state.root_hash_valid():
            raise ValueError("State Merkle root of block %r not found in "
                             "database" % self)
        if (not self.is_genesis() and self.nonce and not self.header.check_pow()):
            raise ValueError("PoW check failed")
        self.db.put(b'validated:' + self.hash, '1')

    @classmethod
    def init_from_header(cls, header_rlp, db):
        """Create a block without specifying transactions or uncles.

        :param header_rlp: the RLP encoded block header
        :param db: the database for the block
        """
        header = rlp.decode(header_rlp, BlockHeader, db=db)
        return cls(header, None, [], db=db)

    @classmethod
    def init_from_parent(cls, parent, coinbase, nonce=b'', extra_data=b'',
                         timestamp=int(time.time()), uncles=[]):
        """Create a new block based on a parent block.

        The block will not include any transactions and will not be finalized.
        """
        header = BlockHeader(prevhash=parent.hash,
                             uncles_hash=utils.sha3(rlp.encode(uncles)),
                             coinbase=coinbase,
                             state_root=parent.state_root,
                             tx_list_root=trie.BLANK_ROOT,
                             receipts_root=trie.BLANK_ROOT,
                             bloom=0,
                             difficulty=calc_difficulty(parent, timestamp),
                             mixhash='',
                             number=parent.number + 1,
                             gas_limit=calc_gaslimit(parent),
                             gas_used=0,
                             timestamp=timestamp,
                             extra_data=extra_data,
                             nonce=nonce)
        block = Block(header, [], uncles, db=parent.db,
                      parent=parent, making=True)
        block.ancestor_hashes = [parent.hash] + parent.ancestor_hashes
        return block

    def check_fields(self):
        """Check that the values of all fields are well formed."""
        # serialize and deserialize and check that the values didn't change
        l = Block.serialize(self)
        return rlp.decode(rlp.encode(l)) == l

    @property
    def hash(self):
        """The binary block hash

        This is equivalent to ``header.hash``.
        """
        return utils.sha3(rlp.encode(self.header))

    def hex_hash(self):
        """The hex encoded block hash.

        This is equivalent to ``header.hex_hash().
        """
        return encode_hex(self.hash)

    @property
    def tx_list_root(self):
        return self.transactions.root_hash

    @tx_list_root.setter
    def tx_list_root(self, value):
        self.transactions = Trie(self.db, value)

    @property
    def receipts_root(self):
        return self.receipts.root_hash

    @receipts_root.setter
    def receipts_root(self, value):
        self.receipts = Trie(self.db, value)

    @property
    def state_root(self):
        self.commit_state()
        return self.state.root_hash

    @state_root.setter
    def state_root(self, value):
        self.state = SecureTrie(Trie(self.db, value))
        self.reset_cache()

    @property
    def uncles_hash(self):
        return utils.sha3(rlp.encode(self.uncles))

    @property
    def transaction_list(self):
        txs = []
        for i in range(self.transaction_count):
            txs.append(self.get_transaction(i))
        return txs

    def validate_uncles(self):
        """Validate the uncles of this block."""
        if utils.sha3(rlp.encode(self.uncles)) != self.uncles_hash:
            return False
        if len(self.uncles) > MAX_UNCLES:
            return False
        for uncle in self.uncles:
            assert uncle.prevhash in self.db
            if uncle.number == self.number:
                log.error("uncle at same block height", block=self)
                return False

        # Check uncle validity
        ancestor_chain = [self] + [a for a in self.get_ancestor_list(MAX_UNCLE_DEPTH + 1) if a]
        assert len(ancestor_chain) == min(self.header.number + 1, MAX_UNCLE_DEPTH + 2)
        ineligible = []
        # Uncles of this block cannot be direct ancestors and cannot also
        # be uncles included 1-6 blocks ago
        for ancestor in ancestor_chain[1:]:
            ineligible.extend(ancestor.uncles)
        ineligible.extend([b.header for b in ancestor_chain])
        eligible_ancestor_hashes = [x.hash for x in ancestor_chain[2:]]
        for uncle in self.uncles:
            if not uncle.check_pow():
                return False
            if uncle.prevhash not in eligible_ancestor_hashes:
                log.error("Uncle does not have a valid ancestor", block=self,
                          eligible=[x.encode('hex') for x in eligible_ancestor_hashes],
                          uncle_prevhash=uncle.prevhash.encode('hex'))
                return False
            if uncle in ineligible:
                log.error("Duplicate uncle", block=self,
                          uncle=encode_hex(utils.sha3(rlp.encode(uncle))))
                return False
            ineligible.append(uncle)
        return True

    def get_ancestor_list(self, n):
        """Return `n` ancestors of this block.

        :returns: a list [p(self), p(p(self)), ..., p^n(self)]
        """
        if n == 0 or self.header.number == 0:
            return []
        p = self.get_parent()
        return [p] + p.get_ancestor_list(n-1)

    def get_ancestor_hash(self, n):
        assert n > 0
        while len(self.ancestor_hashes) < n:
            if self.number == len(self.ancestor_hashes) - 1:
                self.ancestor_hashes.append(None)
            else:
                self.ancestor_hashes.append(
                    get_block(self.db,
                              self.ancestor_hashes[-1]).get_parent().hash)
        return self.ancestor_hashes[n-1]

    def get_ancestor(self, n):
        return self.get_block(self.get_ancestor_hash(n))

    def is_genesis(self):
        """`True` if this block is the genesis block, otherwise `False`."""
        return self.header.number == 0

    def _get_acct(self, address):
        """Get the account with the given address.

        Note that this method ignores cached account items.
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20 or len(address) == 0
        rlpdata = self.state.get(address)
        if rlpdata != trie.BLANK_NODE:
            acct = rlp.decode(rlpdata, Account, db=self.db)
        else:
            acct = Account.blank_account(self.db)
        return acct

    def _get_acct_item(self, address, param):
        """Get a specific parameter of a specific account.

        :param address: the address of the account (binary or hex string)
        :param param: the requested parameter (`'nonce'`, `'balance'`,
                      `'storage'` or `'code'`)
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20 or len(address) == 0
        if address in self.caches[param]:
            return self.caches[param][address]
        else:
            account = self._get_acct(address)
            o = getattr(account, param)
            self.caches[param][address] = o
            return o

    def _set_acct_item(self, address, param, value):
        """Set a specific parameter of a specific account.

        :param address: the address of the account (binary or hex string)
        :param param: the requested parameter (`'nonce'`, `'balance'`,
                      `'storage'` or `'code'`)
        :param value: the new value
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20
        self.set_and_journal(param, address, value)
        self.set_and_journal('all', address, True)

    def set_and_journal(self, cache, index, value):
        prev = self.caches[cache].get(index, None)
        if prev != value:
            self.journal.append([cache, index, prev, value])
            self.caches[cache][index] = value

    def _delta_item(self, address, param, value):
        """Add a value to an account item.

        If the resulting value would be negative, it is left unchanged and
        `False` is returned.

        :param address: the address of the account (binary or hex string)
        :param param: the parameter to increase or decrease (`'nonce'`,
                      `'balance'`, `'storage'` or `'code'`)
        :param value: can be positive or negative
        :returns: `True` if the operation was successful, `False` if not
        """
        new_value = self._get_acct_item(address, param) + value
        if new_value < 0:
            return False
        self._set_acct_item(address, param, new_value % 2**256)
        return True

    def mk_transaction_receipt(self, tx):
        """Create a receipt for a transaction."""
        return Receipt(self.state_root, self.gas_used, self.logs)

    def add_transaction_to_list(self, tx):
        """Add a transaction to the transaction trie.

        Note that this does not execute anything, i.e. the state is not
        updated.
        """
        k = rlp.encode(self.transaction_count)
        self.transactions.update(k, rlp.encode(tx))
        r = self.mk_transaction_receipt(tx)
        self.receipts.update(k, rlp.encode(r))
        self.bloom |= r.bloom  # int
        self.transaction_count += 1

    def get_transaction(self, num):
        """Get the `num`th transaction in this block.

        :raises: :exc:`IndexError` if the transaction does not exist
        """
        index = rlp.encode(num)
        tx = self.transactions.get(index)
        if tx == trie.BLANK_NODE:
            raise IndexError('Transaction does not exist')
        else:
            return rlp.decode(tx, Transaction)

    _get_transactions_cache = None

    def get_transactions(self):
        """Build a list of all transactions in this block."""
        num = self.transaction_count
        if not self._get_transactions_cache or len(self._get_transactions_cache) != num:
            txs = []
            for i in range(num):
                txs.append(self.get_transaction(i))
            self._get_transactions_cache = txs
        return self._get_transactions_cache

    def get_transaction_hashes(self):
        "helper to check if blk contains a tx"
        return [utils.sha3(self.transactions.get(rlp.encode(i)))
                for i in range(self.transaction_count)]

    def includes_transaction(self, tx_hash):
        assert isinstance(tx_hash, bytes)
        #assert self.get_transaction_hashes() == [tx.hash for tx in self.get_transactions()]
        return tx_hash in self.get_transaction_hashes()

    def get_receipt(self, num):
        """Get the receipt of the `num`th transaction.

        :returns: an instance of :class:`Receipt`
        """
        index = rlp.encode(num)
        receipt = self.receipts.get(index)
        if receipt == trie.BLANK_NODE:
            raise IndexError('Receipt does not exist')
        else:
            return rlp.decode(receipt, Receipt)

    def get_receipts(self):
        """Build a list of all receipts in this block."""
        receipts = []
        for i in count():
            try:
                receipts.append(self.get_receipt(i))
            except IndexError:
                return receipts

    def get_nonce(self, address):
        """Get the nonce of an account.

        :param address: the address of the account (binary or hex string)
        """
        return self._get_acct_item(address, 'nonce')

    def set_nonce(self, address, value):
        """Set the nonce of an account.

        :param address: the address of the account (binary or hex string)
        :param value: the new nonce
        :returns: `True` if successful, otherwise `False`
        """
        return self._set_acct_item(address, 'nonce', value)

    def increment_nonce(self, address):
        """Increment the nonce of an account.

        :param address: the address of the account (binary or hex string)
        :returns: `True` if successful, otherwise `False`
        """
        return self._delta_item(address, 'nonce', 1)

    def decrement_nonce(self, address):
        """Decrement the nonce of an account.

        :param address: the address of the account (binary or hex string)
        :returns: `True` if successful, otherwise `False`
        """
        return self._delta_item(address, 'nonce', -1)

    def get_balance(self, address):
        """Get the balance of an account.

        :param address: the address of the account (binary or hex string)
        """
        return self._get_acct_item(address, 'balance')

    def set_balance(self, address, value):
        """Set the balance of an account.

        :param address: the address of the account (binary or hex string)
        :param value: the new balance
        :returns: `True` if successful, otherwise `False`
        """
        self._set_acct_item(address, 'balance', value)

    def delta_balance(self, address, value):
        """Increase the balance of an account.

        :param address: the address of the account (binary or hex string)
        :param value: can be positive or negative
        :returns: `True` if successful, otherwise `False`
        """
        return self._delta_item(address, 'balance', value)

    def transfer_value(self, from_addr, to_addr, value):
        """Transfer a value between two account balances.

        :param from_addr: the address of the sending account (binary or hex
                          string)
        :param to_addr: the address of the receiving account (binary or hex
                        string)
        :param value: the (positive) value to send
        :returns: `True` if successful, otherwise `False`
        """
        assert value >= 0
        if self.delta_balance(from_addr, -value):
            return self.delta_balance(to_addr, value)
        return False

    def get_code(self, address):
        """Get the code of an account.

        :param address: the address of the account (binary or hex string)
        """
        return self._get_acct_item(address, 'code')

    def set_code(self, address, value):
        """Set the code of an account.

        :param address: the address of the account (binary or hex string)
        :param value: the new code
        :returns: `True` if successful, otherwise `False`
        """
        self._set_acct_item(address, 'code', value)

    def get_storage(self, address):
        """Get the trie holding an account's storage.

        :param address: the address of the account (binary or hex string)
        :param value: the new code
        """
        storage_root = self._get_acct_item(address, 'storage')
        return SecureTrie(Trie(self.db, storage_root))

    def reset_storage(self, address):
        self._set_acct_item(address, 'storage', b'')
        CACHE_KEY = b'storage:' + address
        if CACHE_KEY in self.caches:
            for k in self.caches[CACHE_KEY]:
                self.set_and_journal(CACHE_KEY, k, 0)

    def get_storage_data(self, address, index):
        """Get a specific item in the storage of an account.

        :param address: the address of the account (binary or hex string)
        :param index: the index of the requested item in the storage
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20
        CACHE_KEY = b'storage:' + address
        if CACHE_KEY in self.caches:
            if index in self.caches[CACHE_KEY]:
                return self.caches[CACHE_KEY][index]
        key = utils.zpad(utils.coerce_to_bytes(index), 32)
        storage = self.get_storage(address).get(key)
        if storage:
            return rlp.decode(storage, big_endian_int)
        else:
            return 0

    def set_storage_data(self, address, index, value):
        """Set a specific item in the storage of an account.

        :param address: the address of the account (binary or hex string)
        :param index: the index of the item in the storage
        :param value: the new value of the item
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20
        CACHE_KEY = b'storage:' + address
        if CACHE_KEY not in self.caches:
            self.caches[CACHE_KEY] = {}
            self.set_and_journal('all', address, True)
        self.set_and_journal(CACHE_KEY, index, value)

    def account_exists(self, address):
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20
        return len(self.state.get(address)) > 0 or address in self.caches['all']

    def add_log(self, log):
        self.logs.append(log)
        for L in self.log_listeners:
            L(log)

    def commit_state(self):
        """Commit account caches"""
        """Write the acount caches on the corresponding tries."""
        changes = []
        if len(self.journal) == 0:
            # log_state.trace('delta', changes=[])
            return
        addresses = sorted(list(self.caches['all'].keys()))
        for addr in addresses:
            acct = self._get_acct(addr)

            # storage
            for field in ('balance', 'nonce', 'code', 'storage'):
                if addr in self.caches[field]:
                    v = self.caches[field][addr]
                    changes.append([field, addr, v])
                    setattr(acct, field, v)

            t = SecureTrie(Trie(self.db, acct.storage))
            for k, v in self.caches.get(b'storage:' + addr, {}).items():
                enckey = utils.zpad(utils.coerce_to_bytes(k), 32)
                val = rlp.encode(v)
                changes.append(['storage', addr, k, v])
                if v:
                    t.update(enckey, val)
                else:
                    t.delete(enckey)
            acct.storage = t.root_hash
            self.state.update(addr, rlp.encode(acct))
        log_state.trace('delta', changes=changes)
        self.reset_cache()
        self.db.put(b'validated:' + self.hash, '1')

    def del_account(self, address):
        """Delete an account.

        :param address: the address of the account (binary or hex string)
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20
        self.commit_state()
        self.state.delete(address)

    def account_to_dict(self, address, with_storage_root=False,
                        with_storage=True):
        """Serialize an account to a dictionary with human readable entries.

        :param address: the 20 bytes account address
        :param with_storage_root: include the account's storage root
        :param with_storage: include the whole account's storage
        """
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20

        if with_storage_root:
            # if there are uncommited account changes the current storage root
            # is meaningless
            assert len(self.journal) == 0
        med_dict = {}

        account = self._get_acct(address)
        for field in ('balance', 'nonce'):
            value = self.caches[field].get(address, getattr(account, field))
            med_dict[field] = to_string(value)
        code = self.caches['code'].get(address, account.code)
        med_dict['code'] = b'0x' + encode_hex(code)

        storage_trie = SecureTrie(Trie(self.db, account.storage))
        if with_storage_root:
            med_dict['storage_root'] = encode_hex(storage_trie.get_root_hash())
        if with_storage:
            med_dict['storage'] = {}
            d = storage_trie.to_dict()
            subcache = self.caches.get(b'storage:' + address, {})
            subkeys = [utils.zpad(utils.coerce_to_bytes(kk), 32)
                       for kk in list(subcache.keys())]
            for k in list(d.keys()) + subkeys:
                v = d.get(k, None)
                v2 = subcache.get(utils.big_endian_to_int(k), None)
                hexkey = b'0x' + encode_hex(utils.zunpad(k))
                if v2 is not None:
                    if v2 != 0:
                        med_dict['storage'][hexkey] = \
                            b'0x' + encode_hex(utils.int_to_big_endian(v2))
                elif v is not None:
                    med_dict['storage'][hexkey] = b'0x' + encode_hex(rlp.decode(v))

        return med_dict

    def reset_cache(self):
        """Reset cache and journal without commiting any changes."""
        self.caches = {
            'all': {},
            'balance': {},
            'nonce': {},
            'code': {},
            'storage': {},
        }
        self.journal = []

    def snapshot(self):
        """Make a snapshot of the current state to enable later reverting."""
        return {
            'state': self.state.root_hash,
            'gas': self.gas_used,
            'txs': self.transactions,
            'txcount': self.transaction_count,
            'suicides': self.suicides,
            'logs': self.logs,
            'refunds': self.refunds,
            'suicides_size': len(self.suicides),
            'logs_size': len(self.logs),
            'journal': self.journal,  # pointer to reference, so is not static
            'journal_size': len(self.journal),
            'ether_delta': self.ether_delta
        }

    def revert(self, mysnapshot):
        """Revert to a previously made snapshot.

        Reverting is for example necessary when a contract runs out of gas
        during execution.
        """
        self.journal = mysnapshot['journal']
        log_state.trace('reverting')
        while len(self.journal) > mysnapshot['journal_size']:
            cache, index, prev, post = self.journal.pop()
            log_state.trace('%r %r %r %r' % (cache, index, prev, post))
            if prev is not None:
                self.caches[cache][index] = prev
            else:
                del self.caches[cache][index]
        self.suicides = mysnapshot['suicides']
        while len(self.suicides) > mysnapshot['suicides_size']:
            self.suicides.pop()
        self.logs = mysnapshot['logs']
        while len(self.logs) > mysnapshot['logs_size']:
            self.logs.pop()
        self.refunds = mysnapshot['refunds']
        self.state.root_hash = mysnapshot['state']
        self.gas_used = mysnapshot['gas']
        self.transactions = mysnapshot['txs']
        self.transaction_count = mysnapshot['txcount']
        self._get_transactions_cache = None
        self.ether_delta = mysnapshot['ether_delta']

    def finalize(self):
        """Apply rewards and commit."""
        delta = int(BLOCK_REWARD + NEPHEW_REWARD * len(self.uncles))
        self.delta_balance(self.coinbase, delta)
        self.ether_delta += delta

        for uncle in self.uncles:
            r = BLOCK_REWARD * \
                (UNCLE_DEPTH_PENALTY_FACTOR + uncle.number - self.number) \
                / UNCLE_DEPTH_PENALTY_FACTOR
            r = int(r)
            self.delta_balance(uncle.coinbase, r)
            self.ether_delta += r
        self.commit_state()

    def to_dict(self, with_state=False, full_transactions=False,
                with_storage_roots=False, with_uncles=False):
        """Serialize the block to a readable dictionary.

        :param with_state: include state for all accounts
        :param full_transactions: include serialized transactions (hashes
                                  otherwise)
        :param with_storage_roots: if account states are included also include
                                   their storage roots
        :param with_uncles: include uncle hashes
        """
        b = {"header": self.header.to_dict()}
        txlist = []
        for i, tx in enumerate(self.get_transactions()):
            receipt_rlp = self.receipts.get(rlp.encode(i))
            receipt = rlp.decode(receipt_rlp, Receipt)
            if full_transactions:
                txjson = tx.to_dict()
            else:
                txjson = tx.hash
            txlist.append({
                "tx": txjson,
                "medstate": encode_hex(receipt.state_root),
                "gas": to_string(receipt.gas_used),
                "logs": [Log.serialize(log) for log in receipt.logs],
                "bloom": utils.int256.serialize(receipt.bloom)
            })
        b["transactions"] = txlist
        if with_state:
            state_dump = {}
            for address, v in self.state.to_dict().items():
                state_dump[encode_hex(address)] = self.account_to_dict(address, with_storage_roots)
            b['state'] = state_dump
        if with_uncles:
            b['uncles'] = [self.__class__.deserialize_header(u)
                           for u in self.uncles]
        return b

    @property
    def mining_hash(self):
        return utils.sha3(rlp.encode(self.header,
                                     BlockHeader.exclude(['nonce', 'mixhash'])))

    def get_parent(self):
        """Get the parent of this block."""
        if self.number == 0:
            raise UnknownParentException('Genesis block has no parent')
        try:
            parent = get_block(self.db, self.prevhash)
        except KeyError:
            raise UnknownParentException(encode_hex(self.prevhash))
        # assert parent.state.db.db == self.state.db.db
        return parent

    def get_parent_header(self):
        """Get the parent of this block."""
        if self.number == 0:
            raise UnknownParentException('Genesis block has no parent')
        try:
            parent_header = get_block_header(self.db, self.prevhash)
        except KeyError:
            raise UnknownParentException(encode_hex(self.prevhash))
        # assert parent.state.db.db == self.state.db.db
        return parent_header

    def has_parent(self):
        """`True` if this block has a known parent, otherwise `False`."""
        try:
            self.get_parent()
            return True
        except UnknownParentException:
            return False

    def chain_difficulty(self):
        """Get the summarized difficulty.

        If the summarized difficulty is not stored in the database, it will be
        calculated recursively and put in the database.
        """
        if self.is_genesis():
            return self.difficulty
        elif b'difficulty:' + encode_hex(self.hash) in self.db:
            encoded = self.db.get(b'difficulty:' + encode_hex(self.hash))
            return utils.decode_int(encoded)
        else:
            o = self.difficulty + self.get_parent().chain_difficulty()
            # o += sum([uncle.difficulty for uncle in self.uncles])
            self.state.db.put(b'difficulty:' + encode_hex(self.hash),
                              utils.encode_int(o))
            return o

            return rlp.decode(rlp.encode(l)) == l

    def __eq__(self, other):
        """Two blocks are equal iff they have the same hash."""
        return isinstance(other, (Block, CachedBlock)) and self.hash == other.hash

    def __hash__(self):
        return utils.big_endian_to_int(self.hash)

    def __ne__(self, other):
        return not self.__eq__(other)

    def __gt__(self, other):
        return self.number > other.number

    def __lt__(self, other):
        return self.number < other.number

    def __repr__(self):
        return '<%s(#%d %s)>' % (self.__class__.__name__, self.number, encode_hex(self.hash)[:8])

    def __structlog__(self):
        return encode_hex(self.hash)