mining: Refactor policy into its own struct.
This introduces the concept of a mining policy struct which is used to control block template generation instead of directly accessing the config struct. This is a step toward decoupling the mining code from the internals of btcd. Ultimately the intent is to create a separate mining package.
This commit is contained in:
parent
2799ddf538
commit
a4aa131dd5
4 changed files with 72 additions and 38 deletions
|
@ -52,6 +52,7 @@ var (
|
|||
// system which is typically sufficient.
|
||||
type CPUMiner struct {
|
||||
sync.Mutex
|
||||
policy *miningPolicy
|
||||
server *server
|
||||
numWorkers uint32
|
||||
started bool
|
||||
|
@ -302,7 +303,7 @@ out:
|
|||
// Create a new block template using the available transactions
|
||||
// in the memory pool as a source of transactions to potentially
|
||||
// include in the block.
|
||||
template, err := NewBlockTemplate(m.server, payToAddr)
|
||||
template, err := NewBlockTemplate(m.policy, m.server, payToAddr)
|
||||
m.submitBlockLock.Unlock()
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Failed to create new block "+
|
||||
|
@ -564,7 +565,7 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*wire.ShaHash, error) {
|
|||
// Create a new block template using the available transactions
|
||||
// in the memory pool as a source of transactions to potentially
|
||||
// include in the block.
|
||||
template, err := NewBlockTemplate(m.server, payToAddr)
|
||||
template, err := NewBlockTemplate(m.policy, m.server, payToAddr)
|
||||
m.submitBlockLock.Unlock()
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Failed to create new block "+
|
||||
|
@ -599,8 +600,9 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*wire.ShaHash, error) {
|
|||
// newCPUMiner returns a new instance of a CPU miner for the provided server.
|
||||
// Use Start to begin the mining process. See the documentation for CPUMiner
|
||||
// type for more details.
|
||||
func newCPUMiner(s *server) *CPUMiner {
|
||||
func newCPUMiner(policy *miningPolicy, s *server) *CPUMiner {
|
||||
return &CPUMiner{
|
||||
policy: policy,
|
||||
server: s,
|
||||
numWorkers: defaultNumWorkers,
|
||||
updateNumWorkers: make(chan struct{}),
|
||||
|
|
81
mining.go
81
mining.go
|
@ -40,6 +40,28 @@ const (
|
|||
coinbaseFlags = "/P2SH/btcd/"
|
||||
)
|
||||
|
||||
// miningPolicy houses the policy (configuration parameters) which is used to
|
||||
// control the generation of block templates. See the documentation for
|
||||
// NewBlockTemplate for more details on each of these parameters are used.
|
||||
type miningPolicy struct {
|
||||
// BlockMinSize is the minimum block size in bytes to be used when
|
||||
// generating a block template.
|
||||
BlockMinSize uint32
|
||||
|
||||
// BlockMaxSize is the maximum block size in bytes to be used when
|
||||
// generating a block template.
|
||||
BlockMaxSize uint32
|
||||
|
||||
// BlockPrioritySize is the size in bytes for high-priority / low-fee
|
||||
// transactions to be used when generating a block template.
|
||||
BlockPrioritySize uint32
|
||||
|
||||
// TxMinFreeFee is the minimum fee in Satoshi/kB that is required for a
|
||||
// transaction to be treated as free for mining purposes (block template
|
||||
// generation). This value is in Satoshi/1000 bytes.
|
||||
TxMinFreeFee btcutil.Amount
|
||||
}
|
||||
|
||||
// txPrioItem houses a transaction along with extra information that allows the
|
||||
// transaction to be prioritized and track dependencies on other transactions
|
||||
// which have not been mined into a block yet.
|
||||
|
@ -320,53 +342,54 @@ func medianAdjustedTime(chainState *chainState, timeSource blockchain.MedianTime
|
|||
// amounts, older inputs, and small sizes have the highest priority. Second, a
|
||||
// fee per kilobyte is calculated for each transaction. Transactions with a
|
||||
// higher fee per kilobyte are preferred. Finally, the block generation related
|
||||
// configuration options are all taken into account.
|
||||
// policy settings are all taken into account.
|
||||
//
|
||||
// Transactions which only spend outputs from other transactions already in the
|
||||
// block chain are immediately added to a priority queue which either
|
||||
// prioritizes based on the priority (then fee per kilobyte) or the fee per
|
||||
// kilobyte (then priority) depending on whether or not the BlockPrioritySize
|
||||
// configuration option allots space for high-priority transactions.
|
||||
// Transactions which spend outputs from other transactions in the memory pool
|
||||
// are added to a dependency map so they can be added to the priority queue once
|
||||
// the transactions they depend on have been included.
|
||||
// policy setting allots space for high-priority transactions. Transactions
|
||||
// which spend outputs from other transactions in the memory pool are added to a
|
||||
// dependency map so they can be added to the priority queue once the
|
||||
// transactions they depend on have been included.
|
||||
//
|
||||
// Once the high-priority area (if configured) has been filled with transactions,
|
||||
// or the priority falls below what is considered high-priority, the priority
|
||||
// queue is updated to prioritize by fees per kilobyte (then priority).
|
||||
// Once the high-priority area (if configured) has been filled with
|
||||
// transactions, or the priority falls below what is considered high-priority,
|
||||
// the priority queue is updated to prioritize by fees per kilobyte (then
|
||||
// priority).
|
||||
//
|
||||
// When the fees per kilobyte drop below the TxMinFreeFee configuration option,
|
||||
// the transaction will be skipped unless there is a BlockMinSize set, in which
|
||||
// case the block will be filled with the low-fee/free transactions until the
|
||||
// block size reaches that minimum size.
|
||||
// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the
|
||||
// transaction will be skipped unless the BlockMinSize policy setting is
|
||||
// nonzero, in which case the block will be filled with the low-fee/free
|
||||
// transactions until the block size reaches that minimum size.
|
||||
//
|
||||
// Any transactions which would cause the block to exceed the BlockMaxSize
|
||||
// configuration option, exceed the maximum allowed signature operations per
|
||||
// block, or otherwise cause the block to be invalid are skipped.
|
||||
// policy setting, exceed the maximum allowed signature operations per block, or
|
||||
// otherwise cause the block to be invalid are skipped.
|
||||
//
|
||||
// Given the above, a block generated by this function is of the following form:
|
||||
//
|
||||
// ----------------------------------- -- --
|
||||
// | Coinbase Transaction | | |
|
||||
// |-----------------------------------| | |
|
||||
// | | | | ----- cfg.BlockPrioritySize
|
||||
// | | | | ----- policy.BlockPrioritySize
|
||||
// | High-priority Transactions | | |
|
||||
// | | | |
|
||||
// |-----------------------------------| | --
|
||||
// | | |
|
||||
// | | |
|
||||
// | | |--- cfg.BlockMaxSize
|
||||
// | | |--- policy.BlockMaxSize
|
||||
// | Transactions prioritized by fee | |
|
||||
// | until <= cfg.TxMinFreeFee | |
|
||||
// | until <= policy.TxMinFreeFee | |
|
||||
// | | |
|
||||
// | | |
|
||||
// | | |
|
||||
// |-----------------------------------| |
|
||||
// | Low-fee/Non high-priority (free) | |
|
||||
// | transactions (while block size | |
|
||||
// | <= cfg.BlockMinSize) | |
|
||||
// | <= policy.BlockMinSize) | |
|
||||
// ----------------------------------- --
|
||||
func NewBlockTemplate(server *server, payToAddress btcutil.Address) (*BlockTemplate, error) {
|
||||
func NewBlockTemplate(policy *miningPolicy, server *server, payToAddress btcutil.Address) (*BlockTemplate, error) {
|
||||
blockManager := server.blockManager
|
||||
timeSource := server.timeSource
|
||||
chainState := &blockManager.chainState
|
||||
|
@ -405,7 +428,7 @@ func NewBlockTemplate(server *server, payToAddress btcutil.Address) (*BlockTempl
|
|||
// whether or not there is an area allocated for high-priority
|
||||
// transactions.
|
||||
mempoolTxns := server.txMemPool.TxDescs()
|
||||
sortedByFee := cfg.BlockPrioritySize == 0
|
||||
sortedByFee := policy.BlockPrioritySize == 0
|
||||
priorityQueue := newTxPriorityQueue(len(mempoolTxns), sortedByFee)
|
||||
|
||||
// Create a slice to hold the transactions to be included in the
|
||||
|
@ -563,7 +586,7 @@ mempoolLoop:
|
|||
// Enforce maximum block size. Also check for overflow.
|
||||
txSize := uint32(tx.MsgTx().SerializeSize())
|
||||
blockPlusTxSize := blockSize + txSize
|
||||
if blockPlusTxSize < blockSize || blockPlusTxSize >= cfg.BlockMaxSize {
|
||||
if blockPlusTxSize < blockSize || blockPlusTxSize >= policy.BlockMaxSize {
|
||||
minrLog.Tracef("Skipping tx %s because it would exceed "+
|
||||
"the max block size", tx.Sha())
|
||||
logSkippedDeps(tx, deps)
|
||||
|
@ -601,14 +624,14 @@ mempoolLoop:
|
|||
// Skip free transactions once the block is larger than the
|
||||
// minimum block size.
|
||||
if sortedByFee &&
|
||||
prioItem.feePerKB < int64(cfg.minRelayTxFee) &&
|
||||
blockPlusTxSize >= cfg.BlockMinSize {
|
||||
prioItem.feePerKB < int64(policy.TxMinFreeFee) &&
|
||||
blockPlusTxSize >= policy.BlockMinSize {
|
||||
|
||||
minrLog.Tracef("Skipping tx %s with feePerKB %.2f "+
|
||||
"< minTxRelayFee %d and block size %d >= "+
|
||||
"< TxMinFreeFee %d and block size %d >= "+
|
||||
"minBlockSize %d", tx.Sha(), prioItem.feePerKB,
|
||||
cfg.minRelayTxFee, blockPlusTxSize,
|
||||
cfg.BlockMinSize)
|
||||
policy.TxMinFreeFee, blockPlusTxSize,
|
||||
policy.BlockMinSize)
|
||||
logSkippedDeps(tx, deps)
|
||||
continue
|
||||
}
|
||||
|
@ -616,13 +639,13 @@ mempoolLoop:
|
|||
// Prioritize by fee per kilobyte once the block is larger than
|
||||
// the priority size or there are no more high-priority
|
||||
// transactions.
|
||||
if !sortedByFee && (blockPlusTxSize >= cfg.BlockPrioritySize ||
|
||||
if !sortedByFee && (blockPlusTxSize >= policy.BlockPrioritySize ||
|
||||
prioItem.priority <= minHighPriority) {
|
||||
|
||||
minrLog.Tracef("Switching to sort by fees per "+
|
||||
"kilobyte blockSize %d >= BlockPrioritySize "+
|
||||
"%d || priority %.2f <= minHighPriority %.2f",
|
||||
blockPlusTxSize, cfg.BlockPrioritySize,
|
||||
blockPlusTxSize, policy.BlockPrioritySize,
|
||||
prioItem.priority, minHighPriority)
|
||||
|
||||
sortedByFee = true
|
||||
|
@ -634,7 +657,7 @@ mempoolLoop:
|
|||
// too low. Otherwise this transaction will be the
|
||||
// final one in the high-priority section, so just fall
|
||||
// though to the code below so it is added now.
|
||||
if blockPlusTxSize > cfg.BlockPrioritySize ||
|
||||
if blockPlusTxSize > policy.BlockPrioritySize ||
|
||||
prioItem.priority < minHighPriority {
|
||||
|
||||
heap.Push(priorityQueue, prioItem)
|
||||
|
|
|
@ -1518,7 +1518,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo
|
|||
// block template doesn't include the coinbase, so the caller
|
||||
// will ultimately create their own coinbase which pays to the
|
||||
// appropriate address(es).
|
||||
blkTemplate, err := NewBlockTemplate(s.server, payAddr)
|
||||
blkTemplate, err := NewBlockTemplate(s.policy, s.server, payAddr)
|
||||
if err != nil {
|
||||
return internalRPCError("Failed to create new block "+
|
||||
"template: "+err.Error(), "")
|
||||
|
@ -2708,8 +2708,7 @@ func handleGetWorkRequest(s *rpcServer) (interface{}, error) {
|
|||
|
||||
// Choose a payment address at random.
|
||||
payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))]
|
||||
|
||||
template, err := NewBlockTemplate(s.server, payToAddr)
|
||||
template, err := NewBlockTemplate(s.policy, s.server, payToAddr)
|
||||
if err != nil {
|
||||
context := "Failed to create new block template"
|
||||
return nil, internalRPCError(err.Error(), context)
|
||||
|
@ -3518,6 +3517,7 @@ func handleVerifyMessage(s *rpcServer, cmd interface{}, closeChan <-chan struct{
|
|||
type rpcServer struct {
|
||||
started int32
|
||||
shutdown int32
|
||||
policy *miningPolicy
|
||||
server *server
|
||||
authsha [fastsha256.Size]byte
|
||||
limitauthsha [fastsha256.Size]byte
|
||||
|
@ -3995,8 +3995,9 @@ func genCertPair(certFile, keyFile string) error {
|
|||
}
|
||||
|
||||
// newRPCServer returns a new instance of the rpcServer struct.
|
||||
func newRPCServer(listenAddrs []string, s *server) (*rpcServer, error) {
|
||||
func newRPCServer(listenAddrs []string, policy *miningPolicy, s *server) (*rpcServer, error) {
|
||||
rpc := rpcServer{
|
||||
policy: policy,
|
||||
server: s,
|
||||
statusLines: make(map[int]string),
|
||||
workState: newWorkState(),
|
||||
|
|
12
server.go
12
server.go
|
@ -2322,7 +2322,15 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
|
|||
}
|
||||
s.blockManager = bm
|
||||
s.txMemPool = newTxMemPool(&s)
|
||||
s.cpuMiner = newCPUMiner(&s)
|
||||
|
||||
// Create the mining policy based on the configuration options.
|
||||
policy := miningPolicy{
|
||||
BlockMinSize: cfg.BlockMinSize,
|
||||
BlockMaxSize: cfg.BlockMaxSize,
|
||||
BlockPrioritySize: cfg.BlockPrioritySize,
|
||||
TxMinFreeFee: cfg.minRelayTxFee,
|
||||
}
|
||||
s.cpuMiner = newCPUMiner(&policy, &s)
|
||||
|
||||
if cfg.AddrIndex {
|
||||
ai, err := newAddrIndexer(&s)
|
||||
|
@ -2333,7 +2341,7 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
|
|||
}
|
||||
|
||||
if !cfg.DisableRPC {
|
||||
s.rpcServer, err = newRPCServer(cfg.RPCListeners, &s)
|
||||
s.rpcServer, err = newRPCServer(cfg.RPCListeners, &policy, &s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue