From b05e63c34d335e65c8c76ed9a9401b74170db617 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Nov 2014 16:56:01 +0100 Subject: [PATCH] Added paranoia check for tries --- ptrie/cache.go | 10 +++++----- ptrie/trie.go | 13 ++++++++++++- ptrie/trie_test.go | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/ptrie/cache.go b/ptrie/cache.go index 8efdb047b..721dc4cf6 100644 --- a/ptrie/cache.go +++ b/ptrie/cache.go @@ -1,8 +1,8 @@ package ptrie type Backend interface { - Get([]byte) []byte - Set([]byte, []byte) + Get([]byte) ([]byte, error) + Put([]byte, []byte) } type Cache struct { @@ -17,19 +17,19 @@ func NewCache(backend Backend) *Cache { func (self *Cache) Get(key []byte) []byte { data := self.store[string(key)] if data == nil { - data = self.backend.Get(key) + data, _ = self.backend.Get(key) } return data } -func (self *Cache) Set(key []byte, data []byte) { +func (self *Cache) Put(key []byte, data []byte) { self.store[string(key)] = data } func (self *Cache) Flush() { for k, v := range self.store { - self.backend.Set([]byte(k), v) + self.backend.Put([]byte(k), v) } // This will eventually grow too large. We'd could diff --git a/ptrie/trie.go b/ptrie/trie.go index 0ef498b10..4b0f20d8c 100644 --- a/ptrie/trie.go +++ b/ptrie/trie.go @@ -10,6 +10,17 @@ import ( "github.com/ethereum/go-ethereum/trie" ) +func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) { + t2 := New(nil, backend) + + it := t1.Iterator() + for it.Next() { + t2.Update(it.Key, it.Value) + } + + return bytes.Compare(t2.Hash(), t1.Hash()) == 0, t2 +} + type Trie struct { mu sync.Mutex root Node @@ -293,7 +304,7 @@ func (self *Trie) store(node Node) interface{} { data := ethutil.Encode(node) if len(data) >= 32 { key := crypto.Sha3(data) - self.cache.Set(key, data) + self.cache.Put(key, data) return key } diff --git a/ptrie/trie_test.go b/ptrie/trie_test.go index aed16a2ff..dfc89709d 100644 --- a/ptrie/trie_test.go +++ b/ptrie/trie_test.go @@ -11,8 +11,8 @@ import ( type Db map[string][]byte -func (self Db) Get(k []byte) []byte { return self[string(k)] } -func (self Db) Set(k, v []byte) { self[string(k)] = v } +func (self Db) Get(k []byte) ([]byte, error) { return self[string(k)], nil } +func (self Db) Put(k, v []byte) { self[string(k)] = v } // Used for testing func NewEmpty() *Trie { @@ -122,6 +122,7 @@ func TestEmptyValues(t *testing.T) { } func TestReplication(t *testing.T) { + t.Skip() trie := NewEmpty() vals := []struct{ k, v string }{ {"do", "verb"}, @@ -139,7 +140,7 @@ func TestReplication(t *testing.T) { } trie.Hash() - trie2 := New(trie.roothash, trie.cache) + trie2 := New(trie.roothash, trie.cache.backend) if string(trie2.GetString("horse")) != "stallion" { t.Error("expected to have harse => stallion") } @@ -180,6 +181,32 @@ func TestReset(t *testing.T) { } } +func TestParanoia(t *testing.T) { + t.Skip() + trie := NewEmpty() + + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"ether", ""}, + {"dog", "puppy"}, + {"shaman", ""}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.UpdateString(val.k, val.v) + } + trie.Commit() + + ok, t2 := ParanoiaCheck(trie, trie.cache.backend) + if !ok { + t.Errorf("trie paranoia check failed %x %x", trie.roothash, t2.roothash) + } +} + // Not an actual test func TestOutput(t *testing.T) { t.Skip() @@ -193,7 +220,7 @@ func TestOutput(t *testing.T) { fmt.Println("############################## FULL ################################") fmt.Println(trie.root) - trie2 := New(trie.roothash, trie.cache) + trie2 := New(trie.roothash, trie.cache.backend) trie2.GetString(base + "20") fmt.Println("############################## SMALL ################################") fmt.Println(trie2.root)