Skip to content

Commit 8fb4b5e

Browse files
committed
blsToExecutionChange
1 parent 92a78d5 commit 8fb4b5e

File tree

12 files changed

+187
-68
lines changed

12 files changed

+187
-68
lines changed

cl/beacon/handler/handler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ type ApiHandler struct {
8383
syncContributionAndProofsService services.SyncContributionService
8484
aggregateAndProofsService services.AggregateAndProofService
8585
voluntaryExitService services.VoluntaryExitService
86+
blsToExecutionChangeService services.BLSToExecutionChangeService
8687
}
8788

8889
func NewApiHandler(
@@ -112,6 +113,8 @@ func NewApiHandler(
112113
syncContributionAndProofs services.SyncContributionService,
113114
aggregateAndProofs services.AggregateAndProofService,
114115
voluntaryExitService services.VoluntaryExitService,
116+
blsToExecutionChangeService services.BLSToExecutionChangeService,
117+
115118
) *ApiHandler {
116119
blobBundles, err := lru.New[common.Bytes48, BlobBundle]("blobs", maxBlobBundleCacheSize)
117120
if err != nil {
@@ -149,6 +152,7 @@ func NewApiHandler(
149152
syncContributionAndProofsService: syncContributionAndProofs,
150153
aggregateAndProofsService: aggregateAndProofs,
151154
voluntaryExitService: voluntaryExitService,
155+
blsToExecutionChangeService: blsToExecutionChangeService,
152156
}
153157
}
154158

cl/beacon/handler/pool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ func (a *ApiHandler) PostEthV1BeaconPoolBlsToExecutionChanges(w http.ResponseWri
226226
}
227227
failures := []poolingFailure{}
228228
for _, v := range req {
229-
if err := a.forkchoiceStore.OnBlsToExecutionChange(v, false); err != nil {
229+
if err := a.blsToExecutionChangeService.ProcessMessage(r.Context(), nil, v); err != nil && !errors.Is(err, services.ErrIgnore) {
230230
failures = append(failures, poolingFailure{Index: len(failures), Message: err.Error()})
231231
continue
232232
}

cl/beacon/handler/utils_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
8989
syncContributionService := mock_services.NewMockSyncContributionService(ctrl)
9090
aggregateAndProofsService := mock_services.NewMockAggregateAndProofService(ctrl)
9191
voluntaryExitService := mock_services.NewMockVoluntaryExitService(ctrl)
92+
blsToExecutionChangeService := mock_services.NewMockBLSToExecutionChangeService(ctrl)
93+
9294
// ctx context.Context, subnetID *uint64, msg *cltypes.SyncCommitteeMessage) error
9395
syncCommitteeMessagesService.EXPECT().ProcessMessage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, subnetID *uint64, msg *cltypes.SyncCommitteeMessage) error {
9496
return h.syncMessagePool.AddSyncCommitteeMessage(postState, *subnetID, msg)
@@ -105,6 +107,10 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
105107
opPool.VoluntaryExistsPool.Insert(msg.VoluntaryExit.ValidatorIndex, msg)
106108
return nil
107109
}).AnyTimes()
110+
blsToExecutionChangeService.EXPECT().ProcessMessage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, subnetID *uint64, msg *cltypes.SignedBLSToExecutionChange) error {
111+
opPool.BLSToExecutionChangesPool.Insert(msg.Signature, msg)
112+
return nil
113+
}).AnyTimes()
108114

109115
vp = validator_params.NewValidatorParams()
110116
h = NewApiHandler(
@@ -128,7 +134,13 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
128134
Events: true,
129135
Validator: true,
130136
Lighthouse: true,
131-
}, nil, blobStorage, nil, vp, nil, nil, fcu.SyncContributionPool, nil, nil, syncCommitteeMessagesService, syncContributionService, aggregateAndProofsService, voluntaryExitService) // TODO: add tests
137+
}, nil, blobStorage, nil, vp, nil, nil, fcu.SyncContributionPool, nil, nil,
138+
syncCommitteeMessagesService,
139+
syncContributionService,
140+
aggregateAndProofsService,
141+
voluntaryExitService,
142+
blsToExecutionChangeService,
143+
) // TODO: add tests
132144
h.Init()
133145
return
134146
}

