Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/bench/block_assemble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <script/standard.h>
#include <node/miner.h>
#include <test/util/mining.h>
#include <test/util/script.h>
#include <test/util/setup_common.h>
Expand Down Expand Up @@ -51,5 +52,18 @@ static void AssembleBlock(benchmark::Bench& bench)
PrepareBlock(test_setup->m_node, SCRIPT_PUB);
});
}
static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench)
{
FastRandomContext det_rand{true};
auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()};
testing_setup->PopulateMempool(det_rand, /*num_transactions=*/1000, /*submit=*/true);
node::BlockAssembler::Options assembler_options;
assembler_options.test_block_validity = false;

bench.run([&] {
PrepareBlock(testing_setup->m_node, P2SH_OP_TRUE, assembler_options);
});
}

BENCHMARK(AssembleBlock, benchmark::PriorityLevel::HIGH);
BENCHMARK(BlockAssemblerAddPackageTxns, benchmark::PriorityLevel::LOW);
5 changes: 5 additions & 0 deletions src/bench/descriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <bench/bench.h>
#include <key.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <script/standard.h>

Expand All @@ -12,6 +13,8 @@

static void ExpandDescriptor(benchmark::Bench& bench)
{
ECC_Start();

const auto desc_str = "sh(multi(15,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06))";
const std::pair<int64_t, int64_t> range = {0, 1000};
FlatSigningProvider provider;
Expand All @@ -25,6 +28,8 @@ static void ExpandDescriptor(benchmark::Bench& bench)
assert(success);
}
});

ECC_Stop();
}

BENCHMARK(ExpandDescriptor, benchmark::PriorityLevel::HIGH);
62 changes: 31 additions & 31 deletions src/node/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,45 +62,42 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime;
}

BlockAssembler::Options::Options()
static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
{
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
options.nBlockMaxSize = std::clamp<size_t>(options.nBlockMaxSize, 1000, DEFAULT_BLOCK_MAX_SIZE);
return options;
}

BlockAssembler::BlockAssembler(Chainstate& chainstate, const NodeContext& node, const CTxMemPool* mempool, const Options& options) :
m_chain_helper(chainstate.ChainHelper()),
m_chainstate(chainstate),
m_chainstate{chainstate},
m_evoDb(*Assert(node.evodb)),
m_chainlocks(*Assert(node.chainlocks)),
m_clhandler(*Assert(node.clhandler)),
chainparams(chainstate.m_chainman.GetParams()),
m_mempool(mempool),
m_quorum_block_processor(*Assert(Assert(node.llmq_ctx)->quorum_block_processor))
m_mempool{mempool},
m_quorum_block_processor(*Assert(Assert(node.llmq_ctx)->quorum_block_processor)),
m_options{ClampOptions(options)}
{
blockMinFeeRate = options.blockMinFeeRate;
nBlockMaxSize = options.nBlockMaxSize;
}

