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.
|
// system which is typically sufficient.
|
||||||
type CPUMiner struct {
|
type CPUMiner struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
policy *miningPolicy
|
||||||
server *server
|
server *server
|
||||||
numWorkers uint32
|
numWorkers uint32
|
||||||
started bool
|
started bool
|
||||||
|
@ -302,7 +303,7 @@ out:
|
||||||
// Create a new block template using the available transactions
|
// Create a new block template using the available transactions
|
||||||
// in the memory pool as a source of transactions to potentially
|
// in the memory pool as a source of transactions to potentially
|
||||||
// include in the block.
|
// include in the block.
|
||||||
template, err := NewBlockTemplate(m.server, payToAddr)
|
template, err := NewBlockTemplate(m.policy, m.server, payToAddr)
|
||||||
m.submitBlockLock.Unlock()
|
m.submitBlockLock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errStr := fmt.Sprintf("Failed to create new block "+
|
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
|
// Create a new block template using the available transactions
|
||||||
// in the memory pool as a source of transactions to potentially
|
// in the memory pool as a source of transactions to potentially
|
||||||
// include in the block.
|
// include in the block.
|
||||||
template, err := NewBlockTemplate(m.server, payToAddr)
|
template, err := NewBlockTemplate(m.policy, m.server, payToAddr)
|
||||||
m.submitBlockLock.Unlock()
|
m.submitBlockLock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errStr := fmt.Sprintf("Failed to create new block "+
|
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.
|
// 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
|
// Use Start to begin the mining process. See the documentation for CPUMiner
|
||||||
// type for more details.
|
// type for more details.
|
||||||
func newCPUMiner(s *server) *CPUMiner {
|
func newCPUMiner(policy *miningPolicy, s *server) *CPUMiner {
|
||||||
return &CPUMiner{
|
return &CPUMiner{
|
||||||
|
policy: policy,
|
||||||
server: s,
|
server: s,
|
||||||
numWorkers: defaultNumWorkers,
|
numWorkers: defaultNumWorkers,
|
||||||
updateNumWorkers: make(chan struct{}),
|
updateNumWorkers: make(chan struct{}),
|
||||||
|
|
81
mining.go
81
mining.go
|
@ -40,6 +40,28 @@ const (
|
||||||
coinbaseFlags = "/P2SH/btcd/"
|
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
|
// txPrioItem houses a transaction along with extra information that allows the
|
||||||
// transaction to be prioritized and track dependencies on other transactions
|
// transaction to be prioritized and track dependencies on other transactions
|
||||||
// which have not been mined into a block yet.
|
// 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
|
// amounts, older inputs, and small sizes have the highest priority. Second, a
|
||||||
// fee per kilobyte is calculated for each transaction. Transactions with a
|
// fee per kilobyte is calculated for each transaction. Transactions with a
|
||||||
// higher fee per kilobyte are preferred. Finally, the block generation related
|
// 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
|
// Transactions which only spend outputs from other transactions already in the
|
||||||
// block chain are immediately added to a priority queue which either
|
// block chain are immediately added to a priority queue which either
|
||||||
// prioritizes based on the priority (then fee per kilobyte) or the fee per
|
// prioritizes based on the priority (then fee per kilobyte) or the fee per
|
||||||
// kilobyte (then priority) depending on whether or not the BlockPrioritySize
|
// kilobyte (then priority) depending on whether or not the BlockPrioritySize
|
||||||
// configuration option allots space for high-priority transactions.
|
// policy setting allots space for high-priority transactions. Transactions
|
||||||
// Transactions which spend outputs from other transactions in the memory pool
|
// which spend outputs from other transactions in the memory pool are added to a
|
||||||
// are added to a dependency map so they can be added to the priority queue once
|
// dependency map so they can be added to the priority queue once the
|
||||||
// the transactions they depend on have been included.
|
// transactions they depend on have been included.
|
||||||
//
|
//
|
||||||
// Once the high-priority area (if configured) has been filled with transactions,
|
// Once the high-priority area (if configured) has been filled with
|
||||||
// or the priority falls below what is considered high-priority, the priority
|
// transactions, or the priority falls below what is considered high-priority,
|
||||||
// queue is updated to prioritize by fees per kilobyte (then 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,
|
// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the
|
||||||
// the transaction will be skipped unless there is a BlockMinSize set, in which
|
// transaction will be skipped unless the BlockMinSize policy setting is
|
||||||
// case the block will be filled with the low-fee/free transactions until the
|
// nonzero, in which case the block will be filled with the low-fee/free
|
||||||
// block size reaches that minimum size.
|
// transactions until the block size reaches that minimum size.
|
||||||
//
|
//
|
||||||
// Any transactions which would cause the block to exceed the BlockMaxSize
|
// Any transactions which would cause the block to exceed the BlockMaxSize
|
||||||
// configuration option, exceed the maximum allowed signature operations per
|
// policy setting, exceed the maximum allowed signature operations per block, or
|
||||||
// block, or otherwise cause the block to be invalid are skipped.
|
// otherwise cause the block to be invalid are skipped.
|
||||||
//
|
//
|
||||||
// Given the above, a block generated by this function is of the following form:
|
// Given the above, a block generated by this function is of the following form:
|
||||||
//
|
//
|
||||||
// ----------------------------------- -- --
|
// ----------------------------------- -- --
|
||||||
// | Coinbase Transaction | | |
|
// | Coinbase Transaction | | |
|
||||||
// |-----------------------------------| | |
|
// |-----------------------------------| | |
|
||||||
// | | | | ----- cfg.BlockPrioritySize
|
// | | | | ----- policy.BlockPrioritySize
|
||||||
// | High-priority Transactions | | |
|
// | High-priority Transactions | | |
|
||||||
// | | | |
|
// | | | |
|
||||||
// |-----------------------------------| | --
|
// |-----------------------------------| | --
|
||||||
// | | |
|
// | | |
|
||||||
// | | |
|
// | | |
|
||||||
// | | |--- cfg.BlockMaxSize
|
// | | |--- policy.BlockMaxSize
|
||||||
// | Transactions prioritized by fee | |
|
// | Transactions prioritized by fee | |
|
||||||
// | until <= cfg.TxMinFreeFee | |
|
// | until <= policy.TxMinFreeFee | |
|
||||||
// | | |
|
// | | |
|
||||||
// | | |
|
// | | |
|
||||||
// | | |
|
// | | |
|
||||||
// |-----------------------------------| |
|
// |-----------------------------------| |
|
||||||
// | Low-fee/Non high-priority (free) | |
|
// | Low-fee/Non high-priority (free) | |
|
||||||
// | transactions (while block size | |
|
// | 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
|
blockManager := server.blockManager
|
||||||
timeSource := server.timeSource
|
timeSource := server.timeSource
|
||||||
chainState := &blockManager.chainState
|
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
|
// whether or not there is an area allocated for high-priority
|
||||||
// transactions.
|
// transactions.
|
||||||
mempoolTxns := server.txMemPool.TxDescs()
|
mempoolTxns := server.txMemPool.TxDescs()
|
||||||
sortedByFee := cfg.BlockPrioritySize == 0
|
sortedByFee := policy.BlockPrioritySize == 0
|
||||||
priorityQueue := newTxPriorityQueue(len(mempoolTxns), sortedByFee)
|
priorityQueue := newTxPriorityQueue(len(mempoolTxns), sortedByFee)
|
||||||
|
|
||||||
// Create a slice to hold the transactions to be included in the
|
// 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.
|
// Enforce maximum block size. Also check for overflow.
|
||||||
txSize := uint32(tx.MsgTx().SerializeSize())
|
txSize := uint32(tx.MsgTx().SerializeSize())
|
||||||
blockPlusTxSize := blockSize + txSize
|
blockPlusTxSize := blockSize + txSize
|
||||||
if blockPlusTxSize < blockSize || blockPlusTxSize >= cfg.BlockMaxSize {
|
if blockPlusTxSize < blockSize || blockPlusTxSize >= policy.BlockMaxSize {
|
||||||
minrLog.Tracef("Skipping tx %s because it would exceed "+
|
minrLog.Tracef("Skipping tx %s because it would exceed "+
|
||||||
"the max block size", tx.Sha())
|
"the max block size", tx.Sha())
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
|
@ -601,14 +624,14 @@ mempoolLoop:
|
||||||
// Skip free transactions once the block is larger than the
|
// Skip free transactions once the block is larger than the
|
||||||
// minimum block size.
|
// minimum block size.
|
||||||
if sortedByFee &&
|
if sortedByFee &&
|
||||||
prioItem.feePerKB < int64(cfg.minRelayTxFee) &&
|
prioItem.feePerKB < int64(policy.TxMinFreeFee) &&
|
||||||
blockPlusTxSize >= cfg.BlockMinSize {
|
blockPlusTxSize >= policy.BlockMinSize {
|
||||||
|
|
||||||
minrLog.Tracef("Skipping tx %s with feePerKB %.2f "+
|
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,
|
"minBlockSize %d", tx.Sha(), prioItem.feePerKB,
|
||||||
cfg.minRelayTxFee, blockPlusTxSize,
|
policy.TxMinFreeFee, blockPlusTxSize,
|
||||||
cfg.BlockMinSize)
|
policy.BlockMinSize)
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -616,13 +639,13 @@ mempoolLoop:
|
||||||
// Prioritize by fee per kilobyte once the block is larger than
|
// Prioritize by fee per kilobyte once the block is larger than
|
||||||
// the priority size or there are no more high-priority
|
// the priority size or there are no more high-priority
|
||||||
// transactions.
|
// transactions.
|
||||||
if !sortedByFee && (blockPlusTxSize >= cfg.BlockPrioritySize ||
|
if !sortedByFee && (blockPlusTxSize >= policy.BlockPrioritySize ||
|
||||||
prioItem.priority <= minHighPriority) {
|
prioItem.priority <= minHighPriority) {
|
||||||
|
|
||||||
minrLog.Tracef("Switching to sort by fees per "+
|
minrLog.Tracef("Switching to sort by fees per "+
|
||||||
"kilobyte blockSize %d >= BlockPrioritySize "+
|
"kilobyte blockSize %d >= BlockPrioritySize "+
|
||||||
"%d || priority %.2f <= minHighPriority %.2f",
|
"%d || priority %.2f <= minHighPriority %.2f",
|
||||||
blockPlusTxSize, cfg.BlockPrioritySize,
|
blockPlusTxSize, policy.BlockPrioritySize,
|
||||||
prioItem.priority, minHighPriority)
|
prioItem.priority, minHighPriority)
|
||||||
|
|
||||||
sortedByFee = true
|
sortedByFee = true
|
||||||
|
@ -634,7 +657,7 @@ mempoolLoop:
|
||||||
// too low. Otherwise this transaction will be the
|
// too low. Otherwise this transaction will be the
|
||||||
// final one in the high-priority section, so just fall
|
// final one in the high-priority section, so just fall
|
||||||
// though to the code below so it is added now.
|
// though to the code below so it is added now.
|
||||||
if blockPlusTxSize > cfg.BlockPrioritySize ||
|
if blockPlusTxSize > policy.BlockPrioritySize ||
|
||||||
prioItem.priority < minHighPriority {
|
prioItem.priority < minHighPriority {
|
||||||
|
|
||||||
heap.Push(priorityQueue, prioItem)
|
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
|
// block template doesn't include the coinbase, so the caller
|
||||||
// will ultimately create their own coinbase which pays to the
|
// will ultimately create their own coinbase which pays to the
|
||||||
// appropriate address(es).
|
// appropriate address(es).
|
||||||
blkTemplate, err := NewBlockTemplate(s.server, payAddr)
|
blkTemplate, err := NewBlockTemplate(s.policy, s.server, payAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return internalRPCError("Failed to create new block "+
|
return internalRPCError("Failed to create new block "+
|
||||||
"template: "+err.Error(), "")
|
"template: "+err.Error(), "")
|
||||||
|
@ -2708,8 +2708,7 @@ func handleGetWorkRequest(s *rpcServer) (interface{}, error) {
|
||||||
|
|
||||||
// Choose a payment address at random.
|
// Choose a payment address at random.
|
||||||
payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))]
|
payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))]
|
||||||
|
template, err := NewBlockTemplate(s.policy, s.server, payToAddr)
|
||||||
template, err := NewBlockTemplate(s.server, payToAddr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
context := "Failed to create new block template"
|
context := "Failed to create new block template"
|
||||||
return nil, internalRPCError(err.Error(), context)
|
return nil, internalRPCError(err.Error(), context)
|
||||||
|
@ -3518,6 +3517,7 @@ func handleVerifyMessage(s *rpcServer, cmd interface{}, closeChan <-chan struct{
|
||||||
type rpcServer struct {
|
type rpcServer struct {
|
||||||
started int32
|
started int32
|
||||||
shutdown int32
|
shutdown int32
|
||||||
|
policy *miningPolicy
|
||||||
server *server
|
server *server
|
||||||
authsha [fastsha256.Size]byte
|
authsha [fastsha256.Size]byte
|
||||||
limitauthsha [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.
|
// 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{
|
rpc := rpcServer{
|
||||||
|
policy: policy,
|
||||||
server: s,
|
server: s,
|
||||||
statusLines: make(map[int]string),
|
statusLines: make(map[int]string),
|
||||||
workState: newWorkState(),
|
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.blockManager = bm
|
||||||
s.txMemPool = newTxMemPool(&s)
|
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 {
|
if cfg.AddrIndex {
|
||||||
ai, err := newAddrIndexer(&s)
|
ai, err := newAddrIndexer(&s)
|
||||||
|
@ -2333,7 +2341,7 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.DisableRPC {
|
if !cfg.DisableRPC {
|
||||||
s.rpcServer, err = newRPCServer(cfg.RPCListeners, &s)
|
s.rpcServer, err = newRPCServer(cfg.RPCListeners, &policy, &s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue