github.com/theQRL/go-zond@v0.2.1/tests/fuzzers/trie/trie-fuzzer.go (about) 1 // Copyright 2019 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 "encoding/binary" 22 "errors" 23 "fmt" 24 25 "github.com/theQRL/go-zond/core/rawdb" 26 "github.com/theQRL/go-zond/core/types" 27 "github.com/theQRL/go-zond/trie" 28 "github.com/theQRL/go-zond/trie/trienode" 29 ) 30 31 // randTest performs random trie operations. 32 // Instances of this test are created by Generate. 33 type randTest []randTestStep 34 35 type randTestStep struct { 36 op int 37 key []byte // for opUpdate, opDelete, opGet 38 value []byte // for opUpdate 39 err error // for debugging 40 } 41 42 type proofDb struct{} 43 44 func (proofDb) Put(key []byte, value []byte) error { 45 return nil 46 } 47 48 func (proofDb) Delete(key []byte) error { 49 return nil 50 } 51 52 const ( 53 opUpdate = iota 54 opDelete 55 opGet 56 opHash 57 opCommit 58 opItercheckhash 59 opProve 60 opMax // boundary value, not an actual op 61 ) 62 63 type dataSource struct { 64 input []byte 65 reader *bytes.Reader 66 } 67 68 func newDataSource(input []byte) *dataSource { 69 return &dataSource{ 70 input, bytes.NewReader(input), 71 } 72 } 73 func (ds *dataSource) readByte() byte { 74 if b, err := ds.reader.ReadByte(); err != nil { 75 return 0 76 } else { 77 return b 78 } 79 } 80 func (ds *dataSource) Read(buf []byte) (int, error) { 81 return ds.reader.Read(buf) 82 } 83 func (ds *dataSource) Ended() bool { 84 return ds.reader.Len() == 0 85 } 86 87 func Generate(input []byte) randTest { 88 var allKeys [][]byte 89 r := newDataSource(input) 90 genKey := func() []byte { 91 if len(allKeys) < 2 || r.readByte() < 0x0f { 92 // new key 93 key := make([]byte, r.readByte()%50) 94 r.Read(key) 95 allKeys = append(allKeys, key) 96 return key 97 } 98 // use existing key 99 return allKeys[int(r.readByte())%len(allKeys)] 100 } 101 102 var steps randTest 103 104 for i := 0; !r.Ended(); i++ { 105 step := randTestStep{op: int(r.readByte()) % opMax} 106 switch step.op { 107 case opUpdate: 108 step.key = genKey() 109 step.value = make([]byte, 8) 110 binary.BigEndian.PutUint64(step.value, uint64(i)) 111 case opGet, opDelete, opProve: 112 step.key = genKey() 113 } 114 steps = append(steps, step) 115 if len(steps) > 500 { 116 break 117 } 118 } 119 120 return steps 121 } 122 123 // Fuzz is the fuzzing entry-point. 124 // The function must return 125 // 126 // - 1 if the fuzzer should increase priority of the 127 // given input during subsequent fuzzing (for example, the input is lexically 128 // correct and was parsed successfully); 129 // - -1 if the input must not be added to corpus even if gives new coverage; and 130 // - 0 otherwise 131 // 132 // other values are reserved for future use. 133 func Fuzz(input []byte) int { 134 program := Generate(input) 135 if len(program) == 0 { 136 return 0 137 } 138 if err := runRandTest(program); err != nil { 139 panic(err) 140 } 141 return 1 142 } 143 144 func runRandTest(rt randTest) error { 145 var ( 146 triedb = trie.NewDatabase(rawdb.NewMemoryDatabase(), nil) 147 tr = trie.NewEmpty(triedb) 148 origin = types.EmptyRootHash 149 values = make(map[string]string) // tracks content of the trie 150 ) 151 for i, step := range rt { 152 switch step.op { 153 case opUpdate: 154 tr.MustUpdate(step.key, step.value) 155 values[string(step.key)] = string(step.value) 156 case opDelete: 157 tr.MustDelete(step.key) 158 delete(values, string(step.key)) 159 case opGet: 160 v := tr.MustGet(step.key) 161 want := values[string(step.key)] 162 if string(v) != want { 163 rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) 164 } 165 case opHash: 166 tr.Hash() 167 case opCommit: 168 hash, nodes, err := tr.Commit(false) 169 if err != nil { 170 return err 171 } 172 if nodes != nil { 173 if err := triedb.Update(hash, origin, 0, trienode.NewWithNodeSet(nodes), nil); err != nil { 174 return err 175 } 176 } 177 newtr, err := trie.New(trie.TrieID(hash), triedb) 178 if err != nil { 179 return err 180 } 181 tr = newtr 182 origin = hash 183 case opItercheckhash: 184 checktr := trie.NewEmpty(triedb) 185 it := trie.NewIterator(tr.MustNodeIterator(nil)) 186 for it.Next() { 187 checktr.MustUpdate(it.Key, it.Value) 188 } 189 if tr.Hash() != checktr.Hash() { 190 return errors.New("hash mismatch in opItercheckhash") 191 } 192 case opProve: 193 rt[i].err = tr.Prove(step.key, proofDb{}) 194 } 195 // Abort the test on error. 196 if rt[i].err != nil { 197 return rt[i].err 198 } 199 } 200 return nil 201 }