diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index 6eef9ad81..27085d40a 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -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 diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index e4c869ded..f73531f38 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -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 diff --git a/scripts/phase0/build_spec.py b/scripts/phase0/build_spec.py index 98b1cad78..54adfdde7 100644 --- a/scripts/phase0/build_spec.py +++ b/scripts/phase0/build_spec.py @@ -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: diff --git a/scripts/phase0/function_puller.py b/scripts/phase0/function_puller.py index d0f3f66f1..fc7f9fb8c 100644 --- a/scripts/phase0/function_puller.py +++ b/scripts/phase0/function_puller.py @@ -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 diff --git a/test_libs/config_helpers/preset_loader/loader.py b/test_libs/config_helpers/preset_loader/loader.py index 043c58805..f37aca393 100644 --- a/test_libs/config_helpers/preset_loader/loader.py +++ b/test_libs/config_helpers/preset_loader/loader.py @@ -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 diff --git a/test_libs/gen_helpers/gen_base/gen_runner.py b/test_libs/gen_helpers/gen_base/gen_runner.py index 8a179b089..e36d48b8b 100644 --- a/test_libs/gen_helpers/gen_base/gen_runner.py +++ b/test_libs/gen_helpers/gen_base/gen_runner.py @@ -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})') diff --git a/test_libs/pyspec/eth2spec/debug/decode.py b/test_libs/pyspec/eth2spec/debug/decode.py new file mode 100644 index 000000000..aeac3924d --- /dev/null +++ b/test_libs/pyspec/eth2spec/debug/decode.py @@ -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") diff --git a/test_libs/pyspec/eth2spec/debug/encode.py b/test_libs/pyspec/eth2spec/debug/encode.py new file mode 100644 index 000000000..f50bc9d5e --- /dev/null +++ b/test_libs/pyspec/eth2spec/debug/encode.py @@ -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") + diff --git a/test_libs/pyspec/eth2spec/debug/jsonize.py b/test_libs/pyspec/eth2spec/debug/jsonize.py deleted file mode 100644 index 3ea6fe3f5..000000000 --- a/test_libs/pyspec/eth2spec/debug/jsonize.py +++ /dev/null @@ -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") diff --git a/test_libs/pyspec/eth2spec/phase0/state_transition.py b/test_libs/pyspec/eth2spec/phase0/state_transition.py index 59ff07d37..d869fc408 100644 --- a/test_libs/pyspec/eth2spec/phase0/state_transition.py +++ b/test_libs/pyspec/eth2spec/phase0/state_transition.py @@ -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) +