Work for new pyspec based test generators

This commit is contained in:
protolambda 2019-04-07 23:36:05 +10:00
parent fea40da6fe
commit db91c7fe9e
No known key found for this signature in database
GPG Key ID: EC89FDBB2B4C7623
10 changed files with 105 additions and 73 deletions

View File

@ -22,7 +22,7 @@ SHUFFLE_ROUND_COUNT: 90
# Deposit contract
# ---------------------------------------------------------------
# **TBD**
DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123567890123456789012357890
DEPOSIT_CONTRACT_ADDRESS: 0x12345678901235678901234567890123567890
# 2**5 ` (= 32)
DEPOSIT_CONTRACT_TREE_DEPTH: 32

View File

@ -22,7 +22,7 @@ SHUFFLE_ROUND_COUNT: 90
# Deposit contract
# ---------------------------------------------------------------
# **TBD**
DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123567890123456789012357890
DEPOSIT_CONTRACT_ADDRESS: 0x12345678901235678901234567890123567890
# 2**5 ` (= 32)
DEPOSIT_CONTRACT_TREE_DEPTH: 32
@ -62,8 +62,8 @@ SLOTS_PER_EPOCH: 8
MIN_SEED_LOOKAHEAD: 1
# 2**2 ` (= 4) epochs 25.6 minutes
ACTIVATION_EXIT_DELAY: 4
# 2**4 ` (= 16) epochs ~1.7 hours
EPOCHS_PER_ETH1_VOTING_PERIOD: 16
# [customized] higher frequency new deposits from eth1 for testing
EPOCHS_PER_ETH1_VOTING_PERIOD: 2
# [customized] smaller state
SLOTS_PER_HISTORICAL_ROOT: 64
# 2**8 ` (= 256) epochs ~27 hours

View File

@ -83,11 +83,14 @@ def hash(x):
# Access to overwrite spec constants based on configuration
def apply_constants_preset(preset: Dict[str, Any]):
global_vars = globals()
for k, v in preset:
for k, v in preset.items():
global_vars[k] = v
# Deal with derived constants
GENESIS_EPOCH = slot_to_epoch(GENESIS_SLOT)
global_vars['GENESIS_EPOCH'] = slot_to_epoch(GENESIS_SLOT)
# Initialize SSZ types again, to account for changed lengths
init_SSZ_types()
""")
with open(outfile, 'w') as out:

View File

@ -6,7 +6,8 @@ def get_spec(file_name) -> List[str]:
code_lines = []
pulling_from = None
current_name = None
processing_typedef = False
current_typedef = None
type_defs = []
for linenum, line in enumerate(open(sys.argv[1]).readlines()):
line = line.rstrip()
if pulling_from is None and len(line) > 0 and line[0] == '#' and line[-1] == '`':
@ -18,21 +19,26 @@ def get_spec(file_name) -> List[str]:
if pulling_from is None:
pulling_from = linenum
else:
if processing_typedef:
if current_typedef is not None:
assert code_lines[-1] == '}'
code_lines[-1] = '})'
current_typedef[-1] = '})'
type_defs.append((current_name, current_typedef))
pulling_from = None
processing_typedef = False
current_typedef = None
else:
if pulling_from == linenum and line == '{':
code_lines.append('%s = SSZType({' % current_name)
processing_typedef = True
current_typedef = ['global_vars["%s"] = SSZType({' % current_name]
elif pulling_from is not None:
# Add some whitespace between functions
if line[:3] == 'def':
code_lines.append("")
code_lines.append("")
code_lines.append('')
code_lines.append('')
code_lines.append(line)
# Remember type def lines
if current_typedef is not None:
current_typedef.append(line)
elif pulling_from is None and len(line) > 0 and line[0] == '|':
row = line[1:].split('|')
if len(row) >= 2:
@ -48,4 +54,12 @@ def get_spec(file_name) -> List[str]:
eligible = False
if eligible:
code_lines.append(row[0] + ' = ' + (row[1].replace('**TBD**', '0x1234567890123567890123456789012357890')))
# Build type-def re-initialization
code_lines.append('')
code_lines.append('def init_SSZ_types():')
code_lines.append(' global_vars = globals()')
for ssz_type_name, ssz_type in type_defs:
code_lines.append('')
for type_line in ssz_type:
code_lines.append(' ' + type_line)
return code_lines

View File

@ -14,5 +14,12 @@ def load_presets(configs_dir, presets_name) -> Dict[str, Any]:
:return: Dictionary, mapping of constant-name -> constant-value
"""
path = Path(join(configs_dir, 'constant_presets', presets_name+'.yaml'))
yaml = YAML(typ='safe')
return yaml.load(path)
yaml = YAML(typ='base')
loaded = yaml.load(path)
out = dict()
for k, v in loaded.items():
if v.startswith("0x"):
out[k] = bytes.fromhex(v[2:])
else:
out[k] = int(v)
return out

View File

@ -90,6 +90,7 @@ def run_generator(generator_name, suite_creators: List[TestSuiteCreator]):
file_mode = "w"
yaml = YAML(pure=True)
yaml.default_flow_style = None
print(f"Generating tests for {generator_name}, creating {len(suite_creators)} test suite files...")
print(f"Reading config presets and fork timelines from {args.configs_path}")
@ -98,7 +99,8 @@ def run_generator(generator_name, suite_creators: List[TestSuiteCreator]):
handler_output_dir = Path(output_dir) / Path(handler)
try:
handler_output_dir.mkdir()
if not handler_output_dir.exists():
handler_output_dir.mkdir()
except FileNotFoundError as e:
sys.exit(f'Error when creating handler dir {handler} for test "{suite["title"]}" ({e})')

View File

@ -0,0 +1,28 @@
from eth2spec.utils.minimal_ssz import hash_tree_root
def decode(json, typ):
if isinstance(typ, str) and typ[:4] == 'uint':
return json
elif typ == 'bool':
assert json in (True, False)
return json
elif isinstance(typ, list):
return [decode(element, typ[0]) for element in json]
elif isinstance(typ, str) and typ[:4] == 'byte':
return bytes.fromhex(json[2:])
elif hasattr(typ, 'fields'):
temp = {}
for field, subtype in typ.fields.items():
temp[field] = decode(json[field], subtype)
if field + "_hash_tree_root" in json:
assert(json[field + "_hash_tree_root"][2:] ==
hash_tree_root(temp[field], subtype).hex())
ret = typ(**temp)
if "hash_tree_root" in json:
assert(json["hash_tree_root"][2:] ==
hash_tree_root(ret, typ).hex())
return ret
else:
print(json, typ)
raise Exception("Type not recognized")

View File

@ -0,0 +1,26 @@
from eth2spec.utils.minimal_ssz import hash_tree_root
def encode(value, typ, include_hash_tree_roots=False):
if isinstance(typ, str) and typ[:4] == 'uint':
return value
elif typ == 'bool':
assert value in (True, False)
return value
elif isinstance(typ, list):
return [encode(element, typ[0], include_hash_tree_roots) for element in value]
elif isinstance(typ, str) and typ[:4] == 'byte':
return '0x' + value.hex()
elif hasattr(typ, 'fields'):
ret = {}
for field, subtype in typ.fields.items():
ret[field] = encode(getattr(value, field), subtype, include_hash_tree_roots)
if include_hash_tree_roots:
ret[field + "_hash_tree_root"] = '0x' + hash_tree_root(getattr(value, field), subtype).hex()
if include_hash_tree_roots:
ret["hash_tree_root"] = '0x' + hash_tree_root(value, typ).hex()
return ret
else:
print(value, typ)
raise Exception("Type not recognized")

View File

@ -1,52 +0,0 @@
from eth2spec.utils.minimal_ssz import hash_tree_root
def jsonize(value, typ, include_hash_tree_roots=False):
if isinstance(typ, str) and typ[:4] == 'uint':
return value
elif typ == 'bool':
assert value in (True, False)
return value
elif isinstance(typ, list):
return [jsonize(element, typ[0], include_hash_tree_roots) for element in value]
elif isinstance(typ, str) and typ[:4] == 'byte':
return '0x' + value.hex()
elif hasattr(typ, 'fields'):
ret = {}
for field, subtype in typ.fields.items():
ret[field] = jsonize(getattr(value, field), subtype, include_hash_tree_roots)
if include_hash_tree_roots:
ret[field + "_hash_tree_root"] = '0x' + hash_tree_root(getattr(value, field), subtype).hex()
if include_hash_tree_roots:
ret["hash_tree_root"] = '0x' + hash_tree_root(value, typ).hex()
return ret
else:
print(value, typ)
raise Exception("Type not recognized")
def dejsonize(json, typ):
if isinstance(typ, str) and typ[:4] == 'uint':
return json
elif typ == 'bool':
assert json in (True, False)
return json
elif isinstance(typ, list):
return [dejsonize(element, typ[0]) for element in json]
elif isinstance(typ, str) and typ[:4] == 'byte':
return bytes.fromhex(json[2:])
elif hasattr(typ, 'fields'):
temp = {}
for field, subtype in typ.fields.items():
temp[field] = dejsonize(json[field], subtype)
if field + "_hash_tree_root" in json:
assert(json[field + "_hash_tree_root"][2:] ==
hash_tree_root(temp[field], subtype).hex())
ret = typ(**temp)
if "hash_tree_root" in json:
assert(json["hash_tree_root"][2:] ==
hash_tree_root(ret, typ).hex())
return ret
else:
print(json, typ)
raise Exception("Type not recognized")

View File

@ -99,13 +99,17 @@ def process_epoch_transition(state: BeaconState) -> None:
spec.finish_epoch_update(state)
def state_transition(state: BeaconState,
block: BeaconBlock,
verify_state_root: bool=False) -> BeaconState:
while state.slot < block.slot:
def state_transition_to(state: BeaconState, up_to: int) -> BeaconState:
while state.slot < up_to:
spec.cache_state(state)
if (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0:
process_epoch_transition(state)
spec.advance_slot(state)
if block.slot == state.slot:
process_block(state, block, verify_state_root)
def state_transition(state: BeaconState,
block: BeaconBlock,
verify_state_root: bool=False) -> BeaconState:
state_transition_to(state, block.slot)
process_block(state, block, verify_state_root)