class HistoricalBatch(ssz.Serializable): fields = [ ('block_roots', Vector(bytes32, 1)), ('state_roots', Vector(bytes32, 1)), ] def __init__(self, *, block_roots: Sequence[Hash32] = default_tuple, state_roots: Sequence[Hash32] = default_tuple, config: Eth2Config = None) -> None: if config: # try to provide sane defaults if block_roots == default_tuple: block_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) if state_roots == default_tuple: state_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) super().__init__( block_roots=block_roots, state_roots=state_roots, )
class HistoricalBatch(ssz.Serializable): fields = [ # Block roots ('block_roots', Vector(bytes32, 1)), # State roots ('state_roots', Vector(bytes32, 1)), ] def __init__(self, *, block_roots: Sequence[Hash32], state_roots: Sequence[Hash32]) -> None: super().__init__( block_roots=block_roots, state_roots=state_roots, )
def test_byte_vector(value): byte_vector = ByteVector(len(value)) serialized_value = ssz.encode(value, byte_vector) assert serialized_value == ssz.encode( tuple(bytes([byte_value]) for byte_value in value), Vector(byte, len(value))) assert ssz.decode(serialized_value, byte_vector) == value
def test_tuple_of_static_sized_entries(value, serialized): sedes = Vector(uint8, len(value)) assert encode_hex(ssz.encode(value, sedes)) == serialized decoded = ssz.decode(decode_hex(serialized), sedes) assert isinstance(decoded, HashableVector) assert tuple(decoded) == value assert decoded.sedes == sedes
class Deposit(ssz.Serializable): """ A :class:`~eth2.beacon.types.deposits.Deposit` contains the data represented by an instance of :class:`~eth2.beacon.types.deposit_data.DepositData`, along with a Merkle proof (``branch`` and ``index``) that can be used to verify inclusion in the canonical deposit tree. """ fields = [ # Merkle branch in the deposit tree ('proof', Vector(bytes32, 1)), # Index in the deposit tree ('index', uint64), # Deposit data ('deposit_data', DepositData), ] def __init__(self, proof: Sequence[Hash32], index: int, deposit_data: DepositData)-> None: super().__init__( proof, index, deposit_data, )
def parse_type_definition(type_definition): error_message = f"Could not parse type definition {type_definition}" if isinstance(type_definition, str): try: sedes = sedes_by_name[type_definition] except KeyError: raise ValueError(error_message) else: return sedes elif isinstance(type_definition, Sequence): if len(type_definition) == 1: return List(parse_type_definition(type_definition[0])) elif len(type_definition) == 2: element_type = parse_type_definition(type_definition[0]) try: length = int(type_definition[1]) except ValueError: raise ValueError(error_message) return Vector(element_type, length) else: raise ValueError(error_message) elif isinstance(type_definition, Mapping): return Container(tuple( (field_name, parse_type_definition(field_type)) for field_name, field_type in type_definition.items() )) else: raise ValueError(error_message)
def test_list_of_dynamic_sized_entries(value, serialized): sedes = Vector(List(uint8, 2**32), len(value)) assert encode_hex(ssz.encode(value, sedes)) == serialized decoded = ssz.decode(decode_hex(serialized), sedes) assert isinstance(decoded, HashableVector) assert tuple(tuple(element) for element in decoded) == value assert decoded.sedes == sedes
class State(Serializable): fields = [ ("validators", List(Validator, VALIDATOR_REGISTRY_LIMIT)), ("balances", List(uint64, VALIDATOR_REGISTRY_LIMIT)), ("randao_mixes", Vector(bytes32, EPOCHS_PER_HISTORICAL_VECTOR)), ("latest_block_header", BeaconBlockHeader), ("eth1_data", Eth1Data), ]
def general_vector_sedes_and_values_st(draw, element_sedes_and_elements, size=None): element_sedes, elements = element_sedes_and_elements if size is None: size = draw(st.integers(min_value=1, max_value=10)) sedes = Vector(length=size, element_sedes=element_sedes) values = st.builds(tuple, st.lists(elements, min_size=size, max_size=size)) return sedes, values
class HistoricalBatch(HashableContainer): fields = [("block_roots", Vector(bytes32, 1)), ("state_roots", Vector(bytes32, 1))] @classmethod def create( cls: Type[THistoricalBatch], *, block_roots: Sequence[Root] = default_tuple, state_roots: Sequence[Hash32] = default_tuple, config: Eth2Config = None ) -> THistoricalBatch: if config: # try to provide sane defaults if block_roots == default_tuple: block_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_ROOT ) if state_roots == default_tuple: state_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32 ) return super().create(block_roots=block_roots, state_roots=state_roots)
class Deposit(ssz.Serializable): """ A :class:`~eth2.beacon.types.deposits.Deposit` contains the data represented by an instance of :class:`~eth2.beacon.types.deposit_data.DepositData`, along with a Merkle proof that can be used to verify inclusion in the canonical deposit tree. """ fields = [ # Merkle path to deposit root ("proof", Vector(bytes32, DEPOSIT_PROOF_VECTOR_SIZE)), ("data", DepositData), ] def __init__( self, proof: Sequence[Hash32] = default_proof_tuple, data: DepositData = default_deposit_data, ) -> None: super().__init__(proof, data) def __repr__(self) -> str: return f"<Deposit hash_tree_root: {encode_hex(self.hash_tree_root)[0:8]} data: {self.data}>"
def test_vector_of_basics(serialized_uints128, result): sedes = Vector(uint128, len(serialized_uints128)) int_values = tuple(ssz.decode(value, uint128) for value in serialized_uints128) assert ssz.get_hash_tree_root(int_values, sedes) == result
class BeaconState(ssz.Serializable): fields = [ # Versioning ('genesis_time', uint64), ('slot', uint64), ('fork', Fork), # History ('latest_block_header', BeaconBlockHeader), ('block_roots', Vector(bytes32, 1) ), # Needed to process attestations, older to newer # noqa: E501 ('state_roots', Vector(bytes32, 1)), ( 'historical_roots', List(bytes32) ), # allow for a log-sized Merkle proof from any block to any historical block root # noqa: E501 # Ethereum 1.0 chain ('eth1_data', Eth1Data), ('eth1_data_votes', List(Eth1Data)), ('eth1_deposit_index', uint64), # Validator registry ('validators', List(Validator)), ('balances', List(uint64)), # Shuffling ('start_shard', uint64), ('randao_mixes', Vector(bytes32, 1)), ('active_index_roots', Vector(bytes32, 1)), # Slashings ('slashed_balances', Vector(uint64, 1) ), # Balances slashed at every withdrawal period # noqa: E501 # Attestations ('previous_epoch_attestations', List(PendingAttestation)), ('current_epoch_attestations', List(PendingAttestation)), # Crosslinks ('previous_crosslinks', Vector(Crosslink, 1)), ('current_crosslinks', Vector(Crosslink, 1)), # Justification ('previous_justified_epoch', uint64), ('previous_justified_root', bytes32), ('current_justified_epoch', uint64), ('current_justified_root', bytes32), # Note: justification_bitfield is meant to be defined as an integer type, # so its bit operation is in Python and is easier to specify and implement. ('justification_bitfield', uint64), # Finality ('finalized_epoch', uint64), ('finalized_root', bytes32), ] def __init__(self, *, genesis_time: Timestamp = default_timestamp, slot: Slot = default_slot, fork: Fork = default_fork, latest_block_header: BeaconBlockHeader = default_beacon_block_header, block_roots: Sequence[Hash32] = default_tuple, state_roots: Sequence[Hash32] = default_tuple, historical_roots: Sequence[Hash32] = default_tuple, eth1_data: Eth1Data = default_eth1_data, eth1_data_votes: Sequence[Eth1Data] = default_tuple, eth1_deposit_index: int = 0, validators: Sequence[Validator] = default_tuple, balances: Sequence[Gwei] = default_tuple, start_shard: Shard = default_shard, randao_mixes: Sequence[Hash32] = default_tuple, active_index_roots: Sequence[Hash32] = default_tuple, slashed_balances: Sequence[Gwei] = default_tuple, previous_epoch_attestations: Sequence[ PendingAttestation] = default_tuple, current_epoch_attestations: Sequence[ PendingAttestation] = default_tuple, previous_crosslinks: Sequence[Crosslink] = default_tuple, current_crosslinks: Sequence[Crosslink] = default_tuple, previous_justified_epoch: Epoch = default_epoch, previous_justified_root: Hash32 = ZERO_HASH32, current_justified_epoch: Epoch = default_epoch, current_justified_root: Hash32 = ZERO_HASH32, justification_bitfield: int = 0, finalized_epoch: Epoch = default_epoch, finalized_root: Hash32 = ZERO_HASH32, config: Eth2Config = None) -> None: if len(validators) != len(balances): raise ValueError( "The length of validators and balances lists should be the same." ) if config: # try to provide sane defaults if block_roots == default_tuple: block_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) if state_roots == default_tuple: state_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) if randao_mixes == default_tuple: randao_mixes = default_tuple_of_size( config.EPOCHS_PER_HISTORICAL_VECTOR, ZERO_HASH32) if active_index_roots == default_tuple: active_index_roots = default_tuple_of_size( config.EPOCHS_PER_HISTORICAL_VECTOR, ZERO_HASH32) if slashed_balances == default_tuple: slashed_balances = default_tuple_of_size( config.EPOCHS_PER_SLASHED_BALANCES_VECTOR, Gwei(0), ) if previous_crosslinks == default_tuple: previous_crosslinks = default_tuple_of_size( config.SHARD_COUNT, default_crosslink, ) if current_crosslinks == default_tuple: current_crosslinks = default_tuple_of_size( config.SHARD_COUNT, default_crosslink, ) super().__init__( genesis_time=genesis_time, slot=slot, fork=fork, latest_block_header=latest_block_header, block_roots=block_roots, state_roots=state_roots, historical_roots=historical_roots, eth1_data=eth1_data, eth1_data_votes=eth1_data_votes, eth1_deposit_index=eth1_deposit_index, validators=validators, balances=balances, start_shard=start_shard, randao_mixes=randao_mixes, active_index_roots=active_index_roots, slashed_balances=slashed_balances, previous_epoch_attestations=previous_epoch_attestations, current_epoch_attestations=current_epoch_attestations, previous_crosslinks=previous_crosslinks, current_crosslinks=current_crosslinks, previous_justified_epoch=previous_justified_epoch, previous_justified_root=previous_justified_root, current_justified_epoch=current_justified_epoch, current_justified_root=current_justified_root, justification_bitfield=justification_bitfield, finalized_epoch=finalized_epoch, finalized_root=finalized_root, ) def __repr__(self) -> str: return f"<BeaconState #{self.slot} {encode_hex(self.root)[2:10]}>" @property def validator_count(self) -> int: return len(self.validators) def update_validator(self, validator_index: ValidatorIndex, validator: Validator, balance: Gwei = None) -> 'BeaconState': """ Replace ``self.validators[validator_index]`` with ``validator``. Callers can optionally provide a ``balance`` which will replace ``self.balances[validator_index] with ``balance``. """ if (validator_index >= len(self.validators) or validator_index >= len(self.balances) or validator_index < 0): raise IndexError("Incorrect validator index") state = self.update_validator_with_fn( validator_index, lambda *_: validator, ) if balance: return state._update_validator_balance( validator_index, balance, ) else: return state def update_validator_with_fn(self, validator_index: ValidatorIndex, fn: Callable[[Validator, Any], Validator], *args: Any) -> 'BeaconState': """ Replace ``self.validators[validator_index]`` with the result of calling ``fn`` on the existing ``validator``. Any auxillary args passed in ``args`` are provided to ``fn`` along with the ``validator``. """ if validator_index >= len(self.validators) or validator_index < 0: raise IndexError("Incorrect validator index") return self.copy(validators=update_tuple_item_with_fn( self.validators, validator_index, fn, *args, ), ) def _update_validator_balance(self, validator_index: ValidatorIndex, balance: Gwei) -> 'BeaconState': """ Update the balance of validator of the given ``validator_index``. """ if validator_index >= len(self.balances) or validator_index < 0: raise IndexError("Incorrect validator index") return self.copy(balances=update_tuple_item( self.balances, validator_index, balance, )) def current_epoch(self, slots_per_epoch: int) -> Epoch: return slot_to_epoch(self.slot, slots_per_epoch) def previous_epoch(self, slots_per_epoch: int, genesis_epoch: Epoch) -> Epoch: current_epoch = self.current_epoch(slots_per_epoch) if current_epoch == genesis_epoch: return genesis_epoch else: return Epoch(current_epoch - 1) def next_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) + 1)
class Zoo(HashableContainer): fields = [("animals", Vector(Animal, 3))]
byte_list, bytes32, bytes48, bytes96, uint8, uint256, ) @pytest.mark.parametrize( ("sedes", "size"), ( (boolean, 1), (uint8, 1), (uint256, 32), (Vector(uint8, 0), 0), (Vector(uint8, 2), 2), (Container((uint8, Vector(uint8, 4))), 5), (Vector(List(uint8), 0), 0), (Vector(Container((uint8, Vector(uint8, 4))), 4), 20), (byte, 1), (ByteVector(0), 0), (bytes32, 32), (bytes48, 48), (bytes96, 96), ), ) def test_fixed_size(sedes, size): assert sedes.is_fixed_sized assert sedes.get_fixed_size() == size
class BeaconState(ssz.Serializable): fields = [ # Misc ('slot', uint64), ('genesis_time', uint64), ('fork', Fork), # For versioning hard forks # Validator registry ('validator_registry', List(Validator)), ('validator_balances', List(uint64)), ('validator_registry_update_epoch', uint64), # Randomness and committees ('latest_randao_mixes', Vector(bytes32, 1)), ('previous_shuffling_start_shard', uint64), ('current_shuffling_start_shard', uint64), ('previous_shuffling_epoch', uint64), ('current_shuffling_epoch', uint64), ('previous_shuffling_seed', bytes32), ('current_shuffling_seed', bytes32), # Finality ('previous_epoch_attestations', List(PendingAttestation)), ('current_epoch_attestations', List(PendingAttestation)), ('previous_justified_epoch', uint64), ('current_justified_epoch', uint64), ('previous_justified_root', bytes32), ('current_justified_root', bytes32), # Note: justification_bitfield is meant to be defined as an integer type, # so its bit operation is in Python and is easier to specify and implement. ('justification_bitfield', uint64), ('finalized_epoch', uint64), ('finalized_root', bytes32), # Recent state ('latest_crosslinks', Vector(Crosslink, 1)), ('latest_block_roots', Vector(bytes32, 1) ), # Needed to process attestations, older to newer # noqa: E501 ('latest_state_roots', Vector(bytes32, 1)), ('latest_active_index_roots', Vector(bytes32, 1)), ('latest_slashed_balances', Vector( uint64, 1)), # Balances slashed at every withdrawal period # noqa: E501 ('latest_block_header', BeaconBlockHeader), ( 'historical_roots', List(bytes32) ), # allow for a log-sized Merkle proof from any block to any historical block root" # noqa: E501 # Ethereum 1.0 chain ('latest_eth1_data', Eth1Data), ('eth1_data_votes', List(Eth1DataVote)), ('deposit_index', uint64), ] def __init__( self, *, # Misc slot: Slot, genesis_time: Timestamp, fork: Fork, # Validator registry validator_registry: Sequence[Validator], validator_balances: Sequence[Gwei], validator_registry_update_epoch: Epoch, # Randomness and committees latest_randao_mixes: Sequence[Hash32], previous_shuffling_start_shard: Shard, current_shuffling_start_shard: Shard, previous_shuffling_epoch: Epoch, current_shuffling_epoch: Epoch, previous_shuffling_seed: Hash32, current_shuffling_seed: Hash32, # Finality previous_epoch_attestations: Sequence[PendingAttestation], current_epoch_attestations: Sequence[PendingAttestation], previous_justified_epoch: Epoch, current_justified_epoch: Epoch, previous_justified_root: Hash32, current_justified_root: Hash32, justification_bitfield: int, finalized_epoch: Epoch, finalized_root: Hash32, # Recent state latest_crosslinks: Sequence[Crosslink], latest_block_roots: Sequence[Hash32], latest_state_roots: Sequence[Hash32], latest_active_index_roots: Sequence[Hash32], latest_slashed_balances: Sequence[Gwei], latest_block_header: BeaconBlockHeader, historical_roots: Sequence[Hash32], # Ethereum 1.0 chain latest_eth1_data: Eth1Data, eth1_data_votes: Sequence[Eth1DataVote], deposit_index: int) -> None: if len(validator_registry) != len(validator_balances): raise ValueError( "The length of validator_registry and validator_balances should be the same." ) super().__init__( # Misc slot=slot, genesis_time=genesis_time, fork=fork, # Validator registry validator_registry=validator_registry, validator_balances=validator_balances, validator_registry_update_epoch=validator_registry_update_epoch, # Randomness and committees latest_randao_mixes=latest_randao_mixes, previous_shuffling_start_shard=previous_shuffling_start_shard, current_shuffling_start_shard=current_shuffling_start_shard, previous_shuffling_epoch=previous_shuffling_epoch, current_shuffling_epoch=current_shuffling_epoch, previous_shuffling_seed=previous_shuffling_seed, current_shuffling_seed=current_shuffling_seed, # Finality previous_epoch_attestations=previous_epoch_attestations, current_epoch_attestations=current_epoch_attestations, previous_justified_epoch=previous_justified_epoch, current_justified_epoch=current_justified_epoch, previous_justified_root=previous_justified_root, current_justified_root=current_justified_root, justification_bitfield=justification_bitfield, finalized_epoch=finalized_epoch, finalized_root=finalized_root, # Recent state latest_crosslinks=latest_crosslinks, latest_block_roots=latest_block_roots, latest_state_roots=latest_state_roots, latest_active_index_roots=latest_active_index_roots, latest_slashed_balances=latest_slashed_balances, latest_block_header=latest_block_header, historical_roots=historical_roots, # Ethereum 1.0 chain latest_eth1_data=latest_eth1_data, eth1_data_votes=eth1_data_votes, deposit_index=deposit_index, ) def __repr__(self) -> str: return f"<BeaconState #{self.slot} {encode_hex(self.root)[2:10]}>" @property def num_validators(self) -> int: return len(self.validator_registry) @property def num_crosslinks(self) -> int: return len(self.latest_crosslinks) @classmethod def create_filled_state( cls, *, genesis_epoch: Epoch, genesis_start_shard: Shard, genesis_slot: Slot, shard_count: int, slots_per_historical_root: int, latest_active_index_roots_length: int, latest_randao_mixes_length: int, latest_slashed_exit_length: int, activated_genesis_validators: Sequence[Validator] = (), genesis_balances: Sequence[Gwei] = () ) -> 'BeaconState': return cls( # Misc slot=genesis_slot, genesis_time=Timestamp(0), fork=Fork( previous_version=(0).to_bytes(4, 'little'), current_version=(0).to_bytes(4, 'little'), epoch=genesis_epoch, ), # Validator registry validator_registry=activated_genesis_validators, validator_balances=genesis_balances, validator_registry_update_epoch=genesis_epoch, # Randomness and committees latest_randao_mixes=(ZERO_HASH32, ) * latest_randao_mixes_length, previous_shuffling_start_shard=genesis_start_shard, current_shuffling_start_shard=genesis_start_shard, previous_shuffling_epoch=genesis_epoch, current_shuffling_epoch=genesis_epoch, previous_shuffling_seed=ZERO_HASH32, current_shuffling_seed=ZERO_HASH32, # Finality previous_epoch_attestations=(), current_epoch_attestations=(), previous_justified_epoch=genesis_epoch, current_justified_epoch=genesis_epoch, previous_justified_root=ZERO_HASH32, current_justified_root=ZERO_HASH32, justification_bitfield=0, finalized_epoch=genesis_epoch, finalized_root=ZERO_HASH32, # Recent state latest_crosslinks=((Crosslink( epoch=genesis_epoch, crosslink_data_root=ZERO_HASH32, ), ) * shard_count), latest_block_roots=(ZERO_HASH32, ) * slots_per_historical_root, latest_state_roots=(ZERO_HASH32, ) * slots_per_historical_root, latest_active_index_roots=(ZERO_HASH32, ) * latest_active_index_roots_length, latest_slashed_balances=(Gwei(0), ) * latest_slashed_exit_length, latest_block_header=get_temporary_block_header( BeaconBlock.create_empty_block(genesis_slot), ), historical_roots=(), # Ethereum 1.0 chain data latest_eth1_data=Eth1Data.create_empty_data(), eth1_data_votes=(), deposit_index=len(activated_genesis_validators), ) def update_validator_registry(self, validator_index: ValidatorIndex, validator: Validator) -> 'BeaconState': """ Replace ``self.validator_registry[validator_index]`` with ``validator``. """ if validator_index >= self.num_validators or validator_index < 0: raise IndexError("Incorrect validator index") validator_registry = list(self.validator_registry) validator_registry[validator_index] = validator updated_state = self.copy( validator_registry=tuple(validator_registry), ) return updated_state def update_validator_balance(self, validator_index: ValidatorIndex, balance: Gwei) -> 'BeaconState': """ Update the balance of validator of the given ``validator_index``. """ if validator_index >= self.num_validators or validator_index < 0: raise IndexError("Incorrect validator index") validator_balances = list(self.validator_balances) validator_balances[validator_index] = balance updated_state = self.copy( validator_balances=tuple(validator_balances), ) return updated_state def update_validator(self, validator_index: ValidatorIndex, validator: Validator, balance: Gwei) -> 'BeaconState': """ Update the ``Validator`` and balance of validator of the given ``validator_index``. """ state = self.update_validator_registry(validator_index, validator) state = state.update_validator_balance(validator_index, balance) return state def current_epoch(self, slots_per_epoch: int) -> Epoch: return slot_to_epoch(self.slot, slots_per_epoch) def previous_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) - 1) def next_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) + 1)
("sedes1", "sedes2"), ((uint8, uint8), (UInt(8), UInt(8)), (UInt(256), UInt(256))) ) def test_uint_eq(sedes1, sedes2): assert sedes1 == sedes1 assert sedes2 == sedes2 assert sedes1 == sedes2 assert hash(sedes1) == hash(sedes2) @pytest.mark.parametrize( ("sedes1", "sedes2"), ( (UInt(8), UInt(256)), (UInt(8), Byte()), (UInt(8), boolean), (UInt(8), Vector(UInt(8), 1)), ), ) def test_uint_neq(sedes1, sedes2): assert sedes1 != sedes2 assert hash(sedes1) != hash(sedes2) @pytest.mark.parametrize( ("sedes1", "sedes2"), ((boolean, boolean), (Boolean(), Boolean())) ) def test_bool_eq(sedes1, sedes2): assert sedes1 == sedes1 assert sedes2 == sedes2 assert sedes1 == sedes2 assert hash(sedes1) == hash(sedes2)
class BeaconState(ssz.Serializable): fields = [ # Versioning ("genesis_time", uint64), ("slot", uint64), ("fork", Fork), # History ("latest_block_header", BeaconBlockHeader), ( "block_roots", Vector(bytes32, 1), ), # Needed to process attestations, older to newer # noqa: E501 ("state_roots", Vector(bytes32, 1)), ( "historical_roots", List(bytes32, 1), ), # allow for a log-sized Merkle proof from any block to any historical block root # noqa: E501 # Ethereum 1.0 chain ("eth1_data", Eth1Data), ("eth1_data_votes", List(Eth1Data, 1)), ("eth1_deposit_index", uint64), # Validator registry ("validators", List(Validator, 1)), ("balances", List(uint64, 1)), # Shuffling ("start_shard", uint64), ("randao_mixes", Vector(bytes32, 1)), ("active_index_roots", Vector(bytes32, 1)), ("compact_committees_roots", Vector(bytes32, 1)), # Slashings ( "slashings", Vector(uint64, 1), ), # Balances slashed at every withdrawal period # noqa: E501 # Attestations ("previous_epoch_attestations", List(PendingAttestation, 1)), ("current_epoch_attestations", List(PendingAttestation, 1)), # Crosslinks ("previous_crosslinks", Vector(Crosslink, 1)), ("current_crosslinks", Vector(Crosslink, 1)), # Justification ("justification_bits", Bitvector(JUSTIFICATION_BITS_LENGTH)), ("previous_justified_checkpoint", Checkpoint), ("current_justified_checkpoint", Checkpoint), # Finality ("finalized_checkpoint", Checkpoint), ] def __init__( self, *, genesis_time: Timestamp = default_timestamp, slot: Slot = default_slot, fork: Fork = default_fork, latest_block_header: BeaconBlockHeader = default_beacon_block_header, block_roots: Sequence[Hash32] = default_tuple, state_roots: Sequence[Hash32] = default_tuple, historical_roots: Sequence[Hash32] = default_tuple, eth1_data: Eth1Data = default_eth1_data, eth1_data_votes: Sequence[Eth1Data] = default_tuple, eth1_deposit_index: int = 0, validators: Sequence[Validator] = default_tuple, balances: Sequence[Gwei] = default_tuple, start_shard: Shard = default_shard, randao_mixes: Sequence[Hash32] = default_tuple, active_index_roots: Sequence[Hash32] = default_tuple, compact_committees_roots: Sequence[Hash32] = default_tuple, slashings: Sequence[Gwei] = default_tuple, previous_epoch_attestations: Sequence[ PendingAttestation] = default_tuple, current_epoch_attestations: Sequence[ PendingAttestation] = default_tuple, previous_crosslinks: Sequence[Crosslink] = default_tuple, current_crosslinks: Sequence[Crosslink] = default_tuple, justification_bits: Bitfield = default_justification_bits, previous_justified_checkpoint: Checkpoint = default_checkpoint, current_justified_checkpoint: Checkpoint = default_checkpoint, finalized_checkpoint: Checkpoint = default_checkpoint, config: Eth2Config = None, ) -> None: if len(validators) != len(balances): raise ValueError( "The length of validators and balances lists should be the same." ) if config: # try to provide sane defaults if block_roots == default_tuple: block_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) if state_roots == default_tuple: state_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) if randao_mixes == default_tuple: randao_mixes = default_tuple_of_size( config.EPOCHS_PER_HISTORICAL_VECTOR, ZERO_HASH32) if active_index_roots == default_tuple: active_index_roots = default_tuple_of_size( config.EPOCHS_PER_HISTORICAL_VECTOR, ZERO_HASH32) if compact_committees_roots == default_tuple: compact_committees_roots = default_tuple_of_size( config.EPOCHS_PER_HISTORICAL_VECTOR, ZERO_HASH32) if slashings == default_tuple: slashings = default_tuple_of_size( config.EPOCHS_PER_SLASHINGS_VECTOR, Gwei(0)) if previous_crosslinks == default_tuple: previous_crosslinks = default_tuple_of_size( config.SHARD_COUNT, default_crosslink) if current_crosslinks == default_tuple: current_crosslinks = default_tuple_of_size( config.SHARD_COUNT, default_crosslink) super().__init__( genesis_time=genesis_time, slot=slot, fork=fork, latest_block_header=latest_block_header, block_roots=block_roots, state_roots=state_roots, historical_roots=historical_roots, eth1_data=eth1_data, eth1_data_votes=eth1_data_votes, eth1_deposit_index=eth1_deposit_index, validators=validators, balances=balances, start_shard=start_shard, randao_mixes=randao_mixes, active_index_roots=active_index_roots, compact_committees_roots=compact_committees_roots, slashings=slashings, previous_epoch_attestations=previous_epoch_attestations, current_epoch_attestations=current_epoch_attestations, previous_crosslinks=previous_crosslinks, current_crosslinks=current_crosslinks, justification_bits=justification_bits, previous_justified_checkpoint=previous_justified_checkpoint, current_justified_checkpoint=current_justified_checkpoint, finalized_checkpoint=finalized_checkpoint, ) def __repr__(self) -> str: return f"<BeaconState #{self.slot} {encode_hex(self.hash_tree_root)[2:10]}>" @property def validator_count(self) -> int: return len(self.validators) def update_validator( self, validator_index: ValidatorIndex, validator: Validator, balance: Gwei = None, ) -> "BeaconState": """ Replace ``self.validators[validator_index]`` with ``validator``. Callers can optionally provide a ``balance`` which will replace ``self.balances[validator_index] with ``balance``. """ if (validator_index >= len(self.validators) or validator_index >= len(self.balances) or validator_index < 0): raise IndexError("Incorrect validator index") state = self.update_validator_with_fn(validator_index, lambda *_: validator) if balance: return state._update_validator_balance(validator_index, balance) else: return state def update_validator_with_fn( self, validator_index: ValidatorIndex, fn: Callable[[Validator, Any], Validator], *args: Any, ) -> "BeaconState": """ Replace ``self.validators[validator_index]`` with the result of calling ``fn`` on the existing ``validator``. Any auxillary args passed in ``args`` are provided to ``fn`` along with the ``validator``. """ if validator_index >= len(self.validators) or validator_index < 0: raise IndexError("Incorrect validator index") return self.copy(validators=update_tuple_item_with_fn( self.validators, validator_index, fn, *args)) def _update_validator_balance(self, validator_index: ValidatorIndex, balance: Gwei) -> "BeaconState": """ Update the balance of validator of the given ``validator_index``. """ if validator_index >= len(self.balances) or validator_index < 0: raise IndexError("Incorrect validator index") return self.copy(balances=update_tuple_item(self.balances, validator_index, balance)) def current_epoch(self, slots_per_epoch: int) -> Epoch: return compute_epoch_of_slot(self.slot, slots_per_epoch) def previous_epoch(self, slots_per_epoch: int, genesis_epoch: Epoch) -> Epoch: current_epoch = self.current_epoch(slots_per_epoch) if current_epoch == genesis_epoch: return genesis_epoch else: return Epoch(current_epoch - 1) def next_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) + 1)
def test_byte_vector(value): byte_sequence = tuple(bytes([byte_value]) for byte_value in value) expected_vector_root = ssz.hash_tree_root(byte_sequence, Vector(byte, len(value))) assert ssz.hash_tree_root(value, ByteVector(len(value))) == expected_vector_root
class Zoo(Serializable): fields = [ ('animals', Vector(Animal, 3)), ]
from ssz.hashable_container import HashableContainer, SignedHashableContainer from ssz.sedes import ( Bitlist, Bitvector, List, Vector, boolean, bytes32, bytes48, bytes96, uint64, ) import sys import argparse if __name__ == "__main__": # Setup argument parser # the parameters are the elements of the vector parser = argparse.ArgumentParser() parser.add_argument('element', type=int, nargs='*') args = parser.parse_args() # Execute function/method to test hash = Vector(uint64, len(args.element)).get_hash_tree_root(args.element) # Write result to stdout in binary sys.stdout.buffer.write(hash)
def test_vector_of_composite(bytes16_vector, result): sedes = Vector(ByteVector(16), len(bytes16_vector)) assert ssz.get_hash_tree_root(bytes16_vector, sedes) == result
def test_bitvector_round_trip_no_sedes(size, value): foo = Bitvector(size) assert decode(encode(value, foo), foo) == value @pytest.mark.parametrize(("sedes", "id"), ((Bitvector(64), "Bitvector64"), )) def test_get_sedes_id(sedes, id): assert sedes.get_sedes_id() == id @pytest.mark.parametrize(("sedes1", "sedes2"), ((Bitvector(2), Bitvector(2)), )) def test_eq(sedes1, sedes2): assert sedes1 == sedes1 assert sedes2 == sedes2 assert sedes1 == sedes2 assert hash(sedes1) == hash(sedes2) @pytest.mark.parametrize( ("sedes1", "sedes2"), ( (Bitvector(2), Bitvector(3)), (Bitvector(2), Bitlist(2)), (Bitvector(2), Vector(boolean, 2)), ), ) def test_neq(sedes1, sedes2): assert sedes1 != sedes2 assert hash(sedes1) != hash(sedes2)
def test_container_of_dynamic_sized_fields(fields, value, serialized): sedes = Container(fields) assert encode_hex(ssz.encode(value, sedes)) == serialized decoded = ssz.decode(decode_hex(serialized), sedes) pure_decoded = tuple( tuple(element) if isinstance(element, HashableList) else element for element in decoded) assert pure_decoded == value @pytest.mark.parametrize( ("sedes", "id"), ( (List(uint8, 2), "List(UInt8,2)"), (Vector(uint8, 2), "Vector(UInt8,2)"), (Container((uint8, bytes32)), "UInt8,ByteVector32"), (Container((uint8, List(uint8, 2))), "UInt8,List(UInt8,2)"), ( Vector(Container((uint8, List(uint8, 2))), 2), "Vector(UInt8,List(UInt8,2),2)", ), ), ) def test_get_sedes_id(sedes, id): assert sedes.get_sedes_id() == id @pytest.mark.parametrize( ("sedes1", "sedes2"), (
def test_tuple_of_dynamic_sized_entries(value, serialized): sedes = Vector(List(uint8), len(value)) assert encode_hex(ssz.encode(value, sedes)) == serialized assert ssz.decode(decode_hex(serialized), sedes) == value
class BeaconState(HashableContainer): fields = [ # Versioning ("genesis_time", uint64), ("slot", uint64), ("fork", Fork), # History ("latest_block_header", BeaconBlockHeader), ( "block_roots", Vector(bytes32, 1), ), # Needed to process attestations, older to newer # noqa: E501 ("state_roots", Vector(bytes32, 1)), ( "historical_roots", List(bytes32, 1), ), # allow for a log-sized Merkle proof from any block to any historical block root # noqa: E501 # Ethereum 1.0 chain ("eth1_data", Eth1Data), ("eth1_data_votes", List(Eth1Data, 1)), ("eth1_deposit_index", uint64), # Validator registry ("validators", List(Validator, 1)), ("balances", List(uint64, 1)), # Shuffling ("randao_mixes", Vector(bytes32, 1)), # Slashings ( "slashings", Vector(uint64, 1), ), # Balances slashed at every withdrawal period # noqa: E501 # Attestations ("previous_epoch_attestations", List(PendingAttestation, 1)), ("current_epoch_attestations", List(PendingAttestation, 1)), # Justification ("justification_bits", Bitvector(JUSTIFICATION_BITS_LENGTH)), ("previous_justified_checkpoint", Checkpoint), ("current_justified_checkpoint", Checkpoint), # Finality ("finalized_checkpoint", Checkpoint), ] @classmethod def create( cls: Type[TBeaconState], *, genesis_time: Timestamp = default_timestamp, slot: Slot = default_slot, fork: Fork = default_fork, latest_block_header: BeaconBlockHeader = default_beacon_block_header, block_roots: Sequence[SigningRoot] = default_block_roots, state_roots: Sequence[Hash32] = default_state_roots, historical_roots: Sequence[Hash32] = default_tuple, eth1_data: Eth1Data = default_eth1_data, eth1_data_votes: Sequence[Eth1Data] = default_tuple, eth1_deposit_index: int = 0, validators: Sequence[Validator] = default_tuple, balances: Sequence[Gwei] = default_tuple, randao_mixes: Sequence[Hash32] = default_randao_mixes, slashings: Sequence[Gwei] = default_slashings, previous_epoch_attestations: Sequence[ PendingAttestation] = default_tuple, current_epoch_attestations: Sequence[ PendingAttestation] = default_tuple, justification_bits: Bitfield = default_justification_bits, previous_justified_checkpoint: Checkpoint = default_checkpoint, current_justified_checkpoint: Checkpoint = default_checkpoint, finalized_checkpoint: Checkpoint = default_checkpoint, config: Eth2Config = None, validator_and_balance_length_check: bool = True, ) -> TBeaconState: # We usually want to check that the lengths of each list are the same # In some cases, e.g. SSZ fuzzing, they are not and we still want to instantiate an object. if validator_and_balance_length_check: if len(validators) != len(balances): raise ValueError( f"The length of validators ({len(validators)}) and balances ({len(balances)}) " "lists should be the same.") if config: # try to provide sane defaults if block_roots == default_tuple: block_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_SIGNING_ROOT) if state_roots == default_tuple: state_roots = default_tuple_of_size( config.SLOTS_PER_HISTORICAL_ROOT, ZERO_HASH32) if randao_mixes == default_tuple: randao_mixes = default_tuple_of_size( config.EPOCHS_PER_HISTORICAL_VECTOR, ZERO_HASH32) if slashings == default_tuple: slashings = default_tuple_of_size( config.EPOCHS_PER_SLASHINGS_VECTOR, Gwei(0)) return super().create( genesis_time=genesis_time, slot=slot, fork=fork, latest_block_header=latest_block_header, block_roots=block_roots, state_roots=state_roots, historical_roots=historical_roots, eth1_data=eth1_data, eth1_data_votes=eth1_data_votes, eth1_deposit_index=eth1_deposit_index, validators=validators, balances=balances, randao_mixes=randao_mixes, slashings=slashings, previous_epoch_attestations=previous_epoch_attestations, current_epoch_attestations=current_epoch_attestations, justification_bits=justification_bits, previous_justified_checkpoint=previous_justified_checkpoint, current_justified_checkpoint=current_justified_checkpoint, finalized_checkpoint=finalized_checkpoint, ) def __str__(self) -> str: return ( f"[hash_tree_root]={humanize_hash(self.hash_tree_root)}, slot={self.slot}" ) @property def validator_count(self) -> int: return len(self.validators) def current_epoch(self, slots_per_epoch: int) -> Epoch: return compute_epoch_at_slot(self.slot, slots_per_epoch) def previous_epoch(self, slots_per_epoch: int, genesis_epoch: Epoch) -> Epoch: current_epoch = self.current_epoch(slots_per_epoch) if current_epoch == genesis_epoch: return genesis_epoch else: return Epoch(current_epoch - 1) def next_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) + 1)
byte, bytes32, bytes48, bytes96, uint8, uint256, ) @pytest.mark.parametrize( ("sedes", "size"), ( (boolean, 1), (uint8, 1), (uint256, 32), (Vector(uint8, 1), 1), (Vector(uint8, 2), 2), (Container((uint8, Vector(uint8, 4))), 5), (Vector(Container((uint8, Vector(uint8, 4))), 4), 20), (byte, 1), (bytes32, 32), (bytes48, 48), (bytes96, 96), ), ) def test_fixed_size(sedes, size): assert sedes.is_fixed_sized assert sedes.get_fixed_size() == size @pytest.mark.parametrize(