diff --git a/beacon_chain/spec/datatypes/altair.nim b/beacon_chain/spec/datatypes/altair.nim index ad5221484d..5f757c078d 100644 --- a/beacon_chain/spec/datatypes/altair.nim +++ b/beacon_chain/spec/datatypes/altair.nim @@ -83,6 +83,10 @@ type sync_committee_bits*: BitArray[SYNC_COMMITTEE_SIZE] sync_committee_signature*: ValidatorSig + TrustedSyncAggregate* = object + sync_committee_bits*: BitArray[SYNC_COMMITTEE_SIZE] + sync_committee_signature*: TrustedSig + # https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/altair/beacon-chain.md#synccommittee SyncCommittee* = object pubkeys*: HashArray[Limit SYNC_COMMITTEE_SIZE, ValidatorPubKey] @@ -369,7 +373,7 @@ type voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS] # [New in Altair] - sync_aggregate*: SyncAggregate + sync_aggregate*: SyncAggregate # TODO TrustedSyncAggregate after batching SyncnetBits* = BitArray[SYNC_COMMITTEE_SUBNET_COUNT] @@ -393,7 +397,7 @@ type voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS] # [New in Altair] - sync_aggregate*: SyncAggregate + sync_aggregate*: TrustedSyncAggregate # https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/phase0/beacon-chain.md#signedbeaconblock SignedBeaconBlock* = object @@ -431,6 +435,8 @@ type SomeBeaconBlock* = BeaconBlock | SigVerifiedBeaconBlock | TrustedBeaconBlock SomeBeaconBlockBody* = BeaconBlockBody | SigVerifiedBeaconBlockBody | TrustedBeaconBlockBody + SomeSyncAggregate* = SyncAggregate | TrustedSyncAggregate + SyncSubcommitteeIndex* = distinct uint8 IndexInSyncCommittee* = distinct uint16 diff --git a/beacon_chain/spec/datatypes/base.nim b/beacon_chain/spec/datatypes/base.nim index c09a687b09..c75e869e28 100644 --- a/beacon_chain/spec/datatypes/base.nim +++ b/beacon_chain/spec/datatypes/base.nim @@ -623,13 +623,10 @@ proc readValue*(reader: var JsonReader, value: var ForkDigest) static: doAssert high(int) >= high(int32) # `ValidatorIndex` seq handling. -func `[]`*[T](a: var seq[T], b: ValidatorIndex): var T = - a[b.int] - -func `[]=`*[T](a: var seq[T], b: ValidatorIndex, c: T) = +template `[]=`*[T](a: var seq[T], b: ValidatorIndex, c: T) = a[b.int] = c -func `[]`*[T](a: seq[T], b: ValidatorIndex): auto = +template `[]`*[T](a: seq[T], b: ValidatorIndex): auto = # Also var seq (!) a[b.int] # `ValidatorIndex` Nim integration diff --git a/beacon_chain/spec/datatypes/merge.nim b/beacon_chain/spec/datatypes/merge.nim index b422eb1848..e792d9e9ae 100644 --- a/beacon_chain/spec/datatypes/merge.nim +++ b/beacon_chain/spec/datatypes/merge.nim @@ -263,7 +263,7 @@ type attestations*: List[Attestation, Limit MAX_ATTESTATIONS] deposits*: List[Deposit, Limit MAX_DEPOSITS] voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS] - sync_aggregate*: SyncAggregate + sync_aggregate*: SyncAggregate # TODO TrustedSyncAggregate after batching # Execution execution_payload*: ExecutionPayload # [New in Merge] @@ -283,7 +283,7 @@ type attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS] deposits*: List[Deposit, Limit MAX_DEPOSITS] voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS] - sync_aggregate*: SyncAggregate + sync_aggregate*: TrustedSyncAggregate # Execution execution_payload*: ExecutionPayload # [New in Merge] diff --git a/beacon_chain/spec/state_transition_block.nim b/beacon_chain/spec/state_transition_block.nim index f8c02f968b..b7fa3ca779 100644 --- a/beacon_chain/spec/state_transition_block.nim +++ b/beacon_chain/spec/state_transition_block.nim @@ -429,7 +429,7 @@ proc process_operations(cfg: RuntimeConfig, # https://github.com/ethereum/consensus-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#sync-committee-processing proc process_sync_aggregate*( state: var (altair.BeaconState | merge.BeaconState), - aggregate: SyncAggregate, total_active_balance: Gwei, cache: var StateCache): + aggregate: SomeSyncAggregate, total_active_balance: Gwei, cache: var StateCache): Result[void, cstring] {.nbench.} = # Verify sync committee aggregate signature signing over the previous slot # block root @@ -439,21 +439,22 @@ proc process_sync_aggregate*( domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot)) signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain) - var participant_pubkeys: seq[ValidatorPubKey] - for i in 0 ..< committee_pubkeys.len: - if aggregate.sync_committee_bits[i]: - participant_pubkeys.add committee_pubkeys[i] + when aggregate.sync_committee_signature isnot TrustedSig: + var participant_pubkeys: seq[ValidatorPubKey] + for i in 0 ..< committee_pubkeys.len: + if aggregate.sync_committee_bits[i]: + participant_pubkeys.add committee_pubkeys[i] # p2p-interface message validators check for empty sync committees, so it # shouldn't run except as part of test suite. - if participant_pubkeys.len == 0 and - aggregate.sync_committee_signature != default(CookedSig).toValidatorSig(): - return err("process_sync_aggregate: empty sync aggregates need signature of point at infinity") - - # Empty participants allowed - if participant_pubkeys.len > 0 and not blsFastAggregateVerify( - participant_pubkeys, signing_root.data, aggregate.sync_committee_signature): - return err("process_sync_aggregate: invalid signature") + if participant_pubkeys.len == 0 and + aggregate.sync_committee_signature != default(CookedSig).toValidatorSig(): + return err("process_sync_aggregate: empty sync aggregates need signature of point at infinity") + + # Empty participants allowed + if participant_pubkeys.len > 0 and not blsFastAggregateVerify( + participant_pubkeys, signing_root.data, aggregate.sync_committee_signature): + return err("process_sync_aggregate: invalid signature") # Compute participant and proposer rewards let diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index 80ee29b816..789818a8af 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -870,10 +870,13 @@ func process_effective_balance_updates*(state: var ForkyBeaconState) {.nbench.} let effective_balance = state.validators.asSeq()[index].effective_balance if balance + DOWNWARD_THRESHOLD < effective_balance or effective_balance + UPWARD_THRESHOLD < balance: - state.validators[index].effective_balance = + let new_effective_balance = min( balance - balance mod EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + # Protect against unnecessary cache invalidation + if new_effective_balance != effective_balance: + state.validators[index].effective_balance = new_effective_balance # https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/phase0/beacon-chain.md#slashings-balances-updates func process_slashings_reset*(state: var ForkyBeaconState) {.nbench.} = @@ -946,13 +949,13 @@ func process_inactivity_updates*( previous_epoch = get_previous_epoch(state) # get_eligible_validator_indices() not_in_inactivity_leak = not is_in_inactivity_leak(state) - state.inactivity_scores.clearCache() for index in 0'u64 ..< state.validators.lenu64: if not is_eligible_validator(info.validators[index]): continue # Increase the inactivity score of inactive validators - var inactivity_score = state.inactivity_scores.asSeq()[index] + let pre_inactivity_score = state.inactivity_scores.asSeq()[index] + var inactivity_score = pre_inactivity_score # TODO activeness already checked; remove redundant checks between # is_active_validator and is_unslashed_participating_index if is_unslashed_participating_index( @@ -964,7 +967,9 @@ func process_inactivity_updates*( # leak-free epoch if not_in_inactivity_leak: inactivity_score -= min(INACTIVITY_SCORE_RECOVERY_RATE.uint64, inactivity_score) - state.inactivity_scores.asSeq()[index] = inactivity_score + # Most inactivity scores remain at 0 - avoid invalidating cache + if pre_inactivity_score != inactivity_score: + state.inactivity_scores[index] = inactivity_score # https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/phase0/beacon-chain.md#epoch-processing proc process_epoch*(