def setup_tester_chain(genesis_params=None, genesis_state=None, num_accounts=None): from eth.chains.base import MiningChain from eth.db import get_db_backend from eth.vm.forks.muir_glacier import MuirGlacierVM class MuirGlacierNoProofVM(MuirGlacierVM): """Muir Glacier VM rules, without validating any miner proof of work""" @classmethod def validate_seal(self, header): pass class MainnetTesterNoProofChain(MiningChain): vm_configuration = ((0, MuirGlacierNoProofVM), ) @classmethod def validate_seal(cls, block): pass if genesis_params is None: genesis_params = get_default_genesis_params() if genesis_state: num_accounts = len(genesis_state) account_keys = get_default_account_keys(quantity=num_accounts) if genesis_state is None: genesis_state = generate_genesis_state_for_keys(account_keys) base_db = get_db_backend() chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params, genesis_state) return account_keys, chain
def setup_tester_chain(): from eth.chains.base import MiningChain from eth.db import get_db_backend from eth.vm.forks.byzantium import ByzantiumVM class ByzantiumNoProofVM(ByzantiumVM): """Byzantium VM rules, without validating any miner proof of work""" @classmethod def validate_seal(self, header): pass class MainnetTesterNoProofChain(MiningChain): vm_configuration = ((0, ByzantiumNoProofVM), ) @classmethod def validate_seal(cls, block): pass genesis_params = get_default_genesis_params() account_keys = get_default_account_keys() genesis_state = generate_genesis_state(account_keys) base_db = get_db_backend() chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params, genesis_state) return account_keys, chain
def setup_tester_chain(genesis_params=None, genesis_state=None, num_accounts=None, vm_configuration=None, mnemonic=None): from eth.chains.base import MiningChain from eth.consensus import ( NoProofConsensus, ConsensusApplier, ) from eth.db import get_db_backend if vm_configuration is None: from eth.vm.forks import LondonVM no_proof_vms = ((0, LondonVM.configure( consensus_class=NoProofConsensus)), ) else: consensus_applier = ConsensusApplier(NoProofConsensus) no_proof_vms = consensus_applier.amend_vm_configuration( vm_configuration) class MainnetTesterNoProofChain(MiningChain): chain_id = 131277322940537 vm_configuration = no_proof_vms def create_header_from_parent(self, parent_header, **header_params): # Keep the gas limit constant return super().create_header_from_parent( parent_header, **assoc(header_params, 'gas_limit', parent_header.gas_limit)) def get_transaction_builder(self): return super().get_vm().get_transaction_builder() if genesis_params is None: genesis_params = get_default_genesis_params() if genesis_state: num_accounts = len(genesis_state) if mnemonic: account_keys = get_account_keys_from_mnemonic(mnemonic, quantity=num_accounts) else: account_keys = get_default_account_keys(quantity=num_accounts) if genesis_state is None: genesis_state = generate_genesis_state_for_keys(account_keys) base_db = get_db_backend() chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params, genesis_state) return account_keys, chain
def setup_tester_chain(genesis_params=None, genesis_state=None, num_accounts=None, vm_configuration=None): from eth.chains.base import MiningChain from eth.consensus import ( NoProofConsensus, ConsensusApplier, ) from eth.db import get_db_backend if vm_configuration is None: from eth.vm.forks.muir_glacier import MuirGlacierVM no_proof_vms = ((0, MuirGlacierVM.configure( consensus_class=NoProofConsensus)), ) else: consensus_applier = ConsensusApplier(NoProofConsensus) no_proof_vms = consensus_applier.amend_vm_configuration( vm_configuration) class MainnetTesterNoProofChain(MiningChain): vm_configuration = no_proof_vms def create_header_from_parent(self, parent_header, **header_params): # Keep the gas limit constant return super().create_header_from_parent( parent_header, **assoc(header_params, 'gas_limit', parent_header.gas_limit)) if genesis_params is None: genesis_params = get_default_genesis_params() if genesis_state: num_accounts = len(genesis_state) account_keys = get_default_account_keys(quantity=num_accounts) if genesis_state is None: genesis_state = generate_genesis_state_for_keys(account_keys) base_db = get_db_backend() chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params, genesis_state) return account_keys, chain
def _setup_tester_chain(genesis_params, genesis_state, num_accounts): class DebugNoProofVM(DebugVM): """Byzantium VM rules, without validating any miner proof of work""" @classmethod def validate_seal(self, header): pass class MainnetTesterNoProofChain(MiningChain): vm_configuration = ((0, DebugNoProofVM), ) genesis_params = get_default_genesis_params() account_keys = get_default_account_keys(quantity=num_accounts) genesis_state = generate_genesis_state_for_keys(account_keys) base_db = get_db_backend() chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params, genesis_state) return account_keys, chain
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 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 test_vm_fixtures(fixture, vm_class, computation_getter): chaindb = ChainDB(get_db_backend()) header = BlockHeader( coinbase=fixture['env']['currentCoinbase'], difficulty=fixture['env']['currentDifficulty'], block_number=fixture['env']['currentNumber'], gas_limit=fixture['env']['currentGasLimit'], timestamp=fixture['env']['currentTimestamp'], ) vm = vm_class(header=header, chaindb=chaindb) 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("Got log entries: {0}".format(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, "Gas difference: {0}".format(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 test_raises_if_db_path_is_not_specified(config_env): with pytest.raises(TypeError): get_db_backend()
def level_db(config_env, tmpdir): level_db_path = str(tmpdir.mkdir("level_db_path")) return get_db_backend(db_path=level_db_path)
def shard_db(): return ShardDB(get_db_backend())
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']