static BlockAssembler::Options DefaultOptions()
void ApplyArgsManOptions(const ArgsManager& args, BlockAssembler::Options& options)
{
// Block resource limits
BlockAssembler::Options options;
options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
if (gArgs.IsArgSet("-blockmaxsize")) {
options.nBlockMaxSize = gArgs.GetIntArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
}
if (gArgs.IsArgSet("-blockmintxfee")) {
std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
} else {
options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
options.nBlockMaxSize = args.GetIntArg("-blockmaxsize", options.nBlockMaxSize);
if (const auto blockmintxfee{args.GetArg("-blockmintxfee")}) {
if (const auto parsed{ParseMoney(*blockmintxfee)}) options.blockMinFeeRate = CFeeRate{*parsed};
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
static BlockAssembler::Options ConfiguredOptions()
{
BlockAssembler::Options options;
ApplyArgsManOptions(gArgs, options);
return options;
}

BlockAssembler::BlockAssembler(Chainstate& chainstate, const NodeContext& node, const CTxMemPool* mempool)
: BlockAssembler(chainstate, node, mempool, DefaultOptions()) {}
: BlockAssembler(chainstate, node, mempool, ConfiguredOptions()) {}

void BlockAssembler::resetBlock()
{
Expand Down Expand Up @@ -177,7 +174,7 @@ static bool CalcCbTxBestChainlock(const chainlock::Chainlocks& chainlocks, const

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
int64_t nTimeStart = GetTimeMicros();
const auto time_start{SteadyClock::now()};

resetBlock();

Expand All @@ -204,8 +201,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
const bool fV20Active_context{DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V20)};

// Limit size to between 1K and MaxBlockSize()-1K for sanity:
nBlockMaxSize = std::max<unsigned int>(1000, std::min<unsigned int>(MaxBlockSize(fDIP0001Active_context) - 1000, nBlockMaxSize));
nBlockMaxSigOps = MaxBlockSigOps(fDIP0001Active_context);
m_options.nBlockMaxSize = std::max<unsigned int>(1000, std::min<unsigned int>(MaxBlockSize(fDIP0001Active_context) - 1000, m_options.nBlockMaxSize));
m_options.nBlockMaxSigOps = MaxBlockSigOps(fDIP0001Active_context);

pblock->nVersion = m_chainstate.m_chainman.m_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
// Non-mainnet only: allow overriding block.nVersion with
Expand Down Expand Up @@ -241,7 +238,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
addPackageTxs(*m_mempool, nPackagesSelected, nDescendantsUpdated, pindexPrev);
}

int64_t nTime1 = GetTimeMicros();
const auto time_1{SteadyClock::now()};

m_last_block_num_txs = nBlockTx;
m_last_block_size = nBlockSize;
Expand Down Expand Up @@ -330,12 +327,15 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);

BlockValidationState state;
if (!TestBlockValidity(state, m_chainlocks, m_evoDb, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
if (m_options.test_block_validity && !TestBlockValidity(state, m_chainlocks, m_evoDb, chainparams, m_chainstate, *pblock, pindexPrev, /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
}
int64_t nTime2 = GetTimeMicros();
const auto time_2{SteadyClock::now()};

LogPrint(BCLog::BENCHMARK, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));
LogPrint(BCLog::BENCHMARK, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n",
Ticks<MillisecondsDouble>(time_1 - time_start), nPackagesSelected, nDescendantsUpdated,
Ticks<MillisecondsDouble>(time_2 - time_1),
Ticks<MillisecondsDouble>(time_2 - time_start));

return std::move(pblocktemplate);
}
Expand All @@ -354,11 +354,11 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)

bool BlockAssembler::TestPackage(uint64_t packageSize, unsigned int packageSigOps) const
{
if (nBlockSize + packageSize >= nBlockMaxSize) {
if (nBlockSize + packageSize >= m_options.nBlockMaxSize) {
return false;
}

if (nBlockSigOps + packageSigOps >= nBlockMaxSigOps) {
if (nBlockSigOps + packageSigOps >= m_options.nBlockMaxSigOps) {
return false;
}
return true;
Expand Down Expand Up @@ -565,7 +565,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
packageSigOps = modit->nSigOpCountWithAncestors;
}

if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
if (packageFees < m_options.blockMinFeeRate.GetFee(packageSize)) {
// Everything else we might consider has a lower fee rate
return;
}
Expand All @@ -581,7 +581,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele

++nConsecutiveFailed;

if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockSize > nBlockMaxSize - 1000) {
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockSize > m_options.nBlockMaxSize - 1000) {
// Give up if we're close to full and haven't succeeded in a while
break;
}
Expand Down
21 changes: 13 additions & 8 deletions src/node/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef BITCOIN_NODE_MINER_H
#define BITCOIN_NODE_MINER_H

#include <policy/policy.h>
#include <primitives/block.h>
#include <txmempool.h>

Expand All @@ -19,6 +20,7 @@
#include <boost/multi_index/tag.hpp>
#include <boost/multi_index_container.hpp>

class ArgsManager;
class CBlockIndex;
class CChainParams;
class CChainstateHelper;
Expand Down Expand Up @@ -149,11 +151,6 @@ class BlockAssembler
// The constructed block template
std::unique_ptr<CBlockTemplate> pblocktemplate;

// Configuration parameters for the block size
unsigned int nBlockMaxSize;
unsigned int nBlockMaxSigOps;
CFeeRate blockMinFeeRate;

// Information on the current status of the block
uint64_t nBlockSize;
uint64_t nBlockTx;
Expand All @@ -176,9 +173,12 @@ class BlockAssembler

public:
struct Options {
Options();
size_t nBlockMaxSize;
CFeeRate blockMinFeeRate;
// Configuration parameters for the block size
mutable size_t nBlockMaxSize{DEFAULT_BLOCK_MAX_SIZE};
mutable size_t nBlockMaxSigOps{0};
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
// Whether to call TestBlockValidity() at the end of CreateNewBlock().
bool test_block_validity{true};
};

explicit BlockAssembler(Chainstate& chainstate, const node::NodeContext& node, const CTxMemPool* mempool);
Expand All @@ -191,6 +191,8 @@ class BlockAssembler
inline static std::optional<int64_t> m_last_block_size{};

private:
const Options m_options;

// utility functions
/** Clear the block's state and prepare for assembling a new block */
void resetBlock();
Expand Down Expand Up @@ -219,6 +221,9 @@ class BlockAssembler
};

int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);

/** Apply -blockmintxfee and -blockmaxsize options from ArgsManager to BlockAssembler options. */
void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} // namespace node

#endif // BITCOIN_NODE_MINER_H
2 changes: 1 addition & 1 deletion src/node/psbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
}

