From ba295ec6feb8288bb1e0cacca4ed2c3c5515d133 Mon Sep 17 00:00:00 2001 From: Jason Carver Date: Thu, 21 May 2015 08:50:01 -0700 Subject: [PATCH 1/5] 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 { From 8a7fb5fd342ee9d4c2e8609d4c008f12c5956a41 Mon Sep 17 00:00:00 2001 From: Jason Carver Date: Sat, 23 May 2015 12:00:18 -0700 Subject: [PATCH 2/5] do not export constant for when to log a deep block you mined --- miner/worker.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 5b4af64cb4..937e98e438 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -38,7 +38,7 @@ type Agent interface { GetHashRate() int64 } -const MINING_LOG_AT_DEPTH = 5 +const miningLogAtDepth = 5 type UInt64RingBuffer struct { ints []uint64 //array of all integers in buffer @@ -219,7 +219,7 @@ out: func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *UInt64RingBuffer) (minedBlocks *UInt64RingBuffer) { if prevMinedBlocks == nil { - minedBlocks = &UInt64RingBuffer{next: 0, ints: make([]uint64, MINING_LOG_AT_DEPTH)} + minedBlocks = &UInt64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth)} } else { minedBlocks = prevMinedBlocks } @@ -353,9 +353,9 @@ 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 + inspectBlockNum := checkBlockNum - miningLogAtDepth if self.isBlockLocallyMined(inspectBlockNum) { - glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", MINING_LOG_AT_DEPTH, inspectBlockNum) + glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum) } } } From f1ce5877badf5624a5fc5214dc18086b930c8d38 Mon Sep 17 00:00:00 2001 From: Jason Carver Date: Sat, 23 May 2015 12:04:00 -0700 Subject: [PATCH 3/5] do not export ring buffer struct --- miner/worker.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 937e98e438..6f618d632d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -40,7 +40,7 @@ type Agent interface { const miningLogAtDepth = 5 -type UInt64RingBuffer struct { +type uint64RingBuffer struct { ints []uint64 //array of all integers in buffer next int //where is the next insertion? assert 0 <= next < len(ints) } @@ -61,7 +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) + 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 @@ -217,9 +217,9 @@ out: events.Unsubscribe() } -func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *UInt64RingBuffer) (minedBlocks *UInt64RingBuffer) { +func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *uint64RingBuffer) (minedBlocks *uint64RingBuffer) { if prevMinedBlocks == nil { - minedBlocks = &UInt64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth)} + minedBlocks = &uint64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth)} } else { minedBlocks = prevMinedBlocks } From 6019f1bb0a0744ffa52bf1ab93309c1a6dd9063c Mon Sep 17 00:00:00 2001 From: Jason Carver Date: Tue, 26 May 2015 18:54:56 -0700 Subject: [PATCH 4/5] deep-mining-log: only track non-stale blocks if you track stale blocks, then you quickly overflow your ring buffer in the local network case where you're mining every block and generating a lot of stales. --- miner/worker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 6f618d632d..fac2e65683 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -248,12 +248,12 @@ func (self *worker) wait() { canonBlock := self.chain.GetBlockByNumber(block.NumberU64()) if canonBlock != nil && canonBlock.Hash() != block.Hash() { stale = "stale-" + } else { + self.current.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), self.current.localMinedBlocks) } 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(), From de12183d3824c25763e8996c14f8b5a52832fad6 Mon Sep 17 00:00:00 2001 From: Jason Carver Date: Tue, 26 May 2015 18:55:52 -0700 Subject: [PATCH 5/5] deep-mining-log: need ring buffer to be one bigger for all-blocks-mined case --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index fac2e65683..12ed656268 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -219,7 +219,7 @@ out: func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *uint64RingBuffer) (minedBlocks *uint64RingBuffer) { if prevMinedBlocks == nil { - minedBlocks = &uint64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth)} + minedBlocks = &uint64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth + 1)} } else { minedBlocks = prevMinedBlocks }