github.com/r8d8/go-ethereum@v5.5.2+incompatible/trie/proof_test.go (about)

     1  // Copyright 2015 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  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     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  // GNU Lesser General Public License for more details.
    13  //
    14  // 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  
    17  package trie
    18  
    19  import (
    20  	"bytes"
    21  	crand "crypto/rand"
    22  	mrand "math/rand"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/ethereumproject/go-ethereum/common"
    27  	"github.com/ethereumproject/go-ethereum/crypto"
    28  	"github.com/ethereumproject/go-ethereum/ethdb"
    29  )
    30  
    31  func init() {
    32  	// FIXME: BEWARE
    33  	mrand.Seed(time.Now().Unix())
    34  }
    35  
    36  func TestProof(t *testing.T) {
    37  	trie, vals := randomTrie(500)
    38  	root := trie.Hash()
    39  	for _, kv := range vals {
    40  		proofs, _ := ethdb.NewMemDatabase()
    41  		if trie.Prove(kv.k, 0, proofs) != nil {
    42  			t.Fatalf("missing key %x while constructing proof", kv.k)
    43  		}
    44  		val, err, _ := VerifyProof(root, kv.k, proofs)
    45  		if err != nil {
    46  			t.Fatalf("VerifyProof error for key %x: %v\nraw proof: %v", kv.k, err, proofs)
    47  		}
    48  		if !bytes.Equal(val, kv.v) {
    49  			t.Fatalf("VerifyProof returned wrong value for key %x: got %x, want %x", kv.k, val, kv.v)
    50  		}
    51  	}
    52  }
    53  
    54  func TestOneElementProof(t *testing.T) {
    55  	trie := new(Trie)
    56  	updateString(trie, "k", "v")
    57  	proofs, _ := ethdb.NewMemDatabase()
    58  	trie.Prove([]byte("k"), 0, proofs)
    59  	if len(proofs.Keys()) != 1 {
    60  		t.Error("proof should have one element")
    61  	}
    62  	val, err, _ := VerifyProof(trie.Hash(), []byte("k"), proofs)
    63  	if err != nil {
    64  		t.Fatalf("VerifyProof error: %v\nproof hashes: %v", err, proofs.Keys())
    65  	}
    66  	if !bytes.Equal(val, []byte("v")) {
    67  		t.Fatalf("VerifyProof returned wrong value: got %x, want 'k'", val)
    68  	}
    69  }
    70  
    71  func TestVerifyBadProof(t *testing.T) {
    72  	trie, vals := randomTrie(800)
    73  	root := trie.Hash()
    74  	for _, kv := range vals {
    75  		proofs, _ := ethdb.NewMemDatabase()
    76  		trie.Prove(kv.k, 0, proofs)
    77  		if len(proofs.Keys()) == 0 {
    78  			t.Fatal("zero length proof")
    79  		}
    80  		keys := proofs.Keys()
    81  		key := keys[mrand.Intn(len(keys))]
    82  		node, _ := proofs.Get(key)
    83  		proofs.Delete(key)
    84  		mutateByte(node)
    85  		proofs.Put(crypto.Keccak256(node), node)
    86  		if _, err, _ := VerifyProof(root, kv.k, proofs); err == nil {
    87  			t.Fatalf("expected proof to fail for key %x", kv.k)
    88  		}
    89  	}
    90  }
    91  
    92  // mutateByte changes one byte in b.
    93  func mutateByte(b []byte) {
    94  	for r := mrand.Intn(len(b)); ; {
    95  		new := byte(mrand.Intn(255))
    96  		if new != b[r] {
    97  			b[r] = new
    98  			break
    99  		}
   100  	}
   101  }
   102  
   103  func BenchmarkProve(b *testing.B) {
   104  	trie, vals := randomTrie(100)
   105  	var keys []string
   106  	for k := range vals {
   107  		keys = append(keys, k)
   108  	}
   109  
   110  	b.ResetTimer()
   111  	for i := 0; i < b.N; i++ {
   112  		kv := vals[keys[i%len(keys)]]
   113  		proofs, _ := ethdb.NewMemDatabase()
   114  		if trie.Prove(kv.k, 0, proofs); len(proofs.Keys()) == 0 {
   115  			b.Fatalf("zero length proof for %x", kv.k)
   116  		}
   117  	}
   118  }
   119  
   120  func BenchmarkVerifyProof(b *testing.B) {
   121  	trie, vals := randomTrie(100)
   122  	root := trie.Hash()
   123  	var keys []string
   124  	var proofs []*ethdb.MemDatabase
   125  	for k := range vals {
   126  		keys = append(keys, k)
   127  		proof, _ := ethdb.NewMemDatabase()
   128  		trie.Prove([]byte(k), 0, proof)
   129  		proofs = append(proofs, proof)
   130  	}
   131  
   132  	b.ResetTimer()
   133  	for i := 0; i < b.N; i++ {
   134  		im := i % len(keys)
   135  		if _, err, _ := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil {
   136  			b.Fatalf("key %x: %v", keys[im], err)
   137  		}
   138  	}
   139  }
   140  
   141  func randomTrie(n int) (*Trie, map[string]*kv) {
   142  	trie := new(Trie)
   143  	vals := make(map[string]*kv)
   144  	for i := byte(0); i < 100; i++ {
   145  		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
   146  		value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false}
   147  		trie.Update(value.k, value.v)
   148  		trie.Update(value2.k, value2.v)
   149  		vals[string(value.k)] = value
   150  		vals[string(value2.k)] = value2
   151  	}
   152  	for i := 0; i < n; i++ {
   153  		value := &kv{randBytes(32), randBytes(20), false}
   154  		trie.Update(value.k, value.v)
   155  		vals[string(value.k)] = value
   156  	}
   157  	return trie, vals
   158  }
   159  
   160  func randBytes(n int) []byte {
   161  	r := make([]byte, n)
   162  	crand.Read(r)
   163  	return r
   164  }