Skip to content

Commit

Permalink
check attestation signature (#10018)
Browse files Browse the repository at this point in the history
  • Loading branch information
domiwei authored Apr 23, 2024
1 parent 190cbfa commit 586416c
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 26 deletions.
1 change: 1 addition & 0 deletions cl/beacon/synced_data/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "github.com/ledgerwatch/erigon/cl/phase1/core/state"
type SyncedData interface {
OnHeadState(newState *state.CachingBeaconState) (err error)
HeadState() *state.CachingBeaconState
HeadStateReader() state.BeaconStateReader
Syncing() bool
HeadSlot() uint64
}
14 changes: 14 additions & 0 deletions cl/beacon/synced_data/mock_services/synced_data_mock.go

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

8 changes: 8 additions & 0 deletions cl/beacon/synced_data/synced_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ func (s *SyncedDataManager) HeadState() *state.CachingBeaconState {
return nil
}

func (s *SyncedDataManager) HeadStateReader() state.BeaconStateReader {
headstate := s.HeadState()
if headstate == nil {
return nil
}
return headstate
}

func (s *SyncedDataManager) Syncing() bool {
if !s.enabled {
return false
Expand Down
12 changes: 12 additions & 0 deletions cl/phase1/core/state/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package state

import libcommon "github.com/ledgerwatch/erigon-lib/common"

// BeaconStateReader is an interface for reading the beacon state.
//
//go:generate mockgen -destination=./mock_services/beacon_state_reader.go -package=mock_services . BeaconStateReader
type BeaconStateReader interface {
ValidatorPublicKey(index int) (libcommon.Bytes48, error)
GetDomain(domainType [4]byte, epoch uint64) ([]byte, error)
CommitteeCount(epoch uint64) uint64
}
84 changes: 84 additions & 0 deletions cl/phase1/core/state/mock_services/beacon_state_reader.go

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

27 changes: 25 additions & 2 deletions cl/phase1/network/services/attestation_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"fmt"
"time"

"github.com/Giulio2002/bls"
"github.com/ledgerwatch/erigon/cl/beacon/synced_data"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
"github.com/ledgerwatch/erigon/cl/fork"
"github.com/ledgerwatch/erigon/cl/phase1/core/state/lru"
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice"
"github.com/ledgerwatch/erigon/cl/phase1/network/subnets"
Expand All @@ -19,6 +21,8 @@ import (
var (
computeSubnetForAttestation = subnets.ComputeSubnetForAttestation
computeCommitteeCountPerSlot = subnets.ComputeCommitteeCountPerSlot
computeSigningRoot = fork.ComputeSigningRoot
blsVerify = bls.Verify
)

type attestationService struct {
Expand Down Expand Up @@ -59,7 +63,7 @@ func (s *attestationService) ProcessMessage(ctx context.Context, subnet *uint64,
committeeIndex = att.AttestantionData().CommitteeIndex()
targetEpoch = att.AttestantionData().Target().Epoch()
)
headState := s.syncedDataManager.HeadState()
headState := s.syncedDataManager.HeadStateReader()
if headState == nil {
return ErrIgnore
}
Expand Down Expand Up @@ -117,7 +121,6 @@ func (s *attestationService) ProcessMessage(ctx context.Context, subnet *uint64,
if setBits != 1 {
return fmt.Errorf("attestation does not have exactly one participating validator")
}

// [IGNORE] There has been no other valid attestation seen on an attestation subnet that has an identical attestation.data.target.epoch and participating validator index.
if err != nil {
return err
Expand All @@ -133,6 +136,26 @@ func (s *attestationService) ProcessMessage(ctx context.Context, subnet *uint64,
}
s.validatorAttestationSeen.Add(vIndex, targetEpoch)

// [REJECT] The signature of attestation is valid.
signature := att.Signature()
pubKey, err := headState.ValidatorPublicKey(int(beaconCommittee[onBitIndex]))
if err != nil {
return fmt.Errorf("unable to get public key: %v", err)
}
domain, err := headState.GetDomain(s.beaconCfg.DomainBeaconAttester, targetEpoch)
if err != nil {
return fmt.Errorf("unable to get the domain: %v", err)
}
signingRoot, err := computeSigningRoot(att.AttestantionData(), domain)
if err != nil {
return fmt.Errorf("unable to get signing root: %v", err)
}
if valid, err := blsVerify(signature[:], signingRoot[:], pubKey[:]); err != nil {
return err
} else if !valid {
return fmt.Errorf("invalid signature")
}

// [IGNORE] The block being voted for (attestation.data.beacon_block_root) has been seen (via both gossip and non-gossip sources)
// (a client MAY queue attestations for processing once block is retrieved).
if _, ok := s.forkchoiceStore.GetHeader(root); !ok {
Expand Down
Loading

0 comments on commit 586416c

Please sign in to comment.