@@ -18,6 +18,8 @@ package trie
18
18
19
19
import (
20
20
"bytes"
21
+ "runtime"
22
+ "sync"
21
23
"testing"
22
24
23
25
"github.com/ethereum/go-ethereum/common"
@@ -31,6 +33,37 @@ func newEmptySecure() *SecureTrie {
31
33
return trie
32
34
}
33
35
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
+
34
67
func TestSecureDelete (t * testing.T ) {
35
68
trie := newEmptySecure ()
36
69
vals := []struct { k , v string }{
@@ -72,3 +105,41 @@ func TestSecureGetKey(t *testing.T) {
72
105
t .Errorf ("GetKey returned %q, want %q" , k , key )
73
106
}
74
107
}
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