trie_test.go 15.4 KB
Newer Older
1
// Copyright 2014 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
5 6 7 8
// 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.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16

obscuren's avatar
obscuren committed
17
package trie
obscuren's avatar
obscuren committed
18 19

import (
obscuren's avatar
obscuren committed
20
	"bytes"
Felix Lange's avatar
Felix Lange committed
21
	"encoding/binary"
22
	"errors"
obscuren's avatar
obscuren committed
23
	"fmt"
Felix Lange's avatar
Felix Lange committed
24
	"io/ioutil"
25
	"math/big"
26
	"math/rand"
Felix Lange's avatar
Felix Lange committed
27
	"os"
28
	"reflect"
obscuren's avatar
obscuren committed
29
	"testing"
30
	"testing/quick"
31

Felix Lange's avatar
Felix Lange committed
32
	"github.com/davecgh/go-spew/spew"
obscuren's avatar
obscuren committed
33
	"github.com/ethereum/go-ethereum/common"
34
	"github.com/ethereum/go-ethereum/crypto"
Felix Lange's avatar
Felix Lange committed
35
	"github.com/ethereum/go-ethereum/ethdb"
36
	"github.com/ethereum/go-ethereum/rlp"
obscuren's avatar
obscuren committed
37 38
)

Felix Lange's avatar
Felix Lange committed
39 40
func init() {
	spew.Config.Indent = "    "
41
	spew.Config.DisableMethods = false
obscuren's avatar
obscuren committed
42 43
}

Felix Lange's avatar
Felix Lange committed
44 45
// Used for testing
func newEmpty() *Trie {
46
	trie, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
Felix Lange's avatar
Felix Lange committed
47
	return trie
obscuren's avatar
obscuren committed
48 49
}

50
func TestEmptyTrie(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
51
	var trie Trie
52
	res := trie.Hash()
Felix Lange's avatar
Felix Lange committed
53 54
	exp := emptyRoot
	if res != common.Hash(exp) {
55 56
		t.Errorf("expected %x got %x", exp, res)
	}
obscuren's avatar
obscuren committed
57 58
}

59
func TestNull(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
60
	var trie Trie
61
	key := make([]byte, 32)
62
	value := []byte("test")
63
	trie.Update(key, value)
64 65 66
	if !bytes.Equal(trie.Get(key), value) {
		t.Fatal("wrong value")
	}
67 68
}

Felix Lange's avatar
Felix Lange committed
69
func TestMissingRoot(t *testing.T) {
70
	trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(ethdb.NewMemDatabase()))
Felix Lange's avatar
Felix Lange committed
71 72 73
	if trie != nil {
		t.Error("New returned non-nil trie for invalid root")
	}
74
	if _, ok := err.(*MissingNodeError); !ok {
Felix Lange's avatar
Felix Lange committed
75
		t.Errorf("New returned wrong error: %v", err)
Felix Lange's avatar
Felix Lange committed
76 77 78
	}
}

79 80 81 82
func TestMissingNodeDisk(t *testing.T)    { testMissingNode(t, false) }
func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) }

