Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
8080ed4
draft
olegshmuelov Sep 9, 2025
33f9a51
fix build
nkryuchkov Oct 20, 2025
c840f12
WIP on setting up aggregator committee runner
nkryuchkov Oct 20, 2025
e9c6e82
Merge branch 'stage' into aggregator-committee
nkryuchkov Oct 22, 2025
af127f6
implement reverted beacon client changes
nkryuchkov Oct 22, 2025
b6f495f
run aggregator committee duty
nkryuchkov Oct 22, 2025
2bd98f9
add aggregator committee checks to message validation
nkryuchkov Oct 24, 2025
1e2e89c
add basic fork handling to handlers
nkryuchkov Oct 24, 2025
0107fe6
add submission logs for aggregator committee
nkryuchkov Oct 24, 2025
5654a12
fix missed RoleAggregatorCommittee handling
nkryuchkov Oct 24, 2025
f875cc4
fix message validation aggregator committee issues
nkryuchkov Oct 24, 2025
61a95a0
fix some message validation issues
nkryuchkov Oct 30, 2025
dc5fb2a
Merge branch 'stage' into aggregator-committee
nkryuchkov Nov 6, 2025
7c2e239
WIP on issues after merging
nkryuchkov Nov 6, 2025
cf8d7bf
fix issues after merging
nkryuchkov Nov 14, 2025
be274d5
fix some bugs
nkryuchkov Nov 19, 2025
f9126ff
fix aggregator committee post-consensus message validation
nkryuchkov Nov 22, 2025
9ce6743
fix on timeout logic for aggregator committee
nkryuchkov Nov 22, 2025
d661f22
fix aggregator committee value check
nkryuchkov Nov 22, 2025
82c5b9f
fix aggregator committee post consensus message validation
nkryuchkov Nov 22, 2025
518c69a
filter messages matching the runner role from the queue
nkryuchkov Nov 22, 2025
0a835d9
fix expected aggregator committee duty type
nkryuchkov Nov 22, 2025
54c5944
pass error on failure to decide
nkryuchkov Nov 22, 2025
40bf179
fix ProcessConsensus
nkryuchkov Nov 22, 2025
8c5630b
Merge branch 'stage' into aggregator-committee
nkryuchkov Nov 25, 2025
bbd1e09
fix merging leftovers
nkryuchkov Dec 1, 2025
8ed4fd1
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 1, 2025
2b0747b
fix queue bugs
nkryuchkov Dec 1, 2025
f8a7709
fix post-consensus bug
nkryuchkov Dec 1, 2025
33b8a84
fix assertion bug
nkryuchkov Dec 1, 2025
6aeb03e
missing metrics
nkryuchkov Dec 1, 2025
a88f6e5
set fork epoch in all configs
nkryuchkov Dec 1, 2025
4c27b84
fork epoch 0 in test/local networks
nkryuchkov Dec 1, 2025
71b07b4
fetch attester and sync committee duties
nkryuchkov Dec 1, 2025
107a862
fix log text
nkryuchkov Dec 1, 2025
16e76ec
update spec
nkryuchkov Dec 1, 2025
f9c884c
add fulu to constructSignedAggregateAndProof
nkryuchkov Dec 1, 2025
539666b
fix a bug in constructSignedAggregateAndProof
nkryuchkov Dec 2, 2025
e0e75d7
fix a bug in constructSignedAggregateAndProof [2]
nkryuchkov Dec 2, 2025
422a89a
update spec version
nkryuchkov Dec 2, 2025
386a143
update spec version
nkryuchkov Dec 2, 2025
a36ce6d
update spec version
nkryuchkov Dec 2, 2025
804fbfc
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 2, 2025
7f8b7d9
fix linter
nkryuchkov Dec 2, 2025
9a7b1ea
fix some tests
nkryuchkov Dec 2, 2025
06e2692
fix a data race in tests
nkryuchkov Dec 2, 2025
a14b36c
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 2, 2025
09a6835
fix using wrong cache
nkryuchkov Dec 2, 2025
194586e
fix root caching
nkryuchkov Dec 2, 2025
8bc8237
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 3, 2025
9ef2204
add missing AggregatorCommittee in tests
nkryuchkov Dec 3, 2025
e74f880
fix duty scheduler unit tests
nkryuchkov Dec 3, 2025
77e8a8d
add a TODO
nkryuchkov Dec 3, 2025
fcfcc36
partially fix ssv mapping tests
nkryuchkov Dec 3, 2025
a0cee07
leftovers for AggregatorRunners in ssv mapping
nkryuchkov Dec 3, 2025
fb477ce
fix spec tests
nkryuchkov Dec 6, 2025
82e62ab
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 6, 2025
c3289c5
fix linter
nkryuchkov Dec 6, 2025
beb4ca5
simplify GetProcessMessageF
nkryuchkov Dec 8, 2025
8a2737e
further simplification
nkryuchkov Dec 8, 2025
82da430
delete ExecuteAggregatorCommitteeDuty
nkryuchkov Dec 8, 2025
d37f64c
delete CreateAggregatorRunnerFn
nkryuchkov Dec 8, 2025
96f000c
code review
nkryuchkov Dec 8, 2025
432d6a9
simplify validator committee
nkryuchkov Dec 8, 2025
ea29da2
delete confusing comment
nkryuchkov Dec 8, 2025
0ac2c78
delete hardcoded consts
nkryuchkov Dec 8, 2025
771752a
check PostDutyCommitteeRoot for aggregator committee
nkryuchkov Dec 8, 2025
62ca1cd
fix aggregator duty submission bug
nkryuchkov Dec 9, 2025
7a0291c
delete unnecessary normalizeAggregatorDecidedValues
nkryuchkov Dec 9, 2025
30cc104
update spec version
nkryuchkov Dec 11, 2025
8391389
cleanup some leftovers
nkryuchkov Dec 11, 2025
014acc0
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 11, 2025
341e6ff
Revert "update spec version"
nkryuchkov Dec 11, 2025
fecca4e
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 12, 2025
ef11ccc
code review suggestions
nkryuchkov Dec 25, 2025
71b74b0
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 25, 2025
8942757
fix spec tests data race
nkryuchkov Dec 26, 2025
02851a0
get rid of the aggregator committee handler
nkryuchkov Dec 26, 2025
53fbef1
wait only for committee role in duty scheduler
nkryuchkov Dec 26, 2025
002eea4
add waiting in aggregator committee runner
nkryuchkov Dec 26, 2025
a8c4558
aggregator committee runner: improve formatting
nkryuchkov Dec 26, 2025
86087ab
rename AggregatorCommittee fork to Boole; delete Alan fork from config
nkryuchkov Dec 26, 2025
81da547
attempt to fix TestScheduler_Committee_Indices_Changed_Attester_Only
nkryuchkov Dec 26, 2025
3d6f388
align to the latest spec changes
nkryuchkov Dec 26, 2025
29527e5
improve the comment
nkryuchkov Dec 29, 2025
1539de9
use trace.SpanFromContext
nkryuchkov Dec 29, 2025
dd93297
align to the latest spec
nkryuchkov Dec 29, 2025
7971c7f
Merge branch 'stage' into aggregator-committee
nkryuchkov Dec 29, 2025
8ae7ccd
align to https://github.com/ssvlabs/ssv/pull/2629
nkryuchkov Dec 29, 2025
cf2323e
code review comments
nkryuchkov Dec 29, 2025
e49c3ea
code review comments
nkryuchkov Dec 30, 2025
2e0f8a5
Merge branch 'stage' into aggregator-committee
nkryuchkov Jan 12, 2026
eec1a74
message/validation: update rules according to https://github.com/ssvl…
nkryuchkov Jan 12, 2026
7e0539a
fix variable name
nkryuchkov Jan 12, 2026
3b895e3
align with the latest spec
nkryuchkov Jan 13, 2026
7b3f7a7
align with the latest spec
nkryuchkov Jan 13, 2026
e73d41b
Merge branch 'stage' into aggregator-committee
nkryuchkov Jan 13, 2026
90b6b1a
fix compilation issue
nkryuchkov Jan 13, 2026
44a4e5f
fix tests
nkryuchkov Jan 13, 2026
9ed705e
get message size limits from spec
nkryuchkov Jan 13, 2026
86f431a
add nil share checks
nkryuchkov Jan 14, 2026
10211c2
use spec without jsons
nkryuchkov Jan 14, 2026
e666322
update spec version for ssvsigner
nkryuchkov Jan 14, 2026
b372872
fix linter
nkryuchkov Jan 14, 2026
188bbe5
fix missing roles in the updated spec
nkryuchkov Jan 19, 2026
63305a5
fix remaining usages of duty.RunnerRole()
nkryuchkov Jan 19, 2026
73c4358
fix pre-fork duty runner choice
nkryuchkov Jan 20, 2026
9e43711
fix a committeeDuty bug
nkryuchkov Jan 20, 2026
4ad0e5b
fix loop iteration
nkryuchkov Jan 20, 2026
a6a28f1
Merge branch 'stage' into aggregator-committee
nkryuchkov Jan 20, 2026
8769885
fix issues after merging
nkryuchkov Jan 20, 2026
a1e1c4f
apply changes from https://github.com/ssvlabs/ssv/pull/2658 to the ag…
nkryuchkov Jan 20, 2026
be4ab2a
fix TestFieldPreservation
nkryuchkov Jan 20, 2026
74f9c54
fix code review comments
nkryuchkov Jan 20, 2026
8bbec89
use spec without some tests
nkryuchkov Jan 21, 2026
baf3f4c
fix some spec tests
nkryuchkov Jan 21, 2026
8de1071
fix deduplication in agg comm runner
nkryuchkov Jan 21, 2026
4cd8084
fix value checker in spec tests
nkryuchkov Jan 21, 2026
c21a701
remove redundant spec tests code
nkryuchkov Jan 21, 2026
3a177ae
simplify ssv spec test
nkryuchkov Jan 21, 2026
2f43aec
refactor ssv mapping test
nkryuchkov Jan 21, 2026
c5760b2
simplify fixCommitteeForRun
nkryuchkov Jan 21, 2026
a2ae5fa
fix linter
nkryuchkov Jan 21, 2026
e83d299
improve comments
nkryuchkov Jan 21, 2026
fbe56a6
reject Boole roles during Alan and Alan roles during Boole
nkryuchkov Jan 22, 2026
a3fe784
optimize the role check
nkryuchkov Jan 22, 2026
61dd89c
add 'slot' to error log
nkryuchkov Jan 26, 2026
e133dfd
fix a bug with validator consensus data value check during Alan
nkryuchkov Jan 26, 2026
8e35a08
use the correct root(s) when calculating SyncCommitteeSubnetID
nkryuchkov Jan 28, 2026
fcd5dc4
fix a panic on nil interface
nkryuchkov Jan 29, 2026
6ce575e
Merge branch 'boole-fork' into aggregator-committee
nkryuchkov Feb 2, 2026
217f53d
fix issues after merging
nkryuchkov Feb 2, 2026
cfe7d1a
deduplicate messages if validator has already been seen for a subnet
nkryuchkov Feb 2, 2026
2aa6aa2
debug logs on errors in loops
nkryuchkov Feb 2, 2026
d74fa1e
cache aggregator committee roots
nkryuchkov Feb 2, 2026
82f64a8
fix a typo
nkryuchkov Feb 2, 2026
19ec3ba
end consensus on failure in decide()
nkryuchkov Feb 2, 2026
60c46b2
iterate over consensus data instead of duty
nkryuchkov Feb 2, 2026
bc80e2f
add slot in returned error
nkryuchkov Feb 2, 2026
4cf41f1
pass logger to where it's missing
nkryuchkov Feb 2, 2026
b48d61d
struct tags for SSVForks
nkryuchkov Feb 2, 2026
37efb44
use correct type for sync committee index
nkryuchkov Feb 2, 2026
ece1a85
implement missing checks for aggregator committee
nkryuchkov Feb 4, 2026
8abb87e
attempt to fix unit tests
nkryuchkov Feb 4, 2026
a4207dc
Revert "implement missing checks for aggregator committee"
nkryuchkov Feb 9, 2026
8a3af6b
Revert "deduplicate messages if validator has already been seen for a…
nkryuchkov Feb 9, 2026
714ce37
Merge branch 'boole-fork' into aggregator-committee
nkryuchkov Feb 9, 2026
c4d4909
fix issues after merging
nkryuchkov Feb 9, 2026
46eb76d
fix linter
nkryuchkov Feb 9, 2026
b757f32
Merge branch 'boole-fork' into aggregator-committee
nkryuchkov Feb 11, 2026
8596dbb
attempt to fix linter
nkryuchkov Feb 11, 2026
aa62a2c
fix unit tests after pulling changes from the base branch
nkryuchkov Feb 11, 2026
c4acabc
Revert "attempt to fix linter"
nkryuchkov Feb 11, 2026
c5fa18c
Merge branch 'boole-fork' into aggregator-committee
nkryuchkov Feb 11, 2026
8894049
fix tests
nkryuchkov Feb 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 186 additions & 79 deletions beacon/goclient/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package goclient