// Check if it is final
if (!utxo.IsNull() && !PSBTInputSigned(input)) {
if (!PSBTInputSignedAndVerified(psbtx, i, &txdata)) {
input_analysis.is_final = false;

// Figure out what is missing
Expand Down
9 changes: 5 additions & 4 deletions src/policy/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,15 +1009,16 @@ bool CBlockPolicyEstimator::Read(AutoFile& filein)
return true;
}

void CBlockPolicyEstimator::FlushUnconfirmed() {
int64_t startclear = GetTimeMicros();
void CBlockPolicyEstimator::FlushUnconfirmed()
{
const auto startclear{SteadyClock::now()};
LOCK(m_cs_fee_estimator);
size_t num_entries = mapMemPoolTxs.size();
// Remove every entry in mapMemPoolTxs
while (!mapMemPoolTxs.empty()) {
auto mi = mapMemPoolTxs.begin();
_removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
}
int64_t endclear = GetTimeMicros();
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %ld micros\n", num_entries, endclear - startclear);
const auto endclear{SteadyClock::now()};
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
}
8 changes: 8 additions & 0 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <iterator>
#include <limits>
#include <memory>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -205,6 +206,13 @@ class CTxOut

struct CMutableTransaction;

template<typename TxType>
inline CAmount CalculateOutputValue(const TxType& tx)
{
return std::accumulate(tx.vout.cbegin(), tx.vout.cend(), CAmount{0}, [](CAmount sum, const auto& txout) { return sum + txout.nValue; });
}


/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
Expand Down
30 changes: 29 additions & 1 deletion src/psbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,33 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
}

bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata)
Comment thread
knst marked this conversation as resolved.
{
CTxOut utxo;
assert(psbt.inputs.size() >= input_index);
const PSBTInput& input = psbt.inputs[input_index];
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if (input.non_witness_utxo) {
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
COutPoint prevout = psbt.tx->vin[input_index].prevout;
if (prevout.n >= input.non_witness_utxo->vout.size()) {
return false;
}
if (input.non_witness_utxo->GetHash() != prevout.hash) {
return false;
}
utxo = input.non_witness_utxo->vout[prevout.n];
} else {
return false;
}

if (txdata) {
return VerifyScript(input.final_script_sig, utxo.scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, *txdata, MissingDataBehavior::FAIL});
} else {
return VerifyScript(input.final_script_sig, utxo.scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, MissingDataBehavior::FAIL});
}
}

size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
size_t count = 0;
for (const auto& input : psbt.inputs) {
Expand Down Expand Up @@ -211,6 +238,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio
// Put redeem_script, key paths, into PSBTOutput.
psbt_out.FromSignatureData(sigdata);
}

bool PSBTInputSigned(const PSBTInput& input)
{
return !input.final_script_sig.empty();
Expand Down Expand Up @@ -238,7 +266,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
PSBTInput& input = psbt.inputs.at(index);
const CMutableTransaction& tx = *psbt.tx;

if (PSBTInputSigned(input)) {
if (PSBTInputSignedAndVerified(psbt, index, txdata)) {
return true;
}
Comment on lines +269 to 271

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return false for invalid finalized PSBT inputs

When a PSBT contains a nonempty but invalid final_script_sig and a matching non_witness_utxo, this check fails and execution falls through to FillSignatureData(), which marks the signature data complete; ProduceSignature() then immediately returns true without re-verifying it. Consequently FinalizePSBT/finalizepsbt can report completion and extract a transaction whose input script fails verification, while AnalyzePSBT labels the input ready for the finalizer. Keep the outer PSBTInputSigned(input) check and return the verification result for already-final inputs instead of falling through.

AGENTS.md reference: AGENTS.md:L176-L181

Useful? React with 👍 / 👎.

Comment thread
knst marked this conversation as resolved.

Expand Down
5 changes: 4 additions & 1 deletion src/psbt.h
Original file line number Diff line number Diff line change
Expand Up @@ -865,9 +865,12 @@ std::string PSBTRoleName(PSBTRole role);
/** Compute a PrecomputedTransactionData object from a psbt. */
PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction& psbt);

/** Checks whether a PSBTInput is already signed. */
/** Checks whether a PSBTInput is already signed by checking for non-null finalized fields. */
bool PSBTInputSigned(const PSBTInput& input);

/** Checks whether a PSBTInput is already signed by doing script verification using final fields. */
bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/** Signs a PSBTInput, verifying that all provided data matches what is being signed.
*
* txdata should be the output of PrecomputePSBTData (which can be shared across
Expand Down
6 changes: 3 additions & 3 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,18 +803,18 @@ static RPCHelpMan getblocktemplate()

// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
static int64_t time_start;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
if (pindexPrev != active_chain.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = nullptr;

// Store the ::ChainActive().Tip() used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = active_chain.Tip();
nStart = GetTime();
time_start = GetTime();

// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
Expand Down
Loading
Loading