diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 377a3ebae..a2e61bbc0 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -137,9 +137,8 @@ var ( errRecentlySigned = errors.New("recently signed") ) -// SignerFn is a signer callback function to request a header to be signed by a -// backing account. -type SignerFn func(accounts.Account, string, []byte) ([]byte, error) +// SignerFn hashes and signs the data to be signed by a backing account. +type SignerFn func(signer accounts.Account, mimeType string, message []byte) ([]byte, error) // ecrecover extracts the Ethereum account address from a signed header. func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) { diff --git a/miner/worker.go b/miner/worker.go index 42a98e6af..177e72728 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -305,6 +305,28 @@ func (w *worker) close() { close(w.exitCh) } +// recalcRecommit recalculates the resubmitting interval upon feedback. +func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) time.Duration { + var ( + prevF = float64(prev.Nanoseconds()) + next float64 + ) + if inc { + next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) + max := float64(maxRecommitInterval.Nanoseconds()) + if next > max { + next = max + } + } else { + next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) + min := float64(minRecommit.Nanoseconds()) + if next < min { + next = min + } + } + return time.Duration(int64(next)) +} + // newWorkLoop is a standalone goroutine to submit new mining work upon received events. func (w *worker) newWorkLoop(recommit time.Duration) { var ( @@ -327,27 +349,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) { timer.Reset(recommit) atomic.StoreInt32(&w.newTxs, 0) } - // recalcRecommit recalculates the resubmitting interval upon feedback. - recalcRecommit := func(target float64, inc bool) { - var ( - prev = float64(recommit.Nanoseconds()) - next float64 - ) - if inc { - next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) - // Recap if interval is larger than the maximum time interval - if next > float64(maxRecommitInterval.Nanoseconds()) { - next = float64(maxRecommitInterval.Nanoseconds()) - } - } else { - next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) - // Recap if interval is less than the user specified minimum - if next < float64(minRecommit.Nanoseconds()) { - next = float64(minRecommit.Nanoseconds()) - } - } - recommit = time.Duration(int64(next)) - } // clearPending cleans the stale pending tasks. clearPending := func(number uint64) { w.pendingMu.Lock() @@ -400,11 +401,12 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // Adjust resubmit interval by feedback. if adjust.inc { before := recommit - recalcRecommit(float64(recommit.Nanoseconds())/adjust.ratio, true) + target := float64(recommit.Nanoseconds()) / adjust.ratio + recommit = recalcRecommit(minRecommit, recommit, target, true) log.Trace("Increase miner recommit interval", "from", before, "to", recommit) } else { before := recommit - recalcRecommit(float64(minRecommit.Nanoseconds()), false) + recommit = recalcRecommit(minRecommit, recommit, float64(minRecommit.Nanoseconds()), false) log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) } @@ -553,7 +555,7 @@ func (w *worker) taskLoop() { continue } w.pendingMu.Lock() - w.pendingTasks[w.engine.SealHash(task.block.Header())] = task + w.pendingTasks[sealHash] = task w.pendingMu.Unlock() if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { @@ -974,13 +976,9 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) // and commits new work if consensus engine is running. func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { // Deep copy receipts here to avoid interaction between different tasks. - receipts := make([]*types.Receipt, len(w.current.receipts)) - for i, l := range w.current.receipts { - receipts[i] = new(types.Receipt) - *receipts[i] = *l - } + receipts := copyReceipts(w.current.receipts) s := w.current.state.Copy() - block, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) + block, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, w.current.txs, uncles, receipts) if err != nil { return err } @@ -991,15 +989,10 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st select { case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: w.unconfirmed.Shift(block.NumberU64() - 1) - - feesWei := new(big.Int) - for i, tx := range block.Transactions() { - feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) - } - feesEth := new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) - log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), - "uncles", len(uncles), "txs", w.current.tcount, "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) + "uncles", len(uncles), "txs", w.current.tcount, + "gas", block.GasUsed(), "fees", totalFees(block, receipts), + "elapsed", common.PrettyDuration(time.Since(start))) case <-w.exitCh: log.Info("Worker has exited") @@ -1011,6 +1004,16 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st return nil } +// copyReceipts makes a deep copy of the given receipts. +func copyReceipts(receipts []*types.Receipt) []*types.Receipt { + result := make([]*types.Receipt, len(receipts)) + for i, l := range receipts { + cpy := *l + result[i] = &cpy + } + return result +} + // postSideBlock fires a side chain event, only use it for testing. func (w *worker) postSideBlock(event core.ChainSideEvent) { select { @@ -1018,3 +1021,12 @@ func (w *worker) postSideBlock(event core.ChainSideEvent) { case <-w.exitCh: } } + +// totalFees computes total consumed fees in ETH. Block transactions and receipts have to have the same order. +func totalFees(block *types.Block, receipts []*types.Receipt) *big.Float { + feesWei := new(big.Int) + for i, tx := range block.Transactions() { + feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) + } + return new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) +}