import (
"context"
"crypto/sha256"
"encoding/binary"
"fmt"
"net/http"
"time"
Expand All @@ -13,6 +15,36 @@ import (
ssz "github.com/ferranbt/fastssz"
)

func (gc *GoClient) IsAggregator(
_ context.Context,
_ phase0.Slot,
_ phase0.CommitteeIndex,
committeeLength uint64,
slotSig []byte,
) bool {
modulo := committeeLength / gc.beaconConfig.TargetAggregatorsPerCommittee
if modulo == 0 {
modulo = 1
}

h := sha256.Sum256(slotSig)
x := binary.LittleEndian.Uint64(h[:8])

return x%modulo == 0
}

func (gc *GoClient) GetAggregateAttestation(
ctx context.Context,
slot phase0.Slot,
committeeIndex phase0.CommitteeIndex,
) (ssz.Marshaler, spec.DataVersion, error) {
va, _, err := gc.fetchVersionedAggregate(ctx, slot, committeeIndex)
if err != nil {
return nil, DataVersionNil, err
}
return versionedAggregateToSSZ(va)
}

// SubmitAggregateSelectionProof returns an AggregateAndProof object
func (gc *GoClient) SubmitAggregateSelectionProof(
ctx context.Context,
Expand All @@ -29,144 +61,219 @@ func (gc *GoClient) SubmitAggregateSelectionProof(
return nil, 0, fmt.Errorf("wait for 2/3 of slot: %w", err)
}

va, _, err := gc.fetchVersionedAggregate(ctx, slot, committeeIndex)
if err != nil {
return nil, DataVersionNil, err
}

var selectionProof phase0.BLSSignature
copy(selectionProof[:], slotSig)

return versionedToAggregateAndProof(va, index, selectionProof)
}

// SubmitSignedAggregateSelectionProof broadcasts a signed aggregator msg
func (gc *GoClient) SubmitSignedAggregateSelectionProof(
ctx context.Context,
msg *spec.VersionedSignedAggregateAndProof,
) error {
start := time.Now()
err := gc.multiClient.SubmitAggregateAttestations(ctx, &api.SubmitAggregateAttestationsOpts{
SignedAggregateAndProofs: []*spec.VersionedSignedAggregateAndProof{msg},
})
recordRequest(ctx, gc.log, "SubmitAggregateAttestations", gc.multiClient, http.MethodPost, true, time.Since(start), err)
if err != nil {
return errMultiClient(fmt.Errorf("submit aggregate attestations: %w", err), "SubmitAggregateAttestations")
}

return nil
}

// waitTwoThirdsIntoSlot waits until two-third of the slot has transpired (SECONDS_PER_SLOT * 2 / 3 seconds after the start of slot)
func (gc *GoClient) waitTwoThirdsIntoSlot(ctx context.Context, slot phase0.Slot) error {
config := gc.getBeaconConfig()
oneInterval := config.IntervalDuration()
finalTime := config.SlotStartTime(slot).Add(2 * oneInterval)
wait := time.Until(finalTime)
if wait <= 0 {
return nil
}

select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(wait):
return nil
}
}

