@@ -18,6 +18,8 @@ package trie
1818
1919import (
2020 "bytes"
21+ "runtime"
22+ "sync"
2123 "testing"
2224
2325 "github.com/ethereum/go-ethereum/common"
@@ -31,6 +33,37 @@ func newEmptySecure() *SecureTrie {
3133 return trie
3234}
3335
36+ // makeTestSecureTrie creates a large enough secure trie for testing.
37+ func makeTestSecureTrie () (ethdb.Database , * SecureTrie , map [string ][]byte ) {
38+ // Create an empty trie
39+ db , _ := ethdb .NewMemDatabase ()
40+ trie , _ := NewSecure (common.Hash {}, db )
41+
42+ // Fill it with some arbitrary data
43+ content := make (map [string ][]byte )
44+ for i := byte (0 ); i < 255 ; i ++ {
45+ // Map the same data under multiple keys
46+ key , val := common .LeftPadBytes ([]byte {1 , i }, 32 ), []byte {i }
47+ content [string (key )] = val
48+ trie .Update (key , val )
49+
50+ key , val = common .LeftPadBytes ([]byte {2 , i }, 32 ), []byte {i }
51+ content [string (key )] = val
52+ trie .Update (key , val )
53+
54+ // Add some other data to inflate th trie
55+ for j := byte (3 ); j < 13 ; j ++ {
56+ key , val = common .LeftPadBytes ([]byte {j , i }, 32 ), []byte {j , i }
57+ content [string (key )] = val
58+ trie .Update (key , val )
59+ }
60+ }
61+ trie .Commit ()
62+
63+ // Return the generated trie
64+ return db , trie , content
65+ }
66+
3467func TestSecureDelete (t * testing.T ) {
3568 trie := newEmptySecure ()
3669 vals := []struct { k , v string }{
@@ -72,3 +105,41 @@ func TestSecureGetKey(t *testing.T) {
72105 t .Errorf ("GetKey returned %q, want %q" , k , key )
73106 }
74107}
108+
109+ func TestSecureTrieConcurrency (t * testing.T ) {
110+ // Create an initial trie and copy if for concurrent access
111+ _ , trie , _ := makeTestSecureTrie ()
112+
113+ threads := runtime .NumCPU ()
114+ tries := make ([]* SecureTrie , threads )
115+ for i := 0 ; i < threads ; i ++ {
116+ cpy := * trie
117+ tries [i ] = & cpy
118+ }
119+ // Start a batch of goroutines interactng with the trie
120+ pend := new (sync.WaitGroup )
121+ pend .Add (threads )
122+ for i := 0 ; i < threads ; i ++ {
123+ go func (index int ) {
124+ defer pend .Done ()
125+
126+ for j := byte (0 ); j < 255 ; j ++ {
127+ // Map the same data under multiple keys
128+ key , val := common .LeftPadBytes ([]byte {byte (index ), 1 , j }, 32 ), []byte {j }
129+ tries [index ].Update (key , val )
130+
131+ key , val = common .LeftPadBytes ([]byte {byte (index ), 2 , j }, 32 ), []byte {j }
132+ tries [index ].Update (key , val )
133+
134+ // Add some other data to inflate the trie
135+ for k := byte (3 ); k < 13 ; k ++ {
136+ key , val = common .LeftPadBytes ([]byte {byte (index ), k , j }, 32 ), []byte {k , j }
137+ tries [index ].Update (key , val )
138+ }
139+ }
140+ tries [index ].Commit ()
141+ }(i )
142+ }
143+ // Wait for all threads to finish
144+ pend .Wait ()
145+ }
0 commit comments