diff options
Diffstat (limited to 'src/miner.cpp')
-rw-r--r-- | src/miner.cpp | 101 |
1 files changed, 75 insertions, 26 deletions
diff --git a/src/miner.cpp b/src/miner.cpp index a7bf9ae84c..cfc2dae56e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -45,6 +45,7 @@ using namespace std; uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; +uint64_t nLastBlockCost = 0; class ScoreCompare { @@ -75,15 +76,36 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam BlockAssembler::BlockAssembler(const CChainParams& _chainparams) : chainparams(_chainparams) { - // Largest block you're willing to create: - nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); - // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + // Block resource limits + // If neither -blockmaxsize or -blockmaxcost is given, limit to DEFAULT_BLOCK_MAX_* + // If only one is given, only restrict the specified resource. + // If both are given, restrict both. + nBlockMaxCost = DEFAULT_BLOCK_MAX_COST; + nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; + bool fCostSet = false; + if (mapArgs.count("-blockmaxcost")) { + nBlockMaxCost = GetArg("-blockmaxcost", DEFAULT_BLOCK_MAX_COST); + nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE; + fCostSet = true; + } + if (mapArgs.count("-blockmaxsize")) { + nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); + if (!fCostSet) { + nBlockMaxCost = nBlockMaxSize * WITNESS_SCALE_FACTOR; + } + } + // Limit cost to between 4K and MAX_BLOCK_COST-4K for sanity: + nBlockMaxCost = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_COST-4000), nBlockMaxCost)); + // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity: + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SERIALIZED_SIZE-1000), nBlockMaxSize)); // Minimum block size you want to create; block will be filled with free transactions // until there are no more or the block reaches this size: nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); + + // Whether we need to account for byte usage (in addition to cost usage) + fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000) || (nBlockMinSize > 0); } void BlockAssembler::resetBlock() @@ -92,7 +114,8 @@ void BlockAssembler::resetBlock() // Reserve space for coinbase tx nBlockSize = 1000; - nBlockSigOps = 100; + nBlockCost = 4000; + nBlockSigOpsCost = 400; fIncludeWitness = false; // These counters do not include coinbase tx @@ -116,7 +139,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) // Add dummy coinbase tx as first transaction pblock->vtx.push_back(CTransaction()); pblocktemplate->vTxFees.push_back(-1); // updated at end - pblocktemplate->vTxSigOps.push_back(-1); // updated at end + pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); @@ -144,11 +167,18 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()); addPriorityTxs(); - addPackageTxs(); + if (fNeedSizeAccounting) { + // addPackageTxs (the CPFP-based algorithm) cannot deal with size based + // accounting, so fall back to the old algorithm. + addScoreTxs(); + } else { + addPackageTxs(); + } nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); + nLastBlockCost = nBlockCost; + LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOpsCost); // Create coinbase transaction. CMutableTransaction coinbaseTx; @@ -167,7 +197,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; - pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); + pblocktemplate->vTxSigOpsCost[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { @@ -201,11 +231,12 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet) } } -bool BlockAssembler::TestPackage(uint64_t packageSize, unsigned int packageSigOps) +bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) { - if (nBlockSize + packageSize >= nBlockMaxSize) + // TODO: switch to cost-based accounting for packages instead of vsize-based accounting. + if (nBlockCost + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxCost) return false; - if (nBlockSigOps + packageSigOps >= MAX_BLOCK_SIGOPS) + if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST) return false; return true; } @@ -223,26 +254,39 @@ bool BlockAssembler::TestPackageFinality(const CTxMemPool::setEntries& package) bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter) { - if (nBlockSize + iter->GetTxSize() >= nBlockMaxSize) { + if (nBlockCost + iter->GetTxCost() >= nBlockMaxCost) { // If the block is so close to full that no more txs will fit // or if we've tried more than 50 times to fill remaining space // then flag that the block is finished - if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { + if (nBlockCost > nBlockMaxCost - 400 || lastFewTxs > 50) { blockFinished = true; return false; } - // Once we're within 1000 bytes of a full block, only look at 50 more txs + // Once we're within 4000 cost of a full block, only look at 50 more txs // to try to fill the remaining space. - if (nBlockSize > nBlockMaxSize - 1000) { + if (nBlockCost > nBlockMaxCost - 4000) { lastFewTxs++; } return false; } - if (nBlockSigOps + iter->GetSigOpCount() >= MAX_BLOCK_SIGOPS) { + if (fNeedSizeAccounting) { + if (nBlockSize + ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION) >= nBlockMaxSize) { + if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { + blockFinished = true; + return false; + } + if (nBlockSize > nBlockMaxSize - 1000) { + lastFewTxs++; + } + return false; + } + } + + if (nBlockSigOpsCost + iter->GetSigOpCost() >= MAX_BLOCK_SIGOPS_COST) { // If the block has room for no more sig ops then // flag that the block is finished - if (nBlockSigOps > MAX_BLOCK_SIGOPS - 2) { + if (nBlockSigOpsCost > MAX_BLOCK_SIGOPS_COST - 8) { blockFinished = true; return false; } @@ -264,10 +308,13 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { pblock->vtx.push_back(iter->GetTx()); pblocktemplate->vTxFees.push_back(iter->GetFee()); - pblocktemplate->vTxSigOps.push_back(iter->GetSigOpCount()); - nBlockSize += iter->GetTxSize(); + pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost()); + if (fNeedSizeAccounting) { + nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION); + } + nBlockCost += iter->GetTxCost(); ++nBlockTx; - nBlockSigOps += iter->GetSigOpCount(); + nBlockSigOpsCost += iter->GetSigOpCost(); nFees += iter->GetFee(); inBlock.insert(iter); @@ -358,7 +405,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread CTxMemPoolModifiedEntry modEntry(desc); modEntry.nSizeWithAncestors -= it->GetTxSize(); modEntry.nModFeesWithAncestors -= it->GetModifiedFee(); - modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount(); + modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost(); mapModifiedTx.insert(modEntry); } else { mapModifiedTx.modify(mit, update_for_parent_inclusion(it)); @@ -460,19 +507,19 @@ void BlockAssembler::addPackageTxs() uint64_t packageSize = iter->GetSizeWithAncestors(); CAmount packageFees = iter->GetModFeesWithAncestors(); - unsigned int packageSigOps = iter->GetSigOpCountWithAncestors(); + int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors(); if (fUsingModified) { packageSize = modit->nSizeWithAncestors; packageFees = modit->nModFeesWithAncestors; - packageSigOps = modit->nSigOpCountWithAncestors; + packageSigOpsCost = modit->nSigOpCostWithAncestors; } - if (packageFees < ::minRelayTxFee.GetFee(packageSize) && nBlockSize >= nBlockMinSize) { + if (packageFees < ::minRelayTxFee.GetFee(packageSize)) { // Everything else we might consider has a lower fee rate return; } - if (!TestPackage(packageSize, packageSigOps)) { + if (!TestPackage(packageSize, packageSigOpsCost)) { if (fUsingModified) { // Since we always look at the best entry in mapModifiedTx, // we must erase failed entries so that we can consider the @@ -526,6 +573,8 @@ void BlockAssembler::addPriorityTxs() return; } + fNeedSizeAccounting = true; + // This vector will be sorted into a priority queue: vector<TxCoinAgePriority> vecPriority; TxCoinAgePriorityCompare pricomparer; |