| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-31 14:45:03 +01:00
										 |  |  | package trie | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2014-11-18 19:52:45 +01:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	"encoding/binary" | 
					
						
							| 
									
										
										
										
											2014-05-26 00:09:38 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2014-11-18 19:52:45 +01:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2014-11-15 20:21:55 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	"github.com/davecgh/go-spew/spew" | 
					
						
							| 
									
										
										
										
											2015-03-16 11:27:38 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func init() { | 
					
						
							|  |  |  | 	spew.Config.Indent = "    " | 
					
						
							|  |  |  | 	spew.Config.DisableMethods = true | 
					
						
							| 
									
										
										
										
											2014-02-15 13:21:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | // Used for testing | 
					
						
							|  |  |  | func newEmpty() *Trie { | 
					
						
							|  |  |  | 	db, _ := ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 	trie, _ := New(common.Hash{}, db) | 
					
						
							|  |  |  | 	return trie | 
					
						
							| 
									
										
										
										
											2015-03-03 12:15:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestEmptyTrie(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	var trie Trie | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	res := trie.Hash() | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	exp := emptyRoot | 
					
						
							|  |  |  | 	if res != common.Hash(exp) { | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		t.Errorf("expected %x got %x", exp, res) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-15 13:21:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-19 10:57:02 +01:00
										 |  |  | func TestNull(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	var trie Trie | 
					
						
							| 
									
										
										
										
											2015-03-19 10:57:02 +01:00
										 |  |  | 	key := make([]byte, 32) | 
					
						
							|  |  |  | 	value := common.FromHex("0x823140710bf13990e4500136726d8b55") | 
					
						
							|  |  |  | 	trie.Update(key, value) | 
					
						
							|  |  |  | 	value = trie.Get(key) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func TestMissingRoot(t *testing.T) { | 
					
						
							|  |  |  | 	db, _ := ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 	trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), db) | 
					
						
							|  |  |  | 	if trie != nil { | 
					
						
							|  |  |  | 		t.Error("New returned non-nil trie for invalid root") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err != ErrMissingRoot { | 
					
						
							|  |  |  | 		t.Error("New returned wrong error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestInsert(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2014-02-15 13:21:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	updateString(trie, "doe", "reindeer") | 
					
						
							|  |  |  | 	updateString(trie, "dog", "puppy") | 
					
						
							|  |  |  | 	updateString(trie, "dogglesworth", "cat") | 
					
						
							| 
									
										
										
										
											2014-02-15 13:21:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	root := trie.Hash() | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	if root != exp { | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		t.Errorf("exp %x got %x", exp, root) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-20 14:40:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie = newEmpty() | 
					
						
							|  |  |  | 	updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") | 
					
						
							| 
									
										
										
										
											2014-02-20 14:40:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") | 
					
						
							|  |  |  | 	root, err := trie.Commit() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("commit error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if root != exp { | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		t.Errorf("exp %x got %x", exp, root) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-20 14:40:00 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-24 12:11:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestGet(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							|  |  |  | 	updateString(trie, "doe", "reindeer") | 
					
						
							|  |  |  | 	updateString(trie, "dog", "puppy") | 
					
						
							|  |  |  | 	updateString(trie, "dogglesworth", "cat") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < 2; i++ { | 
					
						
							|  |  |  | 		res := getString(trie, "dog") | 
					
						
							|  |  |  | 		if !bytes.Equal(res, []byte("puppy")) { | 
					
						
							|  |  |  | 			t.Errorf("expected puppy got %x", res) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-05-26 00:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		unknown := getString(trie, "unknown") | 
					
						
							|  |  |  | 		if unknown != nil { | 
					
						
							|  |  |  | 			t.Errorf("expected nil got %x", unknown) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-30 13:08:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		if i == 1 { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		trie.Commit() | 
					
						
							| 
									
										
										
										
											2014-06-17 18:05:46 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-30 13:08:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestDelete(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							| 
									
										
										
										
											2014-06-17 18:05:46 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	for _, val := range vals { | 
					
						
							|  |  |  | 		if val.v != "" { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 			updateString(trie, val.k, val.v) | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 			deleteString(trie, val.k) | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-30 13:08:00 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	hash := trie.Hash() | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") | 
					
						
							|  |  |  | 	if hash != exp { | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		t.Errorf("expected %x got %x", exp, hash) | 
					
						
							| 
									
										
										
										
											2014-06-30 13:08:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-05-27 01:08:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestEmptyValues(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2014-06-30 13:08:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							| 
									
										
										
										
											2014-06-30 13:08:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	for _, val := range vals { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		updateString(trie, val.k, val.v) | 
					
						
							| 
									
										
										
										
											2014-07-01 09:55:20 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	hash := trie.Hash() | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") | 
					
						
							|  |  |  | 	if hash != exp { | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		t.Errorf("expected %x got %x", exp, hash) | 
					
						
							| 
									
										
										
										
											2014-06-17 18:05:46 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-07-01 09:55:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestReplication(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							| 
									
										
										
										
											2014-06-17 18:05:46 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	for _, val := range vals { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		updateString(trie, val.k, val.v) | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	exp, err := trie.Commit() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("commit error: %v", err) | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-07-15 15:29:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	// create a new trie on top of the database and check that lookups work. | 
					
						
							|  |  |  | 	trie2, err := New(exp, trie.db) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("can't recreate trie at %x: %v", exp, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, kv := range vals { | 
					
						
							|  |  |  | 		if string(getString(trie2, kv.k)) != kv.v { | 
					
						
							|  |  |  | 			t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	hash, err := trie2.Commit() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("commit error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if hash != exp { | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		t.Errorf("root failure. expected %x got %x", exp, hash) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-07-17 11:21:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	// perform some insertions on the new trie. | 
					
						
							|  |  |  | 	vals2 := []struct{ k, v string }{ | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		// {"shaman", "horse"}, | 
					
						
							|  |  |  | 		// {"doge", "coin"}, | 
					
						
							|  |  |  | 		// {"ether", ""}, | 
					
						
							|  |  |  | 		// {"dog", "puppy"}, | 
					
						
							|  |  |  | 		// {"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							|  |  |  | 		// {"shaman", ""}, | 
					
						
							| 
									
										
										
										
											2014-10-10 17:00:06 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	for _, val := range vals2 { | 
					
						
							|  |  |  | 		updateString(trie2, val.k, val.v) | 
					
						
							| 
									
										
										
										
											2014-10-10 17:00:06 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	if trie2.Hash() != exp { | 
					
						
							|  |  |  | 		t.Errorf("root failure. expected %x got %x", exp, hash) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-14 15:19:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func paranoiaCheck(t1 *Trie) (bool, *Trie) { | 
					
						
							|  |  |  | 	t2 := new(Trie) | 
					
						
							|  |  |  | 	it := NewIterator(t1) | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		t2.Update(it.Key, it.Value) | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	return t2.Hash() == t1.Hash(), t2 | 
					
						
							| 
									
										
										
										
											2014-11-12 01:36:36 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | func TestParanoia(t *testing.T) { | 
					
						
							|  |  |  | 	t.Skip() | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2014-11-18 12:03:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							|  |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"ether", ""}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"shaman", ""}, | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 		{"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							| 
									
										
										
										
											2014-11-18 12:03:09 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, val := range vals { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		updateString(trie, val.k, val.v) | 
					
						
							| 
									
										
										
										
											2014-11-18 12:03:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	trie.Commit() | 
					
						
							| 
									
										
										
										
											2014-11-18 12:03:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	ok, t2 := paranoiaCheck(trie) | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		t.Errorf("trie paranoia check failed %x %x", trie.Hash(), t2.Hash()) | 
					
						
							| 
									
										
										
										
											2014-11-18 12:03:09 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | // Not an actual test | 
					
						
							|  |  |  | func TestOutput(t *testing.T) { | 
					
						
							|  |  |  | 	t.Skip() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	base := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	for i := 0; i < 50; i++ { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		updateString(trie, fmt.Sprintf("%s%d", base, i), "valueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println("############################## FULL ################################") | 
					
						
							|  |  |  | 	fmt.Println(trie.root) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	trie.Commit() | 
					
						
							|  |  |  | 	fmt.Println("############################## SMALL ################################") | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie2, _ := New(trie.Hash(), trie.db) | 
					
						
							|  |  |  | 	getString(trie2, base+"20") | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | 	fmt.Println(trie2.root) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func TestLargeValue(t *testing.T) { | 
					
						
							|  |  |  | 	trie := newEmpty() | 
					
						
							|  |  |  | 	trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) | 
					
						
							|  |  |  | 	trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) | 
					
						
							|  |  |  | 	trie.Hash() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-07 17:03:22 +01:00
										 |  |  | type kv struct { | 
					
						
							|  |  |  | 	k, v []byte | 
					
						
							|  |  |  | 	t    bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestLargeData(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2015-02-07 17:03:22 +01:00
										 |  |  | 	vals := make(map[string]*kv) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-05 17:46:00 +01:00
										 |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							| 
									
										
										
										
											2015-03-16 11:27:38 +01:00
										 |  |  | 		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} | 
					
						
							|  |  |  | 		value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} | 
					
						
							| 
									
										
										
										
											2015-02-07 17:03:22 +01:00
										 |  |  | 		trie.Update(value.k, value.v) | 
					
						
							|  |  |  | 		trie.Update(value2.k, value2.v) | 
					
						
							|  |  |  | 		vals[string(value.k)] = value | 
					
						
							|  |  |  | 		vals[string(value2.k)] = value2 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	it := NewIterator(trie) | 
					
						
							| 
									
										
										
										
											2015-02-07 17:03:22 +01:00
										 |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		vals[string(it.Key)].t = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var untouched []*kv | 
					
						
							|  |  |  | 	for _, value := range vals { | 
					
						
							|  |  |  | 		if !value.t { | 
					
						
							|  |  |  | 			untouched = append(untouched, value) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(untouched) > 0 { | 
					
						
							|  |  |  | 		t.Errorf("Missed %d nodes", len(untouched)) | 
					
						
							|  |  |  | 		for _, value := range untouched { | 
					
						
							|  |  |  | 			t.Error(value) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-03 12:15:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | func BenchmarkGet(b *testing.B)      { benchGet(b, false) } | 
					
						
							|  |  |  | func BenchmarkGetDB(b *testing.B)    { benchGet(b, true) } | 
					
						
							|  |  |  | func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } | 
					
						
							|  |  |  | func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } | 
					
						
							|  |  |  | func BenchmarkHashBE(b *testing.B)   { benchHash(b, binary.BigEndian) } | 
					
						
							|  |  |  | func BenchmarkHashLE(b *testing.B)   { benchHash(b, binary.LittleEndian) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const benchElemCount = 20000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func benchGet(b *testing.B, commit bool) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := new(Trie) | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	if commit { | 
					
						
							|  |  |  | 		dir, tmpdb := tempDB() | 
					
						
							|  |  |  | 		defer os.RemoveAll(dir) | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		trie, _ = New(common.Hash{}, tmpdb) | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	k := make([]byte, 32) | 
					
						
							|  |  |  | 	for i := 0; i < benchElemCount; i++ { | 
					
						
							|  |  |  | 		binary.LittleEndian.PutUint64(k, uint64(i)) | 
					
						
							|  |  |  | 		trie.Update(k, k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	binary.LittleEndian.PutUint64(k, benchElemCount/2) | 
					
						
							|  |  |  | 	if commit { | 
					
						
							|  |  |  | 		trie.Commit() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		trie.Get(k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	k := make([]byte, 32) | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		e.PutUint64(k, uint64(i)) | 
					
						
							|  |  |  | 		trie.Update(k, k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return trie | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func benchHash(b *testing.B, e binary.ByteOrder) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	k := make([]byte, 32) | 
					
						
							|  |  |  | 	for i := 0; i < benchElemCount; i++ { | 
					
						
							|  |  |  | 		e.PutUint64(k, uint64(i)) | 
					
						
							|  |  |  | 		trie.Update(k, k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		trie.Hash() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func tempDB() (string, Database) { | 
					
						
							| 
									
										
										
										
											2015-06-30 14:54:37 +02:00
										 |  |  | 	dir, err := ioutil.TempDir("", "trie-bench") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("can't create temporary directory: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	db, err := ethdb.NewLDBDatabase(dir, 300*1024) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("can't create temporary database: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return dir, db | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func getString(trie *Trie, k string) []byte { | 
					
						
							|  |  |  | 	return trie.Get([]byte(k)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func updateString(trie *Trie, k, v string) { | 
					
						
							|  |  |  | 	trie.Update([]byte(k), []byte(v)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func deleteString(trie *Trie, k string) { | 
					
						
							|  |  |  | 	trie.Delete([]byte(k)) | 
					
						
							|  |  |  | } |