func testMissingNode(t *testing.T, memonly bool) {
83
	diskdb := ethdb.NewMemDatabase()
84 85 86
	triedb := NewDatabase(diskdb)

	trie, _ := New(common.Hash{}, triedb)
87 88
	updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
	updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
89 90 91 92
	root, _ := trie.Commit(nil)
	if !memonly {
		triedb.Commit(root, true)
	}
93

94
	trie, _ = New(root, triedb)
95 96 97 98
	_, err := trie.TryGet([]byte("120000"))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
99
	trie, _ = New(root, triedb)
100 101 102 103
	_, err = trie.TryGet([]byte("120099"))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
104
	trie, _ = New(root, triedb)
105 106 107 108
	_, err = trie.TryGet([]byte("123456"))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
109
	trie, _ = New(root, triedb)
110 111 112 113
	err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv"))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
114
	trie, _ = New(root, triedb)
115 116 117 118 119
	err = trie.TryDelete([]byte("123456"))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

120 121 122 123 124 125
	hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9")
	if memonly {
		delete(triedb.nodes, hash)
	} else {
		diskdb.Delete(hash[:])
	}
126

127
	trie, _ = New(root, triedb)
128 129 130 131
	_, err = trie.TryGet([]byte("120000"))
	if _, ok := err.(*MissingNodeError); !ok {
		t.Errorf("Wrong error: %v", err)
	}
132
	trie, _ = New(root, triedb)
133 134 135 136
	_, err = trie.TryGet([]byte("120099"))
	if _, ok := err.(*MissingNodeError); !ok {
		t.Errorf("Wrong error: %v", err)
	}
137
	trie, _ = New(root, triedb)
138 139 140 141
	_, err = trie.TryGet([]byte("123456"))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
142
	trie, _ = New(root, triedb)
143 144 145 146
	err = trie.TryUpdate([]byte("120099"), []byte("zxcv"))
	if _, ok := err.(*MissingNodeError); !ok {
		t.Errorf("Wrong error: %v", err)
	}
147
	trie, _ = New(root, triedb)
148 149 150 151 152 153
	err = trie.TryDelete([]byte("123456"))
	if _, ok := err.(*MissingNodeError); !ok {
		t.Errorf("Wrong error: %v", err)
	}
}

154
func TestInsert(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
155
	trie := newEmpty()
obscuren's avatar
obscuren committed
156

Felix Lange's avatar
Felix Lange committed
157 158 159
	updateString(trie, "doe", "reindeer")
	updateString(trie, "dog", "puppy")
	updateString(trie, "dogglesworth", "cat")
obscuren's avatar
obscuren committed
160

Felix Lange's avatar
Felix Lange committed
161
	exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3")
162
	root := trie.Hash()
Felix Lange's avatar
Felix Lange committed
163
	if root != exp {
164 165
		t.Errorf("exp %x got %x", exp, root)
	}
166

Felix Lange's avatar
Felix Lange committed
167 168
	trie = newEmpty()
	updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
169

Felix Lange's avatar
Felix Lange committed
170
	exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
171
	root, err := trie.Commit(nil)
Felix Lange's avatar
Felix Lange committed
172 173 174 175
	if err != nil {
		t.Fatalf("commit error: %v", err)
	}
	if root != exp {
176 177
		t.Errorf("exp %x got %x", exp, root)
	}
178
}
obscuren's avatar
obscuren committed
179

180
func TestGet(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
181 182 183 184 185 186 187 188 189 190
	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)
		}
obscuren's avatar
obscuren committed
191

Felix Lange's avatar
Felix Lange committed
192 193 194 195
		unknown := getString(trie, "unknown")
		if unknown != nil {
			t.Errorf("expected nil got %x", unknown)
		}
obscuren's avatar
obscuren committed
196

Felix Lange's avatar
Felix Lange committed
197 198 199
		if i == 1 {
			return
		}
200
		trie.Commit(nil)
201
	}
obscuren's avatar
obscuren committed
202 203
}

204
func TestDelete(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
205
	trie := newEmpty()
206 207 208 209 210 211 212 213 214
	vals := []struct{ k, v string }{
		{"do", "verb"},
		{"ether", "wookiedoo"},
		{"horse", "stallion"},
		{"shaman", "horse"},
		{"doge", "coin"},
		{"ether", ""},
		{"dog", "puppy"},
		{"shaman", ""},
215
	}
216 217
	for _, val := range vals {
		if val.v != "" {
Felix Lange's avatar
Felix Lange committed
218
			updateString(trie, val.k, val.v)
219
		} else {
Felix Lange's avatar
Felix Lange committed
220
			deleteString(trie, val.k)
221
		}
obscuren's avatar
obscuren committed
222 223
	}

224
	hash := trie.Hash()
Felix Lange's avatar
Felix Lange committed
225 226
	exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84")
	if hash != exp {
227
		t.Errorf("expected %x got %x", exp, hash)
obscuren's avatar
obscuren committed
228
	}
229
}
obscuren's avatar
obscuren committed
230

