Skip to content

Commit

Permalink
blsToExecutionChange
Browse files Browse the repository at this point in the history
  • Loading branch information
domiwei committed Apr 18, 2024
1 parent 92a78d5 commit 8fb4b5e
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 68 deletions.
4 changes: 4 additions & 0 deletions cl/beacon/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type ApiHandler struct {
syncContributionAndProofsService services.SyncContributionService
aggregateAndProofsService services.AggregateAndProofService
voluntaryExitService services.VoluntaryExitService
blsToExecutionChangeService services.BLSToExecutionChangeService
}

func NewApiHandler(
Expand Down Expand Up @@ -112,6 +113,8 @@ func NewApiHandler(
syncContributionAndProofs services.SyncContributionService,
aggregateAndProofs services.AggregateAndProofService,
voluntaryExitService services.VoluntaryExitService,
blsToExecutionChangeService services.BLSToExecutionChangeService,

) *ApiHandler {
blobBundles, err := lru.New[common.Bytes48, BlobBundle]("blobs", maxBlobBundleCacheSize)
if err != nil {
Expand Down Expand Up @@ -149,6 +152,7 @@ func NewApiHandler(
syncContributionAndProofsService: syncContributionAndProofs,
aggregateAndProofsService: aggregateAndProofs,
voluntaryExitService: voluntaryExitService,
blsToExecutionChangeService: blsToExecutionChangeService,
}
}

Expand Down
2 changes: 1 addition & 1 deletion cl/beacon/handler/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func (a *ApiHandler) PostEthV1BeaconPoolBlsToExecutionChanges(w http.ResponseWri
}
failures := []poolingFailure{}
for _, v := range req {
if err := a.forkchoiceStore.OnBlsToExecutionChange(v, false); err != nil {
if err := a.blsToExecutionChangeService.ProcessMessage(r.Context(), nil, v); err != nil && !errors.Is(err, services.ErrIgnore) {
failures = append(failures, poolingFailure{Index: len(failures), Message: err.Error()})
continue
}
Expand Down
14 changes: 13 additions & 1 deletion cl/beacon/handler/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
syncContributionService := mock_services.NewMockSyncContributionService(ctrl)
aggregateAndProofsService := mock_services.NewMockAggregateAndProofService(ctrl)
voluntaryExitService := mock_services.NewMockVoluntaryExitService(ctrl)
blsToExecutionChangeService := mock_services.NewMockBLSToExecutionChangeService(ctrl)

// ctx context.Context, subnetID *uint64, msg *cltypes.SyncCommitteeMessage) error
syncCommitteeMessagesService.EXPECT().ProcessMessage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, subnetID *uint64, msg *cltypes.SyncCommitteeMessage) error {
return h.syncMessagePool.AddSyncCommitteeMessage(postState, *subnetID, msg)
Expand All @@ -105,6 +107,10 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
opPool.VoluntaryExistsPool.Insert(msg.VoluntaryExit.ValidatorIndex, msg)
return nil
}).AnyTimes()
blsToExecutionChangeService.EXPECT().ProcessMessage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, subnetID *uint64, msg *cltypes.SignedBLSToExecutionChange) error {
opPool.BLSToExecutionChangesPool.Insert(msg.Signature, msg)
return nil
}).AnyTimes()

