Skip to content

Commit eeaf191

Browse files
committed
core, eth, trie: prepare trie sync for path based operation
1 parent 5883afb commit eeaf191

File tree

6 files changed

+480
-105
lines changed

6 files changed

+480
-105
lines changed

core/state/sync_test.go

+103-24
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/ethereum/go-ethereum/crypto"
2727
"github.com/ethereum/go-ethereum/ethdb"
2828
"github.com/ethereum/go-ethereum/ethdb/memorydb"
29+
"github.com/ethereum/go-ethereum/rlp"
2930
"github.com/ethereum/go-ethereum/trie"
3031
)
3132

@@ -44,7 +45,7 @@ func makeTestState() (Database, common.Hash, []*testAccount) {
4445
state, _ := New(common.Hash{}, db, nil)
4546

4647
// Fill it with some arbitrary data
47-
accounts := []*testAccount{}
48+
var accounts []*testAccount
4849
for i := byte(0); i < 96; i++ {
4950
obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
5051
acc := &testAccount{address: common.BytesToAddress([]byte{i})}
@@ -59,6 +60,11 @@ func makeTestState() (Database, common.Hash, []*testAccount) {
5960
obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i})
6061
acc.code = []byte{i, i, i, i, i}
6162
}
63+
if i%5 == 0 {
64+
for j := byte(0); j < 5; j++ {
65+
obj.SetState(db, crypto.Keccak256Hash([]byte{i, i, i, i, i, j, j}), crypto.Keccak256Hash([]byte{i, i, i, i, i, j, j}))
66+
}
67+
}
6268
state.updateStateObject(obj)
6369
accounts = append(accounts, acc)
6470
}
@@ -126,52 +132,109 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error {
126132
// Tests that an empty state is not scheduled for syncing.
127133
func TestEmptyStateSync(t *testing.T) {
128134
empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
129-
if req := NewStateSync(empty, rawdb.NewMemoryDatabase(), trie.NewSyncBloom(1, memorydb.New())).Missing(1); len(req) != 0 {
130-
t.Errorf("content requested for empty state: %v", req)
135+
sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), trie.NewSyncBloom(1, memorydb.New()))
136+
if nodes, paths, codes := sync.Missing(1); len(nodes) != 0 || len(paths) != 0 || len(codes) != 0 {
137+
t.Errorf(" content requested for empty state: %v, %v, %v", nodes, paths, codes)
131138
}
132139
}
133140

134141
// Tests that given a root hash, a state can sync iteratively on a single thread,
135142
// requesting retrieval tasks and returning all of them in one go.
136-
func TestIterativeStateSyncIndividual(t *testing.T) { testIterativeStateSync(t, 1, false) }
137-
func TestIterativeStateSyncBatched(t *testing.T) { testIterativeStateSync(t, 100, false) }
138-
func TestIterativeStateSyncIndividualFromDisk(t *testing.T) { testIterativeStateSync(t, 1, true) }
139-
func TestIterativeStateSyncBatchedFromDisk(t *testing.T) { testIterativeStateSync(t, 100, true) }
143+
func TestIterativeStateSyncIndividual(t *testing.T) {
144+
testIterativeStateSync(t, 1, false, false)
145+
}
146+
func TestIterativeStateSyncBatched(t *testing.T) {
147+
testIterativeStateSync(t, 100, false, false)
148+
}
149+
func TestIterativeStateSyncIndividualFromDisk(t *testing.T) {
150+
testIterativeStateSync(t, 1, true, false)
151+
}
152+
func TestIterativeStateSyncBatchedFromDisk(t *testing.T) {
153+
testIterativeStateSync(t, 100, true, false)
154+
}
155+
func TestIterativeStateSyncIndividualByPath(t *testing.T) {
156+
testIterativeStateSync(t, 1, false, true)
157+
}
158+
func TestIterativeStateSyncBatchedByPath(t *testing.T) {
159+
testIterativeStateSync(t, 100, false, true)
160+
}
140161

141-
func testIterativeStateSync(t *testing.T, count int, commit bool) {
162+
func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
142163
// Create a random state to copy
143164
srcDb, srcRoot, srcAccounts := makeTestState()
144165
if commit {
145166
srcDb.TrieDB().Commit(srcRoot, false, nil)
146167
}
168+
srcTrie, _ := trie.New(srcRoot, srcDb.TrieDB())
169+
147170
// Create a destination state and sync with the scheduler
148171
dstDb := rawdb.NewMemoryDatabase()
149172
sched := NewStateSync(srcRoot, dstDb, trie.NewSyncBloom(1, dstDb))
150173

151-
queue := append([]common.Hash{}, sched.Missing(count)...)
152-
for len(queue) > 0 {
153-
results := make([]trie.SyncResult, len(queue))
154-
for i, hash := range queue {
174+
nodes, paths, codes := sched.Missing(count)
175+
var (
176+
hashQueue []common.Hash
177+
pathQueue []trie.SyncPath
178+
)
179+
if !bypath {
180+
hashQueue = append(append(hashQueue[:0], nodes...), codes...)
181+
} else {
182+
hashQueue = append(hashQueue[:0], codes...)
183+
pathQueue = append(pathQueue[:0], paths...)
184+
}
185+
for len(hashQueue)+len(pathQueue) > 0 {
186+
results := make([]trie.SyncResult, len(hashQueue)+len(pathQueue))
187+
for i, hash := range hashQueue {
155188
data, err := srcDb.TrieDB().Node(hash)
156189
if err != nil {
157190
data, err = srcDb.ContractCode(common.Hash{}, hash)
158191
}
159192
if err != nil {
160-
t.Fatalf("failed to retrieve node data for %x", hash)
193+
t.Fatalf("failed to retrieve node data for hash %x", hash)
161194
}
162195
results[i] = trie.SyncResult{Hash: hash, Data: data}
163196
}
197+
for i, path := range pathQueue {
198+
if len(path) == 1 {
199+
data, _, err := srcTrie.TryGetNode(path[0])
200+
if err != nil {
201+
t.Fatalf("failed to retrieve node data for path %x: %v", path, err)
202+
}
203+
results[len(hashQueue)+i] = trie.SyncResult{Hash: crypto.Keccak256Hash(data), Data: data}
204+
} else {
205+
var acc Account
206+
if err := rlp.DecodeBytes(srcTrie.Get(path[0]), &acc); err != nil {
207+
t.Fatalf("failed to decode account on path %x: %v", path, err)
208+
}
209+
stTrie, err := trie.New(acc.Root, srcDb.TrieDB())
210+
if err != nil {
211+
t.Fatalf("failed to retriev storage trie for path %x: %v", path, err)
212+
}
213+
data, _, err := stTrie.TryGetNode(path[1])
214+
if err != nil {
215+
t.Fatalf("failed to retrieve node data for path %x: %v", path, err)
216+
}
217+
results[len(hashQueue)+i] = trie.SyncResult{Hash: crypto.Keccak256Hash(data), Data: data}
218+
}
219+
}
164220
for _, result := range results {
165221
if err := sched.Process(result); err != nil {
166-
t.Fatalf("failed to process result %v", err)
222+
t.Errorf("failed to process result %v", err)
167223
}
168224
}
169225
batch := dstDb.NewBatch()
170226
if err := sched.Commit(batch); err != nil {
171227
t.Fatalf("failed to commit data: %v", err)
172228
}
173229
batch.Write()
174-
queue = append(queue[:0], sched.Missing(count)...)
230+
231+
nodes, paths, codes = sched.Missing(count)
232+
if !bypath {
233+
hashQueue = append(append(hashQueue[:0], nodes...), codes...)
234+
} else {
235+
hashQueue = append(hashQueue[:0], codes...)
236+
pathQueue = append(pathQueue[:0], paths...)
237+
}
175238
}
176239
// Cross check that the two states are in sync
177240
checkStateAccounts(t, dstDb, srcRoot, srcAccounts)
@@ -187,7 +250,9 @@ func TestIterativeDelayedStateSync(t *testing.T) {
187250
dstDb := rawdb.NewMemoryDatabase()
188251
sched := NewStateSync(srcRoot, dstDb, trie.NewSyncBloom(1, dstDb))
189252

190-
queue := append([]common.Hash{}, sched.Missing(0)...)
253+
nodes, _, codes := sched.Missing(0)
254+
queue := append(append([]common.Hash{}, nodes...), codes...)
255+
191256
for len(queue) > 0 {
192257
// Sync only half of the scheduled nodes
193258
results := make([]trie.SyncResult, len(queue)/2+1)
@@ -211,7 +276,9 @@ func TestIterativeDelayedStateSync(t *testing.T) {
211276
t.Fatalf("failed to commit data: %v", err)
212277
}
213278
batch.Write()
214-
queue = append(queue[len(results):], sched.Missing(0)...)
279+
280+
nodes, _, codes = sched.Missing(0)
281+
queue = append(append(queue[len(results):], nodes...), codes...)
215282
}
216283
// Cross check that the two states are in sync
217284
checkStateAccounts(t, dstDb, srcRoot, srcAccounts)
@@ -232,7 +299,8 @@ func testIterativeRandomStateSync(t *testing.T, count int) {
232299
sched := NewStateSync(srcRoot, dstDb, trie.NewSyncBloom(1, dstDb))
233300

234301
queue := make(map[common.Hash]struct{})
235-
for _, hash := range sched.Missing(count) {
302+
nodes, _, codes := sched.Missing(count)
303+
for _, hash := range append(nodes, codes...) {
236304
queue[hash] = struct{}{}
237305
}
238306
for len(queue) > 0 {
@@ -259,8 +327,10 @@ func testIterativeRandomStateSync(t *testing.T, count int) {
259327
t.Fatalf("failed to commit data: %v", err)
260328
}
261329
batch.Write()
330+
262331
queue = make(map[common.Hash]struct{})
263-
for _, hash := range sched.Missing(count) {
332+
nodes, _, codes = sched.Missing(count)
333+
for _, hash := range append(nodes, codes...) {
264334
queue[hash] = struct{}{}
265335
}
266336
}
@@ -279,7 +349,8 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
279349
sched := NewStateSync(srcRoot, dstDb, trie.NewSyncBloom(1, dstDb))
280350

281351
queue := make(map[common.Hash]struct{})
282-
for _, hash := range sched.Missing(0) {
352+
nodes, _, codes := sched.Missing(0)
353+
for _, hash := range append(nodes, codes...) {
283354
queue[hash] = struct{}{}
284355
}
285356
for len(queue) > 0 {
@@ -312,7 +383,11 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
312383
t.Fatalf("failed to commit data: %v", err)
313384
}
314385
batch.Write()
315-
for _, hash := range sched.Missing(0) {
386+
for _, result := range results {
387+
delete(queue, result.Hash)
388+
}
389+
nodes, _, codes = sched.Missing(0)
390+
for _, hash := range append(nodes, codes...) {
316391
queue[hash] = struct{}{}
317392
}
318393
}
@@ -341,8 +416,11 @@ func TestIncompleteStateSync(t *testing.T) {
341416
dstDb := rawdb.NewMemoryDatabase()
342417
sched := NewStateSync(srcRoot, dstDb, trie.NewSyncBloom(1, dstDb))
343418

344-
added := []common.Hash{}
345-
queue := append([]common.Hash{}, sched.Missing(1)...)
419+
var added []common.Hash
420+
421+
nodes, _, codes := sched.Missing(1)
422+
queue := append(append([]common.Hash{}, nodes...), codes...)
423+
346424
for len(queue) > 0 {
347425
// Fetch a batch of state nodes
348426
results := make([]trie.SyncResult, len(queue))
@@ -382,7 +460,8 @@ func TestIncompleteStateSync(t *testing.T) {
382460
}
383461
}
384462
// Fetch the next batch to retrieve
385-
queue = append(queue[:0], sched.Missing(1)...)
463+
nodes, _, codes = sched.Missing(1)
464+
queue = append(append(queue[:0], nodes...), codes...)
386465
}
387466
// Sanity check that removing any node from the database is detected
388467
for _, node := range added[1:] {

0 commit comments

Comments
 (0)