diff --git a/.circleci/config.yml b/.circleci/config.yml index 2408057d2a..01a30e506b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -169,6 +169,12 @@ jobs: - image: circleci/python:3.6 environment: TOXENV: py36-rpc-state-homestead + py36-rpc-state-istanbul: + <<: *common + docker: + - image: circleci/python:3.6 + environment: + TOXENV: py36-rpc-state-istanbul py36-rpc-state-petersburg: <<: *common docker: diff --git a/newsfragments/1372.internal.rst b/newsfragments/1372.internal.rst new file mode 100644 index 0000000000..ea660451e9 --- /dev/null +++ b/newsfragments/1372.internal.rst @@ -0,0 +1 @@ +Test Trinity against Istanbul tests \ No newline at end of file diff --git a/newsfragments/1403.bugfix.rst b/newsfragments/1403.bugfix.rst new file mode 100644 index 0000000000..340fd9ca7a --- /dev/null +++ b/newsfragments/1403.bugfix.rst @@ -0,0 +1,4 @@ +Ensure ``eth_getStorageAt`` pads results to 32 byte + +See: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat +Geth Example: https://api.etherscan.io/api?module=proxy&action=eth_getStorageAt&address=0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd&position=0x0&tag=latest&apikey=YourApiKeyToken \ No newline at end of file diff --git a/tests/core/json-rpc/test_rpc_during_beam_sync.py b/tests/core/json-rpc/test_rpc_during_beam_sync.py index 311ec34ec6..d4430d7cb0 100644 --- a/tests/core/json-rpc/test_rpc_during_beam_sync.py +++ b/tests/core/json-rpc/test_rpc_during_beam_sync.py @@ -281,7 +281,8 @@ async def test_getStorageAt_during_beam_sync( # sanity check, by default it works response = await ipc_request('eth_getStorageAt', params) assert 'error' not in response - assert response['result'] == '0x01' # this was set in the genesis_state fixture + # this was set in the genesis_state fixture + assert response['result'] == '0x0000000000000000000000000000000000000000000000000000000000000001' # noqa: E501 missing_node = chain.chaindb.db.pop(storage_root) @@ -294,7 +295,8 @@ async def test_getStorageAt_during_beam_sync( async with fake_beam_syncer({storage_root: missing_node}): response = await ipc_request('eth_getStorageAt', params) assert 'error' not in response - assert response['result'] == '0x01' # this was set in the genesis_state fixture + # this was set in the genesis_state fixture + assert response['result'] == '0x0000000000000000000000000000000000000000000000000000000000000001' # noqa: E501 @pytest.fixture diff --git a/tests/json-fixtures-over-rpc/test_rpc_fixtures.py b/tests/json-fixtures-over-rpc/test_rpc_fixtures.py index f3abaed814..16492c184a 100644 --- a/tests/json-fixtures-over-rpc/test_rpc_fixtures.py +++ b/tests/json-fixtures-over-rpc/test_rpc_fixtures.py @@ -14,6 +14,7 @@ from eth_utils import ( add_0x_prefix, + decode_hex, encode_hex, is_address, is_hex, @@ -38,6 +39,9 @@ load_fixture, should_run_slow_tests, ) +from eth._utils.padding import ( + pad32, +) from trinity.chains.full import ( FullChain, @@ -70,6 +74,7 @@ 'randomStatetest94_Byzantium', 'randomStatetest94_Constantinople', 'randomStatetest94_ConstantinopleFix', + 'randomStatetest94_Istanbul', 'ShanghaiLove_Homestead', 'ShanghaiLove_Frontier', 'static_Call1024PreCalls_d1g0v0', @@ -142,12 +147,28 @@ ('GeneralStateTests/stSStoreTest/InitCollision_d0g0v0.json', 'InitCollision_d0g0v0_ConstantinopleFix'), # noqa: E501 ('GeneralStateTests/stSStoreTest/InitCollision_d1g0v0.json', 'InitCollision_d1g0v0_ConstantinopleFix'), # noqa: E501 ('GeneralStateTests/stSStoreTest/InitCollision_d3g0v0.json', 'InitCollision_d3g0v0_ConstantinopleFix'), # noqa: E501 + ('GeneralStateTests/stSStoreTest/InitCollision.json', 'InitCollision_d0g0v0_Istanbul'), # noqa: E501 + ('GeneralStateTests/stSStoreTest/InitCollision.json', 'InitCollision_d1g0v0_Istanbul'), # noqa: E501 + ('GeneralStateTests/stSStoreTest/InitCollision.json', 'InitCollision_d3g0v0_Istanbul'), # noqa: E501 } + +def pad32_dict_values(some_dict): + return { + key: encode_hex(pad32(decode_hex(value))) + for key, value in some_dict.items() + } + + +def map_0x_to_0x0(value): + return '0x0' if value == '0x' else value + + RPC_STATE_NORMALIZERS = { 'balance': remove_leading_zeros, 'code': empty_to_0x, 'nonce': remove_leading_zeros, + 'storage': pad32_dict_values } RPC_BLOCK_REMAPPERS = { @@ -176,7 +197,7 @@ 'nonce': remove_leading_zeros, 'gasLimit': remove_leading_zeros, 'gasPrice': remove_leading_zeros, - 'value': remove_leading_zeros, + 'value': compose(remove_leading_zeros, map_0x_to_0x0), 'data': empty_to_0x, 'to': compose( apply_formatter_if(is_address, to_checksum_address), @@ -298,8 +319,8 @@ async def validate_account_state(rpc, state, addr, at_block): at_block=at_block ) for key in state['storage']: - position = '0x0' if key == '0x' else key - expected_storage = state['storage'][key] + position = map_0x_to_0x0(key) + expected_storage = standardized_state['storage'][key] await assert_rpc_result( rpc, 'eth_getStorageAt', @@ -451,8 +472,7 @@ async def validate_uncles(rpc, block_fixture, at_block): def chain_fixture(fixture_data): fixture_path, fixture_key, fixture_fork = fixture_data fixture = load_fixture(fixture_path, fixture_key) - if fixture_fork == 'Istanbul': - pytest.skip('Istanbul VM rules not yet supported') + return fixture diff --git a/tox.ini b/tox.ini index 9cd98dea29..46481c07ab 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ envlist= py{36,37}-{eth1-core,p2p,p2p-trio,eth1-monitor-trio,integration,lightchain_integration,eth2-core,eth2-fixtures,eth2-integration,eth1-components,eth2-utils} py36-long_run_integration py36-rpc-blockchain - py36-rpc-state-{frontier,homestead,tangerine_whistle,spurious_dragon,byzantium,constantinople,petersburg} + py36-rpc-state-{frontier,homestead,tangerine_whistle,spurious_dragon,byzantium,constantinople,petersburg,istanbul} py37-rpc-state-{quadratic,sstore,zero_knowledge} py37-{libp2p,eth2-components} py{36,37}-lint @@ -50,6 +50,7 @@ commands= rpc-state-byzantium: pytest -n 3 {posargs:tests/json-fixtures-over-rpc/test_rpc_fixtures.py --fork Byzantium -k 'GeneralStateTests and not stQuadraticComplexityTest and not stSStoreTest and not stZeroKnowledge'} rpc-state-constantinople: pytest -n 3 {posargs:tests/json-fixtures-over-rpc/test_rpc_fixtures.py --fork Constantinople -k 'GeneralStateTests and not stQuadraticComplexityTest and not stSStoreTest and not stZeroKnowledge'} rpc-state-petersburg: pytest -n 3 {posargs:tests/json-fixtures-over-rpc/test_rpc_fixtures.py --fork ConstantinopleFix -k 'GeneralStateTests and not stQuadraticComplexityTest and not stSStoreTest and not stZeroKnowledge'} + rpc-state-istanbul: pytest -n 3 {posargs:tests/json-fixtures-over-rpc/test_rpc_fixtures.py --fork Istanbul -k 'GeneralStateTests and not stQuadraticComplexityTest and not stSStoreTest and not stZeroKnowledge'} # Long-running categories. rpc-state-quadratic: pytest -n 4 {posargs:tests/json-fixtures-over-rpc/test_rpc_fixtures.py -k 'GeneralStateTests and stQuadraticComplexityTest'} rpc-state-sstore: pytest -n 4 {posargs:tests/json-fixtures-over-rpc/test_rpc_fixtures.py -k 'GeneralStateTests and stSStoreTest'} diff --git a/trinity/rpc/modules/eth.py b/trinity/rpc/modules/eth.py index 23777c269d..42e5605c90 100644 --- a/trinity/rpc/modules/eth.py +++ b/trinity/rpc/modules/eth.py @@ -43,6 +43,9 @@ from eth.vm.spoof import ( SpoofTransaction, ) +from eth._utils.padding import ( + pad32, +) from trinity.chains.base import AsyncChainAPI from trinity.constants import ( @@ -214,7 +217,8 @@ async def getStorageAt(self, address: Address, position: int, at_block: Union[st state = await state_at_block(self.chain, at_block) stored_val = state.get_storage(address, position) - return encode_hex(int_to_big_endian(stored_val)) + + return encode_hex(pad32(int_to_big_endian(stored_val))) @format_params(decode_hex) async def getTransactionByHash(self,