Skip to content

Commit 00c22d0

Browse files
authored
Merge branch 'unstable' into column-syncer
2 parents 6f345dc + f1e6eeb commit 00c22d0

File tree

13 files changed

+108
-47
lines changed

13 files changed

+108
-47
lines changed

AllTests-mainnet.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ AllTests-mainnet
1111
+ Attestations with disjoint comittee bits and equal data into single on-chain aggregate [Pr OK
1212
+ Can add and retrieve simple electra attestations [Preset: mainnet] OK
1313
+ Working with electra aggregates [Preset: mainnet] OK
14+
+ simple add and get with electra nonzero committee [Preset: mainnet] OK
1415
```
1516
## Attestation pool processing [Preset: mainnet]
1617
```diff

beacon_chain/conf.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ type
576576
name: "discv5" .}: bool
577577

578578
dumpEnabled* {.
579-
desc: "Write SSZ dumps of blocks, attestations and states to data dir"
579+
desc: "Write SSZ dumps of blocks and states to data dir"
580580
defaultValue: false
581581
name: "dump" .}: bool
582582

beacon_chain/consensus_object_pools/attestation_pool.nim

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# beacon_chain
2-
# Copyright (c) 2018-2024 Status Research & Development GmbH
2+
# Copyright (c) 2018-2025 Status Research & Development GmbH
33
# Licensed and distributed under either of
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@@ -8,7 +8,6 @@
88
{.push raises: [].}
99

1010
import
11-
std/algorithm,
1211
# Status libraries
1312
metrics,
1413
chronicles, stew/byteutils,
@@ -19,6 +18,7 @@ import
1918
../fork_choice/fork_choice,
2019
../beacon_clock
2120

21+
from std/algorithm import sort
2222
from std/sequtils import keepItIf, maxIndex
2323

2424
export blockchain_dag, fork_choice
@@ -66,6 +66,10 @@ type
6666
## voted on different states - this map keeps track of each vote keyed by
6767
## getAttestationCandidateKey()
6868

69+
CandidateIdxType {.pure.} = enum
70+
phase0Idx
71+
electraIdx
72+
6973
AttestationPool* = object
7074
## The attestation pool keeps track of all attestations that potentially
7175
## could be added to a block during block production.
@@ -198,11 +202,12 @@ proc addForkChoiceVotes(
198202
# hopefully the fork choice will heal itself over time.
199203
error "Couldn't add attestation to fork choice, bug?", err = v.error()
200204

201-
func candidateIdx(pool: AttestationPool, slot: Slot,
202-
isElectra: bool = false): Opt[int] =
205+
func candidateIdx(
206+
pool: AttestationPool, slot: Slot, candidateIdxType: CandidateIdxType):
207+
Opt[int] =
203208
static: doAssert pool.phase0Candidates.len == pool.electraCandidates.len
204209

205-
let poolLength = if isElectra:
210+
let poolLength = if candidateIdxtype == CandidateIdxType.electraIdx:
206211
pool.electraCandidates.lenu64 else: pool.phase0Candidates.lenu64
207212

208213
if slot >= pool.startingSlot and
@@ -413,6 +418,11 @@ proc addAttestation(
413418

414419
true
415420

421+
func getAttestationCandidateKey(
422+
attestationDataRoot: Eth2Digest, committee_index: CommitteeIndex):
423+
Eth2Digest =
424+
hash_tree_root([attestationDataRoot, hash_tree_root(committee_index.uint64)])
425+
416426
func getAttestationCandidateKey(
417427
data: AttestationData,
418428
committee_index: Opt[CommitteeIndex]): Eth2Digest =
@@ -424,13 +434,7 @@ func getAttestationCandidateKey(
424434
# i.e. no committees selected, so it can't be an actual Electra attestation
425435
hash_tree_root(data)
426436
else:
427-
hash_tree_root([hash_tree_root(data),
428-
hash_tree_root(committee_index.get.uint64)])
429-
430-
func getAttestationCandidateKey(
431-
attestationDataRoot: Eth2Digest, committee_index: CommitteeIndex):
432-
Eth2Digest =
433-
hash_tree_root([attestationDataRoot, hash_tree_root(committee_index.uint64)])
437+
getAttestationCandidateKey(hash_tree_root(data), committee_index.get)
434438

435439
proc addAttestation*(
436440
pool: var AttestationPool,
@@ -450,7 +454,14 @@ proc addAttestation*(
450454

451455
updateCurrent(pool, wallTime.slotOrZero)
452456

453-
let candidateIdx = pool.candidateIdx(attestation.data.slot)
457+
when kind(typeof(attestation)) == ConsensusFork.Electra:
458+
let candidateIdx = pool.candidateIdx(
459+
attestation.data.slot, CandidateIdxType.electraIdx)
460+
elif kind(typeof(attestation)) == ConsensusFork.Phase0:
461+
let candidateIdx = pool.candidateIdx(
462+
attestation.data.slot, CandidateIdxType.phase0Idx)
463+
else:
464+
static: doAssert false
454465
if candidateIdx.isNone:
455466
debug "Skipping old attestation for block production",
456467
startingSlot = pool.startingSlot
@@ -464,14 +475,20 @@ proc addAttestation*(
464475
# creating an unnecessary AttestationEntry on the hot path and avoiding
465476
# multiple lookups
466477
template addAttToPool(attCandidates: untyped, entry: untyped, committee_index: untyped) =
467-
let attestation_data_root = getAttestationCandidateKey(entry.data, committee_index)
468-
469-
attCandidates[candidateIdx.get()].withValue(attestation_data_root, entry) do:
478+
# `AttestationData.index == 0` in Electra, but the attestation pool always
479+
# represents an AttestationEntry regardless as having the actual committee
480+
# index. The entry, therefore, is not the same as the AttestationData, and
481+
# thus cannot function as the basis for deriving the hashtable key for the
482+
# entry. Instead use the (correctly data.index == 0) attestation passed to
483+
# addAttestation.
484+
let candidate_key = getAttestationCandidateKey(attestation.data, committee_index)
485+
486+
attCandidates[candidateIdx.get()].withValue(candidate_key, entry) do:
470487
if not addAttestation(entry[], attestation, index_in_committee, signature):
471488
return
472489
do:
473490
if not addAttestation(
474-
attCandidates[candidateIdx.get()].mgetOrPut(attestation_data_root, entry),
491+
attCandidates[candidateIdx.get()].mgetOrPut(candidate_key, entry),
475492
attestation, index_in_committee, signature):
476493
# Returns from overall function, not only template
477494
return
@@ -540,7 +557,7 @@ func covers*(
540557
## the existing aggregates, making it redundant
541558
## the `var` attestation pool is needed to use `withValue`, else Table becomes
542559
## unusably inefficient
543-
let candidateIdx = pool.candidateIdx(data.slot)
560+
let candidateIdx = pool.candidateIdx(data.slot, CandidateIdxType.phase0Idx)
544561
if candidateIdx.isNone:
545562
return false
546563

@@ -558,7 +575,7 @@ func covers*(
558575
## the existing aggregates, making it redundant
559576
## the `var` attestation pool is needed to use `withValue`, else Table becomes
560577
## unusably inefficient
561-
let candidateIdx = pool.candidateIdx(data.slot)
578+
let candidateIdx = pool.candidateIdx(data.slot, CandidateIdxType.electraIdx)
562579
if candidateIdx.isNone:
563580
return false
564581

@@ -593,7 +610,8 @@ iterator attestations*(
593610
committee_index: Opt[CommitteeIndex]): phase0.Attestation =
594611
let candidateIndices =
595612
if slot.isSome():
596-
let candidateIdx = pool.candidateIdx(slot.get())
613+
let candidateIdx = pool.candidateIdx(
614+
slot.get(), CandidateIdxType.phase0Idx)
597615
if candidateIdx.isSome():
598616
candidateIdx.get() .. candidateIdx.get()
599617
else:
@@ -622,7 +640,8 @@ iterator electraAttestations*(
622640
committee_index: Opt[CommitteeIndex]): electra.Attestation =
623641
let candidateIndices =
624642
if slot.isSome():
625-
let candidateIdx = pool.candidateIdx(slot.get(), true)
643+
let candidateIdx = pool.candidateIdx(
644+
slot.get(), CandidateIdxType.electraIdx)
626645
if candidateIdx.isSome():
627646
candidateIdx.get() .. candidateIdx.get()
628647
else:
@@ -795,7 +814,7 @@ proc getAttestationsForBlock*(pool: var AttestationPool,
795814

796815
let
797816
slot = Slot(maxAttestationSlot - i)
798-
candidateIdx = pool.candidateIdx(slot)
817+
candidateIdx = pool.candidateIdx(slot, CandidateIdxType.phase0Idx)
799818

800819
if candidateIdx.isNone():
801820
# Passed the collection horizon - shouldn't happen because it's based on
@@ -931,7 +950,7 @@ proc getElectraAttestationsForBlock*(
931950

932951
let
933952
slot = Slot(maxAttestationSlot - i)
934-
candidateIdx = pool.candidateIdx(slot)
953+
candidateIdx = pool.candidateIdx(slot, CandidateIdxType.electraIdx)
935954

936955
if candidateIdx.isNone():
937956
# Passed the collection horizon - shouldn't happen because it's based on
@@ -1096,7 +1115,7 @@ func getElectraAggregatedAttestation*(
10961115
Opt[electra.Attestation] =
10971116

10981117
let
1099-
candidateIdx = pool.candidateIdx(slot)
1118+
candidateIdx = pool.candidateIdx(slot, CandidateIdxType.electraIdx)
11001119
if candidateIdx.isNone:
11011120
return Opt.none(electra.Attestation)
11021121

@@ -1124,7 +1143,7 @@ func getElectraAggregatedAttestation*(
11241143
# be used here, because otherwise they wouldn't have the same value. It thus
11251144
# leaves the cross-committee aggregation for getElectraAttestationsForBlock,
11261145
# which does do this.
1127-
let candidateIdx = pool.candidateIdx(slot)
1146+
let candidateIdx = pool.candidateIdx(slot, CandidateIdxType.electraIdx)
11281147
if candidateIdx.isNone:
11291148
return Opt.none(electra.Attestation)
11301149

@@ -1147,7 +1166,7 @@ func getPhase0AggregatedAttestation*(
11471166
pool: var AttestationPool, slot: Slot, attestation_data_root: Eth2Digest):
11481167
Opt[phase0.Attestation] =
11491168
let
1150-
candidateIdx = pool.candidateIdx(slot)
1169+
candidateIdx = pool.candidateIdx(slot, CandidateIdxType.phase0Idx)
11511170
if candidateIdx.isNone:
11521171
return Opt.none(phase0.Attestation)
11531172

@@ -1168,7 +1187,7 @@ func getPhase0AggregatedAttestation*(
11681187
## Select the attestation that has the most votes going for it in the given
11691188
## slot/index
11701189
## https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#construct-aggregate
1171-
let candidateIdx = pool.candidateIdx(slot)
1190+
let candidateIdx = pool.candidateIdx(slot, CandidateIdxType.phase0Idx)
11721191
if candidateIdx.isNone:
11731192
return Opt.none(phase0.Attestation)
11741193

beacon_chain/nimbus_beacon_node.nim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ proc initFullNode(
536536
syncManager = newSyncManager[Peer, PeerId](
537537
node.network.peerPool,
538538
dag.cfg.DENEB_FORK_EPOCH,
539+
dag.cfg.FULU_FORK_EPOCH,
539540
dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS,
540541
dag.cfg.MAX_BLOBS_PER_BLOCK_ELECTRA,
541542
SyncQueueKind.Forward, getLocalHeadSlot,
@@ -547,6 +548,7 @@ proc initFullNode(
547548
backfiller = newSyncManager[Peer, PeerId](
548549
node.network.peerPool,
549550
dag.cfg.DENEB_FORK_EPOCH,
551+
dag.cfg.FULU_FORK_EPOCH,
550552
dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS,
551553
dag.cfg.MAX_BLOBS_PER_BLOCK_ELECTRA,
552554
SyncQueueKind.Backward, getLocalHeadSlot,
@@ -563,6 +565,7 @@ proc initFullNode(
563565
untrustedManager = newSyncManager[Peer, PeerId](
564566
node.network.peerPool,
565567
dag.cfg.DENEB_FORK_EPOCH,
568+
dag.cfg.FULU_FORK_EPOCH,
566569
dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS,
567570
dag.cfg.MAX_BLOBS_PER_BLOCK_ELECTRA,
568571
SyncQueueKind.Backward, getLocalHeadSlot,

beacon_chain/sync/sync_manager.nim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type
5656
SyncManager*[A, B] = ref object
5757
pool: PeerPool[A, B]
5858
DENEB_FORK_EPOCH: Epoch
59+
FULU_FORK_EPOCH: Epoch
5960
MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: uint64
6061
MAX_BLOBS_PER_BLOCK_ELECTRA: uint64
6162
responseTimeout: chronos.Duration
@@ -142,6 +143,7 @@ proc initQueue[A, B](man: SyncManager[A, B]) =
142143
proc newSyncManager*[A, B](
143144
pool: PeerPool[A, B],
144145
denebEpoch: Epoch,
146+
fuluEpoch: Epoch,
145147
minEpochsForBlobSidecarsRequests: uint64,
146148
maxBlobsPerBlockElectra: uint64,
147149
direction: SyncQueueKind,
@@ -171,6 +173,7 @@ proc newSyncManager*[A, B](
171173
var res = SyncManager[A, B](
172174
pool: pool,
173175
DENEB_FORK_EPOCH: denebEpoch,
176+
FULU_FORK_EPOCH: fuluEpoch,
174177
MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: minEpochsForBlobSidecarsRequests,
175178
MAX_BLOBS_PER_BLOCK_ELECTRA: maxBlobsPerBlockElectra,
176179
getLocalHeadSlot: getLocalHeadSlotCb,
@@ -212,7 +215,7 @@ proc shouldGetBlobs[A, B](man: SyncManager[A, B], s: Slot): bool =
212215
let
213216
wallEpoch = man.getLocalWallSlot().epoch
214217
epoch = s.epoch()
215-
(epoch >= man.DENEB_FORK_EPOCH) and
218+
(epoch >= man.DENEB_FORK_EPOCH) and (epoch < man.FULU_FORK_EPOCH) and
216219
(wallEpoch < man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS or
217220
epoch >= wallEpoch - man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS)
218221

beacon_chain/sync/sync_queue.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ iterator blocks(
692692
proc push*[T](sq: SyncQueue[T], sr: SyncRequest[T]) =
693693
## Push failed request back to queue.
694694
let pos = sq.find(sr).valueOr:
695-
debug "Request is no more relevant", request = sr
695+
debug "Request is not relevant anymore", request = sr
696696
return
697697
sq.del(pos)
698698

@@ -768,7 +768,7 @@ proc push*[T](
768768

769769
template findPosition(sq, sr: untyped): SyncPosition =
770770
sq.find(sr).valueOr:
771-
debug "Request is no more relevant",
771+
debug "Request is not relevant anymore",
772772
request = sr, sync_ident = sq.ident, topics = "syncman"
773773
# Request is not in queue anymore, probably reset happened.
774774
return
@@ -790,7 +790,7 @@ proc push*[T](
790790
let res = await sq.waitForChanges()
791791
if res:
792792
# SyncQueue reset happen
793-
debug "Request is no more relevant, reset happen",
793+
debug "Request is not relevant anymore, reset has happened",
794794
request = sr,
795795
sync_ident = sq.ident,
796796
topics = "syncman"

beacon_chain/validator_client/block_service.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
387387

388388
for task in epochDuties.duties:
389389
if task notin duties:
390-
# Task is no more relevant, so cancel it.
390+
# Task is not relevant anymore, so cancel it.
391391
debug "Cancelling running proposal duty tasks",
392392
slot = task.duty.slot,
393393
pubkey = shortLog(task.duty.pubkey)

docs/the_nimbus_book/src/options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ The following options are available:
116116
keys of the validators what to sign and when) and load the validators in the
117117
beacon node itself [=true].
118118
--discv5 Enable Discovery v5 [=true].
119-
--dump Write SSZ dumps of blocks, attestations and states to data dir [=false].
119+
--dump Write SSZ dumps of blocks and states to data dir [=false].
120120
--direct-peer The list of privileged, secure and known peers to connect and maintain the
121121
connection to. This requires a not random netkey-file. In the multiaddress
122122
format like: /ip4/<address>/tcp/<port>/p2p/<peerId-public-key>, or enr format

scripts/geth_binaries.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ source "${SCRIPTS_DIR}/bash_utils.sh"
1919

2020
download_geth_stable() {
2121
if [[ ! -e "${STABLE_GETH_BINARY}" ]]; then
22-
GETH_VERSION="1.15.5-4263936a" # https://geth.ethereum.org/downloads
22+
GETH_VERSION="1.15.6-19d2b4c8" # https://geth.ethereum.org/downloads
2323
GETH_URL="https://gethstore.blob.core.windows.net/builds/"
2424

2525
case "${OS}-${ARCH}" in

0 commit comments

Comments
 (0)