mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
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:
commit
03b0acd7d0
8
doc/release-notes-16524.md
Normal file
8
doc/release-notes-16524.md
Normal 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)
|
31
doc/release-notes-17004.md
Normal file
31
doc/release-notes-17004.md
Normal 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.
|
@ -327,6 +327,7 @@ BITCOIN_CORE_H = \
|
||||
util/vector.h \
|
||||
util/url.h \
|
||||
util/validation.h \
|
||||
util/vector.h \
|
||||
validation.h \
|
||||
validationinterface.h \
|
||||
versionbits.h \
|
||||
|
@ -40,8 +40,8 @@ static void AssembleBlock(benchmark::Bench& bench)
|
||||
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
||||
|
||||
for (const auto& txr : txs) {
|
||||
CValidationState state;
|
||||
bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, nullptr /* pfMissingInputs */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
|
||||
TxValidationState state;
|
||||
bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, false /* bypass_limits */, /* nAbsurdFee */ 0)};
|
||||
assert(ret);
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
|
||||
bool rewound = stream.Rewind(benchmark::data::block813851.size());
|
||||
assert(rewound);
|
||||
|
||||
CValidationState validationState;
|
||||
BlockValidationState validationState;
|
||||
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), block.GetBlockTime());
|
||||
assert(checked);
|
||||
});
|
||||
|
@ -56,7 +56,7 @@ static void DuplicateInputs(benchmark::Bench& bench)
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
|
||||
bench.minEpochIterations(10).run([&] {
|
||||
CValidationState cvstate{};
|
||||
BlockValidationState cvstate{};
|
||||
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
||||
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
||||
});
|
||||
|
@ -198,13 +198,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
|
||||
if (vtx_missing.size() != tx_missing_offset)
|
||||
return READ_STATUS_INVALID;
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!CheckBlock(block, state, Params().GetConsensus())) {
|
||||
// TODO: We really want to just check merkle tree manually here,
|
||||
// but that is expensive, and CheckBlock caches a block's
|
||||
// "checked-status" (in the CBlock?). CBlock should be able to
|
||||
// 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_CHECKBLOCK_FAILED;
|
||||
}
|
||||
|
@ -351,8 +351,8 @@ bool CCoinJoin::IsCollateralValid(CTxMemPool& mempool, const CTransaction& txCol
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CValidationState validationState;
|
||||
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*pfMissingInputs=*/nullptr, /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) {
|
||||
TxValidationState validationState;
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
@ -320,9 +320,9 @@ void CCoinJoinServer::CommitFinalTransaction()
|
||||
{
|
||||
// See if the transaction is valid
|
||||
TRY_LOCK(cs_main, lockMain);
|
||||
CValidationState validationState;
|
||||
TxValidationState validationState;
|
||||
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");
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
// 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
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CValidationState validationState;
|
||||
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||
TxValidationState validationState;
|
||||
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||
LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__);
|
||||
} else {
|
||||
connman.RelayTransaction(*txref);
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <primitives/transaction.h>
|
||||
#include <consensus/validation.h>
|
||||
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
||||
bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
|
||||
{
|
||||
bool allowEmptyTxInOut = false;
|
||||
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
|
||||
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())
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-empty");
|
||||
// Size limits
|
||||
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)
|
||||
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)
|
||||
CAmount nValueOut = 0;
|
||||
for (const auto& txout : tx.vout) {
|
||||
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)
|
||||
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;
|
||||
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)
|
||||
@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
||||
std::set<COutPoint> vInOutPoints;
|
||||
for (const auto& txin : tx.vin) {
|
||||
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()) {
|
||||
@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
||||
minCbSize = 1;
|
||||
}
|
||||
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 {
|
||||
for (const auto& txin : tx.vin)
|
||||
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;
|
||||
|
@ -13,9 +13,9 @@
|
||||
*/
|
||||
|
||||
class CTransaction;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
|
||||
/** Context-independent validity checks */
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||
bool CheckTransaction(const CTransaction& tx, TxValidationState& state);
|
||||
|
||||
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
|
||||
|
@ -158,11 +158,12 @@ unsigned int GetTransactionSigOpCount(const CTransaction& tx, const CCoinsViewCa
|
||||
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?
|
||||
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;
|
||||
@ -173,25 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
||||
|
||||
// If prev is coinbase, check that it's matured
|
||||
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
|
||||
nValueIn += coin.out.nValue;
|
||||
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();
|
||||
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
|
||||
const CAmount txfee_aux = nValueIn - value_out;
|
||||
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;
|
||||
|
@ -13,7 +13,7 @@
|
||||
class CBlockIndex;
|
||||
class CCoinsViewCache;
|
||||
class CTransaction;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
|
||||
/** Transaction validation functions */
|
||||
|
||||
@ -24,7 +24,7 @@ namespace Consensus {
|
||||
* @param[out] txfee Set to the transaction fee if successful.
|
||||
* 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
|
||||
|
||||
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
||||
|
@ -8,31 +8,47 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
/** "reject" message codes */
|
||||
static const unsigned char REJECT_MALFORMED = 0x01;
|
||||
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.
|
||||
/** A "reason" why a transaction was invalid, suitable for determining whether the
|
||||
* provider of the transaction should be banned/ignored/disconnected/etc.
|
||||
*/
|
||||
enum class ValidationInvalidReason {
|
||||
// txn and blocks:
|
||||
NONE, //!< not actually invalid
|
||||
CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
|
||||
enum class TxValidationResult {
|
||||
TX_RESULT_UNSET, //!< initial value. Tx has not yet been rejected
|
||||
TX_CONSENSUS, //!< invalid by consensus rules
|
||||
/**
|
||||
* Invalid by a change to consensus rules more recent than some major deployment.
|
||||
*/
|
||||
RECENT_CONSENSUS_CHANGE,
|
||||
// Only blocks (or headers):
|
||||
CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why
|
||||
// Only loose txn:
|
||||
TX_RECENT_CONSENSUS_CHANGE,
|
||||
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_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
|
||||
@ -40,95 +56,78 @@ enum class ValidationInvalidReason {
|
||||
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_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 */
|
||||
class CValidationState {
|
||||
/** Base class for capturing information about block/transaction validation. This is subclassed
|
||||
* by TxValidationState and BlockValidationState for validation information on transactions
|
||||
* and blocks respectively. */
|
||||
class ValidationState {
|
||||
private:
|
||||
enum mode_state {
|
||||
MODE_VALID, //!< everything ok
|
||||
MODE_INVALID, //!< network rule violation (DoS value may be set)
|
||||
MODE_ERROR, //!< run-time error
|
||||
} mode;
|
||||
ValidationInvalidReason m_reason;
|
||||
std::string strRejectReason;
|
||||
unsigned int chRejectCode;
|
||||
std::string strDebugMessage;
|
||||
public:
|
||||
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {}
|
||||
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
|
||||
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
|
||||
const std::string &strDebugMessageIn="") {
|
||||
m_reason = reasonIn;
|
||||
chRejectCode = chRejectCodeIn;
|
||||
strRejectReason = strRejectReasonIn;
|
||||
strDebugMessage = strDebugMessageIn;
|
||||
if (mode == MODE_ERROR)
|
||||
return ret;
|
||||
mode = MODE_INVALID;
|
||||
return ret;
|
||||
} m_mode;
|
||||
std::string m_reject_reason;
|
||||
std::string m_debug_message;
|
||||
protected:
|
||||
void Invalid(const std::string &reject_reason="",
|
||||
const std::string &debug_message="")
|
||||
{
|
||||
m_reject_reason = reject_reason;
|
||||
m_debug_message = debug_message;
|
||||
if (m_mode != MODE_ERROR) m_mode = MODE_INVALID;
|
||||
}
|
||||
bool Error(const std::string& strRejectReasonIn) {
|
||||
if (mode == MODE_VALID)
|
||||
strRejectReason = strRejectReasonIn;
|
||||
mode = MODE_ERROR;
|
||||
public:
|
||||
// ValidationState is abstract. Have a pure virtual destructor.
|
||||
virtual ~ValidationState() = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
bool IsValid() const {
|
||||
return mode == MODE_VALID;
|
||||
bool IsValid() const { return m_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 {
|
||||
return mode == MODE_INVALID;
|
||||
TxValidationResult GetResult() const { return m_result; }
|
||||
};
|
||||
|
||||
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 {
|
||||
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; }
|
||||
BlockValidationResult GetResult() const { return m_result; }
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CONSENSUS_VALIDATION_H
|
||||
|
@ -15,33 +15,33 @@
|
||||
#include <chainparams.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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-type");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-type");
|
||||
}
|
||||
|
||||
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;
|
||||
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) {
|
||||
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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-height");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-height");
|
||||
}
|
||||
|
||||
if (pindexPrev) {
|
||||
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
|
||||
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
|
||||
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) {
|
||||
return true;
|
||||
@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
||||
|
||||
CCbTx 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;
|
||||
@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
||||
if (sml == smlCached) {
|
||||
merkleRootRet = merkleRootCached;
|
||||
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;
|
||||
}
|
||||
@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
||||
mutatedCached = 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;
|
||||
} catch (const std::exception& e) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 nTimeLoop = 0;
|
||||
@ -233,7 +233,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
||||
|
||||
auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor);
|
||||
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
|
||||
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) {
|
||||
llmq::CFinalCommitmentTxPayload 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()) {
|
||||
// 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);
|
||||
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();
|
||||
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);
|
||||
assert(llmq_params_opt.has_value());
|
||||
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
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -8,10 +8,11 @@
|
||||
#include <primitives/transaction.h>
|
||||
#include <univalue.h>
|
||||
|
||||
class BlockValidationState;
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
class CCoinsViewCache;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
|
||||
namespace llmq {
|
||||
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 CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view);
|
||||
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state);
|
||||
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, BlockValidationState& state, const CCoinsViewCache& view);
|
||||
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state);
|
||||
|
||||
#endif // BITCOIN_EVO_CBTX_H
|
||||
|
@ -654,7 +654,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
|
||||
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);
|
||||
|
||||
@ -672,7 +672,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
||||
try {
|
||||
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
|
||||
return false;
|
||||
}
|
||||
@ -710,7 +710,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
||||
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
|
||||
} catch (const std::exception& e) {
|
||||
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
|
||||
@ -723,7 +723,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
||||
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__,
|
||||
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);
|
||||
}
|
||||
@ -775,7 +775,7 @@ void CDeterministicMNManager::UpdatedBlockTip(const CBlockIndex* 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);
|
||||
|
||||
@ -820,11 +820,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
|
||||
CProRegTx 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)) {
|
||||
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);
|
||||
@ -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)) {
|
||||
// should actually never get to this point as CheckProRegTx should have handled this case.
|
||||
// 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);
|
||||
@ -858,10 +858,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
}
|
||||
|
||||
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)) {
|
||||
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;
|
||||
@ -883,26 +883,26 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
||||
CProUpServTx 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)) {
|
||||
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) {
|
||||
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);
|
||||
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) {
|
||||
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)) {
|
||||
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);
|
||||
@ -932,12 +932,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
||||
CProUpRegTx 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);
|
||||
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);
|
||||
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) {
|
||||
CProUpRevTx 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);
|
||||
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);
|
||||
newState->ResetOperatorFields();
|
||||
@ -979,19 +979,19 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
} else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||
llmq::CFinalCommitmentTxPayload 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()) {
|
||||
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
||||
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 quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
|
||||
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
|
||||
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
|
||||
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);
|
||||
@ -1348,111 +1348,111 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
}
|
||||
|
||||
template <typename ProTx>
|
||||
static bool CheckService(const ProTx& proTx, CValidationState& state)
|
||||
static bool CheckService(const ProTx& proTx, TxValidationState& state)
|
||||
{
|
||||
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()) {
|
||||
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();
|
||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||
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) {
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename ProTx>
|
||||
static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state)
|
||||
static bool CheckPlatformFields(const ProTx& proTx, TxValidationState& state)
|
||||
{
|
||||
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();
|
||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||
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();
|
||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||
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();
|
||||
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) {
|
||||
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 ||
|
||||
proTx.platformP2PPort == 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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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))) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
|
||||
}
|
||||
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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||
}
|
||||
|
||||
CProRegTx 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) {
|
||||
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
|
||||
@ -1477,31 +1477,31 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
||||
if (!ptx.collateralOutpoint.hash.IsNull()) {
|
||||
Coin coin;
|
||||
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)) {
|
||||
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.
|
||||
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
|
||||
keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest);
|
||||
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;
|
||||
} else {
|
||||
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) {
|
||||
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)) {
|
||||
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);
|
||||
@ -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)
|
||||
// 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))) {
|
||||
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) {
|
||||
@ -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)
|
||||
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
|
||||
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
|
||||
if (ptx.nType == MnType::HighPerformance) {
|
||||
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 (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) {
|
||||
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) {
|
||||
@ -1553,26 +1553,26 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
||||
} else {
|
||||
// collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||
}
|
||||
|
||||
CProUpServTx 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) {
|
||||
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)) {
|
||||
@ -1590,34 +1590,34 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
|
||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||
auto mn = mnList.GetMN(ptx.proTxHash);
|
||||
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
|
||||
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
|
||||
if (ptx.nType == MnType::HighPerformance) {
|
||||
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 (mn->nOperatorReward == 0) {
|
||||
// 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()) {
|
||||
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
|
||||
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)) {
|
||||
// pass the state returned by the function above
|
||||
@ -1628,69 +1628,69 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
|
||||
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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||
}
|
||||
|
||||
CProUpRegTx 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) {
|
||||
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;
|
||||
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
|
||||
// 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) {
|
||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||
auto dmn = mnList.GetMN(ptx.proTxHash);
|
||||
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)
|
||||
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;
|
||||
if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) {
|
||||
// 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)
|
||||
CTxDestination 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))) {
|
||||
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)) {
|
||||
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
|
||||
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 (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) {
|
||||
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)) {
|
||||
// pass the state returned by the function above
|
||||
@ -1701,29 +1701,29 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
|
||||
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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||
}
|
||||
|
||||
CProUpRevTx 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) {
|
||||
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) {
|
||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||
auto dmn = mnList.GetMN(ptx.proTxHash);
|
||||
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) {
|
||||
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)) {
|
||||
// pass the state returned by the function above
|
||||
|
@ -27,7 +27,7 @@
|
||||
class CConnman;
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
class CSimplifiedMNListDiff;
|
||||
|
||||
extern CCriticalSection cs_main;
|
||||
@ -563,14 +563,14 @@ public:
|
||||
m_evoDb(evoDb), connman(_connman) {}
|
||||
~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);
|
||||
bool UndoBlock(const CBlock& block, 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)
|
||||
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);
|
||||
static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs);
|
||||
static void DecreasePoSePenalties(CDeterministicMNList& mnList);
|
||||
@ -595,10 +595,10 @@ private:
|
||||
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 CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs);
|
||||
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs);
|
||||
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, 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, TxValidationState& state, 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, TxValidationState& state, bool check_sigs);
|
||||
|
||||
extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
|
||||
|
||||
|
@ -34,33 +34,33 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
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)) {
|
||||
// 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()) {
|
||||
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)) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-invalid");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <univalue.h>
|
||||
|
||||
class CBlockIndex;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
extern CCriticalSection cs_main;
|
||||
|
||||
// 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
|
||||
|
@ -14,34 +14,34 @@
|
||||
maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
{
|
||||
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)) {
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-type"};
|
||||
return {TxValidationResult::TX_CONSENSUS, "bad-protx-type"};
|
||||
}
|
||||
if (nMode != 0) {
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
||||
return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"};
|
||||
}
|
||||
|
||||
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()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||
}
|
||||
|
||||
CTxDestination payoutDest;
|
||||
if (!ExtractDestination(scriptPayout, payoutDest)) {
|
||||
// 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)
|
||||
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) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-operator-reward"};
|
||||
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-reward"};
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -87,7 +87,7 @@ std::string CProRegTx::ToString() const
|
||||
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
{
|
||||
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
|
||||
return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -108,17 +108,17 @@ std::string CProUpServTx::ToString() const
|
||||
maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
{
|
||||
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) {
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
||||
return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"};
|
||||
}
|
||||
|
||||
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()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -138,13 +138,13 @@ std::string CProUpRegTx::ToString() const
|
||||
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
{
|
||||
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 is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0
|
||||
if (nReason > CProUpRevTx::REASON_LAST) {
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-reason"};
|
||||
return {TxValidationResult::TX_CONSENSUS, "bad-protx-reason"};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
class CBlockIndex;
|
||||
class CCoinsViewCache;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
|
||||
class CProRegTx
|
||||
{
|
||||
@ -329,7 +329,7 @@ template <typename ProTx>
|
||||
static maybe_error CheckInputsHash(const CTransaction& tx, const ProTx& proTx)
|
||||
{
|
||||
if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) {
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-inputs-hash"};
|
||||
return {TxValidationResult::TX_CONSENSUS, "bad-protx-inputs-hash"};
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -17,11 +17,11 @@
|
||||
|
||||
struct maybe_error {
|
||||
bool did_err{false};
|
||||
ValidationInvalidReason reason{ValidationInvalidReason::CONSENSUS};
|
||||
TxValidationResult reason{TxValidationResult::TX_CONSENSUS};
|
||||
std::string_view error_str;
|
||||
|
||||
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>
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <primitives/block.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);
|
||||
|
||||
@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
||||
return true;
|
||||
|
||||
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 {
|
||||
@ -46,13 +46,13 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
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) {
|
||||
return true;
|
||||
@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
|
||||
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)
|
||||
@ -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,
|
||||
CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots)
|
||||
BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
@ -112,13 +112,18 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
|
||||
int64_t nTime1 = GetTimeMicros();
|
||||
|
||||
for (const auto& ptr_tx : block.vtx) {
|
||||
if (!CheckSpecialTx(*ptr_tx, pindex->pprev, state, view, fCheckCbTxMerleRoots)) {
|
||||
// pass the state returned by the function above
|
||||
return false;
|
||||
TxValidationState tx_state;
|
||||
// At this moment CheckSpecialTx() and ProcessSpecialTx() may fail by 2 possible ways:
|
||||
// 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)) {
|
||||
// pass the state returned by the function above
|
||||
return false;
|
||||
if (!ProcessSpecialTx(*ptr_tx, pindex, tx_state)) {
|
||||
assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL);
|
||||
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);
|
||||
} catch (const std::exception& e) {
|
||||
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;
|
||||
|
@ -9,19 +9,20 @@
|
||||
#include <sync.h>
|
||||
#include <threadsafety.h>
|
||||
|
||||
class BlockValidationState;
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
class CCoinsViewCache;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
namespace llmq {
|
||||
class CQuorumBlockProcessor;
|
||||
} // namespace llmq
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
#endif // BITCOIN_EVO_SPECIALTXMAN_H
|
||||
|
@ -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 relevant pointers before the ABC call.
|
||||
for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) {
|
||||
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
|
||||
StartShutdown();
|
||||
|
@ -23,7 +23,6 @@ class CFeeRate;
|
||||
class CRPCCommand;
|
||||
class CScheduler;
|
||||
class CTxMemPool;
|
||||
class CValidationState;
|
||||
class CFeeRate;
|
||||
class CBlockIndex;
|
||||
class Coin;
|
||||
|
19
src/key.h
19
src/key.h
@ -161,25 +161,6 @@ struct CExtKey {
|
||||
bool Derive(CExtKey& out, unsigned int nChild) const;
|
||||
CExtPubKey Neuter() const;
|
||||
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. */
|
||||
|
@ -136,7 +136,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
|
||||
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);
|
||||
|
||||
@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
|
||||
const auto numCommitmentsInNewBlock = qcs.count(params.type);
|
||||
|
||||
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) {
|
||||
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)) {
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -234,31 +234,31 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
|
||||
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__,
|
||||
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) {
|
||||
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());
|
||||
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.VerifyNull()) {
|
||||
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());
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
|
||||
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid-null");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (HasMinedCommitment(llmq_params.type, quorumHash)) {
|
||||
// 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)) {
|
||||
// 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);
|
||||
@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
|
||||
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__,
|
||||
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) {
|
||||
@ -313,7 +313,7 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
|
||||
llmq::utils::PreComputeQuorumMembers(pindex, true);
|
||||
|
||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||
CValidationState dummy;
|
||||
BlockValidationState dummy;
|
||||
if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) {
|
||||
return false;
|
||||
}
|
||||
@ -378,7 +378,7 @@ bool CQuorumBlockProcessor::UpgradeDB()
|
||||
assert(r);
|
||||
|
||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||
CValidationState dummyState;
|
||||
BlockValidationState dummyState;
|
||||
GetCommitmentsFromBlock(block, pindex, qcs, dummyState);
|
||||
|
||||
for (const auto& p : qcs) {
|
||||
@ -407,7 +407,7 @@ bool CQuorumBlockProcessor::UpgradeDB()
|
||||
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);
|
||||
|
||||
@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
|
||||
if (!GetTxPayload(*tx, qc)) {
|
||||
// should not happen as it was verified before processing the block
|
||||
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);
|
||||
if (!llmq_params_opt.has_value()) {
|
||||
// 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)
|
||||
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
|
||||
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()) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-premature");
|
||||
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-premature");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
class BlockValidationState;
|
||||
class CNode;
|
||||
class CConnman;
|
||||
class CValidationState;
|
||||
class CEvoDB;
|
||||
|
||||
extern CCriticalSection cs_main;
|
||||
@ -49,7 +49,7 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
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::optional<const CBlockIndex*> GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const;
|
||||
private:
|
||||
static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& 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);
|
||||
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, 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);
|
||||
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);
|
||||
|
@ -494,20 +494,20 @@ void CChainLocksHandler::EnforceBestChainLock()
|
||||
}
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState dummy_state;
|
||||
const auto ¶ms = Params();
|
||||
|
||||
// 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
|
||||
// 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());
|
||||
::ChainstateActive().EnforceBlock(state, params, pindex);
|
||||
::ChainstateActive().EnforceBlock(dummy_state, params, pindex);
|
||||
|
||||
bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex;
|
||||
|
||||
if (activateNeeded) {
|
||||
if (!::ChainstateActive().ActivateBestChain(state, params)) {
|
||||
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state));
|
||||
if (!::ChainstateActive().ActivateBestChain(dummy_state, params)) {
|
||||
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(dummy_state));
|
||||
return;
|
||||
}
|
||||
LOCK(cs_main);
|
||||
|
@ -176,18 +176,18 @@ bool CFinalCommitment::VerifySizes(const Consensus::LLMQParams& params) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
||||
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state)
|
||||
{
|
||||
CFinalCommitmentTxPayload qcTx;
|
||||
if (!GetTxPayload(tx, qcTx)) {
|
||||
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);
|
||||
if (!llmq_params_opt.has_value()) {
|
||||
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)) {
|
||||
@ -201,36 +201,36 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
|
||||
|
||||
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
|
||||
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)) {
|
||||
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));
|
||||
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)) {
|
||||
// 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.VerifyNull()) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) {
|
||||
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);
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <univalue.h>
|
||||
|
||||
class CBlockIndex;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
|
||||
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
|
||||
|
||||
|
@ -1477,7 +1477,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
|
||||
|
||||
LogPrintf("CInstantSendManager::%s -- invalidating block %s\n", __func__, pindex->GetBlockHash().ToString());
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
// need non-const pointer
|
||||
auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash()));
|
||||
if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) {
|
||||
@ -1495,7 +1495,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
|
||||
}
|
||||
|
||||
if (activateBestChain) {
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!::ChainstateActive().ActivateBestChain(state, Params())) {
|
||||
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
|
||||
|
@ -205,7 +205,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
|
||||
|
||||
cbTx.nHeight = nHeight;
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
|
||||
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->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);
|
||||
|
||||
CValidationState state;
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
|
||||
BlockValidationState state;
|
||||
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)));
|
||||
}
|
||||
|
@ -173,8 +173,8 @@ namespace {
|
||||
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
||||
|
||||
/**
|
||||
* Sources of received blocks, saved to be able to send them reject
|
||||
* messages or ban them when processing happens afterwards.
|
||||
* Sources of received blocks, saved to be able punish them when processing
|
||||
* happens afterwards.
|
||||
* Set mapBlockSource[hash].second to false if the node should not be
|
||||
* 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
|
||||
* 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)
|
||||
*/
|
||||
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()) {
|
||||
case ValidationInvalidReason::NONE:
|
||||
switch (state.GetResult()) {
|
||||
case BlockValidationResult::BLOCK_RESULT_UNSET:
|
||||
break;
|
||||
// The node is providing invalid data:
|
||||
case ValidationInvalidReason::CONSENSUS:
|
||||
case ValidationInvalidReason::BLOCK_MUTATED:
|
||||
case BlockValidationResult::BLOCK_CONSENSUS:
|
||||
case BlockValidationResult::BLOCK_MUTATED:
|
||||
if (!via_compact_block) {
|
||||
Misbehaving(nodeid, 100, message);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ValidationInvalidReason::CACHED_INVALID:
|
||||
case BlockValidationResult::BLOCK_CACHED_INVALID:
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CNodeState *node_state = State(nodeid);
|
||||
@ -1260,25 +1260,18 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ValidationInvalidReason::BLOCK_INVALID_HEADER:
|
||||
case ValidationInvalidReason::BLOCK_CHECKPOINT:
|
||||
case ValidationInvalidReason::BLOCK_INVALID_PREV:
|
||||
case BlockValidationResult::BLOCK_INVALID_HEADER:
|
||||
case BlockValidationResult::BLOCK_CHECKPOINT:
|
||||
case BlockValidationResult::BLOCK_INVALID_PREV:
|
||||
Misbehaving(nodeid, 100, message);
|
||||
return true;
|
||||
// Conflicting (but not necessarily invalid) data or different policy:
|
||||
case ValidationInvalidReason::BLOCK_MISSING_PREV:
|
||||
case ValidationInvalidReason::BLOCK_CHAINLOCK:
|
||||
case ValidationInvalidReason::TX_BAD_SPECIAL:
|
||||
case ValidationInvalidReason::TX_CONFLICT_LOCK:
|
||||
case BlockValidationResult::BLOCK_MISSING_PREV:
|
||||
case BlockValidationResult::BLOCK_CHAINLOCK:
|
||||
Misbehaving(nodeid, 10, message);
|
||||
return true;
|
||||
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
|
||||
case ValidationInvalidReason::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:
|
||||
case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
|
||||
case BlockValidationResult::BLOCK_TIME_FUTURE:
|
||||
break;
|
||||
}
|
||||
if (message != "") {
|
||||
@ -1287,6 +1280,41 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
||||
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
|
||||
* 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);
|
||||
|
||||
const uint256 hash(block.GetHash());
|
||||
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
|
||||
|
||||
if (state.IsInvalid()) {
|
||||
// Don't send reject message with code 0 or an internal reject code.
|
||||
if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) {
|
||||
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||
}
|
||||
// If the block failed validation, we know where it came from and we're still connected
|
||||
// to that peer, maybe punish.
|
||||
if (state.IsInvalid() &&
|
||||
it != mapBlockSource.end() &&
|
||||
State(it->second.first)) {
|
||||
MaybePunishNodeForBlock(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||
}
|
||||
// Check that:
|
||||
// 1. The block is valid
|
||||
@ -1710,7 +1739,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
||||
}
|
||||
} // release cs_main before calling ActivateBestChain
|
||||
if (need_activate_chain) {
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
|
||||
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;
|
||||
CBlockHeader first_invalid_header;
|
||||
if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
|
||||
BlockValidationState state;
|
||||
if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
|
||||
if (state.IsInvalid()) {
|
||||
MaybePunishNode(pfrom.GetId(), state, via_compact_block, "invalid header received");
|
||||
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2265,14 +2293,13 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
|
||||
const CTransactionRef porphanTx = orphan_it->second.tx;
|
||||
const CTransaction& orphanTx = *porphanTx;
|
||||
NodeId fromPeer = orphan_it->second.fromPeer;
|
||||
bool fMissingInputs2 = false;
|
||||
// Use a new CValidationState because orphans come from different peers (and we call
|
||||
// MaybePunishNode based on the source peer from the orphan map, not based on the peer
|
||||
// Use a new TxValidationState because orphans come from different peers (and we call
|
||||
// MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer
|
||||
// that relayed the previous transaction).
|
||||
CValidationState orphan_state;
|
||||
TxValidationState orphan_state;
|
||||
|
||||
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 */)) {
|
||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
||||
RelayTransaction(orphanTx.GetHash(), connman);
|
||||
@ -2286,10 +2313,10 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
|
||||
}
|
||||
EraseOrphanTx(orphanHash);
|
||||
done = true;
|
||||
} else if (!fMissingInputs2) {
|
||||
} else if (orphan_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
|
||||
if (orphan_state.IsInvalid()) {
|
||||
// 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);
|
||||
}
|
||||
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
|
||||
// Probably non-standard or insufficient fee
|
||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
||||
assert(IsTransactionReason(orphan_state.GetReason()));
|
||||
assert(recentRejects);
|
||||
recentRejects->insert(orphanHash);
|
||||
EraseOrphanTx(orphanHash);
|
||||
@ -2523,25 +2549,6 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
|
||||
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)
|
||||
{
|
||||
if (!dstx.IsValidStructure()) {
|
||||
@ -3148,7 +3155,7 @@ void PeerLogicValidation::ProcessMessage(
|
||||
LOCK(cs_most_recent_block);
|
||||
a_recent_block = most_recent_block;
|
||||
}
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
|
||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||
}
|
||||
@ -3364,10 +3371,9 @@ void PeerLogicValidation::ProcessMessage(
|
||||
|
||||
LOCK2(cs_main, g_cs_orphans);
|
||||
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
TxValidationState 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 */)) {
|
||||
// Process custom txes, this changes AlreadyHave to "true"
|
||||
if (nInvType == MSG_DSTX) {
|
||||
@ -3398,7 +3404,7 @@ void PeerLogicValidation::ProcessMessage(
|
||||
// Recursively process any orphan transactions that depended on this one
|
||||
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
|
||||
for (const CTxIn& txin : tx.vin) {
|
||||
@ -3435,7 +3441,6 @@ void PeerLogicValidation::ProcessMessage(
|
||||
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
|
||||
}
|
||||
} else {
|
||||
assert(IsTransactionReason(state.GetReason()));
|
||||
assert(recentRejects);
|
||||
recentRejects->insert(tx.GetHash());
|
||||
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(),
|
||||
pfrom.GetId(),
|
||||
FormatStateMessage(state));
|
||||
MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ false);
|
||||
MaybePunishNodeForTx(pfrom.GetId(), state);
|
||||
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
|
||||
}
|
||||
return;
|
||||
@ -3513,10 +3518,10 @@ void PeerLogicValidation::ProcessMessage(
|
||||
}
|
||||
|
||||
const CBlockIndex *pindex = nullptr;
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -3750,11 +3755,12 @@ void PeerLogicValidation::ProcessMessage(
|
||||
// been run). This is handled below, so just treat this as
|
||||
// though the block was successfully read, and rely on the
|
||||
// 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
|
||||
fBlockRead = true;
|
||||
// mapBlockSource is only used for sending reject messages and DoS scores,
|
||||
// so the race between here and cs_main in ProcessNewBlock is fine.
|
||||
// mapBlockSource is used for potentially punishing peers and
|
||||
// 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
|
||||
// the header only; we should not punish peers if the block turns
|
||||
// out to be invalid.
|
||||
@ -3835,8 +3841,9 @@ void PeerLogicValidation::ProcessMessage(
|
||||
// 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.
|
||||
forceProcessing |= MarkBlockAsReceived(hash);
|
||||
// mapBlockSource is only used for sending reject messages and DoS scores,
|
||||
// so the race between here and cs_main in ProcessNewBlock is fine.
|
||||
// mapBlockSource is only used for punishing peers and setting
|
||||
// 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));
|
||||
}
|
||||
bool fNewBlock = false;
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
/**
|
||||
* Overridden from CValidationInterface.
|
||||
*/
|
||||
void BlockChecked(const CBlock& block, const CValidationState& state) override;
|
||||
void BlockChecked(const CBlock& block, const BlockValidationState& state) override;
|
||||
/**
|
||||
* Overridden from CValidationInterface.
|
||||
*/
|
||||
|
@ -39,18 +39,16 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
|
||||
}
|
||||
if (!node.mempool->exists(hashTx)) {
|
||||
// Transaction is not already in the mempool. Submit it.
|
||||
CValidationState state;
|
||||
bool fMissingInputs;
|
||||
if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx), &fMissingInputs,
|
||||
TxValidationState state;
|
||||
if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx),
|
||||
bypass_limits, max_tx_fee)) {
|
||||
err_string = FormatStateMessage(state);
|
||||
if (state.IsInvalid()) {
|
||||
err_string = FormatStateMessage(state);
|
||||
return TransactionError::MEMPOOL_REJECTED;
|
||||
} else {
|
||||
if (fMissingInputs) {
|
||||
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
||||
return TransactionError::MISSING_INPUTS;
|
||||
}
|
||||
err_string = FormatStateMessage(state);
|
||||
return TransactionError::MEMPOOL_REJECTED;
|
||||
} else {
|
||||
return TransactionError::MEMPOOL_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
/** Fee rate of 0 satoshis per kB */
|
||||
CFeeRate() : nSatoshisPerK(0) { }
|
||||
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...
|
||||
static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
|
||||
}
|
||||
|
@ -130,6 +130,7 @@ public:
|
||||
currentUnit = unit;
|
||||
amountValidator->updateUnit(unit);
|
||||
|
||||
setPlaceholderText(BitcoinUnits::format(currentUnit, m_min_amount, false, BitcoinUnits::separatorAlways));
|
||||
if(valid)
|
||||
setValue(val);
|
||||
else
|
||||
|
@ -1811,7 +1811,7 @@ static UniValue preciousblock(const JSONRPCRequest& request)
|
||||
}
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
::ChainstateActive().PreciousBlock(state, Params(), pblockindex);
|
||||
|
||||
if (!state.IsValid()) {
|
||||
@ -1836,7 +1836,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
|
||||
}.Check(request);
|
||||
|
||||
uint256 hash(ParseHashV(request.params[0], "blockhash"));
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
|
||||
CBlockIndex* pblockindex;
|
||||
{
|
||||
@ -1886,7 +1886,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
|
||||
::ChainstateActive().ResetBlockFailureFlags(pblockindex);
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
::ChainstateActive().ActivateBestChain(state, Params());
|
||||
|
||||
if (!state.IsValid()) {
|
||||
|
@ -326,7 +326,7 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const CMu
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
if (!CheckSpecialTx(CTransaction(tx), ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) {
|
||||
throw std::runtime_error(FormatStateMessage(state));
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ static UniValue generateblock(const JSONRPCRequest& request)
|
||||
{
|
||||
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)) {
|
||||
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
|
||||
static UniValue BIP22ValidationResult(const CValidationState& state)
|
||||
static UniValue BIP22ValidationResult(const BlockValidationState& state)
|
||||
{
|
||||
if (state.IsValid())
|
||||
return NullUniValue;
|
||||
@ -670,7 +670,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||
// TestBlockValidity only supports blocks built on the current Tip
|
||||
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
||||
return "inconclusive-not-best-prevblk";
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true);
|
||||
return BIP22ValidationResult(state);
|
||||
}
|
||||
@ -951,12 +951,12 @@ class submitblock_StateCatcher : public CValidationInterface
|
||||
public:
|
||||
uint256 hash;
|
||||
bool found;
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
|
||||
explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
|
||||
|
||||
protected:
|
||||
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
|
||||
void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override {
|
||||
if (block.GetHash() != hash)
|
||||
return;
|
||||
found = true;
|
||||
@ -1046,8 +1046,8 @@ static UniValue submitheader(const JSONRPCRequest& request)
|
||||
}
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params(), /* ppindex */ nullptr, /* first_invalid */ nullptr);
|
||||
BlockValidationState state;
|
||||
EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params());
|
||||
if (state.IsValid()) return NullUniValue;
|
||||
if (state.IsError()) {
|
||||
throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state));
|
||||
|
@ -918,20 +918,21 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
||||
UniValue result_0(UniValue::VOBJ);
|
||||
result_0.pushKV("txid", tx_hash.GetHex());
|
||||
|
||||
CValidationState state;
|
||||
bool missing_inputs;
|
||||
TxValidationState state;
|
||||
bool test_accept_res;
|
||||
{
|
||||
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);
|
||||
}
|
||||
result_0.pushKV("allowed", test_accept_res);
|
||||
if (!test_accept_res) {
|
||||
if (state.IsInvalid()) {
|
||||
result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
|
||||
} else if (missing_inputs) {
|
||||
result_0.pushKV("reject-reason", "missing-inputs");
|
||||
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
||||
result_0.pushKV("reject-reason", "missing-inputs");
|
||||
} else {
|
||||
result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
|
||||
}
|
||||
} else {
|
||||
result_0.pushKV("reject-reason", state.GetRejectReason());
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <util/spanparsing.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/system.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
#include <memory>
|
||||
#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. */
|
||||
class AddressDescriptor final : public DescriptorImpl
|
||||
{
|
||||
const CTxDestination m_destination;
|
||||
protected:
|
||||
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:
|
||||
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
|
||||
bool IsSolvable() const final { return false; }
|
||||
@ -576,7 +568,7 @@ class RawDescriptor final : public DescriptorImpl
|
||||
const CScript m_script;
|
||||
protected:
|
||||
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:
|
||||
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
|
||||
bool IsSolvable() const final { return false; }
|
||||
@ -586,9 +578,9 @@ public:
|
||||
class PKDescriptor final : public DescriptorImpl
|
||||
{
|
||||
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:
|
||||
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. */
|
||||
@ -599,10 +591,10 @@ protected:
|
||||
{
|
||||
CKeyID id = keys[0].GetID();
|
||||
out.pubkeys.emplace(id, keys[0]);
|
||||
return Singleton(GetScriptForDestination(PKHash(id)));
|
||||
return Vector(GetScriptForDestination(PKHash(id)));
|
||||
}
|
||||
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 */
|
||||
@ -616,9 +608,9 @@ protected:
|
||||
if (m_sorted) {
|
||||
std::vector<CPubKey> sorted_keys(keys);
|
||||
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:
|
||||
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
|
||||
{
|
||||
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:
|
||||
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
|
||||
};
|
||||
@ -653,7 +645,7 @@ protected:
|
||||
}
|
||||
|
||||
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") {}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -118,22 +118,6 @@ static void RunTest(const TestVector &test) {
|
||||
}
|
||||
key = keyNew;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,8 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
|
||||
block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
|
||||
CBlockHeader header = block->GetBlockHeader();
|
||||
|
||||
CValidationState state;
|
||||
if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
|
||||
BlockValidationState state;
|
||||
if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// into account
|
||||
auto tx2 = MalleateProTxPayout<CProRegTx>(tx);
|
||||
CValidationState dummyState;
|
||||
TxValidationState dummy_state;
|
||||
// Technically, the payload is still valid...
|
||||
{
|
||||
LOCK(cs_main);
|
||||
BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true));
|
||||
BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::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(), dummy_state, ::ChainstateActive().CoinsTip(), true));
|
||||
}
|
||||
// But the signature should not verify anymore
|
||||
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);
|
||||
// check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx
|
||||
auto tx2 = MalleateProTxPayout<CProUpRegTx>(tx);
|
||||
CValidationState dummyState;
|
||||
TxValidationState dummy_state;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true));
|
||||
BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::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(), dummy_state, ::ChainstateActive().CoinsTip(), true));
|
||||
}
|
||||
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
|
||||
BOOST_ASSERT(!CheckTransactionSignature(*(setup.m_node.mempool), tx2));
|
||||
|
@ -36,17 +36,17 @@ FUZZ_TARGET_INIT(block, initialize_block)
|
||||
return;
|
||||
}
|
||||
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);
|
||||
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("");
|
||||
CValidationState validation_state_pow;
|
||||
BlockValidationState validation_state_pow;
|
||||
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());
|
||||
CValidationState validation_state_merkle;
|
||||
BlockValidationState validation_state_merkle;
|
||||
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());
|
||||
CValidationState validation_state_none;
|
||||
BlockValidationState validation_state_none;
|
||||
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());
|
||||
if (valid_incl_pow_and_merkle) {
|
||||
|
@ -223,12 +223,12 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
|
||||
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
|
||||
},
|
||||
[&] {
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
CAmount tx_fee_out;
|
||||
const CTransaction transaction{random_mutable_transaction};
|
||||
if (ContainsSpentInput(transaction, coins_view_cache)) {
|
||||
// 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;
|
||||
}
|
||||
try {
|
||||
|
@ -60,7 +60,7 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
|
||||
return;
|
||||
}
|
||||
|
||||
CValidationState state_with_dupe_check;
|
||||
TxValidationState state_with_dupe_check;
|
||||
(void)CheckTransaction(tx, state_with_dupe_check);
|
||||
|
||||
std::string reason;
|
||||
|
@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(findCommonAncestor)
|
||||
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
||||
auto* orig_tip = active.Tip();
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
ChainstateActive().InvalidateBlock(state, Params(), active.Tip());
|
||||
}
|
||||
BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10);
|
||||
|
@ -536,7 +536,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
|
||||
} // unlock cs_main while calling InvalidateBlock
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip()));
|
||||
|
||||
SetMockTime(0);
|
||||
|
@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
||||
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream >> tx;
|
||||
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
|
||||
BOOST_CHECK(state.IsValid());
|
||||
|
||||
|
@ -18,15 +18,15 @@
|
||||
#include <vector>
|
||||
|
||||
|
||||
bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state)
|
||||
bool VerifyMNHFTx(const CTransaction& tx, TxValidationState& state)
|
||||
{
|
||||
MNHFTxPayload 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) {
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version");
|
||||
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version");
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests)
|
||||
BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash));
|
||||
|
||||
const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver);
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state));
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||
CTransaction tx(deserialize, stream);
|
||||
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
||||
BOOST_CHECK(state.IsValid());
|
||||
|
||||
@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||
CTransaction tx(deserialize, stream);
|
||||
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
fValid = CheckTransaction(tx, state) && state.IsValid();
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
||||
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
||||
CMutableTransaction tx;
|
||||
stream >> tx;
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
||||
|
||||
// Check that duplicate txins fail
|
||||
|
@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
||||
|
||||
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
|
||||
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
@ -39,7 +39,6 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
||||
BOOST_CHECK_EQUAL(
|
||||
false,
|
||||
AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx),
|
||||
nullptr /* pfMissingInputs */,
|
||||
true /* bypass_limits */,
|
||||
0 /* nAbsurdFee */));
|
||||
|
||||
@ -49,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
||||
// Check that the validation state reflects the unsuccessful attempt.
|
||||
BOOST_CHECK(state.IsInvalid());
|
||||
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
|
||||
BOOST_CHECK(state.GetReason() == ValidationInvalidReason::CONSENSUS);
|
||||
BOOST_CHECK(state.GetResult() == TxValidationResult::TX_CONSENSUS);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#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)
|
||||
|
||||
@ -27,8 +27,8 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
||||
const auto ToMemPool = [this](const CMutableTransaction& tx) {
|
||||
LOCK(cs_main);
|
||||
|
||||
CValidationState state;
|
||||
return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */,
|
||||
TxValidationState validationState;
|
||||
return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, validationState, MakeTransactionRef(tx),
|
||||
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
|
||||
// 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) {
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
// Filter out incompatible flag choices
|
||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
||||
// CLEANSTACK requires P2SH, see VerifyScript() in
|
||||
@ -193,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
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));
|
||||
@ -262,7 +262,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
||||
|
||||
// Make it valid, and check again
|
||||
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
PrecomputedTransactionData txdata;
|
||||
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
|
||||
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
PrecomputedTransactionData txdata;
|
||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
|
||||
m_node.connman->Init(options);
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!::ChainstateActive().ActivateBestChain(state, chainparams)) {
|
||||
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)) {
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!CalcCbTxMerkleRootMNList(block, ::ChainActive().Tip(), cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
|
||||
}
|
||||
|
||||
bool ignored;
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
std::vector<CBlockHeader> headers;
|
||||
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
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
for (const auto& tx : txs) {
|
||||
BOOST_REQUIRE(AcceptToMemoryPool(
|
||||
::ChainstateActive(),
|
||||
*m_node.mempool,
|
||||
state,
|
||||
tx,
|
||||
/* pfMissingInputs */ &ignored,
|
||||
/* bypass_limits */ false,
|
||||
/* nAbsurdFee */ 0));
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
|
||||
WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23));
|
||||
// Unlike c1, which doesn't have any blocks. Gets us different tip, height.
|
||||
c2.LoadGenesisBlock(chainparams);
|
||||
CValidationState _;
|
||||
BOOST_CHECK(c2.ActivateBestChain(_, chainparams, nullptr));
|
||||
BlockValidationState dummy_state;
|
||||
BOOST_CHECK(c2.ActivateBestChain(dummy_state, chainparams, nullptr));
|
||||
|
||||
BOOST_CHECK(manager.IsSnapshotActive());
|
||||
BOOST_CHECK(!manager.IsSnapshotValidated());
|
||||
|
@ -1023,9 +1023,9 @@ void CTxMemPool::clear()
|
||||
|
||||
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;
|
||||
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);
|
||||
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) {
|
||||
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
|
||||
|
@ -343,8 +343,11 @@ struct TxMempoolInfo
|
||||
/** Time the transaction entered the mempool. */
|
||||
std::chrono::seconds m_time;
|
||||
|
||||
/** Feerate of the transaction. */
|
||||
CFeeRate feeRate;
|
||||
/** Fee of the transaction. */
|
||||
CAmount fee;
|
||||
|
||||
/** Virtual size of the transaction. */
|
||||
size_t vsize;
|
||||
|
||||
/** The fee delta. */
|
||||
int64_t nFeeDelta;
|
||||
|
@ -8,11 +8,10 @@
|
||||
#include <consensus/validation.h>
|
||||
#include <tinyformat.h>
|
||||
|
||||
/** Convert CValidationState to a human-readable message for logging */
|
||||
std::string FormatStateMessage(const CValidationState &state)
|
||||
/** Convert ValidationState to a human-readable message for logging */
|
||||
std::string FormatStateMessage(const ValidationState &state)
|
||||
{
|
||||
return strprintf("%s%s (code %i)",
|
||||
return strprintf("%s%s",
|
||||
state.GetRejectReason(),
|
||||
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
|
||||
state.GetRejectCode());
|
||||
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage());
|
||||
}
|
||||
|
@ -8,9 +8,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
class CValidationState;
|
||||
class ValidationState;
|
||||
|
||||
/** Convert CValidationState to a human-readable message for logging */
|
||||
std::string FormatStateMessage(const CValidationState &state);
|
||||
/** Convert ValidationState to a human-readable message for logging */
|
||||
std::string FormatStateMessage(const ValidationState &state);
|
||||
|
||||
#endif // BITCOIN_UTIL_VALIDATION_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,7 @@ class CQuorumBlockProcessor;
|
||||
class CEvoDB;
|
||||
|
||||
class CChainState;
|
||||
class BlockValidationState;
|
||||
class CBlockIndex;
|
||||
class CBlockTreeDB;
|
||||
class CBlockUndo;
|
||||
@ -52,7 +53,7 @@ class CInv;
|
||||
class CConnman;
|
||||
class CScriptCheck;
|
||||
class CTxMemPool;
|
||||
class CValidationState;
|
||||
class TxValidationState;
|
||||
class ChainstateManager;
|
||||
struct PrecomputedTransactionData;
|
||||
struct ChainTxData;
|
||||
@ -215,8 +216,8 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
|
||||
void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
|
||||
|
||||
/** (try to) add transaction to memory pool */
|
||||
bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
|
||||
bool* pfMissingInputs, bool bypass_limits,
|
||||
bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||
bool bypass_limits,
|
||||
const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
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 */
|
||||
|
||||
/** 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) */
|
||||
bool TestBlockValidity(CValidationState& state,
|
||||
bool TestBlockValidity(BlockValidationState& state,
|
||||
llmq::CChainLocksHandler& clhandler,
|
||||
CEvoDB& evoDb,
|
||||
const CChainParams& chainparams,
|
||||
@ -454,7 +455,7 @@ public:
|
||||
*/
|
||||
bool AcceptBlockHeader(
|
||||
const CBlockHeader& block,
|
||||
CValidationState& state,
|
||||
BlockValidationState& state,
|
||||
const CChainParams& chainparams,
|
||||
CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
@ -681,7 +682,7 @@ public:
|
||||
*/
|
||||
bool FlushStateToDisk(
|
||||
const CChainParams& chainparams,
|
||||
CValidationState &state,
|
||||
BlockValidationState &state,
|
||||
FlushStateMode mode,
|
||||
int nManualPruneHeight = 0);
|
||||
|
||||
@ -708,29 +709,29 @@ public:
|
||||
* @returns true unless a system error occurred
|
||||
*/
|
||||
bool ActivateBestChain(
|
||||
CValidationState& state,
|
||||
BlockValidationState& state,
|
||||
const CChainParams& chainparams,
|
||||
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:
|
||||
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.
|
||||
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:
|
||||
/** Mark a block as precious and reorganize.
|
||||
*
|
||||
* 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. */
|
||||
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. */
|
||||
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. */
|
||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
@ -738,7 +739,7 @@ public:
|
||||
bool ReplayBlocks(const CChainParams& params);
|
||||
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
|
||||
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();
|
||||
|
||||
@ -774,10 +775,10 @@ public:
|
||||
std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
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 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 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(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);
|
||||
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);
|
||||
|
||||
//! 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
|
||||
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] 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
|
||||
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);
|
||||
|
||||
/** 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 */
|
||||
CBlockFileInfo* GetBlockFileInfo(size_t n);
|
||||
|
||||
|
@ -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 CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
|
||||
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 *)>AcceptedBlockHeader;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,12 @@
|
||||
#include <memory>
|
||||
|
||||
extern CCriticalSection cs_main;
|
||||
class BlockValidationState;
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
struct CBlockLocator;
|
||||
class CConnman;
|
||||
class CValidationInterface;
|
||||
class CValidationState;
|
||||
class CGovernanceVote;
|
||||
class CGovernanceObject;
|
||||
class CDeterministicMNList;
|
||||
@ -185,11 +185,11 @@ protected:
|
||||
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* 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 NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman);
|
||||
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>&);
|
||||
};
|
||||
|
||||
|
@ -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). "
|
||||
"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);
|
||||
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);
|
||||
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);
|
||||
|
@ -2315,7 +2315,7 @@ static UniValue settxfee(const JSONRPCRequest& request)
|
||||
CAmount nAmount = AmountFromValue(request.params[0]);
|
||||
CFeeRate tx_fee_rate(nAmount, 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
|
||||
} 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()));
|
||||
|
@ -178,6 +178,7 @@ public:
|
||||
int nChangePosRet = -1;
|
||||
bilingual_str strError;
|
||||
CCoinControl coinControl;
|
||||
coinControl.m_feerate = CFeeRate(1000);
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
BOOST_CHECK(reserveDest.GetReservedDestination(tallyItem.txdest, false));
|
||||
|
@ -38,6 +38,10 @@ extern RecursiveMutex cs_wallets;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
|
||||
|
||||
namespace {
|
||||
constexpr CAmount fallbackFee = 1000;
|
||||
} // anonymous namespace
|
||||
|
||||
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
|
||||
{
|
||||
DatabaseOptions options;
|
||||
@ -869,7 +873,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
coinControl.Select(GetCoins({{100000, false}})[0]);
|
||||
|
||||
// Start with fallback feerate
|
||||
runTest(1, DEFAULT_FALLBACK_FEE, {
|
||||
runTest(1, fallbackFee, {
|
||||
{0, {true, ChangeTest::ChangeExpected}},
|
||||
{1, {true, ChangeTest::ChangeExpected}},
|
||||
{2, {true, ChangeTest::ChangeExpected}},
|
||||
@ -886,7 +890,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
{13, {false, ChangeTest::Skip}}
|
||||
});
|
||||
// Now with 100x fallback feerate
|
||||
runTest(2, DEFAULT_FALLBACK_FEE * 100, {
|
||||
runTest(2, fallbackFee * 100, {
|
||||
{0, {true, ChangeTest::ChangeExpected}},
|
||||
{1, {false, ChangeTest::Skip}},
|
||||
{2, {true, ChangeTest::ChangeExpected}},
|
||||
@ -912,7 +916,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
}
|
||||
|
||||
// Start with fallback feerate
|
||||
runTest(3, DEFAULT_FALLBACK_FEE, {
|
||||
runTest(3, fallbackFee, {
|
||||
{0, {true, ChangeTest::ChangeExpected}},
|
||||
{1, {false, ChangeTest::Skip}},
|
||||
{2, {true, ChangeTest::ChangeExpected}},
|
||||
@ -929,7 +933,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
{13, {false, ChangeTest::Skip}}
|
||||
});
|
||||
// Now with 100x fallback feerate
|
||||
runTest(4, DEFAULT_FALLBACK_FEE * 100, {
|
||||
runTest(4, fallbackFee * 100, {
|
||||
{0, {true, ChangeTest::ChangeExpected}},
|
||||
{1, {false, ChangeTest::Skip}},
|
||||
{2, {true, ChangeTest::ChangeExpected}},
|
||||
@ -958,7 +962,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
}
|
||||
|
||||
// Start with fallback feerate
|
||||
runTest(5, DEFAULT_FALLBACK_FEE, {
|
||||
runTest(5, fallbackFee, {
|
||||
{0, {true, ChangeTest::ChangeExpected}},
|
||||
{1, {false, ChangeTest::Skip}},
|
||||
{2, {true, ChangeTest::ChangeExpected}},
|
||||
@ -975,7 +979,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
{13, {false, ChangeTest::Skip}}
|
||||
});
|
||||
// Now with 100x fallback feerate
|
||||
runTest(6, DEFAULT_FALLBACK_FEE * 100, {
|
||||
runTest(6, fallbackFee * 100, {
|
||||
{0, {false, ChangeTest::Skip}},
|
||||
{1, {false, ChangeTest::Skip}},
|
||||
{2, {false, ChangeTest::Skip}},
|
||||
@ -996,6 +1000,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
// which inputs to use
|
||||
{
|
||||
coinControl.SetNull();
|
||||
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||
auto setCoins = GetCoins({{1000, false}, {1000, false}, {1000, false}, {1000, false}, {1000, false},
|
||||
{1100, false}, {1200, false}, {1300, false}, {1400, false}, {1500, 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
|
||||
{
|
||||
coinControl.SetNull();
|
||||
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||
coinControl.Select(GetCoins({{100000, false}})[0]);
|
||||
|
||||
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
|
||||
{
|
||||
coinControl.SetNull();
|
||||
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||
// First try to send something without any coins available
|
||||
{
|
||||
// Lock all other coins
|
||||
@ -1090,6 +1097,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
||||
};
|
||||
|
||||
coinControl.SetNull();
|
||||
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||
coinControl.Select(GetCoins({{100 * COIN, false}})[0]);
|
||||
|
||||
BOOST_CHECK(CreateTransaction({{-5000, false}}, strAmountNotNegative, false));
|
||||
|
@ -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_allow_fallback_fee = Params().IsTestChain();
|
||||
if (gArgs.IsArgSet("-fallbackfee")) {
|
||||
std::optional<CAmount> fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", ""));
|
||||
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."));
|
||||
}
|
||||
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")) {
|
||||
std::optional<CAmount> discard_fee = ParseMoney(gArgs.GetArg("-discardfee", ""));
|
||||
if (!discard_fee) {
|
||||
|
@ -67,7 +67,7 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
|
||||
//! -paytxfee default
|
||||
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
|
||||
//! -fallbackfee default
|
||||
static const CAmount DEFAULT_FALLBACK_FEE = 1000;
|
||||
static const CAmount DEFAULT_FALLBACK_FEE = 0;
|
||||
//! -discardfee default
|
||||
static const CAmount DEFAULT_DISCARD_FEE = 10000;
|
||||
//! -mintxfee default
|
||||
@ -1070,7 +1070,7 @@ public:
|
||||
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
|
||||
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
|
||||
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
|
||||
/**
|
||||
* If fee estimation does not have enough data to provide estimates, use this fee instead.
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include <wallet/walletdb.h>
|
||||
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <key_io.h>
|
||||
#include <fs.h>
|
||||
#include <governance/object.h>
|
||||
@ -255,8 +253,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
ssKey >> hash;
|
||||
CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
|
||||
ssValue >> wtx;
|
||||
CValidationState state;
|
||||
if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
|
||||
if (wtx.GetHash() != hash)
|
||||
return false;
|
||||
|
||||
// Undo serialize changes in 31600
|
||||
|
@ -22,7 +22,7 @@ SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift
|
||||
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
||||
|
||||
# RPC error for non-BIP68 final transactions
|
||||
NOT_FINAL_ERROR = "non-BIP68-final (code 64)"
|
||||
NOT_FINAL_ERROR = "non-BIP68-final"
|
||||
|
||||
class BIP68Test(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
|
@ -130,7 +130,7 @@ class BIP65Test(BitcoinTestFramework):
|
||||
|
||||
# First we show that this tx is valid except for CLTV by getting it
|
||||
# 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.
|
||||
block.vtx.append(spendtx)
|
||||
|
@ -112,7 +112,7 @@ class BIP66Test(BitcoinTestFramework):
|
||||
|
||||
# First we show that this tx is valid except for DERSIG by getting it
|
||||
# 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.
|
||||
block.vtx.append(spendtx)
|
||||
|
@ -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 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
|
||||
cl_block = self.create_block(self.nodes[0])
|
||||
|
@ -20,7 +20,7 @@ from test_framework.test_framework import BitcoinTestFramework
|
||||
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):
|
||||
scriptSig = CScript(tx.vin[0].scriptSig)
|
||||
|
@ -77,7 +77,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
node.generate(1)
|
||||
self.mempool_size = 0
|
||||
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],
|
||||
)
|
||||
|
||||
@ -115,7 +115,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
node.sendrawtransaction(hexstring=raw_tx_0)
|
||||
self.mempool_size += 1
|
||||
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],
|
||||
)
|
||||
|
||||
@ -128,7 +128,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
txid_0_reject = tx.rehash()
|
||||
self.check_mempool_result(
|
||||
# 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],
|
||||
)
|
||||
|
||||
@ -140,7 +140,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
|
||||
# skip re-signing the tx
|
||||
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()],
|
||||
maxfeerate=0,
|
||||
)
|
||||
@ -199,7 +199,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
# 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'])))
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -207,7 +207,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
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()))
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -215,7 +215,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vout[0].nValue *= -1
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -224,7 +224,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vout[0].nValue = MAX_MONEY + 1
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -233,7 +233,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.vout = [tx.vout[0]] * 2
|
||||
tx.vout[0].nValue = MAX_MONEY
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -241,7 +241,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vin = [tx.vin[0]] * 2
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -250,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
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)))
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -258,13 +258,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.nVersion = 4 # A version currently non-standard
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
@ -273,25 +273,25 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
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)
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
||||
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()],
|
||||
)
|
||||
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
|
||||
tx.vout = [output_p2sh_burn] * num_scripts
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vout[0] = output_p2sh_burn
|
||||
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
|
||||
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()],
|
||||
)
|
||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
||||
tx.vout = [tx.vout[0]] * 2
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -322,7 +322,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored
|
||||
tx.nLockTime = node.getblockcount() + 1
|
||||
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()],
|
||||
)
|
||||
|
||||
@ -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
|
||||
# Can skip re-signing the tx because of early rejection
|
||||
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()],
|
||||
maxfeerate=0,
|
||||
)
|
||||
|
@ -151,7 +151,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)
|
||||
|
||||
# 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 #
|
||||
@ -388,7 +388,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
# Thus, testmempoolaccept should reject
|
||||
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
|
||||
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
|
||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
||||
# and the following calls should both succeed
|
||||
@ -412,7 +412,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
# Thus, testmempoolaccept should reject
|
||||
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
|
||||
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
|
||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
|
||||
# and the following calls should both succeed
|
||||
|
@ -340,6 +340,7 @@ def initialize_datadir(dirname, n, chain):
|
||||
f.write("[{}]\n".format(chain_name_conf_section))
|
||||
f.write("port=" + str(p2p_port(n)) + "\n")
|
||||
f.write("rpcport=" + str(rpc_port(n)) + "\n")
|
||||
f.write("fallbackfee=0.00001\n")
|
||||
f.write("server=1\n")
|
||||
f.write("keypool=1\n")
|
||||
f.write("discover=0\n")
|
||||
|
Loading…
Reference in New Issue
Block a user