|
|
|
@ -18,6 +18,8 @@ package trie |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"runtime" |
|
|
|
|
"sync" |
|
|
|
|
"testing" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
@ -31,6 +33,37 @@ func newEmptySecure() *SecureTrie { |
|
|
|
|
return trie |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// makeTestSecureTrie creates a large enough secure trie for testing.
|
|
|
|
|
func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) { |
|
|
|
|
// Create an empty trie
|
|
|
|
|
db, _ := ethdb.NewMemDatabase() |
|
|
|
|
trie, _ := NewSecure(common.Hash{}, db) |
|
|
|
|
|
|
|
|
|
// Fill it with some arbitrary data
|
|
|
|
|
content := make(map[string][]byte) |
|
|
|
|
for i := byte(0); i < 255; i++ { |
|
|
|
|
// Map the same data under multiple keys
|
|
|
|
|
key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} |
|
|
|
|
content[string(key)] = val |
|
|
|
|
trie.Update(key, val) |
|
|
|
|
|
|
|
|
|
key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} |
|
|
|
|
content[string(key)] = val |
|
|
|
|
trie.Update(key, val) |
|
|
|
|
|
|
|
|
|
// Add some other data to inflate th trie
|
|
|
|
|
for j := byte(3); j < 13; j++ { |
|
|
|
|
key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} |
|
|
|
|
content[string(key)] = val |
|
|
|
|
trie.Update(key, val) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
trie.Commit() |
|
|
|
|
|
|
|
|
|
// Return the generated trie
|
|
|
|
|
return db, trie, content |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestSecureDelete(t *testing.T) { |
|
|
|
|
trie := newEmptySecure() |
|
|
|
|
vals := []struct{ k, v string }{ |
|
|
|
@ -72,3 +105,41 @@ func TestSecureGetKey(t *testing.T) { |
|
|
|
|
t.Errorf("GetKey returned %q, want %q", k, key) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestSecureTrieConcurrency(t *testing.T) { |
|
|
|
|
// Create an initial trie and copy if for concurrent access
|
|
|
|
|
_, trie, _ := makeTestSecureTrie() |
|
|
|
|
|
|
|
|
|
threads := runtime.NumCPU() |
|
|
|
|
tries := make([]*SecureTrie, threads) |
|
|
|
|
for i := 0; i < threads; i++ { |
|
|
|
|
cpy := *trie |
|
|
|
|
tries[i] = &cpy |
|
|
|
|
} |
|
|
|
|
// Start a batch of goroutines interactng with the trie
|
|
|
|
|
pend := new(sync.WaitGroup) |
|
|
|
|
pend.Add(threads) |
|
|
|
|
for i := 0; i < threads; i++ { |
|
|
|
|
go func(index int) { |
|
|
|
|
defer pend.Done() |
|
|
|
|
|
|
|
|
|
for j := byte(0); j < 255; j++ { |
|
|
|
|
// Map the same data under multiple keys
|
|
|
|
|
key, val := common.LeftPadBytes([]byte{byte(index), 1, j}, 32), []byte{j} |
|
|
|
|
tries[index].Update(key, val) |
|
|
|
|
|
|
|
|
|
key, val = common.LeftPadBytes([]byte{byte(index), 2, j}, 32), []byte{j} |
|
|
|
|
tries[index].Update(key, val) |
|
|
|
|
|
|
|
|
|
// Add some other data to inflate the trie
|
|
|
|
|
for k := byte(3); k < 13; k++ { |
|
|
|
|
key, val = common.LeftPadBytes([]byte{byte(index), k, j}, 32), []byte{k, j} |
|
|
|
|
tries[index].Update(key, val) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
tries[index].Commit() |
|
|
|
|
}(i) |
|
|
|
|
} |
|
|
|
|
// Wait for all threads to finish
|
|
|
|
|
pend.Wait() |
|
|
|
|
} |
|
|
|
|