Skip to content

Commit 6d9a5fd

Browse files
authored
Caplin: Added SyncAggregate computation to block production (#10009)
This PR allows the computation for the computation of the `SyncAggregate` field in block production: https://sepolia.beaconcha.in/slot/4832922 proof of the code working is that now Caplin validators can include sync aggregates in their blocks. Things modified: * We do not aggregate pre-aggregated `SyncContributionAndProof`s, instead we just listen to the network and pick the most profitable ones for each sub sync committee (4 sync subcommittee on mainnet). profitability == most bits set in `AggregationBits` field. * Separate aggregates set for contribution to be included in a block from the ones constructed from `SyncCommitteeMessage`s, combining the two causes some contributions to be marked as invalid and not aggregable. * Remove SyncContributionMock in favor of gomock
1 parent 7d668f2 commit 6d9a5fd

File tree

18 files changed

+209
-126
lines changed

18 files changed

+209
-126
lines changed

cl/aggregation/pool_impl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (p *aggregationPoolImpl) AddAttestation(inAtt *solid.Attestation) error {
6161
return nil
6262
}
6363

64-
if utils.IsSupersetBitlist(att.AggregationBits(), inAtt.AggregationBits()) {
64+
if utils.IsNonStrictSupersetBitlist(att.AggregationBits(), inAtt.AggregationBits()) {
6565
return ErrIsSuperset
6666
}
6767

cl/beacon/handler/block_production.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"sync"
1212
"time"
1313

14-
"github.com/Giulio2002/bls"
1514
"github.com/go-chi/chi/v5"
1615
"github.com/ledgerwatch/erigon-lib/common"
1716
libcommon "github.com/ledgerwatch/erigon-lib/common"
@@ -170,10 +169,6 @@ func (a *ApiHandler) produceBeaconBody(ctx context.Context, apiVersion int, base
170169
beaconBody.RandaoReveal = randaoReveal
171170
beaconBody.Graffiti = graffiti
172171
beaconBody.Version = stateVersion
173-
// Sync aggregate is empty for now.
174-
beaconBody.SyncAggregate = &cltypes.SyncAggregate{
175-
SyncCommiteeSignature: bls.InfiniteSignature,
176-
}
177172

178173
// Build execution payload
179174
latestExecutionPayload := baseState.LatestExecutionPayloadHeader()
@@ -308,6 +303,15 @@ func (a *ApiHandler) produceBeaconBody(ctx context.Context, apiVersion int, base
308303
}
309304
}
310305
}()
306+
// process the sync aggregate in parallel
307+
wg.Add(1)
308+
go func() {
309+
defer wg.Done()
310+
beaconBody.SyncAggregate, err = a.syncMessagePool.GetSyncAggregate(targetSlot-1, blockRoot)
311+
if err != nil {
312+
log.Error("BlockProduction: Failed to get sync aggregate", "err", err)
313+
}
314+
}()
311315
wg.Wait()
312316
if executionPayload == nil {
313317
return nil, 0, fmt.Errorf("failed to produce execution payload")

cl/beacon/handler/utils_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
4545
bcfg.CapellaForkEpoch = 1
4646
blocks, preState, postState = tests.GetCapellaRandom()
4747
}
48-
fcu = forkchoice.NewForkChoiceStorageMock()
48+
fcu = forkchoice.NewForkChoiceStorageMock(t)
4949
db = memdb.NewTestDB(t)
5050
blobDb := memdb.NewTestDB(t)
5151
var reader *tests.MockBlockReader

cl/phase1/forkchoice/forkchoice_mock.go

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package forkchoice
22

33
import (
44
"context"
5+
"testing"
56

67
"github.com/ledgerwatch/erigon-lib/common"
78
libcommon "github.com/ledgerwatch/erigon-lib/common"
@@ -12,6 +13,7 @@ import (
1213
"github.com/ledgerwatch/erigon/cl/pool"
1314
"github.com/ledgerwatch/erigon/cl/transition/impl/eth2"
1415
"github.com/ledgerwatch/erigon/cl/validator/sync_contribution_pool"
16+
"go.uber.org/mock/gomock"
1517
)
1618

1719
// Make mocks with maps and simple setters and getters, panic on methods from ForkChoiceStorageWriter
@@ -47,7 +49,51 @@ type ForkChoiceStorageMock struct {
4749
Pool pool.OperationsPool
4850
}
4951

50-
func NewForkChoiceStorageMock() *ForkChoiceStorageMock {
52+
func makeSyncContributionPoolMock(t *testing.T) sync_contribution_pool.SyncContributionPool {
53+
ctrl := gomock.NewController(t)
54+
type syncContributionKey struct {
55+
slot uint64
56+
subcommitteeIndex uint64
57+
beaconBlockRoot common.Hash
58+
}
59+
u := map[syncContributionKey]*cltypes.Contribution{}
60+
pool := sync_contribution_pool.NewMockSyncContributionPool(ctrl)
61+
pool.EXPECT().AddSyncContribution(gomock.Any(), gomock.Any()).DoAndReturn(func(headState *state.CachingBeaconState, contribution *cltypes.Contribution) error {
62+
key := syncContributionKey{
63+
slot: contribution.Slot,
64+
subcommitteeIndex: contribution.SubcommitteeIndex,
65+
beaconBlockRoot: contribution.BeaconBlockRoot,
66+
}
67+
u[key] = contribution
68+
return nil
69+
}).AnyTimes()
70+
pool.EXPECT().GetSyncContribution(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(slot uint64, subcommitteeIndex uint64, beaconBlockRoot common.Hash) (*cltypes.Contribution, bool) {
71+
key := syncContributionKey{
72+
slot: slot,
73+
subcommitteeIndex: subcommitteeIndex,
74+
beaconBlockRoot: beaconBlockRoot,
75+
}
76+
v, ok := u[key]
77+
return v, ok
78+
}).AnyTimes()
79+
pool.EXPECT().AddSyncCommitteeMessage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(headState *state.CachingBeaconState, subCommitee uint64, message *cltypes.SyncCommitteeMessage) error {
80+
key := syncContributionKey{
81+
slot: message.Slot,
82+
subcommitteeIndex: subCommitee,
83+
beaconBlockRoot: message.BeaconBlockRoot,
84+
}
85+
u[key] = &cltypes.Contribution{
86+
Slot: message.Slot,
87+
SubcommitteeIndex: subCommitee,
88+
BeaconBlockRoot: message.BeaconBlockRoot,
89+
AggregationBits: make([]byte, cltypes.SyncCommitteeAggregationBitsSize),
90+
}
91+
return nil
92+
}).AnyTimes()
93+
return pool
94+
}
95+
96+
func NewForkChoiceStorageMock(t *testing.T) *ForkChoiceStorageMock {
5197
return &ForkChoiceStorageMock{
5298
Ancestors: make(map[uint64]common.Hash),
5399
AnchorSlotVal: 0,
@@ -66,9 +112,9 @@ func NewForkChoiceStorageMock() *ForkChoiceStorageMock {
66112
GetFinalityCheckpointsVal: make(map[common.Hash][3]solid.Checkpoint),
67113
LightClientBootstraps: make(map[common.Hash]*cltypes.LightClientBootstrap),
68114
LCUpdates: make(map[uint64]*cltypes.LightClientUpdate),
69-
SyncContributionPool: sync_contribution_pool.NewSyncContributionPoolMock(),
70115
Headers: make(map[common.Hash]*cltypes.BeaconBlockHeader),
71116
GetBeaconCommitteeMock: nil,
117+
SyncContributionPool: makeSyncContributionPoolMock(t),
72118
}
73119
}
74120

cl/phase1/network/services/aggregate_and_proof_service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func setupAggregateAndProofTest(t *testing.T) (AggregateAndProofService, *synced
4343
cn()
4444
cfg := &clparams.MainnetBeaconConfig
4545
syncedDataManager := synced_data.NewSyncedDataManager(true, cfg)
46-
forkchoiceMock := forkchoice.NewForkChoiceStorageMock()
46+
forkchoiceMock := forkchoice.NewForkChoiceStorageMock(t)
4747
blockService := NewAggregateAndProofService(ctx, syncedDataManager, forkchoiceMock, cfg, nil, true)
4848
return blockService, syncedDataManager, forkchoiceMock
4949
}

cl/phase1/network/services/blob_sidecar_service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func setupBlobSidecarService(t *testing.T, ctrl *gomock.Controller, test bool) (
5656
cfg := &clparams.MainnetBeaconConfig
5757
syncedDataManager := synced_data.NewSyncedDataManager(true, cfg)
5858
ethClock := eth_clock.NewMockEthereumClock(ctrl)
59-
forkchoiceMock := forkchoice.NewForkChoiceStorageMock()
59+
forkchoiceMock := forkchoice.NewForkChoiceStorageMock(t)
6060
blockService := NewBlobSidecarService(ctx2, cfg, forkchoiceMock, syncedDataManager, ethClock, test)
6161
return blockService, syncedDataManager, ethClock, forkchoiceMock
6262
}

cl/phase1/network/services/block_service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func setupBlockService(t *testing.T, ctrl *gomock.Controller) (BlockService, *sy
2121
cfg := &clparams.MainnetBeaconConfig
2222
syncedDataManager := synced_data.NewSyncedDataManager(true, cfg)
2323
ethClock := eth_clock.NewMockEthereumClock(ctrl)
24-
forkchoiceMock := forkchoice.NewForkChoiceStorageMock()
24+
forkchoiceMock := forkchoice.NewForkChoiceStorageMock(t)
2525
blockService := NewBlockService(context.Background(), db, forkchoiceMock, syncedDataManager, ethClock, cfg, nil)
2626
return blockService, syncedDataManager, ethClock, forkchoiceMock
2727
}

cl/phase1/network/services/sync_committee_messages_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (s *syncCommitteeMessagesService) ProcessMessage(ctx context.Context, subne
9999
func (s *syncCommitteeMessagesService) cleanupOldSyncCommitteeMessages() {
100100
headSlot := s.syncedDataManager.HeadSlot()
101101
for k := range s.seenSyncCommitteeMessages {
102-
if headSlot != k.slot {
102+
if headSlot > k.slot+1 {
103103
delete(s.seenSyncCommitteeMessages, k)
104104
}
105105
}

cl/sentinel/handlers/heartbeats_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestPing(t *testing.T) {
6868
peersPool := peers.NewPool()
6969
beaconDB, indiciesDB := setupStore(t)
7070

71-
f := forkchoice.NewForkChoiceStorageMock()
71+
f := forkchoice.NewForkChoiceStorageMock(t)
7272
ethClock := getEthClock(t)
7373

7474
_, beaconCfg := clparams.GetConfigsByNetwork(1)
@@ -123,7 +123,7 @@ func TestGoodbye(t *testing.T) {
123123
peersPool := peers.NewPool()
124124
beaconDB, indiciesDB := setupStore(t)
125125

126-
f := forkchoice.NewForkChoiceStorageMock()
126+
f := forkchoice.NewForkChoiceStorageMock(t)
127127
ethClock := getEthClock(t)
128128
_, beaconCfg := clparams.GetConfigsByNetwork(1)
129129
c := NewConsensusHandlers(
@@ -183,7 +183,7 @@ func TestMetadataV2(t *testing.T) {
183183
peersPool := peers.NewPool()
184184
beaconDB, indiciesDB := setupStore(t)
185185

186-
f := forkchoice.NewForkChoiceStorageMock()
186+
f := forkchoice.NewForkChoiceStorageMock(t)
187187
ethClock := getEthClock(t)
188188
nc := clparams.NetworkConfigs[clparams.MainnetNetwork]
189189
_, beaconCfg := clparams.GetConfigsByNetwork(1)
@@ -241,7 +241,7 @@ func TestMetadataV1(t *testing.T) {
241241
peersPool := peers.NewPool()
242242
beaconDB, indiciesDB := setupStore(t)
243243

244-
f := forkchoice.NewForkChoiceStorageMock()
244+
f := forkchoice.NewForkChoiceStorageMock(t)
245245

246246
nc := clparams.NetworkConfigs[clparams.MainnetNetwork]
247247
ethClock := getEthClock(t)
@@ -299,7 +299,7 @@ func TestStatus(t *testing.T) {
299299
peersPool := peers.NewPool()
300300
beaconDB, indiciesDB := setupStore(t)
301301

302-
f := forkchoice.NewForkChoiceStorageMock()
302+
f := forkchoice.NewForkChoiceStorageMock(t)
303303

304304
hs := handshake.New(ctx, getEthClock(t), &clparams.MainnetBeaconConfig, nil)
305305
s := &cltypes.Status{

cl/sentinel/handlers/light_client_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestLightClientOptimistic(t *testing.T) {
4545
peersPool := peers.NewPool()
4646
beaconDB, indiciesDB := setupStore(t)
4747

48-
f := forkchoice.NewForkChoiceStorageMock()
48+
f := forkchoice.NewForkChoiceStorageMock(t)
4949

5050
f.NewestLCUpdate = &cltypes.LightClientUpdate{
5151
AttestedHeader: cltypes.NewLightClientHeader(clparams.AltairVersion),
@@ -115,7 +115,7 @@ func TestLightClientFinality(t *testing.T) {
115115
peersPool := peers.NewPool()
116116
beaconDB, indiciesDB := setupStore(t)
117117

118-
f := forkchoice.NewForkChoiceStorageMock()
118+
f := forkchoice.NewForkChoiceStorageMock(t)
119119

120120
f.NewestLCUpdate = &cltypes.LightClientUpdate{
121121
AttestedHeader: cltypes.NewLightClientHeader(clparams.AltairVersion),
@@ -188,7 +188,7 @@ func TestLightClientBootstrap(t *testing.T) {
188188
peersPool := peers.NewPool()
189189
beaconDB, indiciesDB := setupStore(t)
190190

191-
f := forkchoice.NewForkChoiceStorageMock()
191+
f := forkchoice.NewForkChoiceStorageMock(t)
192192

193193
f.NewestLCUpdate = &cltypes.LightClientUpdate{
194194
AttestedHeader: cltypes.NewLightClientHeader(clparams.AltairVersion),
@@ -270,7 +270,7 @@ func TestLightClientUpdates(t *testing.T) {
270270
peersPool := peers.NewPool()
271271
beaconDB, indiciesDB := setupStore(t)
272272

273-
f := forkchoice.NewForkChoiceStorageMock()
273+
f := forkchoice.NewForkChoiceStorageMock(t)
274274
ethClock := getEthClock(t)
275275

276276
up := &cltypes.LightClientUpdate{

0 commit comments

Comments
 (0)