mining+config: modify GBT mining to limit by weight, add witness commitment
This commit modifies the existing block selection logic to limit preferentially by weight instead of serialized block size, and also to adhere to the new sig-op cost limits which are weighted according to the witness discount.
This commit is contained in:
parent
8b130ec4ea
commit
1244c45b88
5 changed files with 172 additions and 72 deletions
|
@ -1473,6 +1473,7 @@ func newBlockManager(s *server, indexManager blockchain.IndexManager) (*blockMan
|
||||||
Notifications: bm.handleNotifyMsg,
|
Notifications: bm.handleNotifyMsg,
|
||||||
SigCache: s.sigCache,
|
SigCache: s.sigCache,
|
||||||
IndexManager: indexManager,
|
IndexManager: indexManager,
|
||||||
|
HashCache: s.hashCache,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
49
config.go
49
config.go
|
@ -20,13 +20,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/connmgr"
|
"github.com/btcsuite/btcd/connmgr"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/btcsuite/btcd/database"
|
||||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
_ "github.com/btcsuite/btcd/database/ffldb"
|
||||||
"github.com/btcsuite/btcd/mempool"
|
"github.com/btcsuite/btcd/mempool"
|
||||||
"github.com/btcsuite/btcd/wire"
|
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/go-socks/socks"
|
"github.com/btcsuite/go-socks/socks"
|
||||||
flags "github.com/jessevdk/go-flags"
|
flags "github.com/jessevdk/go-flags"
|
||||||
|
@ -49,8 +49,12 @@ const (
|
||||||
defaultFreeTxRelayLimit = 15.0
|
defaultFreeTxRelayLimit = 15.0
|
||||||
defaultBlockMinSize = 0
|
defaultBlockMinSize = 0
|
||||||
defaultBlockMaxSize = 750000
|
defaultBlockMaxSize = 750000
|
||||||
|
defaultBlockMinWeight = 0
|
||||||
|
defaultBlockMaxWeight = 3000000
|
||||||
blockMaxSizeMin = 1000
|
blockMaxSizeMin = 1000
|
||||||
blockMaxSizeMax = wire.MaxBlockPayload - 1000
|
blockMaxSizeMax = blockchain.MaxBlockBaseSize - 1000
|
||||||
|
blockMaxWeightMin = 4000
|
||||||
|
blockMaxWeightMax = blockchain.MaxBlockWeight - 4000
|
||||||
defaultGenerate = false
|
defaultGenerate = false
|
||||||
defaultMaxOrphanTransactions = 100
|
defaultMaxOrphanTransactions = 100
|
||||||
defaultMaxOrphanTxSize = 100000
|
defaultMaxOrphanTxSize = 100000
|
||||||
|
@ -140,6 +144,8 @@ type config struct {
|
||||||
MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"`
|
MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"`
|
||||||
BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"`
|
BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"`
|
||||||
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
|
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
|
||||||
|
BlockMinWeight uint32 `long:"blockminweight" description:"Mininum block weight to be used when creating a block"`
|
||||||
|
BlockMaxWeight uint32 `long:"blockmaxweight" description:"Maximum block weight to be used when creating a block"`
|
||||||
BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"`
|
BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"`
|
||||||
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
|
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
|
||||||
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
|
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
|
||||||
|
@ -407,6 +413,8 @@ func loadConfig() (*config, []string, error) {
|
||||||
FreeTxRelayLimit: defaultFreeTxRelayLimit,
|
FreeTxRelayLimit: defaultFreeTxRelayLimit,
|
||||||
BlockMinSize: defaultBlockMinSize,
|
BlockMinSize: defaultBlockMinSize,
|
||||||
BlockMaxSize: defaultBlockMaxSize,
|
BlockMaxSize: defaultBlockMaxSize,
|
||||||
|
BlockMinWeight: defaultBlockMinWeight,
|
||||||
|
BlockMaxWeight: defaultBlockMaxWeight,
|
||||||
BlockPrioritySize: mempool.DefaultBlockPrioritySize,
|
BlockPrioritySize: mempool.DefaultBlockPrioritySize,
|
||||||
MaxOrphanTxs: defaultMaxOrphanTransactions,
|
MaxOrphanTxs: defaultMaxOrphanTransactions,
|
||||||
SigCacheMaxSize: defaultSigCacheMaxSize,
|
SigCacheMaxSize: defaultSigCacheMaxSize,
|
||||||
|
@ -531,8 +539,8 @@ func loadConfig() (*config, []string, error) {
|
||||||
cfg.DisableDNSSeed = true
|
cfg.DisableDNSSeed = true
|
||||||
}
|
}
|
||||||
if numNets > 1 {
|
if numNets > 1 {
|
||||||
str := "%s: The testnet, regtest, and simnet params can't be " +
|
str := "%s: The testnet, regtest, segnet, and simnet params " +
|
||||||
"used together -- choose one of the three"
|
"can't be used together -- choose one of the four"
|
||||||
err := fmt.Errorf(str, funcName)
|
err := fmt.Errorf(str, funcName)
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
fmt.Fprintln(os.Stderr, usageMessage)
|
fmt.Fprintln(os.Stderr, usageMessage)
|
||||||
|
@ -723,7 +731,20 @@ func loadConfig() (*config, []string, error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the max orphan count to a sane value.
|
// Limit the max block weight to a sane value.
|
||||||
|
if cfg.BlockMaxWeight < blockMaxWeightMin ||
|
||||||
|
cfg.BlockMaxWeight > blockMaxWeightMax {
|
||||||
|
|
||||||
|
str := "%s: The blockmaxweight option must be in between %d " +
|
||||||
|
"and %d -- parsed [%d]"
|
||||||
|
err := fmt.Errorf(str, funcName, blockMaxWeightMin,
|
||||||
|
blockMaxWeightMax, cfg.BlockMaxWeight)
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
fmt.Fprintln(os.Stderr, usageMessage)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit the max orphan count to a sane vlue.
|
||||||
if cfg.MaxOrphanTxs < 0 {
|
if cfg.MaxOrphanTxs < 0 {
|
||||||
str := "%s: The maxorphantx option may not be less than 0 " +
|
str := "%s: The maxorphantx option may not be less than 0 " +
|
||||||
"-- parsed [%d]"
|
"-- parsed [%d]"
|
||||||
|
@ -736,6 +757,24 @@ func loadConfig() (*config, []string, error) {
|
||||||
// Limit the block priority and minimum block sizes to max block size.
|
// Limit the block priority and minimum block sizes to max block size.
|
||||||
cfg.BlockPrioritySize = minUint32(cfg.BlockPrioritySize, cfg.BlockMaxSize)
|
cfg.BlockPrioritySize = minUint32(cfg.BlockPrioritySize, cfg.BlockMaxSize)
|
||||||
cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize)
|
cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize)
|
||||||
|
cfg.BlockMinWeight = minUint32(cfg.BlockMinWeight, cfg.BlockMaxWeight)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
// If the max block size isn't set, but the max weight is, then we'll
|
||||||
|
// set the limit for the max block size to a safe limit so weight takes
|
||||||
|
// precedence.
|
||||||
|
case cfg.BlockMaxSize == defaultBlockMaxSize &&
|
||||||
|
cfg.BlockMaxWeight != defaultBlockMaxWeight:
|
||||||
|
|
||||||
|
cfg.BlockMaxSize = blockchain.MaxBlockBaseSize - 1000
|
||||||
|
|
||||||
|
// If the max block weight isn't set, but the block size is, then we'll
|
||||||
|
// scale the set weight accordingly based on the max block size value.
|
||||||
|
case cfg.BlockMaxSize != defaultBlockMaxSize &&
|
||||||
|
cfg.BlockMaxWeight == defaultBlockMaxWeight:
|
||||||
|
|
||||||
|
cfg.BlockMaxWeight = cfg.BlockMaxSize * blockchain.WitnessScaleFactor
|
||||||
|
}
|
||||||
|
|
||||||
// Look for illegal characters in the user agent comments.
|
// Look for illegal characters in the user agent comments.
|
||||||
for _, uaComment := range cfg.UserAgentComments {
|
for _, uaComment := range cfg.UserAgentComments {
|
||||||
|
|
172
mining/mining.go
172
mining/mining.go
|
@ -197,9 +197,9 @@ type BlockTemplate struct {
|
||||||
// sum of the fees of all other transactions.
|
// sum of the fees of all other transactions.
|
||||||
Fees []int64
|
Fees []int64
|
||||||
|
|
||||||
// SigOpCounts contains the number of signature operations each
|
// SigOpCosts contains the number of signature operations each
|
||||||
// transaction in the generated template performs.
|
// transaction in the generated template performs.
|
||||||
SigOpCounts []int64
|
SigOpCosts []int64
|
||||||
|
|
||||||
// Height is the height at which the block template connects to the main
|
// Height is the height at which the block template connects to the main
|
||||||
// chain.
|
// chain.
|
||||||
|
@ -210,6 +210,12 @@ type BlockTemplate struct {
|
||||||
// NewBlockTemplate for details on which this can be useful to generate
|
// NewBlockTemplate for details on which this can be useful to generate
|
||||||
// templates without a coinbase payment address.
|
// templates without a coinbase payment address.
|
||||||
ValidPayAddress bool
|
ValidPayAddress bool
|
||||||
|
|
||||||
|
// WitnessCommitment is a commitment to the witness data (if any)
|
||||||
|
// within the block. This field will only be populted once segregated
|
||||||
|
// witness has been activated, and the block contains a transaction
|
||||||
|
// which has witness data.
|
||||||
|
WitnessCommitment []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeUtxoView adds all of the entries in view to viewA. The result is that
|
// mergeUtxoView adds all of the entries in view to viewA. The result is that
|
||||||
|
@ -347,6 +353,7 @@ type BlkTmplGenerator struct {
|
||||||
chain *blockchain.BlockChain
|
chain *blockchain.BlockChain
|
||||||
timeSource blockchain.MedianTimeSource
|
timeSource blockchain.MedianTimeSource
|
||||||
sigCache *txscript.SigCache
|
sigCache *txscript.SigCache
|
||||||
|
hashCache *txscript.HashCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlkTmplGenerator returns a new block template generator for the given
|
// NewBlkTmplGenerator returns a new block template generator for the given
|
||||||
|
@ -358,7 +365,8 @@ type BlkTmplGenerator struct {
|
||||||
func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
|
func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
|
||||||
txSource TxSource, chain *blockchain.BlockChain,
|
txSource TxSource, chain *blockchain.BlockChain,
|
||||||
timeSource blockchain.MedianTimeSource,
|
timeSource blockchain.MedianTimeSource,
|
||||||
sigCache *txscript.SigCache) *BlkTmplGenerator {
|
sigCache *txscript.SigCache,
|
||||||
|
hashCache *txscript.HashCache) *BlkTmplGenerator {
|
||||||
|
|
||||||
return &BlkTmplGenerator{
|
return &BlkTmplGenerator{
|
||||||
policy: policy,
|
policy: policy,
|
||||||
|
@ -367,6 +375,7 @@ func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
timeSource: timeSource,
|
timeSource: timeSource,
|
||||||
sigCache: sigCache,
|
sigCache: sigCache,
|
||||||
|
hashCache: hashCache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,12 +460,13 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress btcutil.Address) (*Bloc
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// TODO(roasbeef): add witnesss commitment output
|
||||||
coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,
|
coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,
|
||||||
nextBlockHeight, payToAddress)
|
nextBlockHeight, payToAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
numCoinbaseSigOps := int64(blockchain.CountSigOps(coinbaseTx))
|
coinbaseSigOpCost := int64(blockchain.CountSigOps(coinbaseTx)) * blockchain.WitnessScaleFactor
|
||||||
|
|
||||||
// Get the current source transactions and create a priority queue to
|
// Get the current source transactions and create a priority queue to
|
||||||
// hold the transactions which are ready for inclusion into a block
|
// hold the transactions which are ready for inclusion into a block
|
||||||
|
@ -490,9 +500,9 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress btcutil.Address) (*Bloc
|
||||||
// However, since the total fees aren't known yet, use a dummy value for
|
// However, since the total fees aren't known yet, use a dummy value for
|
||||||
// the coinbase fee which will be updated later.
|
// the coinbase fee which will be updated later.
|
||||||
txFees := make([]int64, 0, len(sourceTxns))
|
txFees := make([]int64, 0, len(sourceTxns))
|
||||||
txSigOpCounts := make([]int64, 0, len(sourceTxns))
|
txSigOpCosts := make([]int64, 0, len(sourceTxns))
|
||||||
txFees = append(txFees, -1) // Updated once known
|
txFees = append(txFees, -1) // Updated once known
|
||||||
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)
|
txSigOpCosts = append(txSigOpCosts, coinbaseSigOpCost)
|
||||||
|
|
||||||
log.Debugf("Considering %d transactions for inclusion to new block",
|
log.Debugf("Considering %d transactions for inclusion to new block",
|
||||||
len(sourceTxns))
|
len(sourceTxns))
|
||||||
|
@ -570,6 +580,7 @@ mempoolLoop:
|
||||||
nextBlockHeight)
|
nextBlockHeight)
|
||||||
|
|
||||||
// Calculate the fee in Satoshi/kB.
|
// Calculate the fee in Satoshi/kB.
|
||||||
|
// TODO(roasbeef): cost accounting by weight
|
||||||
prioItem.feePerKB = txDesc.FeePerKB
|
prioItem.feePerKB = txDesc.FeePerKB
|
||||||
prioItem.fee = txDesc.Fee
|
prioItem.fee = txDesc.Fee
|
||||||
|
|
||||||
|
@ -591,10 +602,14 @@ mempoolLoop:
|
||||||
// The starting block size is the size of the block header plus the max
|
// The starting block size is the size of the block header plus the max
|
||||||
// possible transaction count size, plus the size of the coinbase
|
// possible transaction count size, plus the size of the coinbase
|
||||||
// transaction.
|
// transaction.
|
||||||
blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())
|
blockWeight := uint32((blockHeaderOverhead * (blockchain.WitnessScaleFactor - 1)) + blockchain.GetTransactionWeight(coinbaseTx))
|
||||||
blockSigOps := numCoinbaseSigOps
|
blockSigOpCost := coinbaseSigOpCost
|
||||||
totalFees := int64(0)
|
totalFees := int64(0)
|
||||||
|
|
||||||
|
// TODO(roasbeef): should be guarded by version bits state check
|
||||||
|
var witnessIncluded bool
|
||||||
|
includeWitness := true
|
||||||
|
|
||||||
// Choose which transactions make it into the block.
|
// Choose which transactions make it into the block.
|
||||||
for priorityQueue.Len() > 0 {
|
for priorityQueue.Len() > 0 {
|
||||||
// Grab the highest priority (or highest fee per kilobyte
|
// Grab the highest priority (or highest fee per kilobyte
|
||||||
|
@ -602,45 +617,73 @@ mempoolLoop:
|
||||||
prioItem := heap.Pop(priorityQueue).(*txPrioItem)
|
prioItem := heap.Pop(priorityQueue).(*txPrioItem)
|
||||||
tx := prioItem.tx
|
tx := prioItem.tx
|
||||||
|
|
||||||
|
switch {
|
||||||
|
// If segregated witness has not been activated yet, then we
|
||||||
|
// shouldn't include any witness transactions in the block.
|
||||||
|
case tx.HasWitness() && !segwitActive:
|
||||||
|
continue
|
||||||
|
|
||||||
|
// Otherwise, Keep track of if we've included a transaction
|
||||||
|
// with witness data or not. If so, then we'll need to include
|
||||||
|
// the witness commitment as the last output in the coinbase
|
||||||
|
// transaction.
|
||||||
|
case tx.HasWitness() && segwitActive:
|
||||||
|
// If we're about to include a transaction bearing
|
||||||
|
// witness data, then we'll also need to include a
|
||||||
|
// witness commitment in the coinbase transaction.
|
||||||
|
// Therefore, we account for the additional weight
|
||||||
|
// within the block.
|
||||||
|
if !witnessIncluded {
|
||||||
|
// First we account for the additional witness
|
||||||
|
// data in the witness nonce of the coinbaes
|
||||||
|
// transaction: 32-bytes of zeroes.
|
||||||
|
blockWeight += 2 + 32
|
||||||
|
|
||||||
|
// Next we account for the additional flag and
|
||||||
|
// marker bytes in the transaction
|
||||||
|
// serialization.
|
||||||
|
blockWeight += (1 + 1) * blockchain.WitnessScaleFactor
|
||||||
|
|
||||||
|
// Finally we account for the weight of the
|
||||||
|
// additional OP_RETURN output: 8-bytes (value)
|
||||||
|
// + 1-byte (var-int) + 38-bytes (pkScript),
|
||||||
|
// scaling up the weight as it's non-witness
|
||||||
|
// data.
|
||||||
|
blockWeight += (8 + 1 + 38) * blockchain.WitnessScaleFactor
|
||||||
|
}
|
||||||
|
|
||||||
|
witnessIncluded = true
|
||||||
|
}
|
||||||
|
|
||||||
// Grab any transactions which depend on this one.
|
// Grab any transactions which depend on this one.
|
||||||
deps := dependers[*tx.Hash()]
|
deps := dependers[*tx.Hash()]
|
||||||
|
|
||||||
// Enforce maximum block size. Also check for overflow.
|
// Enforce maximum block size. Also check for overflow.
|
||||||
txSize := uint32(tx.MsgTx().SerializeSize())
|
txWeight := uint32(blockchain.GetTransactionWeight(tx))
|
||||||
blockPlusTxSize := blockSize + txSize
|
blockPlusTxWeight := uint32(blockWeight + txWeight)
|
||||||
if blockPlusTxSize < blockSize ||
|
if blockPlusTxWeight < blockWeight ||
|
||||||
blockPlusTxSize >= g.policy.BlockMaxSize {
|
blockPlusTxWeight >= g.policy.BlockMaxWeight {
|
||||||
|
|
||||||
log.Tracef("Skipping tx %s because it would exceed "+
|
log.Tracef("Skipping tx %s because it would exceed "+
|
||||||
"the max block size", tx.Hash())
|
"the max block weight", tx.Hash())
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce maximum signature operations per block. Also check
|
// Enforce maximum signature operation cost per block. Also
|
||||||
// for overflow.
|
// check for overflow.
|
||||||
numSigOps := int64(blockchain.CountSigOps(tx))
|
sigOpCost, err := blockchain.GetSigOpCost(tx, false,
|
||||||
if blockSigOps+numSigOps < blockSigOps ||
|
blockUtxos, true, includeWitness)
|
||||||
blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {
|
|
||||||
log.Tracef("Skipping tx %s because it would exceed "+
|
|
||||||
"the maximum sigops per block", tx.Hash())
|
|
||||||
logSkippedDeps(tx, deps)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
numP2SHSigOps, err := blockchain.CountP2SHSigOps(tx, false,
|
|
||||||
blockUtxos)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Tracef("Skipping tx %s due to error in "+
|
log.Tracef("Skipping tx %s due to error in "+
|
||||||
"CountP2SHSigOps: %v", tx.Hash(), err)
|
"GetSigOpCost: %v", tx.Hash(), err)
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
numSigOps += int64(numP2SHSigOps)
|
if blockSigOpCost+int64(sigOpCost) < blockSigOpCost ||
|
||||||
if blockSigOps+numSigOps < blockSigOps ||
|
blockSigOpCost+int64(sigOpCost) > blockchain.MaxBlockSigOpsCost {
|
||||||
blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {
|
log.Tracef("Skipping tx %s because it would "+
|
||||||
log.Tracef("Skipping tx %s because it would exceed "+
|
"exceed the maximum sigops per block", tx.Hash())
|
||||||
"the maximum sigops per block (p2sh)",
|
|
||||||
tx.Hash())
|
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -649,13 +692,13 @@ mempoolLoop:
|
||||||
// minimum block size.
|
// minimum block size.
|
||||||
if sortedByFee &&
|
if sortedByFee &&
|
||||||
prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&
|
prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&
|
||||||
blockPlusTxSize >= g.policy.BlockMinSize {
|
blockPlusTxWeight >= g.policy.BlockMinWeight {
|
||||||
|
|
||||||
log.Tracef("Skipping tx %s with feePerKB %.2f "+
|
log.Tracef("Skipping tx %s with feePerKB %d "+
|
||||||
"< TxMinFreeFee %d and block size %d >= "+
|
"< TxMinFreeFee %d and block weight %d >= "+
|
||||||
"minBlockSize %d", tx.Hash(), prioItem.feePerKB,
|
"minBlockWeight %d", tx.Hash(), prioItem.feePerKB,
|
||||||
g.policy.TxMinFreeFee, blockPlusTxSize,
|
g.policy.TxMinFreeFee, blockPlusTxWeight,
|
||||||
g.policy.BlockMinSize)
|
g.policy.BlockMinWeight)
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -663,13 +706,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 >= g.policy.BlockPrioritySize ||
|
if !sortedByFee && (blockPlusTxWeight >= g.policy.BlockPrioritySize ||
|
||||||
prioItem.priority <= MinHighPriority) {
|
prioItem.priority <= MinHighPriority) {
|
||||||
|
|
||||||
log.Tracef("Switching to sort by fees per kilobyte "+
|
log.Tracef("Switching to sort by fees per "+
|
||||||
"blockSize %d >= BlockPrioritySize %d || "+
|
"kilobyte blockSize %d >= BlockPrioritySize "+
|
||||||
"priority %.2f <= minHighPriority %.2f",
|
"%d || priority %.2f <= minHighPriority %.2f",
|
||||||
blockPlusTxSize, g.policy.BlockPrioritySize,
|
blockPlusTxWeight, g.policy.BlockPrioritySize,
|
||||||
prioItem.priority, MinHighPriority)
|
prioItem.priority, MinHighPriority)
|
||||||
|
|
||||||
sortedByFee = true
|
sortedByFee = true
|
||||||
|
@ -677,11 +720,11 @@ mempoolLoop:
|
||||||
|
|
||||||
// Put the transaction back into the priority queue and
|
// Put the transaction back into the priority queue and
|
||||||
// skip it so it is re-priortized by fees if it won't
|
// skip it so it is re-priortized by fees if it won't
|
||||||
// fit into the high-priority section or the priority is
|
// fit into the high-priority section or the priority
|
||||||
// too low. Otherwise this transaction will be the
|
// is 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 > g.policy.BlockPrioritySize ||
|
if blockPlusTxWeight > g.policy.BlockPrioritySize ||
|
||||||
prioItem.priority < MinHighPriority {
|
prioItem.priority < MinHighPriority {
|
||||||
|
|
||||||
heap.Push(priorityQueue, prioItem)
|
heap.Push(priorityQueue, prioItem)
|
||||||
|
@ -700,11 +743,11 @@ mempoolLoop:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
|
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
|
||||||
txscript.StandardVerifyFlags, g.sigCache)
|
txscript.StandardVerifyFlags, g.sigCache,
|
||||||
|
g.hashCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Tracef("Skipping tx %s due to error in "+
|
log.Tracef("Skipping tx %s due to error in "+
|
||||||
"ValidateTransactionScripts: %v", tx.Hash(),
|
"ValidateTransactionScripts: %v", tx.Hash(), err)
|
||||||
err)
|
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -719,11 +762,11 @@ mempoolLoop:
|
||||||
// save the fees and signature operation counts to the block
|
// save the fees and signature operation counts to the block
|
||||||
// template.
|
// template.
|
||||||
blockTxns = append(blockTxns, tx)
|
blockTxns = append(blockTxns, tx)
|
||||||
blockSize += txSize
|
blockWeight += txWeight
|
||||||
blockSigOps += numSigOps
|
blockSigOpCost += int64(sigOpCost)
|
||||||
totalFees += prioItem.fee
|
totalFees += prioItem.fee
|
||||||
txFees = append(txFees, prioItem.fee)
|
txFees = append(txFees, prioItem.fee)
|
||||||
txSigOpCounts = append(txSigOpCounts, numSigOps)
|
txSigOpCosts = append(txSigOpCosts, int64(sigOpCost))
|
||||||
|
|
||||||
log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",
|
log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",
|
||||||
prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)
|
prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)
|
||||||
|
@ -742,13 +785,18 @@ mempoolLoop:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that the actual transactions have been selected, update the
|
// Now that the actual transactions have been selected, update the
|
||||||
// block size for the real transaction count and coinbase value with
|
// block weight for the real transaction count and coinbase value with
|
||||||
// the total fees accordingly.
|
// the total fees accordingly.
|
||||||
blockSize -= wire.MaxVarIntPayload -
|
blockWeight -= wire.MaxVarIntPayload -
|
||||||
uint32(wire.VarIntSerializeSize(uint64(len(blockTxns))))
|
(uint32(wire.VarIntSerializeSize(uint64(len(blockTxns)))) *
|
||||||
|
(blockchain.WitnessScaleFactor - 1))
|
||||||
coinbaseTx.MsgTx().TxOut[0].Value += totalFees
|
coinbaseTx.MsgTx().TxOut[0].Value += totalFees
|
||||||
txFees[0] = -totalFees
|
txFees[0] = -totalFees
|
||||||
|
|
||||||
|
// TODO(roasbeef): add witness commitment
|
||||||
|
if witnessIncluded {
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the required difficulty for the block. The timestamp
|
// Calculate the required difficulty for the block. The timestamp
|
||||||
// is potentially adjusted to ensure it comes after the median time of
|
// is potentially adjusted to ensure it comes after the median time of
|
||||||
// the last several blocks per the chain consensus rules.
|
// the last several blocks per the chain consensus rules.
|
||||||
|
@ -766,7 +814,7 @@ mempoolLoop:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new block ready to be solved.
|
// Create a new block ready to be solved.
|
||||||
merkles := blockchain.BuildMerkleTreeStore(blockTxns)
|
merkles := blockchain.BuildMerkleTreeStore(blockTxns, false)
|
||||||
var msgBlock wire.MsgBlock
|
var msgBlock wire.MsgBlock
|
||||||
msgBlock.Header = wire.BlockHeader{
|
msgBlock.Header = wire.BlockHeader{
|
||||||
Version: nextBlockVersion,
|
Version: nextBlockVersion,
|
||||||
|
@ -790,15 +838,15 @@ mempoolLoop:
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Created new block template (%d transactions, %d in fees, "+
|
log.Debugf("Created new block template (%d transactions, %d in "+
|
||||||
"%d signature operations, %d bytes, target difficulty %064x)",
|
"fees, %d signature operations cost, %d weight, target difficulty "+
|
||||||
len(msgBlock.Transactions), totalFees, blockSigOps, blockSize,
|
"%064x)", len(msgBlock.Transactions), totalFees, blockSigOpCost,
|
||||||
blockchain.CompactToBig(msgBlock.Header.Bits))
|
blockWeight, blockchain.CompactToBig(msgBlock.Header.Bits))
|
||||||
|
|
||||||
return &BlockTemplate{
|
return &BlockTemplate{
|
||||||
Block: &msgBlock,
|
Block: &msgBlock,
|
||||||
Fees: txFees,
|
Fees: txFees,
|
||||||
SigOpCounts: txSigOpCounts,
|
SigOpCosts: txSigOpCosts,
|
||||||
Height: nextBlockHeight,
|
Height: nextBlockHeight,
|
||||||
ValidPayAddress: payToAddress != nil,
|
ValidPayAddress: payToAddress != nil,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -852,7 +900,7 @@ func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight
|
||||||
|
|
||||||
// Recalculate the merkle root with the updated extra nonce.
|
// Recalculate the merkle root with the updated extra nonce.
|
||||||
block := btcutil.NewBlock(msgBlock)
|
block := btcutil.NewBlock(msgBlock)
|
||||||
merkles := blockchain.BuildMerkleTreeStore(block.Transactions())
|
merkles := blockchain.BuildMerkleTreeStore(block.Transactions(), false)
|
||||||
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
|
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,20 @@ const (
|
||||||
// the generation of block templates. See the documentation for
|
// the generation of block templates. See the documentation for
|
||||||
// NewBlockTemplate for more details on each of these parameters are used.
|
// NewBlockTemplate for more details on each of these parameters are used.
|
||||||
type Policy struct {
|
type Policy struct {
|
||||||
// BlockMinSize is the minimum block size in bytes to be used when
|
// BlockMinWeight is the minimum block weight to be used when
|
||||||
// generating a block template.
|
// generating a block template.
|
||||||
|
BlockMinWeight uint32
|
||||||
|
|
||||||
|
// BlockMaxWeight is the maximum block weight to be used when
|
||||||
|
// generating a block template.
|
||||||
|
BlockMaxWeight uint32
|
||||||
|
|
||||||
|
// BlockMinWeight is the minimum block size to be used when generating
|
||||||
|
// a block template.
|
||||||
BlockMinSize uint32
|
BlockMinSize uint32
|
||||||
|
|
||||||
// BlockMaxSize is the maximum block size in bytes to be used when
|
// BlockMaxSize is the maximum block size to be used when generating a
|
||||||
// generating a block template.
|
// block template.
|
||||||
BlockMaxSize uint32
|
BlockMaxSize uint32
|
||||||
|
|
||||||
// BlockPrioritySize is the size in bytes for high-priority / low-fee
|
// BlockPrioritySize is the size in bytes for high-priority / low-fee
|
||||||
|
|
|
@ -173,6 +173,7 @@ type server struct {
|
||||||
addrManager *addrmgr.AddrManager
|
addrManager *addrmgr.AddrManager
|
||||||
connManager *connmgr.ConnManager
|
connManager *connmgr.ConnManager
|
||||||
sigCache *txscript.SigCache
|
sigCache *txscript.SigCache
|
||||||
|
hashCache *txscript.HashCache
|
||||||
rpcServer *rpcServer
|
rpcServer *rpcServer
|
||||||
blockManager *blockManager
|
blockManager *blockManager
|
||||||
txMemPool *mempool.TxPool
|
txMemPool *mempool.TxPool
|
||||||
|
@ -2412,6 +2413,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
||||||
timeSource: blockchain.NewMedianTime(),
|
timeSource: blockchain.NewMedianTime(),
|
||||||
services: services,
|
services: services,
|
||||||
sigCache: txscript.NewSigCache(cfg.SigCacheMaxSize),
|
sigCache: txscript.NewSigCache(cfg.SigCacheMaxSize),
|
||||||
|
hashCache: txscript.NewHashCache(cfg.SigCacheMaxSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the transaction and address indexes if needed.
|
// Create the transaction and address indexes if needed.
|
||||||
|
@ -2459,7 +2461,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
||||||
FreeTxRelayLimit: cfg.FreeTxRelayLimit,
|
FreeTxRelayLimit: cfg.FreeTxRelayLimit,
|
||||||
MaxOrphanTxs: cfg.MaxOrphanTxs,
|
MaxOrphanTxs: cfg.MaxOrphanTxs,
|
||||||
MaxOrphanTxSize: defaultMaxOrphanTxSize,
|
MaxOrphanTxSize: defaultMaxOrphanTxSize,
|
||||||
MaxSigOpsPerTx: blockchain.MaxSigOpsPerBlock / 5,
|
MaxSigOpCostPerTx: blockchain.MaxBlockSigOpsCost / 4,
|
||||||
MinRelayTxFee: cfg.minRelayTxFee,
|
MinRelayTxFee: cfg.minRelayTxFee,
|
||||||
MaxTxVersion: 2,
|
MaxTxVersion: 2,
|
||||||
},
|
},
|
||||||
|
@ -2483,6 +2485,8 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
||||||
// NOTE: The CPU miner relies on the mempool, so the mempool has to be
|
// NOTE: The CPU miner relies on the mempool, so the mempool has to be
|
||||||
// created before calling the function to create the CPU miner.
|
// created before calling the function to create the CPU miner.
|
||||||
policy := mining.Policy{
|
policy := mining.Policy{
|
||||||
|
BlockMinWeight: cfg.BlockMinWeight,
|
||||||
|
BlockMaxWeight: cfg.BlockMaxWeight,
|
||||||
BlockMinSize: cfg.BlockMinSize,
|
BlockMinSize: cfg.BlockMinSize,
|
||||||
BlockMaxSize: cfg.BlockMaxSize,
|
BlockMaxSize: cfg.BlockMaxSize,
|
||||||
BlockPrioritySize: cfg.BlockPrioritySize,
|
BlockPrioritySize: cfg.BlockPrioritySize,
|
||||||
|
@ -2490,7 +2494,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
||||||
}
|
}
|
||||||
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
|
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
|
||||||
s.chainParams, s.txMemPool, s.blockManager.chain, s.timeSource,
|
s.chainParams, s.txMemPool, s.blockManager.chain, s.timeSource,
|
||||||
s.sigCache)
|
s.sigCache, s.hashCache)
|
||||||
s.cpuMiner = cpuminer.New(&cpuminer.Config{
|
s.cpuMiner = cpuminer.New(&cpuminer.Config{
|
||||||
ChainParams: chainParams,
|
ChainParams: chainParams,
|
||||||
BlockTemplateGenerator: blockTemplateGenerator,
|
BlockTemplateGenerator: blockTemplateGenerator,
|
||||||
|
|
Loading…
Add table
Reference in a new issue