| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | package ptrie | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:35:57 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethutil" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | type Db map[string][]byte | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:56:01 +01:00
										 |  |  | func (self Db) Get(k []byte) ([]byte, error) { return self[string(k)], nil } | 
					
						
							|  |  |  | func (self Db) Put(k, v []byte)              { self[string(k)] = v } | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Used for testing | 
					
						
							|  |  |  | func NewEmpty() *Trie { | 
					
						
							|  |  |  | 	return New(nil, make(Db)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:35:57 +01:00
										 |  |  | func TestEmptyTrie(t *testing.T) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 	res := trie.Hash() | 
					
						
							|  |  |  | 	exp := crypto.Sha3(ethutil.Encode("")) | 
					
						
							|  |  |  | 	if !bytes.Equal(res, exp) { | 
					
						
							|  |  |  | 		t.Errorf("expected %x got %x", exp, res) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | func TestInsert(t *testing.T) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	trie.UpdateString("doe", "reindeer") | 
					
						
							|  |  |  | 	trie.UpdateString("dog", "puppy") | 
					
						
							|  |  |  | 	trie.UpdateString("dogglesworth", "cat") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	exp := ethutil.Hex2Bytes("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") | 
					
						
							|  |  |  | 	root := trie.Hash() | 
					
						
							|  |  |  | 	if !bytes.Equal(root, exp) { | 
					
						
							|  |  |  | 		t.Errorf("exp %x got %x", exp, root) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	trie = NewEmpty() | 
					
						
							|  |  |  | 	trie.UpdateString("A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	exp = ethutil.Hex2Bytes("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") | 
					
						
							|  |  |  | 	root = trie.Hash() | 
					
						
							|  |  |  | 	if !bytes.Equal(root, exp) { | 
					
						
							|  |  |  | 		t.Errorf("exp %x got %x", exp, root) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestGet(t *testing.T) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	trie.UpdateString("doe", "reindeer") | 
					
						
							|  |  |  | 	trie.UpdateString("dog", "puppy") | 
					
						
							|  |  |  | 	trie.UpdateString("dogglesworth", "cat") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res := trie.GetString("dog") | 
					
						
							|  |  |  | 	if !bytes.Equal(res, []byte("puppy")) { | 
					
						
							|  |  |  | 		t.Errorf("expected puppy got %x", res) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unknown := trie.GetString("unknown") | 
					
						
							|  |  |  | 	if unknown != nil { | 
					
						
							|  |  |  | 		t.Errorf("expected nil got %x", unknown) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestDelete(t *testing.T) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:35:57 +01:00
										 |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		if val.v != "" { | 
					
						
							|  |  |  | 			trie.UpdateString(val.k, val.v) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			trie.DeleteString(val.k) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hash := trie.Hash() | 
					
						
							|  |  |  | 	exp := ethutil.Hex2Bytes("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") | 
					
						
							|  |  |  | 	if !bytes.Equal(hash, exp) { | 
					
						
							|  |  |  | 		t.Errorf("expected %x got %x", exp, hash) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestEmptyValues(t *testing.T) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		trie.UpdateString(val.k, val.v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hash := trie.Hash() | 
					
						
							|  |  |  | 	exp := ethutil.Hex2Bytes("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") | 
					
						
							|  |  |  | 	if !bytes.Equal(hash, exp) { | 
					
						
							|  |  |  | 		t.Errorf("expected %x got %x", exp, hash) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestReplication(t *testing.T) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							|  |  |  | 		{"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		trie.UpdateString(val.k, val.v) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-20 18:11:31 +01:00
										 |  |  | 	trie.Commit() | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:56:01 +01:00
										 |  |  | 	trie2 := New(trie.roothash, trie.cache.backend) | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 	if string(trie2.GetString("horse")) != "stallion" { | 
					
						
							|  |  |  | 		t.Error("expected to have harse => stallion") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hash := trie2.Hash() | 
					
						
							|  |  |  | 	exp := trie.Hash() | 
					
						
							|  |  |  | 	if !bytes.Equal(hash, exp) { | 
					
						
							|  |  |  | 		t.Errorf("root failure. expected %x got %x", exp, hash) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | func TestReset(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		trie.UpdateString(val.k, val.v) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | 	trie.Commit() | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | 	before := ethutil.CopyBytes(trie.roothash) | 
					
						
							|  |  |  | 	trie.UpdateString("should", "revert") | 
					
						
							|  |  |  | 	trie.Hash() | 
					
						
							|  |  |  | 	// Should have no effect | 
					
						
							|  |  |  | 	trie.Hash() | 
					
						
							|  |  |  | 	trie.Hash() | 
					
						
							|  |  |  | 	// ### | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | 	trie.Reset() | 
					
						
							|  |  |  | 	after := ethutil.CopyBytes(trie.roothash) | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | 	if !bytes.Equal(before, after) { | 
					
						
							|  |  |  | 		t.Errorf("expected roots to be equal. %x - %x", before, after) | 
					
						
							| 
									
										
										
										
											2014-11-18 12:02:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-18 12:18:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:56:01 +01:00
										 |  |  | func TestParanoia(t *testing.T) { | 
					
						
							|  |  |  | 	t.Skip() | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							|  |  |  | 		{"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		trie.UpdateString(val.k, val.v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	trie.Commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ok, t2 := ParanoiaCheck(trie, trie.cache.backend) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		t.Errorf("trie paranoia check failed %x %x", trie.roothash, t2.roothash) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 16:35:57 +01:00
										 |  |  | // Not an actual test | 
					
						
							| 
									
										
										
										
											2014-11-18 12:18:27 +01:00
										 |  |  | func TestOutput(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	t.Skip() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 12:18:27 +01:00
										 |  |  | 	base := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 	for i := 0; i < 50; i++ { | 
					
						
							|  |  |  | 		trie.UpdateString(fmt.Sprintf("%s%d", base, i), "valueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println("############################## FULL ################################") | 
					
						
							|  |  |  | 	fmt.Println(trie.root) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 10:48:07 -05:00
										 |  |  | 	trie.Commit() | 
					
						
							|  |  |  | 	fmt.Println("############################## SMALL ################################") | 
					
						
							| 
									
										
										
										
											2014-11-19 16:56:01 +01:00
										 |  |  | 	trie2 := New(trie.roothash, trie.cache.backend) | 
					
						
							| 
									
										
										
										
											2014-11-18 12:18:27 +01:00
										 |  |  | 	trie2.GetString(base + "20") | 
					
						
							|  |  |  | 	fmt.Println(trie2.root) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-19 16:21:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkGets(b *testing.B) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							|  |  |  | 		{"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		trie.UpdateString(val.k, val.v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		trie.Get([]byte("horse")) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkUpdate(b *testing.B) { | 
					
						
							|  |  |  | 	trie := NewEmpty() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		trie.UpdateString(fmt.Sprintf("aaaaaaaaa%d", i), "value") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	trie.Hash() | 
					
						
							|  |  |  | } |