diff --git a/beacon-chain/core/blocks/attestation.go b/beacon-chain/core/blocks/attestation.go index 3b7da7049176..34ba477c9158 100644 --- a/beacon-chain/core/blocks/attestation.go +++ b/beacon-chain/core/blocks/attestation.go @@ -64,7 +64,7 @@ func ProcessAttestations( // assert data.source == state.previous_justified_checkpoint // state.previous_epoch_attestations.append(pending_attestation) // -// # Check signature +// # Verify signature // assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) func ProcessAttestation( ctx context.Context, diff --git a/beacon-chain/core/blocks/eth1_data.go b/beacon-chain/core/blocks/eth1_data.go index 62a794296ecb..978c7b543523 100644 --- a/beacon-chain/core/blocks/eth1_data.go +++ b/beacon-chain/core/blocks/eth1_data.go @@ -19,7 +19,7 @@ import ( // def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None: // state.eth1_data_votes.append(body.eth1_data) // if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH: -// state.latest_eth1_data = body.eth1_data +// state.eth1_data = body.eth1_data func ProcessEth1DataInBlock(_ context.Context, beaconState iface.BeaconState, b *ethpb.SignedBeaconBlock) (iface.BeaconState, error) { block := b.Block if beaconState == nil { diff --git a/beacon-chain/core/blocks/header.go b/beacon-chain/core/blocks/header.go index d2577650c18a..c9cf27dfc11e 100644 --- a/beacon-chain/core/blocks/header.go +++ b/beacon-chain/core/blocks/header.go @@ -19,23 +19,24 @@ import ( // def process_block_header(state: BeaconState, block: BeaconBlock) -> None: // # Verify that the slots match // assert block.slot == state.slot -// # Verify that proposer index is the correct index +// # Verify that the block is newer than latest block header +// assert block.slot > state.latest_block_header.slot +// # Verify that proposer index is the correct index // assert block.proposer_index == get_beacon_proposer_index(state) // # Verify that the parent matches // assert block.parent_root == hash_tree_root(state.latest_block_header) -// # Save current block as the new latest block +// # Cache current block as the new latest block // state.latest_block_header = BeaconBlockHeader( // slot=block.slot, +// proposer_index=block.proposer_index, // parent_root=block.parent_root, -// # state_root: zeroed, overwritten in the next `process_slot` call +// state_root=Bytes32(), # Overwritten in the next process_slot call // body_root=hash_tree_root(block.body), -// # signature is always zeroed // ) +// // # Verify proposer is not slashed -// proposer = state.validators[get_beacon_proposer_index(state)] +// proposer = state.validators[block.proposer_index] // assert not proposer.slashed -// # Verify proposer signature -// assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER)) func ProcessBlockHeader( _ context.Context, beaconState iface.BeaconState, @@ -64,20 +65,23 @@ func ProcessBlockHeader( // def process_block_header(state: BeaconState, block: BeaconBlock) -> None: // # Verify that the slots match // assert block.slot == state.slot -// # Verify that proposer index is the correct index +// # Verify that the block is newer than latest block header +// assert block.slot > state.latest_block_header.slot +// # Verify that proposer index is the correct index // assert block.proposer_index == get_beacon_proposer_index(state) // # Verify that the parent matches // assert block.parent_root == hash_tree_root(state.latest_block_header) -// # Save current block as the new latest block +// # Cache current block as the new latest block // state.latest_block_header = BeaconBlockHeader( // slot=block.slot, +// proposer_index=block.proposer_index, // parent_root=block.parent_root, -// # state_root: zeroed, overwritten in the next `process_slot` call +// state_root=Bytes32(), # Overwritten in the next process_slot call // body_root=hash_tree_root(block.body), -// # signature is always zeroed // ) +// // # Verify proposer is not slashed -// proposer = state.validators[get_beacon_proposer_index(state)] +// proposer = state.validators[block.proposer_index] // assert not proposer.slashed func ProcessBlockHeaderNoVerify( beaconState iface.BeaconState, diff --git a/beacon-chain/core/blocks/proposer_slashing.go b/beacon-chain/core/blocks/proposer_slashing.go index c32734b7c82d..d839b9f126e3 100644 --- a/beacon-chain/core/blocks/proposer_slashing.go +++ b/beacon-chain/core/blocks/proposer_slashing.go @@ -19,22 +19,25 @@ import ( // // Spec pseudocode definition: // def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None: -// """ -// Process ``ProposerSlashing`` operation. -// """ -// proposer = state.validator_registry[proposer_slashing.proposer_index] -// # Verify slots match -// assert proposer_slashing.header_1.slot == proposer_slashing.header_2.slot -// # But the headers are different -// assert proposer_slashing.header_1 != proposer_slashing.header_2 -// # Check proposer is slashable +// header_1 = proposer_slashing.signed_header_1.message +// header_2 = proposer_slashing.signed_header_2.message +// +// # Verify header slots match +// assert header_1.slot == header_2.slot +// # Verify header proposer indices match +// assert header_1.proposer_index == header_2.proposer_index +// # Verify the headers are different +// assert header_1 != header_2 +// # Verify the proposer is slashable +// proposer = state.validators[header_1.proposer_index] // assert is_slashable_validator(proposer, get_current_epoch(state)) -// # Signatures are valid -// for header in (proposer_slashing.header_1, proposer_slashing.header_2): -// domain = get_domain(state, DOMAIN_BEACON_PROPOSER, slot_to_epoch(header.slot)) -// assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain) +// # Verify signatures +// for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): +// domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) +// signing_root = compute_signing_root(signed_header.message, domain) +// assert bls.Verify(proposer.pubkey, signing_root, signed_header.signature) // -// slash_validator(state, proposer_slashing.proposer_index) +// slash_validator(state, header_1.proposer_index) func ProcessProposerSlashings( _ context.Context, beaconState iface.BeaconState, diff --git a/beacon-chain/core/epoch/epoch_processing.go b/beacon-chain/core/epoch/epoch_processing.go index 1480195dcb5b..2a09f2370c3f 100644 --- a/beacon-chain/core/epoch/epoch_processing.go +++ b/beacon-chain/core/epoch/epoch_processing.go @@ -157,7 +157,7 @@ func ProcessRegistryUpdates(state iface.BeaconState) (iface.BeaconState, error) // for index, validator in enumerate(state.validators): // if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch: // increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow -// penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance +// penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance // penalty = penalty_numerator // total_balance * increment // decrease_balance(state, ValidatorIndex(index), penalty) func ProcessSlashings(state iface.BeaconState) (iface.BeaconState, error) { @@ -474,9 +474,9 @@ func UnslashedAttestingIndices(state iface.ReadOnlyBeaconState, atts []*pb.Pendi // // Spec pseudocode definition: // def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: -// total_balance = get_total_active_balance(state) -// effective_balance = state.validator_registry[index].effective_balance -// return effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH +// total_balance = get_total_active_balance(state) +// effective_balance = state.validators[index].effective_balance +// return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH) func BaseReward(state iface.ReadOnlyBeaconState, index types.ValidatorIndex) (uint64, error) { totalBalance, err := helpers.TotalActiveBalance(state) if err != nil { diff --git a/beacon-chain/core/helpers/attestation.go b/beacon-chain/core/helpers/attestation.go index f29e4bd3fdf3..fb376a27bc1d 100644 --- a/beacon-chain/core/helpers/attestation.go +++ b/beacon-chain/core/helpers/attestation.go @@ -53,7 +53,7 @@ func ValidateSlotTargetEpoch(data *ethpb.AttestationData) error { // def is_aggregator(state: BeaconState, slot: Slot, index: CommitteeIndex, slot_signature: BLSSignature) -> bool: // committee = get_beacon_committee(state, slot, index) // modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE) -// return bytes_to_int(hash(slot_signature)[0:8]) % modulo == 0 +// return bytes_to_uint64(hash(slot_signature)[0:8]) % modulo == 0 func IsAggregator(committeeCount uint64, slotSig []byte) (bool, error) { modulo := uint64(1) if committeeCount/params.BeaconConfig().TargetAggregatorsPerCommittee > 1 { @@ -69,7 +69,7 @@ func IsAggregator(committeeCount uint64, slotSig []byte) (bool, error) { // Spec pseudocode definition: // def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature: // signatures = [attestation.signature for attestation in attestations] -// return bls_aggregate_signatures(signatures) +// return bls.Aggregate(signatures) func AggregateSignature(attestations []*ethpb.Attestation) (bls.Signature, error) { sigs := make([]bls.Signature, len(attestations)) var err error diff --git a/beacon-chain/core/helpers/committee.go b/beacon-chain/core/helpers/committee.go index 3138d2fa9511..6b64dd11d6ca 100644 --- a/beacon-chain/core/helpers/committee.go +++ b/beacon-chain/core/helpers/committee.go @@ -34,9 +34,9 @@ var proposerIndicesCache = cache.NewProposerIndicesCache() // """ // Return the number of committees in each slot for the given ``epoch``. // """ -// return max(1, min( +// return max(uint64(1), min( // MAX_COMMITTEES_PER_SLOT, -// len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, +// uint64(len(get_active_validator_indices(state, epoch))) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, // )) func SlotCommitteeCount(activeValidatorCount uint64) uint64 { var committeePerSlot = activeValidatorCount / uint64(params.BeaconConfig().SlotsPerEpoch) / params.BeaconConfig().TargetCommitteeSize @@ -121,15 +121,15 @@ func BeaconCommittee( // // Spec pseudocode definition: // def compute_committee(indices: Sequence[ValidatorIndex], -// seed: Hash, +// seed: Bytes32, // index: uint64, // count: uint64) -> Sequence[ValidatorIndex]: // """ // Return the committee corresponding to ``indices``, ``seed``, ``index``, and committee ``count``. // """ // start = (len(indices) * index) // count -// end = (len(indices) * (index + 1)) // count -// return [indices[compute_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end) +// end = (len(indices) * uint64(index + 1)) // count +// return [indices[compute_shuffled_index(uint64(i), uint64(len(indices)), seed)] for i in range(start, end)] func ComputeCommittee( indices []types.ValidatorIndex, seed [32]byte, diff --git a/beacon-chain/core/helpers/rewards_penalties.go b/beacon-chain/core/helpers/rewards_penalties.go index 85b6db02df6b..2e8bca9d3f0c 100644 --- a/beacon-chain/core/helpers/rewards_penalties.go +++ b/beacon-chain/core/helpers/rewards_penalties.go @@ -14,6 +14,7 @@ import ( // """ // Return the combined effective balance of the ``indices``. // ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero. +// Math safe up to ~10B ETH, afterwhich this overflows uint64. // """ // return Gwei(max(EFFECTIVE_BALANCE_INCREMENT, sum([state.validators[index].effective_balance for index in indices]))) func TotalBalance(state iface.ReadOnlyValidators, indices []types.ValidatorIndex) uint64 { @@ -42,6 +43,7 @@ func TotalBalance(state iface.ReadOnlyValidators, indices []types.ValidatorIndex // def get_total_active_balance(state: BeaconState) -> Gwei: // """ // Return the combined effective balance of the active validators. +// Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero. // """ // return get_total_balance(state, set(get_active_validator_indices(state, get_current_epoch(state)))) func TotalActiveBalance(state iface.ReadOnlyBeaconState) (uint64, error) { diff --git a/beacon-chain/core/helpers/slot_epoch.go b/beacon-chain/core/helpers/slot_epoch.go index 3feae3e37b40..b6374105aa51 100644 --- a/beacon-chain/core/helpers/slot_epoch.go +++ b/beacon-chain/core/helpers/slot_epoch.go @@ -21,7 +21,7 @@ const MaxSlotBuffer = uint64(1 << 7) // Spec pseudocode definition: // def compute_epoch_at_slot(slot: Slot) -> Epoch: // """ -// Return the epoch number of ``slot``. +// Return the epoch number at ``slot``. // """ // return Epoch(slot // SLOTS_PER_EPOCH) func SlotToEpoch(slot types.Slot) types.Epoch { @@ -36,7 +36,7 @@ func SlotToEpoch(slot types.Slot) types.Epoch { // """ // Return the current epoch. // """ -// return compute_epoch_of_slot(state.slot) +// return compute_epoch_at_slot(state.slot) func CurrentEpoch(state iface.ReadOnlyBeaconState) types.Epoch { return SlotToEpoch(state.Slot()) } diff --git a/beacon-chain/core/helpers/validators.go b/beacon-chain/core/helpers/validators.go index d445468fc58f..47b832671797 100644 --- a/beacon-chain/core/helpers/validators.go +++ b/beacon-chain/core/helpers/validators.go @@ -156,7 +156,7 @@ func ActivationExitEpoch(epoch types.Epoch) types.Epoch { // Return the validator churn limit for the current epoch. // """ // active_validator_indices = get_active_validator_indices(state, get_current_epoch(state)) -// return max(MIN_PER_EPOCH_CHURN_LIMIT, len(active_validator_indices) // CHURN_LIMIT_QUOTIENT) +// return max(MIN_PER_EPOCH_CHURN_LIMIT, uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT) func ValidatorChurnLimit(activeValidatorCount uint64) (uint64, error) { churnLimit := activeValidatorCount / params.BeaconConfig().ChurnLimitQuotient if churnLimit < params.BeaconConfig().MinPerEpochChurnLimit { @@ -173,7 +173,7 @@ func ValidatorChurnLimit(activeValidatorCount uint64) (uint64, error) { // Return the beacon proposer index at the current slot. // """ // epoch = get_current_epoch(state) -// seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + int_to_bytes(state.slot, length=8)) +// seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + uint_to_bytes(state.slot)) // indices = get_active_validator_indices(state, epoch) // return compute_proposer_index(state, indices, seed) func BeaconProposerIndex(state iface.ReadOnlyBeaconState) (types.ValidatorIndex, error) { diff --git a/beacon-chain/core/state/transition.go b/beacon-chain/core/state/transition.go index 187e81585831..86e64b8697f3 100644 --- a/beacon-chain/core/state/transition.go +++ b/beacon-chain/core/state/transition.go @@ -109,11 +109,9 @@ func ExecuteStateTransition( // # Cache state root // previous_state_root = hash_tree_root(state) // state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root -// // # Cache latest block header state root // if state.latest_block_header.state_root == Bytes32(): // state.latest_block_header.state_root = previous_state_root -// // # Cache block root // previous_block_root = hash_tree_root(state.latest_block_header) // state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root @@ -192,14 +190,13 @@ func ProcessSlotsUsingNextSlotCache( // // Spec pseudocode definition: // def process_slots(state: BeaconState, slot: Slot) -> None: -// assert state.slot <= slot +// assert state.slot < slot // while state.slot < slot: // process_slot(state) -// # Process epoch on the first slot of the next epoch +// # Process epoch on the start slot of the next epoch // if (state.slot + 1) % SLOTS_PER_EPOCH == 0: // process_epoch(state) -// state.slot += 1 -// ] +// state.slot = Slot(state.slot + 1) func ProcessSlots(ctx context.Context, state iface.BeaconState, slot types.Slot) (iface.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots") defer span.End() diff --git a/shared/attestationutil/attestation_utils.go b/shared/attestationutil/attestation_utils.go index cf9b0f9f244a..bed032bf7eb1 100644 --- a/shared/attestationutil/attestation_utils.go +++ b/shared/attestationutil/attestation_utils.go @@ -88,18 +88,18 @@ func AttestingIndices(bf bitfield.Bitfield, committee []types.ValidatorIndex) ([ // // Spec pseudocode definition: // def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool: -// """ -// Check if ``indexed_attestation`` has sorted and unique indices and a valid aggregate signature. -// """ -// # Verify indices are sorted and unique -// indices = indexed_attestation.attesting_indices -// if not indices == sorted(set(indices)): +// """ +// Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature. +// """ +// # Verify indices are sorted and unique +// indices = indexed_attestation.attesting_indices +// if len(indices) == 0 or not indices == sorted(set(indices)): // return False -// # Verify aggregate signature -// pubkeys = [state.validators[i].pubkey for i in indices] -// domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) -// signing_root = compute_signing_root(indexed_attestation.data, domain) -// return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) +// # Verify aggregate signature +// pubkeys = [state.validators[i].pubkey for i in indices] +// domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) +// signing_root = compute_signing_root(indexed_attestation.data, domain) +// return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedAttestation, pubKeys []bls.PublicKey, domain []byte) error { ctx, span := trace.StartSpan(ctx, "attestationutil.VerifyIndexedAttestationSig") defer span.End() @@ -128,24 +128,17 @@ func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedA // Spec pseudocode definition: // def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool: // """ -// Check if ``indexed_attestation``is not empty, has valid indices, and signature. +// Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature. // """ +// # Verify indices are sorted and unique // indices = indexed_attestation.attesting_indices -// -// # Verify max number of indices -// if not len(indices) <= MAX_VALIDATORS_PER_COMMITTEE: +// if len(indices) == 0 or not indices == sorted(set(indices)): // return False -// # Verify indices are sorted and unique -// if not indices == sorted(set(indices)): // # Verify aggregate signature -// if not bls_verify( -// pubkey=bls_aggregate_pubkeys([state.validators[i].pubkey for i in indices]), -// message_hash=hash_tree_root(indexed_attestation.data), -// signature=indexed_attestation.signature, -// domain=get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch), -// ): -// return False -// return True +// pubkeys = [state.validators[i].pubkey for i in indices] +// domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) +// signing_root = compute_signing_root(indexed_attestation.data, domain) +// return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) func IsValidAttestationIndices(ctx context.Context, indexedAttestation *ethpb.IndexedAttestation) error { ctx, span := trace.StartSpan(ctx, "attestationutil.IsValidAttestationIndices") defer span.End() diff --git a/shared/depositutil/deposit.go b/shared/depositutil/deposit.go index 065be8fd808a..7eea25c5a0d3 100644 --- a/shared/depositutil/deposit.go +++ b/shared/depositutil/deposit.go @@ -25,7 +25,7 @@ import ( // - Let amount be the amount in Gwei to be deposited by the validator where MIN_DEPOSIT_AMOUNT <= amount <= MAX_EFFECTIVE_BALANCE. // - Set deposit_data.amount = amount. // - Let signature be the result of bls_sign of the signing_root(deposit_data) with domain=compute_domain(DOMAIN_DEPOSIT). (Deposits are valid regardless of fork version, compute_domain will default to zeroes there). -// - Send a transaction on the Ethereum 1.0 chain to DEPOSIT_CONTRACT_ADDRESS executing def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96]) along with a deposit of amount Gwei. +// - Send a transaction on the Ethereum 1.0 chain to DEPOSIT_CONTRACT_ADDRESS executing `deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96])` along with a deposit of amount Gwei. // // See: https://github.com/ethereum/eth2.0-specs/blob/master/specs/validator/0_beacon-chain-validator.md#submit-deposit func DepositInput(depositKey, withdrawalKey bls.SecretKey, amountInGwei uint64) (*ethpb.Deposit_Data, [32]byte, error) {