def from_genesis(cls, base_db: BaseDB, genesis_params: Dict[str, HeaderParams], genesis_state: AccountState=None) -> 'BaseChain': """ Initializes the Chain from a genesis state. """ genesis_vm_class = cls.get_vm_class_for_block_number(BlockNumber(0)) account_db = genesis_vm_class.get_state_class().get_account_db_class()( base_db, BLANK_ROOT_HASH, ) if genesis_state is None: genesis_state = {} # mutation apply_state_dict(account_db, genesis_state) account_db.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', account_db.state_root) elif genesis_params['state_root'] != account_db.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 " "genesis state root. Got {0}. Expected {1}".format( account_db.state_root, genesis_params['state_root'], ) ) genesis_header = BlockHeader(**genesis_params) return cls.from_genesis_header(base_db, genesis_header)
def test_state_fixtures(fixture, fixture_vm_class): header = BlockHeader( coinbase=fixture['env']['currentCoinbase'], difficulty=fixture['env']['currentDifficulty'], block_number=fixture['env']['currentNumber'], gas_limit=fixture['env']['currentGasLimit'], timestamp=fixture['env']['currentTimestamp'], parent_hash=fixture['env']['previousHash'], ) chaindb = ChainDB(get_db_backend()) vm = fixture_vm_class(header=header, chaindb=chaindb) state = vm.state apply_state_dict(state.account_db, fixture['pre']) state.account_db.persist() # Update state_root manually vm.block = vm.block.copy(header=vm.block.header.copy( state_root=state.state_root)) if 'secretKey' in fixture['transaction']: unsigned_transaction = vm.create_unsigned_transaction( nonce=fixture['transaction']['nonce'], gas_price=fixture['transaction']['gasPrice'], gas=fixture['transaction']['gasLimit'], to=fixture['transaction']['to'], value=fixture['transaction']['value'], data=fixture['transaction']['data'], ) private_key = keys.PrivateKey(fixture['transaction']['secretKey']) transaction = unsigned_transaction.as_signed_transaction( private_key=private_key) elif 'vrs' in fixture['transaction']: v, r, s = ( fixture['transaction']['v'], fixture['transaction']['r'], fixture['transaction']['s'], ) transaction = vm.create_transaction( nonce=fixture['transaction']['nonce'], gas_price=fixture['transaction']['gasPrice'], gas=fixture['transaction']['gasLimit'], to=fixture['transaction']['to'], value=fixture['transaction']['value'], data=fixture['transaction']['data'], v=v, r=r, s=s, ) try: header, receipt, computation = vm.apply_transaction( vm.block.header, transaction) transactions = vm.block.transactions + (transaction, ) receipts = vm.block.get_receipts(chaindb) + (receipt, ) block = vm.set_block_transactions(vm.block, header, transactions, receipts) except ValidationError as err: block = vm.block transaction_error = err logger.warn("Got transaction error", exc_info=True) else: transaction_error = False if not transaction_error: log_entries = computation.get_log_entries() actual_logs_hash = hash_log_entries(log_entries) if 'logs' in fixture['post']: expected_logs_hash = fixture['post']['logs'] assert expected_logs_hash == actual_logs_hash elif log_entries: raise AssertionError("Got log {0} entries. hash:{1}".format( len(log_entries), actual_logs_hash, )) if 'out' in fixture: expected_output = fixture['out'] if isinstance(expected_output, int): assert len(computation.output) == expected_output else: assert computation.output == expected_output assert block.header.state_root == fixture['post']['hash']
def calc_state_root(state, account_db_class): account_db = account_db_class(MemoryDB()) apply_state_dict(account_db, state) return account_db.state_root
def calc_state_root(state: AccountState, account_db_class: Type[BaseAccountDB]) -> bytes: account_db = account_db_class(MemoryDB()) apply_state_dict(account_db, state) return account_db.state_root
def test_state_fixtures(fixture, fixture_vm_class): header = BlockHeader( coinbase=fixture['env']['currentCoinbase'], difficulty=fixture['env']['currentDifficulty'], block_number=fixture['env']['currentNumber'], gas_limit=fixture['env']['currentGasLimit'], timestamp=fixture['env']['currentTimestamp'], parent_hash=fixture['env']['previousHash'], ) chaindb = ChainDB(get_db_backend()) vm = fixture_vm_class(header=header, chaindb=chaindb) state = vm.state apply_state_dict(state.account_db, fixture['pre']) state.account_db.persist() # Update state_root manually vm.block = vm.block.copy(header=vm.block.header.copy( state_root=state.state_root)) if 'secretKey' in fixture['transaction']: unsigned_transaction = vm.create_unsigned_transaction( nonce=fixture['transaction']['nonce'], gas_price=fixture['transaction']['gasPrice'], gas=fixture['transaction']['gasLimit'], to=fixture['transaction']['to'], value=fixture['transaction']['value'], data=fixture['transaction']['data'], ) private_key = keys.PrivateKey(fixture['transaction']['secretKey']) transaction = unsigned_transaction.as_signed_transaction( private_key=private_key) elif 'vrs' in fixture['transaction']: v, r, s = ( fixture['transaction']['v'], fixture['transaction']['r'], fixture['transaction']['s'], ) transaction = vm.create_transaction( nonce=fixture['transaction']['nonce'], gas_price=fixture['transaction']['gasPrice'], gas=fixture['transaction']['gasLimit'], to=fixture['transaction']['to'], value=fixture['transaction']['value'], data=fixture['transaction']['data'], v=v, r=r, s=s, ) else: raise Exception("Invariant: No transaction specified") try: header, receipt, computation = vm.apply_transaction( vm.block.header, transaction) except ValidationError as err: logger.warning("Got transaction error", exc_info=True) transaction_error = err else: transaction_error = False transactions = vm.block.transactions + (transaction, ) receipts = vm.block.get_receipts(chaindb) + (receipt, ) vm.block = vm.set_block_transactions(vm.block, header, transactions, receipts) finally: # This is necessary due to the manner in which the state tests are # generated. State tests are generated from the BlockChainTest tests # in which these transactions are included in the larger context of a # block and thus, the mechanisms which would touch/create/clear the # coinbase account based on the mining reward are present during test # generation, but not part of the execution, thus we must artificially # create the account in VMs prior to the state clearing rules, # as well as conditionally cleaning up the coinbase account when left # empty in VMs after the state clearing rules came into effect. # Related change in geth: # https://github.com/ethereum/go-ethereum/commit/32f28a9360d26a661d55915915f12fd3c70f012b#diff-f53696be8527ac422b8d4de7c8e945c1R149 # noqa: E501 if isinstance(vm, PRE_STATE_CLEARING_VMS): state.account_db.touch_account(vm.block.header.coinbase) state.account_db.persist() vm.block = vm.block.copy(header=vm.block.header.copy( state_root=state.state_root)) elif state.account_db.account_is_empty(vm.block.header.coinbase): state.account_db.delete_account(vm.block.header.coinbase) state.account_db.persist() vm.block = vm.block.copy(header=vm.block.header.copy( state_root=state.state_root)) block = vm.block if not transaction_error: log_entries = computation.get_log_entries() actual_logs_hash = hash_log_entries(log_entries) if 'logs' in fixture['post']: expected_logs_hash = fixture['post']['logs'] assert expected_logs_hash == actual_logs_hash elif log_entries: raise AssertionError("Got log {0} entries. hash:{1}".format( len(log_entries), actual_logs_hash, )) if 'out' in fixture: expected_output = fixture['out'] if isinstance(expected_output, int): assert len(computation.output) == expected_output else: assert computation.output == expected_output assert block.header.state_root == fixture['post']['hash']