@@ -27,11 +27,14 @@ import (
27
27
"testing"
28
28
"time"
29
29
30
+ mrand "math/rand"
31
+
30
32
"github.com/ethereum/go-ethereum/common"
31
33
"github.com/ethereum/go-ethereum/core/rawdb"
32
34
"github.com/ethereum/go-ethereum/core/types"
33
35
"github.com/ethereum/go-ethereum/crypto"
34
36
"github.com/ethereum/go-ethereum/ethdb"
37
+ "github.com/ethereum/go-ethereum/internal/testrand"
35
38
"github.com/ethereum/go-ethereum/light"
36
39
"github.com/ethereum/go-ethereum/log"
37
40
"github.com/ethereum/go-ethereum/rlp"
@@ -729,7 +732,7 @@ func TestSyncWithStorage(t *testing.T) {
729
732
})
730
733
}
731
734
)
732
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (3 , 3000 , true , false )
735
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (3 , 3000 , true , false , false )
733
736
734
737
mkSource := func (name string ) * testPeer {
735
738
source := newTestPeer (name , t , term )
@@ -761,7 +764,7 @@ func TestMultiSyncManyUseless(t *testing.T) {
761
764
})
762
765
}
763
766
)
764
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false )
767
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false , false )
765
768
766
769
mkSource := func (name string , noAccount , noStorage , noTrieNode bool ) * testPeer {
767
770
source := newTestPeer (name , t , term )
@@ -807,7 +810,7 @@ func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) {
807
810
})
808
811
}
809
812
)
810
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false )
813
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false , false )
811
814
812
815
mkSource := func (name string , noAccount , noStorage , noTrieNode bool ) * testPeer {
813
816
source := newTestPeer (name , t , term )
@@ -858,7 +861,7 @@ func TestMultiSyncManyUnresponsive(t *testing.T) {
858
861
})
859
862
}
860
863
)
861
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false )
864
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false , false )
862
865
863
866
mkSource := func (name string , noAccount , noStorage , noTrieNode bool ) * testPeer {
864
867
source := newTestPeer (name , t , term )
@@ -1125,7 +1128,7 @@ func TestSyncBoundaryStorageTrie(t *testing.T) {
1125
1128
})
1126
1129
}
1127
1130
)
1128
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (10 , 1000 , false , true )
1131
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (10 , 1000 , false , true , false )
1129
1132
1130
1133
mkSource := func (name string ) * testPeer {
1131
1134
source := newTestPeer (name , t , term )
@@ -1161,7 +1164,7 @@ func TestSyncWithStorageAndOneCappedPeer(t *testing.T) {
1161
1164
})
1162
1165
}
1163
1166
)
1164
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (300 , 1000 , false , false )
1167
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (300 , 1000 , false , false , false )
1165
1168
1166
1169
mkSource := func (name string , slow bool ) * testPeer {
1167
1170
source := newTestPeer (name , t , term )
@@ -1202,7 +1205,7 @@ func TestSyncWithStorageAndCorruptPeer(t *testing.T) {
1202
1205
})
1203
1206
}
1204
1207
)
1205
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false )
1208
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false , false )
1206
1209
1207
1210
mkSource := func (name string , handler storageHandlerFunc ) * testPeer {
1208
1211
source := newTestPeer (name , t , term )
@@ -1240,7 +1243,7 @@ func TestSyncWithStorageAndNonProvingPeer(t *testing.T) {
1240
1243
})
1241
1244
}
1242
1245
)
1243
- sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false )
1246
+ sourceAccountTrie , elems , storageTries , storageElems := makeAccountTrieWithStorage (100 , 3000 , true , false , false )
1244
1247
1245
1248
mkSource := func (name string , handler storageHandlerFunc ) * testPeer {
1246
1249
source := newTestPeer (name , t , term )
@@ -1298,6 +1301,37 @@ func TestSyncWithStorageMisbehavingProve(t *testing.T) {
1298
1301
verifyTrie (syncer .db , sourceAccountTrie .Hash (), t )
1299
1302
}
1300
1303
1304
+ func TestSyncWithUnevenStorage (t * testing.T ) {
1305
+ t .Parallel ()
1306
+ var (
1307
+ once sync.Once
1308
+ cancel = make (chan struct {})
1309
+ term = func () {
1310
+ once .Do (func () {
1311
+ close (cancel )
1312
+ })
1313
+ }
1314
+ )
1315
+
1316
+ accountTrie , accounts , storageTries , storageElems := makeAccountTrieWithStorage (3 , 256 , false , false , true )
1317
+ mkSource := func (name string ) * testPeer {
1318
+ source := newTestPeer (name , t , term )
1319
+ source .accountTrie = accountTrie
1320
+ source .accountValues = accounts
1321
+ source .storageTries = storageTries
1322
+ source .storageValues = storageElems
1323
+ source .storageRequestHandler = func (t * testPeer , reqId uint64 , root common.Hash , accounts []common.Hash , origin , limit []byte , max uint64 ) error {
1324
+ return defaultStorageRequestHandler (t , reqId , root , accounts , origin , limit , 128 ) // retrieve storage in large mode
1325
+ }
1326
+ return source
1327
+ }
1328
+ syncer := setupSyncer (mkSource ("source" ))
1329
+ if err := syncer .Sync (accountTrie .Hash (), cancel ); err != nil {
1330
+ t .Fatalf ("sync failed: %v" , err )
1331
+ }
1332
+ verifyTrie (syncer .db , accountTrie .Hash (), t )
1333
+ }
1334
+
1301
1335
type kv struct {
1302
1336
k , v []byte
1303
1337
}
@@ -1466,33 +1500,37 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
1466
1500
}
1467
1501
1468
1502
// makeAccountTrieWithStorage spits out a trie, along with the leafs
1469
- func makeAccountTrieWithStorage (accounts , slots int , code , boundary bool ) (* trie.Trie , entrySlice , map [common .Hash ]* trie.Trie , map [common.Hash ]entrySlice ) {
1503
+ func makeAccountTrieWithStorage (accounts , slots int , code , boundary bool , uneven bool ) (* trie.Trie , entrySlice , map [common .Hash ]* trie.Trie , map [common.Hash ]entrySlice ) {
1470
1504
var (
1471
1505
db = trie .NewDatabase (rawdb .NewMemoryDatabase ())
1472
1506
accTrie , _ = trie .New (common.Hash {}, db )
1473
1507
entries entrySlice
1474
1508
storageTries = make (map [common.Hash ]* trie.Trie )
1475
1509
storageEntries = make (map [common.Hash ]entrySlice )
1476
1510
)
1477
- // Make a storage trie which we reuse for the whole lot
1478
- var (
1479
- stTrie * trie.Trie
1480
- stEntries entrySlice
1481
- )
1482
- if boundary {
1483
- stTrie , stEntries = makeBoundaryStorageTrie (slots , db )
1484
- } else {
1485
- stTrie , stEntries = makeStorageTrieWithSeed (uint64 (slots ), 0 , db )
1486
- }
1487
- stRoot := stTrie .Hash ()
1488
1511
1489
1512
// Create n accounts in the trie
1490
1513
for i := uint64 (1 ); i <= uint64 (accounts ); i ++ {
1514
+ var (
1515
+ stTrie * trie.Trie
1516
+ stEntries entrySlice
1517
+ )
1518
+
1491
1519
key := key32 (i )
1492
1520
codehash := emptyCode [:]
1493
1521
if code {
1494
1522
codehash = getCodeHash (i )
1495
1523
}
1524
+
1525
+ if boundary {
1526
+ stTrie , stEntries = makeBoundaryStorageTrie (slots , db )
1527
+ } else if uneven {
1528
+ stTrie , stEntries = makeUnevenStorageTrie (slots , db )
1529
+ } else {
1530
+ stTrie , stEntries = makeStorageTrieWithSeed (uint64 (slots ), 0 , db )
1531
+ }
1532
+ stRoot := stTrie .Hash ()
1533
+
1496
1534
value , _ := rlp .EncodeToBytes (types.StateAccount {
1497
1535
Nonce : i ,
1498
1536
Balance : big .NewInt (int64 (i )),
@@ -1507,8 +1545,8 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie
1507
1545
storageEntries [common .BytesToHash (key )] = stEntries
1508
1546
}
1509
1547
sort .Sort (entries )
1510
- stTrie .Commit (nil )
1511
1548
accTrie .Commit (nil )
1549
+
1512
1550
return accTrie , entries , storageTries , storageEntries
1513
1551
}
1514
1552
@@ -1586,6 +1624,39 @@ func makeBoundaryStorageTrie(n int, db *trie.Database) (*trie.Trie, entrySlice)
1586
1624
return trie , entries
1587
1625
}
1588
1626
1627
+ // makeUnevenStorageTrie constructs a storage tries will states distributed in
1628
+ // different range unevenly.
1629
+ func makeUnevenStorageTrie (slots int , db * trie.Database ) (* trie.Trie , []* kv ) {
1630
+ var (
1631
+ entries entrySlice
1632
+ // tr, _ = trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db)
1633
+ tr , _ = trie .New (common.Hash {}, db )
1634
+ chosen = make (map [byte ]struct {})
1635
+ )
1636
+ for i := 0 ; i < 3 ; i ++ {
1637
+ var n int
1638
+ for {
1639
+ n = mrand .Intn (15 ) // the last range is set empty deliberately
1640
+ if _ , ok := chosen [byte (n )]; ok {
1641
+ continue
1642
+ }
1643
+ chosen [byte (n )] = struct {}{}
1644
+ break
1645
+ }
1646
+ for j := 0 ; j < slots / 3 ; j ++ {
1647
+ key := append ([]byte {byte (n )}, testrand .Bytes (31 )... )
1648
+ val , _ := rlp .EncodeToBytes (testrand .Bytes (32 ))
1649
+
1650
+ elem := & kv {key , val }
1651
+ tr .Update (elem .k , elem .v )
1652
+ entries = append (entries , elem )
1653
+ }
1654
+ }
1655
+ sort .Sort (entries )
1656
+ tr .Commit (nil )
1657
+ return tr , entries
1658
+ }
1659
+
1589
1660
func verifyTrie (db ethdb.KeyValueStore , root common.Hash , t * testing.T ) {
1590
1661
t .Helper ()
1591
1662
triedb := trie .NewDatabase (db )
0 commit comments