func (gc *GoClient) computeAttDataRootAndVersion(
ctx context.Context,
slot phase0.Slot,
committeeIndex phase0.CommitteeIndex,
) (root [32]byte, err error) {
attData, _, err := gc.GetAttestationData(ctx, slot)
if err != nil {
return nil, DataVersionNil, fmt.Errorf("fetch attestation data: %w", err)
return root, fmt.Errorf("fetch attestation data: %w", err)
}

// Explicitly set Index field as beacon nodes may return inconsistent values.
// EIP-7549: For Electra and later, index must always be 0, pre-Electra uses committee index.
dataVersion, _ := gc.beaconConfig.BeaconForkAtEpoch(gc.getBeaconConfig().EstimatedEpochAtSlot(attData.Slot))
// EIP-7549: Electra+ uses Index=0; pre-Electra uses committee index
version, _ := gc.beaconConfig.BeaconForkAtEpoch(gc.getBeaconConfig().EstimatedEpochAtSlot(attData.Slot))
attData.Index = 0
if dataVersion < spec.DataVersionElectra {
if version < spec.DataVersionElectra {
attData.Index = committeeIndex
}

// Get aggregate attestation data.
root, err := attData.HashTreeRoot()
root, err = attData.HashTreeRoot()
if err != nil {
return nil, DataVersionNil, fmt.Errorf("fetch attestation data root: %w", err)
return root, fmt.Errorf("fetch attestation data root: %w", err)
}
return root, nil
}

aggDataReqStart := time.Now()
aggDataResp, err := gc.multiClient.AggregateAttestation(ctx, &api.AggregateAttestationOpts{
func (gc *GoClient) fetchVersionedAggregate(
ctx context.Context,
slot phase0.Slot,
committeeIndex phase0.CommitteeIndex,
) (*spec.VersionedAttestation, spec.DataVersion, error) {
root, err := gc.computeAttDataRootAndVersion(ctx, slot, committeeIndex)
if err != nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("compute attestation root: %w", err), "AggregateAttestation")
}

start := time.Now()
resp, err := gc.multiClient.AggregateAttestation(ctx, &api.AggregateAttestationOpts{
Slot: slot,
AttestationDataRoot: root,
CommitteeIndex: committeeIndex,
})
recordRequest(ctx, gc.log, "AggregateAttestation", gc.multiClient, http.MethodGet, true, time.Since(aggDataReqStart), err)
recordRequest(ctx, gc.log, "AggregateAttestation", gc.multiClient, http.MethodGet, true, time.Since(start), err)
if err != nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("fetch aggregate attestation: %w", err), "AggregateAttestation")
}
if aggDataResp == nil {
if resp == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation response is nil"), "AggregateAttestation")
}
if aggDataResp.Data == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation response data is nil"), "AggregateAttestation")
if resp.Data == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation data is nil"), "AggregateAttestation")
}
return resp.Data, resp.Data.Version, nil
}

