def from_genesis(cls, db, genesis_params, genesis_state=None): """ Initialize the Chain from a genesis state. """ state_db = State(db) if genesis_state is None: genesis_state = {} for account, account_data in genesis_state.items(): state_db.set_balance(account, account_data['balance']) state_db.set_nonce(account, account_data['nonce']) state_db.set_code(account, account_data['code']) for slot, value in account_data['storage'].items(): state_db.set_storage(account, slot, value) genesis_header = BlockHeader(**genesis_params) if genesis_header.state_root != state_db.root_hash: raise ValidationError( "The provided genesis state root does not match the computed " "genesis state root. Got {0}. Expected {1}".format( state_db.root_hash, genesis_header.state_root, ) ) genesis_chain = cls(db, genesis_header) persist_block_to_db(db, genesis_chain.get_block()) add_block_number_to_hash_lookup(db, genesis_chain.get_block()) return cls(db, genesis_chain.create_header_from_parent(genesis_header))
def from_genesis(cls, genesis_params, genesis_state=None): """ Initialize the EVM from a genesis state. """ if cls.db is None: raise ValueError("MetaEVM class must have a db") state_db = State(cls.db) if genesis_state is None: genesis_state = {} for account, account_data in genesis_state.items(): state_db.set_balance(account, account_data['balance']) state_db.set_nonce(account, account_data['nonce']) state_db.set_code(account, account_data['code']) for slot, value in account_data['storage']: state_db.set_storage(account, slot, value) genesis_header = BlockHeader(**genesis_params) if genesis_header.state_root != state_db.root_hash: raise ValidationError( "The provided genesis state root does not match the computed " "genesis state root. Got {0}. Expected {1}".format( state_db.root_hash, genesis_header.state_root, )) meta_evm = cls(header=genesis_header) evm = meta_evm.get_evm() persist_block_to_db(meta_evm.db, evm.block) meta_evm.header = evm.create_header_from_parent(genesis_header) return meta_evm
def from_genesis(cls, db, genesis_params, genesis_state=None): """ Initialize the EVM from a genesis state. """ state_db = State(db) if genesis_state is None: genesis_state = {} for account, account_data in genesis_state.items(): state_db.set_balance(account, account_data['balance']) state_db.set_nonce(account, account_data['nonce']) state_db.set_code(account, account_data['code']) for slot, value in account_data['storage'].items(): state_db.set_storage(account, slot, value) genesis_header = BlockHeader(**genesis_params) if genesis_header.state_root != state_db.root_hash: raise ValidationError( "The provided genesis state root does not match the computed " "genesis state root. Got {0}. Expected {1}".format( state_db.root_hash, genesis_header.state_root, )) evm = cls(db, genesis_header) persist_block_to_db(evm.db, evm.get_block()) # XXX: It doesn't feel right to overwrite evm.header here given that # it is set by EVM.__init__, which we called above. evm.header = evm.create_header_from_parent(genesis_header) return evm
def __init__(self, evm, db): if db is None: raise ValueError("VM classes must have a `db`") self.db = db self.evm = evm block_class = self.get_block_class() self.block = block_class.from_header(header=self.evm.header, db=db) self.state_db = State(db=self.db, root_hash=self.evm.header.state_root)
def __init__(self, header, db=None): if db is not None: self.db = db if self.db is None: raise ValueError("EVM classes must have a `db`") self.header = header block_class = self.get_block_class() self.block = block_class.from_header(header=self.header) self.state_db = State(db=self.db, root_hash=self.header.state_root)
def __init__(self, header, transactions=None, uncles=None, db=None): if transactions is None: transactions = [] if uncles is None: uncles = [] self.db = db if self.db is None: raise TypeError("Block must have a db") super(FrontierBlock, self).__init__( header=header, transactions=transactions, uncles=uncles, ) self.state_db = State(self.db, root_hash=self.header.state_root) self.transaction_db = Trie(self.db, root_hash=self.header.transaction_root) self.receipt_db = Trie(self.db, root_hash=self.header.receipts_root)
def block(self, value): self._block = value self.state_db = State(db=self.db, root_hash=value.header.state_root)
class VM(object): """ The VM class represents the EVM for a specific protocol definition. Defining an EVM for an ethereum network involves defining individual VM classes for each protocol fork within that network. """ db = None opcodes = None block_class = None def __init__(self, header, db): if db is None: raise ValueError("VM classes must have a `db`") self.db = db block_class = self.get_block_class() self.block = block_class.from_header(header=header, db=db) @classmethod def configure(cls, name=None, **overrides): if name is None: name = cls.__name__ for key in overrides: if not hasattr(cls, key): raise TypeError( "The VM.configure cannot set attributes that are not " "already present on the base class. The attribute `{0}` was " "not found on the base class `{1}`".format(key, cls) ) return type(name, (cls,), overrides) _block = None state_db = None @property def block(self): if self._block is None: raise AttributeError("No block property set") return self._block @block.setter def block(self, value): self._block = value self.state_db = State(db=self.db, root_hash=value.header.state_root) # # Logging # @property def logger(self): return logging.getLogger('evm.vm.base.VM.{0}'.format(self.__class__.__name__)) # # Execution # def apply_transaction(self, transaction): """ Apply the transaction to the vm in the current block. """ computation = self.execute_transaction(transaction) # NOTE: mutation self.block = self.block.add_transaction( transaction=transaction, computation=computation, ) return computation def execute_transaction(self, transaction): """ Execute the transaction in the vm. """ raise NotImplementedError("Must be implemented by subclasses") def apply_create_message(self, message): """ Execution of an VM message to create a new contract. """ raise NotImplementedError("Must be implemented by subclasses") def apply_message(self, message): """ Execution of an VM message. """ raise NotImplementedError("Must be implemented by subclasses") def apply_computation(self, message): """ Perform the computation that would be triggered by the VM message. """ raise NotImplementedError("Must be implemented by subclasses") # # Mining # def get_block_reward(self, block_number): return BLOCK_REWARD def get_nephew_reward(self, block_number): return NEPHEW_REWARD def import_block(self, block): self.configure_header( coinbase=block.header.coinbase, gas_limit=block.header.gas_limit, timestamp=block.header.timestamp, extra_data=block.header.extra_data, mix_hash=block.header.mix_hash, nonce=block.header.nonce, ) for transaction in block.transactions: self.apply_transaction(transaction) for uncle in block.uncles: self.block.add_uncle(uncle) mined_block = self.mine_block() if mined_block != block: diff = diff_rlp_object(mined_block, block) longest_field_name = max(len(field_name) for field_name, _, _ in diff) error_message = ( "Mismatch between block and imported block on {0} fields:\n - {1}".format( len(diff), "\n - ".join(tuple( "{0}:\n (actual) : {1}\n (expected): {2}".format( pad_right(field_name, longest_field_name, ' '), actual, expected, ) for field_name, actual, expected in diff )), ) ) raise ValidationError(error_message) return mined_block def mine_block(self, *args, **kwargs): """ Mine the current block. """ block = self.block block.mine(*args, **kwargs) if block.number > 0: block_reward = self.get_block_reward(block.number) + ( len(block.uncles) * self.get_nephew_reward(block.number) ) self.state_db.delta_balance(block.header.coinbase, block_reward) self.logger.debug( "BLOCK REWARD: %s -> %s", block_reward, block.header.coinbase, ) for uncle in block.uncles: uncle_reward = BLOCK_REWARD * ( UNCLE_DEPTH_PENALTY_FACTOR + uncle.block_number - block.number ) // UNCLE_DEPTH_PENALTY_FACTOR self.state_db.delta_balance(uncle.coinbase, uncle_reward) self.logger.debug( "UNCLE REWARD REWARD: %s -> %s", uncle_reward, uncle.coinbase, ) self.logger.debug('BEFORE ROOT: %s', block.header.state_root) block.header.state_root = self.state_db.root_hash self.logger.debug('STATE_ROOT: %s', block.header.state_root) return block # # Transactions # def get_transaction_class(self): """ Return the class that this VM uses for transactions. """ return self.get_block_class().get_transaction_class() def create_transaction(self, *args, **kwargs): """ Proxy for instantiating a transaction for this VM. """ return self.get_transaction_class()(*args, **kwargs) def create_unsigned_transaction(self, *args, **kwargs): """ Proxy for instantiating a transaction for this VM. """ return self.get_transaction_class().create_unsigned_transaction(*args, **kwargs) def validate_transaction(self, transaction): """ Perform evm-aware validation checks on the transaction. """ raise NotImplementedError("Must be implemented by subclasses") # # Blocks # _block_class = None def get_block_class(self): """ Return the class that this VM uses for blocks. """ if self._block_class is None: raise AttributeError("No `_block_class` has been set for this VM") return self._block_class def get_block_by_header(self, block_header): return self.get_block_class().from_header(block_header, self.db) def get_block_hash(self, block_number): """ For getting block hash for any block number in the the last 256 blocks. """ ancestor_depth = self.block.number - block_number if 1 <= ancestor_depth <= 256: return lookup_block_hash(self.db, block_number) else: return b'' # # Headers # @classmethod def create_header_from_parent(cls, parent_header, **header_params): """ Creates and initializes a new block header from the provided `parent_header`. """ raise NotImplementedError("Must be implemented by subclasses") def configure_header(self, **header_params): """ Setup the current header with the provided parameters. This can be used to set fields like the gas limit or timestamp to value different than their computed defaults. """ raise NotImplementedError("Must be implemented by subclasses") # # Snapshot and Revert # def snapshot(self): """ Perform a full snapshot of the current state of the VM. TODO: This needs to do more than just snapshot the state_db but this is a start. """ return self.state_db.snapshot() def revert(self, snapshot): """ Revert the VM to the state TODO: This needs to do more than just snapshot the state_db but this is a start. """ return self.state_db.revert(snapshot) # # Opcode API # def get_opcode_fn(self, opcode): try: return self.opcodes[opcode] except KeyError: return InvalidOpcode(opcode)
class VM(object): """ The VM class represents the Chain rules for a specific protocol definition such as the Frontier or Homestead network. Defining an Chain defining individual VM classes for each fork of the protocol rules within that network. """ db = None opcodes = None _block_class = None def __init__(self, header, db): if db is None: raise ValueError("VM classes must have a `db`") self.db = db block_class = self.get_block_class() self.block = block_class.from_header(header=header, db=db) @classmethod def configure(cls, name=None, **overrides): if name is None: name = cls.__name__ for key in overrides: if not hasattr(cls, key): raise TypeError( "The VM.configure cannot set attributes that are not " "already present on the base class. The attribute `{0}` was " "not found on the base class `{1}`".format(key, cls)) return type(name, (cls, ), overrides) _block = None state_db = None @property def block(self): if self._block is None: raise AttributeError("No block property set") return self._block @block.setter def block(self, value): self._block = value self.state_db = State(db=self.db, root_hash=value.header.state_root) # # Logging # @property def logger(self): return logging.getLogger('evm.vm.base.VM.{0}'.format( self.__class__.__name__)) # # Execution # def apply_transaction(self, transaction): """ Apply the transaction to the vm in the current block. """ computation = self.execute_transaction(transaction) # NOTE: mutation. Needed in order to update self.state_db, so we should be able to get rid # of this once we fix https://github.com/pipermerriam/py-evm/issues/67 self.block = self.block.add_transaction( transaction=transaction, computation=computation, ) return computation def execute_transaction(self, transaction): """ Execute the transaction in the vm. """ raise NotImplementedError("Must be implemented by subclasses") def apply_create_message(self, message): """ Execution of an VM message to create a new contract. """ raise NotImplementedError("Must be implemented by subclasses") def apply_message(self, message): """ Execution of an VM message. """ raise NotImplementedError("Must be implemented by subclasses") def apply_computation(self, message): """ Perform the computation that would be triggered by the VM message. """ raise NotImplementedError("Must be implemented by subclasses") # # Mining # def get_block_reward(self, block_number): return BLOCK_REWARD def get_nephew_reward(self, block_number): return NEPHEW_REWARD def import_block(self, block): self.configure_header( coinbase=block.header.coinbase, gas_limit=block.header.gas_limit, timestamp=block.header.timestamp, extra_data=block.header.extra_data, mix_hash=block.header.mix_hash, nonce=block.header.nonce, ) for transaction in block.transactions: self.apply_transaction(transaction) for uncle in block.uncles: self.block.add_uncle(uncle) return self.mine_block() def mine_block(self, *args, **kwargs): """ Mine the current block. """ block = self.block block.mine(*args, **kwargs) if block.number > 0: block_reward = self.get_block_reward(block.number) + ( len(block.uncles) * self.get_nephew_reward(block.number)) self.state_db.delta_balance(block.header.coinbase, block_reward) self.logger.debug( "BLOCK REWARD: %s -> %s", block_reward, block.header.coinbase, ) for uncle in block.uncles: uncle_reward = BLOCK_REWARD * ( UNCLE_DEPTH_PENALTY_FACTOR + uncle.block_number - block.number) // UNCLE_DEPTH_PENALTY_FACTOR self.state_db.delta_balance(uncle.coinbase, uncle_reward) self.logger.debug( "UNCLE REWARD REWARD: %s -> %s", uncle_reward, uncle.coinbase, ) self.logger.debug('BEFORE ROOT: %s', block.header.state_root) block.header.state_root = self.state_db.root_hash self.logger.debug('STATE_ROOT: %s', block.header.state_root) return block # # Transactions # def get_transaction_class(self): """ Return the class that this VM uses for transactions. """ return self.get_block_class().get_transaction_class() def create_transaction(self, *args, **kwargs): """ Proxy for instantiating a transaction for this VM. """ return self.get_transaction_class()(*args, **kwargs) def create_unsigned_transaction(self, *args, **kwargs): """ Proxy for instantiating a transaction for this VM. """ return self.get_transaction_class().create_unsigned_transaction( *args, **kwargs) def validate_transaction(self, transaction): """ Perform chain-aware validation checks on the transaction. """ raise NotImplementedError("Must be implemented by subclasses") # # Blocks # @classmethod def get_block_class(cls): """ Return the class that this VM uses for blocks. """ if cls._block_class is None: raise AttributeError("No `_block_class` has been set for this VM") return cls._block_class def get_block_by_header(self, block_header): return self.get_block_class().from_header(block_header, self.db) def get_ancestor_hash(self, block_number): """ Return the hash for the ancestor with the given number """ ancestor_depth = self.block.number - block_number if ancestor_depth > 256 or ancestor_depth < 1: return b'' h = get_block_header_by_hash(self.db, self.block.header.parent_hash) while h.block_number != block_number: h = get_block_header_by_hash(self.db, h.parent_hash) return h.hash # # Headers # @classmethod def create_header_from_parent(cls, parent_header, **header_params): """ Creates and initializes a new block header from the provided `parent_header`. """ raise NotImplementedError("Must be implemented by subclasses") def configure_header(self, **header_params): """ Setup the current header with the provided parameters. This can be used to set fields like the gas limit or timestamp to value different than their computed defaults. """ raise NotImplementedError("Must be implemented by subclasses") # # Snapshot and Revert # def snapshot(self): """ Perform a full snapshot of the current state of the VM. TODO: This needs to do more than just snapshot the state_db but this is a start. """ return self.state_db.snapshot() def revert(self, snapshot): """ Revert the VM to the state TODO: This needs to do more than just snapshot the state_db but this is a start. """ return self.state_db.revert(snapshot) # # Opcode API # def get_opcode_fn(self, opcode): try: return self.opcodes[opcode] except KeyError: return InvalidOpcode(opcode)
class BaseEVM(object): """ The EVM class is... TODO: """ db = None block = None opcodes = None block_class = None def __init__(self, header, db=None): if db is not None: self.db = db if self.db is None: raise ValueError("EVM classes must have a `db`") self.header = header block_class = self.get_block_class() self.block = block_class.from_header(header=self.header) self.state_db = State(db=self.db, root_hash=self.header.state_root) @classmethod def configure(cls, name=None, **overrides): if name is None: name = cls.__name__ for key in overrides: if not hasattr(cls, key): raise TypeError( "The EVM.configure cannot set attributes that are not " "already present on the base class. The attribute `{0}` was " "not found on the base class `{1}`".format(key, cls)) return type(name, (cls, ), overrides) # # Logging # @property def logger(self): return logging.getLogger('evm.vm.evm.EVM.{0}'.format( self.__class__.__name__)) # # Execution # def apply_transaction(self, transaction): """ Execution of a transaction in the EVM. """ raise NotImplementedError("Must be implemented by subclasses") def apply_create_message(self, message): """ Execution of an EVM message to create a new contract. """ raise NotImplementedError("Must be implemented by subclasses") def apply_message(self, message): """ Execution of an EVM message. """ raise NotImplementedError("Must be implemented by subclasses") def apply_computation(self, message): """ Perform the computation that would be triggered by the EVM message. """ raise NotImplementedError("Must be implemented by subclasses") # # Mining # def get_block_reward(self, block_number): return BLOCK_REWARD def get_nephew_reward(self, block_number): return NEPHEW_REWARD def mine_block(self, *args, **kwargs): """ Mine the current block. """ block = self.block.mine(*args, **kwargs) if block.number > 0: block_reward = self.get_block_reward(block.number) + ( len(block.uncles) * self.get_nephew_reward(block.number)) self.state_db.delta_balance(block.header.coinbase, block_reward) for uncle in block.uncles: uncle_reward = block_reward * ( UNCLE_DEPTH_PENALTY_FACTOR + uncle.block_number - block.number) // UNCLE_DEPTH_PENALTY_FACTOR self.state_db.delta_balance(uncle.coinbase, uncle_reward) block.header.state_root = self.state_db.root_hash return block # # Transactions # @classmethod def get_transaction_class(cls): """ Return the class that this EVM uses for transactions. """ return cls.get_block_class().get_transaction_class() def create_transaction(self, *args, **kwargs): """ Proxy for instantiating a transaction for this EVM. """ return self.get_transaction_class()(*args, **kwargs) def validate_transaction(self, transaction): """ Perform evm-aware validation checks on the transaction. """ raise NotImplementedError("Must be implemented by subclasses") # # Blocks # _block_class = None @classmethod def get_block_class(cls): """ Return the class that this EVM uses for blocks. """ if cls._block_class is None: raise AttributeError("No `_block_class` has been set for this EVM") block_class = cls._block_class.configure(db=cls.db) return block_class def get_block_by_hash(self, block_hash): block_class = self.get_block_class() block = rlp.decode(self.db.get(block_hash), sedes=block_class, db=self.db) return block def get_block_hash(self, block_number): """ For getting block hash for any block number in the the last 256 blocks. """ raise NotImplementedError("Not yet implemented") # # Headers # def create_header_from_parent(self, parent_header, **header_params): """ Creates and initializes a new block header from the provided `parent_header`. """ raise NotImplementedError("Must be implemented by subclasses") def configure_header(self, **header_params): """ Setup the current header with the provided parameters. This can be used to set fields like the gas limit or timestamp to value different than their computed defaults. """ raise NotImplementedError("Must be implemented by subclasses") # # Snapshot and Revert # def snapshot(self): """ Perform a full snapshot of the current state of the EVM. TODO: This needs to do more than just snapshot the state_db but this is a start. """ return self.state_db.snapshot() def revert(self, snapshot): """ Revert the EVM to the state TODO: This needs to do more than just snapshot the state_db but this is a start. """ return self.state_db.revert(snapshot) # # Opcode API # def get_opcode_fn(self, opcode): try: return self.opcodes[opcode] except KeyError: return InvalidOpcode(opcode)