| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-08 11:47:04 +01:00
										 |  |  | package trie | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 12:11:56 +02:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2016-01-06 12:11:56 +02:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestIterator(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	trie := newEmpty() | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	vals := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"do", "verb"}, | 
					
						
							|  |  |  | 		{"ether", "wookiedoo"}, | 
					
						
							|  |  |  | 		{"horse", "stallion"}, | 
					
						
							| 
									
										
										
										
											2014-11-20 18:11:31 +01:00
										 |  |  | 		{"shaman", "horse"}, | 
					
						
							|  |  |  | 		{"doge", "coin"}, | 
					
						
							|  |  |  | 		{"dog", "puppy"}, | 
					
						
							|  |  |  | 		{"somethingveryoddindeedthis is", "myothernodedata"}, | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	all := make(map[string]string) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	for _, val := range vals { | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 		all[val.k] = val.v | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 		trie.Update([]byte(val.k), []byte(val.v)) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	trie.Commit(nil) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	found := make(map[string]string) | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	it := NewIterator(trie.NodeIterator(nil)) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	for it.Next() { | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 		found[string(it.Key)] = string(it.Value) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	for k, v := range all { | 
					
						
							|  |  |  | 		if found[k] != v { | 
					
						
							|  |  |  | 			t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kv struct { | 
					
						
							|  |  |  | 	k, v []byte | 
					
						
							|  |  |  | 	t    bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestIteratorLargeData(t *testing.T) { | 
					
						
							|  |  |  | 	trie := newEmpty() | 
					
						
							|  |  |  | 	vals := make(map[string]*kv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							|  |  |  | 		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} | 
					
						
							|  |  |  | 		value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} | 
					
						
							|  |  |  | 		trie.Update(value.k, value.v) | 
					
						
							|  |  |  | 		trie.Update(value2.k, value2.v) | 
					
						
							|  |  |  | 		vals[string(value.k)] = value | 
					
						
							|  |  |  | 		vals[string(value2.k)] = value2 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	it := NewIterator(trie.NodeIterator(nil)) | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02: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) | 
					
						
							| 
									
										
										
										
											2014-11-19 15:05:08 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-06 12:11:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that the node iterator indeed walks over the entire database contents. | 
					
						
							|  |  |  | func TestNodeIteratorCoverage(t *testing.T) { | 
					
						
							|  |  |  | 	// Create some arbitrary test trie to iterate | 
					
						
							|  |  |  | 	db, trie, _ := makeTestTrie() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Gather all the node hashes found by the iterator | 
					
						
							|  |  |  | 	hashes := make(map[common.Hash]struct{}) | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	for it := trie.NodeIterator(nil); it.Next(true); { | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 		if it.Hash() != (common.Hash{}) { | 
					
						
							|  |  |  | 			hashes[it.Hash()] = struct{}{} | 
					
						
							| 
									
										
										
										
											2016-01-06 12:11:56 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Cross check the hashes and the database itself | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 	for hash := range hashes { | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		if _, err := db.Node(hash); err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-06 12:11:56 +02:00
										 |  |  | 			t.Errorf("failed to retrieve reported node %x: %v", hash, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	for hash, obj := range db.nodes { | 
					
						
							|  |  |  | 		if obj != nil && hash != (common.Hash{}) { | 
					
						
							|  |  |  | 			if _, ok := hashes[hash]; !ok { | 
					
						
							|  |  |  | 				t.Errorf("state entry not reported %x", hash) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, key := range db.diskdb.(*ethdb.MemDatabase).Keys() { | 
					
						
							| 
									
										
										
										
											2016-01-06 12:11:56 +02:00
										 |  |  | 		if _, ok := hashes[common.BytesToHash(key)]; !ok { | 
					
						
							|  |  |  | 			t.Errorf("state entry not reported %x", key) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | type kvs struct{ k, v string } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var testdata1 = []kvs{ | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 	{"barb", "ba"}, | 
					
						
							|  |  |  | 	{"bard", "bc"}, | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	{"bars", "bb"}, | 
					
						
							|  |  |  | 	{"bar", "b"}, | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 	{"fab", "z"}, | 
					
						
							|  |  |  | 	{"food", "ab"}, | 
					
						
							|  |  |  | 	{"foos", "aa"}, | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	{"foo", "a"}, | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | var testdata2 = []kvs{ | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 	{"aardvark", "c"}, | 
					
						
							|  |  |  | 	{"bar", "b"}, | 
					
						
							|  |  |  | 	{"barb", "bd"}, | 
					
						
							|  |  |  | 	{"bars", "be"}, | 
					
						
							|  |  |  | 	{"fab", "z"}, | 
					
						
							|  |  |  | 	{"foo", "a"}, | 
					
						
							|  |  |  | 	{"foos", "aa"}, | 
					
						
							|  |  |  | 	{"food", "ab"}, | 
					
						
							|  |  |  | 	{"jars", "d"}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | func TestIteratorSeek(t *testing.T) { | 
					
						
							|  |  |  | 	trie := newEmpty() | 
					
						
							|  |  |  | 	for _, val := range testdata1 { | 
					
						
							|  |  |  | 		trie.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Seek to the middle. | 
					
						
							|  |  |  | 	it := NewIterator(trie.NodeIterator([]byte("fab"))) | 
					
						
							|  |  |  | 	if err := checkIteratorOrder(testdata1[4:], it); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Seek to a non-existent key. | 
					
						
							|  |  |  | 	it = NewIterator(trie.NodeIterator([]byte("barc"))) | 
					
						
							|  |  |  | 	if err := checkIteratorOrder(testdata1[1:], it); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Seek beyond the end. | 
					
						
							|  |  |  | 	it = NewIterator(trie.NodeIterator([]byte("z"))) | 
					
						
							|  |  |  | 	if err := checkIteratorOrder(nil, it); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func checkIteratorOrder(want []kvs, it *Iterator) error { | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		if len(want) == 0 { | 
					
						
							|  |  |  | 			return fmt.Errorf("didn't expect any more values, got key %q", it.Key) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !bytes.Equal(it.Key, []byte(want[0].k)) { | 
					
						
							|  |  |  | 			return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		want = want[1:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(want) > 0 { | 
					
						
							|  |  |  | 		return fmt.Errorf("iterator ended early, want key %q", want[0]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | func TestDifferenceIterator(t *testing.T) { | 
					
						
							|  |  |  | 	triea := newEmpty() | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 	for _, val := range testdata1 { | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 		triea.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	triea.Commit(nil) | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	trieb := newEmpty() | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 	for _, val := range testdata2 { | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 		trieb.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	trieb.Commit(nil) | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	found := make(map[string]string) | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) | 
					
						
							| 
									
										
										
										
											2017-04-18 13:37:10 +02:00
										 |  |  | 	it := NewIterator(di) | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		found[string(it.Key)] = string(it.Value) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	all := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"aardvark", "c"}, | 
					
						
							|  |  |  | 		{"barb", "bd"}, | 
					
						
							|  |  |  | 		{"bars", "be"}, | 
					
						
							|  |  |  | 		{"jars", "d"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, item := range all { | 
					
						
							|  |  |  | 		if found[item.k] != item.v { | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 			t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) | 
					
						
							| 
									
										
										
										
											2017-02-22 22:49:34 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(found) != len(all) { | 
					
						
							|  |  |  | 		t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestUnionIterator(t *testing.T) { | 
					
						
							|  |  |  | 	triea := newEmpty() | 
					
						
							|  |  |  | 	for _, val := range testdata1 { | 
					
						
							|  |  |  | 		triea.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	triea.Commit(nil) | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	trieb := newEmpty() | 
					
						
							|  |  |  | 	for _, val := range testdata2 { | 
					
						
							|  |  |  | 		trieb.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	trieb.Commit(nil) | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 14:41:24 +02:00
										 |  |  | 	di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) | 
					
						
							| 
									
										
										
										
											2017-04-18 13:37:10 +02:00
										 |  |  | 	it := NewIterator(di) | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	all := []struct{ k, v string }{ | 
					
						
							|  |  |  | 		{"aardvark", "c"}, | 
					
						
							|  |  |  | 		{"barb", "ba"}, | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 		{"barb", "bd"}, | 
					
						
							| 
									
										
										
										
											2017-04-13 10:14:19 +01:00
										 |  |  | 		{"bard", "bc"}, | 
					
						
							|  |  |  | 		{"bars", "bb"}, | 
					
						
							|  |  |  | 		{"bars", "be"}, | 
					
						
							|  |  |  | 		{"bar", "b"}, | 
					
						
							|  |  |  | 		{"fab", "z"}, | 
					
						
							|  |  |  | 		{"food", "ab"}, | 
					
						
							|  |  |  | 		{"foos", "aa"}, | 
					
						
							|  |  |  | 		{"foo", "a"}, | 
					
						
							|  |  |  | 		{"jars", "d"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, kv := range all { | 
					
						
							|  |  |  | 		if !it.Next() { | 
					
						
							|  |  |  | 			t.Errorf("Iterator ends prematurely at element %d", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if kv.k != string(it.Key) { | 
					
						
							|  |  |  | 			t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if kv.v != string(it.Value) { | 
					
						
							|  |  |  | 			t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if it.Next() { | 
					
						
							|  |  |  | 		t.Errorf("Iterator returned extra values.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestIteratorNoDups(t *testing.T) { | 
					
						
							|  |  |  | 	var tr Trie | 
					
						
							|  |  |  | 	for _, val := range testdata1 { | 
					
						
							|  |  |  | 		tr.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	checkIteratorNoDups(t, tr.NodeIterator(nil), nil) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | func TestIteratorContinueAfterErrorDisk(t *testing.T)    { testIteratorContinueAfterError(t, false) } | 
					
						
							|  |  |  | func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testIteratorContinueAfterError(t *testing.T, memonly bool) { | 
					
						
							| 
									
										
										
										
											2018-05-09 20:24:25 +08:00
										 |  |  | 	diskdb := ethdb.NewMemDatabase() | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	triedb := NewDatabase(diskdb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tr, _ := New(common.Hash{}, triedb) | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	for _, val := range testdata1 { | 
					
						
							|  |  |  | 		tr.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	tr.Commit(nil) | 
					
						
							|  |  |  | 	if !memonly { | 
					
						
							|  |  |  | 		triedb.Commit(tr.Hash(), true) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		diskKeys [][]byte | 
					
						
							|  |  |  | 		memKeys  []common.Hash | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if memonly { | 
					
						
							|  |  |  | 		memKeys = triedb.Nodes() | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		diskKeys = diskdb.Keys() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	for i := 0; i < 20; i++ { | 
					
						
							|  |  |  | 		// Create trie that will load all nodes from DB. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		tr, _ := New(tr.Hash(), triedb) | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Remove a random node from the database. It can't be the root node | 
					
						
							|  |  |  | 		// because that one is already loaded. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		var ( | 
					
						
							|  |  |  | 			rkey common.Hash | 
					
						
							|  |  |  | 			rval []byte | 
					
						
							|  |  |  | 			robj *cachedNode | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 		for { | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 			if memonly { | 
					
						
							|  |  |  | 				rkey = memKeys[rand.Intn(len(memKeys))] | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				copy(rkey[:], diskKeys[rand.Intn(len(diskKeys))]) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if rkey != tr.Hash() { | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		if memonly { | 
					
						
							|  |  |  | 			robj = triedb.nodes[rkey] | 
					
						
							|  |  |  | 			delete(triedb.nodes, rkey) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			rval, _ = diskdb.Get(rkey[:]) | 
					
						
							|  |  |  | 			diskdb.Delete(rkey[:]) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 		// Iterate until the error is hit. | 
					
						
							|  |  |  | 		seen := make(map[string]bool) | 
					
						
							|  |  |  | 		it := tr.NodeIterator(nil) | 
					
						
							|  |  |  | 		checkIteratorNoDups(t, it, seen) | 
					
						
							|  |  |  | 		missing, ok := it.Error().(*MissingNodeError) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		if !ok || missing.NodeHash != rkey { | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 			t.Fatal("didn't hit missing node, got", it.Error()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Add the node back and continue iteration. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		if memonly { | 
					
						
							|  |  |  | 			triedb.nodes[rkey] = robj | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			diskdb.Put(rkey[:], rval) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 		checkIteratorNoDups(t, it, seen) | 
					
						
							|  |  |  | 		if it.Error() != nil { | 
					
						
							|  |  |  | 			t.Fatal("unexpected error", it.Error()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(seen) != wantNodeCount { | 
					
						
							|  |  |  | 			t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Similar to the test above, this one checks that failure to create nodeIterator at a | 
					
						
							|  |  |  | // certain key prefix behaves correctly when Next is called. The expectation is that Next | 
					
						
							|  |  |  | // should retry seeking before returning true for the first time. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | func TestIteratorContinueAfterSeekErrorDisk(t *testing.T) { | 
					
						
							|  |  |  | 	testIteratorContinueAfterSeekError(t, false) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { | 
					
						
							|  |  |  | 	testIteratorContinueAfterSeekError(t, true) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	// Commit test trie to db, then remove the node containing "bars". | 
					
						
							| 
									
										
										
										
											2018-05-09 20:24:25 +08:00
										 |  |  | 	diskdb := ethdb.NewMemDatabase() | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	triedb := NewDatabase(diskdb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctr, _ := New(common.Hash{}, triedb) | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	for _, val := range testdata1 { | 
					
						
							|  |  |  | 		ctr.Update([]byte(val.k), []byte(val.v)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	root, _ := ctr.Commit(nil) | 
					
						
							|  |  |  | 	if !memonly { | 
					
						
							|  |  |  | 		triedb.Commit(root, true) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		barNodeBlob []byte | 
					
						
							|  |  |  | 		barNodeObj  *cachedNode | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if memonly { | 
					
						
							|  |  |  | 		barNodeObj = triedb.nodes[barNodeHash] | 
					
						
							|  |  |  | 		delete(triedb.nodes, barNodeHash) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		barNodeBlob, _ = diskdb.Get(barNodeHash[:]) | 
					
						
							|  |  |  | 		diskdb.Delete(barNodeHash[:]) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	// Create a new iterator that seeks to "bars". Seeking can't proceed because | 
					
						
							|  |  |  | 	// the node is missing. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	tr, _ := New(root, triedb) | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	it := tr.NodeIterator([]byte("bars")) | 
					
						
							|  |  |  | 	missing, ok := it.Error().(*MissingNodeError) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		t.Fatal("want MissingNodeError, got", it.Error()) | 
					
						
							|  |  |  | 	} else if missing.NodeHash != barNodeHash { | 
					
						
							|  |  |  | 		t.Fatal("wrong node missing") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Reinsert the missing node. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	if memonly { | 
					
						
							|  |  |  | 		triedb.nodes[barNodeHash] = barNodeObj | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		diskdb.Put(barNodeHash[:], barNodeBlob) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-20 18:26:09 +02:00
										 |  |  | 	// Check that iteration produces the right set of values. | 
					
						
							|  |  |  | 	if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int { | 
					
						
							|  |  |  | 	if seen == nil { | 
					
						
							|  |  |  | 		seen = make(map[string]bool) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for it.Next(true) { | 
					
						
							|  |  |  | 		if seen[string(it.Path())] { | 
					
						
							|  |  |  | 			t.Fatalf("iterator visited node path %x twice", it.Path()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		seen[string(it.Path())] = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return len(seen) | 
					
						
							|  |  |  | } |