Skip to content

Commit b5c6acf

Browse files
authored
chore: adopt libevm options, simplify constructors and unexport configs (#1289)
Signed-off-by: Tsvetan Dimitrov ([email protected])
1 parent 9032df6 commit b5c6acf

File tree

10 files changed

+284
-274
lines changed

10 files changed

+284
-274
lines changed

plugin/evm/atomic/sync/extender.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99

1010
"github.com/ava-labs/coreth/plugin/evm/atomic/state"
1111
"github.com/ava-labs/coreth/plugin/evm/message"
12+
"github.com/ava-labs/coreth/sync"
1213

13-
synccommon "github.com/ava-labs/coreth/sync"
1414
syncclient "github.com/ava-labs/coreth/sync/client"
1515
)
1616

@@ -29,17 +29,20 @@ func (a *Extender) Initialize(backend *state.AtomicBackend, trie *state.AtomicTr
2929
}
3030

3131
// CreateSyncer creates the atomic syncer with the given client and verDB.
32-
func (a *Extender) CreateSyncer(client syncclient.LeafClient, verDB *versiondb.Database, summary message.Syncable) (synccommon.Syncer, error) {
32+
func (a *Extender) CreateSyncer(client syncclient.LeafClient, verDB *versiondb.Database, summary message.Syncable) (sync.Syncer, error) {
3333
atomicSummary, ok := summary.(*Summary)
3434
if !ok {
3535
return nil, fmt.Errorf("expected *Summary, got %T", summary)
3636
}
3737

38-
return newSyncer(client, verDB, a.trie, atomicSummary.AtomicRoot, &Config{
39-
TargetHeight: atomicSummary.BlockNumber,
40-
RequestSize: a.requestSize,
41-
NumWorkers: defaultNumWorkers,
42-
})
38+
return NewSyncer(
39+
client,
40+
verDB,
41+
a.trie,
42+
atomicSummary.AtomicRoot,
43+
atomicSummary.BlockNumber,
44+
WithRequestSize(a.requestSize),
45+
)
4346
}
4447

4548
// OnFinishBeforeCommit implements the sync.Extender interface by marking the previously last accepted block for the shared memory cursor.

plugin/evm/atomic/sync/syncer.go

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package sync
55

66
import (
7-
"bytes"
87
"context"
98
"encoding/binary"
109
"errors"
@@ -13,12 +12,13 @@ import (
1312
"github.com/ava-labs/avalanchego/database/versiondb"
1413
"github.com/ava-labs/avalanchego/utils/wrappers"
1514
"github.com/ava-labs/libevm/common"
15+
"github.com/ava-labs/libevm/libevm/options"
1616
"github.com/ava-labs/libevm/trie"
1717

1818
"github.com/ava-labs/coreth/plugin/evm/message"
19+
"github.com/ava-labs/coreth/sync"
1920

2021
atomicstate "github.com/ava-labs/coreth/plugin/evm/atomic/state"
21-
synccommon "github.com/ava-labs/coreth/sync"
2222
syncclient "github.com/ava-labs/coreth/sync/client"
2323
)
2424

@@ -31,53 +31,48 @@ const (
3131
)
3232

3333
var (
34-
errInvalidTargetHeight = errors.New("TargetHeight must be greater than 0")
35-
36-
// Pre-allocate zero bytes to avoid repeated allocations.
37-
zeroBytes = bytes.Repeat([]byte{0x00}, common.HashLength)
38-
39-
_ synccommon.Syncer = (*syncer)(nil)
34+
_ sync.Syncer = (*Syncer)(nil)
4035
_ syncclient.LeafSyncTask = (*syncerLeafTask)(nil)
41-
)
42-
43-
// Name returns the human-readable name for this sync task.
44-
func (*syncer) Name() string { return "Atomic State Syncer" }
45-
46-
// ID returns the stable identifier for this sync task.
47-
func (*syncer) ID() string { return "state_atomic_sync" }
4836

49-
// Config holds the configuration for creating a new atomic syncer.
50-
type Config struct {
51-
// TargetHeight is the target block height to sync to.
52-
TargetHeight uint64
37+
errTargetHeightRequired = errors.New("target height must be > 0")
38+
)
5339

54-
// RequestSize is the maximum number of leaves to request in a single network call.
40+
// config holds the configuration for creating a new atomic syncer.
41+
type config struct {
42+
// requestSize is the maximum number of leaves to request in a single network call.
5543
// NOTE: user facing option validated as the parameter [plugin/evm/config.Config.StateSyncRequestSize].
56-
RequestSize uint16
44+
requestSize uint16
5745

58-
// NumWorkers is the number of worker goroutines to use for syncing.
46+
// numWorkers is the number of worker goroutines to use for syncing.
5947
// If not set, [defaultNumWorkers] will be used.
60-
NumWorkers int
48+
numWorkers int
6149
}
6250

63-
// WithUnsetDefaults returns a copy of the config with defaults applied for any
64-
// unset (zero) fields.
65-
func (c Config) WithUnsetDefaults() Config {
66-
out := c
67-
if out.NumWorkers == 0 {
68-
out.NumWorkers = defaultNumWorkers
69-
}
70-
if out.RequestSize == 0 {
71-
out.RequestSize = defaultRequestSize
72-
}
51+
// SyncerOption configures the atomic syncer via functional options.
52+
type SyncerOption = options.Option[config]
7353

74-
return out
54+
// WithRequestSize sets the request size per network call.
55+
func WithRequestSize(n uint16) SyncerOption {
56+
return options.Func[config](func(c *config) {
57+
if n > 0 {
58+
c.requestSize = n
59+
}
60+
})
7561
}
7662

77-
// syncer is used to sync the atomic trie from the network. The CallbackLeafSyncer
78-
// is responsible for orchestrating the sync while syncer is responsible for maintaining
63+
// WithNumWorkers sets the number of worker goroutines for syncing.
64+
func WithNumWorkers(n int) SyncerOption {
65+
return options.Func[config](func(c *config) {
66+
if n > 0 {
67+
c.numWorkers = n
68+
}
69+
})
70+
}
71+
72+
// Syncer is used to sync the atomic trie from the network. The CallbackLeafSyncer
73+
// is responsible for orchestrating the sync while Syncer is responsible for maintaining
7974
// the state of progress and writing the actual atomic trie to the trieDB.
80-
type syncer struct {
75+
type Syncer struct {
8176
db *versiondb.Database
8277
atomicTrie *atomicstate.AtomicTrie
8378
trie *trie.Trie // used to update the atomic trie
@@ -92,62 +87,76 @@ type syncer struct {
9287
lastHeight uint64
9388
}
9489

95-
// addZeros adds [common.HashLenth] zeros to [height] and returns the result as []byte
96-
func addZeroes(height uint64) []byte {
97-
packer := wrappers.Packer{Bytes: make([]byte, atomicstate.TrieKeyLength)}
98-
packer.PackLong(height)
99-
packer.PackFixedBytes(zeroBytes)
100-
return packer.Bytes
101-
}
102-
103-
// newSyncer returns a new syncer instance that will sync the atomic trie from the network.
104-
func newSyncer(client syncclient.LeafClient, db *versiondb.Database, atomicTrie *atomicstate.AtomicTrie, targetRoot common.Hash, config *Config) (*syncer, error) {
105-
if config.TargetHeight == 0 {
106-
return nil, errInvalidTargetHeight
90+
// NewSyncer returns a new syncer instance that will sync the atomic trie from the network.
91+
func NewSyncer(client syncclient.LeafClient, db *versiondb.Database, atomicTrie *atomicstate.AtomicTrie, targetRoot common.Hash, targetHeight uint64, opts ...SyncerOption) (*Syncer, error) {
92+
if targetHeight == 0 {
93+
return nil, errTargetHeightRequired
10794
}
10895

109-
// Apply defaults for unset fields.
110-
cfg := config.WithUnsetDefaults()
96+
cfg := config{
97+
numWorkers: defaultNumWorkers,
98+
requestSize: defaultRequestSize,
99+
}
100+
options.ApplyTo(&cfg, opts...)
111101

112102
lastCommittedRoot, lastCommit := atomicTrie.LastCommitted()
113103
trie, err := atomicTrie.OpenTrie(lastCommittedRoot)
114104
if err != nil {
115105
return nil, err
116106
}
117107

118-
syncer := &syncer{
108+
syncer := &Syncer{
119109
db: db,
120110
atomicTrie: atomicTrie,
121111
trie: trie,
122112
targetRoot: targetRoot,
123-
targetHeight: cfg.TargetHeight,
113+
targetHeight: targetHeight,
124114
lastHeight: lastCommit,
125115
}
126116

127117
// Create tasks channel with capacity for the number of workers.
128-
tasks := make(chan syncclient.LeafSyncTask, cfg.NumWorkers)
118+
tasks := make(chan syncclient.LeafSyncTask, cfg.numWorkers)
129119

130120
// For atomic trie syncing, we typically want a single task since the trie is sequential.
131121
// But we can create multiple tasks if needed for parallel processing of different ranges.
132122
tasks <- &syncerLeafTask{syncer: syncer}
133123
close(tasks)
134124

135125
syncer.syncer = syncclient.NewCallbackLeafSyncer(client, tasks, &syncclient.LeafSyncerConfig{
136-
RequestSize: cfg.RequestSize,
137-
NumWorkers: cfg.NumWorkers,
126+
RequestSize: cfg.requestSize,
127+
NumWorkers: cfg.numWorkers,
138128
OnFailure: func() {}, // No-op since we flush progress to disk at the regular commit interval.
139129
})
140130

141131
return syncer, nil
142132
}
143133

134+
// Name returns the human-readable name for this sync task.
135+
func (*Syncer) Name() string {
136+
return "Atomic State Syncer"
137+
}
138+
139+
// ID returns the stable identifier for this sync task.
140+
func (*Syncer) ID() string {
141+
return "state_atomic_sync"
142+
}
143+
144144
// Sync begins syncing the target atomic root with the configured number of worker goroutines.
145-
func (s *syncer) Sync(ctx context.Context) error {
145+
func (s *Syncer) Sync(ctx context.Context) error {
146146
return s.syncer.Sync(ctx)
147147
}
148148

149+
// addZeroes returns the big-endian representation of `height`, prefixed with [common.HashLength] zeroes.
150+
func addZeroes(height uint64) []byte {
151+
// Key format is [height(8 bytes)][blockchainID(32 bytes)]. Start should be the
152+
// smallest key for the given height, i.e., height followed by zeroed blockchainID.
153+
b := make([]byte, wrappers.LongLen+common.HashLength)
154+
binary.BigEndian.PutUint64(b[:wrappers.LongLen], height)
155+
return b
156+
}
157+
149158
// onLeafs is the callback for the leaf syncer, which will insert the key-value pairs into the trie.
150-
func (s *syncer) onLeafs(keys [][]byte, values [][]byte) error {
159+
func (s *Syncer) onLeafs(keys [][]byte, values [][]byte) error {
151160
for i, key := range keys {
152161
if len(key) != atomicstate.TrieKeyLength {
153162
return fmt.Errorf("unexpected key len (%d) in atomic trie sync", len(key))
@@ -195,7 +204,7 @@ func (s *syncer) onLeafs(keys [][]byte, values [][]byte) error {
195204

196205
// onFinish is called when sync for this trie is complete.
197206
// commit the trie to disk and perform the final checks that we synced the target root correctly.
198-
func (s *syncer) onFinish() error {
207+
func (s *Syncer) onFinish() error {
199208
// commit the trie on finish
200209
root, nodes, err := s.trie.Commit(false)
201210
if err != nil {
@@ -220,7 +229,7 @@ func (s *syncer) onFinish() error {
220229
}
221230

222231
type syncerLeafTask struct {
223-
syncer *syncer
232+
syncer *Syncer
224233
}
225234

226235
func (a *syncerLeafTask) Start() []byte { return addZeroes(a.syncer.lastHeight + 1) }

0 commit comments

Comments
 (0)