Merge pull request #5309 from knst/bc-bp-v20-missing-2

backport: bitcoin#15921, #16507, #16524, #16889, #16911, #17004, #17195, #17624, partial #17212
This commit is contained in:
PastaPastaPasta 2023-04-17 10:43:36 -05:00 committed by GitHub
commit 03b0acd7d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 839 additions and 808 deletions

View File

@ -0,0 +1,8 @@
Low-level changes
=================
Tests
---
- `-fallbackfee` was 0 (disabled) by default for the main chain, but 1000 by default for the test chains. Now it is 0 by default for all chains. Testnet and regtest users will have to add fallbackfee=1000 to their configuration if they weren't setting it and they want it to keep working like before. (bitcoin#16524)

View File

@ -0,0 +1,31 @@
P2P and network changes
-----------------------
#### Removal of reject network messages from Dash Core (BIP61)
The command line option to enable BIP61 (`-enablebip61`) has been removed.
This feature has been disabled by default since Dash Core version 0.19.0.
Nodes on the network can not generally be trusted to send valid ("reject")
messages, so this should only ever be used when connected to a trusted node.
Since Dash Core version 0.20.0 there are extra changes:
The removal of BIP61 REJECT message support also has the following minor RPC
and logging implications:
* `testmempoolaccept` and `sendrawtransaction` no longer return the P2P REJECT
code when a transaction is not accepted to the mempool. They still return the
verbal reject reason.
* Log messages that previously reported the REJECT code when a transaction was
not accepted to the mempool now no longer report the REJECT code. The reason
for rejection is still reported.
Updated RPCs
------------
- `testmempoolaccept` and `sendrawtransaction` no longer return the P2P REJECT
code when a transaction is not accepted to the mempool. See the Section
_Removal of reject network messages from Bitcoin Core (BIP61)_ for details on
the removal of BIP61 REJECT message support.

View File

@ -327,6 +327,7 @@ BITCOIN_CORE_H = \
util/vector.h \ util/vector.h \
util/url.h \ util/url.h \
util/validation.h \ util/validation.h \
util/vector.h \
validation.h \ validation.h \
validationinterface.h \ validationinterface.h \
versionbits.h \ versionbits.h \

View File

@ -40,8 +40,8 @@ static void AssembleBlock(benchmark::Bench& bench)
LOCK(::cs_main); // Required for ::AcceptToMemoryPool. LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
for (const auto& txr : txs) { for (const auto& txr : txs) {
CValidationState state; TxValidationState state;
bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, nullptr /* pfMissingInputs */, false /* bypass_limits */, /* nAbsurdFee */ 0)}; bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, false /* bypass_limits */, /* nAbsurdFee */ 0)};
assert(ret); assert(ret);
} }
} }

View File

@ -42,7 +42,7 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
bool rewound = stream.Rewind(benchmark::data::block813851.size()); bool rewound = stream.Rewind(benchmark::data::block813851.size());
assert(rewound); assert(rewound);
CValidationState validationState; BlockValidationState validationState;
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), block.GetBlockTime()); bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), block.GetBlockTime());
assert(checked); assert(checked);
}); });

View File

@ -56,7 +56,7 @@ static void DuplicateInputs(benchmark::Bench& bench)
block.hashMerkleRoot = BlockMerkleRoot(block); block.hashMerkleRoot = BlockMerkleRoot(block);
bench.minEpochIterations(10).run([&] { bench.minEpochIterations(10).run([&] {
CValidationState cvstate{}; BlockValidationState cvstate{};
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false)); assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate"); assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
}); });

View File

@ -198,13 +198,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
if (vtx_missing.size() != tx_missing_offset) if (vtx_missing.size() != tx_missing_offset)
return READ_STATUS_INVALID; return READ_STATUS_INVALID;
CValidationState state; BlockValidationState state;
if (!CheckBlock(block, state, Params().GetConsensus())) { if (!CheckBlock(block, state, Params().GetConsensus())) {
// TODO: We really want to just check merkle tree manually here, // TODO: We really want to just check merkle tree manually here,
// but that is expensive, and CheckBlock caches a block's // but that is expensive, and CheckBlock caches a block's
// "checked-status" (in the CBlock?). CBlock should be able to // "checked-status" (in the CBlock?). CBlock should be able to
// check its own merkle root and cache that check. // check its own merkle root and cache that check.
if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED) if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED)
return READ_STATUS_FAILED; // Possible Short ID collision return READ_STATUS_FAILED; // Possible Short ID collision
return READ_STATUS_CHECKBLOCK_FAILED; return READ_STATUS_CHECKBLOCK_FAILED;
} }

View File

@ -351,8 +351,8 @@ bool CCoinJoin::IsCollateralValid(CTxMemPool& mempool, const CTransaction& txCol
{ {
LOCK(cs_main); LOCK(cs_main);
CValidationState validationState; TxValidationState validationState;
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*pfMissingInputs=*/nullptr, /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) { if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) {
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n"); LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n");
return false; return false;
} }

View File

@ -320,9 +320,9 @@ void CCoinJoinServer::CommitFinalTransaction()
{ {
// See if the transaction is valid // See if the transaction is valid
TRY_LOCK(cs_main, lockMain); TRY_LOCK(cs_main, lockMain);
CValidationState validationState; TxValidationState validationState;
mempool.PrioritiseTransaction(hashTx, 0.1 * COIN); mempool.PrioritiseTransaction(hashTx, 0.1 * COIN);
if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) { if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) {
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n"); LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
WITH_LOCK(cs_coinjoin, SetNull()); WITH_LOCK(cs_coinjoin, SetNull());
// not much we can do in this case, just notify clients // not much we can do in this case, just notify clients
@ -454,8 +454,8 @@ void CCoinJoinServer::ChargeRandomFees() const
void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const
{ {
LOCK(cs_main); LOCK(cs_main);
CValidationState validationState; TxValidationState validationState;
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) { if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__); LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__);
} else { } else {
connman.RelayTransaction(*txref); connman.RelayTransaction(*txref);

View File

@ -10,7 +10,7 @@
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <consensus/validation.h> #include <consensus/validation.h>
bool CheckTransaction(const CTransaction& tx, CValidationState& state) bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
{ {
bool allowEmptyTxInOut = false; bool allowEmptyTxInOut = false;
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
@ -19,25 +19,25 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
// Basic checks that don't depend on any context // Basic checks that don't depend on any context
if (!allowEmptyTxInOut && tx.vin.empty()) if (!allowEmptyTxInOut && tx.vin.empty())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vin-empty"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vin-empty");
if (!allowEmptyTxInOut && tx.vout.empty()) if (!allowEmptyTxInOut && tx.vout.empty())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-empty");
// Size limits // Size limits
if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE) if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-oversize");
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD) if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-payload-oversize"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-payload-oversize");
// Check for negative or overflow output values (see CVE-2010-5139) // Check for negative or overflow output values (see CVE-2010-5139)
CAmount nValueOut = 0; CAmount nValueOut = 0;
for (const auto& txout : tx.vout) { for (const auto& txout : tx.vout) {
if (txout.nValue < 0) if (txout.nValue < 0)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-negative"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY) if (txout.nValue > MAX_MONEY)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-toolarge"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-toolarge");
nValueOut += txout.nValue; nValueOut += txout.nValue;
if (!MoneyRange(nValueOut)) if (!MoneyRange(nValueOut))
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge");
} }
// Check for duplicate inputs (see CVE-2018-17144) // Check for duplicate inputs (see CVE-2018-17144)
@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
std::set<COutPoint> vInOutPoints; std::set<COutPoint> vInOutPoints;
for (const auto& txin : tx.vin) { for (const auto& txin : tx.vin) {
if (!vInOutPoints.insert(txin.prevout).second) if (!vInOutPoints.insert(txin.prevout).second)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputs-duplicate");
} }
if (tx.IsCoinBase()) { if (tx.IsCoinBase()) {
@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
minCbSize = 1; minCbSize = 1;
} }
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100) if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cb-length");
} else { } else {
for (const auto& txin : tx.vin) for (const auto& txin : tx.vin)
if (txin.prevout.IsNull()) if (txin.prevout.IsNull())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-prevout-null"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-prevout-null");
} }
return true; return true;

View File

@ -13,9 +13,9 @@
*/ */
class CTransaction; class CTransaction;
class CValidationState; class TxValidationState;
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state); bool CheckTransaction(const CTransaction& tx, TxValidationState& state);
#endif // BITCOIN_CONSENSUS_TX_CHECK_H #endif // BITCOIN_CONSENSUS_TX_CHECK_H

View File

@ -158,11 +158,12 @@ unsigned int GetTransactionSigOpCount(const CTransaction& tx, const CCoinsViewCa
return nSigOps; return nSigOps;
} }
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee) bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
{ {
// are the actual inputs available? // are the actual inputs available?
if (!inputs.HaveInputs(tx)) { if (!inputs.HaveInputs(tx)) {
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", strprintf("%s: inputs missing/spent", __func__)); return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",
strprintf("%s: inputs missing/spent", __func__));
} }
CAmount nValueIn = 0; CAmount nValueIn = 0;
@ -173,25 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
// If prev is coinbase, check that it's matured // If prev is coinbase, check that it's matured
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) { if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
} }
// Check for negative or overflow input values // Check for negative or overflow input values
nValueIn += coin.out.nValue; nValueIn += coin.out.nValue;
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) { if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange");
} }
} }
const CAmount value_out = tx.GetValueOut(); const CAmount value_out = tx.GetValueOut();
if (nValueIn < value_out) { if (nValueIn < value_out) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout", strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out))); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
} }
// Tally transaction fees // Tally transaction fees
const CAmount txfee_aux = nValueIn - value_out; const CAmount txfee_aux = nValueIn - value_out;
if (!MoneyRange(txfee_aux)) { if (!MoneyRange(txfee_aux)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
} }
txfee = txfee_aux; txfee = txfee_aux;

View File

@ -13,7 +13,7 @@
class CBlockIndex; class CBlockIndex;
class CCoinsViewCache; class CCoinsViewCache;
class CTransaction; class CTransaction;
class CValidationState; class TxValidationState;
/** Transaction validation functions */ /** Transaction validation functions */
@ -24,7 +24,7 @@ namespace Consensus {
* @param[out] txfee Set to the transaction fee if successful. * @param[out] txfee Set to the transaction fee if successful.
* Preconditions: tx.IsCoinBase() is false. * Preconditions: tx.IsCoinBase() is false.
*/ */
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
} // namespace Consensus } // namespace Consensus
/** Auxiliary functions for transaction validation (ideally should not be exposed) */ /** Auxiliary functions for transaction validation (ideally should not be exposed) */

View File

