def test_configure_duplicate_block_numbers_in_vm_configuration(): with pytest.raises(ValidationError): Chain.configure('TestChain', vm_configuration=[ (0, FrontierVM), (0, HomesteadVM), ])
def test_vm_not_found_if_no_matching_block_number(): chain_class = Chain.configure('TestChain', vm_configuration=( (10, FrontierVM), )) chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100)) with pytest.raises(VMNotFound): chain.get_vm_class_for_block_number(9)
def chain_without_block_validation(): """ Return a Chain object containing just the genesis block. This Chain does not perform any validation when importing new blocks. The Chain's state includes one funded account and a private key for it, which can be found in the funded_address and private_keys variables in the chain itself. """ # Disable block validation so that we don't need to construct finalized blocks. overrides = { 'ensure_blocks_are_equal': lambda self, b1, b2: None, 'validate_block': lambda self, block: None, } klass = Chain.configure( name='TestChainWithoutBlockValidation', vm_configuration=((constants.GENESIS_BLOCK_NUMBER, FrontierVM), ), **overrides, ) private_key = decode_hex( '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8') funded_addr = private_key_to_address(private_key) initial_balance = 100000000 genesis_params = { 'block_number': constants.GENESIS_BLOCK_NUMBER, 'difficulty': constants.GENESIS_DIFFICULTY, 'gas_limit': constants.GENESIS_GAS_LIMIT, 'parent_hash': constants.GENESIS_PARENT_HASH, 'coinbase': constants.GENESIS_COINBASE, 'nonce': constants.GENESIS_NONCE, 'mix_hash': constants.GENESIS_MIX_HASH, 'extra_data': constants.GENESIS_EXTRA_DATA, 'timestamp': 1501851927, 'state_root': decode_hex( '0x9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4' ) } genesis_state = { funded_addr: { 'balance': initial_balance, 'nonce': 0, 'code': b'', 'storage': {}, } } chain = klass.from_genesis(get_db_backend(), genesis_params, genesis_state) chain.funded_address = funded_addr chain.funded_address_initial_balance = initial_balance chain.funded_address_private_key = private_key return chain
def chain_without_pow(base_db: MemoryDB, vm: Type[BaseVM], genesis_params: Any, genesis_state: Any) -> Chain: vm_without_pow = vm.configure(validate_seal=lambda block: None) klass = Chain.configure(__name__='TestChain', vm_configuration=((constants.GENESIS_BLOCK_NUMBER, vm_without_pow), )) chain = klass.from_genesis(base_db, genesis_params, genesis_state) return chain
def test_get_vm_class_for_block_number(): chain_class = Chain.configure(vm_configuration=( (constants.GENESIS_BLOCK_NUMBER, FrontierVM), (constants.HOMESTEAD_MAINNET_BLOCK, HomesteadVM), ), ) chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100)) assert chain.get_vm_class_for_block_number( constants.GENESIS_BLOCK_NUMBER, ) == FrontierVM assert chain.get_vm_class_for_block_number( constants.HOMESTEAD_MAINNET_BLOCK - 1) == FrontierVM assert chain.get_vm_class_for_block_number( constants.HOMESTEAD_MAINNET_BLOCK) == HomesteadVM assert chain.get_vm_class_for_block_number( constants.HOMESTEAD_MAINNET_BLOCK + 1) == HomesteadVM
def test_get_vm_class_for_block_number(): chain_class = Chain.configure( name='TestChain', vm_configuration=( (constants.GENESIS_BLOCK_NUMBER, FrontierVM), (HOMESTEAD_MAINNET_BLOCK, HomesteadVM), ), ) chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100)) assert chain.get_vm_class_for_block_number( constants.GENESIS_BLOCK_NUMBER,) == FrontierVM assert chain.get_vm_class_for_block_number( HOMESTEAD_MAINNET_BLOCK - 1) == FrontierVM assert chain.get_vm_class_for_block_number( HOMESTEAD_MAINNET_BLOCK) == HomesteadVM assert chain.get_vm_class_for_block_number( HOMESTEAD_MAINNET_BLOCK + 1) == HomesteadVM
def chain_without_block_validation(base_db, funded_address, funded_address_initial_balance): """ Return a Chain object containing just the genesis block. This Chain does not perform any validation when importing new blocks. The Chain's state includes one funded account and a private key for it, which can be found in the funded_address and private_keys variables in the chain itself. """ # Disable block validation so that we don't need to construct finalized blocks. overrides = { 'import_block': import_block_without_validation, 'validate_block': lambda self, block: None, } SpuriousDragonVMForTesting = SpuriousDragonVM.configure( validate_seal=lambda self, block: None) klass = Chain.configure( __name__='TestChainWithoutBlockValidation', vm_configuration=((constants.GENESIS_BLOCK_NUMBER, SpuriousDragonVMForTesting), ), **overrides, ) genesis_params = { 'block_number': constants.GENESIS_BLOCK_NUMBER, 'difficulty': constants.GENESIS_DIFFICULTY, 'gas_limit': constants.GENESIS_GAS_LIMIT, 'parent_hash': constants.GENESIS_PARENT_HASH, 'coinbase': constants.GENESIS_COINBASE, 'nonce': constants.GENESIS_NONCE, 'mix_hash': constants.GENESIS_MIX_HASH, 'extra_data': constants.GENESIS_EXTRA_DATA, 'timestamp': 1501851927, } genesis_state = { funded_address: { 'balance': funded_address_initial_balance, 'nonce': 0, 'code': b'', 'storage': {}, } } chain = klass.from_genesis(base_db, genesis_params, genesis_state) return chain
def chain_with_block_validation(base_db, funded_address, funded_address_initial_balance): """ Return a Chain object containing just the genesis block. The Chain's state includes one funded account, which can be found in the funded_address in the chain itself. This Chain will perform all validations when importing new blocks, so only valid and finalized blocks can be used with it. If you want to test importing arbitrarily constructe, not finalized blocks, use the chain_without_block_validation fixture instead. """ genesis_params = { "bloom": 0, "coinbase": to_canonical_address("8888f1f195afa192cfee860698584c030f4c9db1"), "difficulty": 131072, "extra_data": b"B", "gas_limit": 3141592, "gas_used": 0, "mix_hash": decode_hex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), # noqa: E501 "nonce": decode_hex("0102030405060708"), "block_number": 0, "parent_hash": decode_hex("0000000000000000000000000000000000000000000000000000000000000000"), # noqa: E501 "receipt_root": decode_hex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), # noqa: E501 "timestamp": 1422494849, "transaction_root": decode_hex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), # noqa: E501 "uncles_hash": decode_hex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") # noqa: E501 } genesis_state = { funded_address: { "balance": funded_address_initial_balance, "nonce": 0, "code": b"", "storage": {} } } klass = Chain.configure( __name__='TestChain', vm_configuration=( (constants.GENESIS_BLOCK_NUMBER, SpuriousDragonVM), ), network_id=1337, ) chain = klass.from_genesis(base_db, genesis_params, genesis_state) return chain
def test_header_chain_invalid_if_no_vm_configuration(base_db, genesis_header): chain_class = Chain.configure('ChainNoEmptyConfiguration', vm_configuration=()) with pytest.raises(ValueError): chain_class(base_db, genesis_header)
def chain(): """ Return a Chain object containing just the genesis block. The Chain's state includes one funded account, which can be found in the funded_address in the chain itself. This Chain will perform all validations when importing new blocks, so only valid and finalized blocks can be used with it. If you want to test importing arbitrarily constructe, not finalized blocks, use the chain_without_block_validation fixture instead. """ genesis_params = { "bloom": 0, "coinbase": to_canonical_address("8888f1f195afa192cfee860698584c030f4c9db1"), "difficulty": 131072, "extra_data": b"B", "gas_limit": 3141592, "gas_used": 0, "mix_hash": decode_hex( "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" ), "nonce": decode_hex("0102030405060708"), "block_number": 0, "parent_hash": decode_hex( "0000000000000000000000000000000000000000000000000000000000000000" ), "receipt_root": decode_hex( "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" ), "state_root": decode_hex( "cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7" ), "timestamp": 1422494849, "transaction_root": decode_hex( "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" ), "uncles_hash": decode_hex( "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") } funded_addr = to_canonical_address( "a94f5374fce5edbc8e2a8697c15331677e6ebf0b") initial_balance = 10000000000 genesis_state = { funded_addr: { "balance": initial_balance, "nonce": 0, "code": b"", "storage": {} } } klass = Chain.configure(name='TestChain', vm_configuration=((constants.GENESIS_BLOCK_NUMBER, FrontierVM), )) chain = klass.from_genesis(ChainDB(get_db_backend()), genesis_params, genesis_state) chain.funded_address = funded_addr chain.funded_address_initial_balance = initial_balance return chain
def test_blockchain_fixtures(fixture_name, fixture): genesis_params = { 'parent_hash': fixture['genesisBlockHeader']['parentHash'], 'uncles_hash': fixture['genesisBlockHeader']['uncleHash'], 'coinbase': fixture['genesisBlockHeader']['coinbase'], 'state_root': fixture['genesisBlockHeader']['stateRoot'], 'transaction_root': fixture['genesisBlockHeader']['transactionsTrie'], 'receipt_root': fixture['genesisBlockHeader']['receiptTrie'], 'bloom': fixture['genesisBlockHeader']['bloom'], 'difficulty': fixture['genesisBlockHeader']['difficulty'], 'block_number': fixture['genesisBlockHeader']['number'], 'gas_limit': fixture['genesisBlockHeader']['gasLimit'], 'gas_used': fixture['genesisBlockHeader']['gasUsed'], 'timestamp': fixture['genesisBlockHeader']['timestamp'], 'extra_data': fixture['genesisBlockHeader']['extraData'], 'mix_hash': fixture['genesisBlockHeader']['mixHash'], 'nonce': fixture['genesisBlockHeader']['nonce'], } expected_genesis_header = BlockHeader(**genesis_params) # TODO: find out if this is supposed to pass? # if 'genesisRLP' in fixture: # assert rlp.encode(genesis_header) == fixture['genesisRLP'] db = get_db_backend() chain = MainnetChain # TODO: It would be great if we can figure out an API for re-configuring # start block numbers that was more elegant. if fixture_name.startswith('Homestead'): chain = Chain.configure('HomesteadChain', vm_configuration=[(0, HomesteadVM)]) elif fixture_name.startswith('EIP150'): chain = Chain.configure('EIP150VM', vm_configuration=[(0, EIP150VM)]) elif fixture_name.startswith('TestNetwork'): homestead_vm = HomesteadVM.configure(dao_fork_block_number=8) chain = Chain.configure('TestNetworkChain', vm_configuration=[ (0, FrontierVM), (5, homestead_vm), (10, EIP150VM), ]) chain = chain.from_genesis( db, genesis_params=genesis_params, genesis_state=fixture['pre'], ) genesis_block = chain.get_canonical_block_by_number(0) genesis_header = genesis_block.header assert_rlp_equal(genesis_header, expected_genesis_header) # 1 - mine the genesis block # 2 - loop over blocks: # - apply transactions # - mine block # 4 - profit!! for block_data in fixture['blocks']: should_be_good_block = 'blockHeader' in block_data if 'rlp_error' in block_data: assert not should_be_good_block continue # The block to import may be in a different block-class-range than the # chain's current one, so we use the block number specified in the # fixture to look up the correct block class. if should_be_good_block: block_number = block_data['blockHeader']['number'] block_class = chain.get_vm_class_for_block_number( block_number).get_block_class() else: block_class = chain.get_vm().get_block_class() try: block = rlp.decode(block_data['rlp'], sedes=block_class, db=db) except (TypeError, rlp.DecodingError, rlp.DeserializationError) as err: assert not should_be_good_block, "Block should be good: {0}".format( err) continue try: mined_block = chain.import_block(block) except ValidationError as err: assert not should_be_good_block, "Block should be good: {0}".format( err) continue else: assert_rlp_equal(mined_block, block) assert should_be_good_block, "Block should have caused a validation error" latest_block_hash = chain.get_canonical_block_by_number( chain.get_block().number - 1).hash assert latest_block_hash == fixture['lastblockhash'] verify_state_db(fixture['postState'], chain.get_state_db())
from evm import constants from evm import Chain from evm.vm.flavors import ( EIP150VM, FrontierVM, HomesteadVM, ) MainnetChain = Chain.configure( 'MainnetChain', vm_configuration=((0, FrontierVM), (constants.HOMESTEAD_MAINNET_BLOCK, HomesteadVM), (constants.EIP150_MAINNET_BLOCK, EIP150VM)))
def test_vm_not_found_if_no_matching_block_number(genesis_header): chain_class = Chain.configure('ChainStartsAtBlock10', vm_configuration=( (10, VM_A), )) with pytest.raises(VMNotFound): chain_class.get_vm_class_for_block_number(9)
def test_configure_invalid_block_number_in_vm_configuration(): with pytest.raises(ValidationError): Chain.configure('TestChain', vm_configuration=[(-1, FrontierVM)])
def test_invalid_if_no_vm_configuration(): chain_class = Chain.configure('TestChain', vm_configuration=()) with pytest.raises(ValueError): chain_class(get_db_backend(), BlockHeader(1, 0, 100))
name='HomesteadVMForTesting', apply_message=apply_create_message_for_testing, apply_create_message=apply_create_message_for_testing, get_ancestor_hash=get_block_hash_for_testing, ) EIP150VMForTesting = EIP150VM.configure( name='EIP150VMForTesting', apply_message=apply_create_message_for_testing, apply_create_message=apply_create_message_for_testing, get_ancestor_hash=get_block_hash_for_testing, ) ChainForTesting = Chain.configure( name='ChainForTesting', vm_configuration=( (constants.GENESIS_BLOCK_NUMBER, FrontierVMForTesting), (constants.HOMESTEAD_MAINNET_BLOCK, HomesteadVMForTesting), (constants.EIP150_MAINNET_BLOCK, EIP150VMForTesting), ), ) @pytest.mark.parametrize( 'fixture_name,fixture', FIXTURES, ) def test_vm_fixtures(fixture_name, fixture): db = get_db_backend() header = BlockHeader( coinbase=fixture['env']['currentCoinbase'], difficulty=fixture['env']['currentDifficulty'], block_number=fixture['env']['currentNumber'],