var selectionProof phase0.BLSSignature
copy(selectionProof[:], slotSig)
func versionedAggregateToSSZ(va *spec.VersionedAttestation) (ssz.Marshaler, spec.DataVersion, error) {
switch va.Version {
case spec.DataVersionPhase0:
if va.Phase0 == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Phase0, va.Version, nil
case spec.DataVersionAltair:
if va.Altair == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Altair, va.Version, nil
case spec.DataVersionBellatrix:
if va.Bellatrix == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Bellatrix, va.Version, nil
case spec.DataVersionCapella:
if va.Capella == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Capella, va.Version, nil
case spec.DataVersionDeneb:
if va.Deneb == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Deneb, va.Version, nil
case spec.DataVersionElectra:
if va.Electra == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Electra, va.Version, nil
case spec.DataVersionFulu:
if va.Fulu == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return va.Fulu, va.Version, nil
default:
return nil, DataVersionNil, errMultiClient(fmt.Errorf("unknown data version: %d", va.Version), "AggregateAttestation")
}
}

vAtt := aggDataResp.Data
switch vAtt.Version {
func versionedToAggregateAndProof(
va *spec.VersionedAttestation,
index phase0.ValidatorIndex,
selectionProof phase0.BLSSignature,
) (ssz.Marshaler, spec.DataVersion, error) {
switch va.Version {
case spec.DataVersionPhase0:
if vAtt.Phase0 == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Phase0 == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return &phase0.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Phase0,
Aggregate: va.Phase0,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
case spec.DataVersionAltair:
if vAtt.Altair == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Altair == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return &phase0.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Altair,
Aggregate: va.Altair,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
case spec.DataVersionBellatrix:
if vAtt.Bellatrix == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Bellatrix == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return &phase0.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Bellatrix,
Aggregate: va.Bellatrix,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
case spec.DataVersionCapella:
if vAtt.Capella == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Capella == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return &phase0.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Capella,
Aggregate: va.Capella,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
case spec.DataVersionDeneb:
if vAtt.Deneb == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Deneb == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return &phase0.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Deneb,
Aggregate: va.Deneb,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
case spec.DataVersionElectra:
if vAtt.Electra == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Electra == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
return &electra.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Electra,
Aggregate: va.Electra,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
case spec.DataVersionFulu:
if vAtt.Fulu == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", vAtt.Version.String()), "AggregateAttestation")
if va.Fulu == nil {
return nil, DataVersionNil, errMultiClient(fmt.Errorf("aggregate attestation %s data is nil", va.Version.String()), "AggregateAttestation")
}
// Fulu AggregateAndProof uses electra.AggregateAndProof in go-eth2-client
return &electra.AggregateAndProof{
AggregatorIndex: index,
Aggregate: vAtt.Fulu,
Aggregate: va.Fulu,
SelectionProof: selectionProof,
}, vAtt.Version, nil
}, va.Version, nil
default:
return nil, DataVersionNil, fmt.Errorf("unknown data version: %d", vAtt.Version)
}
}

