diff --git a/beacon/light/canonical.go b/beacon/light/canonical.go index 6fa9de48bb..2d65ea0100 100644 --- a/beacon/light/canonical.go +++ b/beacon/light/canonical.go @@ -38,7 +38,8 @@ type canonicalStore[T any] struct { decode func([]byte) (T, error) } -// newCanonicalStore creates a new canonicalStore. +// newCanonicalStore creates a new canonicalStore and loads all keys associated +// with the keyPrefix in order to determine the ranges available in the database. func newCanonicalStore[T any](db ethdb.KeyValueStore, keyPrefix []byte, encode func(T) ([]byte, error), decode func([]byte) (T, error)) *canonicalStore[T] { cs := &canonicalStore[T]{ diff --git a/beacon/light/committee_chain.go b/beacon/light/committee_chain.go index 82a1830986..a068387864 100644 --- a/beacon/light/committee_chain.go +++ b/beacon/light/committee_chain.go @@ -79,11 +79,17 @@ type CommitteeChain struct { config *types.ChainConfig signerThreshold int minimumUpdateScore types.UpdateScore - enforceTime bool + enforceTime bool // enforceTime specifies whether the age of a signed header should be checked } // NewCommitteeChain creates a new CommitteeChain. -func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain { +func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool) *CommitteeChain { + return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() }) +} + +// newCommitteeChain creates a new CommitteeChain with the option of replacing the +// clock source and signature verification for testing purposes. +func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain { var ( fixedRootEncoder = func(root common.Hash) ([]byte, error) { return root[:], nil @@ -163,10 +169,15 @@ func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signer // checkConstraints checks committee chain validity constraints func (s *CommitteeChain) checkConstraints() bool { + isNotInFixedRootRange := func(r Range) bool { + return s.fixedRoots.periods.IsEmpty() || + r.First < s.fixedRoots.periods.First || + r.First >= s.fixedRoots.periods.Next + } + valid := true if !s.updates.periods.IsEmpty() { - if s.fixedRoots.periods.IsEmpty() || s.updates.periods.First < s.fixedRoots.periods.First || - s.updates.periods.First >= s.fixedRoots.periods.Next { + if isNotInFixedRootRange(s.updates.periods) { log.Error("First update is not in the fixed roots range") valid = false } @@ -176,8 +187,7 @@ func (s *CommitteeChain) checkConstraints() bool { } } if !s.committees.periods.IsEmpty() { - if s.fixedRoots.periods.IsEmpty() || s.committees.periods.First < s.fixedRoots.periods.First || - s.committees.periods.First >= s.fixedRoots.periods.Next { + if isNotInFixedRootRange(s.committees.periods) { log.Error("First committee is not in the fixed roots range") valid = false } @@ -206,6 +216,10 @@ func (s *CommitteeChain) AddFixedRoot(period uint64, root common.Hash) error { s.chainmu.Lock() defer s.chainmu.Unlock() + if root == (common.Hash{}) { + return ErrWrongCommitteeRoot + } + batch := s.db.NewBatch() oldRoot := s.getCommitteeRoot(period) if !s.fixedRoots.periods.CanExpand(period) { diff --git a/beacon/light/committee_chain_test.go b/beacon/light/committee_chain_test.go index 02d8710d3e..8cb09d9ff0 100644 --- a/beacon/light/committee_chain_test.go +++ b/beacon/light/committee_chain_test.go @@ -241,12 +241,12 @@ func newCommitteeChainTest(t *testing.T, config types.ChainConfig, signerThresho signerThreshold: signerThreshold, enforceTime: enforceTime, } - c.chain = NewCommitteeChain(c.db, &config, signerThreshold, enforceTime, DummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) }) + c.chain = newCommitteeChain(c.db, &config, signerThreshold, enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) }) return c } func (c *committeeChainTest) reloadChain() { - c.chain = NewCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, DummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) }) + c.chain = newCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) }) } func (c *committeeChainTest) setClockPeriod(period float64) { diff --git a/beacon/light/test_helpers.go b/beacon/light/test_helpers.go index bfecde591a..8f7cc2bf61 100644 --- a/beacon/light/test_helpers.go +++ b/beacon/light/test_helpers.go @@ -51,7 +51,7 @@ func GenerateTestUpdate(config *types.ChainConfig, period uint64, committee, nex func GenerateTestSignedHeader(header types.Header, config *types.ChainConfig, committee *types.SerializedSyncCommittee, signatureSlot uint64, signerCount int) types.SignedHeader { bitmask := makeBitmask(signerCount) signingRoot, _ := config.Forks.SigningRoot(header) - c, _ := DummyVerifier{}.deserializeSyncCommittee(committee) + c, _ := dummyVerifier{}.deserializeSyncCommittee(committee) return types.SignedHeader{ Header: header, Signature: types.SyncAggregate{ @@ -113,33 +113,33 @@ type committeeSigVerifier interface { verifySignature(committee syncCommittee, signedRoot common.Hash, aggregate *types.SyncAggregate) bool } -// BLSVerifier implements committeeSigVerifier -type BLSVerifier struct{} +// blsVerifier implements committeeSigVerifier +type blsVerifier struct{} // deserializeSyncCommittee implements committeeSigVerifier -func (BLSVerifier) deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error) { +func (blsVerifier) deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error) { return s.Deserialize() } // verifySignature implements committeeSigVerifier -func (BLSVerifier) verifySignature(committee syncCommittee, signingRoot common.Hash, aggregate *types.SyncAggregate) bool { +func (blsVerifier) verifySignature(committee syncCommittee, signingRoot common.Hash, aggregate *types.SyncAggregate) bool { return committee.(*types.SyncCommittee).VerifySignature(signingRoot, aggregate) } type dummySyncCommittee [32]byte -// DummyVerifier implements committeeSigVerifier -type DummyVerifier struct{} +// dummyVerifier implements committeeSigVerifier +type dummyVerifier struct{} // deserializeSyncCommittee implements committeeSigVerifier -func (DummyVerifier) deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error) { +func (dummyVerifier) deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error) { var sc dummySyncCommittee copy(sc[:], s[:32]) return sc, nil } // verifySignature implements committeeSigVerifier -func (DummyVerifier) verifySignature(committee syncCommittee, signingRoot common.Hash, aggregate *types.SyncAggregate) bool { +func (dummyVerifier) verifySignature(committee syncCommittee, signingRoot common.Hash, aggregate *types.SyncAggregate) bool { return aggregate.Signature == makeDummySignature(committee.(dummySyncCommittee), signingRoot, aggregate.Signers) } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 46cc7ecef2..cd3651dffe 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -132,12 +132,12 @@ var ( CliqueSnapshotPrefix = []byte("clique-") - preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) - preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) - BestUpdateKey = []byte("update-") // bigEndian64(syncPeriod) -> RLP(types.LightClientUpdate) (nextCommittee only referenced by root hash) FixedRootKey = []byte("fixedRoot-") // bigEndian64(syncPeriod) -> committee root hash SyncCommitteeKey = []byte("committee-") // bigEndian64(syncPeriod) -> serialized committee + + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) + preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) ) // LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary