diff options
-rw-r--r-- | cmd/geth/js.go | 2 | ||||
-rw-r--r-- | core/state/state_object.go | 1 | ||||
-rw-r--r-- | core/state/state_test.go | 104 | ||||
-rw-r--r-- | miner/agent.go | 10 | ||||
-rw-r--r-- | rpc/comms/http.go | 4 |
5 files changed, 117 insertions, 4 deletions
diff --git a/cmd/geth/js.go b/cmd/geth/js.go index c31deefdd..3e3600705 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -121,7 +121,7 @@ func keywordCompleter(line string) []string { } func apiWordCompleter(line string, pos int) (head string, completions []string, tail string) { - if len(line) == 0 { + if len(line) == 0 || pos == 0 { return "", nil, "" } diff --git a/core/state/state_object.go b/core/state/state_object.go index c76feb774..0af0fbd5a 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -263,6 +263,7 @@ func (self *StateObject) Copy() *StateObject { stateObject.gasPool.Set(self.gasPool) stateObject.remove = self.remove stateObject.dirty = self.dirty + stateObject.deleted = self.deleted return stateObject } diff --git a/core/state/state_test.go b/core/state/state_test.go index 5972d266a..60836738e 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -17,6 +17,7 @@ package state import ( + "bytes" "math/big" "testing" @@ -117,3 +118,106 @@ func (s *StateSuite) TestSnapshot(c *checker.C) { c.Assert(data1, checker.DeepEquals, res) } + +// use testing instead of checker because checker does not support +// printing/logging in tests (-check.vv does not work) +func TestSnapshot2(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + state := New(common.Hash{}, db) + + stateobjaddr0 := toAddr([]byte("so0")) + stateobjaddr1 := toAddr([]byte("so1")) + var storageaddr common.Hash + + data0 := common.BytesToHash([]byte{17}) + data1 := common.BytesToHash([]byte{18}) + + state.SetState(stateobjaddr0, storageaddr, data0) + state.SetState(stateobjaddr1, storageaddr, data1) + + // db, trie are already non-empty values + so0 := state.GetStateObject(stateobjaddr0) + so0.balance = big.NewInt(42) + so0.nonce = 43 + so0.gasPool = big.NewInt(44) + so0.code = []byte{'c', 'a', 'f', 'e'} + so0.codeHash = so0.CodeHash() + so0.remove = true + so0.deleted = false + so0.dirty = false + state.SetStateObject(so0) + + // and one with deleted == true + so1 := state.GetStateObject(stateobjaddr1) + so1.balance = big.NewInt(52) + so1.nonce = 53 + so1.gasPool = big.NewInt(54) + so1.code = []byte{'c', 'a', 'f', 'e', '2'} + so1.codeHash = so1.CodeHash() + so1.remove = true + so1.deleted = true + so1.dirty = true + state.SetStateObject(so1) + + so1 = state.GetStateObject(stateobjaddr1) + if so1 != nil { + t.Fatalf("deleted object not nil when getting") + } + + snapshot := state.Copy() + state.Set(snapshot) + + so0Restored := state.GetStateObject(stateobjaddr0) + so1Restored := state.GetStateObject(stateobjaddr1) + // non-deleted is equal (restored) + compareStateObjects(so0Restored, so0, t) + // deleted should be nil, both before and after restore of state copy + if so1Restored != nil { + t.Fatalf("deleted object not nil after restoring snapshot") + } +} + +func compareStateObjects(so0, so1 *StateObject, t *testing.T) { + if so0.address != so1.address { + t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address) + } + if so0.balance.Cmp(so1.balance) != 0 { + t.Fatalf("Balance mismatch: have %v, want %v", so0.balance, so1.balance) + } + if so0.nonce != so1.nonce { + t.Fatalf("Nonce mismatch: have %v, want %v", so0.nonce, so1.nonce) + } + if !bytes.Equal(so0.codeHash, so1.codeHash) { + t.Fatalf("CodeHash mismatch: have %v, want %v", so0.codeHash, so1.codeHash) + } + if !bytes.Equal(so0.code, so1.code) { + t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code) + } + if !bytes.Equal(so0.initCode, so1.initCode) { + t.Fatalf("InitCode mismatch: have %v, want %v", so0.initCode, so1.initCode) + } + + for k, v := range so1.storage { + if so0.storage[k] != v { + t.Fatalf("Storage key %s mismatch: have %v, want %v", k, so0.storage[k], v) + } + } + for k, v := range so0.storage { + if so1.storage[k] != v { + t.Fatalf("Storage key %s mismatch: have %v, want none.", k, v) + } + } + + if so0.gasPool.Cmp(so1.gasPool) != 0 { + t.Fatalf("GasPool mismatch: have %v, want %v", so0.gasPool, so1.gasPool) + } + if so0.remove != so1.remove { + t.Fatalf("Remove mismatch: have %v, want %v", so0.remove, so1.remove) + } + if so0.deleted != so1.deleted { + t.Fatalf("Deleted mismatch: have %v, want %v", so0.deleted, so1.deleted) + } + if so0.dirty != so1.dirty { + t.Fatalf("Dirty mismatch: have %v, want %v", so0.dirty, so1.dirty) + } +} diff --git a/miner/agent.go b/miner/agent.go index 2f8d9fee4..7ccf8d2e0 100644 --- a/miner/agent.go +++ b/miner/agent.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/pow" + "sync/atomic" ) type CpuAgent struct { @@ -35,6 +36,8 @@ type CpuAgent struct { index int pow pow.PoW + + isMining int32 // isMining indicates whether the agent is currently mining } func NewCpuAgent(index int, pow pow.PoW) *CpuAgent { @@ -60,6 +63,10 @@ func (self *CpuAgent) Stop() { func (self *CpuAgent) Start() { self.mu.Lock() defer self.mu.Unlock() + + if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) { + return // agent already started + } self.quit = make(chan struct{}) // creating current op ch makes sure we're not closing a nil ch @@ -99,10 +106,11 @@ done: case <-self.workCh: default: close(self.workCh) - break done } } + + atomic.StoreInt32(&self.isMining, 0) } func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) { diff --git a/rpc/comms/http.go b/rpc/comms/http.go index c165aa27e..f4a930d0e 100644 --- a/rpc/comms/http.go +++ b/rpc/comms/http.go @@ -271,13 +271,13 @@ func (self *httpClient) Send(req interface{}) error { reply, _ := ioutil.ReadAll(resp.Body) var rpcSuccessResponse shared.SuccessResponse if err = self.codec.Decode(reply, &rpcSuccessResponse); err == nil { - self.lastRes = rpcSuccessResponse.Result + self.lastRes = &rpcSuccessResponse self.lastErr = err return nil } else { var rpcErrorResponse shared.ErrorResponse if err = self.codec.Decode(reply, &rpcErrorResponse); err == nil { - self.lastRes = rpcErrorResponse.Error + self.lastRes = &rpcErrorResponse self.lastErr = err return nil } else { |