@ -8,31 +8,47 @@
#include <string> #include <string>
/** "reject" message codes */ /** A "reason" why a transaction was invalid, suitable for determining whether the
static const unsigned char REJECT_MALFORMED = 0x01; * provider of the transaction should be banned/ignored/disconnected/etc.
static const unsigned char REJECT_INVALID = 0x10;
static const unsigned char REJECT_OBSOLETE = 0x11;
static const unsigned char REJECT_DUPLICATE = 0x12;
static const unsigned char REJECT_NONSTANDARD = 0x40;
// static const unsigned char REJECT_DUST = 0x41; // part of BIP 61
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
static const unsigned char REJECT_CHECKPOINT = 0x43;
/** A "reason" why something was invalid, suitable for determining whether the
* provider of the object should be banned/ignored/disconnected/etc.
* These are much more granular than the rejection codes, which may be more
* useful for some other use-cases.
*/ */
enum class ValidationInvalidReason { enum class TxValidationResult {
// txn and blocks: TX_RESULT_UNSET, //!< initial value. Tx has not yet been rejected
NONE, //!< not actually invalid TX_CONSENSUS, //!< invalid by consensus rules
CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
/** /**
* Invalid by a change to consensus rules more recent than some major deployment. * Invalid by a change to consensus rules more recent than some major deployment.
*/ */
RECENT_CONSENSUS_CHANGE, // Only loose txn:
// Only blocks (or headers): TX_RECENT_CONSENSUS_CHANGE,
CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why TX_NOT_STANDARD, //!< didn't meet our local policy rules
TX_MISSING_INPUTS, //!< transaction was missing some of its inputs
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
TX_BAD_SPECIAL, //!< special transaction violates some rules that are not enough for insta-ban
/**
* Tx already in mempool or conflicts with a tx in the chain
* Currently this is only used if the transaction already exists in the mempool or on chain.
*/
TX_CONFLICT,
TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits
};
/** A "reason" why a block was invalid, suitable for determining whether the
* provider of the block should be banned/ignored/disconnected/etc.
* These are much more granular than the rejection codes, which may be more
* useful for some other use-cases.
*/
enum class BlockValidationResult {
BLOCK_RESULT_UNSET, //!< initial value. Block has not yet been rejected
BLOCK_CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
/**
* Invalid by a change to consensus rules more recent than SegWit.
* Currently unused as there are no such consensus rule changes, and any download
* sources realistically need to support SegWit in order to provide useful data,
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
* is uninteresting.
*/
BLOCK_RECENT_CONSENSUS_CHANGE,
BLOCK_CACHED_INVALID, //!< this block was cached as being invalid and we didn't store the reason why
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
@ -40,95 +56,78 @@ enum class ValidationInvalidReason {
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad) BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
BLOCK_CHAINLOCK, //!< the block conflicts with the ChainLock BLOCK_CHAINLOCK, //!< the block conflicts with the ChainLock
// Only loose txn:
TX_NOT_STANDARD, //!< didn't meet our local policy rules
TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
TX_BAD_SPECIAL, //!< special transaction violates some rules that are not enough for insta-ban
/**
* Tx already in mempool or conflicts with a tx in the chain
* TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
* TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
*/
TX_CONFLICT,
TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits
}; };
inline bool IsTransactionReason(ValidationInvalidReason r)
{
return r == ValidationInvalidReason::NONE ||
r == ValidationInvalidReason::CONSENSUS ||
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
r == ValidationInvalidReason::TX_NOT_STANDARD ||
r == ValidationInvalidReason::TX_PREMATURE_SPEND ||
r == ValidationInvalidReason::TX_MISSING_INPUTS ||
r == ValidationInvalidReason::TX_BAD_SPECIAL ||
r == ValidationInvalidReason::TX_CONFLICT ||
r == ValidationInvalidReason::TX_CONFLICT_LOCK ||
r == ValidationInvalidReason::TX_MEMPOOL_POLICY;
}
inline bool IsBlockReason(ValidationInvalidReason r)
{
return r == ValidationInvalidReason::NONE ||
r == ValidationInvalidReason::CONSENSUS ||
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
r == ValidationInvalidReason::CACHED_INVALID ||
r == ValidationInvalidReason::BLOCK_INVALID_HEADER ||
r == ValidationInvalidReason::BLOCK_MUTATED ||
r == ValidationInvalidReason::BLOCK_MISSING_PREV ||
r == ValidationInvalidReason::BLOCK_INVALID_PREV ||
r == ValidationInvalidReason::BLOCK_TIME_FUTURE ||
r == ValidationInvalidReason::BLOCK_CHECKPOINT ||
r == ValidationInvalidReason::BLOCK_CHAINLOCK;
}
/** Capture information about block/transaction validation */ /** Base class for capturing information about block/transaction validation. This is subclassed
class CValidationState { * by TxValidationState and BlockValidationState for validation information on transactions
* and blocks respectively. */
class ValidationState {
private: private:
enum mode_state { enum mode_state {
MODE_VALID, //!< everything ok MODE_VALID, //!< everything ok
MODE_INVALID, //!< network rule violation (DoS value may be set) MODE_INVALID, //!< network rule violation (DoS value may be set)
MODE_ERROR, //!< run-time error MODE_ERROR, //!< run-time error
} mode; } m_mode;
ValidationInvalidReason m_reason; std::string m_reject_reason;
std::string strRejectReason; std::string m_debug_message;
unsigned int chRejectCode; protected:
std::string strDebugMessage; void Invalid(const std::string &reject_reason="",
public: const std::string &debug_message="")
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {} {
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false, m_reject_reason = reject_reason;
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="", m_debug_message = debug_message;
const std::string &strDebugMessageIn="") { if (m_mode != MODE_ERROR) m_mode = MODE_INVALID;
m_reason = reasonIn;
chRejectCode = chRejectCodeIn;
strRejectReason = strRejectReasonIn;
strDebugMessage = strDebugMessageIn;
if (mode == MODE_ERROR)
return ret;
mode = MODE_INVALID;
return ret;
} }
bool Error(const std::string& strRejectReasonIn) { public:
if (mode == MODE_VALID) // ValidationState is abstract. Have a pure virtual destructor.
strRejectReason = strRejectReasonIn; virtual ~ValidationState() = 0;
mode = MODE_ERROR;
ValidationState() : m_mode(MODE_VALID) {}
bool Error(const std::string& reject_reason)
{
if (m_mode == MODE_VALID)
m_reject_reason = reject_reason;
m_mode = MODE_ERROR;
return false; return false;
} }
bool IsValid() const { bool IsValid() const { return m_mode == MODE_VALID; }
return mode == MODE_VALID; bool IsInvalid() const { return m_mode == MODE_INVALID; }
bool IsError() const { return m_mode == MODE_ERROR; }
std::string GetRejectReason() const { return m_reject_reason; }
std::string GetDebugMessage() const { return m_debug_message; }
};
inline ValidationState::~ValidationState() {};
class TxValidationState : public ValidationState {
private:
TxValidationResult m_result = TxValidationResult::TX_RESULT_UNSET;
public:
bool Invalid(TxValidationResult result,
const std::string &reject_reason="",
const std::string &debug_message="")
{
m_result = result;
ValidationState::Invalid(reject_reason, debug_message);
return false;
} }
bool IsInvalid() const { TxValidationResult GetResult() const { return m_result; }
return mode == MODE_INVALID; };
class BlockValidationState : public ValidationState {
private:
BlockValidationResult m_result = BlockValidationResult::BLOCK_RESULT_UNSET;
public:
bool Invalid(BlockValidationResult result,
const std::string &reject_reason="",
const std::string &debug_message="") {
m_result = result;
ValidationState::Invalid(reject_reason, debug_message);
return false;
} }
bool IsError() const { BlockValidationResult GetResult() const { return m_result; }
return mode == MODE_ERROR;
}
ValidationInvalidReason GetReason() const { return m_reason; }
unsigned int GetRejectCode() const { return chRejectCode; }
std::string GetRejectReason() const { return strRejectReason; }
std::string GetDebugMessage() const { return strDebugMessage; }
}; };
#endif // BITCOIN_CONSENSUS_VALIDATION_H #endif // BITCOIN_CONSENSUS_VALIDATION_H

View File

@ -15,33 +15,33 @@
#include <chainparams.h> #include <chainparams.h>
#include <consensus/merkle.h> #include <consensus/merkle.h>
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state)
{ {
if (tx.nType != TRANSACTION_COINBASE) { if (tx.nType != TRANSACTION_COINBASE) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-type");
} }
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-invalid"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-invalid");
} }
CCbTx cbTx; CCbTx cbTx;
if (!GetTxPayload(tx, cbTx)) { if (!GetTxPayload(tx, cbTx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload");
} }
if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) { if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version");
} }
if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) { if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-height"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-height");
} }
if (pindexPrev) { if (pindexPrev) {
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height; bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
if (fDIP0008Active && cbTx.nVersion < 2) { if (fDIP0008Active && cbTx.nVersion < 2) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version");
} }
} }
@ -49,7 +49,7 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidatio
} }
// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list // This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, CValidationState& state, const CCoinsViewCache& view) bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state, const CCoinsViewCache& view)
{ {
if (block.vtx[0]->nType != TRANSACTION_COINBASE) { if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
return true; return true;
@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
CCbTx cbTx; CCbTx cbTx;
if (!GetTxPayload(*block.vtx[0], cbTx)) { if (!GetTxPayload(*block.vtx[0], cbTx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-payload");
} }
int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1; int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
return false; return false;
} }
if (calculatedMerkleRoot != cbTx.merkleRootMNList) { if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-mnmerkleroot");
} }
int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2; int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
return false; return false;
} }
if (calculatedMerkleRoot != cbTx.merkleRootQuorums) { if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-quorummerkleroot");
} }
} }
@ -101,7 +101,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
return true; return true;
} }
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view) bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, BlockValidationState& state, const CCoinsViewCache& view)
{ {
LOCK(deterministicMNManager->cs); LOCK(deterministicMNManager->cs);
@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
if (sml == smlCached) { if (sml == smlCached) {
merkleRootRet = merkleRootCached; merkleRootRet = merkleRootCached;
if (mutatedCached) { if (mutatedCached) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-cached-calc-cb-mnmerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-cached-calc-cb-mnmerkleroot");
} }
return true; return true;
} }
@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
mutatedCached = mutated; mutatedCached = mutated;
if (mutated) { if (mutated) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cb-mnmerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cb-mnmerkleroot");
} }
return true; return true;
} catch (const std::exception& e) { } catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what()); LogPrintf("%s -- failed: %s\n", __func__, e.what());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-calc-cb-mnmerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-calc-cb-mnmerkleroot");
} }
} }
@ -223,7 +223,7 @@ auto CalcHashCountFromQCHashes(const QcHashMap& qcHashes)
return hash_count; return hash_count;
} }
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state) bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state)
{ {
static int64_t nTimeMined = 0; static int64_t nTimeMined = 0;
static int64_t nTimeLoop = 0; static int64_t nTimeLoop = 0;
@ -233,7 +233,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor); auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor);
if (!retVal) { if (!retVal) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "commitment-not-found"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "commitment-not-found");
} }
// The returned quorums are in reversed order, so the most recent one is at index 0 // The returned quorums are in reversed order, so the most recent one is at index 0
auto [qcHashes, qcIndexedHashes] = retVal.value(); auto [qcHashes, qcIndexedHashes] = retVal.value();
@ -249,7 +249,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) { if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
llmq::CFinalCommitmentTxPayload qc; llmq::CFinalCommitmentTxPayload qc;
if (!GetTxPayload(*tx, qc)) { if (!GetTxPayload(*tx, qc)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload-calc-cbtx-quorummerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload-calc-cbtx-quorummerkleroot");
} }
if (qc.commitment.IsNull()) { if (qc.commitment.IsNull()) {
// having null commitments is ok but we don't use them here, move to the next tx // having null commitments is ok but we don't use them here, move to the next tx
@ -257,7 +257,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
} }
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType); const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) { if (!llmq_params_opt.has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
} }
const auto& llmq_params = llmq_params_opt.value(); const auto& llmq_params = llmq_params_opt.value();
auto qcHash = ::SerializeHash(qc.commitment); auto qcHash = ::SerializeHash(qc.commitment);
@ -291,7 +291,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value()); assert(llmq_params_opt.has_value());
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) { if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "excess-quorums-calc-cbtx-quorummerkleroot");
} }
// Copy vec_hashes into vec_hashes_final // Copy vec_hashes into vec_hashes_final
std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final)); std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final));
@ -308,7 +308,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001); LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);
if (mutated) { if (mutated) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cbtx-quorummerkleroot"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cbtx-quorummerkleroot");
} }
return true; return true;

View File

@ -8,10 +8,11 @@
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <univalue.h> #include <univalue.h>
class BlockValidationState;
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
class CCoinsViewCache; class CCoinsViewCache;
class CValidationState; class TxValidationState;
namespace llmq { namespace llmq {
class CQuorumBlockProcessor; class CQuorumBlockProcessor;
@ -53,10 +54,10 @@ public:
} }
}; };
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state); bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state);
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, CValidationState& state, const CCoinsViewCache& view); bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state, const CCoinsViewCache& view);
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view); bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, BlockValidationState& state, const CCoinsViewCache& view);
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state); bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state);
#endif // BITCOIN_EVO_CBTX_H #endif // BITCOIN_EVO_CBTX_H

View File