vp = validator_params.NewValidatorParams()
h = NewApiHandler(
Expand All @@ -128,7 +134,13 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logge
Events: true,
Validator: true,
Lighthouse: true,
}, nil, blobStorage, nil, vp, nil, nil, fcu.SyncContributionPool, nil, nil, syncCommitteeMessagesService, syncContributionService, aggregateAndProofsService, voluntaryExitService) // TODO: add tests
}, nil, blobStorage, nil, vp, nil, nil, fcu.SyncContributionPool, nil, nil,
syncCommitteeMessagesService,
syncContributionService,
aggregateAndProofsService,
voluntaryExitService,
blsToExecutionChangeService,
) // TODO: add tests
h.Init()
return
}
1 change: 1 addition & 0 deletions cl/beacon/handler/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func (t *validatorTestSuite) SetupTest() {
nil,
nil,
nil,
nil,
)
t.gomockCtrl = gomockCtrl
}
Expand Down
6 changes: 0 additions & 6 deletions cl/phase1/forkchoice/fork_choice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,6 @@ func TestForkChoiceBasic(t *testing.T) {
for sd.HeadState() == nil {
time.Sleep(time.Millisecond)
}
// Try processing a bls execution change exit
err = store.OnBlsToExecutionChange(&cltypes.SignedBLSToExecutionChange{
Message: &cltypes.BLSToExecutionChange{
ValidatorIndex: 0,
},
}, true)
require.NoError(t, err)
require.Equal(t, len(pool.VoluntaryExistsPool.Raw()), 1)
}
Expand Down
1 change: 0 additions & 1 deletion cl/phase1/forkchoice/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ type ForkChoiceStorageWriter interface {
OnAttestation(attestation *solid.Attestation, fromBlock, insert bool) error
OnAttesterSlashing(attesterSlashing *cltypes.AttesterSlashing, test bool) error
OnProposerSlashing(proposerSlashing *cltypes.ProposerSlashing, test bool) error
OnBlsToExecutionChange(signedChange *cltypes.SignedBLSToExecutionChange, test bool) error
OnBlock(ctx context.Context, block *cltypes.SignedBeaconBlock, newPayload bool, fullValidation bool, checkDataAvaibility bool) error
AddPreverifiedBlobSidecar(blobSidecar *cltypes.BlobSidecar) error
OnTick(time uint64)
Expand Down
57 changes: 0 additions & 57 deletions cl/phase1/forkchoice/on_operations.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package forkchoice

import (
"bytes"
"fmt"

"github.com/Giulio2002/bls"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/fork"
"github.com/ledgerwatch/erigon/cl/phase1/core/state"
"github.com/ledgerwatch/erigon/cl/pool"
"github.com/ledgerwatch/erigon/cl/utils"
)

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

return nil
}

func (f *ForkChoiceStore) OnBlsToExecutionChange(signedChange *cltypes.SignedBLSToExecutionChange, test bool) error {
if f.operationsPool.BLSToExecutionChangesPool.Has(signedChange.Signature) {
f.emitters.Publish("bls_to_execution_change", signedChange)
return nil
}
change := signedChange.Message

// Take lock as we interact with state.
s := f.syncedDataManager.HeadState()
if s == nil {
return nil
}
validator, err := s.ValidatorForValidatorIndex(int(change.ValidatorIndex))
if err != nil {
return fmt.Errorf("unable to retrieve state: %v", err)
}
wc := validator.WithdrawalCredentials()

if wc[0] != byte(f.beaconCfg.BLSWithdrawalPrefixByte) {
return fmt.Errorf("invalid withdrawal credentials prefix")
}
genesisValidatorRoot := s.GenesisValidatorsRoot()
// Perform full validation if requested.
if !test {
// Check the validator's withdrawal credentials against the provided message.
hashedFrom := utils.Sha256(change.From[:])
if !bytes.Equal(hashedFrom[1:], wc[1:]) {
return fmt.Errorf("invalid withdrawal credentials")
}

// Compute the signing domain and verify the message signature.
domain, err := fork.ComputeDomain(f.beaconCfg.DomainBLSToExecutionChange[:], utils.Uint32ToBytes4(uint32(f.beaconCfg.GenesisForkVersion)), genesisValidatorRoot)
if err != nil {
return err
}
signedRoot, err := fork.ComputeSigningRoot(change, domain)
if err != nil {
return err
}
valid, err := bls.Verify(signedChange.Signature[:], signedRoot[:], change.From[:])
if err != nil {
return err
}
if !valid {
return fmt.Errorf("invalid signature")
}
}

f.operationsPool.BLSToExecutionChangesPool.Insert(signedChange.Signature, signedChange)

// emit bls_to_execution_change
f.emitters.Publish("bls_to_execution_change", signedChange)
return nil
}
9 changes: 8 additions & 1 deletion cl/phase1/network/gossip_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type GossipManager struct {
aggregateAndProofService services.AggregateAndProofService
attestationService services.AttestationService
voluntaryExitService services.VoluntaryExitService
blsToExecutionChangeService services.BLSToExecutionChangeService
}

