mempool: Create and use mempoolPolicy. (#571)

mempoolPolicy contains the values that configure the mempool policy.
This decouples the values from the internals of btcd to move closer
to a mempool package.
This commit is contained in:
David Hill 2016-04-11 17:37:52 -04:00 committed by Dave Collins
parent 5ff5fc5fa2
commit 123ff368f4
3 changed files with 84 additions and 71 deletions

View File

@ -26,27 +26,29 @@ import (
)
const (
defaultConfigFilename = "btcd.conf"
defaultDataDirname = "data"
defaultLogLevel = "info"
defaultLogDirname = "logs"
defaultLogFilename = "btcd.log"
defaultMaxPeers = 125
defaultBanDuration = time.Hour * 24
defaultBanThreshold = 100
defaultMaxRPCClients = 10
defaultMaxRPCWebsockets = 25
defaultVerifyEnabled = false
defaultDbType = "leveldb"
defaultFreeTxRelayLimit = 15.0
defaultBlockMinSize = 0
defaultBlockMaxSize = 750000
blockMaxSizeMin = 1000
blockMaxSizeMax = wire.MaxBlockPayload - 1000
defaultBlockPrioritySize = 50000
defaultGenerate = false
defaultAddrIndex = false
defaultSigCacheMaxSize = 50000
defaultConfigFilename = "btcd.conf"
defaultDataDirname = "data"
defaultLogLevel = "info"
defaultLogDirname = "logs"
defaultLogFilename = "btcd.log"
defaultMaxPeers = 125
defaultBanDuration = time.Hour * 24
defaultBanThreshold = 100
defaultMaxRPCClients = 10
defaultMaxRPCWebsockets = 25
defaultVerifyEnabled = false
defaultDbType = "leveldb"
defaultFreeTxRelayLimit = 15.0
defaultBlockMinSize = 0
defaultBlockMaxSize = 750000
blockMaxSizeMin = 1000
blockMaxSizeMax = wire.MaxBlockPayload - 1000
defaultBlockPrioritySize = 50000
defaultGenerate = false
defaultAddrIndex = false
defaultMaxOrphanTransactions = 1000
defaultMaxOrphanTxSize = 5000
defaultSigCacheMaxSize = 50000
)
var (
@ -341,8 +343,8 @@ func loadConfig() (*config, []string, error) {
BlockMinSize: defaultBlockMinSize,
BlockMaxSize: defaultBlockMaxSize,
BlockPrioritySize: defaultBlockPrioritySize,
MaxOrphanTxs: defaultMaxOrphanTransactions,
SigCacheMaxSize: defaultSigCacheMaxSize,
MaxOrphanTxs: maxOrphanTransactions,
Generate: defaultGenerate,
AddrIndex: defaultAddrIndex,
}

View File

@ -26,20 +26,6 @@ const (
// mempoolHeight is the height used for the "block" height field of the
// contextual transaction information provided in a transaction store.
mempoolHeight = 0x7fffffff
// maxOrphanTransactions is the maximum number of orphan transactions
// that can be queued.
maxOrphanTransactions = 1000
// maxOrphanTxSize is the maximum size allowed for orphan transactions.
// This helps prevent memory exhaustion attacks from sending a lot of
// of big orphans.
maxOrphanTxSize = 5000
// maxSigOpsPerTx is the maximum number of signature operations
// in a single transaction we will relay or mine. It is a fraction
// of the max signature operations for a block.
maxSigOpsPerTx = blockchain.MaxSigOpsPerBlock / 5
)
// mempoolTxDesc is a descriptor containing a transaction in the mempool along
@ -54,10 +40,6 @@ type mempoolTxDesc struct {
// mempoolConfig is a descriptor containing the memory pool configuration.
type mempoolConfig struct {
// DisableRelayPriority defines whether to relay free or low-fee
// transactions that do not have enough priority to be relayed.
DisableRelayPriority bool
// EnableAddrIndex defines whether the address index should be enabled.
EnableAddrIndex bool
@ -65,21 +47,13 @@ type mempoolConfig struct {
// transacation information.
FetchTransactionStore func(*btcutil.Tx, bool) (blockchain.TxStore, error)
// FreeTxRelayLimit defines the given amount in thousands of bytes
// per minute that transactions with no fee are rate limited to.
FreeTxRelayLimit float64
// MaxOrphanTxs defines the maximum number of orphan transactions to
// keep in memory.
MaxOrphanTxs int
// MinRelayTxFee defines the minimum transaction fee in BTC/kB to be
// considered a non-zero fee.
MinRelayTxFee btcutil.Amount
// NewestSha defines the function to retrieve the newest sha
NewestSha func() (*wire.ShaHash, int32, error)
// Policy defines the various mempool configuration options related
// to policy.
Policy mempoolPolicy
// RelayNtfnChan defines the channel to send newly accepted transactions
// to. If unset or set to nil, notifications will not be sent.
RelayNtfnChan chan *btcutil.Tx
@ -91,6 +65,36 @@ type mempoolConfig struct {
TimeSource blockchain.MedianTimeSource
}
// mempoolPolicy houses the policy (configuration parameters) which is used to
// control the mempool.
type mempoolPolicy struct {
// DisableRelayPriority defines whether to relay free or low-fee
// transactions that do not have enough priority to be relayed.
DisableRelayPriority bool
// FreeTxRelayLimit defines the given amount in thousands of bytes
// per minute that transactions with no fee are rate limited to.
FreeTxRelayLimit float64
// MaxOrphanTxs is the maximum number of orphan transactions
// that can be queued.
MaxOrphanTxs int
// MaxOrphanTxSize is the maximum size allowed for orphan transactions.
// This helps prevent memory exhaustion attacks from sending a lot of
// of big orphans.
MaxOrphanTxSize int
// MaxSigOpsPerTx is the maximum number of signature operations
// in a single transaction we will relay or mine. It is a fraction
// of the max signature operations for a block.
MaxSigOpsPerTx int
// MinRelayTxFee defines the minimum transaction fee in BTC/kB to be
// considered a non-zero fee.
MinRelayTxFee btcutil.Amount
}
// txMemPool is used as a source of transactions that need to be mined into
// blocks and relayed to other peers. It is safe for concurrent access from
// multiple peers.
@ -156,7 +160,9 @@ func (mp *txMemPool) RemoveOrphan(txHash *wire.ShaHash) {
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *txMemPool) limitNumOrphans() error {
if len(mp.orphans)+1 > mp.cfg.MaxOrphanTxs && mp.cfg.MaxOrphanTxs > 0 {
if len(mp.orphans)+1 > mp.cfg.Policy.MaxOrphanTxs &&
mp.cfg.Policy.MaxOrphanTxs > 0 {
// Generate a cryptographically random hash.
randHashBytes := make([]byte, wire.HashSize)
_, err := rand.Read(randHashBytes)
@ -222,13 +228,13 @@ func (mp *txMemPool) maybeAddOrphan(tx *btcutil.Tx) error {
//
// Note that the number of orphan transactions in the orphan pool is
// also limited, so this equates to a maximum memory used of
// maxOrphanTxSize * mp.cfg.MaxOrphanTxs (which is ~5MB using the default
// values at the time this comment was written).
// mp.cfg.Policy.MaxOrphanTxSize * mp.cfg.Policy.MaxOrphanTxs (which is ~5MB
// using the default values at the time this comment was written).
serializedLen := tx.MsgTx().SerializeSize()
if serializedLen > maxOrphanTxSize {
if serializedLen > mp.cfg.Policy.MaxOrphanTxSize {
str := fmt.Sprintf("orphan transaction size of %d bytes is "+
"larger than max allowed size of %d bytes",
serializedLen, maxOrphanTxSize)
serializedLen, mp.cfg.Policy.MaxOrphanTxSize)
return txRuleError(wire.RejectNonstandard, str)
}
@ -654,7 +660,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
// forbid their relaying.
if !activeNetParams.RelayNonStdTxs {
err := checkTransactionStandard(tx, nextBlockHeight,
mp.cfg.TimeSource, mp.cfg.MinRelayTxFee)
mp.cfg.TimeSource, mp.cfg.Policy.MinRelayTxFee)
if err != nil {
// Attempt to extract a reject code from the error so
// it can be retained. When not possible, fall back to
@ -767,9 +773,9 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
return nil, err
}
numSigOps += blockchain.CountSigOps(tx)
if numSigOps > maxSigOpsPerTx {
if numSigOps > mp.cfg.Policy.MaxSigOpsPerTx {
str := fmt.Sprintf("transaction %v has too many sigops: %d > %d",
txHash, numSigOps, maxSigOpsPerTx)
txHash, numSigOps, mp.cfg.Policy.MaxSigOpsPerTx)
return nil, txRuleError(wire.RejectNonstandard, str)
}
@ -785,7 +791,8 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
// transaction does not exceeed 1000 less than the reserved space for
// high-priority transactions, don't require a fee for it.
serializedSize := int64(tx.MsgTx().SerializeSize())
minFee := calcMinRequiredTxRelayFee(serializedSize, mp.cfg.MinRelayTxFee)
minFee := calcMinRequiredTxRelayFee(serializedSize,
mp.cfg.Policy.MinRelayTxFee)
if serializedSize >= (defaultBlockPrioritySize-1000) && txFee < minFee {
str := fmt.Sprintf("transaction %v has %d fees which is under "+
"the required amount of %d", txHash, txFee,
@ -797,7 +804,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
// in the next block. Transactions which are being added back to the
// memory pool from blocks that have been disconnected during a reorg
// are exempted.
if isNew && !mp.cfg.DisableRelayPriority && txFee < minFee {
if isNew && !mp.cfg.Policy.DisableRelayPriority && txFee < minFee {
currentPriority := calcPriority(tx.MsgTx(), txStore,
nextBlockHeight)
if currentPriority <= minHighPriority {
@ -819,7 +826,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
mp.lastPennyUnix = nowUnix
// Are we still over the limit?
if mp.pennyTotal >= mp.cfg.FreeTxRelayLimit*10*1000 {
if mp.pennyTotal >= mp.cfg.Policy.FreeTxRelayLimit*10*1000 {
str := fmt.Sprintf("transaction %v has been rejected "+
"by the rate limiter due to low fees", txHash)
return nil, txRuleError(wire.RejectInsufficientFee, str)
@ -829,7 +836,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
mp.pennyTotal += float64(serializedSize)
txmpLog.Tracef("rate limit: curTotal %v, nextTotal: %v, "+
"limit %v", oldTotal, mp.pennyTotal,
mp.cfg.FreeTxRelayLimit*10*1000)
mp.cfg.Policy.FreeTxRelayLimit*10*1000)
}
// Verify crypto signatures for each input and reject the transaction if

View File

@ -2480,16 +2480,20 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
s.blockManager = bm
txC := mempoolConfig{
DisableRelayPriority: cfg.NoRelayPriority,
EnableAddrIndex: cfg.AddrIndex,
FetchTransactionStore: s.blockManager.blockChain.FetchTransactionStore,
FreeTxRelayLimit: cfg.FreeTxRelayLimit,
MaxOrphanTxs: cfg.MaxOrphanTxs,
MinRelayTxFee: cfg.minRelayTxFee,
NewestSha: s.db.NewestSha,
RelayNtfnChan: s.relayNtfnChan,
SigCache: s.sigCache,
TimeSource: s.timeSource,
Policy: mempoolPolicy{
DisableRelayPriority: cfg.NoRelayPriority,
FreeTxRelayLimit: cfg.FreeTxRelayLimit,
MaxOrphanTxs: cfg.MaxOrphanTxs,
MaxOrphanTxSize: defaultMaxOrphanTxSize,
MaxSigOpsPerTx: blockchain.MaxSigOpsPerBlock / 5,
MinRelayTxFee: cfg.minRelayTxFee,
},
RelayNtfnChan: s.relayNtfnChan,
SigCache: s.sigCache,
TimeSource: s.timeSource,
}
s.txMemPool = newTxMemPool(&txC)