// SubmitSignedAggregateSelectionProof broadcasts a signed aggregator msg
func (gc *GoClient) SubmitSignedAggregateSelectionProof(
ctx context.Context,
msg *spec.VersionedSignedAggregateAndProof,
) error {
start := time.Now()
err := gc.multiClient.SubmitAggregateAttestations(ctx, &api.SubmitAggregateAttestationsOpts{SignedAggregateAndProofs: []*spec.VersionedSignedAggregateAndProof{msg}})
recordRequest(ctx, gc.log, "SubmitAggregateAttestations", gc.multiClient, http.MethodPost, true, time.Since(start), err)
if err != nil {
return errMultiClient(fmt.Errorf("submit aggregate attestations: %w", err), "SubmitAggregateAttestations")
}

return nil
}

// waitTwoThirdsIntoSlot waits until two-third of the slot has transpired (SECONDS_PER_SLOT * 2 / 3 seconds after the start of slot)
func (gc *GoClient) waitTwoThirdsIntoSlot(ctx context.Context, slot phase0.Slot) error {
config := gc.getBeaconConfig()
oneInterval := config.IntervalDuration()
finalTime := config.SlotStartTime(slot).Add(2 * oneInterval)
wait := time.Until(finalTime)
if wait <= 0 {
return nil
}

select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(wait):
return nil
return nil, DataVersionNil, errMultiClient(fmt.Errorf("unknown data version: %d", va.Version), "AggregateAttestation")
}
}
3 changes: 3 additions & 0 deletions cli/generate_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ var generateConfigCmd = &cobra.Command{
RegistryContractAddr: ethcommon.HexToAddress(ssvRegistryContractAddr),
Bootnodes: bootnodes,
DiscoveryProtocolID: parsedDiscoveryProtocolIDArr,
Forks: networkconfig.SSVForks{
Boole: 0,
},
}

