github.com/luckypickle/go-ethereum-vet@v1.14.2/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/luckypickle/go-ethereum-vet/common"
    27  	"github.com/luckypickle/go-ethereum-vet/crypto"
    28  	"github.com/luckypickle/go-ethereum-vet/ethdb"
    29  )
    30  
    31  func init() {
    32  	mrand.Seed(time.Now().Unix())
    33  }
    34  
    35  // makeProvers creates Merkle trie provers based on different implementations to
    36  // test all variations.
    37  func makeProvers(trie *Trie) []func(key []byte) *ethdb.MemDatabase {
    38  	var provers []func(key []byte) *ethdb.MemDatabase
    39  
    40  	// Create a direct trie based Merkle prover
    41  	provers = append(provers, func(key []byte) *ethdb.MemDatabase {
    42  		proof := ethdb.NewMemDatabase()
    43  		trie.Prove(key, 0, proof)
    44  		return proof
    45  	})
    46  	// Create a leaf iterator based Merkle prover
    47  	provers = append(provers, func(key []byte) *ethdb.MemDatabase {
    48  		proof := ethdb.NewMemDatabase()
    49  		if it := NewIterator(trie.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) {
    50  			for _, p := range it.Prove() {
    51  				proof.Put(crypto.Keccak256(p), p)
    52  			}
    53  		}
    54  		return proof
    55  	})
    56  	return provers
    57  }
    58  
    59  func TestProof(t *testing.T) {
    60  	trie, vals := randomTrie(500)
    61  	root := trie.Hash()
    62  	for i, prover := range makeProvers(trie) {
    63  		for _, kv := range vals {
    64  			proof := prover(kv.k)
    65  			if proof == nil {
    66  				t.Fatalf("prover %d: missing key %x while constructing proof", i, kv.k)
    67  			}
    68  			val, _, err := VerifyProof(root, kv.k, proof)
    69  			if err != nil {
    70  				t.Fatalf("prover %d: failed to verify proof for key %x: %v\nraw proof: %x", i, kv.k, err, proof)
    71  			}
    72  			if !bytes.Equal(val, kv.v) {
    73  				t.Fatalf("prover %d: verified value mismatch for key %x: have %x, want %x", i, kv.k, val, kv.v)
    74  			}
    75  		}
    76  	}
    77  }
    78  
    79  func TestOneElementProof(t *testing.T) {
    80  	trie := new(Trie)
    81  	updateString(trie, "k", "v")
    82  	for i, prover := range makeProvers(trie) {
    83  		proof := prover([]byte("k"))
    84  		if proof == nil {
    85  			t.Fatalf("prover %d: nil proof", i)
    86  		}
    87  		if proof.Len() != 1 {
    88  			t.Errorf("prover %d: proof should have one element", i)
    89  		}
    90  		val, _, err := VerifyProof(trie.Hash(), []byte("k"), proof)
    91  		if err != nil {
    92  			t.Fatalf("prover %d: failed to verify proof: %v\nraw proof: %x", i, err, proof)
    93  		}
    94  		if !bytes.Equal(val, []byte("v")) {
    95  			t.Fatalf("prover %d: verified value mismatch: have %x, want 'k'", i, val)
    96  		}
    97  	}
    98  }
    99  
   100  func TestBadProof(t *testing.T) {
   101  	trie, vals := randomTrie(800)
   102  	root := trie.Hash()
   103  	for i, prover := range makeProvers(trie) {
   104  		for _, kv := range vals {
   105  			proof := prover(kv.k)
   106  			if proof == nil {
   107  				t.Fatalf("prover %d: nil proof", i)
   108  			}
   109  			key := proof.Keys()[mrand.Intn(proof.Len())]
   110  			val, _ := proof.Get(key)
   111  			proof.Delete(key)
   112  
   113  			mutateByte(val)
   114  			proof.Put(crypto.Keccak256(val), val)
   115  
   116  			if _, _, err := VerifyProof(root, kv.k, proof); err == nil {
   117  				t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k)
   118  			}
   119  		}
   120  	}
   121  }
   122  
   123  // Tests that missing keys can also be proven. The test explicitly uses a single
   124  // entry trie and checks for missing keys both before and after the single entry.
   125  func TestMissingKeyProof(t *testing.T) {
   126  	trie := new(Trie)
   127  	updateString(trie, "k", "v")
   128  
   129  	for i, key := range []string{"a", "j", "l", "z"} {
   130  		proof := ethdb.NewMemDatabase()
   131  		trie.Prove([]byte(key), 0, proof)
   132  
   133  		if proof.Len() != 1 {
   134  			t.Errorf("test %d: proof should have one element", i)
   135  		}
   136  		val, _, err := VerifyProof(trie.Hash(), []byte(key), proof)
   137  		if err != nil {
   138  			t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof)
   139  		}
   140  		if val != nil {
   141  			t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val)
   142  		}
   143  	}
   144  }
   145  
   146  // mutateByte changes one byte in b.
   147  func mutateByte(b []byte) {
   148  	for r := mrand.Intn(len(b)); ; {
   149  		new := byte(mrand.Intn(255))
   150  		if new != b[r] {
   151  			b[r] = new
   152  			break
   153  		}
   154  	}
   155  }
   156  
   157  func BenchmarkProve(b *testing.B) {
   158  	trie, vals := randomTrie(100)
   159  	var keys []string
   160  	for k := range vals {
   161  		keys = append(keys, k)
   162  	}
   163  
   164  	b.ResetTimer()
   165  	for i := 0; i < b.N; i++ {
   166  		kv := vals[keys[i%len(keys)]]
   167  		proofs := ethdb.NewMemDatabase()
   168  		if trie.Prove(kv.k, 0, proofs); len(proofs.Keys()) == 0 {
   169  			b.Fatalf("zero length proof for %x", kv.k)
   170  		}
   171  	}
   172  }
   173  
   174  func BenchmarkVerifyProof(b *testing.B) {
   175  	trie, vals := randomTrie(100)
   176  	root := trie.Hash()
   177  	var keys []string
   178  	var proofs []*ethdb.MemDatabase
   179  	for k := range vals {
   180  		keys = append(keys, k)
   181  		proof := ethdb.NewMemDatabase()
   182  		trie.Prove([]byte(k), 0, proof)
   183  		proofs = append(proofs, proof)
   184  	}
   185  
   186  	b.ResetTimer()
   187  	for i := 0; i < b.N; i++ {
   188  		im := i % len(keys)
   189  		if _, _, err := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil {
   190  			b.Fatalf("key %x: %v", keys[im], err)
   191  		}
   192  	}
   193  }
   194  
   195  func randomTrie(n int) (*Trie, map[string]*kv) {
   196  	trie := new(Trie)
   197  	vals := make(map[string]*kv)
   198  	for i := byte(0); i < 100; i++ {
   199  		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
   200  		value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false}
   201  		trie.Update(value.k, value.v)
   202  		trie.Update(value2.k, value2.v)
   203  		vals[string(value.k)] = value
   204  		vals[string(value2.k)] = value2
   205  	}
   206  	for i := 0; i < n; i++ {
   207  		value := &kv{randBytes(32), randBytes(20), false}
   208  		trie.Update(value.k, value.v)
   209  		vals[string(value.k)] = value
   210  	}
   211  	return trie, vals
   212  }
   213  
   214  func randBytes(n int) []byte {
   215  	r := make([]byte, n)
   216  	crand.Read(r)
   217  	return r
   218  }