cl/beacon/handler/validator_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func (t *validatorTestSuite) SetupTest() {
5454
nil,
5555
nil,
5656
nil,
57+
nil,
5758
)
5859
t.gomockCtrl = gomockCtrl
5960
}

cl/phase1/forkchoice/fork_choice_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,6 @@ func TestForkChoiceBasic(t *testing.T) {
107107
for sd.HeadState() == nil {
108108
time.Sleep(time.Millisecond)
109109
}
110-
// Try processing a bls execution change exit
111-
err = store.OnBlsToExecutionChange(&cltypes.SignedBLSToExecutionChange{
112-
Message: &cltypes.BLSToExecutionChange{
113-
ValidatorIndex: 0,
114-
},
115-
}, true)
116110
require.NoError(t, err)
117111
require.Equal(t, len(pool.VoluntaryExistsPool.Raw()), 1)
118112
}

cl/phase1/forkchoice/interface.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ type ForkChoiceStorageWriter interface {
6161
OnAttestation(attestation *solid.Attestation, fromBlock, insert bool) error
6262
OnAttesterSlashing(attesterSlashing *cltypes.AttesterSlashing, test bool) error
6363
OnProposerSlashing(proposerSlashing *cltypes.ProposerSlashing, test bool) error
64-
OnBlsToExecutionChange(signedChange *cltypes.SignedBLSToExecutionChange, test bool) error
6564
OnBlock(ctx context.Context, block *cltypes.SignedBeaconBlock, newPayload bool, fullValidation bool, checkDataAvaibility bool) error
6665
AddPreverifiedBlobSidecar(blobSidecar *cltypes.BlobSidecar) error
6766
OnTick(time uint64)

cl/phase1/forkchoice/on_operations.go

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package forkchoice
22

33
import (
4-
"bytes"
54
"fmt"
65

76
"github.com/Giulio2002/bls"
87
"github.com/ledgerwatch/erigon/cl/cltypes"
98
"github.com/ledgerwatch/erigon/cl/fork"
109
"github.com/ledgerwatch/erigon/cl/phase1/core/state"
1110
"github.com/ledgerwatch/erigon/cl/pool"
12-
"github.com/ledgerwatch/erigon/cl/utils"
1311
)
1412

1513
// NOTE: This file implements non-official handlers for other types of iterations. what it does is,using the forkchoices
@@ -90,58 +88,3 @@ func (f *ForkChoiceStore) OnProposerSlashing(proposerSlashing *cltypes.ProposerS
9088

9189
return nil
9290
}
93-
94-
func (f *ForkChoiceStore) OnBlsToExecutionChange(signedChange *cltypes.SignedBLSToExecutionChange, test bool) error {
95-
if f.operationsPool.BLSToExecutionChangesPool.Has(signedChange.Signature) {
96-
f.emitters.Publish("bls_to_execution_change", signedChange)
97-
return nil
98-
}
99-
change := signedChange.Message
100-
101-
// Take lock as we interact with state.
102-
s := f.syncedDataManager.HeadState()
103-
if s == nil {
104-
return nil
105-
}
106-
validator, err := s.ValidatorForValidatorIndex(int(change.ValidatorIndex))
107-
if err != nil {
108-
return fmt.Errorf("unable to retrieve state: %v", err)
109-
}
110-
wc := validator.WithdrawalCredentials()
111-
112-
if wc[0] != byte(f.beaconCfg.BLSWithdrawalPrefixByte) {
113-
return fmt.Errorf("invalid withdrawal credentials prefix")
114-
}
115-
genesisValidatorRoot := s.GenesisValidatorsRoot()
116-
// Perform full validation if requested.
117-
if !test {
118-
// Check the validator's withdrawal credentials against the provided message.
119-
hashedFrom := utils.Sha256(change.From[:])
120-
if !bytes.Equal(hashedFrom[1:], wc[1:]) {
121-
return fmt.Errorf("invalid withdrawal credentials")
122-
}
123-
124-
// Compute the signing domain and verify the message signature.
125-
domain, err := fork.ComputeDomain(f.beaconCfg.DomainBLSToExecutionChange[:], utils.Uint32ToBytes4(uint32(f.beaconCfg.GenesisForkVersion)), genesisValidatorRoot)
126-
if err != nil {
127-
return err
128-
}
129-
signedRoot, err := fork.ComputeSigningRoot(change, domain)
130-
if err != nil {
131-
return err
132-
}
133-
valid, err := bls.Verify(signedChange.Signature[:], signedRoot[:], change.From[:])
134-
if err != nil {
135-
return err
136-
}
137-
if !valid {
138-
return fmt.Errorf("invalid signature")
139-
}
140-
}
141-
142-
f.operationsPool.BLSToExecutionChangesPool.Insert(signedChange.Signature, signedChange)
143-
144-
// emit bls_to_execution_change
145-
f.emitters.Publish("bls_to_execution_change", signedChange)
146-
return nil
147-
}

cl/phase1/network/gossip_manager.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type GossipManager struct {
4444
aggregateAndProofService services.AggregateAndProofService
4545
attestationService services.AttestationService
4646
voluntaryExitService services.VoluntaryExitService
47+
blsToExecutionChangeService services.BLSToExecutionChangeService
4748
}
4849

4950
func NewGossipReceiver(
@@ -60,6 +61,7 @@ func NewGossipReceiver(
6061
aggregateAndProofService services.AggregateAndProofService,
6162
attestationService services.AttestationService,
6263
voluntaryExitService services.VoluntaryExitService,
64+
blsToExecutionChangeService services.BLSToExecutionChangeService,
6365
) *GossipManager {
6466
return &GossipManager{
6567
sentinel: s,
@@ -75,6 +77,7 @@ func NewGossipReceiver(
7577
aggregateAndProofService: aggregateAndProofService,
7678
attestationService: attestationService,
7779
voluntaryExitService: voluntaryExitService,
80+
blsToExecutionChangeService: blsToExecutionChangeService,
7881
}
7982
}
8083

@@ -161,7 +164,11 @@ func (g *GossipManager) routeAndProcess(ctx context.Context, data *sentinel.Goss
161164
case gossip.TopicNameAttesterSlashing:
162165
return operationsContract[*cltypes.AttesterSlashing](ctx, g, data, int(version), "attester slashing", g.forkChoice.OnAttesterSlashing)
163166
case gossip.TopicNameBlsToExecutionChange:
164-
return operationsContract[*cltypes.SignedBLSToExecutionChange](ctx, g, data, int(version), "bls to execution change", g.forkChoice.OnBlsToExecutionChange)
167+
obj := &cltypes.SignedBLSToExecutionChange{}
168+
if err := obj.DecodeSSZ(data.Data, int(version)); err != nil {
169+
return err
170+
}
171+
return g.blsToExecutionChangeService.ProcessMessage(ctx, data.SubnetId, obj)
165172
case gossip.TopicNameBeaconAggregateAndProof:
166173
obj := &cltypes.SignedAggregateAndProof{}
167174
if err := obj.DecodeSSZ(data.Data, int(version)); err != nil {
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package services
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
8+
"github.com/Giulio2002/bls"
9+
"github.com/ledgerwatch/erigon/cl/beacon/beaconevents"
10+
"github.com/ledgerwatch/erigon/cl/beacon/synced_data"
11+
"github.com/ledgerwatch/erigon/cl/clparams"
12+
"github.com/ledgerwatch/erigon/cl/cltypes"
13+
"github.com/ledgerwatch/erigon/cl/fork"
14+
"github.com/ledgerwatch/erigon/cl/pool"
15+
"github.com/ledgerwatch/erigon/cl/utils"
16+
)
17+
18+
type blsToExecutionChangeService struct {
19+
operationsPool pool.OperationsPool
20+
emitters *beaconevents.Emitters
21+
syncedDataManager *synced_data.SyncedDataManager
22+
beaconCfg *clparams.BeaconChainConfig
23+
}
24+
25+
func NewBLSToExecutionChangeService(
26+
operationsPool pool.OperationsPool,
27+
emitters *beaconevents.Emitters,
28+
syncedDataManager *synced_data.SyncedDataManager,
29+
beaconCfg *clparams.BeaconChainConfig,
30+
) BLSToExecutionChangeService {
31+
return &blsToExecutionChangeService{
32+
operationsPool: operationsPool,
33+
emitters: emitters,
34+
syncedDataManager: syncedDataManager,
35+
beaconCfg: beaconCfg,
36+
}
37+
}
38+
39+
func (s *blsToExecutionChangeService) ProcessMessage(ctx context.Context, subnet *uint64, msg *cltypes.SignedBLSToExecutionChange) error {
40+
defer s.emitters.Publish("bls_to_execution_change", msg)
41+
42+
// [IGNORE] The signed_bls_to_execution_change is the first valid signed bls to execution change received
43+
// for the validator with index signed_bls_to_execution_change.message.validator_index.
44+
if s.operationsPool.BLSToExecutionChangesPool.Has(msg.Signature) {
45+
return nil
46+
}
47+
change := msg.Message
48+
49+
state := s.syncedDataManager.HeadState()
50+
if state == nil {
51+
return nil
52+
}
53+
54+
// [IGNORE] current_epoch >= CAPELLA_FORK_EPOCH, where current_epoch is defined by the current wall-clock time.
55+
if !(state.Version() >= clparams.CapellaVersion) {
56+
return ErrIgnore
57+
}
58+
59+
// ref: https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
60+
// assert address_change.validator_index < len(state.validators)
61+
validator, err := state.ValidatorForValidatorIndex(int(change.ValidatorIndex))
62+
if err != nil {
63+
return fmt.Errorf("unable to retrieve state: %v", err)
64+
}
65+
wc := validator.WithdrawalCredentials()
66+
67+
// assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX
68+
if wc[0] != byte(s.beaconCfg.BLSWithdrawalPrefixByte) {
69+
return fmt.Errorf("invalid withdrawal credentials prefix")
70+
}
71+
72+
// assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:]
73+
// Perform full validation if requested.
74+
// Check the validator's withdrawal credentials against the provided message.
75+
hashedFrom := utils.Sha256(change.From[:])
76+
if !bytes.Equal(hashedFrom[1:], wc[1:]) {
77+
return fmt.Errorf("invalid withdrawal credentials")
78+
}
79+
80+
// assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature)
81+
genesisValidatorRoot := state.GenesisValidatorsRoot()
82+
domain, err := fork.ComputeDomain(s.beaconCfg.DomainBLSToExecutionChange[:], utils.Uint32ToBytes4(uint32(s.beaconCfg.GenesisForkVersion)), genesisValidatorRoot)
83+
if err != nil {
84+
return err
85+
}
86+
signedRoot, err := fork.ComputeSigningRoot(change, domain)
87+
if err != nil {
88+
return err
89+
}
90+
valid, err := bls.Verify(msg.Signature[:], signedRoot[:], change.From[:])
91+
if err != nil {
92+
return err
93+
}
94+
if !valid {
95+
return fmt.Errorf("invalid signature")
96+
}
97+
s.operationsPool.BLSToExecutionChangesPool.Insert(msg.Signature, msg)
98+
return nil
99+
}

cl/phase1/network/services/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ type AttestationService Service[*solid.Attestation]
3333

3434
//go:generate mockgen -destination=./mock_services/voluntary_exit_service_mock.go -package=mock_services . VoluntaryExitService
3535
type VoluntaryExitService Service[*cltypes.SignedVoluntaryExit]
36+
37+
//go:generate mockgen -destination=./mock_services/bls_to_execution_change_service_mock.go -package=mock_services . BLSToExecutionChangeService
38+
type BLSToExecutionChangeService Service[*cltypes.SignedBLSToExecutionChange]

0 commit comments

Comments
 (0)