mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
trie: improve error reporting of random test
This commit is contained in:
parent
1a008e5511
commit
d36e4a4176
1 changed files with 31 additions and 26 deletions
|
|
@ -19,6 +19,7 @@ package trie
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
@ -34,7 +35,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
spew.Config.Indent = " "
|
spew.Config.Indent = " "
|
||||||
spew.Config.DisableMethods = true
|
spew.Config.DisableMethods = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for testing
|
// Used for testing
|
||||||
|
|
@ -357,6 +358,7 @@ type randTestStep struct {
|
||||||
op int
|
op int
|
||||||
key []byte // for opUpdate, opDelete, opGet
|
key []byte // for opUpdate, opDelete, opGet
|
||||||
value []byte // for opUpdate
|
value []byte // for opUpdate
|
||||||
|
err error // for debugging
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -406,7 +408,7 @@ func runRandTest(rt randTest) bool {
|
||||||
tr, _ := New(common.Hash{}, db)
|
tr, _ := New(common.Hash{}, db)
|
||||||
values := make(map[string]string) // tracks content of the trie
|
values := make(map[string]string) // tracks content of the trie
|
||||||
|
|
||||||
for _, step := range rt {
|
for i, step := range rt {
|
||||||
switch step.op {
|
switch step.op {
|
||||||
case opUpdate:
|
case opUpdate:
|
||||||
tr.Update(step.key, step.value)
|
tr.Update(step.key, step.value)
|
||||||
|
|
@ -418,23 +420,22 @@ func runRandTest(rt randTest) bool {
|
||||||
v := tr.Get(step.key)
|
v := tr.Get(step.key)
|
||||||
want := values[string(step.key)]
|
want := values[string(step.key)]
|
||||||
if string(v) != want {
|
if string(v) != want {
|
||||||
fmt.Printf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
|
rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
case opCommit:
|
case opCommit:
|
||||||
if _, err := tr.Commit(); err != nil {
|
_, rt[i].err = tr.Commit()
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
case opHash:
|
case opHash:
|
||||||
tr.Hash()
|
tr.Hash()
|
||||||
case opReset:
|
case opReset:
|
||||||
hash, err := tr.Commit()
|
hash, err := tr.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
rt[i].err = err
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
newtr, err := New(hash, db)
|
newtr, err := New(hash, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
rt[i].err = err
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
tr = newtr
|
tr = newtr
|
||||||
case opItercheckhash:
|
case opItercheckhash:
|
||||||
|
|
@ -444,17 +445,20 @@ func runRandTest(rt randTest) bool {
|
||||||
checktr.Update(it.Key, it.Value)
|
checktr.Update(it.Key, it.Value)
|
||||||
}
|
}
|
||||||
if tr.Hash() != checktr.Hash() {
|
if tr.Hash() != checktr.Hash() {
|
||||||
fmt.Println("hashes not equal")
|
rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash")
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
case opCheckCacheInvariant:
|
case opCheckCacheInvariant:
|
||||||
return checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0)
|
rt[i].err = checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0)
|
||||||
|
}
|
||||||
|
// Abort the test on error.
|
||||||
|
if rt[i].err != nil {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) bool {
|
func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error {
|
||||||
var children []node
|
var children []node
|
||||||
var flag nodeFlag
|
var flag nodeFlag
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
|
|
@ -465,33 +469,34 @@ func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool
|
||||||
flag = n.flags
|
flag = n.flags
|
||||||
children = n.Children[:]
|
children = n.Children[:]
|
||||||
default:
|
default:
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
showerror := func() {
|
errorf := func(format string, args ...interface{}) error {
|
||||||
fmt.Printf("at depth %d node %s", depth, spew.Sdump(n))
|
msg := fmt.Sprintf(format, args...)
|
||||||
fmt.Printf("parent: %s", spew.Sdump(parent))
|
msg += fmt.Sprintf("\nat depth %d node %s", depth, spew.Sdump(n))
|
||||||
|
msg += fmt.Sprintf("parent: %s", spew.Sdump(parent))
|
||||||
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
if flag.gen > parentCachegen {
|
if flag.gen > parentCachegen {
|
||||||
fmt.Printf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen)
|
return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen)
|
||||||
showerror()
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
if depth > 0 && !parentDirty && flag.dirty {
|
if depth > 0 && !parentDirty && flag.dirty {
|
||||||
fmt.Printf("cache invariant violation: child is dirty but parent isn't\n")
|
return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen)
|
||||||
showerror()
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
for _, child := range children {
|
for _, child := range children {
|
||||||
if !checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1) {
|
if err := checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1); err != nil {
|
||||||
return false
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRandom(t *testing.T) {
|
func TestRandom(t *testing.T) {
|
||||||
if err := quick.Check(runRandTest, nil); err != nil {
|
if err := quick.Check(runRandTest, nil); err != nil {
|
||||||
|
if cerr, ok := err.(*quick.CheckError); ok {
|
||||||
|
t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In))
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue