mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-13 11:35:20 +01:00
386eecff5f
doc: add release notes (ismaelsadeeq)3eaa0a3b66
miner: init: add `-blockreservedweight` startup option (ismaelsadeeq)777434a2cd
doc: rpc: improve `getmininginfo` help text (ismaelsadeeq)c8acd4032d
init: fail to start when `-blockmaxweight` exceeds `MAX_BLOCK_WEIGHT` (ismaelsadeeq)5bb31633cc
test: add `-blockmaxweight` startup option functional test (ismaelsadeeq)2c7d90a6d6
miner: bugfix: fix duplicate weight reservation in block assembler (ismaelsadeeq) Pull request description: * This PR attempts to fix the duplicate coinbase weight reservation issue we currently have. * Fixes #21950 We reserve 4000 weight units for coinbase transaction in `DEFAULT_BLOCK_MAX_WEIGHT`7590e93bc7/src/policy/policy.h (L23)
And also reserve additional `4000` weight units in the default `BlockCreationOptions` struct.7590e93bc7/src/node/types.h (L36-L40)
**Motivation** - This issue was first noticed during a review here https://github.com/bitcoin/bitcoin/pull/11100#discussion_r136157411) - It was later reported in issue #21950. - I also came across the bug while writing a test for building the block template. I could not create a block template above `3,992,000` in the block assembler, and this was not documented anywhere. It took me a while to realize that we were reserving space for the coinbase transaction weight twice. --- This PR fixes this by consolidating the reservation to be in a single location in the codebase. This PR then adds a new startup option `-blockreservedweight` whose default is `8000` that can be used to lower or increase the block reserved weight for block header, txs count, coinbase tx. ACKs for top commit: Sjors: ACK386eecff5f
fjahr: Code review ACK386eecff5f
glozow: utACK386eecff5f
, nonblocking nits. I do think the release notes should be clarified more pinheadmz: ACK386eecff5f
Tree-SHA512: f27efa1da57947b7f4d42b9322b83d13afe73dd749dd9cac49360002824dd41c99a876a610554ac2d67bad7485020b9dcc423a8e6748fc79d6a10de6d4357d4c
232 lines
8.2 KiB
C++
232 lines
8.2 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_NODE_MINER_H
|
|
#define BITCOIN_NODE_MINER_H
|
|
|
|
#include <node/types.h>
|
|
#include <policy/policy.h>
|
|
#include <primitives/block.h>
|
|
#include <txmempool.h>
|
|
#include <util/feefrac.h>
|
|
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <stdint.h>
|
|
|
|
#include <boost/multi_index/identity.hpp>
|
|
#include <boost/multi_index/indexed_by.hpp>
|
|
#include <boost/multi_index/ordered_index.hpp>
|
|
#include <boost/multi_index/tag.hpp>
|
|
#include <boost/multi_index_container.hpp>
|
|
|
|
class ArgsManager;
|
|
class CBlockIndex;
|
|
class CChainParams;
|
|
class CScript;
|
|
class Chainstate;
|
|
class ChainstateManager;
|
|
|
|
namespace Consensus { struct Params; };
|
|
|
|
namespace node {
|
|
static const bool DEFAULT_PRINT_MODIFIED_FEE = false;
|
|
|
|
struct CBlockTemplate
|
|
{
|
|
CBlock block;
|
|
std::vector<CAmount> vTxFees;
|
|
std::vector<int64_t> vTxSigOpsCost;
|
|
std::vector<unsigned char> vchCoinbaseCommitment;
|
|
/* A vector of package fee rates, ordered by the sequence in which
|
|
* packages are selected for inclusion in the block template.*/
|
|
std::vector<FeeFrac> m_package_feerates;
|
|
};
|
|
|
|
// Container for tracking updates to ancestor feerate as we include (parent)
|
|
// transactions in a block
|
|
struct CTxMemPoolModifiedEntry {
|
|
explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
|
|
{
|
|
iter = entry;
|
|
nSizeWithAncestors = entry->GetSizeWithAncestors();
|
|
nModFeesWithAncestors = entry->GetModFeesWithAncestors();
|
|
nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors();
|
|
}
|
|
|
|
CAmount GetModifiedFee() const { return iter->GetModifiedFee(); }
|
|
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
|
|
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
|
|
size_t GetTxSize() const { return iter->GetTxSize(); }
|
|
const CTransaction& GetTx() const { return iter->GetTx(); }
|
|
|
|
CTxMemPool::txiter iter;
|
|
uint64_t nSizeWithAncestors;
|
|
CAmount nModFeesWithAncestors;
|
|
int64_t nSigOpCostWithAncestors;
|
|
};
|
|
|
|
/** Comparator for CTxMemPool::txiter objects.
|
|
* It simply compares the internal memory address of the CTxMemPoolEntry object
|
|
* pointed to. This means it has no meaning, and is only useful for using them
|
|
* as key in other indexes.
|
|
*/
|
|
struct CompareCTxMemPoolIter {
|
|
bool operator()(const CTxMemPool::txiter& a, const CTxMemPool::txiter& b) const
|
|
{
|
|
return &(*a) < &(*b);
|
|
}
|
|
};
|
|
|
|
struct modifiedentry_iter {
|
|
typedef CTxMemPool::txiter result_type;
|
|
result_type operator() (const CTxMemPoolModifiedEntry &entry) const
|
|
{
|
|
return entry.iter;
|
|
}
|
|
};
|
|
|
|
// A comparator that sorts transactions based on number of ancestors.
|
|
// This is sufficient to sort an ancestor package in an order that is valid
|
|
// to appear in a block.
|
|
struct CompareTxIterByAncestorCount {
|
|
bool operator()(const CTxMemPool::txiter& a, const CTxMemPool::txiter& b) const
|
|
{
|
|
if (a->GetCountWithAncestors() != b->GetCountWithAncestors()) {
|
|
return a->GetCountWithAncestors() < b->GetCountWithAncestors();
|
|
}
|
|
return CompareIteratorByHash()(a, b);
|
|
}
|
|
};
|
|
|
|
|
|
struct CTxMemPoolModifiedEntry_Indices final : boost::multi_index::indexed_by<
|
|
boost::multi_index::ordered_unique<
|
|
modifiedentry_iter,
|
|
CompareCTxMemPoolIter
|
|
>,
|
|
// sorted by modified ancestor fee rate
|
|
boost::multi_index::ordered_non_unique<
|
|
// Reuse same tag from CTxMemPool's similar index
|
|
boost::multi_index::tag<ancestor_score>,
|
|
boost::multi_index::identity<CTxMemPoolModifiedEntry>,
|
|
CompareTxMemPoolEntryByAncestorFee
|
|
>
|
|
>
|
|
{};
|
|
|
|
typedef boost::multi_index_container<
|
|
CTxMemPoolModifiedEntry,
|
|
CTxMemPoolModifiedEntry_Indices
|
|
> indexed_modified_transaction_set;
|
|
|
|
typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter;
|
|
typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator modtxscoreiter;
|
|
|
|
struct update_for_parent_inclusion
|
|
{
|
|
explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
|
|
|
|
void operator() (CTxMemPoolModifiedEntry &e)
|
|
{
|
|
e.nModFeesWithAncestors -= iter->GetModifiedFee();
|
|
e.nSizeWithAncestors -= iter->GetTxSize();
|
|
e.nSigOpCostWithAncestors -= iter->GetSigOpCost();
|
|
}
|
|
|
|
CTxMemPool::txiter iter;
|
|
};
|
|
|
|
/** Generate a new block, without valid proof-of-work */
|
|
class BlockAssembler
|
|
{
|
|
private:
|
|
// The constructed block template
|
|
std::unique_ptr<CBlockTemplate> pblocktemplate;
|
|
|
|
// Information on the current status of the block
|
|
uint64_t nBlockWeight;
|
|
uint64_t nBlockTx;
|
|
uint64_t nBlockSigOpsCost;
|
|
CAmount nFees;
|
|
std::unordered_set<Txid, SaltedTxidHasher> inBlock;
|
|
|
|
// Chain context for the block
|
|
int nHeight;
|
|
int64_t m_lock_time_cutoff;
|
|
|
|
const CChainParams& chainparams;
|
|
const CTxMemPool* const m_mempool;
|
|
Chainstate& m_chainstate;
|
|
|
|
public:
|
|
struct Options : BlockCreateOptions {
|
|
// Configuration parameters for the block size
|
|
size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT};
|
|
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
|
|
// Whether to call TestBlockValidity() at the end of CreateNewBlock().
|
|
bool test_block_validity{true};
|
|
bool print_modified_fee{DEFAULT_PRINT_MODIFIED_FEE};
|
|
};
|
|
|
|
explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options);
|
|
|
|
/** Construct a new block template */
|
|
std::unique_ptr<CBlockTemplate> CreateNewBlock();
|
|
|
|
/** The number of transactions in the last assembled block (excluding coinbase transaction) */
|
|
inline static std::optional<int64_t> m_last_block_num_txs{};
|
|
/** The weight of the last assembled block (including reserved weight for block header, txs count and coinbase tx) */
|
|
inline static std::optional<int64_t> m_last_block_weight{};
|
|
|
|
private:
|
|
const Options m_options;
|
|
|
|
// utility functions
|
|
/** Clear the block's state and prepare for assembling a new block */
|
|
void resetBlock();
|
|
/** Add a tx to the block */
|
|
void AddToBlock(CTxMemPool::txiter iter);
|
|
|
|
// Methods for how to add transactions to a block.
|
|
/** Add transactions based on feerate including unconfirmed ancestors
|
|
* Increments nPackagesSelected / nDescendantsUpdated with corresponding
|
|
* statistics from the package selection (for logging statistics).
|
|
*
|
|
* @pre BlockAssembler::m_mempool must not be nullptr
|
|
*/
|
|
void addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(!m_mempool->cs);
|
|
|
|
// helper functions for addPackageTxs()
|
|
/** Remove confirmed (inBlock) entries from given set */
|
|
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
|
|
/** Test if a new package would "fit" in the block */
|
|
bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const;
|
|
/** Perform checks on each transaction in a package:
|
|
* locktime, premature-witness, serialized size (if necessary)
|
|
* These checks should always succeed, and they're here
|
|
* only as an extra check in case of suboptimal node configuration */
|
|
bool TestPackageTransactions(const CTxMemPool::setEntries& package) const;
|
|
/** Sort the package in an order that is valid to appear in a block */
|
|
void SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries);
|
|
};
|
|
|
|
/**
|
|
* Get the minimum time a miner should use in the next block. This always
|
|
* accounts for the BIP94 timewarp rule, so does not necessarily reflect the
|
|
* consensus limit.
|
|
*/
|
|
int64_t GetMinimumTime(const CBlockIndex* pindexPrev, const int64_t difficulty_adjustment_interval);
|
|
|
|
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
|
|
|
|
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
|
|
void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
|
|
|
|
/** Apply -blockmintxfee and -blockmaxweight options from ArgsManager to BlockAssembler options. */
|
|
void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options);
|
|
} // namespace node
|
|
|
|
#endif // BITCOIN_NODE_MINER_H
|