Skip to content

Commit d1efab5

Browse files
committed
beacon/light: attempt at refactoring
1 parent 9fd49b0 commit d1efab5

File tree

4 files changed

+287
-185
lines changed

4 files changed

+287
-185
lines changed

beacon/light/canonical.go

Lines changed: 0 additions & 140 deletions
This file was deleted.

beacon/light/canonicalstore.go

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
// Copyright 2023 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package light
18+
19+
import (
20+
"encoding/binary"
21+
"fmt"
22+
23+
"github.com/ethereum/go-ethereum/beacon/types"
24+
"github.com/ethereum/go-ethereum/common"
25+
"github.com/ethereum/go-ethereum/common/lru"
26+
"github.com/ethereum/go-ethereum/core/rawdb"
27+
"github.com/ethereum/go-ethereum/ethdb"
28+
"github.com/ethereum/go-ethereum/log"
29+
"github.com/ethereum/go-ethereum/rlp"
30+
)
31+
32+
func determineRange(db ethdb.Iteratee, keyPrefix []byte) Range {
33+
var (
34+
iter = db.NewIterator(keyPrefix, nil)
35+
keyLength = len(keyPrefix)
36+
p Range
37+
)
38+
defer iter.Release()
39+
for iter.Next() {
40+
if len(iter.Key()) != keyLength+8 {
41+
log.Warn("Invalid key length in the canonical chain database", "key", fmt.Sprintf("%#x", iter.Key()))
42+
continue
43+
}
44+
period := binary.BigEndian.Uint64(iter.Key()[keyLength : keyLength+8])
45+
if p.Start == 0 {
46+
p.Start = period
47+
} else if p.End != period {
48+
log.Warn("Gap in the canonical chain database")
49+
break // continuity guaranteed
50+
}
51+
p.End = period + 1
52+
}
53+
return p
54+
}
55+
56+
// fixedCommitteeRootsStore stores fixedCommitteeRoots
57+
type fixedCommitteeRootsStore struct {
58+
periods Range
59+
cache *lru.Cache[uint64, common.Hash]
60+
}
61+
62+
// newFixedCommitteeRootsStore creates a new fixedCommitteeRootsStore and
63+
// verifies the continuity of the range in database.
64+
func newFixedCommitteeRootsStore(db ethdb.Iteratee) *fixedCommitteeRootsStore {
65+
return &fixedCommitteeRootsStore{
66+
cache: lru.NewCache[uint64, common.Hash](100),
67+
periods: determineRange(db, rawdb.FixedCommitteeRootKey),
68+
}
69+
}
70+
71+
// databaseKey returns the database key belonging to the given period.
72+
func (cs *fixedCommitteeRootsStore) databaseKey(period uint64) []byte {
73+
return binary.BigEndian.AppendUint64(rawdb.FixedCommitteeRootKey, period)
74+
}
75+
76+
// add adds the given item to the database. It also ensures that the range remains
77+
// continuous. Can be used either with a batch or database backend.
78+
func (cs *fixedCommitteeRootsStore) add(backend ethdb.KeyValueWriter, period uint64, value common.Hash) error {
79+
if !cs.periods.CanExpand(period) {
80+
return fmt.Errorf("period expansion is not allowed, first: %d, next: %d, period: %d", cs.periods.Start, cs.periods.End, period)
81+
}
82+
if err := backend.Put(cs.databaseKey(period), value[:]); err != nil {
83+
return err
84+
}
85+
cs.cache.Add(period, value)
86+
cs.periods.Expand(period)
87+
return nil
88+
}
89+
90+
// deleteFrom removes items starting from the given period.
91+
func (cs *fixedCommitteeRootsStore) deleteFrom(db ethdb.KeyValueWriter, fromPeriod uint64) (deleted Range) {
92+
keepRange, deleteRange := cs.periods.Split(fromPeriod)
93+
deleteRange.Each(func(period uint64) {
94+
db.Delete(cs.databaseKey(period))
95+
cs.cache.Remove(period)
96+
})
97+
cs.periods = keepRange
98+
return deleteRange
99+
}
100+
101+
// get returns the item at the given period or the null value of the given type
102+
// if no item is present.
103+
// Note: get is thread safe in itself and therefore can be called either with
104+
// locked or unlocked chain mutex.
105+
func (cs *fixedCommitteeRootsStore) get(backend ethdb.KeyValueReader, period uint64) (value common.Hash, ok bool) {
106+
if value, ok = cs.cache.Get(period); ok {
107+
return
108+
}
109+
enc, err := backend.Get(cs.databaseKey(period))
110+
if err != nil {
111+
return common.Hash{}, false
112+
}
113+
if len(enc) != common.HashLength {
114+
log.Error("Error decoding canonical store value", "error", "incorrect length for committee root entry in the database")
115+
}
116+
return common.BytesToHash(enc), true
117+
}
118+
119+
// serializedSyncCommitteeStore stores SerializedSyncCommittee
120+
type serializedSyncCommitteeStore struct {
121+
periods Range
122+
cache *lru.Cache[uint64, *types.SerializedSyncCommittee]
123+
}
124+
125+
// newSerializedSyncCommitteSTore creates a new serializedSyncCommitteeStore and
126+
// verifies the continuity of the range in database.
127+
func newSerializedSyncCommitteSTore(db ethdb.Iteratee) *serializedSyncCommitteeStore {
128+
return &serializedSyncCommitteeStore{
129+
cache: lru.NewCache[uint64, *types.SerializedSyncCommittee](100),
130+
periods: determineRange(db, rawdb.SyncCommitteeKey),
131+
}
132+
}
133+
134+
// databaseKey returns the database key belonging to the given period.
135+
func (cs *serializedSyncCommitteeStore) databaseKey(period uint64) []byte {
136+
return binary.BigEndian.AppendUint64(rawdb.SyncCommitteeKey, period)
137+
}
138+
139+
// add adds the given item to the database. It also ensures that the range remains
140+
// continuous. Can be used either with a batch or database backend.
141+
func (cs *serializedSyncCommitteeStore) add(db ethdb.KeyValueWriter, period uint64, value *types.SerializedSyncCommittee) error {
142+
if !cs.periods.CanExpand(period) {
143+
return fmt.Errorf("period expansion is not allowed, first: %d, next: %d, period: %d", cs.periods.Start, cs.periods.End, period)
144+
}
145+
if err := db.Put(cs.databaseKey(period), value[:]); err != nil {
146+
return err
147+
}
148+
cs.cache.Add(period, value)
149+
cs.periods.Expand(period)
150+
return nil
151+
}
152+
153+
// deleteFrom removes items starting from the given period.
154+
func (cs *serializedSyncCommitteeStore) deleteFrom(db ethdb.KeyValueWriter, fromPeriod uint64) (deleted Range) {
155+
keepRange, deleteRange := cs.periods.Split(fromPeriod)
156+
deleteRange.Each(func(period uint64) {
157+
db.Delete(cs.databaseKey(period))
158+
cs.cache.Remove(period)
159+
})
160+
cs.periods = keepRange
161+
return deleteRange
162+
}
163+
164+
// get returns the item at the given period or the null value of the given type
165+
// if no item is present.
166+
// Note: get is thread safe in itself and therefore can be called either with
167+
// locked or unlocked chain mutex.
168+
func (cs *serializedSyncCommitteeStore) get(db ethdb.KeyValueReader, period uint64) (value *types.SerializedSyncCommittee, ok bool) {
169+
if value, ok = cs.cache.Get(period); ok {
170+
return
171+
}
172+
enc, err := db.Get(cs.databaseKey(period))
173+
if err != nil {
174+
return nil, false
175+
}
176+
if len(enc) != types.SerializedSyncCommitteeSize {
177+
log.Error("Error decoding canonical store value", "error", "incorrect length for serialized committee entry in the database")
178+
return nil, false
179+
}
180+
committee := new(types.SerializedSyncCommittee)
181+
copy(committee[:], enc)
182+
return committee, true
183+
}
184+
185+
// updatesStore stores lightclient updates
186+
type updatesStore struct {
187+
periods Range
188+
cache *lru.Cache[uint64, *types.LightClientUpdate]
189+
}
190+
191+
// newUpdatesStore creates a new updatesStore and
192+
// verifies the continuity of the range in database.
193+
func newUpdatesStore(db ethdb.Iteratee) *updatesStore {
194+
return &updatesStore{
195+
cache: lru.NewCache[uint64, *types.LightClientUpdate](100),
196+
periods: determineRange(db, rawdb.BestUpdateKey),
197+
}
198+
}
199+
200+
// databaseKey returns the database key belonging to the given period.
201+
func (cs *updatesStore) databaseKey(period uint64) []byte {
202+
return binary.BigEndian.AppendUint64(rawdb.BestUpdateKey, period)
203+
}
204+
205+
// add adds the given item to the database. It also ensures that the range remains
206+
// continuous. Can be used either with a batch or database backend.
207+
func (cs *updatesStore) add(db ethdb.KeyValueWriter, period uint64, update *types.LightClientUpdate) error {
208+
if !cs.periods.CanExpand(period) {
209+
return fmt.Errorf("period expansion is not allowed, first: %d, next: %d, period: %d", cs.periods.Start, cs.periods.End, period)
210+
}
211+
enc, err := rlp.EncodeToBytes(update)
212+
if err != nil {
213+
return err
214+
}
215+
if err := db.Put(cs.databaseKey(period), enc); err != nil {
216+
return err
217+
}
218+
cs.cache.Add(period, update)
219+
cs.periods.Expand(period)
220+
return nil
221+
}
222+
223+
// deleteFrom removes items starting from the given period.
224+
func (cs *updatesStore) deleteFrom(db ethdb.KeyValueWriter, fromPeriod uint64) (deleted Range) {
225+
keepRange, deleteRange := cs.periods.Split(fromPeriod)
226+
deleteRange.Each(func(period uint64) {
227+
db.Delete(cs.databaseKey(period))
228+
cs.cache.Remove(period)
229+
})
230+
cs.periods = keepRange
231+
return deleteRange
232+
}
233+
234+
// get returns the item at the given period or the null value of the given type
235+
// if no item is present.
236+
// Note: get is thread safe in itself and therefore can be called either with
237+
// locked or unlocked chain mutex.
238+
func (cs *updatesStore) get(db ethdb.KeyValueReader, period uint64) (value *types.LightClientUpdate, ok bool) {
239+
if value, ok = cs.cache.Get(period); ok {
240+
return
241+
}
242+
enc, err := db.Get(cs.databaseKey(period))
243+
if err != nil {
244+
return nil, false
245+
}
246+
update := new(types.LightClientUpdate)
247+
if err := rlp.DecodeBytes(enc, update); err != nil {
248+
log.Error("Error decoding canonical store value", "error", err)
249+
return nil, false
250+
}
251+
return update, true
252+
}

0 commit comments

Comments
 (0)