From 7b6a8cc9ae56856f1c292243b57d658b67b92621 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 7 Apr 2015 12:32:55 +0200 Subject: [PATCH] Fixed pending states --- miner/miner.go | 12 ++++++++ miner/worker.go | 74 +++++++++++++++++++++++++++++++++++-------------- xeth/xeth.go | 28 +++++++++++++------ 3 files changed, 84 insertions(+), 30 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 23e48db407..aa6c059ba6 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -6,6 +6,8 @@ import ( "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/pow" ) @@ -26,6 +28,7 @@ func New(eth core.Backend, pow pow.PoW, minerThreads int) *Miner { for i := 0; i < minerThreads; i++ { miner.worker.register(NewCpuMiner(i, pow)) } + return miner } @@ -40,6 +43,7 @@ func (self *Miner) Start(coinbase common.Address) { self.pow.(*ethash.Ethash).UpdateDAG() self.worker.start() + self.worker.commitNewWork() } @@ -61,3 +65,11 @@ func (self *Miner) HashRate() int64 { func (self *Miner) SetExtra(extra []byte) { self.worker.extra = extra } + +func (self *Miner) PendingState() *state.StateDB { + return self.worker.pendingState() +} + +func (self *Miner) PendingBlock() *types.Block { + return self.worker.pendingBlock() +} diff --git a/miner/worker.go b/miner/worker.go index da10cf7cdb..ffd4af7d3e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -76,16 +76,20 @@ type worker struct { coinbase common.Address extra []byte - current *environment + currentMu sync.Mutex + current *environment uncleMu sync.Mutex possibleUncles map[common.Hash]*types.Block - mining bool + txQueueMu sync.Mutex + txQueue map[common.Hash]*types.Transaction + + mining int64 } func newWorker(coinbase common.Address, eth core.Backend) *worker { - return &worker{ + worker := &worker{ eth: eth, mux: eth.EventMux(), recv: make(chan *types.Block), @@ -93,28 +97,45 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker { proc: eth.BlockProcessor(), possibleUncles: make(map[common.Hash]*types.Block), coinbase: coinbase, + txQueue: make(map[common.Hash]*types.Transaction), } + go worker.update() + go worker.wait() + + worker.quit = make(chan struct{}) + + worker.commitNewWork() + + return worker +} + +func (self *worker) pendingState() *state.StateDB { + self.currentMu.Lock() + defer self.currentMu.Unlock() + + return self.current.state +} + +func (self *worker) pendingBlock() *types.Block { + self.currentMu.Lock() + defer self.currentMu.Unlock() + + return self.current.block } func (self *worker) start() { - self.mining = true - - self.quit = make(chan struct{}) - // spin up agents for _, agent := range self.agents { agent.Start() } - go self.update() - go self.wait() + atomic.StoreInt64(&self.mining, 1) } func (self *worker) stop() { - self.mining = false - atomic.StoreInt64(&self.atWork, 0) + atomic.StoreInt64(&self.mining, 0) - close(self.quit) + atomic.StoreInt64(&self.atWork, 0) } func (self *worker) register(agent Agent) { @@ -123,7 +144,7 @@ func (self *worker) register(agent Agent) { } func (self *worker) update() { - events := self.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}) + events := self.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{}) timer := time.NewTicker(2 * time.Second) @@ -138,6 +159,10 @@ out: self.uncleMu.Lock() self.possibleUncles[ev.Block.Hash()] = ev.Block self.uncleMu.Unlock() + case core.TxPreEvent: + if atomic.LoadInt64(&self.mining) == 0 { + self.commitNewWork() + } } case <-self.quit: @@ -152,7 +177,7 @@ out: } // XXX In case all mined a possible uncle - if atomic.LoadInt64(&self.atWork) == 0 { + if atomic.LoadInt64(&self.atWork) == 0 && atomic.LoadInt64(&self.mining) == 1 { self.commitNewWork() } } @@ -192,7 +217,7 @@ func (self *worker) wait() { } func (self *worker) push() { - if self.mining { + if atomic.LoadInt64(&self.mining) == 1 { self.current.block.Header().GasUsed = self.current.totalUsedGas self.current.block.SetRoot(self.current.state.Root()) @@ -205,12 +230,7 @@ func (self *worker) push() { } } -func (self *worker) commitNewWork() { - self.mu.Lock() - defer self.mu.Unlock() - self.uncleMu.Lock() - defer self.uncleMu.Unlock() - +func (self *worker) makeCurrent() { block := self.chain.NewBlock(self.coinbase) if block.Time() == self.chain.CurrentBlock().Time() { block.Header().Time++ @@ -224,6 +244,17 @@ func (self *worker) commitNewWork() { parent := self.chain.GetBlock(self.current.block.ParentHash()) self.current.coinbase.SetGasPool(core.CalcGasLimit(parent, self.current.block)) +} + +func (self *worker) commitNewWork() { + self.mu.Lock() + defer self.mu.Unlock() + self.uncleMu.Lock() + defer self.uncleMu.Unlock() + self.currentMu.Lock() + defer self.currentMu.Unlock() + + self.makeCurrent() transactions := self.eth.TxPool().GetTransactions() sort.Sort(types.TxByNonce{transactions}) @@ -287,6 +318,7 @@ gasLimit: core.AccumulateRewards(self.current.state, self.current.block) self.current.state.Update() + self.push() } diff --git a/xeth/xeth.go b/xeth/xeth.go index 825f26017c..b8d9ecb088 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -136,13 +136,16 @@ func cTopics(t [][]string) [][]common.Hash { func (self *XEth) RemoteMining() *miner.RemoteAgent { return self.agent } func (self *XEth) AtStateNum(num int64) *XEth { - block := self.getBlockByHeight(num) - var st *state.StateDB - if block != nil { - st = state.New(block.Root(), self.backend.StateDb()) - } else { - st = self.backend.ChainManager().State() + switch num { + case -2: + st = self.backend.Miner().PendingState().Copy() + default: + if block := self.getBlockByHeight(num); block != nil { + st = state.New(block.Root(), self.backend.StateDb()) + } else { + st = state.New(self.backend.ChainManager().GetBlockByNumber(0).Root(), self.backend.StateDb()) + } } return self.withState(st) @@ -164,9 +167,16 @@ func (self *XEth) Whisper() *Whisper { return self.whisper } func (self *XEth) getBlockByHeight(height int64) *types.Block { var num uint64 - if height < 0 { - num = self.CurrentBlock().NumberU64() + uint64(-1*height) - } else { + switch height { + case -2: + return self.backend.Miner().PendingBlock() + case -1: + return self.CurrentBlock() + default: + if height < 0 { + return nil + } + num = uint64(height) }