From 40e3d2ab55f32c2458981533f5511e2f24a65c11 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:47:09 +0200 Subject: [PATCH 1/7] Changed CREATE --- ethchain/vm.go | 59 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 909b375ae3..fa839b260c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -617,48 +617,59 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case CREATE: require(3) - value := stack.Pop() - size, offset := stack.Popn() + var ( + err error + value = stack.Pop() + size, offset = stack.Popn() - // Snapshot the current stack so we are able to - // revert back to it later. - snapshot := vm.state.Copy() + // Snapshot the current stack so we are able to + // revert back to it later. + snapshot = vm.state.Copy() + ) // Generate a new address addr := ethcrypto.CreateAddress(closure.caller.Address(), closure.caller.N()) + for i := int64(0); vm.state.GetStateObject(addr) != nil; i++ { + t := new(big.Int).Set(closure.caller.N()) + addr = ethcrypto.CreateAddress(closure.caller.Address(), t.Add(t, big.NewInt(i))) + } vm.Printf(" (*) %x", addr).Endl() // Create a new contract contract := vm.state.NewStateObject(addr) - contract.Amount = value - - // Set the init script - contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() - // Transfer all remaining gas to the new - // contract so it may run the init script - gas := new(big.Int).Set(closure.Gas) - - // Create the closure - c := NewClosure(closure.caller, - closure.Object(), - contract.initScript, - vm.state, - gas, - closure.Price) - // Call the closure and set the return value as - // main script. - var err error - c.Script, gas, err = c.Call(vm, nil) + if contract.Amount.Cmp(value) >= 0 { + closure.object.SubAmount(value) + contract.AddAmount(value) + + // Set the init script + contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() + // Transfer all remaining gas to the new + // contract so it may run the init script + gas := new(big.Int).Set(closure.Gas) + closure.UseGas(closure.Gas) + + // Create the closure + c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) + // Call the closure and set the return value as + // main script. + c.Script, err, _ = Call(vm, c, nil) + } else { + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + } if err != nil { stack.Push(ethutil.BigFalse) // Revert the state as it was before. vm.state.Set(snapshot) + + vm.Printf("CREATE err %v", err) } else { stack.Push(ethutil.BigD(addr)) + vm.Printf("CREATE success") } + vm.Endl() case CALL: require(7) From 8de099ae753b2ea427a0f43abbd04019c5f76ddf Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:47:18 +0200 Subject: [PATCH 2/7] Added paranoia check --- ethtrie/trie.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ethtrie/trie.go b/ethtrie/trie.go index 194c980069..38c78e7f46 100644 --- a/ethtrie/trie.go +++ b/ethtrie/trie.go @@ -1,6 +1,7 @@ package ethtrie import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" @@ -8,6 +9,19 @@ import ( "sync" ) +func ParanoiaCheck(t1 *Trie) (bool, *Trie) { + t2 := NewTrie(ethutil.Config.Db, "") + + t1.NewIterator().Each(func(key string, v *ethutil.Value) { + t2.Update(key, v.Str()) + }) + + a := ethutil.NewValue(t2.Root).Bytes() + b := ethutil.NewValue(t1.Root).Bytes() + + return bytes.Compare(a, b) == 0, t2 +} + func (s *Cache) Len() int { return len(s.nodes) } From 2f9bc2ab754ff85235ebb0b0b41b9b36ef30253a Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:47:33 +0200 Subject: [PATCH 3/7] Removed old code --- ethchain/state.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 3d05ff582c..7ddf7916f0 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -93,10 +93,6 @@ func (self *State) ResetStateObject(stateObject *StateObject) { func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() - if self.stateObjects[string(addr)] == nil { - self.stateObjects[string(addr)] = stateObject - } - ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) self.trie.Update(string(addr), string(stateObject.RlpEncode())) @@ -131,7 +127,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - //statelogger.Infof("(+) %x\n", addr) + statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject From 35ae9e3aa89dc0e3be1cabed313996a7d49f6628 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:48:10 +0200 Subject: [PATCH 4/7] Paranoia check --- ethchain/state_manager.go | 9 +++++++++ ethchain/state_transition.go | 16 ++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index dea82cae35..c42238e5cc 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,6 +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/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -204,7 +205,15 @@ 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 comparison failed") + } + } + if !block.State().Cmp(state) { + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 9e7ef3efd1..898344c2ed 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -1,7 +1,6 @@ package ethchain import ( - "bytes" "fmt" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -264,23 +263,16 @@ func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr ret, _, err = closure.Call(vm, data) deepErr = vm.err != nil - Paranoia := ethutil.Config.Paranoia - if Paranoia { + if ethutil.Config.Paranoia { var ( context = closure.object trie = context.state.trie - trie2 = ethtrie.NewTrie(ethutil.Config.Db, "") ) - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - trie2.Update(key, v.Str()) - }) - - a := ethutil.NewValue(trie2.Root).Bytes() - b := ethutil.NewValue(context.state.trie.Root).Bytes() - if bytes.Compare(a, b) != 0 { + valid, t2 := ethtrie.ParanoiaCheck(trie) + if !valid { // TODO FIXME ASAP - context.state.trie = trie2 + context.state.trie = t2 /* statelogger.Debugf("(o): %x\n", trie.Root) trie.NewIterator().Each(func(key string, v *ethutil.Value) { From 81bc721c5cd0330547e18bfb710d68d60da4dd46 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 3 Jul 2014 10:03:58 +0200 Subject: [PATCH 5/7] Fixed address generation --- ethcrypto/crypto.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index 8cb0be88c9..b4bb881a01 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -3,8 +3,8 @@ package ethcrypto import ( "code.google.com/p/go.crypto/ripemd160" "crypto/sha256" + "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" - "math/big" ) func Sha256Bin(data []byte) []byte { @@ -28,8 +28,6 @@ func Sha3Bin(data []byte) []byte { } // Creates an ethereum address given the bytes and the nonce -func CreateAddress(b []byte, nonce *big.Int) []byte { - addrBytes := append(b, nonce.Bytes()...) - - return Sha3Bin(addrBytes)[12:] +func CreateAddress(b []byte, nonce uint64) []byte { + return Sha3Bin(ethutil.NewValue([]interface{}{b, nonce}).Encode())[12:] } From 5b8dde96026b123147733bb5cdf88b7774725015 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 3 Jul 2014 10:04:38 +0200 Subject: [PATCH 6/7] Fixed CREATE op. Fixes #87 --- ethchain/vm.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index fa839b260c..35443a6ba8 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -35,7 +35,6 @@ func CalculateTxGas(initSize *big.Int) *big.Int { } type Vm struct { - txPool *TxPool // Stack for processing contracts stack *Stack // non-persistent key/value memory storage @@ -628,11 +627,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - addr := ethcrypto.CreateAddress(closure.caller.Address(), closure.caller.N()) - for i := int64(0); vm.state.GetStateObject(addr) != nil; i++ { - t := new(big.Int).Set(closure.caller.N()) - addr = ethcrypto.CreateAddress(closure.caller.Address(), t.Add(t, big.NewInt(i))) + addr := ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce) + for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ { + ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce+i) } + closure.object.Nonce++ vm.Printf(" (*) %x", addr).Endl() @@ -643,7 +642,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { contract.AddAmount(value) // Set the init script - contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() + contract.initScript = mem.Get(offset.Int64(), size.Int64()) // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) @@ -653,7 +652,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) // Call the closure and set the return value as // main script. - c.Script, err, _ = Call(vm, c, nil) + contract.script, err, _ = Call(vm, c, nil) } else { err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) } From 5d6713920625b82df2b55728b2cbb9f7f3df2025 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 3 Jul 2014 10:05:02 +0200 Subject: [PATCH 7/7] Fix --- ethchain/state_manager.go | 2 +- ethchain/state_transition.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c42238e5cc..027c6a0856 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -208,7 +208,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { if ethutil.Config.Paranoia { valid, _ := ethtrie.ParanoiaCheck(state.trie) if !valid { - err = fmt.Errorf("PARANOIA: World state trie comparison failed") + err = fmt.Errorf("PARANOIA: World state trie corruption") } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 898344c2ed..31196d2d7c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -53,6 +53,7 @@ func (self *StateTransition) Sender() *StateObject { } self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen } func (self *StateTransition) Receiver() *StateObject {