def from_genesis(cls, base_db: AtomicDatabaseAPI, genesis_params: Dict[str, HeaderParams], genesis_state: AccountState=None) -> 'BaseChain': genesis_vm_class = cls.get_vm_class_for_block_number(BlockNumber(0)) pre_genesis_header = BlockHeader(difficulty=0, block_number=-1, gas_limit=0) chain_context = ChainContext(cls.chain_id) state = genesis_vm_class.build_state(base_db, pre_genesis_header, chain_context) if genesis_state is None: genesis_state = {} # mutation apply_state_dict(state, genesis_state) state.persist() if 'state_root' not in genesis_params: # If the genesis state_root was not specified, use the value # computed from the initialized state database. genesis_params = assoc(genesis_params, 'state_root', state.state_root) elif genesis_params['state_root'] != state.state_root: # If the genesis state_root was specified, validate that it matches # the computed state from the initialized state database. raise ValidationError( "The provided genesis state root does not match the computed " f"genesis state root. Got {state.state_root!r}. " f"Expected {genesis_params['state_root']!r}" ) genesis_header = BlockHeader(**genesis_params) return cls.from_genesis_header(base_db, genesis_header)
def setup_computation(vm_class, create_address, code, chain_id=None, gas=1000000, to=CANONICAL_ADDRESS_A, data=b''): message = Message( to=to, sender=CANONICAL_ADDRESS_B, create_address=create_address, value=0, data=data, code=code, gas=gas, ) chain_context = ChainContext(chain_id) tx_context = vm_class._state_class.transaction_context_class( gas_price=1, origin=CANONICAL_ADDRESS_B, ) vm = vm_class(GENESIS_HEADER, ChainDB(AtomicDB()), chain_context) computation = vm_class._state_class.computation_class( state=vm.state, message=message, transaction_context=tx_context, ) return computation
def initialize_vm_and_state(state_test): account_state = decode_account_state(state_test["pre"]) # print(account_state) base_db = AtomicDB() chain = MainnetChain(base_db) pre_genesis_header = BlockHeader(difficulty=0, block_number=-1, gas_limit=0) chain_context = ChainContext(MAINNET_CHAIN_ID) state = IstanbulVM.build_state(base_db, pre_genesis_header, chain_context) # apply custom state apply_state_dict(state, account_state) state.persist() # print("initial state", encode_hex(state.make_state_root())) current_block_params = decode_current_block_params(state_test["env"]) current_block_header = BlockHeader(**current_block_params) # vm = chain.get_vm() vm = IstanbulVM( header=pre_genesis_header, chaindb=chain.chaindb, chain_context=chain_context, consensus_context=chain.consensus_context, ) return vm, state, current_block_header
def get_vm(self, at_header: BlockHeaderAPI = None) -> VirtualMachineAPI: header = self.ensure_header(at_header) vm_class = self.get_vm_class_for_block_number(header.block_number) chain_context = ChainContext(self.chain_id) return vm_class(header=header, chaindb=self.chaindb, chain_context=chain_context, consensus_context=self.consensus_context)
def setup_vm(vm_class, chain_id=None): db = AtomicDB() chain_context = ChainContext(chain_id) genesis_header = vm_class.create_genesis_header( difficulty=constants.GENESIS_DIFFICULTY, timestamp=0, ) return vm_class(genesis_header, ChainDB(db), chain_context, ConsensusContext(db))
def instantiate_vm(vm_class): GENESIS_HEADER = BlockHeader( difficulty=17179869184, block_number=BlockNumber(0), gas_limit=5000, ) chain_context = ChainContext(None) db = AtomicDB() return vm_class(GENESIS_HEADER, ChainDB(db), chain_context, ConsensusContext(db))
def get_vm(self, at_header: BlockHeaderAPI = None) -> VirtualMachineAPI: """ Returns the VM instance for the given block number. """ header = self.ensure_header(at_header) vm_class = self.get_vm_class_for_block_number(header.block_number) chain_context = ChainContext(self.chain_id) return vm_class(header=header, chaindb=self.chaindb, chain_context=chain_context)
def test_mainnet_dao_fork_header_validation(VM, header, previous_header, valid): chain_db = FakeChainDB({}) consensus_context = ConsensusContext(chain_db.db) vm = VM(header=previous_header, chaindb=chain_db, chain_context=ChainContext(1), consensus_context=consensus_context) if valid: vm.validate_header(header, previous_header, check_seal=True) else: try: vm.validate_header(header, previous_header, check_seal=True) except ValidationError: pass else: assert False, "The invalid header %r must fail" % header
def test_vm_fixtures(fixture, vm_class, computation_getter): db = get_db_backend() chaindb = ChainDB(db) consensus_context = ConsensusContext(db) header = BlockHeader( coinbase=fixture['env']['currentCoinbase'], difficulty=fixture['env']['currentDifficulty'], block_number=fixture['env']['currentNumber'], gas_limit=fixture['env']['currentGasLimit'], timestamp=fixture['env']['currentTimestamp'], ) # None of the VM tests (currently) test chain ID, so the setting doesn't matter here. # When they *do* start testing ID, they will have to supply it as part of the environment. # For now, just hard-code it to something not used in practice: chain_context = ChainContext(chain_id=0) vm = vm_class(header=header, chaindb=chaindb, chain_context=chain_context, consensus_context=consensus_context) state = vm.state setup_state(fixture['pre'], state) code = state.get_code(fixture['exec']['address']) # Update state_root manually vm._block = vm.get_block().copy(header=vm.get_header().copy( state_root=state.state_root)) message = Message( to=fixture['exec']['address'], sender=fixture['exec']['caller'], value=fixture['exec']['value'], data=fixture['exec']['data'], code=code, gas=fixture['exec']['gas'], ) transaction_context = BaseTransactionContext( origin=fixture['exec']['origin'], gas_price=fixture['exec']['gasPrice'], ) computation = vm.state.get_computation( message, transaction_context).apply_computation( vm.state, message, transaction_context, ) # Update state_root manually vm._block = vm.get_block().copy( header=vm.get_header().copy(state_root=computation.state.state_root), ) if 'post' in fixture: # # Success checks # assert not computation.is_error log_entries = computation.get_log_entries() if 'logs' in fixture: actual_logs_hash = hash_log_entries(log_entries) expected_logs_hash = fixture['logs'] assert expected_logs_hash == actual_logs_hash elif log_entries: raise AssertionError(f"Got log entries: {log_entries}") expected_output = fixture['out'] assert computation.output == expected_output gas_meter = computation._gas_meter expected_gas_remaining = fixture['gas'] actual_gas_remaining = gas_meter.gas_remaining gas_delta = actual_gas_remaining - expected_gas_remaining assert gas_delta == 0, f"Gas difference: {gas_delta}" call_creates = fixture.get('callcreates', []) assert len(computation.children) == len(call_creates) call_creates = fixture.get('callcreates', []) for child_computation, created_call in zip(computation.children, call_creates): to_address = created_call['destination'] data = created_call['data'] gas_limit = created_call['gasLimit'] value = created_call['value'] assert child_computation.msg.to == to_address assert data == child_computation.msg.data or child_computation.msg.code assert gas_limit == child_computation.msg.gas assert value == child_computation.msg.value expected_account_db = fixture['post'] else: # # Error checks # assert computation.is_error assert isinstance(computation._error, VMError) expected_account_db = fixture['pre'] verify_state(expected_account_db, vm.state)
def setup_vm(vm_class, chain_id=None): db = AtomicDB() chain_context = ChainContext(chain_id) return vm_class(GENESIS_HEADER, ChainDB(db), chain_context, ConsensusContext(db))