def test_get_aggregate_from_valid_committee_attestations( sample_attestation_params, privkeys, genesis_state, config): committee_size = 16 empty_bitfield = get_empty_bitfield(committee_size) base_attestation = Attestation.create(**sample_attestation_params) attestations = [] expected_bitfield = empty_bitfield for i in range(4, 16, 2): attestations.append( base_attestation.mset( "aggregation_bits", set_voted(empty_bitfield, i), "signature", sign_transaction( object=base_attestation.data, privkey=privkeys[i], state=genesis_state, slot=genesis_state.slot, signature_domain=SignatureDomain.DOMAIN_BEACON_ATTESTER, slots_per_epoch=config.SLOTS_PER_EPOCH, ), )) expected_bitfield = set_voted(expected_bitfield, i) aggregate_attestation = get_aggregate_from_valid_committee_attestations( attestations) assert aggregate_attestation.aggregation_bits == expected_bitfield
def create_block_on_state( *, state: BeaconState, config: Eth2Config, state_machine: BaseBeaconStateMachine, signed_block_class: Type[BaseSignedBeaconBlock], parent_block: BaseBeaconBlock, slot: Slot, validator_index: ValidatorIndex, privkey: int, attestations: Sequence[Attestation], eth1_data: Eth1Data = None, deposits: Sequence[Deposit] = None, check_proposer_index: bool = True, ) -> SignedBeaconBlock: """ Create a beacon block with the given parameters. """ if check_proposer_index: validate_proposer_index(state, config, slot, validator_index) block_class = signed_block_class.block_class block = create_unsigned_block_on_state( state=state, config=config, block_class=block_class, parent_block=parent_block.message, slot=slot, attestations=attestations, eth1_data=eth1_data, deposits=deposits, ) # Randao reveal randao_reveal = _generate_randao_reveal(privkey, slot, state, config) block = block.set("body", block.body.set("randao_reveal", randao_reveal)) # Apply state transition to get state root signed_block = signed_block_class.create(message=block, signature=EMPTY_SIGNATURE) post_state, signed_block = state_machine.import_block( signed_block, state, check_proposer_signature=False) # Sign signature = sign_transaction( message_hash=signed_block.message.hash_tree_root, privkey=privkey, state=post_state, slot=slot, signature_domain=SignatureDomain.DOMAIN_BEACON_PROPOSER, slots_per_epoch=config.SLOTS_PER_EPOCH, ) signed_block = signed_block.set("signature", signature) return signed_block
def create_block_on_state( *, state: BeaconState, config: Eth2Config, state_machine: BaseBeaconStateMachine, block_class: Type[BaseBeaconBlock], parent_block: BaseBeaconBlock, slot: Slot, validator_index: ValidatorIndex, privkey: int, attestations: Sequence[Attestation], check_proposer_index: bool = True) -> BaseBeaconBlock: """ Create a beacon block with the given parameters. """ # Check proposer if check_proposer_index: validate_proposer_index(state, config, slot, validator_index) # Prepare block: slot and previous_block_root block = block_class.from_parent( parent_block=parent_block, block_params=FromBlockParams(slot=slot), ) # TODO: Add more operations randao_reveal = _generate_randao_reveal(privkey, slot, state.fork, config) eth1_data = Eth1Data.create_empty_data() body = BeaconBlockBody.create_empty_body().copy( randao_reveal=randao_reveal, eth1_data=eth1_data, attestations=attestations, ) block = block.copy(body=body, ) # Apply state transition to get state root state, block = state_machine.import_block(block, check_proposer_signature=False) # Sign # TODO make sure we use the correct signed_root signature = sign_transaction( message_hash=block.signed_root, privkey=privkey, fork=state.fork, slot=slot, signature_domain=SignatureDomain.DOMAIN_BEACON_BLOCK, slots_per_epoch=config.SLOTS_PER_EPOCH, ) block = block.copy(signature=signature, ) return block
def create_block_on_state( *, state: BeaconState, config: Eth2Config, state_machine: BaseBeaconStateMachine, block_class: Type[BaseBeaconBlock], parent_block: BaseBeaconBlock, slot: Slot, validator_index: ValidatorIndex, privkey: int, attestations: Sequence[Attestation], check_proposer_index: bool = True) -> BaseBeaconBlock: """ Create a beacon block with the given parameters. """ if check_proposer_index: validate_proposer_index(state, config, slot, validator_index) block = block_class.from_parent(parent_block=parent_block, block_params=FromBlockParams(slot=slot)) # MAX_ATTESTATIONS attestations = attestations[:config.MAX_ATTESTATIONS] # TODO: Add more operations randao_reveal = _generate_randao_reveal(privkey, slot, state, config) eth1_data = state.eth1_data body = BeaconBlockBody.create(randao_reveal=randao_reveal, eth1_data=eth1_data, attestations=attestations) block = block.set("body", body) # Apply state transition to get state root state, block = state_machine.import_block(block, state, check_proposer_signature=False) # Sign signature = sign_transaction( message_hash=block.signing_root, privkey=privkey, state=state, slot=slot, signature_domain=SignatureDomain.DOMAIN_BEACON_PROPOSER, slots_per_epoch=config.SLOTS_PER_EPOCH, ) block = block.set("signature", signature) return block
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_at_slot(slot, config.SLOTS_PER_EPOCH) randao_reveal = sign_transaction( object=SerializableUint64(epoch), privkey=privkey, state=state, slot=slot, signature_domain=SignatureDomain.DOMAIN_RANDAO, slots_per_epoch=config.SLOTS_PER_EPOCH, ) return randao_reveal
def _generate_randao_reveal(privkey: int, slot: Slot, fork: Fork, 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 = slot_to_epoch(slot, config.SLOTS_PER_EPOCH) message_hash = Hash32(epoch.to_bytes(32, byteorder='little')) randao_reveal = sign_transaction( message_hash=message_hash, privkey=privkey, fork=fork, slot=slot, signature_domain=SignatureDomain.DOMAIN_RANDAO, slots_per_epoch=config.SLOTS_PER_EPOCH, ) return randao_reveal
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 create_block_on_state( *, state: BeaconState, config: BeaconConfig, state_machine: BaseBeaconStateMachine, block_class: Type[BaseBeaconBlock], parent_block: BaseBeaconBlock, slot: Slot, validator_index: ValidatorIndex, privkey: int, attestations: Sequence[Attestation], check_proposer_index: bool = True) -> BaseBeaconBlock: """ Create a beacon block with the given parameters. """ # Check proposer if check_proposer_index: validate_proposer_index(state, config, slot, validator_index) # Prepare block: slot and parent_root block = block_class.from_parent( parent_block=parent_block, block_params=FromBlockParams(slot=slot), ) # TODO: Add more operations randao_reveal = EMPTY_SIGNATURE eth1_data = Eth1Data.create_empty_data() body = BeaconBlockBody.create_empty_body().copy( attestations=attestations, ) block = block.copy( randao_reveal=randao_reveal, eth1_data=eth1_data, body=body, ) # Apply state transition to get state root state, block = state_machine.import_block(block, check_proposer_signature=False) # Sign empty_signature_block_root = block.block_without_signature_root proposal_root = Proposal( slot, config.BEACON_CHAIN_SHARD_NUMBER, empty_signature_block_root, ).root signature = sign_transaction( message_hash=proposal_root, privkey=privkey, fork=state.fork, slot=slot, signature_domain=SignatureDomain.DOMAIN_PROPOSAL, slots_per_epoch=config.SLOTS_PER_EPOCH, ) block = block.copy(signature=signature, ) return block