From 5b2e5d180fa79865b6319f4251a440da44a81809 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:37:18 +0200 Subject: [PATCH 01/30] Changed diff output not to prefix hex with 0x --- ethchain/state.go | 4 ++-- ethchain/state_manager.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 8df79dcef..4faf691f2 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -212,9 +212,9 @@ func (self *State) Update() { // Debug stuff func (self *State) CreateOutputForDiff() { for addr, stateObject := range self.stateObjects { - fmt.Printf("0x%x 0x%x 0x%x 0x%x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) + fmt.Printf("%x %x %x %x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) stateObject.state.EachStorage(func(addr string, value *ethutil.Value) { - fmt.Printf("0x%x 0x%x\n", addr, value.Bytes()) + fmt.Printf("%x %x\n", addr, value.Bytes()) }) } } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 62fcda8a5..f2ecd4b9f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -151,7 +151,7 @@ done: receipts = append(receipts, receipt) handled = append(handled, tx) - if ethutil.Config.Diff { + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { state.CreateOutputForDiff() } } @@ -187,8 +187,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // before that. defer state.Reset() - if ethutil.Config.Diff { - fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number) + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) } receipts, err := sm.ApplyDiff(state, parent, block) From 2c46bfde8b65c3df0e7ee26955c0e0bd1ddf8873 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:37:41 +0200 Subject: [PATCH 02/30] Increased block request --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 0a4f08af5..8c622aa5c 100644 --- a/peer.go +++ b/peer.go @@ -754,7 +754,7 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { if !p.catchingUp { // Make sure nobody else is catching up when you want to do this p.catchingUp = true - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(10)}) + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(30)}) p.QueueMessage(msg) peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) From 04f8c455e2d8585902e2c9f0cfb8717ef74a65ca Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:37:50 +0200 Subject: [PATCH 03/30] Added diff type --- ethutil/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethutil/config.go b/ethutil/config.go index 2f3d706fe..41bece21d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -14,6 +14,7 @@ type ConfigManager struct { ExecPath string Debug bool Diff bool + DiffType string Paranoia bool conf *globalconf.GlobalConf From 5a0c4ce29509046e7de801e96bee893c82bfc1e8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:38:20 +0200 Subject: [PATCH 04/30] Fixed "Copy" to also copy over the pending storage changes --- ethchain/state_object.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index ebc050863..f4adc4c80 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -15,6 +15,18 @@ func (self Code) String() string { return strings.Join(Disassemble(self), " ") } +type Storage map[string]*ethutil.Value + +func (self Storage) Copy() Storage { + cpy := make(Storage) + for key, value := range self { + // XXX Do we need a 'value' copy or is this sufficient? + cpy[key] = value + } + + return cpy +} + type StateObject struct { // Address of the object address []byte @@ -27,7 +39,7 @@ type StateObject struct { script Code initScript Code - storage map[string]*ethutil.Value + storage Storage // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly @@ -41,7 +53,7 @@ type StateObject struct { } func (self *StateObject) Reset() { - self.storage = make(map[string]*ethutil.Value) + self.storage = make(Storage) } // Converts an transaction in to a state object @@ -95,7 +107,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true - statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) + statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { @@ -154,13 +166,13 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - statelogger.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.DebugDetailf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.DebugDetailf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -222,6 +234,7 @@ func (self *StateObject) Copy() *StateObject { } stateObject.script = ethutil.CopyBytes(self.script) stateObject.initScript = ethutil.CopyBytes(self.initScript) + stateObject.storage = self.storage.Copy() return stateObject } From 767d24ea5da8794dbc3b8bed19f6c204e775e406 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 22:52:30 +0200 Subject: [PATCH 05/30] Removed defer and added receipts checking in tx processing --- ethchain/state_manager.go | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f2ecd4b9f..d52e418ce 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -148,6 +148,11 @@ done: accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + original := block.Receipts()[i] + if !original.Cmp(receipt) { + return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + } + receipts = append(receipts, receipt) handled = append(handled, tx) @@ -192,31 +197,6 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { } receipts, err := sm.ApplyDiff(state, parent, block) - defer func() { - if err != nil { - if len(receipts) == len(block.Receipts()) { - for i, receipt := range block.Receipts() { - statelogger.Infof("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) - } - } else { - statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) - } - } else { - /* - for i, receipt := range receipts { - gu := new(big.Int) - if i != 0 { - gu.Sub(receipt.CumulativeGasUsed, receipts[i-1].CumulativeGasUsed) - } else { - gu.Set(receipt.CumulativeGasUsed) - } - - statelogger.Infof("[r] %v ~ %x (%x)\n", gu, receipt.PostState[0:4], receipt.Tx.Hash()) - } - */ - } - }() - if err != nil { return err } From 98f21d8973398ccf58a762788a1972ef16213de5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 22:52:44 +0200 Subject: [PATCH 06/30] Compare method for receipts --- ethchain/transaction.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index da3f9bcf2..0b4f8d1a4 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -227,6 +227,18 @@ func (self *Receipt) String() string { self.CumulativeGasUsed) } +func (self *Receipt) Cmp(other *Receipt) bool { + if bytes.Compare(self.PostState, other.PostState) != 0 { + return false + } + + if self.CumulativeGasUsed.Cmp(other.CumulativeGasUsed) != 0 { + return false + } + + return true +} + // Transaction slice type for basic sorting type Transactions []*Transaction From 69acda2c255b098a015e17432b9bffd9010d841d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:27 +0200 Subject: [PATCH 07/30] Paranoia check moved --- ethchain/state_transition.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 314d858f2..8cface9e8 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,8 +2,6 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethtrie" - "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -275,20 +273,5 @@ func (self *StateTransition) Eval(script []byte, context *StateObject, typ strin func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { ret, _, err = closure.Call(vm, data) - if ethutil.Config.Paranoia { - var ( - context = closure.object - trie = context.state.trie - ) - - valid, t2 := ethtrie.ParanoiaCheck(trie) - if !valid { - // TODO FIXME ASAP - context.state.trie = t2 - - statelogger.Infoln("Warn: PARANOIA: Different state object roots during copy") - } - } - return } From 50bc838047709796596f447ef3e60d0e4ab47fde Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:38 +0200 Subject: [PATCH 08/30] Moved checks --- ethchain/state.go | 1 - ethchain/state_object.go | 29 +++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 4faf691f2..66c298b3c 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -145,7 +145,6 @@ func (self *State) Set(state *State) { self.trie = state.trie self.stateObjects = state.stateObjects - //*self = *state } func (s *State) Root() interface{} { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index f4adc4c80..5791c6ed1 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -54,6 +54,7 @@ type StateObject struct { func (self *StateObject) Reset() { self.storage = make(Storage) + self.state.Reset() } // Converts an transaction in to a state object @@ -78,7 +79,7 @@ func NewStateObject(addr []byte) *StateObject { object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - object.storage = make(map[string]*ethutil.Value) + object.storage = make(Storage) return object } @@ -125,23 +126,24 @@ func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { self.setStorage(key.Bytes(), value) } -func (self *StateObject) getStorage(key []byte) *ethutil.Value { - k := ethutil.LeftPadBytes(key, 32) +func (self *StateObject) getStorage(k []byte) *ethutil.Value { + key := ethutil.LeftPadBytes(k, 32) - value := self.storage[string(k)] + value := self.storage[string(key)] if value == nil { - value = self.GetAddr(k) + value = self.GetAddr(key) - self.storage[string(k)] = value + if !value.IsNil() { + self.storage[string(key)] = value + } } return value } -func (self *StateObject) setStorage(key []byte, value *ethutil.Value) { - k := ethutil.LeftPadBytes(key, 32) - - self.storage[string(k)] = value +func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { + key := ethutil.LeftPadBytes(k, 32) + self.storage[string(key)] = value.Copy() } func (self *StateObject) Sync() { @@ -152,9 +154,16 @@ func (self *StateObject) Sync() { } self.SetAddr([]byte(key), value) + } + valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) + if !valid { + self.state.trie = t2 + + statelogger.Infoln("Warn: PARANOIA: Different state storage root during copy") } } + func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) From 2784e256f1c5f8112486e9037c9b00e628e5aa10 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:49 +0200 Subject: [PATCH 09/30] Vm logging on diff --- ethchain/state_manager.go | 2 +- ethchain/transaction.go | 4 ---- ethchain/vm.go | 10 ++++++---- ethutil/value.go | 13 +++++++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d52e418ce..129b30ba6 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -196,7 +196,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) } - receipts, err := sm.ApplyDiff(state, parent, block) + _, err = sm.ApplyDiff(state, parent, block) if err != nil { return err } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 0b4f8d1a4..5686a7edb 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -232,10 +232,6 @@ func (self *Receipt) Cmp(other *Receipt) bool { return false } - if self.CumulativeGasUsed.Cmp(other.CumulativeGasUsed) != 0 { - return false - } - return true } diff --git a/ethchain/vm.go b/ethchain/vm.go index f1794ff77..788bde886 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -184,7 +184,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) - if val.IsEmpty() && len(y.Bytes()) > 0 { + //if val.IsEmpty() && len(y.Bytes()) > 0 { + if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 } else if !val.IsEmpty() && len(y.Bytes()) == 0 { mult = ethutil.Big0 @@ -482,7 +483,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) - vm.Printf(" => %v", vm.vars.Origin) + vm.Printf(" => %x", vm.vars.Origin) case CALLER: caller := closure.caller.Address() stack.Push(ethutil.BigD(caller)) @@ -550,10 +551,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } code := closure.Script[cOff : cOff+l] - fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) + //fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) mem.Set(mOff, l, code) - fmt.Println(Code(mem.Get(mOff, l))) + //fmt.Println(Code(mem.Get(mOff, l))) case GASPRICE: stack.Push(closure.Price) @@ -743,6 +744,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if closure.object.Amount.Cmp(value) < 0 { vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + closure.ReturnGas(gas, nil, nil) stack.Push(ethutil.BigFalse) diff --git a/ethutil/value.go b/ethutil/value.go index b37b33c28..ecb9d1511 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -190,6 +190,19 @@ func (val *Value) Get(idx int) *Value { return NewValue(nil) } +func (self *Value) Copy() *Value { + switch val := self.Val.(type) { + case *big.Int: + return NewValue(new(big.Int).Set(val)) + case []byte: + return NewValue(CopyBytes(val)) + default: + return NewValue(self.Val) + } + + return nil +} + func (val *Value) Cmp(o *Value) bool { return reflect.DeepEqual(val.Val, o.Val) } From 9a931698989fb8db2059a3dee1a431ef94beb59e Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 15 Jul 2014 12:52:44 +0200 Subject: [PATCH 10/30] Rewrote mnemonic word loading to facilitate deployable builds. --- ethcrypto/mnemonic.go | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/ethcrypto/mnemonic.go b/ethcrypto/mnemonic.go index 725846792..b8df2ad6f 100644 --- a/ethcrypto/mnemonic.go +++ b/ethcrypto/mnemonic.go @@ -6,30 +6,35 @@ import ( "os" "path" "path/filepath" - "runtime" "strconv" "strings" ) -func InitWords() []string { - _, thisfile, _, _ := runtime.Caller(1) - filename := path.Join(path.Dir(thisfile), "mnemonic.words.lst") +func InitWords(wordsPath string) { + filename := path.Join(wordsPath, "mnemonic.words.lst") if _, err := os.Stat(filename); os.IsNotExist(err) { - fmt.Printf("reading mnemonic word list file 'mnemonic.words.lst' from source folder failed, looking in current folder.") - dir, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - panic(fmt.Errorf("problem getting current folder: ", err)) - } + fmt.Printf("reading mnemonic word list file from supplied path not found. Looked in %s. Trying next option.\n", filename) + + dir := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "eth-go", "ethcrypto") filename = path.Join(dir, "mnemonic.words.lst") + if _, err := os.Stat(filename); os.IsNotExist(err) { + fmt.Printf("reading mnemonic word list file 'mnemonic.words.lst' from source folder failed: %s.\n", filename) + dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + panic(fmt.Errorf("problem getting current folder: ", err)) + } + filename = path.Join(dir, "mnemonic.words.lst") + } } + content, err := ioutil.ReadFile(filename) if err != nil { - panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err)) + panic(fmt.Errorf("All options for finding the mnemonic word list file 'mnemonic.words.lst' failed: ", err)) } - return strings.Split(string(content), "\n") + words = strings.Split(string(content), "\n") } -var words = InitWords() +var words []string // TODO: See if we can refactor this into a shared util lib if we need it multiple times func IndexOf(slice []string, value string) int64 { From 09bade64666f82a2580e7d24a8bc7655e2113287 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 15:29:54 +0200 Subject: [PATCH 11/30] 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) +} From 34da3b4fa8133a2042919fe344b7bc656fcad4f2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 20:35:07 +0200 Subject: [PATCH 12/30] Moved --- ethchain/state_manager.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 129b30ba6..80362fa77 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethtrie" + _ "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -214,12 +214,14 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - if ethutil.Config.Paranoia { - valid, _ := ethtrie.ParanoiaCheck(state.trie) - if !valid { - err = fmt.Errorf("PARANOIA: World state trie corruption") + /* + if ethutil.Config.Paranoia { + valid, _ := ethtrie.ParanoiaCheck(state.trie) + if !valid { + err = fmt.Errorf("PARANOIA: World state trie corruption") + } } - } + */ if !block.State().Cmp(state) { From 7a410643ac5dc7cc297cbdb094539761230440d0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 20:35:55 +0200 Subject: [PATCH 13/30] Added/changed logging --- ethchain/state_object.go | 5 +++-- ethchain/vm.go | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5791c6ed1..889496e91 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -143,6 +143,7 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value { 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() } @@ -158,9 +159,9 @@ func (self *StateObject) Sync() { valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) if !valid { - self.state.trie = t2 + statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.state.trie.Root, t2.Root) - statelogger.Infoln("Warn: PARANOIA: Different state storage root during copy") + self.state.trie = t2 } } diff --git a/ethchain/vm.go b/ethchain/vm.go index 788bde886..3a956ee83 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -155,6 +155,15 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations if vm.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + closure.object.Sync() + closure.object.state.EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) + }) + } + b := pc.Bytes() if len(b) == 0 { b = []byte{0} @@ -184,7 +193,6 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) - //if val.IsEmpty() && len(y.Bytes()) > 0 { if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 } else if !val.IsEmpty() && len(y.Bytes()) == 0 { From 7c0a27a0f4d750c1977777fc7803592f4208f70e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 20:36:04 +0200 Subject: [PATCH 14/30] Added each callback for storage --- ethpub/types.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethpub/types.go b/ethpub/types.go index 5d41269c8..bd1afc007 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "strings" ) @@ -212,6 +213,10 @@ func (c *PStateObject) IsContract() bool { return false } +func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) { + self.object.State().EachStorage(cb) +} + type KeyVal struct { Key string Value string From 8820d4e5ac4db36ac6466fb2ee36bcff9e773558 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 20:36:11 +0200 Subject: [PATCH 15/30] Decreased timeout --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 8c622aa5c..1e354ca6d 100644 --- a/peer.go +++ b/peer.go @@ -319,7 +319,7 @@ func (p *Peer) HandleInbound() { for atomic.LoadInt32(&p.disconnect) == 0 { // HMM? - time.Sleep(500 * time.Millisecond) + time.Sleep(50 * time.Millisecond) // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) if err != nil { From 14c4f06100d9f06592097c4ee588d0f83f6b17bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Jul 2014 13:20:57 +0200 Subject: [PATCH 16/30] Convert a byte slice to address --- ethutil/bytes.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index d68a69433..07584d0bf 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -149,3 +149,13 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } + +func Address(slice []byte) []byte { + if len(slice) < 20 { + slice = LeftPadBytes(slice, 20) + } else if len(slice) > 20 { + slice = slice[len(slice)-20:] + } + + return slice +} From ed3424ff75b396360990725afc124326dea4ab45 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 11:21:18 +0200 Subject: [PATCH 17/30] 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 66c298b3c..6b849296a 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 80362fa77..a0568c4cd 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 889496e91..cf37586fc 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 3a956ee83..58d1bee89 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 07720be54..f0f3fe5a8 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 f39477ff9..3989a8f45 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 07584d0bf..d16bd6780 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 ecb9d1511..fba7426d1 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{} From 0415e4a637296539e7a5c09282b7aee19268e599 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 14:53:27 +0200 Subject: [PATCH 18/30] Fixed coinbase copy in state --- ethchain/state.go | 3 ++- ethchain/state_manager.go | 4 +++- ethchain/state_object.go | 9 ++++++--- ethchain/state_transition.go | 30 +++++++++++++++++------------- ethchain/vm.go | 2 +- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 6b849296a..9748da1bc 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -61,6 +61,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) + fmt.Printf("balance %v %p\n", stateObject.Amount, stateObject) self.trie.Update(string(addr), string(stateObject.RlpEncode())) @@ -174,7 +175,7 @@ func (s *State) Reset() { func (s *State) Sync() { // Sync all nested states for _, stateObject := range s.stateObjects { - s.UpdateStateObject(stateObject) + //s.UpdateStateObject(stateObject) if stateObject.state == nil { continue diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a0568c4cd..0d4b8ac55 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -120,7 +120,9 @@ func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *Stat done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) - st := NewStateTransition(coinbase, tx, state, block) + + cb := state.GetStateObject(coinbase.Address()) + st := NewStateTransition(cb, tx, state, block) //fmt.Printf("#%d\n", i+1) err = st.TransitionState() if err != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cf37586fc..a4225991a 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -80,6 +80,7 @@ func NewStateObject(addr []byte) *StateObject { object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) object.storage = make(Storage) + object.gasPool = new(big.Int) return object } @@ -183,7 +184,7 @@ func (self *StateObject) Sync() { fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) }) */ - //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { @@ -197,13 +198,13 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - statelogger.DebugDetailf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - statelogger.DebugDetailf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -266,6 +267,7 @@ func (self *StateObject) Copy() *StateObject { stateObject.script = ethutil.CopyBytes(self.script) stateObject.initScript = ethutil.CopyBytes(self.initScript) stateObject.storage = self.storage.Copy() + stateObject.gasPool.Set(self.gasPool) return stateObject } @@ -324,6 +326,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) + c.gasPool = new(big.Int) c.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8cface9e8..8ed528c9f 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -42,7 +42,7 @@ func (self *StateTransition) Coinbase() *StateObject { return self.cb } - self.cb = self.state.GetAccount(self.coinbase) + self.cb = self.state.GetOrNewStateObject(self.coinbase) return self.cb } func (self *StateTransition) Sender() *StateObject { @@ -50,7 +50,7 @@ func (self *StateTransition) Sender() *StateObject { return self.sen } - self.sen = self.state.GetAccount(self.tx.Sender()) + self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) return self.sen } @@ -63,7 +63,7 @@ func (self *StateTransition) Receiver() *StateObject { return self.rec } - self.rec = self.state.GetAccount(self.tx.Recipient) + self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) return self.rec } @@ -174,13 +174,16 @@ func (self *StateTransition) TransitionState() (err error) { return } - /* FIXME - * If tx goes TO "0", goes OOG during init, reverse changes, but initial endowment should happen. The ether is lost forever - */ - var snapshot *State + if sender.Amount.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + } + var snapshot *State // If the receiver is nil it's a contract (\0*32). if tx.CreatesContract() { + // Subtract the (irreversible) amount from the senders account + sender.SubAmount(self.value) + snapshot = self.state.Copy() // Create a new state object for the contract @@ -189,16 +192,17 @@ func (self *StateTransition) TransitionState() (err error) { if receiver == nil { return fmt.Errorf("Unable to create contract") } + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) } else { receiver = self.Receiver() - } - // Transfer value from sender to receiver - if err = self.transferValue(sender, receiver); err != nil { - return - } + // Subtract the amount from the senders account + sender.SubAmount(self.value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) - if snapshot == nil { snapshot = self.state.Copy() } diff --git a/ethchain/vm.go b/ethchain/vm.go index 58d1bee89..4fdf8b31a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -456,7 +456,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case BYTE: require(2) val, th := stack.Popn() - if th.Cmp(big.NewInt(32)) < 0 { + if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 { byt := big.NewInt(int64(val.Bytes()[th.Int64()])) stack.Push(byt) From 90f63657cbcbf6768cd146d17d176d2a0ee4b778 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 15:01:33 +0200 Subject: [PATCH 19/30] Removed debug log --- ethchain/state.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethchain/state.go b/ethchain/state.go index 9748da1bc..684b81102 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -61,7 +61,6 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) - fmt.Printf("balance %v %p\n", stateObject.Amount, stateObject) self.trie.Update(string(addr), string(stateObject.RlpEncode())) From 16f61005006751c38607da089a864350d997c52e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 15:11:09 +0200 Subject: [PATCH 20/30] Removed debug log --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index a4225991a..8e7b5fece 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -184,7 +184,7 @@ func (self *StateObject) Sync() { fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) }) */ - fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { From 3331bb29eaf6569925e0001f1b177c6b17b682af Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 15:35:46 +0200 Subject: [PATCH 21/30] bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ef9bba70..69c6eb0ad 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 0.5.16". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 0.5.20". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. From a626b7ebe1fa5f1029840e25e88a4de426cf64c4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 17:11:00 +0200 Subject: [PATCH 22/30] Fixed string data --- ethutil/bytes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index d16bd6780..34fff7d42 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -118,7 +118,7 @@ func FormatData(data string) []byte { // Simple stupid d := new(big.Int) if data[0:1] == "\"" && data[len(data)-1:] == "\"" { - return RightPadBytes([]byte(data), 32) + return RightPadBytes([]byte(data[1:len(data)-1]), 32) } else if len(data) > 1 && data[:2] == "0x" { d.SetBytes(Hex2Bytes(data[2:])) } else { From 6a19b62db6466f88132f5e41868336ff74ef969c Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 22:01:13 +0200 Subject: [PATCH 23/30] added chainSync event --- ethereum.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ethereum.go b/ethereum.go index 2806dfd9d..f43d37be2 100644 --- a/ethereum.go +++ b/ethereum.go @@ -80,6 +80,8 @@ type Ethereum struct { keyManager *ethcrypto.KeyManager clientIdentity ethwire.ClientIdentity + + isUpToDate bool } func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { @@ -107,6 +109,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager nat: nat, keyManager: keyManager, clientIdentity: clientIdentity, + isUpToDate: true, } ethereum.reactor = ethutil.NewReactorEngine() @@ -371,6 +374,7 @@ func (s *Ethereum) Start(seed bool) { // Start the reaping processes go s.ReapDeadPeerHandler() + go s.update() if seed { s.Seed() @@ -510,3 +514,23 @@ out: ethlogger.Debugln("succesfully disestablished UPnP port mapping") } } + +func (self *Ethereum) update() { + upToDateTimer := time.NewTicker(1 * time.Second) + +out: + for { + select { + case <-upToDateTimer.C: + if self.IsUpToDate() && !self.isUpToDate { + self.reactor.Post("chainSync", false) + self.isUpToDate = true + } else if !self.IsUpToDate() && self.isUpToDate { + self.reactor.Post("chainSync", true) + self.isUpToDate = false + } + case <-self.quit: + break out + } + } +} From 28a146d438b0c11820aef5d9551c6eff929acdec Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 22:30:00 +0200 Subject: [PATCH 24/30] Added find name for namereg --- ethpub/pub.go | 13 +++++++++++++ ethpub/types.go | 1 + 2 files changed, 14 insertions(+) diff --git a/ethpub/pub.go b/ethpub/pub.go index f409d136b..5d01a7a44 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -179,6 +179,19 @@ func FindAddressInNameReg(stateManager *ethchain.StateManager, name string) []by return nil } +func FindNameInNameReg(stateManager *ethchain.StateManager, addr []byte) string { + nameReg := EthereumConfig(stateManager).NameReg() + if nameReg != nil { + addr = ethutil.LeftPadBytes(addr, 32) + + reg := nameReg.GetStorage(ethutil.BigD(addr)) + + return strings.TrimRight(reg.Str(), "\x00") + } + + return "" +} + func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool diff --git a/ethpub/types.go b/ethpub/types.go index bd1afc007..9e5159a4c 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -47,6 +47,7 @@ type PBlock struct { Transactions string `json:"transactions"` Time int64 `json:"time"` Coinbase string `json:"coinbase"` + Name string `json:"name"` GasLimit string `json:"gasLimit"` GasUsed string `json:"gasUsed"` } From 449b9a9d688eaf6a8628a3ae9fa1dd3496f99c71 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 11:57:44 +0200 Subject: [PATCH 25/30] Check if version in known + fix --- ethereum.go | 2 +- peer.go | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ethereum.go b/ethereum.go index f43d37be2..18c1f8a23 100644 --- a/ethereum.go +++ b/ethereum.go @@ -160,7 +160,7 @@ func (s *Ethereum) IsUpToDate() bool { upToDate := true eachPeer(s.peers, func(peer *Peer, e *list.Element) { if atomic.LoadInt32(&peer.connected) == 1 { - if peer.catchingUp == true { + if peer.catchingUp == true && peer.versionKnown { upToDate = false } } diff --git a/peer.go b/peer.go index 1e354ca6d..a900a3192 100644 --- a/peer.go +++ b/peer.go @@ -328,6 +328,7 @@ func (p *Peer) HandleInbound() { for _, msg := range msgs { peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) + nextMsg: switch msg.Type { case ethwire.MsgHandshakeTy: // Version message @@ -373,6 +374,7 @@ func (p *Peer) HandleInbound() { p.diverted = false if !p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { p.SyncWithPeerToLastKnown() + break nextMsg } break } @@ -385,10 +387,11 @@ func (p *Peer) HandleInbound() { p.blocksRequested = p.blocksRequested * 2 peerlogger.Infof("No common ancestor found, requesting %d more blocks.\n", p.blocksRequested) - p.catchingUp = false p.FindCommonParentBlock() - break + break nextMsg } + + p.catchingUp = false } for i := msg.Data.Len() - 1; i >= 0; i-- { From db8170def31e03ecb7086dd257d7c8fce084313f Mon Sep 17 00:00:00 2001 From: Maran Date: Fri, 18 Jul 2014 12:01:08 +0200 Subject: [PATCH 26/30] WIP to expose hashrate to gui --- ethchain/dagger.go | 11 +++++++++-- ethminer/miner.go | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4dda21ff5..dccd2ff5b 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -16,10 +16,16 @@ var powlogger = ethlog.NewLogger("POW") type PoW interface { Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool + GetHashrate() int64 } type EasyPow struct { - hash *big.Int + hash *big.Int + HashRate int64 +} + +func (pow *EasyPow) GetHashrate() int64 { + return pow.HashRate } func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { @@ -39,7 +45,8 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - powlogger.Infoln("Hashing @", int64(hashes), "khash") + pow.HashRate = int64(hashes) + powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash") } sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethminer/miner.go b/ethminer/miner.go index 71d4b2428..f45615b62 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -24,6 +24,10 @@ type Miner struct { quitChan chan bool } +func (self Miner) GetPow() *ethchain.PoW { + return &self.pow +} + func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block From dad29bcaa12d7b170d81a9f5a44a5faa119bd210 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 12:21:11 +0200 Subject: [PATCH 27/30] Added channel for starting/stopping miner --- ethminer/miner.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index f45615b62..fd14571cd 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -24,11 +24,11 @@ type Miner struct { quitChan chan bool } -func (self Miner) GetPow() *ethchain.PoW { - return &self.pow +func (self *Miner) GetPow() ethchain.PoW { + return self.pow } -func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { +func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) *Miner { reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block powQuitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread @@ -59,7 +59,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { miner.txs = ethereum.TxPool().Flush() miner.block = ethereum.BlockChain().NewBlock(miner.coinbase) - return miner + return &miner } func (miner *Miner) Start() { @@ -67,6 +67,8 @@ func (miner *Miner) Start() { //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) go miner.listener() logger.Infoln("Started") + + miner.ethereum.Reactor().Post("miner:start", miner) } func (miner *Miner) listener() { @@ -137,6 +139,8 @@ func (self *Miner) Stop() { close(self.powQuitChan) close(self.quitChan) + + self.ethereum.Reactor().Post("miner:stop", self) } func (self *Miner) mineNewBlock() { From 61cc2ba7d960b2e82886223b78190d552529cb12 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 13:00:22 +0200 Subject: [PATCH 28/30] fixed --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index a900a3192..89032364e 100644 --- a/peer.go +++ b/peer.go @@ -413,7 +413,7 @@ func (p *Peer) HandleInbound() { } } - if msg.Data.Len() == 0 { + if msg.Data.Len() <= 1 { // Set catching up to false if // the peer has nothing left to give p.catchingUp = false From cd9b344506ee2daeb7a6248b2cdb5e7e69db7e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 13:21:40 +0200 Subject: [PATCH 29/30] Fixed range --- ethchain/state_manager.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 0d4b8ac55..a12ce53e5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -151,9 +151,11 @@ done: accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} - original := block.Receipts()[i] - if !original.Cmp(receipt) { - return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + if i < len(block.Receipts()) { + original := block.Receipts()[i] + if !original.Cmp(receipt) { + return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + } } receipts = append(receipts, receipt) From 2762ec22d0693b406ead2f0c07b62e9b66d395e4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 13:50:15 +0200 Subject: [PATCH 30/30] Fixed miner and logger --- ethlog/loggers.go | 2 +- ethminer/miner.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ethlog/loggers.go b/ethlog/loggers.go index ec481edd8..50de213b3 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -96,7 +96,7 @@ func AddLogSystem(logSystem LogSystem) { mutex.Lock() defer mutex.Unlock() if logSystems == nil { - logMessages = make(chan *logMessage) + logMessages = make(chan *logMessage, 10) quit = make(chan bool, 1) go start() } diff --git a/ethminer/miner.go b/ethminer/miner.go index fd14571cd..a50b3712f 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -135,10 +135,9 @@ out: func (self *Miner) Stop() { logger.Infoln("Stopping...") - self.quitChan <- true - close(self.powQuitChan) - close(self.quitChan) + self.quitChan <- true + self.powQuitChan <- ethutil.React{} self.ethereum.Reactor().Post("miner:stop", self) }