ソースを参照

Fixed pending states

obscuren 10 年 前
コミット
7b6a8cc9ae
3 ファイル変更83 行追加29 行削除
  1. 12 0
      miner/miner.go
  2. 52 20
      miner/worker.go
  3. 19 9
      xeth/xeth.go

+ 12 - 0
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()
+}

+ 52 - 20
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) start() {
-	self.mining = true
+func (self *worker) pendingState() *state.StateDB {
+	self.currentMu.Lock()
+	defer self.currentMu.Unlock()
+
+	return self.current.state
+}
 
-	self.quit = make(chan struct{})
+func (self *worker) pendingBlock() *types.Block {
+	self.currentMu.Lock()
+	defer self.currentMu.Unlock()
 
+	return self.current.block
+}
+
+func (self *worker) start() {
 	// 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()
 }
 

+ 19 - 9
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)
 	}