@ -654,7 +654,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId()); mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
} }
bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& _state, const CCoinsViewCache& view, bool fJustCheck) bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -672,7 +672,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
try { try {
LOCK(cs); LOCK(cs);
if (!BuildNewListFromBlock(block, pindex->pprev, _state, view, newList, true)) { if (!BuildNewListFromBlock(block, pindex->pprev, state, view, newList, true)) {
// pass the state returned by the function above // pass the state returned by the function above
return false; return false;
} }
@ -710,7 +710,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff); mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
} catch (const std::exception& e) { } catch (const std::exception& e) {
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what()); LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-dmn-block"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-dmn-block");
} }
// Don't hold cs while calling signals // Don't hold cs while calling signals
@ -723,7 +723,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) { if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {
LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__, LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__,
pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight); pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight);
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-dip3-enf-block"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-dip3-enf-block");
} }
LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight); LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight);
} }
@ -775,7 +775,7 @@ void CDeterministicMNManager::UpdatedBlockTip(const CBlockIndex* pindex)
tipIndex = pindex; tipIndex = pindex;
} }
bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& _state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs) bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
@ -820,11 +820,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) { if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx; CProRegTx proTx;
if (!GetTxPayload(tx, proTx)) { if (!GetTxPayload(tx, proTx)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
} }
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) { if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
} }
auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType); auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType);
@ -842,7 +842,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) { if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
// should actually never get to this point as CheckProRegTx should have handled this case. // should actually never get to this point as CheckProRegTx should have handled this case.
// We do this additional check nevertheless to be 100% sure // We do this additional check nevertheless to be 100% sure
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral");
} }
auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint); auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
@ -858,10 +858,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
} }
if (newList.HasUniqueProperty(proTx.addr)) { if (newList.HasUniqueProperty(proTx.addr)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr");
} }
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) { if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-key"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-key");
} }
dmn->nOperatorReward = proTx.nOperatorReward; dmn->nOperatorReward = proTx.nOperatorReward;
@ -883,26 +883,26 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) { } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx; CProUpServTx proTx;
if (!GetTxPayload(tx, proTx)) { if (!GetTxPayload(tx, proTx)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
} }
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) { if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
} }
if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) { if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr");
} }
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
if (!dmn) { if (!dmn) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
} }
if (proTx.nType != dmn->nType) { if (proTx.nType != dmn->nType) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type-mismatch"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-type-mismatch");
} }
if (!IsValidMnType(proTx.nType)) { if (!IsValidMnType(proTx.nType)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-type");
} }
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState); auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
@ -932,12 +932,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) { } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
CProUpRegTx proTx; CProUpRegTx proTx;
if (!GetTxPayload(tx, proTx)) { if (!GetTxPayload(tx, proTx)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
} }
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
if (!dmn) { if (!dmn) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
} }
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState); auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) { if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
@ -958,12 +958,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) { } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
CProUpRevTx proTx; CProUpRevTx proTx;
if (!GetTxPayload(tx, proTx)) { if (!GetTxPayload(tx, proTx)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
} }
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
if (!dmn) { if (!dmn) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
} }
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState); auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
newState->ResetOperatorFields(); newState->ResetOperatorFields();
@ -979,19 +979,19 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
} else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { } else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
llmq::CFinalCommitmentTxPayload qc; llmq::CFinalCommitmentTxPayload qc;
if (!GetTxPayload(tx, qc)) { if (!GetTxPayload(tx, qc)) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload");
} }
if (!qc.commitment.IsNull()) { if (!qc.commitment.IsNull()) {
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType); const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) { if (!llmq_params_opt.has_value()) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type");
} }
int qcnHeight = int(qc.nHeight); int qcnHeight = int(qc.nHeight);
int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex); int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight); auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) { if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
// we should actually never get into this case as validation should have caught it...but let's be sure // we should actually never get into this case as validation should have caught it...but let's be sure
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-quorum-hash");
} }
HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs); HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs);
@ -1348,111 +1348,111 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
} }
template <typename ProTx> template <typename ProTx>
static bool CheckService(const ProTx& proTx, CValidationState& state) static bool CheckService(const ProTx& proTx, TxValidationState& state)
{ {
if (!proTx.addr.IsValid()) { if (!proTx.addr.IsValid()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr");
} }
if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) { if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr");
} }
static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
if (proTx.addr.GetPort() != mainnetDefaultPort) { if (proTx.addr.GetPort() != mainnetDefaultPort) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port");
} }
} else if (proTx.addr.GetPort() == mainnetDefaultPort) { } else if (proTx.addr.GetPort() == mainnetDefaultPort) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port");
} }
if (!proTx.addr.IsIPv4()) { if (!proTx.addr.IsIPv4()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr");
} }
return true; return true;
} }
template <typename ProTx> template <typename ProTx>
static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state) static bool CheckPlatformFields(const ProTx& proTx, TxValidationState& state)
{ {
if (proTx.platformNodeID.IsNull()) { if (proTx.platformNodeID.IsNull()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-nodeid"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-nodeid");
} }
static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort(); static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort();
if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
if (proTx.platformP2PPort != mainnetPlatformP2PPort) { if (proTx.platformP2PPort != mainnetPlatformP2PPort) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
} }
} }
static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort(); static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort();
if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) { if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
} }
} }
static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
if (proTx.platformP2PPort == mainnetDefaultP2PPort) { if (proTx.platformP2PPort == mainnetDefaultP2PPort) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
} }
if (proTx.platformHTTPPort == mainnetDefaultP2PPort) { if (proTx.platformHTTPPort == mainnetDefaultP2PPort) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
} }
if (proTx.platformP2PPort == proTx.platformHTTPPort || if (proTx.platformP2PPort == proTx.platformHTTPPort ||
proTx.platformP2PPort == proTx.addr.GetPort() || proTx.platformP2PPort == proTx.addr.GetPort() ||
proTx.platformHTTPPort == proTx.addr.GetPort()) { proTx.platformHTTPPort == proTx.addr.GetPort()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-dup-ports"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-dup-ports");
} }
return true; return true;
} }
template <typename ProTx> template <typename ProTx>
static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, CValidationState& state) static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state)
{ {
std::string strError; std::string strError;
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) { if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
} }
return true; return true;
} }
template <typename ProTx> template <typename ProTx>
static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, CValidationState& state) static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state)
{ {
std::string strError; std::string strError;
if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) { if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
} }
return true; return true;
} }
template <typename ProTx> template <typename ProTx>
static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state) static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, TxValidationState& state)
{ {
if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) { if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
} }
return true; return true;
} }
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs)
{ {
if (tx.nType != TRANSACTION_PROVIDER_REGISTER) { if (tx.nType != TRANSACTION_PROVIDER_REGISTER) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
} }
CProRegTx ptx; CProRegTx ptx;
if (!GetTxPayload(tx, ptx)) { if (!GetTxPayload(tx, ptx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
} }
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
// It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later // It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
@ -1477,31 +1477,31 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
if (!ptx.collateralOutpoint.hash.IsNull()) { if (!ptx.collateralOutpoint.hash.IsNull()) {
Coin coin; Coin coin;
if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) { if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral");
} }
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-dest");
} }
// Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH. // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest); keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest);
if (!keyForPayloadSig) { if (!keyForPayloadSig) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-pkh"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-pkh");
} }
collateralOutpoint = ptx.collateralOutpoint; collateralOutpoint = ptx.collateralOutpoint;
} else { } else {
if (ptx.collateralOutpoint.n >= tx.vout.size()) { if (ptx.collateralOutpoint.n >= tx.vout.size()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-index"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-index");
} }
if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) { if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral");
} }
if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) { if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-dest");
} }
collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n); collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n);
@ -1510,7 +1510,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
// this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH // this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH
if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) { if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-reuse");
} }
if (pindexPrev) { if (pindexPrev) {
@ -1518,30 +1518,30 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
// only allow reusing of addresses when it's for the same collateral (which replaces the old MN) // only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) { if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-addr");
} }
// never allow duplicate keys, even if this ProTx would replace an existing MN // never allow duplicate keys, even if this ProTx would replace an existing MN
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) { if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-key");
} }
// never allow duplicate platformNodeIds for HPMNs // never allow duplicate platformNodeIds for HPMNs
if (ptx.nType == MnType::HighPerformance) { if (ptx.nType == MnType::HighPerformance) {
if (mnList.HasUniqueProperty(ptx.platformNodeID)) { if (mnList.HasUniqueProperty(ptx.platformNodeID)) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-platformnodeid");
} }
} }
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
if (ptx.keyIDOwner != ptx.keyIDVoting) { if (ptx.keyIDOwner != ptx.keyIDVoting) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-not-same");
} }
} }
} }
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
if (keyForPayloadSig) { if (keyForPayloadSig) {
@ -1553,26 +1553,26 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
} else { } else {
// collateral is part of this ProRegTx, so we know the collateral is owned by the issuer // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
if (!ptx.vchSig.empty()) { if (!ptx.vchSig.empty()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
} }
} }
return true; return true;
} }
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs)
{ {
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
} }
CProUpServTx ptx; CProUpServTx ptx;
if (!GetTxPayload(tx, ptx)) { if (!GetTxPayload(tx, ptx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
} }
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
if (!CheckService(ptx, state)) { if (!CheckService(ptx, state)) {
@ -1590,34 +1590,34 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
auto mn = mnList.GetMN(ptx.proTxHash); auto mn = mnList.GetMN(ptx.proTxHash);
if (!mn) { if (!mn) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash");
} }
// don't allow updating to addresses already used by other MNs // don't allow updating to addresses already used by other MNs
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) { if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-addr");
} }
// don't allow updating to platformNodeIds already used by other HPMNs // don't allow updating to platformNodeIds already used by other HPMNs
if (ptx.nType == MnType::HighPerformance) { if (ptx.nType == MnType::HighPerformance) {
if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) { if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-platformnodeid");
} }
} }
if (ptx.scriptOperatorPayout != CScript()) { if (ptx.scriptOperatorPayout != CScript()) {
if (mn->nOperatorReward == 0) { if (mn->nOperatorReward == 0) {
// don't allow setting operator reward payee in case no operatorReward was set // don't allow setting operator reward payee in case no operatorReward was set
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-payee");
} }
if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) { if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-payee");
} }
} }
// we can only check the signature if pindexPrev != nullptr and the MN is known // we can only check the signature if pindexPrev != nullptr and the MN is known
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) { if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) {
// pass the state returned by the function above // pass the state returned by the function above
@ -1628,69 +1628,69 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
return true; return true;
} }
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs)
{ {
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
} }
CProUpRegTx ptx; CProUpRegTx ptx;
if (!GetTxPayload(tx, ptx)) { if (!GetTxPayload(tx, ptx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
} }
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
CTxDestination payoutDest; CTxDestination payoutDest;
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) { if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
// should not happen as we checked script types before // should not happen as we checked script types before
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-dest"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest");
} }
if (pindexPrev) { if (pindexPrev) {
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
auto dmn = mnList.GetMN(ptx.proTxHash); auto dmn = mnList.GetMN(ptx.proTxHash);
if (!dmn) { if (!dmn) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash");
} }
// don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server) // don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server)
if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) { if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-reuse"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse");
} }
Coin coin; Coin coin;
if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) { if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) {
// this should never happen (there would be no dmn otherwise) // this should never happen (there would be no dmn otherwise)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-collateral");
} }
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
CTxDestination collateralTxDest; CTxDestination collateralTxDest;
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral-dest"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-collateral-dest");
} }
if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) { if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-reuse");
} }
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) { if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator); auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
if (ptx.proTxHash != otherDmn->proTxHash) { if (ptx.proTxHash != otherDmn->proTxHash) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-key");
} }
} }
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) { if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-not-same");
} }
} }
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) { if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) {
// pass the state returned by the function above // pass the state returned by the function above
@ -1701,29 +1701,29 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
return true; return true;
} }
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs)
{ {
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
} }
CProUpRevTx ptx; CProUpRevTx ptx;
if (!GetTxPayload(tx, ptx)) { if (!GetTxPayload(tx, ptx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
} }
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
if (pindexPrev) { if (pindexPrev) {
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
auto dmn = mnList.GetMN(ptx.proTxHash); auto dmn = mnList.GetMN(ptx.proTxHash);
if (!dmn) if (!dmn)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash");
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
} }
if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) { if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) {
// pass the state returned by the function above // pass the state returned by the function above

View File

@ -27,7 +27,7 @@
class CConnman; class CConnman;
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
class CValidationState; class TxValidationState;
class CSimplifiedMNListDiff; class CSimplifiedMNListDiff;
extern CCriticalSection cs_main; extern CCriticalSection cs_main;
@ -563,14 +563,14 @@ public:
m_evoDb(evoDb), connman(_connman) {} m_evoDb(evoDb), connman(_connman) {}
~CDeterministicMNManager() = default; ~CDeterministicMNManager() = default;
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state,
const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs); const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs);
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs); bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
void UpdatedBlockTip(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs); void UpdatedBlockTip(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
// the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet) // the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet)
bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view,
CDeterministicMNList& mnListRet, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(cs); CDeterministicMNList& mnListRet, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(cs);
static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs); static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs);
static void DecreasePoSePenalties(CDeterministicMNList& mnList); static void DecreasePoSePenalties(CDeterministicMNList& mnList);
@ -595,10 +595,10 @@ private:
CDeterministicMNList GetListForBlockInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs); CDeterministicMNList GetListForBlockInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs);
}; };
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs); bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs);
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs); bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs);
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs); bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs);
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs); bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs);
extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager; extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;

View File

@ -34,33 +34,33 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset); llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset);
} }
bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
MNHFTxPayload mnhfTx; MNHFTxPayload mnhfTx;
if (!GetTxPayload(tx, mnhfTx)) { if (!GetTxPayload(tx, mnhfTx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload");
} }
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) { if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version");
} }
const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash); const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash);
if (!pindexQuorum) { if (!pindexQuorum) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash");
} }
if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) { if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
// not part of active chain // not part of active chain
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash");
} }
if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) { if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-type");
} }
if (!mnhfTx.signal.Verify(pindexQuorum)) { if (!mnhfTx.signal.Verify(pindexQuorum)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-invalid"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid");
} }
return true; return true;

View File

@ -12,7 +12,7 @@
#include <univalue.h> #include <univalue.h>
class CBlockIndex; class CBlockIndex;
class CValidationState; class TxValidationState;
extern CCriticalSection cs_main; extern CCriticalSection cs_main;
// mnhf signal special transaction // mnhf signal special transaction
@ -72,6 +72,6 @@ public:
} }
}; };
bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
#endif // BITCOIN_EVO_MNHFTX_H #endif // BITCOIN_EVO_MNHFTX_H

View File

@ -14,34 +14,34 @@
maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
{ {
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
} }
if (!IsValidMnType(nType)) { if (!IsValidMnType(nType)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-type"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-type"};
} }
if (nMode != 0) { if (nMode != 0) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"};
} }
if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) { if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null"};
} }
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) { if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"};
} }
CTxDestination payoutDest; CTxDestination payoutDest;
if (!ExtractDestination(scriptPayout, payoutDest)) { if (!ExtractDestination(scriptPayout, payoutDest)) {
// should not happen as we checked script types before // should not happen as we checked script types before
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee-dest"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest"};
} }
// don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server) // don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server)
if (payoutDest == CTxDestination(PKHash(keyIDOwner)) || payoutDest == CTxDestination(PKHash(keyIDVoting))) { if (payoutDest == CTxDestination(PKHash(keyIDOwner)) || payoutDest == CTxDestination(PKHash(keyIDVoting))) {
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee-reuse"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse"};
} }
if (nOperatorReward > 10000) { if (nOperatorReward > 10000) {
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-operator-reward"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-reward"};
} }
return {}; return {};
@ -87,7 +87,7 @@ std::string CProRegTx::ToString() const
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
{ {
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
} }
return {}; return {};
@ -108,17 +108,17 @@ std::string CProUpServTx::ToString() const
maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
{ {
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
} }
if (nMode != 0) { if (nMode != 0) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"};
} }
if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) { if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null"};
} }
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) { if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"}; return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"};
} }
return {}; return {};
} }
@ -138,13 +138,13 @@ std::string CProUpRegTx::ToString() const
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
{ {
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
} }
// nReason < CProUpRevTx::REASON_NOT_SPECIFIED is always `false` since // nReason < CProUpRevTx::REASON_NOT_SPECIFIED is always `false` since
// nReason is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0 // nReason is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0
if (nReason > CProUpRevTx::REASON_LAST) { if (nReason > CProUpRevTx::REASON_LAST) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-reason"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-reason"};
} }
return {}; return {};
} }

View File

@ -20,7 +20,7 @@
class CBlockIndex; class CBlockIndex;
class CCoinsViewCache; class CCoinsViewCache;
class CValidationState; class TxValidationState;
class CProRegTx class CProRegTx
{ {
@ -329,7 +329,7 @@ template <typename ProTx>
static maybe_error CheckInputsHash(const CTransaction& tx, const ProTx& proTx) static maybe_error CheckInputsHash(const CTransaction& tx, const ProTx& proTx)
{ {
if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) { if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-inputs-hash"}; return {TxValidationResult::TX_CONSENSUS, "bad-protx-inputs-hash"};
} }
return {}; return {};

View File

@ -17,11 +17,11 @@
struct maybe_error { struct maybe_error {
bool did_err{false}; bool did_err{false};
ValidationInvalidReason reason{ValidationInvalidReason::CONSENSUS}; TxValidationResult reason{TxValidationResult::TX_CONSENSUS};
std::string_view error_str; std::string_view error_str;
constexpr maybe_error() = default; constexpr maybe_error() = default;
constexpr maybe_error(ValidationInvalidReason reasonIn, std::string_view err): did_err(true), reason(reasonIn), error_str(err) {}; constexpr maybe_error(TxValidationResult reasonIn, std::string_view err): did_err(true), reason(reasonIn), error_str(err) {};
}; };
template <typename T> template <typename T>

View File

@ -16,7 +16,7 @@
#include <primitives/block.h> #include <primitives/block.h>
#include <validation.h> #include <validation.h>
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
return true; return true;
if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) { if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type");
} }
try { try {
@ -46,13 +46,13 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what()); LogPrintf("%s -- failed: %s\n", __func__, e.what());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-check-special-tx"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "failed-check-special-tx");
} }
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type-check"); return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type-check");
} }
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state) bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, TxValidationState& state)
{ {
if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) { if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) {
return true; return true;
@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
return true; // handled per block return true; // handled per block
} }
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-tx-type-proc"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-tx-type-proc");
} }
bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex) bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
@ -99,7 +99,7 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
} }
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor, bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor,
CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -112,13 +112,18 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
int64_t nTime1 = GetTimeMicros(); int64_t nTime1 = GetTimeMicros();
for (const auto& ptr_tx : block.vtx) { for (const auto& ptr_tx : block.vtx) {
if (!CheckSpecialTx(*ptr_tx, pindex->pprev, state, view, fCheckCbTxMerleRoots)) { TxValidationState tx_state;
// pass the state returned by the function above // At this moment CheckSpecialTx() and ProcessSpecialTx() may fail by 2 possible ways:
return false; // consensus failures and "TX_BAD_SPECIAL"
if (!CheckSpecialTx(*ptr_tx, pindex->pprev, tx_state, view, fCheckCbTxMerleRoots)) {
assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
strprintf("Special Transaction check failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage()));
} }
if (!ProcessSpecialTx(*ptr_tx, pindex, state)) { if (!ProcessSpecialTx(*ptr_tx, pindex, tx_state)) {
// pass the state returned by the function above assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL);
return false; return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
strprintf("Process Special Transaction failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage()));
} }
} }
@ -154,7 +159,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001); LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
} catch (const std::exception& e) { } catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what()); LogPrintf("%s -- failed: %s\n", __func__, e.what());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-procspectxsinblock");
} }
return true; return true;

View File

@ -9,19 +9,20 @@
#include <sync.h> #include <sync.h>
#include <threadsafety.h> #include <threadsafety.h>
class BlockValidationState;
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
class CCoinsViewCache; class CCoinsViewCache;
class CValidationState; class TxValidationState;
namespace llmq { namespace llmq {
class CQuorumBlockProcessor; class CQuorumBlockProcessor;
} // namespace llmq } // namespace llmq
extern CCriticalSection cs_main; extern CCriticalSection cs_main;
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor, bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor,
CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main); BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
#endif // BITCOIN_EVO_SPECIALTXMAN_H #endif // BITCOIN_EVO_SPECIALTXMAN_H

View File

@ -928,7 +928,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
// the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve
// the relevant pointers before the ABC call. // the relevant pointers before the ABC call.
for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
CValidationState state; BlockValidationState state;
if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) { if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) {
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state)); LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
StartShutdown(); StartShutdown();

View File

@ -23,7 +23,6 @@ class CFeeRate;
class CRPCCommand; class CRPCCommand;
class CScheduler; class CScheduler;
class CTxMemPool; class CTxMemPool;
class CValidationState;
class CFeeRate; class CFeeRate;
class CBlockIndex; class CBlockIndex;
class Coin; class Coin;

View File

@ -161,25 +161,6 @@ struct CExtKey {
bool Derive(CExtKey& out, unsigned int nChild) const; bool Derive(CExtKey& out, unsigned int nChild) const;
CExtPubKey Neuter() const; CExtPubKey Neuter() const;
void SetSeed(const unsigned char* seed, unsigned int nSeedLen); void SetSeed(const unsigned char* seed, unsigned int nSeedLen);
template <typename Stream>
void Serialize(Stream& s) const
{
unsigned int len = BIP32_EXTKEY_SIZE;
::WriteCompactSize(s, len);
unsigned char code[BIP32_EXTKEY_SIZE];
Encode(code);
s.write((const char *)&code[0], len);
}
template <typename Stream>
void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
if (len != BIP32_EXTKEY_SIZE)
throw std::runtime_error("Invalid extended key size\n");
s.read((char *)&code[0], len);
Decode(code);
}
}; };
/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */

View File

@ -136,7 +136,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
AddMineableCommitment(qc); AddMineableCommitment(qc);
} }
bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck, bool fBLSChecks) bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
const auto numCommitmentsInNewBlock = qcs.count(params.type); const auto numCommitmentsInNewBlock = qcs.count(params.type);
if (numCommitmentsRequired < numCommitmentsInNewBlock) { if (numCommitmentsRequired < numCommitmentsInNewBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-not-allowed"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-not-allowed");
} }
if (numCommitmentsRequired > numCommitmentsInNewBlock) { if (numCommitmentsRequired > numCommitmentsInNewBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-missing");
} }
if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) { if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock); LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
@ -210,7 +210,7 @@ static std::tuple<std::string, Consensus::LLMQType, int, uint32_t> BuildInversed
return std::make_tuple(DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT_Q_INDEXED, llmqType, quorumIndex, htobe32(std::numeric_limits<uint32_t>::max() - nMinedHeight)); return std::make_tuple(DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT_Q_INDEXED, llmqType, quorumIndex, htobe32(std::numeric_limits<uint32_t>::max() - nMinedHeight));
} }
bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck, bool fBLSChecks) bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, bool fJustCheck, bool fBLSChecks)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -234,31 +234,31 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
if (quorumHash.IsNull()) { if (quorumHash.IsNull()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-block");
} }
if (quorumHash != qc.quorumHash) { if (quorumHash != qc.quorumHash) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-block");
} }
if (qc.IsNull()) { if (qc.IsNull()) {
if (!qc.VerifyNull()) { if (!qc.VerifyNull()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers()); nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid-null");
} }
return true; return true;
} }
if (HasMinedCommitment(llmq_params.type, quorumHash)) { if (HasMinedCommitment(llmq_params.type, quorumHash)) {
// should not happen as it's already handled in ProcessBlock // should not happen as it's already handled in ProcessBlock
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup");
} }
if (!IsMiningPhase(llmq_params, nHeight)) { if (!IsMiningPhase(llmq_params, nHeight)) {
// should not happen as it's already handled in ProcessBlock // should not happen as it's already handled in ProcessBlock
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-height");
} }
const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash); const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash);
@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) { if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid");
} }
if (fJustCheck) { if (fJustCheck) {
@ -313,7 +313,7 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
llmq::utils::PreComputeQuorumMembers(pindex, true); llmq::utils::PreComputeQuorumMembers(pindex, true);
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs; std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
CValidationState dummy; BlockValidationState dummy;
if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) { if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) {
return false; return false;
} }
@ -378,7 +378,7 @@ bool CQuorumBlockProcessor::UpgradeDB()
assert(r); assert(r);
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs; std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
CValidationState dummyState; BlockValidationState dummyState;
GetCommitmentsFromBlock(block, pindex, qcs, dummyState); GetCommitmentsFromBlock(block, pindex, qcs, dummyState);
for (const auto& p : qcs) { for (const auto& p : qcs) {
@ -407,7 +407,7 @@ bool CQuorumBlockProcessor::UpgradeDB()
return true; return true;
} }
bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& state) bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, BlockValidationState& state)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
if (!GetTxPayload(*tx, qc)) { if (!GetTxPayload(*tx, qc)) {
// should not happen as it was verified before processing the block // should not happen as it was verified before processing the block
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight); LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload");
} }
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType); const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) { if (!llmq_params_opt.has_value()) {
// should not happen as it was verified before processing the block // should not happen as it was verified before processing the block
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type");
} }
// only allow one commitment per type and per block (This was changed with rotation) // only allow one commitment per type and per block (This was changed with rotation)
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) { if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
if (ret.count(qc.commitment.llmqType) != 0) { if (ret.count(qc.commitment.llmqType) != 0) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup");
} }
} }
@ -442,7 +442,7 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
} }
if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) { if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-premature"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-premature");
} }
return true; return true;

View File

@ -16,9 +16,9 @@
#include <optional> #include <optional>
class BlockValidationState;
class CNode; class CNode;
class CConnman; class CConnman;
class CValidationState;
class CEvoDB; class CEvoDB;
extern CCriticalSection cs_main; extern CCriticalSection cs_main;
@ -49,7 +49,7 @@ public:
void ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv); void ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv);
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void AddMineableCommitment(const CFinalCommitment& fqc); void AddMineableCommitment(const CFinalCommitment& fqc);
@ -67,8 +67,8 @@ public:
std::vector<std::pair<int, const CBlockIndex*>> GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const; std::vector<std::pair<int, const CBlockIndex*>> GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const;
std::optional<const CBlockIndex*> GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const; std::optional<const CBlockIndex*> GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const;
private: private:
static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
static bool IsMiningPhase(const Consensus::LLMQParams& llmqParams, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main); static bool IsMiningPhase(const Consensus::LLMQParams& llmqParams, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
static uint256 GetQuorumBlockHash(const Consensus::LLMQParams& llmqParams, int nHeight, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); static uint256 GetQuorumBlockHash(const Consensus::LLMQParams& llmqParams, int nHeight, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

View File

@ -494,20 +494,20 @@ void CChainLocksHandler::EnforceBestChainLock()
} }
} }
CValidationState state; BlockValidationState dummy_state;
const auto &params = Params(); const auto &params = Params();
// Go backwards through the chain referenced by clsig until we find a block that is part of the main chain. // Go backwards through the chain referenced by clsig until we find a block that is part of the main chain.
// For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig // For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig
// and mark all of them as conflicting. // and mark all of them as conflicting.
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString()); LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString());
::ChainstateActive().EnforceBlock(state, params, pindex); ::ChainstateActive().EnforceBlock(dummy_state, params, pindex);
bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex; bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex;
if (activateNeeded) { if (activateNeeded) {
if (!::ChainstateActive().ActivateBestChain(state, params)) { if (!::ChainstateActive().ActivateBestChain(dummy_state, params)) {
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state)); LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(dummy_state));
return; return;
} }
LOCK(cs_main); LOCK(cs_main);

View File

@ -176,18 +176,18 @@ bool CFinalCommitment::VerifySizes(const Consensus::LLMQParams& params) const
return true; return true;
} }
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state)
{ {
CFinalCommitmentTxPayload qcTx; CFinalCommitmentTxPayload qcTx;
if (!GetTxPayload(tx, qcTx)) { if (!GetTxPayload(tx, qcTx)) {
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight); LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-payload");
} }
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType); const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
if (!llmq_params_opt.has_value()) { if (!llmq_params_opt.has_value()) {
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType)); LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType));
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-commitment-type");
} }
if (LogAcceptCategory(BCLog::LLMQ)) { if (LogAcceptCategory(BCLog::LLMQ)) {
@ -201,36 +201,36 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) { if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion); LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-version"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-version");
} }
if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) { if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) {
LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight); LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-height");
} }
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash));
if (pQuorumBaseBlockIndex == nullptr) { if (pQuorumBaseBlockIndex == nullptr) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash");
} }
if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) { if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) {
// not part of active chain // not part of active chain
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash");
} }
if (qcTx.commitment.IsNull()) { if (qcTx.commitment.IsNull()) {
if (!qcTx.commitment.VerifyNull()) { if (!qcTx.commitment.VerifyNull()) {
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid-null");
} }
return true; return true;
} }
if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) { if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) {
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid");
} }
LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight); LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight);

View File

@ -15,7 +15,7 @@
#include <univalue.h> #include <univalue.h>
class CBlockIndex; class CBlockIndex;
class CValidationState; class TxValidationState;
namespace llmq namespace llmq
{ {
@ -168,7 +168,7 @@ public:
} }
}; };
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state); bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state);
} // namespace llmq } // namespace llmq

View File

@ -1477,7 +1477,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
LogPrintf("CInstantSendManager::%s -- invalidating block %s\n", __func__, pindex->GetBlockHash().ToString()); LogPrintf("CInstantSendManager::%s -- invalidating block %s\n", __func__, pindex->GetBlockHash().ToString());
CValidationState state; BlockValidationState state;
// need non-const pointer // need non-const pointer
auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash())); auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash()));
if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) { if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) {
@ -1495,7 +1495,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
} }
if (activateBestChain) { if (activateBestChain) {
CValidationState state; BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, Params())) { if (!::ChainstateActive().ActivateBestChain(state, Params())) {
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state)); LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state));
// This should not have happened and we are in a state were it's not safe to continue anymore // This should not have happened and we are in a state were it's not safe to continue anymore

View File

@ -205,7 +205,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
cbTx.nHeight = nHeight; cbTx.nHeight = nHeight;
CValidationState state; BlockValidationState state;
if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) { if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootMNList failed: %s", __func__, FormatStateMessage(state))); throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootMNList failed: %s", __func__, FormatStateMessage(state)));
} }
@ -233,8 +233,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
pblocktemplate->nPrevBits = pindexPrev->nBits; pblocktemplate->nPrevBits = pindexPrev->nBits;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]); pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);
CValidationState state;
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
BlockValidationState state;
if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) { if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
} }

View File

@ -173,8 +173,8 @@ namespace {
int nSyncStarted GUARDED_BY(cs_main) = 0; int nSyncStarted GUARDED_BY(cs_main) = 0;
/** /**
* Sources of received blocks, saved to be able to send them reject * Sources of received blocks, saved to be able punish them when processing
* messages or ban them when processing happens afterwards. * happens afterwards.
* Set mapBlockSource[hash].second to false if the node should not be * Set mapBlockSource[hash].second to false if the node should not be
* punished if the block is invalid. * punished if the block is invalid.
*/ */
@ -1222,7 +1222,7 @@ bool IsBanned(NodeId pnode)
} }
/** /**
* Potentially mark a node discouraged based on the contents of a CValidationState object * Potentially mark a node discouraged based on the contents of a BlockValidationState object
* *
* @param[in] via_compact_block this bool is passed in because net_processing should * @param[in] via_compact_block this bool is passed in because net_processing should
* punish peers differently depending on whether the data was provided in a compact * punish peers differently depending on whether the data was provided in a compact
@ -1231,20 +1231,20 @@ bool IsBanned(NodeId pnode)
* *
* @return Returns true if the peer was punished (probably disconnected) * @return Returns true if the peer was punished (probably disconnected)
*/ */
static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "")
{ {
switch (state.GetReason()) { switch (state.GetResult()) {
case ValidationInvalidReason::NONE: case BlockValidationResult::BLOCK_RESULT_UNSET:
break; break;
// The node is providing invalid data: // The node is providing invalid data:
case ValidationInvalidReason::CONSENSUS: case BlockValidationResult::BLOCK_CONSENSUS:
case ValidationInvalidReason::BLOCK_MUTATED: case BlockValidationResult::BLOCK_MUTATED:
if (!via_compact_block) { if (!via_compact_block) {
Misbehaving(nodeid, 100, message); Misbehaving(nodeid, 100, message);
return true; return true;
} }
break; break;
case ValidationInvalidReason::CACHED_INVALID: case BlockValidationResult::BLOCK_CACHED_INVALID:
{ {
LOCK(cs_main); LOCK(cs_main);
CNodeState *node_state = State(nodeid); CNodeState *node_state = State(nodeid);
@ -1260,25 +1260,18 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
} }
break; break;
} }
case ValidationInvalidReason::BLOCK_INVALID_HEADER: case BlockValidationResult::BLOCK_INVALID_HEADER:
case ValidationInvalidReason::BLOCK_CHECKPOINT: case BlockValidationResult::BLOCK_CHECKPOINT:
case ValidationInvalidReason::BLOCK_INVALID_PREV: case BlockValidationResult::BLOCK_INVALID_PREV:
Misbehaving(nodeid, 100, message); Misbehaving(nodeid, 100, message);
return true; return true;
// Conflicting (but not necessarily invalid) data or different policy: // Conflicting (but not necessarily invalid) data or different policy:
case ValidationInvalidReason::BLOCK_MISSING_PREV: case BlockValidationResult::BLOCK_MISSING_PREV:
case ValidationInvalidReason::BLOCK_CHAINLOCK: case BlockValidationResult::BLOCK_CHAINLOCK:
case ValidationInvalidReason::TX_BAD_SPECIAL:
case ValidationInvalidReason::TX_CONFLICT_LOCK:
Misbehaving(nodeid, 10, message); Misbehaving(nodeid, 10, message);
return true; return true;
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE: case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
case ValidationInvalidReason::BLOCK_TIME_FUTURE: case BlockValidationResult::BLOCK_TIME_FUTURE:
case ValidationInvalidReason::TX_NOT_STANDARD:
case ValidationInvalidReason::TX_MISSING_INPUTS:
case ValidationInvalidReason::TX_PREMATURE_SPEND:
case ValidationInvalidReason::TX_CONFLICT:
case ValidationInvalidReason::TX_MEMPOOL_POLICY:
break; break;
} }
if (message != "") { if (message != "") {
@ -1287,6 +1280,41 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
return false; return false;
} }
/**
* Potentially ban a node based on the contents of a TxValidationState object
*
* @return Returns true if the peer was punished (probably disconnected)
*
* Changes here may need to be reflected in TxRelayMayResultInDisconnect().
*/
static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") {
switch (state.GetResult()) {
case TxValidationResult::TX_RESULT_UNSET:
break;
// The node is providing invalid data:
case TxValidationResult::TX_CONSENSUS:
{
LOCK(cs_main);
Misbehaving(nodeid, 100, message);
return true;
}
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
case TxValidationResult::TX_NOT_STANDARD:
case TxValidationResult::TX_MISSING_INPUTS:
case TxValidationResult::TX_PREMATURE_SPEND:
case TxValidationResult::TX_CONFLICT:
case TxValidationResult::TX_MEMPOOL_POLICY:
// moved from BLOCK
case TxValidationResult::TX_BAD_SPECIAL:
case TxValidationResult::TX_CONFLICT_LOCK:
break;
}
if (message != "") {
LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
}
return false;
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -1507,17 +1535,18 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
* Handle invalid block rejection and consequent peer discouragement, maintain which * Handle invalid block rejection and consequent peer discouragement, maintain which
* peers announce compact blocks. * peers announce compact blocks.
*/ */
void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) { void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidationState& state) {
LOCK(cs_main); LOCK(cs_main);
const uint256 hash(block.GetHash()); const uint256 hash(block.GetHash());
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash); std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
if (state.IsInvalid()) { // If the block failed validation, we know where it came from and we're still connected
// Don't send reject message with code 0 or an internal reject code. // to that peer, maybe punish.
if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) { if (state.IsInvalid() &&
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second); it != mapBlockSource.end() &&
} State(it->second.first)) {
MaybePunishNodeForBlock(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
} }
// Check that: // Check that:
// 1. The block is valid // 1. The block is valid
@ -1710,7 +1739,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
} }
} // release cs_main before calling ActivateBestChain } // release cs_main before calling ActivateBestChain
if (need_activate_chain) { if (need_activate_chain) {
CValidationState state; BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) { if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state)); LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
} }
@ -2126,11 +2155,10 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
} }
} }
CValidationState state; BlockValidationState state;
CBlockHeader first_invalid_header; if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
MaybePunishNode(pfrom.GetId(), state, via_compact_block, "invalid header received"); MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
return; return;
} }
} }
@ -2265,14 +2293,13 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
const CTransactionRef porphanTx = orphan_it->second.tx; const CTransactionRef porphanTx = orphan_it->second.tx;
const CTransaction& orphanTx = *porphanTx; const CTransaction& orphanTx = *porphanTx;
NodeId fromPeer = orphan_it->second.fromPeer; NodeId fromPeer = orphan_it->second.fromPeer;
bool fMissingInputs2 = false; // Use a new TxValidationState because orphans come from different peers (and we call
// Use a new CValidationState because orphans come from different peers (and we call // MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer
// MaybePunishNode based on the source peer from the orphan map, not based on the peer
// that relayed the previous transaction). // that relayed the previous transaction).
CValidationState orphan_state; TxValidationState orphan_state;
if (setMisbehaving.count(fromPeer)) continue; if (setMisbehaving.count(fromPeer)) continue;
if (AcceptToMemoryPool(::ChainstateActive(), mempool, orphan_state, porphanTx, &fMissingInputs2 /* pfMissingInputs */, if (AcceptToMemoryPool(::ChainstateActive(), mempool, orphan_state, porphanTx,
false /* bypass_limits */, 0 /* nAbsurdFee */)) { false /* bypass_limits */, 0 /* nAbsurdFee */)) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString()); LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx.GetHash(), connman); RelayTransaction(orphanTx.GetHash(), connman);
@ -2286,10 +2313,10 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
} }
EraseOrphanTx(orphanHash); EraseOrphanTx(orphanHash);
done = true; done = true;
} else if (!fMissingInputs2) { } else if (orphan_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
if (orphan_state.IsInvalid()) { if (orphan_state.IsInvalid()) {
// Punish peer that gave us an invalid orphan tx // Punish peer that gave us an invalid orphan tx
if (MaybePunishNode(fromPeer, orphan_state, /*via_compact_block*/ false)) { if (MaybePunishNodeForTx(fromPeer, orphan_state)) {
setMisbehaving.insert(fromPeer); setMisbehaving.insert(fromPeer);
} }
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString()); LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
@ -2297,7 +2324,6 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
// Has inputs but not accepted to mempool // Has inputs but not accepted to mempool
// Probably non-standard or insufficient fee // Probably non-standard or insufficient fee
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString()); LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
assert(IsTransactionReason(orphan_state.GetReason()));
assert(recentRejects); assert(recentRejects);
recentRejects->insert(orphanHash); recentRejects->insert(orphanHash);
EraseOrphanTx(orphanHash); EraseOrphanTx(orphanHash);
@ -2523,25 +2549,6 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
connman.PushMessage(&peer, std::move(msg)); connman.PushMessage(&peer, std::move(msg));
} }
std::string RejectCodeToString(const unsigned char code)
{
if (code == REJECT_MALFORMED)
return "malformed";
if (code == REJECT_INVALID)
return "invalid";
if (code == REJECT_OBSOLETE)
return "obsolete";
if (code == REJECT_DUPLICATE)
return "duplicate";
if (code == REJECT_NONSTANDARD)
return "nonstandard";
if (code == REJECT_INSUFFICIENTFEE)
return "insufficientfee";
if (code == REJECT_CHECKPOINT)
return "checkpoint";
return "";
}
std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx) std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx)
{ {
if (!dstx.IsValidStructure()) { if (!dstx.IsValidStructure()) {
@ -3148,7 +3155,7 @@ void PeerLogicValidation::ProcessMessage(
LOCK(cs_most_recent_block); LOCK(cs_most_recent_block);
a_recent_block = most_recent_block; a_recent_block = most_recent_block;
} }
CValidationState state; BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) { if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state)); LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
} }
@ -3364,10 +3371,9 @@ void PeerLogicValidation::ProcessMessage(
LOCK2(cs_main, g_cs_orphans); LOCK2(cs_main, g_cs_orphans);
bool fMissingInputs = false; TxValidationState state;
CValidationState state;
if (!AlreadyHave(inv, m_mempool, *m_llmq_ctx) && AcceptToMemoryPool(::ChainstateActive(), m_mempool, state, ptx, &fMissingInputs /* pfMissingInputs */, if (!AlreadyHave(inv, m_mempool, *m_llmq_ctx) && AcceptToMemoryPool(::ChainstateActive(), m_mempool, state, ptx,
false /* bypass_limits */, 0 /* nAbsurdFee */)) { false /* bypass_limits */, 0 /* nAbsurdFee */)) {
// Process custom txes, this changes AlreadyHave to "true" // Process custom txes, this changes AlreadyHave to "true"
if (nInvType == MSG_DSTX) { if (nInvType == MSG_DSTX) {
@ -3398,7 +3404,7 @@ void PeerLogicValidation::ProcessMessage(
// Recursively process any orphan transactions that depended on this one // Recursively process any orphan transactions that depended on this one
ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set); ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set);
} }
else if (fMissingInputs) else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
{ {
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
for (const CTxIn& txin : tx.vin) { for (const CTxIn& txin : tx.vin) {
@ -3435,7 +3441,6 @@ void PeerLogicValidation::ProcessMessage(
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx); m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
} }
} else { } else {
assert(IsTransactionReason(state.GetReason()));
assert(recentRejects); assert(recentRejects);
recentRejects->insert(tx.GetHash()); recentRejects->insert(tx.GetHash());
if (RecursiveDynamicUsage(*ptx) < 100000) { if (RecursiveDynamicUsage(*ptx) < 100000) {
@ -3478,7 +3483,7 @@ void PeerLogicValidation::ProcessMessage(
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
pfrom.GetId(), pfrom.GetId(),
FormatStateMessage(state)); FormatStateMessage(state));
MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ false); MaybePunishNodeForTx(pfrom.GetId(), state);
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx); m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
} }
return; return;
@ -3513,10 +3518,10 @@ void PeerLogicValidation::ProcessMessage(
} }
const CBlockIndex *pindex = nullptr; const CBlockIndex *pindex = nullptr;
CValidationState state; BlockValidationState state;
if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) { if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock"); MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
return; return;
} }
} }
@ -3750,11 +3755,12 @@ void PeerLogicValidation::ProcessMessage(
// been run). This is handled below, so just treat this as // been run). This is handled below, so just treat this as
// though the block was successfully read, and rely on the // though the block was successfully read, and rely on the
// handling in ProcessNewBlock to ensure the block index is // handling in ProcessNewBlock to ensure the block index is
// updated, reject messages go out, etc. // updated, etc.
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
fBlockRead = true; fBlockRead = true;
// mapBlockSource is only used for sending reject messages and DoS scores, // mapBlockSource is used for potentially punishing peers and
// so the race between here and cs_main in ProcessNewBlock is fine. // updating which peers send us compact blocks, so the race
// between here and cs_main in ProcessNewBlock is fine.
// BIP 152 permits peers to relay compact blocks after validating // BIP 152 permits peers to relay compact blocks after validating
// the header only; we should not punish peers if the block turns // the header only; we should not punish peers if the block turns
// out to be invalid. // out to be invalid.
@ -3835,8 +3841,9 @@ void PeerLogicValidation::ProcessMessage(
// Also always process if we requested the block explicitly, as we may // Also always process if we requested the block explicitly, as we may
// need it even though it is not a candidate for a new best tip. // need it even though it is not a candidate for a new best tip.
forceProcessing |= MarkBlockAsReceived(hash); forceProcessing |= MarkBlockAsReceived(hash);
// mapBlockSource is only used for sending reject messages and DoS scores, // mapBlockSource is only used for punishing peers and setting
// so the race between here and cs_main in ProcessNewBlock is fine. // which peers send us compact blocks, so the race between here and
// cs_main in ProcessNewBlock is fine.
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true)); mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
} }
bool fNewBlock = false; bool fNewBlock = false;

View File

@ -52,7 +52,7 @@ public:
/** /**
* Overridden from CValidationInterface. * Overridden from CValidationInterface.
*/ */
void BlockChecked(const CBlock& block, const CValidationState& state) override; void BlockChecked(const CBlock& block, const BlockValidationState& state) override;
/** /**
* Overridden from CValidationInterface. * Overridden from CValidationInterface.
*/ */

View File

@ -39,18 +39,16 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
} }
if (!node.mempool->exists(hashTx)) { if (!node.mempool->exists(hashTx)) {
// Transaction is not already in the mempool. Submit it. // Transaction is not already in the mempool. Submit it.
CValidationState state; TxValidationState state;
bool fMissingInputs; if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx),
if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx), &fMissingInputs,
bypass_limits, max_tx_fee)) { bypass_limits, max_tx_fee)) {
err_string = FormatStateMessage(state);
if (state.IsInvalid()) { if (state.IsInvalid()) {
err_string = FormatStateMessage(state); if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
return TransactionError::MEMPOOL_REJECTED;
} else {
if (fMissingInputs) {
return TransactionError::MISSING_INPUTS; return TransactionError::MISSING_INPUTS;
} }
err_string = FormatStateMessage(state); return TransactionError::MEMPOOL_REJECTED;
} else {
return TransactionError::MEMPOOL_ERROR; return TransactionError::MEMPOOL_ERROR;
} }
} }

View File

@ -25,7 +25,7 @@ public:
/** Fee rate of 0 satoshis per kB */ /** Fee rate of 0 satoshis per kB */
CFeeRate() : nSatoshisPerK(0) { } CFeeRate() : nSatoshisPerK(0) { }
template<typename I> template<typename I>
CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { explicit CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
// We've previously had bugs creep in from silent double->int conversion... // We've previously had bugs creep in from silent double->int conversion...
static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats"); static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
} }

View File

@ -130,6 +130,7 @@ public:
currentUnit = unit; currentUnit = unit;
amountValidator->updateUnit(unit); amountValidator->updateUnit(unit);
setPlaceholderText(BitcoinUnits::format(currentUnit, m_min_amount, false, BitcoinUnits::separatorAlways));
if(valid) if(valid)
setValue(val); setValue(val);
else else

View File

@ -1811,7 +1811,7 @@ static UniValue preciousblock(const JSONRPCRequest& request)
} }
} }
CValidationState state; BlockValidationState state;
::ChainstateActive().PreciousBlock(state, Params(), pblockindex); ::ChainstateActive().PreciousBlock(state, Params(), pblockindex);
if (!state.IsValid()) { if (!state.IsValid()) {
@ -1836,7 +1836,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
}.Check(request); }.Check(request);
uint256 hash(ParseHashV(request.params[0], "blockhash")); uint256 hash(ParseHashV(request.params[0], "blockhash"));
CValidationState state; BlockValidationState state;
CBlockIndex* pblockindex; CBlockIndex* pblockindex;
{ {
@ -1886,7 +1886,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
::ChainstateActive().ResetBlockFailureFlags(pblockindex); ::ChainstateActive().ResetBlockFailureFlags(pblockindex);
} }
CValidationState state; BlockValidationState state;
::ChainstateActive().ActivateBestChain(state, Params()); ::ChainstateActive().ActivateBestChain(state, Params());
if (!state.IsValid()) { if (!state.IsValid()) {

View File

@ -326,7 +326,7 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const CMu
{ {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; TxValidationState state;
if (!CheckSpecialTx(CTransaction(tx), ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) { if (!CheckSpecialTx(CTransaction(tx), ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) {
throw std::runtime_error(FormatStateMessage(state)); throw std::runtime_error(FormatStateMessage(state));
} }

View File

@ -380,7 +380,7 @@ static UniValue generateblock(const JSONRPCRequest& request)
{ {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; BlockValidationState state;
if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) { if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.GetRejectReason())); throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.GetRejectReason()));
} }
@ -483,7 +483,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
static UniValue BIP22ValidationResult(const CValidationState& state) static UniValue BIP22ValidationResult(const BlockValidationState& state)
{ {
if (state.IsValid()) if (state.IsValid())
return NullUniValue; return NullUniValue;
@ -670,7 +670,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
// TestBlockValidity only supports blocks built on the current Tip // TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash()) if (block.hashPrevBlock != pindexPrev->GetBlockHash())
return "inconclusive-not-best-prevblk"; return "inconclusive-not-best-prevblk";
CValidationState state; BlockValidationState state;
TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true); TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true);
return BIP22ValidationResult(state); return BIP22ValidationResult(state);
} }
@ -951,12 +951,12 @@ class submitblock_StateCatcher : public CValidationInterface
public: public:
uint256 hash; uint256 hash;
bool found; bool found;
CValidationState state; BlockValidationState state;
explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {} explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
protected: protected:
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override { void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override {
if (block.GetHash() != hash) if (block.GetHash() != hash)
return; return;
found = true; found = true;
@ -1046,8 +1046,8 @@ static UniValue submitheader(const JSONRPCRequest& request)
} }
} }
CValidationState state; BlockValidationState state;
EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params(), /* ppindex */ nullptr, /* first_invalid */ nullptr); EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params());
if (state.IsValid()) return NullUniValue; if (state.IsValid()) return NullUniValue;
if (state.IsError()) { if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state)); throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state));

