From ed3424ff75b396360990725afc124326dea4ab45 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 11:21:18 +0200 Subject: [PATCH] Trie fixes --- ethchain/state.go | 4 +++ ethchain/state_manager.go | 1 + ethchain/state_object.go | 41 +++++++++++++++++------ ethchain/vm.go | 2 +- ethtrie/trie.go | 30 +++++++++++------ ethtrie/trie_test.go | 69 ++++++++++++++++++++++++++++++++++----- ethutil/bytes.go | 12 ++++--- ethutil/value.go | 8 ++--- 8 files changed, 129 insertions(+), 38 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 66c298b3c8..6b849296a6 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -76,6 +76,8 @@ func (self *State) DeleteStateObject(stateObject *StateObject) { // Retrieve a state object given my the address. Nil if not found func (self *State) GetStateObject(addr []byte) *StateObject { + addr = ethutil.Address(addr) + stateObject := self.stateObjects[string(addr)] if stateObject != nil { return stateObject @@ -204,6 +206,8 @@ func (self *State) Update() { // FIXME trie delete is broken valid, t2 := ethtrie.ParanoiaCheck(self.trie) if !valid { + statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.trie.Root, t2.Root) + self.trie = t2 } } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 80362fa771..a0568c4cd2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -121,6 +121,7 @@ done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) st := NewStateTransition(coinbase, tx, state, block) + //fmt.Printf("#%d\n", i+1) err = st.TransitionState() if err != nil { switch { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 889496e91f..cf37586fc4 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -75,7 +75,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { func NewStateObject(addr []byte) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. - address := ethutil.LeftPadBytes(addr, 20) + address := ethutil.Address(addr) object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) @@ -92,13 +92,6 @@ func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { return contract } -// Returns a newly created account -func NewAccount(address []byte, amount *big.Int) *StateObject { - account := &StateObject{address: address, Amount: amount, Nonce: 0} - - return account -} - func NewStateObjectFromBytes(address, data []byte) *StateObject { object := &StateObject{address: address} object.RlpDecode(data) @@ -139,17 +132,37 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value { } return value + + //return self.GetAddr(key) } func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { key := ethutil.LeftPadBytes(k, 32) - //fmt.Printf("%x %v\n", key, value) self.storage[string(key)] = value.Copy() + + /* + if value.BigInt().Cmp(ethutil.Big0) == 0 { + self.state.trie.Delete(string(key)) + return + } + + self.SetAddr(key, value) + */ } func (self *StateObject) Sync() { + /* + fmt.Println("############# BEFORE ################") + self.state.EachStorage(func(key string, value *ethutil.Value) { + fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) + }) + fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + fmt.Println("#####################################") + */ for key, value := range self.storage { - if value.BigInt().Cmp(ethutil.Big0) == 0 { + if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 { + //data := self.getStorage([]byte(key)) + //fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data) self.state.trie.Delete(string(key)) continue } @@ -163,6 +176,14 @@ func (self *StateObject) Sync() { self.state.trie = t2 } + + /* + fmt.Println("############# AFTER ################") + self.state.EachStorage(func(key string, value *ethutil.Value) { + fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) + }) + */ + //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a956ee83f..58d1bee896 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -195,7 +195,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { val := closure.GetStorage(x) if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 - } else if !val.IsEmpty() && len(y.Bytes()) == 0 { + } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { mult = ethutil.Big0 } else { mult = ethutil.Big1 diff --git a/ethtrie/trie.go b/ethtrie/trie.go index 07720be543..f0f3fe5a89 100644 --- a/ethtrie/trie.go +++ b/ethtrie/trie.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" - "reflect" + _ "reflect" "sync" ) @@ -326,7 +326,8 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter // New node n := ethutil.NewValue(node) - if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + if node == nil || n.Len() == 0 { + //if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { newNode := []interface{}{CompactEncode(key), value} return t.Put(newNode) @@ -393,13 +394,17 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter func (t *Trie) deleteState(node interface{}, key []int) interface{} { if len(key) == 0 { + println("") return "" } // New node n := ethutil.NewValue(node) - if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + //if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + if node == nil || n.Len() == 0 { //return nil + //fmt.Printf(" %x %d\n", n, len(n.Bytes())) + return "" } @@ -410,17 +415,19 @@ 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) { + //fmt.Printf(" %x\n", v) + return "" - } else if CompareIntSlice(key[:matchingLength], k) { + } else if CompareIntSlice(key[:len(k)], k) { hash := t.deleteState(v, key[len(k):]) child := t.getNode(hash) - if child.IsNil() { - return node - } + /* + if child.IsNil() { + return node + } + */ var newNode []interface{} if child.Len() == 2 { @@ -430,6 +437,8 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} { newNode = []interface{}{currentNode.Get(0).Str(), hash} } + //fmt.Printf("%x\n", newNode) + return t.Put(newNode) } else { return node @@ -472,10 +481,11 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} { newNode = n } + //fmt.Printf("%x\n", newNode) return t.Put(newNode) } - return "" + panic("unexpected return") } type TrieIterator struct { diff --git a/ethtrie/trie_test.go b/ethtrie/trie_test.go index f39477ff9a..3989a8f451 100644 --- a/ethtrie/trie_test.go +++ b/ethtrie/trie_test.go @@ -1,17 +1,17 @@ package ethtrie import ( - "bytes" - "encoding/hex" - "encoding/json" + _ "bytes" + _ "encoding/hex" + _ "encoding/json" "fmt" "github.com/ethereum/eth-go/ethutil" - "io/ioutil" - "math/rand" - "net/http" - "reflect" + _ "io/ioutil" + _ "math/rand" + _ "net/http" + _ "reflect" "testing" - "time" + _ "time" ) const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" @@ -43,6 +43,7 @@ func New() (*MemDatabase, *Trie) { return db, NewTrie(db, "") } +/* func TestTrieSync(t *testing.T) { db, trie := New() @@ -365,3 +366,55 @@ func TestDelete(t *testing.T) { fmt.Printf("o: %x\nc: %x\n", a, b) } +*/ + +func TestRndCase(t *testing.T) { + _, trie := New() + + data := []struct{ k, v string }{ + {"0000000000000000000000000000000000000000000000000000000000000001", "a07573657264617461000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000003", "8453bb5b31"}, + {"0000000000000000000000000000000000000000000000000000000000000004", "850218711a00"}, + {"0000000000000000000000000000000000000000000000000000000000000005", "9462d7705bd0b3ecbc51a8026a25597cb28a650c79"}, + {"0000000000000000000000000000000000000000000000000000000000000010", "947e70f9460402290a3e487dae01f610a1a8218fda"}, + {"0000000000000000000000000000000000000000000000000000000000000111", "01"}, + {"0000000000000000000000000000000000000000000000000000000000000112", "a053656e6174650000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000113", "a053656e6174650000000000000000000000000000000000000000000000000000"}, + {"53656e6174650000000000000000000000000000000000000000000000000000", "94977e3f62f5e1ed7953697430303a3cfa2b5b736e"}, + } + for _, e := range data { + trie.Update(string(ethutil.Hex2Bytes(e.k)), string(ethutil.Hex2Bytes(e.v))) + } + + fmt.Printf("root after update %x\n", trie.Root) + trie.NewIterator().Each(func(k string, v *ethutil.Value) { + fmt.Printf("%x %x\n", k, v.Bytes()) + }) + + data = []struct{ k, v string }{ + {"0000000000000000000000000000000000000000000000000000000000000112", ""}, + {"436974697a656e73000000000000000000000000000000000000000000000001", ""}, + {"436f757274000000000000000000000000000000000000000000000000000002", ""}, + {"53656e6174650000000000000000000000000000000000000000000000000000", ""}, + {"436f757274000000000000000000000000000000000000000000000000000000", ""}, + {"53656e6174650000000000000000000000000000000000000000000000000001", ""}, + {"0000000000000000000000000000000000000000000000000000000000000113", ""}, + {"436974697a656e73000000000000000000000000000000000000000000000000", ""}, + {"436974697a656e73000000000000000000000000000000000000000000000002", ""}, + {"436f757274000000000000000000000000000000000000000000000000000001", ""}, + {"0000000000000000000000000000000000000000000000000000000000000111", ""}, + {"53656e6174650000000000000000000000000000000000000000000000000002", ""}, + } + + for _, e := range data { + trie.Delete(string(ethutil.Hex2Bytes(e.k))) + } + + fmt.Printf("root after delete %x\n", trie.Root) + + trie.NewIterator().Each(func(k string, v *ethutil.Value) { + fmt.Printf("%x %x\n", k, v.Bytes()) + }) + + fmt.Printf("%x\n", trie.Get(string(ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")))) +} diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 07584d0bfc..d16bd67809 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -150,12 +150,16 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } -func Address(slice []byte) []byte { +func Address(slice []byte) (addr []byte) { if len(slice) < 20 { - slice = LeftPadBytes(slice, 20) + addr = LeftPadBytes(slice, 20) } else if len(slice) > 20 { - slice = slice[len(slice)-20:] + addr = slice[len(slice)-20:] + } else { + addr = slice } - return slice + addr = CopyBytes(addr) + + return } diff --git a/ethutil/value.go b/ethutil/value.go index ecb9d15110..fba7426d13 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -40,13 +40,9 @@ func (val *Value) Len() int { //return val.kind.Len() if data, ok := val.Val.([]interface{}); ok { return len(data) - } else if data, ok := val.Val.([]byte); ok { - return len(data) - } else if data, ok := val.Val.(string); ok { - return len(data) } - return 0 + return len(val.Bytes()) } func (val *Value) Raw() interface{} { @@ -118,6 +114,8 @@ func (val *Value) Bytes() []byte { return []byte{s} } else if s, ok := val.Val.(string); ok { return []byte(s) + } else if s, ok := val.Val.(*big.Int); ok { + return s.Bytes() } return []byte{}