From 09bade64666f82a2580e7d24a8bc7655e2113287 Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Tue, 15 Jul 2014 15:29:54 +0200
Subject: Fixed an issue where the trie might crash on missmatching lengths

---
 ethtrie/trie.go      | 19 ++++++++++++++-----
 ethtrie/trie_test.go | 46 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/ethtrie/trie.go b/ethtrie/trie.go
index 38c78e7f4..07720be54 100644
--- a/ethtrie/trie.go
+++ b/ethtrie/trie.go
@@ -9,6 +9,8 @@ import (
 	"sync"
 )
 
+func __ignore() { fmt.Println("") }
+
 func ParanoiaCheck(t1 *Trie) (bool, *Trie) {
 	t2 := NewTrie(ethutil.Config.Db, "")
 
@@ -269,8 +271,7 @@ func (t *Trie) getState(node interface{}, key []int) interface{} {
 	}
 
 	// It shouldn't come this far
-	fmt.Println("getState unexpected return")
-	return ""
+	panic("unexpected return")
 }
 
 func (t *Trie) getNode(node interface{}) *ethutil.Value {
@@ -287,7 +288,9 @@ func (t *Trie) getNode(node interface{}) *ethutil.Value {
 		return ethutil.NewValueFromBytes([]byte(str))
 	}
 
-	return t.cache.Get(n.Bytes())
+	data := t.cache.Get(n.Bytes())
+
+	return data
 }
 
 func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} {
@@ -385,7 +388,7 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter
 		return t.Put(newNode)
 	}
 
-	return ""
+	panic("unexpected end")
 }
 
 func (t *Trie) deleteState(node interface{}, key []int) interface{} {
@@ -396,6 +399,7 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} {
 	// New node
 	n := ethutil.NewValue(node)
 	if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 {
+		//return nil
 		return ""
 	}
 
@@ -406,12 +410,17 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} {
 		k := CompactDecode(currentNode.Get(0).Str())
 		v := currentNode.Get(1).Raw()
 
+		matchingLength := MatchingNibbleLength(key, k)
+
 		// Matching key pair (ie. there's already an object with this key)
 		if CompareIntSlice(k, key) {
 			return ""
-		} else if CompareIntSlice(key[:len(k)], k) {
+		} else if CompareIntSlice(key[:matchingLength], k) {
 			hash := t.deleteState(v, key[len(k):])
 			child := t.getNode(hash)
+			if child.IsNil() {
+				return node
+			}
 
 			var newNode []interface{}
 			if child.Len() == 2 {
diff --git a/ethtrie/trie_test.go b/ethtrie/trie_test.go
index a3d4547d7..f39477ff9 100644
--- a/ethtrie/trie_test.go
+++ b/ethtrie/trie_test.go
@@ -5,6 +5,7 @@ import (
 	"encoding/hex"
 	"encoding/json"
 	"fmt"
+	"github.com/ethereum/eth-go/ethutil"
 	"io/ioutil"
 	"math/rand"
 	"net/http"
@@ -251,8 +252,8 @@ func TestRemote(t *testing.T) {
 			trie.Update(get(key), get(value))
 		}
 
-		a := NewValue(h(test.Root)).Bytes()
-		b := NewValue(trie.Root).Bytes()
+		a := ethutil.NewValue(h(test.Root)).Bytes()
+		b := ethutil.NewValue(trie.Root).Bytes()
 		if bytes.Compare(a, b) != 0 {
 			t.Errorf("%-10s: %x %x", test.Name, a, b)
 		}
@@ -267,12 +268,12 @@ func TestTrieReplay(t *testing.T) {
 		}
 
 		_, trie2 := New()
-		trie.NewIterator().Each(func(key string, v *Value) {
+		trie.NewIterator().Each(func(key string, v *ethutil.Value) {
 			trie2.Update(key, v.Str())
 		})
 
-		a := NewValue(trie.Root).Bytes()
-		b := NewValue(trie2.Root).Bytes()
+		a := ethutil.NewValue(trie.Root).Bytes()
+		b := ethutil.NewValue(trie2.Root).Bytes()
 		if bytes.Compare(a, b) != 0 {
 			t.Errorf("%s %x %x\n", test.Name, trie.Root, trie2.Root)
 		}
@@ -329,3 +330,38 @@ func TestRegression(t *testing.T) {
 		}
 	}
 }
+
+func TestDelete(t *testing.T) {
+	_, trie := New()
+
+	trie.Update("a", "jeffreytestlongstring")
+	trie.Update("aa", "otherstring")
+	trie.Update("aaa", "othermorestring")
+	trie.Update("aabbbbccc", "hithere")
+	trie.Update("abbcccdd", "hstanoehutnaheoustnh")
+	trie.Update("rnthaoeuabbcccdd", "hstanoehutnaheoustnh")
+	trie.Update("rneuabbcccdd", "hstanoehutnaheoustnh")
+	trie.Update("rneuabboeusntahoeucccdd", "hstanoehutnaheoustnh")
+	trie.Update("rnxabboeusntahoeucccdd", "hstanoehutnaheoustnh")
+	trie.Delete("aaboaestnuhbccc")
+	trie.Delete("a")
+	trie.Update("a", "nthaonethaosentuh")
+	trie.Update("c", "shtaosntehua")
+	trie.Delete("a")
+	trie.Update("aaaa", "testmegood")
+
+	fmt.Println("aa =>", trie.Get("aa"))
+	_, t2 := New()
+	trie.NewIterator().Each(func(key string, v *ethutil.Value) {
+		if key == "aaaa" {
+			t2.Update(key, v.Str())
+		} else {
+			t2.Update(key, v.Str())
+		}
+	})
+
+	a := ethutil.NewValue(trie.Root).Bytes()
+	b := ethutil.NewValue(t2.Root).Bytes()
+
+	fmt.Printf("o: %x\nc: %x\n", a, b)
+}
-- 
cgit v1.2.3