View File

@ -918,20 +918,21 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
UniValue result_0(UniValue::VOBJ); UniValue result_0(UniValue::VOBJ);
result_0.pushKV("txid", tx_hash.GetHex()); result_0.pushKV("txid", tx_hash.GetHex());
CValidationState state; TxValidationState state;
bool missing_inputs;
bool test_accept_res; bool test_accept_res;
{ {
LOCK(cs_main); LOCK(cs_main);
test_accept_res = AcceptToMemoryPool(::ChainstateActive(), mempool, state, std::move(tx), &missing_inputs, test_accept_res = AcceptToMemoryPool(::ChainstateActive(), mempool, state, std::move(tx),
false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true); false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true);
} }
result_0.pushKV("allowed", test_accept_res); result_0.pushKV("allowed", test_accept_res);
if (!test_accept_res) { if (!test_accept_res) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
} else if (missing_inputs) { result_0.pushKV("reject-reason", "missing-inputs");
result_0.pushKV("reject-reason", "missing-inputs"); } else {
result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
}
} else { } else {
result_0.pushKV("reject-reason", state.GetRejectReason()); result_0.pushKV("reject-reason", state.GetRejectReason());
} }

View File

@ -14,6 +14,7 @@
#include <util/spanparsing.h> #include <util/spanparsing.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <util/system.h> #include <util/system.h>
#include <util/vector.h>
#include <memory> #include <memory>
#include <optional> #include <optional>
@ -549,22 +550,13 @@ public:
} }
}; };
/** Construct a vector with one element, which is moved into it. */
template<typename T>
std::vector<T> Singleton(T elem)
{
std::vector<T> ret;
ret.emplace_back(std::move(elem));
return ret;
}
/** A parsed addr(A) descriptor. */ /** A parsed addr(A) descriptor. */
class AddressDescriptor final : public DescriptorImpl class AddressDescriptor final : public DescriptorImpl
{ {
const CTxDestination m_destination; const CTxDestination m_destination;
protected: protected:
std::string ToStringExtra() const override { return EncodeDestination(m_destination); } std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(m_destination)); } std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
public: public:
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {} AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
bool IsSolvable() const final { return false; } bool IsSolvable() const final { return false; }
@ -576,7 +568,7 @@ class RawDescriptor final : public DescriptorImpl
const CScript m_script; const CScript m_script;
protected: protected:
std::string ToStringExtra() const override { return HexStr(m_script); } std::string ToStringExtra() const override { return HexStr(m_script); }
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(m_script); } std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
public: public:
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {} RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
bool IsSolvable() const final { return false; } bool IsSolvable() const final { return false; }
@ -586,9 +578,9 @@ public:
class PKDescriptor final : public DescriptorImpl class PKDescriptor final : public DescriptorImpl
{ {
protected: protected:
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForRawPubKey(keys[0])); } std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
public: public:
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pk") {} PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
}; };
/** A parsed pkh(P) descriptor. */ /** A parsed pkh(P) descriptor. */
@ -599,10 +591,10 @@ protected:
{ {
CKeyID id = keys[0].GetID(); CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]); out.pubkeys.emplace(id, keys[0]);
return Singleton(GetScriptForDestination(PKHash(id))); return Vector(GetScriptForDestination(PKHash(id)));
} }
public: public:
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
}; };
/** A parsed multi(...) or sortedmulti(...) descriptor */ /** A parsed multi(...) or sortedmulti(...) descriptor */
@ -616,9 +608,9 @@ protected:
if (m_sorted) { if (m_sorted) {
std::vector<CPubKey> sorted_keys(keys); std::vector<CPubKey> sorted_keys(keys);
std::sort(sorted_keys.begin(), sorted_keys.end()); std::sort(sorted_keys.begin(), sorted_keys.end());
return Singleton(GetScriptForMultisig(m_threshold, sorted_keys)); return Vector(GetScriptForMultisig(m_threshold, sorted_keys));
} }
return Singleton(GetScriptForMultisig(m_threshold, keys)); return Vector(GetScriptForMultisig(m_threshold, keys));
} }
public: public:
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {} MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
@ -628,7 +620,7 @@ public:
class SHDescriptor final : public DescriptorImpl class SHDescriptor final : public DescriptorImpl
{ {
protected: protected:
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); } std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
public: public:
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {} SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
}; };
@ -653,7 +645,7 @@ protected:
} }
public: public:
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "combo") {} ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
}; };
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////

View File

@ -118,22 +118,6 @@ static void RunTest(const TestVector &test) {
} }
key = keyNew; key = keyNew;
pubkey = pubkeyNew; pubkey = pubkeyNew;
CDataStream ssPub(SER_DISK, CLIENT_VERSION);
ssPub << pubkeyNew;
BOOST_CHECK(ssPub.size() == 75);
CDataStream ssPriv(SER_DISK, CLIENT_VERSION);
ssPriv << keyNew;
BOOST_CHECK(ssPriv.size() == 75);
CExtPubKey pubCheck;
CExtKey privCheck;
ssPub >> pubCheck;
ssPriv >> privCheck;
BOOST_CHECK(pubCheck == pubkeyNew);
BOOST_CHECK(privCheck == keyNew);
} }
} }

View File

@ -100,8 +100,8 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key)); block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
CBlockHeader header = block->GetBlockHeader(); CBlockHeader header = block->GetBlockHeader();
CValidationState state; BlockValidationState state;
if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) { if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex)) {
return false; return false;
} }
} }

View File

@ -294,12 +294,12 @@ void FuncDIP3Protx(TestChainSetup& setup)
// payload itself. This means, we need to rely on script verification, which takes the hash of the extra payload // payload itself. This means, we need to rely on script verification, which takes the hash of the extra payload
// into account // into account
auto tx2 = MalleateProTxPayout<CProRegTx>(tx); auto tx2 = MalleateProTxPayout<CProRegTx>(tx);
CValidationState dummyState; TxValidationState dummy_state;
// Technically, the payload is still valid... // Technically, the payload is still valid...
{ {
LOCK(cs_main); LOCK(cs_main);
BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
} }
// But the signature should not verify anymore // But the signature should not verify anymore
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx)); BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
@ -401,11 +401,11 @@ void FuncDIP3Protx(TestChainSetup& setup)
tx = CreateProUpRegTx(*(setup.m_node.mempool), utxos, dmnHashes[0], ownerKeys[dmnHashes[0]], newOperatorKey.GetPublicKey(), ownerKeys[dmnHashes[0]].GetPubKey().GetID(), dmn->pdmnState->scriptPayout, setup.coinbaseKey); tx = CreateProUpRegTx(*(setup.m_node.mempool), utxos, dmnHashes[0], ownerKeys[dmnHashes[0]], newOperatorKey.GetPublicKey(), ownerKeys[dmnHashes[0]].GetPubKey().GetID(), dmn->pdmnState->scriptPayout, setup.coinbaseKey);
// check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx // check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx
auto tx2 = MalleateProTxPayout<CProUpRegTx>(tx); auto tx2 = MalleateProTxPayout<CProUpRegTx>(tx);
CValidationState dummyState; TxValidationState dummy_state;
{ {
LOCK(cs_main); LOCK(cs_main);
BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
} }
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx)); BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
BOOST_ASSERT(!CheckTransactionSignature(*(setup.m_node.mempool), tx2)); BOOST_ASSERT(!CheckTransactionSignature(*(setup.m_node.mempool), tx2));

View File

@ -36,17 +36,17 @@ FUZZ_TARGET_INIT(block, initialize_block)
return; return;
} }
const Consensus::Params& consensus_params = Params().GetConsensus(); const Consensus::Params& consensus_params = Params().GetConsensus();
CValidationState validation_state_pow_and_merkle; BlockValidationState validation_state_pow_and_merkle;
const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true); const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true);
assert(validation_state_pow_and_merkle.IsValid() || validation_state_pow_and_merkle.IsInvalid() || validation_state_pow_and_merkle.IsError()); assert(validation_state_pow_and_merkle.IsValid() || validation_state_pow_and_merkle.IsInvalid() || validation_state_pow_and_merkle.IsError());
(void)validation_state_pow_and_merkle.Error(""); (void)validation_state_pow_and_merkle.Error("");
CValidationState validation_state_pow; BlockValidationState validation_state_pow;
const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false); const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false);
assert(validation_state_pow.IsValid() || validation_state_pow.IsInvalid() || validation_state_pow.IsError()); assert(validation_state_pow.IsValid() || validation_state_pow.IsInvalid() || validation_state_pow.IsError());
CValidationState validation_state_merkle; BlockValidationState validation_state_merkle;
const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true); const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true);
assert(validation_state_merkle.IsValid() || validation_state_merkle.IsInvalid() || validation_state_merkle.IsError()); assert(validation_state_merkle.IsValid() || validation_state_merkle.IsInvalid() || validation_state_merkle.IsError());
CValidationState validation_state_none; BlockValidationState validation_state_none;
const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false); const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false);
assert(validation_state_none.IsValid() || validation_state_none.IsInvalid() || validation_state_none.IsError()); assert(validation_state_none.IsValid() || validation_state_none.IsInvalid() || validation_state_none.IsError());
if (valid_incl_pow_and_merkle) { if (valid_incl_pow_and_merkle) {

View File

@ -223,12 +223,12 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache); (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
}, },
[&] { [&] {
CValidationState state; TxValidationState state;
CAmount tx_fee_out; CAmount tx_fee_out;
const CTransaction transaction{random_mutable_transaction}; const CTransaction transaction{random_mutable_transaction};
if (ContainsSpentInput(transaction, coins_view_cache)) { if (ContainsSpentInput(transaction, coins_view_cache)) {
// Avoid: // Avoid:
// consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, CValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState&, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
return; return;
} }
try { try {

View File

@ -60,7 +60,7 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
return; return;
} }
CValidationState state_with_dupe_check; TxValidationState state_with_dupe_check;
(void)CheckTransaction(tx, state_with_dupe_check); (void)CheckTransaction(tx, state_with_dupe_check);
std::string reason; std::string reason;

View File

@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(findCommonAncestor)
const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CChain& active = Assert(m_node.chainman)->ActiveChain();
auto* orig_tip = active.Tip(); auto* orig_tip = active.Tip();
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
CValidationState state; BlockValidationState state;
ChainstateActive().InvalidateBlock(state, Params(), active.Tip()); ChainstateActive().InvalidateBlock(state, Params(), active.Tip());
} }
BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10); BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10);

View File

@ -536,7 +536,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
} // unlock cs_main while calling InvalidateBlock } // unlock cs_main while calling InvalidateBlock
CValidationState state; BlockValidationState state;
::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip())); ::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip()));
SetMockTime(0); SetMockTime(0);

View File

@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
stream >> tx; stream >> tx;
CValidationState state; TxValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest); BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
BOOST_CHECK(state.IsValid()); BOOST_CHECK(state.IsValid());

View File

@ -18,15 +18,15 @@
#include <vector> #include <vector>
bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state) bool VerifyMNHFTx(const CTransaction& tx, TxValidationState& state)
{ {
MNHFTxPayload mnhfTx; MNHFTxPayload mnhfTx;
if (!GetTxPayload(tx, mnhfTx)) { if (!GetTxPayload(tx, mnhfTx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload");
} }
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) { if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version");
} }
return true; return true;
@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests)
BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash)); BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash));
const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver); const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver);
CValidationState state; TxValidationState state;
BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state)); BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state));
} }

View File

@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx(deserialize, stream); CTransaction tx(deserialize, stream);
CValidationState state; TxValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid()); BOOST_CHECK(state.IsValid());
@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx(deserialize, stream); CTransaction tx(deserialize, stream);
CValidationState state; TxValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid(); fValid = CheckTransaction(tx, state) && state.IsValid();
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
CMutableTransaction tx; CMutableTransaction tx;
stream >> tx; stream >> tx;
CValidationState state; TxValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid."); BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");
// Check that duplicate txins fail // Check that duplicate txins fail

View File

@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase()); BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
CValidationState state; TxValidationState state;
LOCK(cs_main); LOCK(cs_main);
@ -39,7 +39,6 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
BOOST_CHECK_EQUAL( BOOST_CHECK_EQUAL(
false, false,
AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx), AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx),
nullptr /* pfMissingInputs */,
true /* bypass_limits */, true /* bypass_limits */,
0 /* nAbsurdFee */)); 0 /* nAbsurdFee */));
@ -49,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
// Check that the validation state reflects the unsuccessful attempt. // Check that the validation state reflects the unsuccessful attempt.
BOOST_CHECK(state.IsInvalid()); BOOST_CHECK(state.IsInvalid());
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase"); BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
BOOST_CHECK(state.GetReason() == ValidationInvalidReason::CONSENSUS); BOOST_CHECK(state.GetResult() == TxValidationResult::TX_CONSENSUS);
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

View File

@ -12,7 +12,7 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks); bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) BOOST_AUTO_TEST_SUITE(txvalidationcache_tests)
@ -27,8 +27,8 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
const auto ToMemPool = [this](const CMutableTransaction& tx) { const auto ToMemPool = [this](const CMutableTransaction& tx) {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; TxValidationState validationState;
return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */, return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, validationState, MakeTransactionRef(tx),
true /* bypass_limits */, 0 /* nAbsurdFee */); true /* bypass_limits */, 0 /* nAbsurdFee */);
}; };
@ -111,7 +111,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
// If we add many more flags, this loop can get too expensive, but we can // If we add many more flags, this loop can get too expensive, but we can
// rewrite in the future to randomly pick a set of flags to evaluate. // rewrite in the future to randomly pick a set of flags to evaluate.
for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) { for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) {
CValidationState state; TxValidationState state;
// Filter out incompatible flag choices // Filter out incompatible flag choices
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) { if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
// CLEANSTACK requires P2SH, see VerifyScript() in // CLEANSTACK requires P2SH, see VerifyScript() in
@ -193,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
{ {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; TxValidationState state;
PrecomputedTransactionData ptd_spend_tx; PrecomputedTransactionData ptd_spend_tx;
BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
@ -262,7 +262,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// Make it valid, and check again // Make it valid, and check again
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state; TxValidationState state;
PrecomputedTransactionData txdata; PrecomputedTransactionData txdata;
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
} }
@ -290,7 +290,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// Make it valid, and check again // Make it valid, and check again
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state; TxValidationState state;
PrecomputedTransactionData txdata; PrecomputedTransactionData txdata;
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
} }

