Skip to content

Commit 75be226

Browse files
committed
Support custom genesis file via EIP 1085
1 parent c6d3a8b commit 75be226

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1411
-368
lines changed

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ include requirements.txt
55

66
recursive-exclude * __pycache__
77
recursive-exclude * *.py[co]
8+
9+
include trinity/assets/*

eth/chains/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from .base import ( # noqa: F401
2-
AsyncChain,
32
Chain,
43
)
54
from .mainnet import ( # noqa: F401

eth/chains/base.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,6 @@ def __init__(self) -> None:
143143
def get_chaindb_class(cls) -> Type[BaseChainDB]:
144144
raise NotImplementedError("Chain classes must implement this method")
145145

146-
@classmethod
147-
def get_vm_configuration(cls) -> Tuple[Tuple[int, Type['BaseVM']], ...]:
148-
return cls.vm_configuration
149-
150146
#
151147
# Chain API
152148
#
@@ -918,39 +914,3 @@ def get_vm(self, at_header: BlockHeader=None) -> 'BaseVM':
918914
at_header = self.header
919915

920916
return super().get_vm(at_header)
921-
922-
923-
# This class is a work in progress; its main purpose is to define the API of an asyncio-compatible
924-
# Chain implementation.
925-
class AsyncChain(Chain):
926-
# TODO: this really belongs in the `trinity` module.
927-
928-
async def coro_import_block(self,
929-
block: BlockHeader,
930-
perform_validation: bool=True,
931-
) -> Tuple[BaseBlock, Tuple[BaseBlock, ...], Tuple[BaseBlock, ...]]:
932-
raise NotImplementedError()
933-
934-
async def coro_validate_chain(
935-
self,
936-
parent: BlockHeader,
937-
chain: Tuple[BlockHeader, ...],
938-
seal_check_random_sample_rate: int = 1) -> None:
939-
raise NotImplementedError()
940-
941-
async def coro_validate_receipt(self,
942-
receipt: Receipt,
943-
at_header: BlockHeader) -> None:
944-
raise NotImplementedError()
945-
946-
async def coro_get_block_by_hash(self,
947-
block_hash: Hash32) -> BaseBlock:
948-
raise NotImplementedError()
949-
950-
async def coro_get_block_by_header(self,
951-
header: BlockHeader) -> BaseBlock:
952-
raise NotImplementedError()
953-
954-
async def coro_get_canonical_block_by_number(self,
955-
block_number: BlockNumber) -> BaseBlock:
956-
raise NotImplementedError()

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"termcolor>=1.1.0,<2.0.0",
4949
"uvloop==0.11.2;platform_system=='Linux' or platform_system=='Darwin' or platform_system=='FreeBSD'",
5050
"websockets==5.0.1",
51+
"jsonschema==2.6.0",
5152
],
5253
'test': [
5354
"hypothesis==3.69.5",
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import pytest
2+
3+
from eth_utils import (
4+
decode_hex,
5+
to_int,
6+
)
7+
8+
from eth.db.atomic import AtomicDB
9+
from eth.vm.forks.constantinople import ConstantinopleVM
10+
from eth.vm.forks.homestead import HomesteadVM
11+
from eth.chains.mainnet import (
12+
MainnetChain,
13+
MAINNET_GENESIS_HEADER,
14+
)
15+
from eth.chains.ropsten import (
16+
RopstenChain,
17+
ROPSTEN_GENESIS_HEADER,
18+
)
19+
20+
from trinity.config import (
21+
ChainConfig,
22+
)
23+
from trinity.constants import (
24+
MAINNET_NETWORK_ID,
25+
ROPSTEN_NETWORK_ID,
26+
)
27+
from trinity.utils.db import MemoryDB
28+
from trinity.utils.eip1085 import validate_raw_eip1085_genesis_config
29+
30+
31+
def assert_vm_configuration_equal(left, right):
32+
assert len(left) == len(right), "Length mismatch"
33+
34+
for ((left_block, left_vm), (right_block, right_vm)) in zip(left, right):
35+
assert left_vm.fork is not None
36+
assert left_vm.fork == right_vm.fork
37+
assert left_block == right_block
38+
39+
if isinstance(left_vm, HomesteadVM):
40+
assert left_vm.support_dao_fork is right_vm.support_dao_fork
41+
assert left_vm.dao_fork_block_number == right_vm.dao_fork_block_number
42+
43+
44+
@pytest.mark.parametrize(
45+
'network_id',
46+
(MAINNET_NETWORK_ID, ROPSTEN_NETWORK_ID),
47+
)
48+
def test_chain_config_from_preconfigured_network(network_id):
49+
chain_config = ChainConfig.from_preconfigured_network(network_id)
50+
chain = chain_config.initialize_chain(AtomicDB(MemoryDB()))
51+
52+
if network_id == MAINNET_NETWORK_ID:
53+
assert chain_config.chain_id == MainnetChain.chain_id
54+
assert_vm_configuration_equal(chain_config.vm_configuration, MainnetChain.vm_configuration)
55+
assert chain.get_canonical_head() == MAINNET_GENESIS_HEADER
56+
elif network_id == ROPSTEN_NETWORK_ID:
57+
assert chain_config.chain_id == RopstenChain.chain_id
58+
assert_vm_configuration_equal(chain_config.vm_configuration, RopstenChain.vm_configuration)
59+
assert chain.get_canonical_head() == ROPSTEN_GENESIS_HEADER
60+
else:
61+
assert False, "Invariant: unreachable code path"
62+
63+
64+
EIP1085_GENESIS_CONFIG = {
65+
"version": "1",
66+
"params": {
67+
"miningMethod": "NoProof",
68+
"homesteadForkBlock": "0x00",
69+
"EIP150ForkBlock": "0x00",
70+
"EIP158ForkBlock": "0x00",
71+
"byzantiumForkBlock": "0x00",
72+
"constantinopleForkBlock": "0x00",
73+
"chainId": "0x04d2",
74+
},
75+
"genesis": {
76+
"nonce": "0x0000000000000042",
77+
"difficulty": "0x020000",
78+
"author": "0x0000000000000000000000000000000000000000",
79+
"timestamp": "0x00",
80+
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
81+
"gasLimit": "0x1388"
82+
}
83+
}
84+
85+
86+
def test_chain_config_eip1085_fixture_is_valid():
87+
# Sanity check in case this fixture is no longer actually valid against the
88+
# spec which has not been finalized at the time this was created.
89+
validate_raw_eip1085_genesis_config(EIP1085_GENESIS_CONFIG)
90+
91+
92+
def test_chain_config_from_eip1085_genesis_config():
93+
chain_config = ChainConfig.from_eip1085_genesis_config(EIP1085_GENESIS_CONFIG)
94+
95+
assert chain_config.chain_id == 1234
96+
assert chain_config.vm_configuration == ((0, ConstantinopleVM),)
97+
98+
params = chain_config.genesis_params
99+
100+
assert params.nonce == decode_hex(EIP1085_GENESIS_CONFIG['genesis']['nonce'])
101+
assert params.difficulty == to_int(hexstr=EIP1085_GENESIS_CONFIG['genesis']['difficulty'])
102+
assert params.coinbase == decode_hex(EIP1085_GENESIS_CONFIG['genesis']['author'])
103+
assert params.timestamp == to_int(hexstr=EIP1085_GENESIS_CONFIG['genesis']['timestamp'])
104+
assert params.extra_data == decode_hex(EIP1085_GENESIS_CONFIG['genesis']['extraData'])
105+
assert params.gas_limit == to_int(hexstr=EIP1085_GENESIS_CONFIG['genesis']['gasLimit'])
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import pytest
2+
3+
from eth.vm.forks import (
4+
TangerineWhistleVM,
5+
FrontierVM,
6+
HomesteadVM,
7+
SpuriousDragonVM,
8+
ByzantiumVM,
9+
ConstantinopleVM,
10+
)
11+
12+
from trinity.utils.eip1085 import extract_vm_configuration
13+
14+
15+
def wrap_config(v):
16+
return {'params': v}
17+
18+
19+
CONSTANTINOPLE_AT_0 = wrap_config({
20+
"homesteadForkBlock": "0x00",
21+
"EIP150ForkBlock": "0x00",
22+
"EIP158ForkBlock": "0x00",
23+
"byzantiumForkBlock": "0x00",
24+
"constantinopleForkBlock": "0x00",
25+
})
26+
CONSTANTINOPLE_AT_0_CONFIG = (
27+
(0, ConstantinopleVM),
28+
)
29+
30+
CONSTANTINOPLE_AT_5 = wrap_config({
31+
"homesteadForkBlock": "0x00",
32+
"EIP150ForkBlock": "0x00",
33+
"EIP158ForkBlock": "0x00",
34+
"byzantiumForkBlock": "0x00",
35+
"constantinopleForkBlock": "0x05",
36+
})
37+
CONSTANTINOPLE_AT_5_CONFIG = (
38+
(0, ByzantiumVM),
39+
(5, ConstantinopleVM),
40+
)
41+
42+
BYZANTIUM_AT_0 = wrap_config({
43+
"homesteadForkBlock": "0x00",
44+
"EIP150ForkBlock": "0x00",
45+
"EIP158ForkBlock": "0x00",
46+
"byzantiumForkBlock": "0x00",
47+
})
48+
BYZANTIUM_AT_0_CONFIG = (
49+
(0, ByzantiumVM),
50+
)
51+
52+
BYZANTIUM_AT_5 = wrap_config({
53+
"homesteadForkBlock": "0x00",
54+
"EIP150ForkBlock": "0x00",
55+
"EIP158ForkBlock": "0x00",
56+
"byzantiumForkBlock": "0x05",
57+
})
58+
BYZANTIUM_AT_5_CONFIG = (
59+
(0, SpuriousDragonVM),
60+
(5, ByzantiumVM),
61+
)
62+
63+
SPURIOUS_AT_0 = wrap_config({
64+
"homesteadForkBlock": "0x00",
65+
"EIP150ForkBlock": "0x00",
66+
"EIP158ForkBlock": "0x00",
67+
})
68+
SPURIOUS_AT_0_CONFIG = (
69+
(0, SpuriousDragonVM),
70+
)
71+
72+
SPURIOUS_AT_5 = wrap_config({
73+
"homesteadForkBlock": "0x00",
74+
"EIP150ForkBlock": "0x00",
75+
"EIP158ForkBlock": "0x05",
76+
})
77+
SPURIOUS_AT_5_CONFIG = (
78+
(0, TangerineWhistleVM),
79+
(5, SpuriousDragonVM),
80+
)
81+
82+
TANGERINE_AT_0 = wrap_config({
83+
"homesteadForkBlock": "0x00",
84+
"EIP150ForkBlock": "0x00",
85+
})
86+
TANGERINE_AT_0_CONFIG = (
87+
(0, TangerineWhistleVM),
88+
)
89+
90+
TANGERINE_AT_5 = wrap_config({
91+
"homesteadForkBlock": "0x00",
92+
"EIP150ForkBlock": "0x05",
93+
})
94+
TANGERINE_AT_5_CONFIG = (
95+
(0, HomesteadVM),
96+
(5, TangerineWhistleVM),
97+
)
98+
99+
HOMESTEAD_AT_0 = wrap_config({
100+
"homesteadForkBlock": "0x00",
101+
})
102+
HOMESTEAD_AT_0_CONFIG = (
103+
(0, HomesteadVM),
104+
)
105+
106+
HOMESTEAD_AT_5 = wrap_config({
107+
"homesteadForkBlock": "0x05",
108+
})
109+
HOMESTEAD_AT_5_CONFIG = (
110+
(0, FrontierVM),
111+
(5, HomesteadVM),
112+
)
113+
114+
FRONTIER_AT_0 = wrap_config({
115+
"frontierForkBlock": "0x00",
116+
})
117+
FRONTIER_AT_0_CONFIG = (
118+
(0, FrontierVM),
119+
)
120+
121+
122+
@pytest.mark.parametrize(
123+
'genesis_config,expected',
124+
(
125+
(CONSTANTINOPLE_AT_0, CONSTANTINOPLE_AT_0_CONFIG),
126+
(CONSTANTINOPLE_AT_5, CONSTANTINOPLE_AT_5_CONFIG),
127+
(BYZANTIUM_AT_0, BYZANTIUM_AT_0_CONFIG),
128+
(BYZANTIUM_AT_5, BYZANTIUM_AT_5_CONFIG),
129+
(SPURIOUS_AT_0, SPURIOUS_AT_0_CONFIG),
130+
(SPURIOUS_AT_5, SPURIOUS_AT_5_CONFIG),
131+
(TANGERINE_AT_0, TANGERINE_AT_0_CONFIG),
132+
(TANGERINE_AT_5, TANGERINE_AT_5_CONFIG),
133+
(HOMESTEAD_AT_0, HOMESTEAD_AT_0_CONFIG),
134+
(HOMESTEAD_AT_5, HOMESTEAD_AT_5_CONFIG),
135+
(FRONTIER_AT_0, FRONTIER_AT_0_CONFIG),
136+
),
137+
)
138+
def test_eip1085_extract_vm_configuration(genesis_config, expected):
139+
actual = extract_vm_configuration(genesis_config)
140+
assert actual == expected
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import pytest
2+
3+
from eth_utils import (
4+
to_int,
5+
to_hex,
6+
to_bytes,
7+
to_canonical_address,
8+
)
9+
from eth_utils.curried import (
10+
hexstr_if_str,
11+
)
12+
from eth_utils.toolz import (
13+
merge,
14+
valmap,
15+
)
16+
17+
from trinity.utils.eip1085 import (
18+
GenesisParams,
19+
extract_genesis_params,
20+
)
21+
22+
23+
PARAMS_DEFAULTS = {
24+
"nonce": "0x0000000000000042",
25+
"difficulty": "0x020000",
26+
"author": "0x0000000000000000000000000000000000000000",
27+
"timestamp": "0x00",
28+
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
29+
"gasLimit": "0x1388"
30+
}
31+
N_PARAMS_DEFAULTS = {
32+
"nonce": to_bytes(hexstr=PARAMS_DEFAULTS['nonce']),
33+
"difficulty": to_int(hexstr=PARAMS_DEFAULTS['difficulty']),
34+
"coinbase": to_canonical_address(PARAMS_DEFAULTS['author']),
35+
"timestamp": to_int(hexstr=PARAMS_DEFAULTS['timestamp']),
36+
"extra_data": to_bytes(hexstr=PARAMS_DEFAULTS['extraData']),
37+
"gas_limit": to_int(hexstr=PARAMS_DEFAULTS['gasLimit']),
38+
}
39+
40+
41+
ADDRESS = b'12345678901234567890'
42+
HASH32 = b'unicornsrainbows' * 2
43+
44+
45+
def _mk_raw_params(**kwargs):
46+
return {
47+
'genesis': merge(PARAMS_DEFAULTS, valmap(hexstr_if_str(to_hex), kwargs)),
48+
}
49+
50+
51+
def _mk_params(**kwargs):
52+
return GenesisParams(**merge(N_PARAMS_DEFAULTS, kwargs))
53+
54+
55+
@pytest.mark.parametrize(
56+
'raw_genesis_config,expected',
57+
(
58+
(_mk_raw_params(), _mk_params()),
59+
(_mk_raw_params(nonce=b'unicorns'), _mk_params(nonce=b'unicorns')),
60+
(_mk_raw_params(difficulty=1234), _mk_params(difficulty=1234)),
61+
(_mk_raw_params(author=ADDRESS), _mk_params(coinbase=ADDRESS)),
62+
(_mk_raw_params(timestamp=1234), _mk_params(timestamp=1234)),
63+
(_mk_raw_params(extraData=HASH32), _mk_params(extra_data=HASH32)),
64+
(_mk_raw_params(gasLimit=1234), _mk_params(gas_limit=1234)),
65+
),
66+
)
67+
def test_extract_genesis_params(raw_genesis_config, expected):
68+
actual = extract_genesis_params(raw_genesis_config)
69+
assert actual == expected

0 commit comments

Comments
 (0)