231
func TestEmptyValues(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
232
	trie := newEmpty()
obscuren's avatar
obscuren committed
233

234 235 236 237 238 239 240 241 242
	vals := []struct{ k, v string }{
		{"do", "verb"},
		{"ether", "wookiedoo"},
		{"horse", "stallion"},
		{"shaman", "horse"},
		{"doge", "coin"},
		{"ether", ""},
		{"dog", "puppy"},
		{"shaman", ""},
obscuren's avatar
obscuren committed
243
	}
244
	for _, val := range vals {
Felix Lange's avatar
Felix Lange committed
245
		updateString(trie, val.k, val.v)
obscuren's avatar
obscuren committed
246 247
	}

248
	hash := trie.Hash()
Felix Lange's avatar
Felix Lange committed
249 250
	exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84")
	if hash != exp {
251
		t.Errorf("expected %x got %x", exp, hash)
252
	}
obscuren's avatar
obscuren committed
253 254
}

255
func TestReplication(t *testing.T) {
Felix Lange's avatar
Felix Lange committed
256
	trie := newEmpty()
257 258 259 260 261 262 263 264
	vals := []struct{ k, v string }{
		{"do", "verb"},
		{"ether", "wookiedoo"},
		{"horse", "stallion"},
		{"shaman", "horse"},
		{"doge", "coin"},
		{"dog", "puppy"},
		{"somethingveryoddindeedthis is", "myothernodedata"},
265
	}
266
	for _, val := range vals {
Felix Lange's avatar
Felix Lange committed
267
		updateString(trie, val.k, val.v)
268
	}
269
	exp, err := trie.Commit(nil)
Felix Lange's avatar
Felix Lange committed
270 271
	if err != nil {
		t.Fatalf("commit error: %v", err)
272
	}
273

Felix Lange's avatar
Felix Lange committed
274 275 276 277 278 279 280 281 282 283
	// 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)
		}
	}
284
	hash, err := trie2.Commit(nil)
Felix Lange's avatar
Felix Lange committed
285 286 287 288
	if err != nil {
		t.Fatalf("commit error: %v", err)
	}
	if hash != exp {
289 290
		t.Errorf("root failure. expected %x got %x", exp, hash)
	}
obscuren's avatar
obscuren committed
291

Felix Lange's avatar
Felix Lange committed
292 293
	// perform some insertions on the new trie.
	vals2 := []struct{ k, v string }{
294 295 296
		{"do", "verb"},
		{"ether", "wookiedoo"},
		{"horse", "stallion"},
Felix Lange's avatar
Felix Lange committed
297 298 299 300 301 302
		// {"shaman", "horse"},
		// {"doge", "coin"},
		// {"ether", ""},
		// {"dog", "puppy"},
		// {"somethingveryoddindeedthis is", "myothernodedata"},
		// {"shaman", ""},
303
	}
Felix Lange's avatar
Felix Lange committed
304 305
	for _, val := range vals2 {
		updateString(trie2, val.k, val.v)
306
	}
307
	if hash := trie2.Hash(); hash != exp {
Felix Lange's avatar
Felix Lange committed
308 309 310
		t.Errorf("root failure. expected %x got %x", exp, hash)
	}
}
311

Felix Lange's avatar
Felix Lange committed
312 313 314 315 316
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()
317 318
}

319
type countingDB struct {
320
	ethdb.Database
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
	gets map[string]int
}

func (db *countingDB) Get(key []byte) ([]byte, error) {
	db.gets[string(key)]++
	return db.Database.Get(key)
}

// TestCacheUnload checks that decoded nodes are unloaded after a
// certain number of commit operations.
func TestCacheUnload(t *testing.T) {
	// Create test trie with two branches.
	trie := newEmpty()
	key1 := "---------------------------------"
	key2 := "---some other branch"
	updateString(trie, key1, "this is the branch of key1.")
	updateString(trie, key2, "this is the branch of key2.")
338 339 340

	root, _ := trie.Commit(nil)
	trie.db.Commit(root, true)
341 342 343 344

	// Commit the trie repeatedly and access key1.
	// The branch containing it is loaded from DB exactly two times:
	// in the 0th and 6th iteration.
345 346
	db := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)}
	trie, _ = New(root, NewDatabase(db))
347 348 349
	trie.SetCacheLimit(5)
	for i := 0; i < 12; i++ {
		getString(trie, key1)
350
		trie.Commit(nil)
351 352 353 354 355 356 357 358 359 360 361 362 363
	}
	// Check that it got loaded two times.
	for dbkey, count := range db.gets {
		if count != 2 {
			t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2)
		}
	}
}

// randTest performs random trie operations.
// Instances of this test are created by Generate.
type randTest []randTestStep

364 365 366 367
type randTestStep struct {
	op    int
	key   []byte // for opUpdate, opDelete, opGet
	value []byte // for opUpdate
368
	err   error  // for debugging
369 370 371 372 373 374 375 376 377 378
}

const (
	opUpdate = iota
	opDelete
	opGet
	opCommit
	opHash
	opReset
	opItercheckhash
379
	opCheckCacheInvariant
380 381 382 383 384 385 386 387 388
	opMax // boundary value, not an actual op
)

func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
	var allKeys [][]byte
	genKey := func() []byte {
		if len(allKeys) < 2 || r.Intn(100) < 10 {
			// new key
			key := make([]byte, r.Intn(50))
389
			r.Read(key)
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
			allKeys = append(allKeys, key)
			return key
		}
		// use existing key
		return allKeys[r.Intn(len(allKeys))]
	}

	var steps randTest
	for i := 0; i < size; i++ {
		step := randTestStep{op: r.Intn(opMax)}
		switch step.op {
		case opUpdate:
			step.key = genKey()
			step.value = make([]byte, 8)
			binary.BigEndian.PutUint64(step.value, uint64(i))
		case opGet, opDelete:
			step.key = genKey()
		}
		steps = append(steps, step)
	}
	return reflect.ValueOf(steps)
}

func runRandTest(rt randTest) bool {
414
	triedb := NewDatabase(ethdb.NewMemDatabase())
415 416

	tr, _ := New(common.Hash{}, triedb)
417 418
	values := make(map[string]string) // tracks content of the trie

419
	for i, step := range rt {
420 421 422 423 424 425 426 427 428 429 430
		switch step.op {
		case opUpdate:
			tr.Update(step.key, step.value)
			values[string(step.key)] = string(step.value)
		case opDelete:
			tr.Delete(step.key)
			delete(values, string(step.key))
		case opGet:
			v := tr.Get(step.key)
			want := values[string(step.key)]
			if string(v) != want {
431
				rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
432 433
			}
		case opCommit:
434
			_, rt[i].err = tr.Commit(nil)
435 436 437
		case opHash:
			tr.Hash()
		case opReset:
438
			hash, err := tr.Commit(nil)
439
			if err != nil {
440 441
				rt[i].err = err
				return false
442
			}
443
			newtr, err := New(hash, triedb)
444
			if err != nil {
445 446
				rt[i].err = err
				return false
447 448 449
			}
			tr = newtr
		case opItercheckhash:
450
			checktr, _ := New(common.Hash{}, triedb)
451
			it := NewIterator(tr.NodeIterator(nil))
452 453 454 455
			for it.Next() {
				checktr.Update(it.Key, it.Value)
			}
			if tr.Hash() != checktr.Hash() {
456
				rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash")
457
			}
458
		case opCheckCacheInvariant:
459 460 461 462 463
			rt[i].err = checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0)
		}
		// Abort the test on error.
		if rt[i].err != nil {
			return false
464 465 466 467 468
		}
	}
	return true
}

469
func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error {
470 471
	var children []node
	var flag nodeFlag
472 473
	switch n := n.(type) {
	case *shortNode:
474 475
		flag = n.flags
		children = []node{n.Val}
476
	case *fullNode:
477 478 479
		flag = n.flags
		children = n.Children[:]
	default:
480
		return nil
481 482
	}

483 484 485 486 487
	errorf := func(format string, args ...interface{}) error {
		msg := fmt.Sprintf(format, args...)
		msg += fmt.Sprintf("\nat depth %d node %s", depth, spew.Sdump(n))
		msg += fmt.Sprintf("parent: %s", spew.Sdump(parent))
		return errors.New(msg)
488 489
	}
	if flag.gen > parentCachegen {
490
		return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen)
491 492
	}
	if depth > 0 && !parentDirty && flag.dirty {
493
		return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen)