data, err := yaml.Marshal(&config)
Expand Down
4 changes: 2 additions & 2 deletions exporter/api/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type ParticipantsAPI struct {
ValidatorPK string
Role string
Message specqbft.Message
FullData *spectypes.ValidatorConsensusData
FullData *spectypes.ProposerConsensusData
}

// NewParticipantsAPIMsg creates a new message in a new format from the given message.
Expand Down Expand Up @@ -77,7 +77,7 @@ func ParticipantsAPIData(domainType spectypes.DomainType, msgs ...qbftstorage.Pa
Identifier: msgID[:],
Round: specqbft.FirstRound,
},
FullData: &spectypes.ValidatorConsensusData{
FullData: &spectypes.ProposerConsensusData{
Duty: spectypes.ValidatorDuty{
PubKey: blsPubKey,
Slot: msg.Slot,
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ require (
github.com/sourcegraph/conc v0.3.0
github.com/spf13/cobra v1.8.1
github.com/ssvlabs/eth2-key-manager v1.5.6
github.com/ssvlabs/ssv-spec v1.2.2
github.com/ssvlabs/ssv-spec v1.2.3-0.20260121164943-4280751195c0
github.com/ssvlabs/ssv/ssvsigner v0.0.0-20251110161756-cd931098ea44
github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.11.1
Expand All @@ -55,6 +55,7 @@ require (
go.uber.org/mock v0.5.2
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20250911091902-df9299821621
golang.org/x/mod v0.28.0
golang.org/x/sync v0.17.0
golang.org/x/text v0.29.0
Expand Down Expand Up @@ -99,7 +100,6 @@ require (
go.opentelemetry.io/otel/sdk/log v0.12.2 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
Expand Down
Loading