|
|
@ -305,6 +305,28 @@ func (w *worker) close() { |
|
|
|
close(w.exitCh) |
|
|
|
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.
|
|
|
|
// newWorkLoop is a standalone goroutine to submit new mining work upon received events.
|
|
|
|
func (w *worker) newWorkLoop(recommit time.Duration) { |
|
|
|
func (w *worker) newWorkLoop(recommit time.Duration) { |
|
|
|
var ( |
|
|
|
var ( |
|
|
@ -327,27 +349,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) { |
|
|
|
timer.Reset(recommit) |
|
|
|
timer.Reset(recommit) |
|
|
|
atomic.StoreInt32(&w.newTxs, 0) |
|
|
|
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 cleans the stale pending tasks.
|
|
|
|
clearPending := func(number uint64) { |
|
|
|
clearPending := func(number uint64) { |
|
|
|
w.pendingMu.Lock() |
|
|
|
w.pendingMu.Lock() |
|
|
@ -400,11 +401,12 @@ func (w *worker) newWorkLoop(recommit time.Duration) { |
|
|
|
// Adjust resubmit interval by feedback.
|
|
|
|
// Adjust resubmit interval by feedback.
|
|
|
|
if adjust.inc { |
|
|
|
if adjust.inc { |
|
|
|
before := recommit |
|
|
|
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) |
|
|
|
log.Trace("Increase miner recommit interval", "from", before, "to", recommit) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
before := recommit |
|
|
|
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) |
|
|
|
log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -553,7 +555,7 @@ func (w *worker) taskLoop() { |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
w.pendingMu.Lock() |
|
|
|
w.pendingMu.Lock() |
|
|
|
w.pendingTasks[w.engine.SealHash(task.block.Header())] = task |
|
|
|
w.pendingTasks[sealHash] = task |
|
|
|
w.pendingMu.Unlock() |
|
|
|
w.pendingMu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { |
|
|
|
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.
|
|
|
|
// and commits new work if consensus engine is running.
|
|
|
|
func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { |
|
|
|
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.
|
|
|
|
// Deep copy receipts here to avoid interaction between different tasks.
|
|
|
|
receipts := make([]*types.Receipt, len(w.current.receipts)) |
|
|
|
receipts := copyReceipts(w.current.receipts) |
|
|
|
for i, l := range w.current.receipts { |
|
|
|
|
|
|
|
receipts[i] = new(types.Receipt) |
|
|
|
|
|
|
|
*receipts[i] = *l |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
s := w.current.state.Copy() |
|
|
|
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 { |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
@ -991,15 +989,10 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st |
|
|
|
select { |
|
|
|
select { |
|
|
|
case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: |
|
|
|
case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: |
|
|
|
w.unconfirmed.Shift(block.NumberU64() - 1) |
|
|
|
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()), |
|
|
|
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: |
|
|
|
case <-w.exitCh: |
|
|
|
log.Info("Worker has exited") |
|
|
|
log.Info("Worker has exited") |
|
|
@ -1011,6 +1004,16 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st |
|
|
|
return nil |
|
|
|
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.
|
|
|
|
// postSideBlock fires a side chain event, only use it for testing.
|
|
|
|
func (w *worker) postSideBlock(event core.ChainSideEvent) { |
|
|
|
func (w *worker) postSideBlock(event core.ChainSideEvent) { |
|
|
|
select { |
|
|
|
select { |
|
|
@ -1018,3 +1021,12 @@ func (w *worker) postSideBlock(event core.ChainSideEvent) { |
|
|
|
case <-w.exitCh: |
|
|
|
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))) |
|
|
|
|
|
|
|
} |
|
|
|