@@ -26,6 +26,7 @@ import (
26
26
"github.com/ethereum/go-ethereum/crypto"
27
27
"github.com/ethereum/go-ethereum/ethdb"
28
28
"github.com/ethereum/go-ethereum/ethdb/memorydb"
29
+ "github.com/ethereum/go-ethereum/rlp"
29
30
"github.com/ethereum/go-ethereum/trie"
30
31
)
31
32
@@ -44,7 +45,7 @@ func makeTestState() (Database, common.Hash, []*testAccount) {
44
45
state , _ := New (common.Hash {}, db , nil )
45
46
46
47
// Fill it with some arbitrary data
47
- accounts := []* testAccount {}
48
+ var accounts []* testAccount
48
49
for i := byte (0 ); i < 96 ; i ++ {
49
50
obj := state .GetOrNewStateObject (common .BytesToAddress ([]byte {i }))
50
51
acc := & testAccount {address : common .BytesToAddress ([]byte {i })}
@@ -59,6 +60,11 @@ func makeTestState() (Database, common.Hash, []*testAccount) {
59
60
obj .SetCode (crypto .Keccak256Hash ([]byte {i , i , i , i , i }), []byte {i , i , i , i , i })
60
61
acc .code = []byte {i , i , i , i , i }
61
62
}
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
+ }
62
68
state .updateStateObject (obj )
63
69
accounts = append (accounts , acc )
64
70
}
@@ -126,52 +132,109 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error {
126
132
// Tests that an empty state is not scheduled for syncing.
127
133
func TestEmptyStateSync (t * testing.T ) {
128
134
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 )
131
138
}
132
139
}
133
140
134
141
// Tests that given a root hash, a state can sync iteratively on a single thread,
135
142
// 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
+ }
140
161
141
- func testIterativeStateSync (t * testing.T , count int , commit bool ) {
162
+ func testIterativeStateSync (t * testing.T , count int , commit bool , bypath bool ) {
142
163
// Create a random state to copy
143
164
srcDb , srcRoot , srcAccounts := makeTestState ()
144
165
if commit {
145
166
srcDb .TrieDB ().Commit (srcRoot , false , nil )
146
167
}
168
+ srcTrie , _ := trie .New (srcRoot , srcDb .TrieDB ())
169
+
147
170
// Create a destination state and sync with the scheduler
148
171
dstDb := rawdb .NewMemoryDatabase ()
149
172
sched := NewStateSync (srcRoot , dstDb , trie .NewSyncBloom (1 , dstDb ))
150
173
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 {
155
188
data , err := srcDb .TrieDB ().Node (hash )
156
189
if err != nil {
157
190
data , err = srcDb .ContractCode (common.Hash {}, hash )
158
191
}
159
192
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 )
161
194
}
162
195
results [i ] = trie.SyncResult {Hash : hash , Data : data }
163
196
}
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
+ }
164
220
for _ , result := range results {
165
221
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 )
167
223
}
168
224
}
169
225
batch := dstDb .NewBatch ()
170
226
if err := sched .Commit (batch ); err != nil {
171
227
t .Fatalf ("failed to commit data: %v" , err )
172
228
}
173
229
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
+ }
175
238
}
176
239
// Cross check that the two states are in sync
177
240
checkStateAccounts (t , dstDb , srcRoot , srcAccounts )
@@ -187,7 +250,9 @@ func TestIterativeDelayedStateSync(t *testing.T) {
187
250
dstDb := rawdb .NewMemoryDatabase ()
188
251
sched := NewStateSync (srcRoot , dstDb , trie .NewSyncBloom (1 , dstDb ))
189
252
190
- queue := append ([]common.Hash {}, sched .Missing (0 )... )
253
+ nodes , _ , codes := sched .Missing (0 )
254
+ queue := append (append ([]common.Hash {}, nodes ... ), codes ... )
255
+
191
256
for len (queue ) > 0 {
192
257
// Sync only half of the scheduled nodes
193
258
results := make ([]trie.SyncResult , len (queue )/ 2 + 1 )
@@ -211,7 +276,9 @@ func TestIterativeDelayedStateSync(t *testing.T) {
211
276
t .Fatalf ("failed to commit data: %v" , err )
212
277
}
213
278
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 ... )
215
282
}
216
283
// Cross check that the two states are in sync
217
284
checkStateAccounts (t , dstDb , srcRoot , srcAccounts )
@@ -232,7 +299,8 @@ func testIterativeRandomStateSync(t *testing.T, count int) {
232
299
sched := NewStateSync (srcRoot , dstDb , trie .NewSyncBloom (1 , dstDb ))
233
300
234
301
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 ... ) {
236
304
queue [hash ] = struct {}{}
237
305
}
238
306
for len (queue ) > 0 {
@@ -259,8 +327,10 @@ func testIterativeRandomStateSync(t *testing.T, count int) {
259
327
t .Fatalf ("failed to commit data: %v" , err )
260
328
}
261
329
batch .Write ()
330
+
262
331
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 ... ) {
264
334
queue [hash ] = struct {}{}
265
335
}
266
336
}
@@ -279,7 +349,8 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
279
349
sched := NewStateSync (srcRoot , dstDb , trie .NewSyncBloom (1 , dstDb ))
280
350
281
351
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 ... ) {
283
354
queue [hash ] = struct {}{}
284
355
}
285
356
for len (queue ) > 0 {
@@ -312,7 +383,11 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
312
383
t .Fatalf ("failed to commit data: %v" , err )
313
384
}
314
385
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 ... ) {
316
391
queue [hash ] = struct {}{}
317
392
}
318
393
}
@@ -341,8 +416,11 @@ func TestIncompleteStateSync(t *testing.T) {
341
416
dstDb := rawdb .NewMemoryDatabase ()
342
417
sched := NewStateSync (srcRoot , dstDb , trie .NewSyncBloom (1 , dstDb ))
343
418
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
+
346
424
for len (queue ) > 0 {
347
425
// Fetch a batch of state nodes
348
426
results := make ([]trie.SyncResult , len (queue ))
@@ -382,7 +460,8 @@ func TestIncompleteStateSync(t *testing.T) {
382
460
}
383
461
}
384
462
// 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 ... )
386
465
}
387
466
// Sanity check that removing any node from the database is detected
388
467
for _ , node := range added [1 :] {
0 commit comments