View File

@ -253,7 +253,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
m_node.connman->Init(options); m_node.connman->Init(options);
} }
CValidationState state; BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, chainparams)) { if (!::ChainstateActive().ActivateBestChain(state, chainparams)) {
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state))); throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
} }
@ -338,7 +338,7 @@ CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns,
if (!GetTxPayload(*block.vtx[0], cbTx)) { if (!GetTxPayload(*block.vtx[0], cbTx)) {
BOOST_ASSERT(false); BOOST_ASSERT(false);
} }
CValidationState state; BlockValidationState state;
if (!CalcCbTxMerkleRootMNList(block, ::ChainActive().Tip(), cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) { if (!CalcCbTxMerkleRootMNList(block, ::ChainActive().Tip(), cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
BOOST_ASSERT(false); BOOST_ASSERT(false);
} }

View File

@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
} }
bool ignored; bool ignored;
CValidationState state; BlockValidationState state;
std::vector<CBlockHeader> headers; std::vector<CBlockHeader> headers;
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); }); std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
@ -296,14 +296,13 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
// Add the txs to the tx pool // Add the txs to the tx pool
{ {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; TxValidationState state;
for (const auto& tx : txs) { for (const auto& tx : txs) {
BOOST_REQUIRE(AcceptToMemoryPool( BOOST_REQUIRE(AcceptToMemoryPool(
::ChainstateActive(), ::ChainstateActive(),
*m_node.mempool, *m_node.mempool,
state, state,
tx, tx,
/* pfMissingInputs */ &ignored,
/* bypass_limits */ false, /* bypass_limits */ false,
/* nAbsurdFee */ 0)); /* nAbsurdFee */ 0));
} }

View File

@ -67,8 +67,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23)); WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23));
// Unlike c1, which doesn't have any blocks. Gets us different tip, height. // Unlike c1, which doesn't have any blocks. Gets us different tip, height.
c2.LoadGenesisBlock(chainparams); c2.LoadGenesisBlock(chainparams);
CValidationState _; BlockValidationState dummy_state;
BOOST_CHECK(c2.ActivateBestChain(_, chainparams, nullptr)); BOOST_CHECK(c2.ActivateBestChain(dummy_state, chainparams, nullptr));
BOOST_CHECK(manager.IsSnapshotActive()); BOOST_CHECK(manager.IsSnapshotActive());
BOOST_CHECK(!manager.IsSnapshotValidated()); BOOST_CHECK(!manager.IsSnapshotValidated());

View File

@ -1023,9 +1023,9 @@ void CTxMemPool::clear()
static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight) static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight)
{ {
CValidationState state; TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass
CAmount txfee = 0; CAmount txfee = 0;
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee); bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee);
assert(fCheckResult); assert(fCheckResult);
UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max()); UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max());
} }
@ -1207,7 +1207,7 @@ void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
} }
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()}; return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()};
} }
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const std::vector<TxMempoolInfo> CTxMemPool::infoAll() const

View File

@ -343,8 +343,11 @@ struct TxMempoolInfo
/** Time the transaction entered the mempool. */ /** Time the transaction entered the mempool. */
std::chrono::seconds m_time; std::chrono::seconds m_time;
/** Feerate of the transaction. */ /** Fee of the transaction. */
CFeeRate feeRate; CAmount fee;
/** Virtual size of the transaction. */
size_t vsize;
/** The fee delta. */ /** The fee delta. */
int64_t nFeeDelta; int64_t nFeeDelta;

View File

@ -8,11 +8,10 @@
#include <consensus/validation.h> #include <consensus/validation.h>
#include <tinyformat.h> #include <tinyformat.h>
/** Convert CValidationState to a human-readable message for logging */ /** Convert ValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state) std::string FormatStateMessage(const ValidationState &state)
{ {
return strprintf("%s%s (code %i)", return strprintf("%s%s",
state.GetRejectReason(), state.GetRejectReason(),
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(), state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage());
state.GetRejectCode());
} }

View File

@ -8,9 +8,9 @@
#include <string> #include <string>
class CValidationState; class ValidationState;
/** Convert CValidationState to a human-readable message for logging */ /** Convert ValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state); std::string FormatStateMessage(const ValidationState &state);
#endif // BITCOIN_UTIL_VALIDATION_H #endif // BITCOIN_UTIL_VALIDATION_H

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@ class CQuorumBlockProcessor;
class CEvoDB; class CEvoDB;
class CChainState; class CChainState;
class BlockValidationState;
class CBlockIndex; class CBlockIndex;
class CBlockTreeDB; class CBlockTreeDB;
class CBlockUndo; class CBlockUndo;
@ -52,7 +53,7 @@ class CInv;
class CConnman; class CConnman;
class CScriptCheck; class CScriptCheck;
class CTxMemPool; class CTxMemPool;
class CValidationState; class TxValidationState;
class ChainstateManager; class ChainstateManager;
struct PrecomputedTransactionData; struct PrecomputedTransactionData;
struct ChainTxData; struct ChainTxData;
@ -215,8 +216,8 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight); void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
/** (try to) add transaction to memory pool */ /** (try to) add transaction to memory pool */
bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, bool bypass_limits, bool bypass_limits,
const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin); bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin);
@ -315,10 +316,10 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
/** Functions for validating blocks and updating the block tree */ /** Functions for validating blocks and updating the block tree */
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true); bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
/** Check a block is completely valid from start to finish (only works on top of our current best block) */ /** Check a block is completely valid from start to finish (only works on top of our current best block) */
bool TestBlockValidity(CValidationState& state, bool TestBlockValidity(BlockValidationState& state,
llmq::CChainLocksHandler& clhandler, llmq::CChainLocksHandler& clhandler,
CEvoDB& evoDb, CEvoDB& evoDb,
const CChainParams& chainparams, const CChainParams& chainparams,
@ -454,7 +455,7 @@ public:
*/ */
bool AcceptBlockHeader( bool AcceptBlockHeader(
const CBlockHeader& block, const CBlockHeader& block,
CValidationState& state, BlockValidationState& state,
const CChainParams& chainparams, const CChainParams& chainparams,
CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -681,7 +682,7 @@ public:
*/ */
bool FlushStateToDisk( bool FlushStateToDisk(
const CChainParams& chainparams, const CChainParams& chainparams,
CValidationState &state, BlockValidationState &state,
FlushStateMode mode, FlushStateMode mode,
int nManualPruneHeight = 0); int nManualPruneHeight = 0);
@ -708,29 +709,29 @@ public:
* @returns true unless a system error occurred * @returns true unless a system error occurred
*/ */
bool ActivateBestChain( bool ActivateBestChain(
CValidationState& state, BlockValidationState& state,
const CChainParams& chainparams, const CChainParams& chainparams,
std::shared_ptr<const CBlock> pblock = nullptr) LOCKS_EXCLUDED(cs_main); std::shared_ptr<const CBlock> pblock = nullptr) LOCKS_EXCLUDED(cs_main);
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block (dis)connection on a given view: // Block (dis)connection on a given view:
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main); DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Apply the effects of a block disconnection on the UTXO set. // Apply the effects of a block disconnection on the UTXO set.
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); bool DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
// Manual block validity manipulation: // Manual block validity manipulation:
/** Mark a block as precious and reorganize. /** Mark a block as precious and reorganize.
* *
* May not be called in a validationinterface callback. * May not be called in a validationinterface callback.
*/ */
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); bool PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
/** Mark a block as invalid. */ /** Mark a block as invalid. */
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); bool InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
/** Enforce a block marking all the other chains as conflicting. */ /** Enforce a block marking all the other chains as conflicting. */
void EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); void EnforceBlock(BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
/** Remove invalidity status from a block and its descendants. */ /** Remove invalidity status from a block and its descendants. */
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -738,7 +739,7 @@ public:
bool ReplayBlocks(const CChainParams& params); bool ReplayBlocks(const CChainParams& params);
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */ /** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
bool LoadGenesisBlock(const CChainParams& chainparams); bool LoadGenesisBlock(const CChainParams& chainparams);
bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void PruneBlockIndexCandidates(); void PruneBlockIndexCandidates();
@ -774,10 +775,10 @@ public:
std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
private: private:
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); bool ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); bool ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
void InvalidBlockFound(CBlockIndex* pindex, const CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -785,7 +786,7 @@ private:
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
//! Mark a block as conflicting //! Mark a block as conflicting
bool MarkConflictingBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool MarkConflictingBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
//! Mark a block as not having block data //! Mark a block as not having block data
void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -990,7 +991,7 @@ public:
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
* @param[out] first_invalid First header that fails validation, if one exists * @param[out] first_invalid First header that fails validation, if one exists
*/ */
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main); bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex //! Load the block tree and coins database from disk, initializing state if we're running with -reindex
bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -1031,14 +1032,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
*/ */
bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
/** Reject codes greater or equal to this can be returned by AcceptToMemPool
* for transactions, to signal internal conditions. They cannot and should not
* be sent over the P2P network.
*/
static const unsigned int REJECT_INTERNAL = 0x100;
/** Too high fee. Can not be triggered by P2P transactions */
static const unsigned int REJECT_HIGHFEE = 0x100;
/** Get block file info entry for one block file */ /** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n); CBlockFileInfo* GetBlockFileInfo(size_t n);

View File

@ -44,7 +44,7 @@ struct MainSignalsInstance {
boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected; boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool; boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed; boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock; boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
boost::signals2::signal<void (const CBlockIndex *)>AcceptedBlockHeader; boost::signals2::signal<void (const CBlockIndex *)>AcceptedBlockHeader;
boost::signals2::signal<void (const CBlockIndex *, bool)>NotifyHeaderTip; boost::signals2::signal<void (const CBlockIndex *, bool)>NotifyHeaderTip;
@ -198,7 +198,7 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
}); });
} }
void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) { void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
m_internals->BlockChecked(block, state); m_internals->BlockChecked(block, state);
} }

View File

@ -13,12 +13,12 @@
#include <memory> #include <memory>
extern CCriticalSection cs_main; extern CCriticalSection cs_main;
class BlockValidationState;
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
struct CBlockLocator; struct CBlockLocator;
class CConnman; class CConnman;
class CValidationInterface; class CValidationInterface;
class CValidationState;
class CGovernanceVote; class CGovernanceVote;
class CGovernanceObject; class CGovernanceObject;
class CDeterministicMNList; class CDeterministicMNList;
@ -185,11 +185,11 @@ protected:
virtual void ChainStateFlushed(const CBlockLocator &locator) {} virtual void ChainStateFlushed(const CBlockLocator &locator) {}
/** /**
* Notifies listeners of a block validation result. * Notifies listeners of a block validation result.
* If the provided CValidationState IsValid, the provided block * If the provided BlockValidationState IsValid, the provided block
* is guaranteed to be the current best block at the time the * is guaranteed to be the current best block at the time the
* callback was generated (not necessarily now) * callback was generated (not necessarily now)
*/ */
virtual void BlockChecked(const CBlock&, const CValidationState&) {} virtual void BlockChecked(const CBlock&, const BlockValidationState&) {}
/** /**
* Notifies listeners that a block which builds directly on our current tip * Notifies listeners that a block which builds directly on our current tip
* has been received and connected to the headers tree, though not validated yet */ * has been received and connected to the headers tree, though not validated yet */
@ -236,7 +236,7 @@ public:
void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig); void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig);
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman); void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman);
void ChainStateFlushed(const CBlockLocator &); void ChainStateFlushed(const CBlockLocator &);
void BlockChecked(const CBlock&, const CValidationState&); void BlockChecked(const CBlock&, const BlockValidationState&);
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&); void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
}; };

View File

@ -73,7 +73,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). " argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
"Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target", "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE); CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE);
argsman.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)", argsman.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data. 0 to entirely disable the fallbackfee feature. (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE); CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE);
argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)", argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);

View File

@ -2315,7 +2315,7 @@ static UniValue settxfee(const JSONRPCRequest& request)
CAmount nAmount = AmountFromValue(request.params[0]); CAmount nAmount = AmountFromValue(request.params[0]);
CFeeRate tx_fee_rate(nAmount, 1000); CFeeRate tx_fee_rate(nAmount, 1000);
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000); CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
if (tx_fee_rate == 0) { if (tx_fee_rate == CFeeRate(0)) {
// automatic selection // automatic selection
} else if (tx_fee_rate < pwallet->chain().relayMinFee()) { } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString())); throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));

View File

@ -178,6 +178,7 @@ public:
int nChangePosRet = -1; int nChangePosRet = -1;
bilingual_str strError; bilingual_str strError;
CCoinControl coinControl; CCoinControl coinControl;
coinControl.m_feerate = CFeeRate(1000);
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
BOOST_CHECK(reserveDest.GetReservedDestination(tallyItem.txdest, false)); BOOST_CHECK(reserveDest.GetReservedDestination(tallyItem.txdest, false));

View File

