Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check attestation signature #10018

Merged
merged 3 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading