From ba295ec6feb8288bb1e0cacca4ed2c3c5515d133 Mon Sep 17 00:00:00 2001 From: Jason Carver Date: Thu, 21 May 2015 08:50:01 -0700 Subject: [PATCH] Log locally mined blocks, after they are 5-deep in the chain This helps determine which blocks are unlikely to end up as uncles * Store the 5 most recent locally mined block numbers * On every imported block, check if the 5-deep block num is in that store * Also confirm that the block is signed with miner's coinbase Why not just check the coinbase? This log is useful if you're running multiple miners and want to know if *this* miner is performing well. --- miner/worker.go | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/miner/worker.go b/miner/worker.go index 5e4ff7510f..5b4af64cb4 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -38,6 +38,13 @@ type Agent interface { GetHashRate() int64 } +const MINING_LOG_AT_DEPTH = 5 + +type UInt64RingBuffer struct { + ints []uint64 //array of all integers in buffer + next int //where is the next insertion? assert 0 <= next < len(ints) +} + // environment is the workers current environment and holds // all of the current state information type environment struct { @@ -54,6 +61,7 @@ type environment struct { lowGasTransactors *set.Set ownedAccounts *set.Set lowGasTxs types.Transactions + localMinedBlocks *UInt64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion) } // env returns a new environment for the current cycle @@ -209,6 +217,18 @@ out: events.Unsubscribe() } +func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *UInt64RingBuffer) (minedBlocks *UInt64RingBuffer) { + if prevMinedBlocks == nil { + minedBlocks = &UInt64RingBuffer{next: 0, ints: make([]uint64, MINING_LOG_AT_DEPTH)} + } else { + minedBlocks = prevMinedBlocks + } + + minedBlocks.ints[minedBlocks.next] = blockNumber + minedBlocks.next = (minedBlocks.next + 1) % len(minedBlocks.ints) + return minedBlocks +} + func (self *worker) wait() { for { for block := range self.recv { @@ -232,6 +252,8 @@ func (self *worker) wait() { glog.V(logger.Info).Infof("🔨 Mined %sblock #%v (%x)", stale, block.Number(), block.Hash().Bytes()[:4]) + self.current.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), self.current.localMinedBlocks) + jsonlogger.LogJson(&logger.EthMinerNewBlock{ BlockHash: block.Hash().Hex(), BlockNumber: block.Number(), @@ -286,6 +308,9 @@ func (self *worker) makeCurrent() { current.ignoredTransactors = set.New() current.lowGasTransactors = set.New() current.ownedAccounts = accountAddressesSet(accounts) + if self.current != nil { + current.localMinedBlocks = self.current.localMinedBlocks + } parent := self.chain.GetBlock(current.block.ParentHash()) current.coinbase.SetGasPool(core.CalcGasLimit(parent)) @@ -304,6 +329,38 @@ func (w *worker) setGasPrice(p *big.Int) { w.mux.Post(core.GasPriceChanged{w.gasPrice}) } +func (self *worker) isBlockLocallyMined(deepBlockNum uint64) bool { + //Did this instance mine a block at {deepBlockNum} ? + var isLocal = false + for idx, blockNum := range self.current.localMinedBlocks.ints { + if deepBlockNum == blockNum { + isLocal = true + self.current.localMinedBlocks.ints[idx] = 0 //prevent showing duplicate logs + break + } + } + //Short-circuit on false, because the previous and following tests must both be true + if !isLocal { + return false + } + + //Does the block at {deepBlockNum} send earnings to my coinbase? + var block = self.chain.GetBlockByNumber(deepBlockNum) + return block.Header().Coinbase == self.coinbase +} + +func (self *worker) logLocalMinedBlocks(previous *environment) { + if previous != nil && self.current.localMinedBlocks != nil { + nextBlockNum := self.current.block.Number().Uint64() + for checkBlockNum := previous.block.Number().Uint64(); checkBlockNum < nextBlockNum; checkBlockNum++ { + inspectBlockNum := checkBlockNum - MINING_LOG_AT_DEPTH + if self.isBlockLocallyMined(inspectBlockNum) { + glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", MINING_LOG_AT_DEPTH, inspectBlockNum) + } + } + } +} + func (self *worker) commitNewWork() { self.mu.Lock() defer self.mu.Unlock() @@ -312,6 +369,7 @@ func (self *worker) commitNewWork() { self.currentMu.Lock() defer self.currentMu.Unlock() + previous := self.current self.makeCurrent() current := self.current @@ -347,6 +405,7 @@ func (self *worker) commitNewWork() { // We only care about logging if we're actually mining if atomic.LoadInt32(&self.mining) == 1 { glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles\n", current.block.Number(), current.tcount, len(uncles)) + self.logLocalMinedBlocks(previous) } for _, hash := range badUncles {