func NewGossipReceiver(
Expand All @@ -60,6 +61,7 @@ func NewGossipReceiver(
aggregateAndProofService services.AggregateAndProofService,
attestationService services.AttestationService,
voluntaryExitService services.VoluntaryExitService,
blsToExecutionChangeService services.BLSToExecutionChangeService,
) *GossipManager {
return &GossipManager{
sentinel: s,
Expand All @@ -75,6 +77,7 @@ func NewGossipReceiver(
aggregateAndProofService: aggregateAndProofService,
attestationService: attestationService,
voluntaryExitService: voluntaryExitService,
blsToExecutionChangeService: blsToExecutionChangeService,
}
}

Expand Down Expand Up @@ -161,7 +164,11 @@ func (g *GossipManager) routeAndProcess(ctx context.Context, data *sentinel.Goss
case gossip.TopicNameAttesterSlashing:
return operationsContract[*cltypes.AttesterSlashing](ctx, g, data, int(version), "attester slashing", g.forkChoice.OnAttesterSlashing)
case gossip.TopicNameBlsToExecutionChange:
return operationsContract[*cltypes.SignedBLSToExecutionChange](ctx, g, data, int(version), "bls to execution change", g.forkChoice.OnBlsToExecutionChange)
obj := &cltypes.SignedBLSToExecutionChange{}
if err := obj.DecodeSSZ(data.Data, int(version)); err != nil {
return err
}
return g.blsToExecutionChangeService.ProcessMessage(ctx, data.SubnetId, obj)
case gossip.TopicNameBeaconAggregateAndProof:
obj := &cltypes.SignedAggregateAndProof{}
if err := obj.DecodeSSZ(data.Data, int(version)); err != nil {
Expand Down
99 changes: 99 additions & 0 deletions cl/phase1/network/services/BlsToExecutionChange.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package services

import (
"bytes"
"context"
"fmt"

"github.com/Giulio2002/bls"
"github.com/ledgerwatch/erigon/cl/beacon/beaconevents"
"github.com/ledgerwatch/erigon/cl/beacon/synced_data"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/fork"
"github.com/ledgerwatch/erigon/cl/pool"
"github.com/ledgerwatch/erigon/cl/utils"
)

type blsToExecutionChangeService struct {
operationsPool pool.OperationsPool
emitters *beaconevents.Emitters
syncedDataManager *synced_data.SyncedDataManager
beaconCfg *clparams.BeaconChainConfig
}

func NewBLSToExecutionChangeService(
operationsPool pool.OperationsPool,
emitters *beaconevents.Emitters,
syncedDataManager *synced_data.SyncedDataManager,
beaconCfg *clparams.BeaconChainConfig,
) BLSToExecutionChangeService {
return &blsToExecutionChangeService{
operationsPool: operationsPool,
emitters: emitters,
syncedDataManager: syncedDataManager,
beaconCfg: beaconCfg,
}
}

func (s *blsToExecutionChangeService) ProcessMessage(ctx context.Context, subnet *uint64, msg *cltypes.SignedBLSToExecutionChange) error {
defer s.emitters.Publish("bls_to_execution_change", msg)

// [IGNORE] The signed_bls_to_execution_change is the first valid signed bls to execution change received
// for the validator with index signed_bls_to_execution_change.message.validator_index.
if s.operationsPool.BLSToExecutionChangesPool.Has(msg.Signature) {
return nil
}
change := msg.Message

state := s.syncedDataManager.HeadState()
if state == nil {
return nil
}

// [IGNORE] current_epoch >= CAPELLA_FORK_EPOCH, where current_epoch is defined by the current wall-clock time.
if !(state.Version() >= clparams.CapellaVersion) {
return ErrIgnore
}

// ref: https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
// assert address_change.validator_index < len(state.validators)
validator, err := state.ValidatorForValidatorIndex(int(change.ValidatorIndex))
if err != nil {
return fmt.Errorf("unable to retrieve state: %v", err)
}
wc := validator.WithdrawalCredentials()

// assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX
if wc[0] != byte(s.beaconCfg.BLSWithdrawalPrefixByte) {
return fmt.Errorf("invalid withdrawal credentials prefix")
}

// assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:]
// Perform full validation if requested.
// Check the validator's withdrawal credentials against the provided message.
hashedFrom := utils.Sha256(change.From[:])
if !bytes.Equal(hashedFrom[1:], wc[1:]) {
return fmt.Errorf("invalid withdrawal credentials")
}

// assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature)
genesisValidatorRoot := state.GenesisValidatorsRoot()
domain, err := fork.ComputeDomain(s.beaconCfg.DomainBLSToExecutionChange[:], utils.Uint32ToBytes4(uint32(s.beaconCfg.GenesisForkVersion)), genesisValidatorRoot)
if err != nil {
return err
}
signedRoot, err := fork.ComputeSigningRoot(change, domain)
if err != nil {
return err
}
valid, err := bls.Verify(msg.Signature[:], signedRoot[:], change.From[:])
if err != nil {
return err
}
if !valid {
return fmt.Errorf("invalid signature")
}
s.operationsPool.BLSToExecutionChangesPool.Insert(msg.Signature, msg)
return nil
}
3 changes: 3 additions & 0 deletions cl/phase1/network/services/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ type AttestationService Service[*solid.Attestation]

//go:generate mockgen -destination=./mock_services/voluntary_exit_service_mock.go -package=mock_services . VoluntaryExitService
type VoluntaryExitService Service[*cltypes.SignedVoluntaryExit]

//go:generate mockgen -destination=./mock_services/bls_to_execution_change_service_mock.go -package=mock_services . BLSToExecutionChangeService
type BLSToExecutionChangeService Service[*cltypes.SignedBLSToExecutionChange]

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion cmd/caplin/caplin1/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,11 @@ func RunCaplinPhase1(ctx context.Context, engine execution_client.ExecutionEngin
aggregateAndProofService := services.NewAggregateAndProofService(ctx, syncedDataManager, forkChoice, beaconConfig, aggregationPool)
attestationService := services.NewAttestationService(forkChoice, committeeSub, ethClock, syncedDataManager, beaconConfig, networkConfig)
voluntaryExitService := services.NewVoluntaryExitService(pool, emitters, syncedDataManager, beaconConfig, ethClock)
blsToExecutionChangeService := services.NewBLSToExecutionChangeService(pool, emitters, syncedDataManager, beaconConfig)
// Create the gossip manager
gossipManager := network.NewGossipReceiver(sentinel, forkChoice, beaconConfig, ethClock, emitters, committeeSub,
blockService, blobService, syncCommitteeMessagesService, syncContributionService, aggregateAndProofService,
attestationService, voluntaryExitService)
attestationService, voluntaryExitService, blsToExecutionChangeService)
{ // start ticking forkChoice
go func() {
tickInterval := time.NewTicker(2 * time.Millisecond)
Expand Down Expand Up @@ -294,6 +295,7 @@ func RunCaplinPhase1(ctx context.Context, engine execution_client.ExecutionEngin
syncContributionService,
aggregateAndProofService,
voluntaryExitService,
blsToExecutionChangeService,
)
go beacon.ListenAndServe(&beacon.LayeredBeaconHandler{
ArchiveApi: apiHandler,
Expand Down

0 comments on commit 8fb4b5e

Please sign in to comment.