494 495
	}
	for _, child := range children {
496 497
		if err := checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1); err != nil {
			return err
498
		}
499
	}
500
	return nil
501 502 503 504
}

func TestRandom(t *testing.T) {
	if err := quick.Check(runRandTest, nil); err != nil {
505 506 507
		if cerr, ok := err.(*quick.CheckError); ok {
			t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In))
		}
508 509
		t.Fatal(err)
	}
Felix Lange's avatar
Felix Lange committed
510 511
}

Felix Lange's avatar
Felix Lange committed
512 513 514 515 516 517 518 519
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) }

const benchElemCount = 20000

func benchGet(b *testing.B, commit bool) {
Felix Lange's avatar
Felix Lange committed
520
	trie := new(Trie)
Felix Lange's avatar
Felix Lange committed
521
	if commit {
522
		_, tmpdb := tempDB()
Felix Lange's avatar
Felix Lange committed
523
		trie, _ = New(common.Hash{}, tmpdb)
Felix Lange's avatar
Felix Lange committed
524 525 526 527 528 529 530 531
	}
	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 {
532
		trie.Commit(nil)
Felix Lange's avatar
Felix Lange committed
533 534 535 536 537 538
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		trie.Get(k)
	}
539 540 541
	b.StopTimer()

	if commit {
542
		ldb := trie.db.diskdb.(*ethdb.LDBDatabase)
543 544 545
		ldb.Close()
		os.RemoveAll(ldb.Path())
	}
Felix Lange's avatar
Felix Lange committed
546 547 548
}

func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie {
Felix Lange's avatar
Felix Lange committed
549
	trie := newEmpty()
Felix Lange's avatar
Felix Lange committed
550 551 552 553 554 555 556 557
	k := make([]byte, 32)
	for i := 0; i < b.N; i++ {
		e.PutUint64(k, uint64(i))
		trie.Update(k, k)
	}
	return trie
}

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
// Benchmarks the trie hashing. Since the trie caches the result of any operation,
// we cannot use b.N as the number of hashing rouns, since all rounds apart from
// the first one will be NOOP. As such, we'll use b.N as the number of account to
// insert into the trie before measuring the hashing.
func BenchmarkHash(b *testing.B) {
	// Make the random benchmark deterministic
	random := rand.New(rand.NewSource(0))

	// Create a realistic account trie to hash
	addresses := make([][20]byte, b.N)
	for i := 0; i < len(addresses); i++ {
		for j := 0; j < len(addresses[i]); j++ {
			addresses[i][j] = byte(random.Intn(256))
		}
	}
	accounts := make([][]byte, len(addresses))
	for i := 0; i < len(accounts); i++ {
		var (
			nonce   = uint64(random.Int63())
			balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil))
			root    = emptyRoot
			code    = crypto.Keccak256(nil)
		)
		accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code})
	}
	// Insert the accounts into the trie and hash it
Felix Lange's avatar
Felix Lange committed
584
	trie := newEmpty()
585 586
	for i := 0; i < len(addresses); i++ {
		trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i])
Felix Lange's avatar
Felix Lange committed
587 588
	}
	b.ResetTimer()
589 590
	b.ReportAllocs()
	trie.Hash()
Felix Lange's avatar
Felix Lange committed
591 592
}

593
func tempDB() (string, *Database) {
Felix Lange's avatar
Felix Lange committed
594 595 596 597
	dir, err := ioutil.TempDir("", "trie-bench")
	if err != nil {
		panic(fmt.Sprintf("can't create temporary directory: %v", err))
	}
598
	diskdb, err := ethdb.NewLDBDatabase(dir, 256, 0)
Felix Lange's avatar
Felix Lange committed
599 600 601
	if err != nil {
		panic(fmt.Sprintf("can't create temporary database: %v", err))
	}
602
	return dir, NewDatabase(diskdb)
Felix Lange's avatar
Felix Lange committed
603
}
Felix Lange's avatar
Felix Lange committed
604 605 606 607 608 609 610 611 612 613 614 615

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))
}