@ -38,6 +38,10 @@ extern RecursiveMutex cs_wallets;
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup) BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
namespace {
constexpr CAmount fallbackFee = 1000;
} // anonymous namespace
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain) static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
{ {
DatabaseOptions options; DatabaseOptions options;
@ -869,7 +873,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
coinControl.Select(GetCoins({{100000, false}})[0]); coinControl.Select(GetCoins({{100000, false}})[0]);
// Start with fallback feerate // Start with fallback feerate
runTest(1, DEFAULT_FALLBACK_FEE, { runTest(1, fallbackFee, {
{0, {true, ChangeTest::ChangeExpected}}, {0, {true, ChangeTest::ChangeExpected}},
{1, {true, ChangeTest::ChangeExpected}}, {1, {true, ChangeTest::ChangeExpected}},
{2, {true, ChangeTest::ChangeExpected}}, {2, {true, ChangeTest::ChangeExpected}},
@ -886,7 +890,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
{13, {false, ChangeTest::Skip}} {13, {false, ChangeTest::Skip}}
}); });
// Now with 100x fallback feerate // Now with 100x fallback feerate
runTest(2, DEFAULT_FALLBACK_FEE * 100, { runTest(2, fallbackFee * 100, {
{0, {true, ChangeTest::ChangeExpected}}, {0, {true, ChangeTest::ChangeExpected}},
{1, {false, ChangeTest::Skip}}, {1, {false, ChangeTest::Skip}},
{2, {true, ChangeTest::ChangeExpected}}, {2, {true, ChangeTest::ChangeExpected}},
@ -912,7 +916,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
} }
// Start with fallback feerate // Start with fallback feerate
runTest(3, DEFAULT_FALLBACK_FEE, { runTest(3, fallbackFee, {
{0, {true, ChangeTest::ChangeExpected}}, {0, {true, ChangeTest::ChangeExpected}},
{1, {false, ChangeTest::Skip}}, {1, {false, ChangeTest::Skip}},
{2, {true, ChangeTest::ChangeExpected}}, {2, {true, ChangeTest::ChangeExpected}},
@ -929,7 +933,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
{13, {false, ChangeTest::Skip}} {13, {false, ChangeTest::Skip}}
}); });
// Now with 100x fallback feerate // Now with 100x fallback feerate
runTest(4, DEFAULT_FALLBACK_FEE * 100, { runTest(4, fallbackFee * 100, {
{0, {true, ChangeTest::ChangeExpected}}, {0, {true, ChangeTest::ChangeExpected}},
{1, {false, ChangeTest::Skip}}, {1, {false, ChangeTest::Skip}},
{2, {true, ChangeTest::ChangeExpected}}, {2, {true, ChangeTest::ChangeExpected}},
@ -958,7 +962,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
} }
// Start with fallback feerate // Start with fallback feerate
runTest(5, DEFAULT_FALLBACK_FEE, { runTest(5, fallbackFee, {
{0, {true, ChangeTest::ChangeExpected}}, {0, {true, ChangeTest::ChangeExpected}},
{1, {false, ChangeTest::Skip}}, {1, {false, ChangeTest::Skip}},
{2, {true, ChangeTest::ChangeExpected}}, {2, {true, ChangeTest::ChangeExpected}},
@ -975,7 +979,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
{13, {false, ChangeTest::Skip}} {13, {false, ChangeTest::Skip}}
}); });
// Now with 100x fallback feerate // Now with 100x fallback feerate
runTest(6, DEFAULT_FALLBACK_FEE * 100, { runTest(6, fallbackFee * 100, {
{0, {false, ChangeTest::Skip}}, {0, {false, ChangeTest::Skip}},
{1, {false, ChangeTest::Skip}}, {1, {false, ChangeTest::Skip}},
{2, {false, ChangeTest::Skip}}, {2, {false, ChangeTest::Skip}},
@ -996,6 +1000,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
// which inputs to use // which inputs to use
{ {
coinControl.SetNull(); coinControl.SetNull();
coinControl.m_feerate = CFeeRate(fallbackFee);
auto setCoins = GetCoins({{1000, false}, {1000, false}, {1000, false}, {1000, false}, {1000, false}, auto setCoins = GetCoins({{1000, false}, {1000, false}, {1000, false}, {1000, false}, {1000, false},
{1100, false}, {1200, false}, {1300, false}, {1400, false}, {1500, false}, {1100, false}, {1200, false}, {1300, false}, {1400, false}, {1500, false},
{3000, false}, {3000, false}, {2000, false}, {2000, false}, {1000, false}}); {3000, false}, {3000, false}, {2000, false}, {2000, false}, {1000, false}});
@ -1044,6 +1049,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
// Test if the change output ends up at the requested position // Test if the change output ends up at the requested position
{ {
coinControl.SetNull(); coinControl.SetNull();
coinControl.m_feerate = CFeeRate(fallbackFee);
coinControl.Select(GetCoins({{100000, false}})[0]); coinControl.Select(GetCoins({{100000, false}})[0]);
BOOST_CHECK(CreateTransaction({{25000, false}, {25000, false}, {25000, false}}, {}, 0, true, ChangeTest::ChangeExpected)); BOOST_CHECK(CreateTransaction({{25000, false}, {25000, false}, {25000, false}}, {}, 0, true, ChangeTest::ChangeExpected));
@ -1054,6 +1060,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
// Test error cases // Test error cases
{ {
coinControl.SetNull(); coinControl.SetNull();
coinControl.m_feerate = CFeeRate(fallbackFee);
// First try to send something without any coins available // First try to send something without any coins available
{ {
// Lock all other coins // Lock all other coins
@ -1090,6 +1097,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
}; };
coinControl.SetNull(); coinControl.SetNull();
coinControl.m_feerate = CFeeRate(fallbackFee);
coinControl.Select(GetCoins({{100 * COIN, false}})[0]); coinControl.Select(GetCoins({{100 * COIN, false}})[0]);
BOOST_CHECK(CreateTransaction({{-5000, false}}, strAmountNotNegative, false)); BOOST_CHECK(CreateTransaction({{-5000, false}}, strAmountNotNegative, false));

View File

@ -4610,7 +4610,6 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()}; walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
} }
walletInstance->m_allow_fallback_fee = Params().IsTestChain();
if (gArgs.IsArgSet("-fallbackfee")) { if (gArgs.IsArgSet("-fallbackfee")) {
std::optional<CAmount> fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", "")); std::optional<CAmount> fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", ""));
if (!fallback_fee) { if (!fallback_fee) {
@ -4621,8 +4620,10 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
_("This is the transaction fee you may pay when fee estimates are not available.")); _("This is the transaction fee you may pay when fee estimates are not available."));
} }
walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()}; walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0; //disable fallback fee in case value was set to 0, enable if non-null value
} }
// Disable fallback fee in case value was set to 0, enable if non-null value
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
if (gArgs.IsArgSet("-discardfee")) { if (gArgs.IsArgSet("-discardfee")) {
std::optional<CAmount> discard_fee = ParseMoney(gArgs.GetArg("-discardfee", "")); std::optional<CAmount> discard_fee = ParseMoney(gArgs.GetArg("-discardfee", ""));
if (!discard_fee) { if (!discard_fee) {

View File

@ -67,7 +67,7 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
//! -paytxfee default //! -paytxfee default
constexpr CAmount DEFAULT_PAY_TX_FEE = 0; constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
//! -fallbackfee default //! -fallbackfee default
static const CAmount DEFAULT_FALLBACK_FEE = 1000; static const CAmount DEFAULT_FALLBACK_FEE = 0;
//! -discardfee default //! -discardfee default
static const CAmount DEFAULT_DISCARD_FEE = 10000; static const CAmount DEFAULT_DISCARD_FEE = 10000;
//! -mintxfee default //! -mintxfee default
@ -1070,7 +1070,7 @@ public:
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE}; bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
bool m_allow_fallback_fee{true}; //!< will be defined via chainparams bool m_allow_fallback_fee{true}; //!< will be false if -fallbackfee=0
CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee
/** /**
* If fee estimation does not have enough data to provide estimates, use this fee instead. * If fee estimation does not have enough data to provide estimates, use this fee instead.

View File

@ -6,8 +6,6 @@
#include <wallet/walletdb.h> #include <wallet/walletdb.h>
#include <consensus/tx_check.h>
#include <consensus/validation.h>
#include <key_io.h> #include <key_io.h>
#include <fs.h> #include <fs.h>
#include <governance/object.h> #include <governance/object.h>
@ -255,8 +253,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> hash; ssKey >> hash;
CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef()); CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
ssValue >> wtx; ssValue >> wtx;
CValidationState state; if (wtx.GetHash() != hash)
if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
return false; return false;
// Undo serialize changes in 31600 // Undo serialize changes in 31600

View File

@ -22,7 +22,7 @@ SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift
SEQUENCE_LOCKTIME_MASK = 0x0000ffff SEQUENCE_LOCKTIME_MASK = 0x0000ffff
# RPC error for non-BIP68 final transactions # RPC error for non-BIP68 final transactions
NOT_FINAL_ERROR = "non-BIP68-final (code 64)" NOT_FINAL_ERROR = "non-BIP68-final"
class BIP68Test(BitcoinTestFramework): class BIP68Test(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):

View File

@ -130,7 +130,7 @@ class BIP65Test(BitcoinTestFramework):
# First we show that this tx is valid except for CLTV by getting it # First we show that this tx is valid except for CLTV by getting it
# rejected from the mempool for exactly that reason. # rejected from the mempool for exactly that reason.
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0) assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
# Now we verify that a block with this transaction is also invalid. # Now we verify that a block with this transaction is also invalid.
block.vtx.append(spendtx) block.vtx.append(spendtx)

View File

@ -112,7 +112,7 @@ class BIP66Test(BitcoinTestFramework):
# First we show that this tx is valid except for DERSIG by getting it # First we show that this tx is valid except for DERSIG by getting it
# rejected from the mempool for exactly that reason. # rejected from the mempool for exactly that reason.
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0) assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
# Now we verify that a block with this transaction is also invalid. # Now we verify that a block with this transaction is also invalid.
block.vtx.append(spendtx) block.vtx.append(spendtx)

View File

@ -232,7 +232,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
# Assert that the conflicting tx got mined and the locked TX is not valid # Assert that the conflicting tx got mined and the locked TX is not valid
assert self.nodes[0].getrawtransaction(rawtx1_txid, True)['confirmations'] > 0 assert self.nodes[0].getrawtransaction(rawtx1_txid, True)['confirmations'] > 0
assert_raises_rpc_error(-25, "Missing inputs", self.nodes[0].sendrawtransaction, rawtx2) assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[0].sendrawtransaction, rawtx2)
# Create the block and the corresponding clsig but do not relay clsig yet # Create the block and the corresponding clsig but do not relay clsig yet
cl_block = self.create_block(self.nodes[0]) cl_block = self.create_block(self.nodes[0])

View File

@ -20,7 +20,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error from test_framework.util import assert_equal, assert_raises_rpc_error
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)" NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
def trueDummy(tx): def trueDummy(tx):
scriptSig = CScript(tx.vin[0].scriptSig) scriptSig = CScript(tx.vin[0].scriptSig)

View File

@ -77,7 +77,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
node.generate(1) node.generate(1)
self.mempool_size = 0 self.mempool_size = 0
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': '18: txn-already-known'}], result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}],
rawtxs=[raw_tx_in_block], rawtxs=[raw_tx_in_block],
) )
@ -115,7 +115,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
node.sendrawtransaction(hexstring=raw_tx_0) node.sendrawtransaction(hexstring=raw_tx_0)
self.mempool_size += 1 self.mempool_size += 1
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': '18: txn-already-in-mempool'}], result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}],
rawtxs=[raw_tx_0], rawtxs=[raw_tx_0],
) )
@ -128,7 +128,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
txid_0_reject = tx.rehash() txid_0_reject = tx.rehash()
self.check_mempool_result( self.check_mempool_result(
# No RBF in DASH # No RBF in DASH
result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}], result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
rawtxs=[raw_tx_0_reject], rawtxs=[raw_tx_0_reject],
) )
@ -140,7 +140,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
# skip re-signing the tx # skip re-signing the tx
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
maxfeerate=0, maxfeerate=0,
) )
@ -199,7 +199,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
# Skip re-signing the transaction for context independent checks from now on # Skip re-signing the transaction for context independent checks from now on
# tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex']))) # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -207,7 +207,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize())) tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize()))
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -215,7 +215,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].nValue *= -1 tx.vout[0].nValue *= -1
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -224,7 +224,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].nValue = MAX_MONEY + 1 tx.vout[0].nValue = MAX_MONEY + 1
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -233,7 +233,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout = [tx.vout[0]] * 2 tx.vout = [tx.vout[0]] * 2
tx.vout[0].nValue = MAX_MONEY tx.vout[0].nValue = MAX_MONEY
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -241,7 +241,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin = [tx.vin[0]] * 2 tx.vin = [tx.vin[0]] * 2
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -250,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid']) raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'coinbase'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -258,13 +258,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.nVersion = 4 # A version currently non-standard tx.nVersion = 4 # A version currently non-standard
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
@ -273,25 +273,25 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
pubkey = key.get_pubkey().get_bytes() pubkey = key.get_pubkey().get_bytes()
tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3) tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3)
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: bare-multisig'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes) tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes) tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
@ -299,21 +299,21 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy
tx.vout = [output_p2sh_burn] * num_scripts tx.vout = [output_p2sh_burn] * num_scripts
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0] = output_p2sh_burn tx.vout[0] = output_p2sh_burn
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
tx.vout = [tx.vout[0]] * 2 tx.vout = [tx.vout[0]] * 2
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -322,7 +322,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored
tx.nLockTime = node.getblockcount() + 1 tx.nLockTime = node.getblockcount() + 1
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-final'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
) )
@ -331,7 +331,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
# Can skip re-signing the tx because of early rejection # Can skip re-signing the tx because of early rejection
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],
maxfeerate=0, maxfeerate=0,
) )

View File

@ -151,7 +151,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx) rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)
# This will raise an exception since there are missing inputs # This will raise an exception since there are missing inputs
assert_raises_rpc_error(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx['hex'])
##################################### #####################################
# getrawtransaction with block hash # # getrawtransaction with block hash #
@ -388,7 +388,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Thus, testmempoolaccept should reject # Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0] testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
assert_equal(testres['allowed'], False) assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], '256: absurdly-high-fee') assert_equal(testres['reject-reason'], 'absurdly-high-fee')
# and sendrawtransaction should throw # and sendrawtransaction should throw
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000) assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
# and the following calls should both succeed # and the following calls should both succeed
@ -412,7 +412,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Thus, testmempoolaccept should reject # Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0] testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
assert_equal(testres['allowed'], False) assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], '256: absurdly-high-fee') assert_equal(testres['reject-reason'], 'absurdly-high-fee')
# and sendrawtransaction should throw # and sendrawtransaction should throw
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex']) assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
# and the following calls should both succeed # and the following calls should both succeed

View File

@ -340,6 +340,7 @@ def initialize_datadir(dirname, n, chain):
f.write("[{}]\n".format(chain_name_conf_section)) f.write("[{}]\n".format(chain_name_conf_section))
f.write("port=" + str(p2p_port(n)) + "\n") f.write("port=" + str(p2p_port(n)) + "\n")
f.write("rpcport=" + str(rpc_port(n)) + "\n") f.write("rpcport=" + str(rpc_port(n)) + "\n")
f.write("fallbackfee=0.00001\n")
f.write("server=1\n") f.write("server=1\n")
f.write("keypool=1\n") f.write("keypool=1\n")
f.write("discover=0\n") f.write("discover=0\n")