2b44ef5f93
This change introduces a breaking change to miner.etherbase is configured. Previously, users did not need to explicitly set the etherbase address via flag, since 'first' local account was used as etherbase automatically. This change removes the "default first account" feature. In Proof-of-stake world, the fee recipient address is provided by CL, and not configured in Geth any more - meaning that miner.etherbase is mostly for legacy networks(pow, clique networks etc).
258 lines
8.2 KiB
Go
258 lines
8.2 KiB
Go
// Copyright 2014 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// Package miner implements Ethereum block creation and mining.
|
|
package miner
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/ethereum/go-ethereum/consensus"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
"github.com/ethereum/go-ethereum/core/txpool"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
"github.com/ethereum/go-ethereum/event"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
// Backend wraps all methods required for mining. Only full node is capable
|
|
// to offer all the functions here.
|
|
type Backend interface {
|
|
BlockChain() *core.BlockChain
|
|
TxPool() *txpool.TxPool
|
|
}
|
|
|
|
// Config is the configuration parameters of mining.
|
|
type Config struct {
|
|
Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards
|
|
Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash).
|
|
NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages
|
|
ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner
|
|
GasFloor uint64 // Target gas floor for mined blocks.
|
|
GasCeil uint64 // Target gas ceiling for mined blocks.
|
|
GasPrice *big.Int // Minimum gas price for mining a transaction
|
|
Recommit time.Duration // The time interval for miner to re-create mining work.
|
|
Noverify bool // Disable remote mining solution verification(only useful in ethash).
|
|
|
|
NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload
|
|
}
|
|
|
|
// DefaultConfig contains default settings for miner.
|
|
var DefaultConfig = Config{
|
|
GasCeil: 30000000,
|
|
GasPrice: big.NewInt(params.GWei),
|
|
|
|
// The default recommit time is chosen as two seconds since
|
|
// consensus-layer usually will wait a half slot of time(6s)
|
|
// for payload generation. It should be enough for Geth to
|
|
// run 3 rounds.
|
|
Recommit: 2 * time.Second,
|
|
NewPayloadTimeout: 2 * time.Second,
|
|
}
|
|
|
|
// Miner creates blocks and searches for proof-of-work values.
|
|
type Miner struct {
|
|
mux *event.TypeMux
|
|
eth Backend
|
|
engine consensus.Engine
|
|
exitCh chan struct{}
|
|
startCh chan struct{}
|
|
stopCh chan struct{}
|
|
worker *worker
|
|
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(header *types.Header) bool) *Miner {
|
|
miner := &Miner{
|
|
mux: mux,
|
|
eth: eth,
|
|
engine: engine,
|
|
exitCh: make(chan struct{}),
|
|
startCh: make(chan struct{}),
|
|
stopCh: make(chan struct{}),
|
|
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
|
|
}
|
|
miner.wg.Add(1)
|
|
go miner.update()
|
|
return miner
|
|
}
|
|
|
|
// update keeps track of the downloader events. Please be aware that this is a one shot type of update loop.
|
|
// It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and
|
|
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
|
|
// and halt your mining operation for as long as the DOS continues.
|
|
func (miner *Miner) update() {
|
|
defer miner.wg.Done()
|
|
|
|
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
|
defer func() {
|
|
if !events.Closed() {
|
|
events.Unsubscribe()
|
|
}
|
|
}()
|
|
|
|
shouldStart := false
|
|
canStart := true
|
|
dlEventCh := events.Chan()
|
|
for {
|
|
select {
|
|
case ev := <-dlEventCh:
|
|
if ev == nil {
|
|
// Unsubscription done, stop listening
|
|
dlEventCh = nil
|
|
continue
|
|
}
|
|
switch ev.Data.(type) {
|
|
case downloader.StartEvent:
|
|
wasMining := miner.Mining()
|
|
miner.worker.stop()
|
|
canStart = false
|
|
if wasMining {
|
|
// Resume mining after sync was finished
|
|
shouldStart = true
|
|
log.Info("Mining aborted due to sync")
|
|
}
|
|
case downloader.FailedEvent:
|
|
canStart = true
|
|
if shouldStart {
|
|
miner.worker.start()
|
|
}
|
|
case downloader.DoneEvent:
|
|
canStart = true
|
|
if shouldStart {
|
|
miner.worker.start()
|
|
}
|
|
// Stop reacting to downloader events
|
|
events.Unsubscribe()
|
|
}
|
|
case <-miner.startCh:
|
|
if canStart {
|
|
miner.worker.start()
|
|
}
|
|
shouldStart = true
|
|
case <-miner.stopCh:
|
|
shouldStart = false
|
|
miner.worker.stop()
|
|
case <-miner.exitCh:
|
|
miner.worker.close()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (miner *Miner) Start() {
|
|
miner.startCh <- struct{}{}
|
|
}
|
|
|
|
func (miner *Miner) Stop() {
|
|
miner.stopCh <- struct{}{}
|
|
}
|
|
|
|
func (miner *Miner) Close() {
|
|
close(miner.exitCh)
|
|
miner.wg.Wait()
|
|
}
|
|
|
|
func (miner *Miner) Mining() bool {
|
|
return miner.worker.isRunning()
|
|
}
|
|
|
|
func (miner *Miner) Hashrate() uint64 {
|
|
if pow, ok := miner.engine.(consensus.PoW); ok {
|
|
return uint64(pow.Hashrate())
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (miner *Miner) SetExtra(extra []byte) error {
|
|
if uint64(len(extra)) > params.MaximumExtraDataSize {
|
|
return fmt.Errorf("extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
|
|
}
|
|
miner.worker.setExtra(extra)
|
|
return nil
|
|
}
|
|
|
|
// SetRecommitInterval sets the interval for sealing work resubmitting.
|
|
func (miner *Miner) SetRecommitInterval(interval time.Duration) {
|
|
miner.worker.setRecommitInterval(interval)
|
|
}
|
|
|
|
// Pending returns the currently pending block and associated state.
|
|
func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
|
|
return miner.worker.pending()
|
|
}
|
|
|
|
// PendingBlock returns the currently pending block.
|
|
//
|
|
// Note, to access both the pending block and the pending state
|
|
// simultaneously, please use Pending(), as the pending state can
|
|
// change between multiple method calls
|
|
func (miner *Miner) PendingBlock() *types.Block {
|
|
return miner.worker.pendingBlock()
|
|
}
|
|
|
|
// PendingBlockAndReceipts returns the currently pending block and corresponding receipts.
|
|
func (miner *Miner) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
|
|
return miner.worker.pendingBlockAndReceipts()
|
|
}
|
|
|
|
func (miner *Miner) SetEtherbase(addr common.Address) {
|
|
miner.worker.setEtherbase(addr)
|
|
}
|
|
|
|
// SetGasCeil sets the gaslimit to strive for when mining blocks post 1559.
|
|
// For pre-1559 blocks, it sets the ceiling.
|
|
func (miner *Miner) SetGasCeil(ceil uint64) {
|
|
miner.worker.setGasCeil(ceil)
|
|
}
|
|
|
|
// EnablePreseal turns on the preseal mining feature. It's enabled by default.
|
|
// Note this function shouldn't be exposed to API, it's unnecessary for users
|
|
// (miners) to actually know the underlying detail. It's only for outside project
|
|
// which uses this library.
|
|
func (miner *Miner) EnablePreseal() {
|
|
miner.worker.enablePreseal()
|
|
}
|
|
|
|
// DisablePreseal turns off the preseal mining feature. It's necessary for some
|
|
// fake consensus engine which can seal blocks instantaneously.
|
|
// Note this function shouldn't be exposed to API, it's unnecessary for users
|
|
// (miners) to actually know the underlying detail. It's only for outside project
|
|
// which uses this library.
|
|
func (miner *Miner) DisablePreseal() {
|
|
miner.worker.disablePreseal()
|
|
}
|
|
|
|
// SubscribePendingLogs starts delivering logs from pending transactions
|
|
// to the given channel.
|
|
func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription {
|
|
return miner.worker.pendingLogsFeed.Subscribe(ch)
|
|
}
|
|
|
|
// BuildPayload builds the payload according to the provided parameters.
|
|
func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) {
|
|
return miner.worker.buildPayload(args)
|
|
}
|