Update spec comments (#8727)

This commit is contained in:
Victor Farazdagi 2021-04-08 22:33:54 +03:00 committed by GitHub
parent 76390c94af
commit 0808c02c65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 100 additions and 109 deletions

View File

@ -26,24 +26,23 @@ var ValidatorCannotExitYetMsg = "validator has not been active long enough to ex
// should exit the state's validator registry.
//
// Spec pseudocode definition:
// def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
// """
// Process ``VoluntaryExit`` operation.
// """
// validator = state.validator_registry[exit.validator_index]
// def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
// voluntary_exit = signed_voluntary_exit.message
// validator = state.validators[voluntary_exit.validator_index]
// # Verify the validator is active
// assert is_active_validator(validator, get_current_epoch(state))
// # Verify the validator has not yet exited
// # Verify exit has not been initiated
// assert validator.exit_epoch == FAR_FUTURE_EPOCH
// # Exits must specify an epoch when they become valid; they are not valid before then
// assert get_current_epoch(state) >= exit.epoch
// assert get_current_epoch(state) >= voluntary_exit.epoch
// # Verify the validator has been active long enough
// assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
// # Verify signature
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
// assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain)
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
// signing_root = compute_signing_root(voluntary_exit, domain)
// assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
// # Initiate exit
// initiate_validator_exit(state, exit.validator_index)
// initiate_validator_exit(state, voluntary_exit.validator_index)
func ProcessVoluntaryExits(
_ context.Context,
beaconState iface.BeaconState,
@ -77,22 +76,23 @@ func ProcessVoluntaryExits(
// VerifyExitAndSignature implements the spec defined validation for voluntary exits.
//
// Spec pseudocode definition:
// def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
// """
// Process ``VoluntaryExit`` operation.
// """
// validator = state.validator_registry[exit.validator_index]
// def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
// voluntary_exit = signed_voluntary_exit.message
// validator = state.validators[voluntary_exit.validator_index]
// # Verify the validator is active
// assert is_active_validator(validator, get_current_epoch(state))
// # Verify the validator has not yet exited
// # Verify exit has not been initiated
// assert validator.exit_epoch == FAR_FUTURE_EPOCH
// # Exits must specify an epoch when they become valid; they are not valid before then
// assert get_current_epoch(state) >= exit.epoch
// assert get_current_epoch(state) >= voluntary_exit.epoch
// # Verify the validator has been active long enough
// assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
// # Verify signature
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
// assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain)
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
// signing_root = compute_signing_root(voluntary_exit, domain)
// assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
// # Initiate exit
// initiate_validator_exit(state, voluntary_exit.validator_index)
func VerifyExitAndSignature(
validator iface.ReadOnlyValidator,
currentSlot types.Slot,
@ -122,19 +122,23 @@ func VerifyExitAndSignature(
// verifyExitConditions implements the spec defined validation for voluntary exits(excluding signatures).
//
// Spec pseudocode definition:
// def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
// """
// Process ``VoluntaryExit`` operation.
// """
// validator = state.validator_registry[exit.validator_index]
// def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
// voluntary_exit = signed_voluntary_exit.message
// validator = state.validators[voluntary_exit.validator_index]
// # Verify the validator is active
// assert is_active_validator(validator, get_current_epoch(state))
// # Verify the validator has not yet exited
// # Verify exit has not been initiated
// assert validator.exit_epoch == FAR_FUTURE_EPOCH
// # Exits must specify an epoch when they become valid; they are not valid before then
// assert get_current_epoch(state) >= exit.epoch
// assert get_current_epoch(state) >= voluntary_exit.epoch
// # Verify the validator has been active long enough
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
// # Verify signature
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
// signing_root = compute_signing_root(voluntary_exit, domain)
// assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
// # Initiate exit
// initiate_validator_exit(state, voluntary_exit.validator_index)
func verifyExitConditions(validator iface.ReadOnlyValidator, currentSlot types.Slot, exit *ethpb.VoluntaryExit) error {
currentEpoch := helpers.SlotToEpoch(currentSlot)
// Verify the validator is active.

View File

@ -93,14 +93,15 @@ func IsAggregated(attestation *ethpb.Attestation) bool {
// given epoch.
//
// Spec pseudocode definition:
// def compute_subnet_for_attestation(state: BeaconState, attestation: Attestation) -> uint64:
// def compute_subnet_for_attestation(committees_per_slot: uint64, slot: Slot, committee_index: CommitteeIndex) -> uint64:
// """
// Compute the correct subnet for an attestation for Phase 0.
// Note, this mimics expected Phase 1 behavior where attestations will be mapped to their shard subnet.
// Note, this mimics expected future behavior where attestations will be mapped to their shard subnet.
// """
// slots_since_epoch_start = attestation.data.slot % SLOTS_PER_EPOCH
// committees_since_epoch_start = get_committee_count_at_slot(state, attestation.data.slot) * slots_since_epoch_start
// return (committees_since_epoch_start + attestation.data.index) % ATTESTATION_SUBNET_COUNT
// slots_since_epoch_start = uint64(slot % SLOTS_PER_EPOCH)
// committees_since_epoch_start = committees_per_slot * slots_since_epoch_start
//
// return uint64((committees_since_epoch_start + committee_index) % ATTESTATION_SUBNET_COUNT)
func ComputeSubnetForAttestation(activeValCount uint64, att *ethpb.Attestation) uint64 {
return ComputeSubnetFromCommitteeAndSlot(activeValCount, att.Data.CommitteeIndex, att.Data.Slot)
}
@ -109,14 +110,15 @@ func ComputeSubnetForAttestation(activeValCount uint64, att *ethpb.Attestation)
// the relevant fields from the attestation as function arguments.
//
// Spec pseudocode definition:
// def compute_subnet_for_attestation(state: BeaconState, attestation: Attestation) -> uint64:
// def compute_subnet_for_attestation(committees_per_slot: uint64, slot: Slot, committee_index: CommitteeIndex) -> uint64:
// """
// Compute the correct subnet for an attestation for Phase 0.
// Note, this mimics expected Phase 1 behavior where attestations will be mapped to their shard subnet.
// Note, this mimics expected future behavior where attestations will be mapped to their shard subnet.
// """
// slots_since_epoch_start = attestation.data.slot % SLOTS_PER_EPOCH
// committees_since_epoch_start = get_committee_count_at_slot(state, attestation.data.slot) * slots_since_epoch_start
// return (committees_since_epoch_start + attestation.data.index) % ATTESTATION_SUBNET_COUNT
// slots_since_epoch_start = uint64(slot % SLOTS_PER_EPOCH)
// committees_since_epoch_start = committees_per_slot * slots_since_epoch_start
//
// return uint64((committees_since_epoch_start + committee_index) % ATTESTATION_SUBNET_COUNT)
func ComputeSubnetFromCommitteeAndSlot(activeValCount uint64, comIdx types.CommitteeIndex, attSlot types.Slot) uint64 {
slotSinceStart := SlotsSinceEpochStarts(attSlot)
comCount := SlotCommitteeCount(activeValCount)

View File

@ -30,7 +30,7 @@ func VerifyNilBeaconBlock(b *ethpb.SignedBeaconBlock) error {
// It returns an error if the requested block root is not within the slot range.
//
// Spec pseudocode definition:
// def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Hash:
// def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Root:
// """
// Return the block root at a recent ``slot``.
// """
@ -58,7 +58,7 @@ func StateRootAtSlot(state iface.ReadOnlyBeaconState, slot types.Slot) ([]byte,
// BlockRoot returns the block root stored in the BeaconState for epoch start slot.
//
// Spec pseudocode definition:
// def get_block_root(state: BeaconState, epoch: Epoch) -> Hash:
// def get_block_root(state: BeaconState, epoch: Epoch) -> Root:
// """
// Return the block root at the start of a recent ``epoch``.
// """

View File

@ -12,12 +12,12 @@ import (
// Seed returns the randao seed used for shuffling of a given epoch.
//
// Spec pseudocode definition:
// def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Hash:
// def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Bytes32:
// """
// Return the seed at ``epoch``.
// """
// mix = get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1)) # Avoid underflow
// return hash(domain_type + int_to_bytes(epoch, length=8) + mix)
// return hash(domain_type + uint_to_bytes(epoch) + mix)
func Seed(state iface.ReadOnlyBeaconState, epoch types.Epoch, domain [bls.DomainByteLength]byte) ([32]byte, error) {
// See https://github.com/ethereum/eth2.0-specs/pull/1296 for
// rationale on why offset has to look down by 1.
@ -40,7 +40,7 @@ func Seed(state iface.ReadOnlyBeaconState, epoch types.Epoch, domain [bls.Domain
// of a given slot. It is used to shuffle validators.
//
// Spec pseudocode definition:
// def get_randao_mix(state: BeaconState, epoch: Epoch) -> Hash:
// def get_randao_mix(state: BeaconState, epoch: Epoch) -> Bytes32:
// """
// Return the randao mix at a recent ``epoch``.
// """

View File

@ -47,24 +47,28 @@ func UnShuffledIndex(index types.ValidatorIndex, indexCount uint64, seed [32]byt
// ComputeShuffledIndex returns the shuffled validator index corresponding to seed and index count.
// Spec pseudocode definition:
// def compute_shuffled_index(index: ValidatorIndex, index_count: uint64, seed: Hash) -> ValidatorIndex:
// def compute_shuffled_index(index: uint64, index_count: uint64, seed: Bytes32) -> uint64:
// """
// Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
// Return the shuffled index corresponding to ``seed`` (and ``index_count``).
// """
// assert index < index_count
//
// # Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
// # See the 'generalized domain' algorithm on page 3
// for current_round in range(SHUFFLE_ROUND_COUNT):
// pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count
// flip = ValidatorIndex((pivot + index_count - index) % index_count)
// pivot = bytes_to_uint64(hash(seed + uint_to_bytes(uint8(current_round)))[0:8]) % index_count
// flip = (pivot + index_count - index) % index_count
// position = max(index, flip)
// source = hash(seed + int_to_bytes(current_round, length=1) + int_to_bytes(position // 256, length=4))
// byte = source[(position % 256) // 8]
// source = hash(
// seed
// + uint_to_bytes(uint8(current_round))
// + uint_to_bytes(uint32(position // 256))
// )
// byte = uint8(source[(position % 256) // 8])
// bit = (byte >> (position % 8)) % 2
// index = flip if bit else index
//
// return ValidatorIndex(index)
// return index
func ComputeShuffledIndex(index types.ValidatorIndex, indexCount uint64, seed [32]byte, shuffle bool) (types.ValidatorIndex, error) {
if params.BeaconConfig().ShuffleRoundCount == 0 {
return index, nil

View File

@ -19,7 +19,7 @@ const MaxSlotBuffer = uint64(1 << 7)
// SlotToEpoch returns the epoch number of the input slot.
//
// Spec pseudocode definition:
// def compute_epoch_of_slot(slot: Slot) -> Epoch:
// def compute_epoch_at_slot(slot: Slot) -> Epoch:
// """
// Return the epoch number of ``slot``.
// """

View File

@ -229,19 +229,20 @@ func BeaconProposerIndex(state iface.ReadOnlyBeaconState) (types.ValidatorIndex,
// ComputeProposerIndex returns the index sampled by effective balance, which is used to calculate proposer.
//
// Spec pseudocode definition:
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex:
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex:
// """
// Return from ``indices`` a random index sampled by effective balance.
// """
// assert len(indices) > 0
// MAX_RANDOM_BYTE = 2**8 - 1
// i = 0
// i = uint64(0)
// total = uint64(len(indices))
// while True:
// candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)]
// random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
// candidate_index = indices[compute_shuffled_index(i % total, total, seed)]
// random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32]
// effective_balance = state.validators[candidate_index].effective_balance
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
// return ValidatorIndex(candidate_index)
// return candidate_index
// i += 1
func ComputeProposerIndex(bState iface.ReadOnlyValidators, activeIndices []types.ValidatorIndex, seed [32]byte) (types.ValidatorIndex, error) {
length := uint64(len(activeIndices))

View File

@ -21,39 +21,41 @@ import (
// full deposits were made to the deposit contract and the ChainStart log gets emitted.
//
// Spec pseudocode definition:
// def initialize_beacon_state_from_eth1(eth1_block_hash: Hash,
// eth1_timestamp: uint64,
// deposits: Sequence[Deposit]) -> BeaconState:
// state = BeaconState(
// genesis_time=eth1_timestamp - eth1_timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY,
// eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)),
// latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
// def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
// eth1_timestamp: uint64,
// deposits: Sequence[Deposit]) -> BeaconState:
// fork = Fork(
// previous_version=GENESIS_FORK_VERSION,
// current_version=GENESIS_FORK_VERSION,
// epoch=GENESIS_EPOCH,
// )
// state = BeaconState(
// genesis_time=eth1_timestamp + GENESIS_DELAY,
// fork=fork,
// eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
// latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
// randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
// )
// )
//
// # Process deposits
// leaves = list(map(lambda deposit: deposit.data, deposits))
// for index, deposit in enumerate(deposits):
// deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
// state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
// process_deposit(state, deposit)
// # Process deposits
// leaves = list(map(lambda deposit: deposit.data, deposits))
// for index, deposit in enumerate(deposits):
// deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
// state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
// process_deposit(state, deposit)
//
// # Process activations
// for index, validator in enumerate(state.validators):
// balance = state.balances[index]
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
// if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
// validator.activation_eligibility_epoch = GENESIS_EPOCH
// validator.activation_epoch = GENESIS_EPOCH
// # Process activations
// for index, validator in enumerate(state.validators):
// balance = state.balances[index]
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
// if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
// validator.activation_eligibility_epoch = GENESIS_EPOCH
// validator.activation_epoch = GENESIS_EPOCH
//
// # Populate active_index_roots and compact_committees_roots
// indices_list = List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, GENESIS_EPOCH))
// active_index_root = hash_tree_root(indices_list)
// committee_root = get_compact_committees_root(state, GENESIS_EPOCH)
// for index in range(EPOCHS_PER_HISTORICAL_VECTOR):
// state.active_index_roots[index] = active_index_root
// state.compact_committees_roots[index] = committee_root
// return state
// # Set genesis validators root for domain separation and chain versioning
// state.genesis_validators_root = hash_tree_root(state.validators)
//
// return state
// This method differs from the spec so as to process deposits beforehand instead of the end of the function.
func GenesisBeaconState(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data) (iface.BeaconState, error) {
state, err := EmptyGenesisState()

View File

@ -50,7 +50,7 @@ var processingPipeline = []processFunc{
// ExecuteStateTransition defines the procedure for a state transition function.
//
// Spec pseudocode definition:
// def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> BeaconState:
// def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> None:
// block = signed_block.message
// # Process slots (including those with no blocks) since block
// process_slots(state, block.slot)
@ -62,8 +62,6 @@ var processingPipeline = []processFunc{
// # Verify state root
// if validate_result:
// assert block.state_root == hash_tree_root(state)
// # Return post-state
// return state
func ExecuteStateTransition(
ctx context.Context,
state iface.BeaconState,
@ -111,15 +109,6 @@ func ExecuteStateTransition(
// set of all signatures not verified, so that they can be stored and verified later.
//
// WARNING: This method does not validate any signatures in a block. This method also modifies the passed in state.
//
// Spec pseudocode definition:
// def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
// # Process slots (including those with no blocks) since block
// process_slots(state, block.slot)
// # Process block
// process_block(state, block)
// # Return post-state
// return state
func ExecuteStateTransitionNoVerifyAnySig(
ctx context.Context,
state iface.BeaconState,
@ -164,15 +153,6 @@ func ExecuteStateTransitionNoVerifyAnySig(
//
// WARNING: This method does not validate any BLS signatures. This is used for proposer to compute
// state root before proposing a new block, and this does not modify state.
//
// Spec pseudocode definition:
// def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
// # Process slots (including those with no blocks) since block
// process_slots(state, block.slot)
// # Process block
// process_block(state, block)
// # Return post-state
// return state
func CalculateStateRoot(
ctx context.Context,
state iface.BeaconState,

View File

@ -12,9 +12,7 @@ import (
)
// ToBytes returns integer x to bytes in little-endian format at the specified length.
// Spec pseudocode definition:
// def int_to_bytes(integer: int, length: int) -> bytes:
// return integer.to_bytes(length, 'little')
// Spec defines similar method uint_to_bytes(n: uint) -> bytes, which is equivalent to ToBytes(n, 8).
func ToBytes(x uint64, length int) []byte {
makeLength := length
if length < 8 {