def test_root(data, sedes_and_values): sedes, values = sedes_and_values value = data.draw(values) serializable_value = to_serializable_value(value, sedes) serializable_root = ssz.get_hash_tree_root(serializable_value, sedes) hashable_value = to_hashable_value(value, sedes) hashable_root = ssz.get_hash_tree_root(hashable_value, sedes) assert serializable_root == hashable_root
async def _validate_local_advertisement( self, advertisement: Advertisement) -> None: if not advertisement.node_id == self.local_node_id: raise Exception( "Must be called with an advertisement signed by the local node" ) try: try: # First query "pinned" storage content = self._network.pinned_content_storage.get_content( advertisement.content_key) except ContentNotFound: # Fall back to "commons" storage content = self._network.commons_content_storage.get_content( advertisement.content_key) except ContentNotFound as err: raise ValidationError( f"Content not found: advertisement={advertisement}") from err hash_tree_root = ssz.get_hash_tree_root(content, sedes=content_sedes) if hash_tree_root != advertisement.hash_tree_root: raise ValidationError( f"Mismatched roots: local={hash_tree_root.hex()} " f"advertisement={advertisement.hash_tree_root.hex}")
def get_compact_committees_root(state: BeaconState, epoch: Epoch, config: CommitteeConfig) -> Hash32: shard_count = config.SHARD_COUNT committees = (CompactCommittee(), ) * shard_count start_shard = get_start_shard(state, epoch, config) active_validator_indices = get_active_validator_indices( state.validators, epoch, ) committee_count = get_committee_count( len(active_validator_indices), config.SHARD_COUNT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ) for committee_number in range(committee_count): shard = Shard((start_shard + committee_number) % shard_count) compact_committee = _compute_compact_committee_for_shard_in_epoch( state, epoch, shard, config, ) committees = update_tuple_item( committees, shard, compact_committee, ) return ssz.get_hash_tree_root(committees, sedes=ssz.sedes.Vector( CompactCommittee, shard_count))
def _randao_provider_of_epoch_signature(public_key: BLSPubkey, epoch: Epoch) -> BLSSignature: private_key = private_key_provider(public_key) # TODO: fix how we get the signing root message = ssz.get_hash_tree_root(epoch, sedes=ssz.sedes.uint64) domain = compute_domain(SignatureDomain.DOMAIN_RANDAO) sig = bls.sign(message, private_key, domain) return sig
def initialize_beacon_state_from_eth1(*, eth1_block_hash: Hash32, eth1_timestamp: Timestamp, deposits: Sequence[Deposit], config: Eth2Config) -> BeaconState: fork = Fork.create( previous_version=config.GENESIS_FORK_VERSION, current_version=config.GENESIS_FORK_VERSION, epoch=GENESIS_EPOCH, ) state = BeaconState.create( genesis_time=_genesis_time_from_eth1_timestamp(eth1_timestamp, config.GENESIS_DELAY), fork=fork, eth1_data=Eth1Data.create(block_hash=eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader.create( body_root=BeaconBlockBody.create().hash_tree_root), block_roots=(ZERO_ROOT, ) * config.SLOTS_PER_HISTORICAL_ROOT, state_roots=(ZERO_HASH32, ) * config.SLOTS_PER_HISTORICAL_ROOT, randao_mixes=(eth1_block_hash, ) * config.EPOCHS_PER_HISTORICAL_VECTOR, slashings=(Gwei(0), ) * config.EPOCHS_PER_SLASHINGS_VECTOR, config=config, ) # Process genesis deposits for index, deposit in enumerate(deposits): deposit_data_list = tuple(deposit.data for deposit in deposits[:index + 1]) deposit_root = ssz.get_hash_tree_root( deposit_data_list, ssz.List(DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH)) state = state.transform(("eth1_data", "deposit_root"), deposit_root) state = process_deposit(state=state, deposit=deposit, config=config) # Process genesis activations for validator_index in range(len(state.validators)): validator_index = ValidatorIndex(validator_index) balance = state.balances[validator_index] effective_balance = calculate_effective_balance(balance, config) state = state.transform( ("validators", validator_index, "effective_balance"), effective_balance) if effective_balance == config.MAX_EFFECTIVE_BALANCE: activated_validator = activate_validator( state.validators[validator_index], GENESIS_EPOCH) state = state.transform(("validators", validator_index), activated_validator) return state.set("genesis_validators_root", state.validators.hash_tree_root)
def get_slot_signature(state: BeaconState, slot: Slot, privkey: int, config: Eth2Config) -> BLSSignature: """ Sign on ``slot`` and return the signature. """ domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_ATTESTER, config.SLOTS_PER_EPOCH, message_epoch=compute_epoch_at_slot(slot, config.SLOTS_PER_EPOCH), ) return bls.sign(get_hash_tree_root(slot, sedes=uint64), privkey, domain)
def _compute_next_active_index_roots(state: BeaconState, config: Eth2Config) -> Tuple[Hash32, ...]: next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) index_root_position = (next_epoch + config.ACTIVATION_EXIT_DELAY ) % config.EPOCHS_PER_HISTORICAL_VECTOR validator_indices_for_new_active_index_root = get_active_validator_indices( state.validators, Epoch(next_epoch + config.ACTIVATION_EXIT_DELAY)) new_active_index_root = ssz.get_hash_tree_root( validator_indices_for_new_active_index_root, ssz.sedes.List(ssz.uint64, config.VALIDATOR_REGISTRY_LIMIT), ) return update_tuple_item(state.active_index_roots, index_root_position, new_active_index_root)
def deposit(w3, deposit_contract) -> int: deposit_data = DepositDataFactory() deposit_input = ( deposit_data.pubkey, deposit_data.withdrawal_credentials, deposit_data.signature, ssz.get_hash_tree_root(deposit_data), ) tx_hash = deposit_contract.functions.deposit(*deposit_input).transact( {"value": deposit_data.amount * eth_utils.denoms.gwei}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) assert tx_receipt["status"] return deposit_data.amount
async def process_content(self, content_key: ContentKey, content: bytes) -> None: if self.content_storage.has_content(content_key): local_content = self.content_storage.get_content(content_key) if local_content == content: self.logger.debug( "Ignoring content we already have: content_key=%s", content_key.hex(), ) return self.logger.debug( "Processing content: content_key=%s content=%s", content_key.hex(), content.hex(), ) content_id = content_key_to_content_id(content_key) # TODO: computationally expensive hash_tree_root = ssz.get_hash_tree_root(content, sedes=content_sedes) known_hash_tree_roots = set( self._local_advertisement_db.get_hash_tree_roots_for_content_id( content_id, )) # We should avoid "polution" of our content database with mismatching # roots. This is a stop gap right now because we will need a mechanism # for inserting our own "correct" content into the system even in the # case where the existing "network" content doesn't agree on the hash # tree root. if known_hash_tree_roots and hash_tree_root not in known_hash_tree_roots: known_roots_display = "|".join( (root.hex() for root in known_hash_tree_roots)) raise NotImplementedError( f"Content hash tree root mismatch: " f"content_key={content_key.hex()} root={hash_tree_root.hex()} " f"known={known_roots_display}") self.content_storage.set_content(content_key, content, exists_ok=True) advertisement = self._get_or_create_advertisement( content_key, hash_tree_root) await self._network.broadcast(advertisement) self.logger.debug( "Processed content: content_key=%s content=%s", content_key.hex(), content.hex(), )
def run_with(cls, inputs: InputType, config: Optional[Eth2Config]) -> OutputType: serialized_ssz_object, ssz_object_from_yaml = inputs deserialized_object = _deserialize_object_from_bytes( serialized_ssz_object, cls.object_type) return ( ssz.encode(ssz_object_from_yaml, cls.object_type), deserialized_object, ssz.encode(deserialized_object, cls.object_type), ( ssz.get_hash_tree_root(ssz_object_from_yaml), ssz_object_from_yaml.signing_root if isinstance( ssz_object_from_yaml, SignedHashableContainer) else None, ), )
def state_with_validator_digests(state: BeaconState, config: Eth2Config) -> BeaconState: active_validator_indices = get_active_validator_indices( state.validators, config.GENESIS_EPOCH) active_index_root = ssz.get_hash_tree_root( active_validator_indices, ssz.List(ssz.uint64, config.VALIDATOR_REGISTRY_LIMIT)) active_index_roots = ( active_index_root, ) * config.EPOCHS_PER_HISTORICAL_VECTOR committee_root = get_compact_committees_root(state, config.GENESIS_EPOCH, CommitteeConfig(config)) compact_committees_roots = ( committee_root, ) * config.EPOCHS_PER_HISTORICAL_VECTOR return state.copy( active_index_roots=active_index_roots, compact_committees_roots=compact_committees_roots, )
def test_ssz_full_proofs(content): expected_hash_tree_root = get_hash_tree_root(content, sedes=content_sedes) proof = compute_proof(content, sedes=content_sedes) validate_proof(proof) assert is_proof_valid(proof) assert proof.get_hash_tree_root() == expected_hash_tree_root proven_data_segments = proof.get_proven_data_segments() assert len(proven_data_segments) == 1 start_index, proven_data = proven_data_segments[0] assert start_index == 0 assert proven_data == content proven_data = proof.get_proven_data() assert proven_data[0:len(content)] == content
async def _broadcast_worker( self, receive_channel: trio.abc.ReceiveChannel[ContentKey]) -> None: while self.manager.is_running: content_key = await receive_channel.receive() try: content = self.content_storage.get_content(content_key) except ContentNotFound: continue # TODO: computationally expensive hash_tree_root = ssz.get_hash_tree_root(content, sedes=content_sedes) advertisement = self._get_or_create_advertisement( content_key=content_key, hash_tree_root=hash_tree_root, ) await self._network.broadcast(advertisement)
def test_update_active_index_roots(genesis_state, config, state_slot, slots_per_epoch, epochs_per_historical_vector, activation_exit_delay): state = genesis_state.copy(slot=state_slot, ) result = _compute_next_active_index_roots(state, config) index_root = ssz.get_hash_tree_root( get_active_validator_indices( state.validators, compute_epoch_of_slot(state.slot, slots_per_epoch), ), ssz.sedes.List(ssz.uint64, config.VALIDATOR_REGISTRY_LIMIT), ) target_epoch = state.next_epoch(slots_per_epoch) + activation_exit_delay assert result[target_epoch % epochs_per_historical_vector] == index_root
def deposit(w3, deposit_contract) -> int: amount = get_random_valid_deposit_amount() deposit_input = ( SAMPLE_PUBKEY, SAMPLE_WITHDRAWAL_CREDENTIALS, SAMPLE_VALID_SIGNATURE, ssz.get_hash_tree_root( DepositData( pubkey=SAMPLE_PUBKEY, withdrawal_credentials=SAMPLE_WITHDRAWAL_CREDENTIALS, amount=amount, signature=SAMPLE_VALID_SIGNATURE, )), ) tx_hash = deposit_contract.functions.deposit(*deposit_input).transact( {"value": amount * eth_utils.denoms.gwei}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) assert tx_receipt["status"] return amount
def validate_aggregator_proof(state: BeaconState, aggregate_and_proof: AggregateAndProof, config: Eth2Config) -> None: slot = aggregate_and_proof.aggregate.data.slot pubkey = state.validators[aggregate_and_proof.aggregator_index].pubkey domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_ATTESTER, config.SLOTS_PER_EPOCH, message_epoch=compute_epoch_at_slot(slot, config.SLOTS_PER_EPOCH), ) message_hash = get_hash_tree_root(slot, sedes=uint64) bls.validate( message_hash=message_hash, pubkey=pubkey, signature=aggregate_and_proof.selection_proof, domain=domain, )
def _generate_randao_reveal(privkey: int, slot: Slot, state: BeaconState, config: Eth2Config) -> BLSSignature: """ Return the RANDAO reveal for the validator represented by ``privkey``. The current implementation requires a validator to provide the BLS signature over the SSZ-serialized epoch in which they are proposing a block. """ epoch = compute_epoch_of_slot(slot, config.SLOTS_PER_EPOCH) message_hash = ssz.get_hash_tree_root(epoch, sedes=ssz.sedes.uint64) randao_reveal = sign_transaction( message_hash=message_hash, privkey=privkey, state=state, slot=slot, signature_domain=SignatureDomain.DOMAIN_RANDAO, slots_per_epoch=config.SLOTS_PER_EPOCH, ) return randao_reveal
def initialize_beacon_state_from_eth1(*, eth1_block_hash: Hash32, eth1_timestamp: Timestamp, deposits: Sequence[Deposit], config: Eth2Config) -> BeaconState: state = BeaconState( genesis_time=_genesis_time_from_eth1_timestamp(eth1_timestamp), eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader( body_root=BeaconBlockBody().hash_tree_root), randao_mixes=(eth1_block_hash, ) * config.EPOCHS_PER_HISTORICAL_VECTOR, config=config, ) # Process genesis deposits for index, deposit in enumerate(deposits): deposit_data_list = tuple(deposit.data for deposit in deposits[:index + 1]) state = state.copy(eth1_data=state.eth1_data.copy( deposit_root=ssz.get_hash_tree_root( deposit_data_list, ssz.List(DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH), ))) state = process_deposit(state=state, deposit=deposit, config=config) # Process genesis activations for validator_index in range(len(state.validators)): validator_index = ValidatorIndex(validator_index) balance = state.balances[validator_index] effective_balance = calculate_effective_balance(balance, config) state = state.update_validator_with_fn( validator_index, lambda v, *_: v.copy(effective_balance=effective_balance)) if effective_balance == config.MAX_EFFECTIVE_BALANCE: state = state.update_validator_with_fn(validator_index, activate_validator, config.GENESIS_EPOCH) return state
def validate_randao_reveal( state: BeaconState, proposer_index: int, epoch: Epoch, randao_reveal: Hash32, slots_per_epoch: int, ) -> None: proposer = state.validators[proposer_index] proposer_pubkey = proposer.pubkey message_hash = ssz.get_hash_tree_root(epoch, sedes=ssz.sedes.uint64) domain = get_domain(state, SignatureDomain.DOMAIN_RANDAO, slots_per_epoch) try: bls.validate( pubkey=proposer_pubkey, message_hash=message_hash, signature=cast(BLSSignature, randao_reveal), domain=domain, ) except SignatureError as error: raise ValidationError("RANDAO reveal is invalid", error)
def signing_root(self): return ssz.get_hash_tree_root(self, self._meta.signed_container_sedes)
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_list_of_basic(serialized_uints128, max_length, result): # item_length = 128 / 8 = 16 int_values = tuple(ssz.decode(value, uint128) for value in serialized_uints128) assert ssz.get_hash_tree_root(int_values, List(uint128, max_length)) == result
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
def test_bitlist(size, value, result): foo = Bitlist(size) assert ssz.get_hash_tree_root(value, foo) == result
def test_container(bytes16_fields, result): sedes = Container(tuple(itertools.repeat(bytes16, len(bytes16_fields)))) assert ssz.get_hash_tree_root(bytes16_fields, sedes) == result
def test_list_of_composite(bytes16_list, max_length, result): # item_length = 32 sedes = List(bytes16, max_length) assert ssz.get_hash_tree_root(bytes16_list, sedes) == result
def test_root(): class Test(ssz.Serializable): fields = (("field1", uint8), ("field2", uint8)) test = Test(1, 2) assert test.hash_tree_root == ssz.get_hash_tree_root(test, Test)
def test_uint(uint_and_value): uint, value = uint_and_value assert ssz.get_hash_tree_root(value, uint) == ssz.encode(value, uint).ljust( CHUNK_SIZE, b"\x00")
def test_boolean(value, expected): assert ssz.get_hash_tree_root(value, boolean) == expected
def execute_tree_hash_test_case(test_case): sedes = parse_type_definition(test_case["type"]) value = from_formatted_dict(test_case["value"], sedes, CustomCodec) expected_root = decode_hex(test_case["root"]) calculated_root = ssz.get_hash_tree_root(value, sedes) assert calculated_root == expected_root