From 3c35ba7c31423da644c5fb73030af4673cff90ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 01:12:28 +0200 Subject: [PATCH] Fixed state overwriting issue --- ethchain/state.go | 10 +++------- ethchain/state_object.go | 1 + ethchain/vm.go | 6 +++--- ethpub/pub.go | 2 +- ethutil/trie.go | 12 ++++++++++++ 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index db715f1cb..6ec6916f4 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -60,6 +60,7 @@ func (s *State) GetStateObject(addr []byte) *StateObject { // Check if there's a cached state for this contract cachedStateObject := s.states[string(addr)] if cachedStateObject != nil { + //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) stateObject.state = cachedStateObject } @@ -70,8 +71,9 @@ func (s *State) GetStateObject(addr []byte) *StateObject { func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() - if object.state != nil { + if object.state != nil && s.states[string(addr)] == nil { s.states[string(addr)] = object.state + //fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4]) } ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) @@ -81,12 +83,6 @@ func (s *State) UpdateStateObject(object *StateObject) { s.manifest.AddObjectChange(object) } -func (s *State) SetStateObject(stateObject *StateObject) { - s.states[string(stateObject.address)] = stateObject.state - - s.UpdateStateObject(stateObject) -} - func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cb6211ea6..8e059f334 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -78,6 +78,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) + //fmt.Println("storing", val.BigInt(), "@", num) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index e732d22a4..c4304e5ac 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -448,7 +448,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigD(addr)) - vm.state.SetStateObject(contract) + vm.state.UpdateStateObject(contract) } case oCALL: require(7) @@ -497,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigTrue) } - vm.state.SetStateObject(contract) + vm.state.UpdateStateObject(contract) mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { @@ -515,7 +515,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - vm.state.SetStateObject(receiver) + vm.state.UpdateStateObject(receiver) closure.object.state.Purge() diff --git a/ethpub/pub.go b/ethpub/pub.go index fb1018d47..ec187e276 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -162,7 +162,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) tx.Nonce = acc.Nonce acc.Nonce += 1 - lib.stateManager.TransState().SetStateObject(acc) + lib.stateManager.TransState().UpdateStateObject(acc) tx.Sign(keyPair.PrivateKey) lib.txPool.QueueTransaction(tx) diff --git a/ethutil/trie.go b/ethutil/trie.go index 4d088ccff..c993e4d8f 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -3,8 +3,13 @@ package ethutil import ( "fmt" "reflect" + "sync" ) +func (s *Cache) Len() int { + return len(s.nodes) +} + // TODO // A StateObject is an object that has a state root // This is goig to be the object for the second level caching (the caching of object which have a state such as contracts) @@ -113,6 +118,7 @@ func (cache *Cache) Undo() { // Please note that the data isn't persisted unless `Sync` is // explicitly called. type Trie struct { + mut sync.RWMutex prevRoot interface{} Root interface{} //db Database @@ -157,12 +163,18 @@ func (t *Trie) Cache() *Cache { * Public (query) interface functions */ func (t *Trie) Update(key string, value string) { + t.mut.Lock() + defer t.mut.Unlock() + k := CompactHexDecode(key) t.Root = t.UpdateState(t.Root, k, value) } func (t *Trie) Get(key string) string { + t.mut.RLock() + defer t.mut.RUnlock() + k := CompactHexDecode(key) c := NewValue(t.GetState(t.Root, k))