|
|
@@ -1,9 +1,12 @@
|
|
|
package trie
|
|
|
|
|
|
import (
|
|
|
+ "bytes"
|
|
|
+ "math/big"
|
|
|
"testing"
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
+ "github.com/ethereum/go-ethereum/crypto"
|
|
|
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
|
|
)
|
|
|
|
|
|
@@ -119,3 +122,51 @@ func TestUpdateVariableKeys(t *testing.T) {
|
|
|
t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// TestStacktrieNotModifyValues checks that inserting blobs of data into the
|
|
|
+// stacktrie does not mutate the blobs
|
|
|
+func TestStacktrieNotModifyValues(t *testing.T) {
|
|
|
+ st := NewStackTrie(nil)
|
|
|
+ { // Test a very small trie
|
|
|
+ // Give it the value as a slice with large backing alloc,
|
|
|
+ // so if the stacktrie tries to append, it won't have to realloc
|
|
|
+ value := make([]byte, 1, 100)
|
|
|
+ value[0] = 0x2
|
|
|
+ want := common.CopyBytes(value)
|
|
|
+ st.TryUpdate([]byte{0x01}, value)
|
|
|
+ st.Hash()
|
|
|
+ if have := value; !bytes.Equal(have, want) {
|
|
|
+ t.Fatalf("tiny trie: have %#x want %#x", have, want)
|
|
|
+ }
|
|
|
+ st = NewStackTrie(nil)
|
|
|
+ }
|
|
|
+ // Test with a larger trie
|
|
|
+ keyB := big.NewInt(1)
|
|
|
+ keyDelta := big.NewInt(1)
|
|
|
+ var vals [][]byte
|
|
|
+ getValue := func(i int) []byte {
|
|
|
+ if i%2 == 0 { // large
|
|
|
+ return crypto.Keccak256(big.NewInt(int64(i)).Bytes())
|
|
|
+ } else { //small
|
|
|
+ return big.NewInt(int64(i)).Bytes()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 0; i < 1000; i++ {
|
|
|
+ key := common.BigToHash(keyB)
|
|
|
+ value := getValue(i)
|
|
|
+ st.TryUpdate(key.Bytes(), value)
|
|
|
+ vals = append(vals, value)
|
|
|
+ keyB = keyB.Add(keyB, keyDelta)
|
|
|
+ keyDelta.Add(keyDelta, common.Big1)
|
|
|
+ }
|
|
|
+ st.Hash()
|
|
|
+ for i := 0; i < 1000; i++ {
|
|
|
+ want := getValue(i)
|
|
|
+
|
|
|
+ have := vals[i]
|
|
|
+ if !bytes.Equal(have, want) {
|
|
|
+ t.Fatalf("item %d, have %#x want %#x", i, have, want)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|