diff --git a/eth2/beacon/tools/misc/ssz_vector.py b/eth2/beacon/tools/misc/ssz_vector.py index 41270e8bfd..f90a8b47d4 100644 --- a/eth2/beacon/tools/misc/ssz_vector.py +++ b/eth2/beacon/tools/misc/ssz_vector.py @@ -7,7 +7,7 @@ from eth2.beacon.types.states import BeaconState -def override_vector_length(config: Eth2Config) -> None: +def override_vector_lengths(config: Eth2Config) -> None: state_vector_dict = { "latest_randao_mixes": config.LATEST_RANDAO_MIXES_LENGTH, "latest_crosslinks": config.SHARD_COUNT, diff --git a/eth2/beacon/types/attestation_data_and_custody_bits.py b/eth2/beacon/types/attestation_data_and_custody_bits.py index 2cae03c398..5cbfd9bfc8 100644 --- a/eth2/beacon/types/attestation_data_and_custody_bits.py +++ b/eth2/beacon/types/attestation_data_and_custody_bits.py @@ -2,9 +2,6 @@ from ssz.sedes import ( boolean, ) -from eth_typing import ( - Hash32, -) from .attestation_data import ( AttestationData, @@ -28,9 +25,3 @@ def __init__(self, data=data, custody_bit=custody_bit, ) - - _root = None - - @property - def root(self) -> Hash32: - return super().root diff --git a/eth2/beacon/types/block_headers.py b/eth2/beacon/types/block_headers.py index dc799ae092..1759d71b0a 100644 --- a/eth2/beacon/types/block_headers.py +++ b/eth2/beacon/types/block_headers.py @@ -57,17 +57,3 @@ def __repr__(self) -> str: self.slot, encode_hex(self.signing_root)[2:10], ) - - _root = None - - @property - def root(self) -> Hash32: - return super().root - - _signing_root = None - - @property - def signing_root(self) -> Hash32: - if self._signing_root is None: - self._signing_root = super().signing_root - return Hash32(self._signing_root) diff --git a/eth2/beacon/types/blocks.py b/eth2/beacon/types/blocks.py index 46645a6c4d..15482306bb 100644 --- a/eth2/beacon/types/blocks.py +++ b/eth2/beacon/types/blocks.py @@ -126,12 +126,6 @@ def cast_block_body(cls, transfers=body.transfers, ) - _root = None - - @property - def root(self) -> Hash32: - return super().root - class BaseBeaconBlock(ssz.SignedSerializable, Configurable, ABC): fields = [ @@ -171,20 +165,6 @@ def __repr__(self) -> str: encode_hex(self.signing_root)[2:10], ) - _root = None - - @property - def root(self) -> Hash32: - return super().root - - _signing_root = None - - @property - def signing_root(self) -> Hash32: - if self._signing_root is None: - self._signing_root = super().signing_root - return Hash32(self._signing_root) - @property def num_attestations(self) -> int: return len(self.body.attestations) diff --git a/eth2/beacon/types/crosslink_records.py b/eth2/beacon/types/crosslink_records.py index 8a0fd688bf..de4cbe862f 100644 --- a/eth2/beacon/types/crosslink_records.py +++ b/eth2/beacon/types/crosslink_records.py @@ -28,9 +28,3 @@ def __init__(self, epoch=epoch, crosslink_data_root=crosslink_data_root, ) - - _root = None - - @property - def root(self) -> Hash32: - return super().root diff --git a/eth2/beacon/types/deposit_input.py b/eth2/beacon/types/deposit_input.py index 75e44802f3..4f2acfc251 100644 --- a/eth2/beacon/types/deposit_input.py +++ b/eth2/beacon/types/deposit_input.py @@ -33,18 +33,3 @@ def __init__(self, withdrawal_credentials=withdrawal_credentials, signature=signature, ) - - _root = None - - @property - def root(self) -> Hash32: - return super().root - - _signing_root = None - - @property - def signing_root(self) -> Hash32: - # Use SSZ built-in function - if self._signing_root is None: - self._signing_root = super().signing_root - return self._signing_root diff --git a/eth2/beacon/types/historical_batch.py b/eth2/beacon/types/historical_batch.py index c81505454a..bd1bdc4d4d 100644 --- a/eth2/beacon/types/historical_batch.py +++ b/eth2/beacon/types/historical_batch.py @@ -30,9 +30,3 @@ def __init__(self, block_roots=block_roots, state_roots=state_roots, ) - - _root = None - - @property - def root(self) -> Hash32: - return super().root diff --git a/eth2/beacon/types/slashable_attestations.py b/eth2/beacon/types/slashable_attestations.py index 0f95a254d0..682342b457 100644 --- a/eth2/beacon/types/slashable_attestations.py +++ b/eth2/beacon/types/slashable_attestations.py @@ -52,12 +52,6 @@ def __init__(self, aggregate_signature, ) - _root = None - - @property - def root(self) -> Hash32: - return super().root - @property def are_validator_indices_ascending(self) -> bool: for i in range(len(self.validator_indices) - 1): diff --git a/eth2/beacon/types/states.py b/eth2/beacon/types/states.py index 868d8b35da..b0789afde3 100644 --- a/eth2/beacon/types/states.py +++ b/eth2/beacon/types/states.py @@ -185,12 +185,6 @@ def __repr__(self) -> str: encode_hex(self.root)[2:10], ) - _root = None - - @property - def root(self) -> Hash32: - return super().root - @property def num_validators(self) -> int: return len(self.validator_registry) diff --git a/eth2/beacon/types/transfers.py b/eth2/beacon/types/transfers.py index e2c498d737..22df88ff5e 100644 --- a/eth2/beacon/types/transfers.py +++ b/eth2/beacon/types/transfers.py @@ -1,7 +1,6 @@ from eth_typing import ( BLSPubkey, BLSSignature, - Hash32, ) import ssz from ssz.sedes import ( @@ -54,9 +53,3 @@ def __init__(self, pubkey=pubkey, signature=signature, ) - - _root = None - - @property - def root(self) -> Hash32: - return super().root diff --git a/eth2/beacon/types/voluntary_exits.py b/eth2/beacon/types/voluntary_exits.py index 349438fb3b..2056d74a2f 100644 --- a/eth2/beacon/types/voluntary_exits.py +++ b/eth2/beacon/types/voluntary_exits.py @@ -1,6 +1,5 @@ from eth_typing import ( BLSSignature, - Hash32, ) import ssz from ssz.sedes import ( @@ -35,12 +34,3 @@ def __init__(self, validator_index, signature, ) - - _signing_root = None - - @property - def signing_root(self) -> Hash32: - # Use SSZ built-in function - if self._signing_root is None: - self._signing_root = super().signing_root - return self._signing_root diff --git a/tests/eth2/beacon/conftest.py b/tests/eth2/beacon/conftest.py index e34fe0dc19..1b309ee416 100644 --- a/tests/eth2/beacon/conftest.py +++ b/tests/eth2/beacon/conftest.py @@ -30,7 +30,7 @@ get_genesis_block, ) from eth2.beacon.tools.misc.ssz_vector import ( - override_vector_length, + override_vector_lengths, ) from eth2.beacon.types.blocks import ( BeaconBlockBody, @@ -60,8 +60,8 @@ # SSZ @pytest.fixture(scope="function", autouse=True) -def override_length(config): - override_vector_length(config) +def override_lengths(config): + override_vector_lengths(config) @pytest.fixture(scope="session") diff --git a/tests/eth2/beacon/state-fixtures/test_minimal_state.py b/tests/eth2/beacon/state-fixtures/test_minimal_state.py new file mode 100644 index 0000000000..f47c81be86 --- /dev/null +++ b/tests/eth2/beacon/state-fixtures/test_minimal_state.py @@ -0,0 +1,138 @@ +import os +import yaml +import pytest + +from py_ecc import bls +import ssz + +from eth2.configs import ( + Eth2Config, +) +from eth2.beacon.db.chain import BeaconChainDB +from eth2.beacon.tools.misc.ssz_vector import ( + override_vector_lengths, +) +from eth2.beacon.types.states import BeaconState +from eth2.beacon.state_machines.forks.serenity.blocks import SerenityBeaconBlock +from eth2.beacon.state_machines.forks.serenity import ( + SerenityStateMachine, +) + +# Test files +ROOT_PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) + +BASE_FIXTURE_PATH = os.path.join(ROOT_PROJECT_DIR, '../../', 'eth2-fixtures', 'state') + +FILE_NAMES = [ + "sanity-check_small-config_32-vals.yaml", + "sanity-check_default-config_100-vals.yaml", +] + +# +# Mock bls verification for these tests +# +bls = bls + + +def mock_bls_verify(message_hash, pubkey, signature, domain): + return True + + +def mock_bls_verify_multiple(pubkeys, + message_hashes, + signature, + domain): + return True + + +@pytest.fixture(autouse=True) +def mock_bls(mocker, request): + if 'noautofixt' in request.keywords: + return + + mocker.patch('py_ecc.bls.verify', side_effect=mock_bls_verify) + mocker.patch('py_ecc.bls.verify_multiple', side_effect=mock_bls_verify_multiple) + + +def get_test_case(file_names): + all_test_cases = [] + for file_name in file_names: + with open(BASE_FIXTURE_PATH + '/' + file_name, 'U') as f: + # TODO: `proof_of_possession` is used in v0.5.1 spec and will be renamed to `signature` + # Trinity renamed it ahead due to py-ssz signing_root requirements + new_text = f.read().replace('proof_of_possession', 'signature') + try: + data = yaml.load(new_text) + all_test_cases += data['test_cases'] + except yaml.YAMLError as exc: + print(exc) + return all_test_cases + + +test_cases = get_test_case(FILE_NAMES) + + +@pytest.mark.parametrize("test_case", test_cases) +def test_state(base_db, test_case): + test_name = test_case['name'] + if test_name == 'test_transfer': + print('skip') + else: + execute_state_transtion(test_case, base_db) + + +def generate_config_by_dict(dict_config): + dict_config['DEPOSIT_CONTRACT_ADDRESS'] = b'\x00' * 20 + for key in list(dict_config): + if 'DOMAIN_' in key in key: + # DOMAIN is defined in SignatureDomain + dict_config.pop(key, None) + return Eth2Config(**dict_config) + + +def execute_state_transtion(test_case, base_db): + test_name = test_case['name'] + dict_config = test_case['config'] + verify_signatures = test_case['verify_signatures'] + dict_initial_state = test_case['initial_state'] + dict_blocks = test_case['blocks'] + dict_expected_state = test_case['expected_state'] + + # TODO: make it case by case + assert verify_signatures is False + + print(f"[{test_name}]") + + # Set config + config = generate_config_by_dict(dict_config) + + # Set Vector fields + override_vector_lengths(config) + + # Set pre_state + pre_state = ssz.tools.from_formatted_dict(dict_initial_state, BeaconState) + + # Set blocks + blocks = () + for dict_block in dict_blocks: + block = ssz.tools.from_formatted_dict(dict_block, SerenityBeaconBlock) + blocks += (block,) + + sm_class = SerenityStateMachine.configure( + __name__='SerenityStateMachineForTesting', + config=config, + ) + chaindb = BeaconChainDB(base_db) + + post_state = pre_state.copy() + for block in blocks: + sm = sm_class(chaindb, None, post_state) + post_state, _ = sm.import_block(block) + + # Use dict diff, easier to see the diff + dict_post_state = ssz.tools.to_formatted_dict(post_state, BeaconState) + + for key, value in dict_expected_state.items(): + if isinstance(value, list): + value = tuple(value) + assert dict_post_state[key] == value diff --git a/tests/plugins/eth2/beacon/test_validator.py b/tests/plugins/eth2/beacon/test_validator.py index f0d8e75ca8..fdb74ba9f8 100644 --- a/tests/plugins/eth2/beacon/test_validator.py +++ b/tests/plugins/eth2/beacon/test_validator.py @@ -39,7 +39,7 @@ create_mock_genesis, ) from eth2.beacon.tools.misc.ssz_vector import ( - override_vector_length, + override_vector_lengths, ) from eth2.beacon.tools.builder.proposer import ( _get_proposer_index, @@ -83,7 +83,7 @@ beacon_chain_config = BeaconChainConfig(chain_name='TestTestTest', genesis_data=genesis_data) chain_class = beacon_chain_config.beacon_chain_class -override_vector_length(XIAO_LONG_BAO_CONFIG) +override_vector_lengths(XIAO_LONG_BAO_CONFIG) class FakeProtocol: