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
def _write_state_justification_bits(self, state_root: Root, justification_bits: Bitfield) -> None: key = SchemaV1.state_root_to_justification_bitfield(state_root) encoding = ssz.encode(justification_bits, Bitvector(JUSTIFICATION_BITS_LENGTH)) self._state_bytes_written += len(encoding) self.db[key] = encoding
def bitvector_sedes_and_values_st(draw): size = draw( st.one_of( st.integers(1, 10), st.just(300), # choose at least one sample exceeding one chunk )) return Bitvector(size), bitvector_value_st(size)
class ClockInRecords(SignedHashableContainer): fields = [ ("epoch", uint64), ("bio_id_scan", bytes32), ("poo_log_bits", Bitlist(32)), ("wash_log_bits", Bitvector(32)), ("signature", bytes96), ]
class MetaData(HashableContainer): fields = [("seq_number", uint64), ("attnets", Bitvector(ATTESTATION_SUBNET_COUNT))] @classmethod def create( cls: Type[TMetaData], *, seq_number: SeqNumber = default_seq_number, attnets: Tuple[bool, ...] = default_attnets_tuple, ) -> TMetaData: return super().create(seq_number=seq_number, attnets=attnets) def __str__(self) -> str: attnets = map(lambda elem: "1" if elem else "0", self.attnets) return f"seq_number={self.seq_number}, attnets=0b{''.join(attnets)}"
def test_bitvector_instantiation_bound(): with pytest.raises(TypeError): bit_count = 0 Bitvector(bit_count)
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)
def test_bitvector(size, value, result): foo = Bitvector(size) assert ssz.get_hash_tree_root(value, foo) == result
(16, (True, ) + (False, ) * 15))) def test_bitlist_round_trip_no_sedes(size, value): foo = Bitlist(size) assert decode(encode(value, foo), foo) == value @pytest.mark.parametrize(("sedes", "id"), ((Bitlist(64), "Bitlist64"), )) def test_get_sedes_id(sedes, id): assert sedes.get_sedes_id() == id @pytest.mark.parametrize(("sedes1", "sedes2"), ((Bitlist(2), Bitlist(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"), ( (Bitlist(2), Bitlist(3)), (Bitlist(2), Bitvector(2)), (Bitlist(2), List(boolean, 2)), ), ) def test_neq(sedes1, sedes2): assert sedes1 != sedes2 assert hash(sedes1) != hash(sedes2)
def test_bitvector_deserialize_values(size, value, expected): foo = Bitvector(size) assert foo.deserialize(value) == expected
def test_bitvector_serialize_values(size, value, expected): foo = Bitvector(size) assert encode(value, foo) == expected assert foo.serialize(bytearray(value)) == expected
assert foo.deserialize(value) == expected @pytest.mark.parametrize("size, value", ((16, (True, ) + (False, ) * 15), )) 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)), ), )
# License for the specific language governing permissions and limitations # under the License. from typing import Sequence 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__": # Binary read from stdin bv = sys.stdin.buffer.read() # Execute function/method to test hash = Bitvector(len(bv)).get_hash_tree_root(bv) # Write result to stdout in binary sys.stdout.buffer.write(hash)
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 _read_state_justification_bits(self, state_root: Root) -> Bitfield: key = SchemaV1.state_root_to_justification_bitfield(state_root) return ssz.decode(self.db[key], Bitvector(JUSTIFICATION_BITS_LENGTH))