mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +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/vector.h \
|
||||||
util/url.h \
|
util/url.h \
|
||||||
util/validation.h \
|
util/validation.h \
|
||||||
|
util/vector.h \
|
||||||
validation.h \
|
validation.h \
|
||||||
validationinterface.h \
|
validationinterface.h \
|
||||||
versionbits.h \
|
versionbits.h \
|
||||||
|
@ -40,8 +40,8 @@ static void AssembleBlock(benchmark::Bench& bench)
|
|||||||
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
||||||
|
|
||||||
for (const auto& txr : txs) {
|
for (const auto& txr : txs) {
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, nullptr /* pfMissingInputs */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
|
bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, false /* bypass_limits */, /* nAbsurdFee */ 0)};
|
||||||
assert(ret);
|
assert(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
|
|||||||
bool rewound = stream.Rewind(benchmark::data::block813851.size());
|
bool rewound = stream.Rewind(benchmark::data::block813851.size());
|
||||||
assert(rewound);
|
assert(rewound);
|
||||||
|
|
||||||
CValidationState validationState;
|
BlockValidationState validationState;
|
||||||
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), block.GetBlockTime());
|
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), block.GetBlockTime());
|
||||||
assert(checked);
|
assert(checked);
|
||||||
});
|
});
|
||||||
|
@ -56,7 +56,7 @@ static void DuplicateInputs(benchmark::Bench& bench)
|
|||||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||||
|
|
||||||
bench.minEpochIterations(10).run([&] {
|
bench.minEpochIterations(10).run([&] {
|
||||||
CValidationState cvstate{};
|
BlockValidationState cvstate{};
|
||||||
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
||||||
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
||||||
});
|
});
|
||||||
|
@ -198,13 +198,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
|
|||||||
if (vtx_missing.size() != tx_missing_offset)
|
if (vtx_missing.size() != tx_missing_offset)
|
||||||
return READ_STATUS_INVALID;
|
return READ_STATUS_INVALID;
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!CheckBlock(block, state, Params().GetConsensus())) {
|
if (!CheckBlock(block, state, Params().GetConsensus())) {
|
||||||
// TODO: We really want to just check merkle tree manually here,
|
// TODO: We really want to just check merkle tree manually here,
|
||||||
// but that is expensive, and CheckBlock caches a block's
|
// but that is expensive, and CheckBlock caches a block's
|
||||||
// "checked-status" (in the CBlock?). CBlock should be able to
|
// "checked-status" (in the CBlock?). CBlock should be able to
|
||||||
// check its own merkle root and cache that check.
|
// check its own merkle root and cache that check.
|
||||||
if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED)
|
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED)
|
||||||
return READ_STATUS_FAILED; // Possible Short ID collision
|
return READ_STATUS_FAILED; // Possible Short ID collision
|
||||||
return READ_STATUS_CHECKBLOCK_FAILED;
|
return READ_STATUS_CHECKBLOCK_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -351,8 +351,8 @@ bool CCoinJoin::IsCollateralValid(CTxMemPool& mempool, const CTransaction& txCol
|
|||||||
|
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState validationState;
|
TxValidationState validationState;
|
||||||
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*pfMissingInputs=*/nullptr, /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) {
|
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) {
|
||||||
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n");
|
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -320,9 +320,9 @@ void CCoinJoinServer::CommitFinalTransaction()
|
|||||||
{
|
{
|
||||||
// See if the transaction is valid
|
// See if the transaction is valid
|
||||||
TRY_LOCK(cs_main, lockMain);
|
TRY_LOCK(cs_main, lockMain);
|
||||||
CValidationState validationState;
|
TxValidationState validationState;
|
||||||
mempool.PrioritiseTransaction(hashTx, 0.1 * COIN);
|
mempool.PrioritiseTransaction(hashTx, 0.1 * COIN);
|
||||||
if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) {
|
if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) {
|
||||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
|
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
|
||||||
WITH_LOCK(cs_coinjoin, SetNull());
|
WITH_LOCK(cs_coinjoin, SetNull());
|
||||||
// not much we can do in this case, just notify clients
|
// not much we can do in this case, just notify clients
|
||||||
@ -454,8 +454,8 @@ void CCoinJoinServer::ChargeRandomFees() const
|
|||||||
void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const
|
void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState validationState;
|
TxValidationState validationState;
|
||||||
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__);
|
LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__);
|
||||||
} else {
|
} else {
|
||||||
connman.RelayTransaction(*txref);
|
connman.RelayTransaction(*txref);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <consensus/validation.h>
|
#include <consensus/validation.h>
|
||||||
|
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
|
||||||
{
|
{
|
||||||
bool allowEmptyTxInOut = false;
|
bool allowEmptyTxInOut = false;
|
||||||
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
@ -19,25 +19,25 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
|
|
||||||
// Basic checks that don't depend on any context
|
// Basic checks that don't depend on any context
|
||||||
if (!allowEmptyTxInOut && tx.vin.empty())
|
if (!allowEmptyTxInOut && tx.vin.empty())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vin-empty");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vin-empty");
|
||||||
if (!allowEmptyTxInOut && tx.vout.empty())
|
if (!allowEmptyTxInOut && tx.vout.empty())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-empty");
|
||||||
// Size limits
|
// Size limits
|
||||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-oversize");
|
||||||
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-payload-oversize");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-payload-oversize");
|
||||||
|
|
||||||
// Check for negative or overflow output values (see CVE-2010-5139)
|
// Check for negative or overflow output values (see CVE-2010-5139)
|
||||||
CAmount nValueOut = 0;
|
CAmount nValueOut = 0;
|
||||||
for (const auto& txout : tx.vout) {
|
for (const auto& txout : tx.vout) {
|
||||||
if (txout.nValue < 0)
|
if (txout.nValue < 0)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-negative");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-negative");
|
||||||
if (txout.nValue > MAX_MONEY)
|
if (txout.nValue > MAX_MONEY)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-toolarge");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-toolarge");
|
||||||
nValueOut += txout.nValue;
|
nValueOut += txout.nValue;
|
||||||
if (!MoneyRange(nValueOut))
|
if (!MoneyRange(nValueOut))
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate inputs (see CVE-2018-17144)
|
// Check for duplicate inputs (see CVE-2018-17144)
|
||||||
@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
std::set<COutPoint> vInOutPoints;
|
std::set<COutPoint> vInOutPoints;
|
||||||
for (const auto& txin : tx.vin) {
|
for (const auto& txin : tx.vin) {
|
||||||
if (!vInOutPoints.insert(txin.prevout).second)
|
if (!vInOutPoints.insert(txin.prevout).second)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputs-duplicate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.IsCoinBase()) {
|
if (tx.IsCoinBase()) {
|
||||||
@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
minCbSize = 1;
|
minCbSize = 1;
|
||||||
}
|
}
|
||||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cb-length");
|
||||||
} else {
|
} else {
|
||||||
for (const auto& txin : tx.vin)
|
for (const auto& txin : tx.vin)
|
||||||
if (txin.prevout.IsNull())
|
if (txin.prevout.IsNull())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-prevout-null");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-prevout-null");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
/** Context-independent validity checks */
|
/** Context-independent validity checks */
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
bool CheckTransaction(const CTransaction& tx, TxValidationState& state);
|
||||||
|
|
||||||
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
|
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
|
||||||
|
@ -158,11 +158,12 @@ unsigned int GetTransactionSigOpCount(const CTransaction& tx, const CCoinsViewCa
|
|||||||
return nSigOps;
|
return nSigOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
|
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
|
||||||
{
|
{
|
||||||
// are the actual inputs available?
|
// are the actual inputs available?
|
||||||
if (!inputs.HaveInputs(tx)) {
|
if (!inputs.HaveInputs(tx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", strprintf("%s: inputs missing/spent", __func__));
|
return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",
|
||||||
|
strprintf("%s: inputs missing/spent", __func__));
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount nValueIn = 0;
|
CAmount nValueIn = 0;
|
||||||
@ -173,25 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
|||||||
|
|
||||||
// If prev is coinbase, check that it's matured
|
// If prev is coinbase, check that it's matured
|
||||||
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
|
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
|
||||||
|
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for negative or overflow input values
|
// Check for negative or overflow input values
|
||||||
nValueIn += coin.out.nValue;
|
nValueIn += coin.out.nValue;
|
||||||
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CAmount value_out = tx.GetValueOut();
|
const CAmount value_out = tx.GetValueOut();
|
||||||
if (nValueIn < value_out) {
|
if (nValueIn < value_out) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout", strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
|
||||||
|
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tally transaction fees
|
// Tally transaction fees
|
||||||
const CAmount txfee_aux = nValueIn - value_out;
|
const CAmount txfee_aux = nValueIn - value_out;
|
||||||
if (!MoneyRange(txfee_aux)) {
|
if (!MoneyRange(txfee_aux)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
|
||||||
}
|
}
|
||||||
|
|
||||||
txfee = txfee_aux;
|
txfee = txfee_aux;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CCoinsViewCache;
|
class CCoinsViewCache;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
/** Transaction validation functions */
|
/** Transaction validation functions */
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ namespace Consensus {
|
|||||||
* @param[out] txfee Set to the transaction fee if successful.
|
* @param[out] txfee Set to the transaction fee if successful.
|
||||||
* Preconditions: tx.IsCoinBase() is false.
|
* Preconditions: tx.IsCoinBase() is false.
|
||||||
*/
|
*/
|
||||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
|
bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
|
||||||
} // namespace Consensus
|
} // namespace Consensus
|
||||||
|
|
||||||
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
||||||
|
@ -8,31 +8,47 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/** "reject" message codes */
|
/** A "reason" why a transaction was invalid, suitable for determining whether the
|
||||||
static const unsigned char REJECT_MALFORMED = 0x01;
|
* provider of the transaction should be banned/ignored/disconnected/etc.
|
||||||
static const unsigned char REJECT_INVALID = 0x10;
|
|
||||||
static const unsigned char REJECT_OBSOLETE = 0x11;
|
|
||||||
static const unsigned char REJECT_DUPLICATE = 0x12;
|
|
||||||
static const unsigned char REJECT_NONSTANDARD = 0x40;
|
|
||||||
// static const unsigned char REJECT_DUST = 0x41; // part of BIP 61
|
|
||||||
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
|
|
||||||
static const unsigned char REJECT_CHECKPOINT = 0x43;
|
|
||||||
|
|
||||||
/** A "reason" why something was invalid, suitable for determining whether the
|
|
||||||
* provider of the object should be banned/ignored/disconnected/etc.
|
|
||||||
* These are much more granular than the rejection codes, which may be more
|
|
||||||
* useful for some other use-cases.
|
|
||||||
*/
|
*/
|
||||||
enum class ValidationInvalidReason {
|
enum class TxValidationResult {
|
||||||
// txn and blocks:
|
TX_RESULT_UNSET, //!< initial value. Tx has not yet been rejected
|
||||||
NONE, //!< not actually invalid
|
TX_CONSENSUS, //!< invalid by consensus rules
|
||||||
CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
|
|
||||||
/**
|
/**
|
||||||
* Invalid by a change to consensus rules more recent than some major deployment.
|
* Invalid by a change to consensus rules more recent than some major deployment.
|
||||||
*/
|
*/
|
||||||
RECENT_CONSENSUS_CHANGE,
|
// Only loose txn:
|
||||||
// Only blocks (or headers):
|
TX_RECENT_CONSENSUS_CHANGE,
|
||||||
CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why
|
TX_NOT_STANDARD, //!< didn't meet our local policy rules
|
||||||
|
TX_MISSING_INPUTS, //!< transaction was missing some of its inputs
|
||||||
|
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
|
||||||
|
TX_BAD_SPECIAL, //!< special transaction violates some rules that are not enough for insta-ban
|
||||||
|
/**
|
||||||
|
* Tx already in mempool or conflicts with a tx in the chain
|
||||||
|
* Currently this is only used if the transaction already exists in the mempool or on chain.
|
||||||
|
*/
|
||||||
|
TX_CONFLICT,
|
||||||
|
TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock
|
||||||
|
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A "reason" why a block was invalid, suitable for determining whether the
|
||||||
|
* provider of the block should be banned/ignored/disconnected/etc.
|
||||||
|
* These are much more granular than the rejection codes, which may be more
|
||||||
|
* useful for some other use-cases.
|
||||||
|
*/
|
||||||
|
enum class BlockValidationResult {
|
||||||
|
BLOCK_RESULT_UNSET, //!< initial value. Block has not yet been rejected
|
||||||
|
BLOCK_CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
|
||||||
|
/**
|
||||||
|
* Invalid by a change to consensus rules more recent than SegWit.
|
||||||
|
* Currently unused as there are no such consensus rule changes, and any download
|
||||||
|
* sources realistically need to support SegWit in order to provide useful data,
|
||||||
|
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
|
||||||
|
* is uninteresting.
|
||||||
|
*/
|
||||||
|
BLOCK_RECENT_CONSENSUS_CHANGE,
|
||||||
|
BLOCK_CACHED_INVALID, //!< this block was cached as being invalid and we didn't store the reason why
|
||||||
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
|
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
|
||||||
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
|
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
|
||||||
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
|
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
|
||||||
@ -40,95 +56,78 @@ enum class ValidationInvalidReason {
|
|||||||
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
|
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
|
||||||
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
|
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
|
||||||
BLOCK_CHAINLOCK, //!< the block conflicts with the ChainLock
|
BLOCK_CHAINLOCK, //!< the block conflicts with the ChainLock
|
||||||
// Only loose txn:
|
|
||||||
TX_NOT_STANDARD, //!< didn't meet our local policy rules
|
|
||||||
TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs
|
|
||||||
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
|
|
||||||
TX_BAD_SPECIAL, //!< special transaction violates some rules that are not enough for insta-ban
|
|
||||||
/**
|
|
||||||
* Tx already in mempool or conflicts with a tx in the chain
|
|
||||||
* TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
|
|
||||||
* TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
|
|
||||||
*/
|
|
||||||
TX_CONFLICT,
|
|
||||||
TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock
|
|
||||||
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool IsTransactionReason(ValidationInvalidReason r)
|
|
||||||
{
|
|
||||||
return r == ValidationInvalidReason::NONE ||
|
|
||||||
r == ValidationInvalidReason::CONSENSUS ||
|
|
||||||
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
|
|
||||||
r == ValidationInvalidReason::TX_NOT_STANDARD ||
|
|
||||||
r == ValidationInvalidReason::TX_PREMATURE_SPEND ||
|
|
||||||
r == ValidationInvalidReason::TX_MISSING_INPUTS ||
|
|
||||||
r == ValidationInvalidReason::TX_BAD_SPECIAL ||
|
|
||||||
r == ValidationInvalidReason::TX_CONFLICT ||
|
|
||||||
r == ValidationInvalidReason::TX_CONFLICT_LOCK ||
|
|
||||||
r == ValidationInvalidReason::TX_MEMPOOL_POLICY;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsBlockReason(ValidationInvalidReason r)
|
|
||||||
{
|
|
||||||
return r == ValidationInvalidReason::NONE ||
|
|
||||||
r == ValidationInvalidReason::CONSENSUS ||
|
|
||||||
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
|
|
||||||
r == ValidationInvalidReason::CACHED_INVALID ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_INVALID_HEADER ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_MUTATED ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_MISSING_PREV ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_INVALID_PREV ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_TIME_FUTURE ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_CHECKPOINT ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_CHAINLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Capture information about block/transaction validation */
|
/** Base class for capturing information about block/transaction validation. This is subclassed
|
||||||
class CValidationState {
|
* by TxValidationState and BlockValidationState for validation information on transactions
|
||||||
|
* and blocks respectively. */
|
||||||
|
class ValidationState {
|
||||||
private:
|
private:
|
||||||
enum mode_state {
|
enum mode_state {
|
||||||
MODE_VALID, //!< everything ok
|
MODE_VALID, //!< everything ok
|
||||||
MODE_INVALID, //!< network rule violation (DoS value may be set)
|
MODE_INVALID, //!< network rule violation (DoS value may be set)
|
||||||
MODE_ERROR, //!< run-time error
|
MODE_ERROR, //!< run-time error
|
||||||
} mode;
|
} m_mode;
|
||||||
ValidationInvalidReason m_reason;
|
std::string m_reject_reason;
|
||||||
std::string strRejectReason;
|
std::string m_debug_message;
|
||||||
unsigned int chRejectCode;
|
protected:
|
||||||
std::string strDebugMessage;
|
void Invalid(const std::string &reject_reason="",
|
||||||
public:
|
const std::string &debug_message="")
|
||||||
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {}
|
{
|
||||||
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
|
m_reject_reason = reject_reason;
|
||||||
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
|
m_debug_message = debug_message;
|
||||||
const std::string &strDebugMessageIn="") {
|
if (m_mode != MODE_ERROR) m_mode = MODE_INVALID;
|
||||||
m_reason = reasonIn;
|
|
||||||
chRejectCode = chRejectCodeIn;
|
|
||||||
strRejectReason = strRejectReasonIn;
|
|
||||||
strDebugMessage = strDebugMessageIn;
|
|
||||||
if (mode == MODE_ERROR)
|
|
||||||
return ret;
|
|
||||||
mode = MODE_INVALID;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
bool Error(const std::string& strRejectReasonIn) {
|
public:
|
||||||
if (mode == MODE_VALID)
|
// ValidationState is abstract. Have a pure virtual destructor.
|
||||||
strRejectReason = strRejectReasonIn;
|
virtual ~ValidationState() = 0;
|
||||||
mode = MODE_ERROR;
|
|
||||||
|
ValidationState() : m_mode(MODE_VALID) {}
|
||||||
|
bool Error(const std::string& reject_reason)
|
||||||
|
{
|
||||||
|
if (m_mode == MODE_VALID)
|
||||||
|
m_reject_reason = reject_reason;
|
||||||
|
m_mode = MODE_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool IsValid() const {
|
bool IsValid() const { return m_mode == MODE_VALID; }
|
||||||
return mode == MODE_VALID;
|
bool IsInvalid() const { return m_mode == MODE_INVALID; }
|
||||||
|
bool IsError() const { return m_mode == MODE_ERROR; }
|
||||||
|
std::string GetRejectReason() const { return m_reject_reason; }
|
||||||
|
std::string GetDebugMessage() const { return m_debug_message; }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ValidationState::~ValidationState() {};
|
||||||
|
|
||||||
|
class TxValidationState : public ValidationState {
|
||||||
|
private:
|
||||||
|
TxValidationResult m_result = TxValidationResult::TX_RESULT_UNSET;
|
||||||
|
public:
|
||||||
|
bool Invalid(TxValidationResult result,
|
||||||
|
const std::string &reject_reason="",
|
||||||
|
const std::string &debug_message="")
|
||||||
|
{
|
||||||
|
m_result = result;
|
||||||
|
ValidationState::Invalid(reject_reason, debug_message);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
bool IsInvalid() const {
|
TxValidationResult GetResult() const { return m_result; }
|
||||||
return mode == MODE_INVALID;
|
};
|
||||||
|
|
||||||
|
class BlockValidationState : public ValidationState {
|
||||||
|
private:
|
||||||
|
BlockValidationResult m_result = BlockValidationResult::BLOCK_RESULT_UNSET;
|
||||||
|
public:
|
||||||
|
bool Invalid(BlockValidationResult result,
|
||||||
|
const std::string &reject_reason="",
|
||||||
|
const std::string &debug_message="") {
|
||||||
|
m_result = result;
|
||||||
|
ValidationState::Invalid(reject_reason, debug_message);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
bool IsError() const {
|
BlockValidationResult GetResult() const { return m_result; }
|
||||||
return mode == MODE_ERROR;
|
|
||||||
}
|
|
||||||
ValidationInvalidReason GetReason() const { return m_reason; }
|
|
||||||
unsigned int GetRejectCode() const { return chRejectCode; }
|
|
||||||
std::string GetRejectReason() const { return strRejectReason; }
|
|
||||||
std::string GetDebugMessage() const { return strDebugMessage; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_CONSENSUS_VALIDATION_H
|
#endif // BITCOIN_CONSENSUS_VALIDATION_H
|
||||||
|
@ -15,33 +15,33 @@
|
|||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <consensus/merkle.h>
|
#include <consensus/merkle.h>
|
||||||
|
|
||||||
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_COINBASE) {
|
if (tx.nType != TRANSACTION_COINBASE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tx.IsCoinBase()) {
|
if (!tx.IsCoinBase()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-invalid");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
CCbTx cbTx;
|
CCbTx cbTx;
|
||||||
if (!GetTxPayload(tx, cbTx)) {
|
if (!GetTxPayload(tx, cbTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
|
if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
|
if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-height");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
|
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
|
||||||
if (fDIP0008Active && cbTx.nVersion < 2) {
|
if (fDIP0008Active && cbTx.nVersion < 2) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
|
// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
|
||||||
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, CValidationState& state, const CCoinsViewCache& view)
|
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state, const CCoinsViewCache& view)
|
||||||
{
|
{
|
||||||
if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
|
if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
|
||||||
return true;
|
return true;
|
||||||
@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
|
|
||||||
CCbTx cbTx;
|
CCbTx cbTx;
|
||||||
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
|
int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
|
||||||
@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
|
if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-mnmerkleroot");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
|
int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
|
||||||
@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
|
if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view)
|
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, BlockValidationState& state, const CCoinsViewCache& view)
|
||||||
{
|
{
|
||||||
LOCK(deterministicMNManager->cs);
|
LOCK(deterministicMNManager->cs);
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
|||||||
if (sml == smlCached) {
|
if (sml == smlCached) {
|
||||||
merkleRootRet = merkleRootCached;
|
merkleRootRet = merkleRootCached;
|
||||||
if (mutatedCached) {
|
if (mutatedCached) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-cached-calc-cb-mnmerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-cached-calc-cb-mnmerkleroot");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
|||||||
mutatedCached = mutated;
|
mutatedCached = mutated;
|
||||||
|
|
||||||
if (mutated) {
|
if (mutated) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cb-mnmerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cb-mnmerkleroot");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-calc-cb-mnmerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-calc-cb-mnmerkleroot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ auto CalcHashCountFromQCHashes(const QcHashMap& qcHashes)
|
|||||||
return hash_count;
|
return hash_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state)
|
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state)
|
||||||
{
|
{
|
||||||
static int64_t nTimeMined = 0;
|
static int64_t nTimeMined = 0;
|
||||||
static int64_t nTimeLoop = 0;
|
static int64_t nTimeLoop = 0;
|
||||||
@ -233,7 +233,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
|
|
||||||
auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor);
|
auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor);
|
||||||
if (!retVal) {
|
if (!retVal) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "commitment-not-found");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "commitment-not-found");
|
||||||
}
|
}
|
||||||
// The returned quorums are in reversed order, so the most recent one is at index 0
|
// The returned quorums are in reversed order, so the most recent one is at index 0
|
||||||
auto [qcHashes, qcIndexedHashes] = retVal.value();
|
auto [qcHashes, qcIndexedHashes] = retVal.value();
|
||||||
@ -249,7 +249,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
|
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
llmq::CFinalCommitmentTxPayload qc;
|
llmq::CFinalCommitmentTxPayload qc;
|
||||||
if (!GetTxPayload(*tx, qc)) {
|
if (!GetTxPayload(*tx, qc)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload-calc-cbtx-quorummerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
if (qc.commitment.IsNull()) {
|
if (qc.commitment.IsNull()) {
|
||||||
// having null commitments is ok but we don't use them here, move to the next tx
|
// having null commitments is ok but we don't use them here, move to the next tx
|
||||||
@ -257,7 +257,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
}
|
}
|
||||||
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
const auto& llmq_params = llmq_params_opt.value();
|
const auto& llmq_params = llmq_params_opt.value();
|
||||||
auto qcHash = ::SerializeHash(qc.commitment);
|
auto qcHash = ::SerializeHash(qc.commitment);
|
||||||
@ -291,7 +291,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
|
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
|
||||||
assert(llmq_params_opt.has_value());
|
assert(llmq_params_opt.has_value());
|
||||||
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
|
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "excess-quorums-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
// Copy vec_hashes into vec_hashes_final
|
// Copy vec_hashes into vec_hashes_final
|
||||||
std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final));
|
std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final));
|
||||||
@ -308,7 +308,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);
|
LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);
|
||||||
|
|
||||||
if (mutated) {
|
if (mutated) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cbtx-quorummerkleroot");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -8,10 +8,11 @@
|
|||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
|
class BlockValidationState;
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CCoinsViewCache;
|
class CCoinsViewCache;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
namespace llmq {
|
namespace llmq {
|
||||||
class CQuorumBlockProcessor;
|
class CQuorumBlockProcessor;
|
||||||
@ -53,10 +54,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);
|
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state);
|
||||||
|
|
||||||
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, CValidationState& state, const CCoinsViewCache& view);
|
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state, const CCoinsViewCache& view);
|
||||||
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view);
|
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, BlockValidationState& state, const CCoinsViewCache& view);
|
||||||
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state);
|
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state);
|
||||||
|
|
||||||
#endif // BITCOIN_EVO_CBTX_H
|
#endif // BITCOIN_EVO_CBTX_H
|
||||||
|
@ -654,7 +654,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
|
|||||||
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
|
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& _state, const CCoinsViewCache& view, bool fJustCheck)
|
bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -672,7 +672,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
|||||||
try {
|
try {
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
|
|
||||||
if (!BuildNewListFromBlock(block, pindex->pprev, _state, view, newList, true)) {
|
if (!BuildNewListFromBlock(block, pindex->pprev, state, view, newList, true)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -710,7 +710,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
|||||||
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
|
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
|
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-dmn-block");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-dmn-block");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't hold cs while calling signals
|
// Don't hold cs while calling signals
|
||||||
@ -723,7 +723,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
|||||||
if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {
|
if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {
|
||||||
LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__,
|
LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__,
|
||||||
pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight);
|
pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight);
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-dip3-enf-block");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-dip3-enf-block");
|
||||||
}
|
}
|
||||||
LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight);
|
LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight);
|
||||||
}
|
}
|
||||||
@ -775,7 +775,7 @@ void CDeterministicMNManager::UpdatedBlockTip(const CBlockIndex* pindex)
|
|||||||
tipIndex = pindex;
|
tipIndex = pindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& _state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs)
|
bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs);
|
AssertLockHeld(cs);
|
||||||
|
|
||||||
@ -820,11 +820,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
|
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
|
||||||
CProRegTx proTx;
|
CProRegTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType);
|
auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType);
|
||||||
@ -842,7 +842,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
|
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
|
||||||
// should actually never get to this point as CheckProRegTx should have handled this case.
|
// should actually never get to this point as CheckProRegTx should have handled this case.
|
||||||
// We do this additional check nevertheless to be 100% sure
|
// We do this additional check nevertheless to be 100% sure
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
|
auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
|
||||||
@ -858,10 +858,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newList.HasUniqueProperty(proTx.addr)) {
|
if (newList.HasUniqueProperty(proTx.addr)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
|
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-key");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
dmn->nOperatorReward = proTx.nOperatorReward;
|
dmn->nOperatorReward = proTx.nOperatorReward;
|
||||||
@ -883,26 +883,26 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
||||||
CProUpServTx proTx;
|
CProUpServTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) {
|
if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
|
|
||||||
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
if (proTx.nType != dmn->nType) {
|
if (proTx.nType != dmn->nType) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type-mismatch");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-type-mismatch");
|
||||||
}
|
}
|
||||||
if (!IsValidMnType(proTx.nType)) {
|
if (!IsValidMnType(proTx.nType)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||||
@ -932,12 +932,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
||||||
CProUpRegTx proTx;
|
CProUpRegTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||||
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||||
@ -958,12 +958,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||||
CProUpRevTx proTx;
|
CProUpRevTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||||
newState->ResetOperatorFields();
|
newState->ResetOperatorFields();
|
||||||
@ -979,19 +979,19 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
} else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
llmq::CFinalCommitmentTxPayload qc;
|
llmq::CFinalCommitmentTxPayload qc;
|
||||||
if (!GetTxPayload(tx, qc)) {
|
if (!GetTxPayload(tx, qc)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload");
|
||||||
}
|
}
|
||||||
if (!qc.commitment.IsNull()) {
|
if (!qc.commitment.IsNull()) {
|
||||||
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type");
|
||||||
}
|
}
|
||||||
int qcnHeight = int(qc.nHeight);
|
int qcnHeight = int(qc.nHeight);
|
||||||
int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
|
int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
|
||||||
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
|
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
|
||||||
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
|
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
|
||||||
// we should actually never get into this case as validation should have caught it...but let's be sure
|
// we should actually never get into this case as validation should have caught it...but let's be sure
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs);
|
HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs);
|
||||||
@ -1348,111 +1348,111 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename ProTx>
|
template <typename ProTx>
|
||||||
static bool CheckService(const ProTx& proTx, CValidationState& state)
|
static bool CheckService(const ProTx& proTx, TxValidationState& state)
|
||||||
{
|
{
|
||||||
if (!proTx.addr.IsValid()) {
|
if (!proTx.addr.IsValid()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr");
|
||||||
}
|
}
|
||||||
if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) {
|
if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
||||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||||
if (proTx.addr.GetPort() != mainnetDefaultPort) {
|
if (proTx.addr.GetPort() != mainnetDefaultPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port");
|
||||||
}
|
}
|
||||||
} else if (proTx.addr.GetPort() == mainnetDefaultPort) {
|
} else if (proTx.addr.GetPort() == mainnetDefaultPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!proTx.addr.IsIPv4()) {
|
if (!proTx.addr.IsIPv4()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ProTx>
|
template <typename ProTx>
|
||||||
static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state)
|
static bool CheckPlatformFields(const ProTx& proTx, TxValidationState& state)
|
||||||
{
|
{
|
||||||
if (proTx.platformNodeID.IsNull()) {
|
if (proTx.platformNodeID.IsNull()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-nodeid");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-nodeid");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort();
|
static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort();
|
||||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||||
if (proTx.platformP2PPort != mainnetPlatformP2PPort) {
|
if (proTx.platformP2PPort != mainnetPlatformP2PPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort();
|
static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort();
|
||||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||||
if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) {
|
if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
||||||
if (proTx.platformP2PPort == mainnetDefaultP2PPort) {
|
if (proTx.platformP2PPort == mainnetDefaultP2PPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
|
||||||
}
|
}
|
||||||
if (proTx.platformHTTPPort == mainnetDefaultP2PPort) {
|
if (proTx.platformHTTPPort == mainnetDefaultP2PPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proTx.platformP2PPort == proTx.platformHTTPPort ||
|
if (proTx.platformP2PPort == proTx.platformHTTPPort ||
|
||||||
proTx.platformP2PPort == proTx.addr.GetPort() ||
|
proTx.platformP2PPort == proTx.addr.GetPort() ||
|
||||||
proTx.platformHTTPPort == proTx.addr.GetPort()) {
|
proTx.platformHTTPPort == proTx.addr.GetPort()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-dup-ports");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-dup-ports");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ProTx>
|
template <typename ProTx>
|
||||||
static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, CValidationState& state)
|
static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state)
|
||||||
{
|
{
|
||||||
std::string strError;
|
std::string strError;
|
||||||
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) {
|
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ProTx>
|
template <typename ProTx>
|
||||||
static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, CValidationState& state)
|
static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state)
|
||||||
{
|
{
|
||||||
std::string strError;
|
std::string strError;
|
||||||
if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) {
|
if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ProTx>
|
template <typename ProTx>
|
||||||
static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state)
|
static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, TxValidationState& state)
|
||||||
{
|
{
|
||||||
if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) {
|
if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_REGISTER) {
|
if (tx.nType != TRANSACTION_PROVIDER_REGISTER) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProRegTx ptx;
|
CProRegTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
|
// It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
|
||||||
@ -1477,31 +1477,31 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
if (!ptx.collateralOutpoint.hash.IsNull()) {
|
if (!ptx.collateralOutpoint.hash.IsNull()) {
|
||||||
Coin coin;
|
Coin coin;
|
||||||
if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) {
|
if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-dest");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
|
// Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
|
||||||
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
|
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
|
||||||
keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest);
|
keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest);
|
||||||
if (!keyForPayloadSig) {
|
if (!keyForPayloadSig) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-pkh");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-pkh");
|
||||||
}
|
}
|
||||||
|
|
||||||
collateralOutpoint = ptx.collateralOutpoint;
|
collateralOutpoint = ptx.collateralOutpoint;
|
||||||
} else {
|
} else {
|
||||||
if (ptx.collateralOutpoint.n >= tx.vout.size()) {
|
if (ptx.collateralOutpoint.n >= tx.vout.size()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-index");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-index");
|
||||||
}
|
}
|
||||||
if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) {
|
if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) {
|
if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-dest");
|
||||||
}
|
}
|
||||||
|
|
||||||
collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n);
|
collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n);
|
||||||
@ -1510,7 +1510,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
||||||
// this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH
|
// this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH
|
||||||
if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-reuse");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
@ -1518,30 +1518,30 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
|
|
||||||
// only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
|
// only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
|
||||||
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) {
|
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
|
|
||||||
// never allow duplicate keys, even if this ProTx would replace an existing MN
|
// never allow duplicate keys, even if this ProTx would replace an existing MN
|
||||||
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
// never allow duplicate platformNodeIds for HPMNs
|
// never allow duplicate platformNodeIds for HPMNs
|
||||||
if (ptx.nType == MnType::HighPerformance) {
|
if (ptx.nType == MnType::HighPerformance) {
|
||||||
if (mnList.HasUniqueProperty(ptx.platformNodeID)) {
|
if (mnList.HasUniqueProperty(ptx.platformNodeID)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-platformnodeid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
||||||
if (ptx.keyIDOwner != ptx.keyIDVoting) {
|
if (ptx.keyIDOwner != ptx.keyIDVoting) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-not-same");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyForPayloadSig) {
|
if (keyForPayloadSig) {
|
||||||
@ -1553,26 +1553,26 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
} else {
|
} else {
|
||||||
// collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
|
// collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
|
||||||
if (!ptx.vchSig.empty()) {
|
if (!ptx.vchSig.empty()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs)
|
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProUpServTx ptx;
|
CProUpServTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckService(ptx, state)) {
|
if (!CheckService(ptx, state)) {
|
||||||
@ -1590,34 +1590,34 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
|
|||||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||||
auto mn = mnList.GetMN(ptx.proTxHash);
|
auto mn = mnList.GetMN(ptx.proTxHash);
|
||||||
if (!mn) {
|
if (!mn) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow updating to addresses already used by other MNs
|
// don't allow updating to addresses already used by other MNs
|
||||||
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) {
|
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow updating to platformNodeIds already used by other HPMNs
|
// don't allow updating to platformNodeIds already used by other HPMNs
|
||||||
if (ptx.nType == MnType::HighPerformance) {
|
if (ptx.nType == MnType::HighPerformance) {
|
||||||
if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) {
|
if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-platformnodeid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptx.scriptOperatorPayout != CScript()) {
|
if (ptx.scriptOperatorPayout != CScript()) {
|
||||||
if (mn->nOperatorReward == 0) {
|
if (mn->nOperatorReward == 0) {
|
||||||
// don't allow setting operator reward payee in case no operatorReward was set
|
// don't allow setting operator reward payee in case no operatorReward was set
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-payee");
|
||||||
}
|
}
|
||||||
if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) {
|
if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-payee");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can only check the signature if pindexPrev != nullptr and the MN is known
|
// we can only check the signature if pindexPrev != nullptr and the MN is known
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) {
|
if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
@ -1628,69 +1628,69 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProUpRegTx ptx;
|
CProUpRegTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination payoutDest;
|
CTxDestination payoutDest;
|
||||||
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
|
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
|
||||||
// should not happen as we checked script types before
|
// should not happen as we checked script types before
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-dest");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||||
auto dmn = mnList.GetMN(ptx.proTxHash);
|
auto dmn = mnList.GetMN(ptx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server)
|
// don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server)
|
||||||
if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-reuse");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse");
|
||||||
}
|
}
|
||||||
|
|
||||||
Coin coin;
|
Coin coin;
|
||||||
if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) {
|
if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) {
|
||||||
// this should never happen (there would be no dmn otherwise)
|
// this should never happen (there would be no dmn otherwise)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
||||||
CTxDestination collateralTxDest;
|
CTxDestination collateralTxDest;
|
||||||
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-collateral-dest");
|
||||||
}
|
}
|
||||||
if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-reuse");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
||||||
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
|
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
|
||||||
if (ptx.proTxHash != otherDmn->proTxHash) {
|
if (ptx.proTxHash != otherDmn->proTxHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
||||||
if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
|
if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-not-same");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) {
|
if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
@ -1701,29 +1701,29 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs)
|
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProUpRevTx ptx;
|
CProUpRevTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||||
auto dmn = mnList.GetMN(ptx.proTxHash);
|
auto dmn = mnList.GetMN(ptx.proTxHash);
|
||||||
if (!dmn)
|
if (!dmn)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash");
|
||||||
|
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) {
|
if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
class CConnman;
|
class CConnman;
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
class CSimplifiedMNListDiff;
|
class CSimplifiedMNListDiff;
|
||||||
|
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
@ -563,14 +563,14 @@ public:
|
|||||||
m_evoDb(evoDb), connman(_connman) {}
|
m_evoDb(evoDb), connman(_connman) {}
|
||||||
~CDeterministicMNManager() = default;
|
~CDeterministicMNManager() = default;
|
||||||
|
|
||||||
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state,
|
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state,
|
||||||
const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs);
|
const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs);
|
||||||
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
|
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
|
||||||
|
|
||||||
void UpdatedBlockTip(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
|
void UpdatedBlockTip(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
|
||||||
|
|
||||||
// the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet)
|
// the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet)
|
||||||
bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view,
|
bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view,
|
||||||
CDeterministicMNList& mnListRet, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
CDeterministicMNList& mnListRet, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs);
|
static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs);
|
||||||
static void DecreasePoSePenalties(CDeterministicMNList& mnList);
|
static void DecreasePoSePenalties(CDeterministicMNList& mnList);
|
||||||
@ -595,10 +595,10 @@ private:
|
|||||||
CDeterministicMNList GetListForBlockInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
CDeterministicMNList GetListForBlockInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs);
|
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs);
|
||||||
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs);
|
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs);
|
||||||
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs);
|
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs);
|
||||||
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs);
|
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs);
|
||||||
|
|
||||||
extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
|
extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
|
||||||
|
|
||||||
|
@ -34,33 +34,33 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
|
|||||||
llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset);
|
llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
MNHFTxPayload mnhfTx;
|
MNHFTxPayload mnhfTx;
|
||||||
if (!GetTxPayload(tx, mnhfTx)) {
|
if (!GetTxPayload(tx, mnhfTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash);
|
const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash);
|
||||||
if (!pindexQuorum) {
|
if (!pindexQuorum) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
|
if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
|
||||||
// not part of active chain
|
// not part of active chain
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
|
if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mnhfTx.signal.Verify(pindexQuorum)) {
|
if (!mnhfTx.signal.Verify(pindexQuorum)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-invalid");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
|
|
||||||
// mnhf signal special transaction
|
// mnhf signal special transaction
|
||||||
@ -72,6 +72,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
#endif // BITCOIN_EVO_MNHFTX_H
|
#endif // BITCOIN_EVO_MNHFTX_H
|
||||||
|
@ -14,34 +14,34 @@
|
|||||||
maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||||
{
|
{
|
||||||
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
|
||||||
}
|
}
|
||||||
if (!IsValidMnType(nType)) {
|
if (!IsValidMnType(nType)) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-type"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-type"};
|
||||||
}
|
}
|
||||||
if (nMode != 0) {
|
if (nMode != 0) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
||||||
}
|
}
|
||||||
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination payoutDest;
|
CTxDestination payoutDest;
|
||||||
if (!ExtractDestination(scriptPayout, payoutDest)) {
|
if (!ExtractDestination(scriptPayout, payoutDest)) {
|
||||||
// should not happen as we checked script types before
|
// should not happen as we checked script types before
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee-dest"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest"};
|
||||||
}
|
}
|
||||||
// don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server)
|
// don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server)
|
||||||
if (payoutDest == CTxDestination(PKHash(keyIDOwner)) || payoutDest == CTxDestination(PKHash(keyIDVoting))) {
|
if (payoutDest == CTxDestination(PKHash(keyIDOwner)) || payoutDest == CTxDestination(PKHash(keyIDVoting))) {
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee-reuse"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse"};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nOperatorReward > 10000) {
|
if (nOperatorReward > 10000) {
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-operator-reward"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-reward"};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -87,7 +87,7 @@ std::string CProRegTx::ToString() const
|
|||||||
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||||
{
|
{
|
||||||
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -108,17 +108,17 @@ std::string CProUpServTx::ToString() const
|
|||||||
maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||||
{
|
{
|
||||||
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
|
||||||
}
|
}
|
||||||
if (nMode != 0) {
|
if (nMode != 0) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
||||||
}
|
}
|
||||||
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
||||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"};
|
return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -138,13 +138,13 @@ std::string CProUpRegTx::ToString() const
|
|||||||
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||||
{
|
{
|
||||||
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"};
|
||||||
}
|
}
|
||||||
|
|
||||||
// nReason < CProUpRevTx::REASON_NOT_SPECIFIED is always `false` since
|
// nReason < CProUpRevTx::REASON_NOT_SPECIFIED is always `false` since
|
||||||
// nReason is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0
|
// nReason is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0
|
||||||
if (nReason > CProUpRevTx::REASON_LAST) {
|
if (nReason > CProUpRevTx::REASON_LAST) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-reason"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-reason"};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CCoinsViewCache;
|
class CCoinsViewCache;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
class CProRegTx
|
class CProRegTx
|
||||||
{
|
{
|
||||||
@ -329,7 +329,7 @@ template <typename ProTx>
|
|||||||
static maybe_error CheckInputsHash(const CTransaction& tx, const ProTx& proTx)
|
static maybe_error CheckInputsHash(const CTransaction& tx, const ProTx& proTx)
|
||||||
{
|
{
|
||||||
if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) {
|
if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) {
|
||||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-inputs-hash"};
|
return {TxValidationResult::TX_CONSENSUS, "bad-protx-inputs-hash"};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
struct maybe_error {
|
struct maybe_error {
|
||||||
bool did_err{false};
|
bool did_err{false};
|
||||||
ValidationInvalidReason reason{ValidationInvalidReason::CONSENSUS};
|
TxValidationResult reason{TxValidationResult::TX_CONSENSUS};
|
||||||
std::string_view error_str;
|
std::string_view error_str;
|
||||||
|
|
||||||
constexpr maybe_error() = default;
|
constexpr maybe_error() = default;
|
||||||
constexpr maybe_error(ValidationInvalidReason reasonIn, std::string_view err): did_err(true), reason(reasonIn), error_str(err) {};
|
constexpr maybe_error(TxValidationResult reasonIn, std::string_view err): did_err(true), reason(reasonIn), error_str(err) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) {
|
if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -46,13 +46,13 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
|||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-check-special-tx");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "failed-check-special-tx");
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type-check");
|
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type-check");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state)
|
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, TxValidationState& state)
|
||||||
{
|
{
|
||||||
if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) {
|
if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) {
|
||||||
return true;
|
return true;
|
||||||
@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
|
|||||||
return true; // handled per block
|
return true; // handled per block
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-tx-type-proc");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-tx-type-proc");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
||||||
@ -99,7 +99,7 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor,
|
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor,
|
||||||
CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots)
|
BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -112,13 +112,18 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
|
|||||||
int64_t nTime1 = GetTimeMicros();
|
int64_t nTime1 = GetTimeMicros();
|
||||||
|
|
||||||
for (const auto& ptr_tx : block.vtx) {
|
for (const auto& ptr_tx : block.vtx) {
|
||||||
if (!CheckSpecialTx(*ptr_tx, pindex->pprev, state, view, fCheckCbTxMerleRoots)) {
|
TxValidationState tx_state;
|
||||||
// pass the state returned by the function above
|
// At this moment CheckSpecialTx() and ProcessSpecialTx() may fail by 2 possible ways:
|
||||||
return false;
|
// consensus failures and "TX_BAD_SPECIAL"
|
||||||
|
if (!CheckSpecialTx(*ptr_tx, pindex->pprev, tx_state, view, fCheckCbTxMerleRoots)) {
|
||||||
|
assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL);
|
||||||
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
|
||||||
|
strprintf("Special Transaction check failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage()));
|
||||||
}
|
}
|
||||||
if (!ProcessSpecialTx(*ptr_tx, pindex, state)) {
|
if (!ProcessSpecialTx(*ptr_tx, pindex, tx_state)) {
|
||||||
// pass the state returned by the function above
|
assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL);
|
||||||
return false;
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
|
||||||
|
strprintf("Process Special Transaction failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +159,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
|
|||||||
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
|
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-procspectxsinblock");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -9,19 +9,20 @@
|
|||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <threadsafety.h>
|
#include <threadsafety.h>
|
||||||
|
|
||||||
|
class BlockValidationState;
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CCoinsViewCache;
|
class CCoinsViewCache;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
namespace llmq {
|
namespace llmq {
|
||||||
class CQuorumBlockProcessor;
|
class CQuorumBlockProcessor;
|
||||||
} // namespace llmq
|
} // namespace llmq
|
||||||
|
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
|
|
||||||
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor,
|
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor,
|
||||||
CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
#endif // BITCOIN_EVO_SPECIALTXMAN_H
|
#endif // BITCOIN_EVO_SPECIALTXMAN_H
|
||||||
|
@ -928,7 +928,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
|
|||||||
// the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve
|
// the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve
|
||||||
// the relevant pointers before the ABC call.
|
// the relevant pointers before the ABC call.
|
||||||
for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
|
for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) {
|
if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) {
|
||||||
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
|
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
|
||||||
StartShutdown();
|
StartShutdown();
|
||||||
|
@ -23,7 +23,6 @@ class CFeeRate;
|
|||||||
class CRPCCommand;
|
class CRPCCommand;
|
||||||
class CScheduler;
|
class CScheduler;
|
||||||
class CTxMemPool;
|
class CTxMemPool;
|
||||||
class CValidationState;
|
|
||||||
class CFeeRate;
|
class CFeeRate;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class Coin;
|
class Coin;
|
||||||
|
19
src/key.h
19
src/key.h
@ -161,25 +161,6 @@ struct CExtKey {
|
|||||||
bool Derive(CExtKey& out, unsigned int nChild) const;
|
bool Derive(CExtKey& out, unsigned int nChild) const;
|
||||||
CExtPubKey Neuter() const;
|
CExtPubKey Neuter() const;
|
||||||
void SetSeed(const unsigned char* seed, unsigned int nSeedLen);
|
void SetSeed(const unsigned char* seed, unsigned int nSeedLen);
|
||||||
template <typename Stream>
|
|
||||||
void Serialize(Stream& s) const
|
|
||||||
{
|
|
||||||
unsigned int len = BIP32_EXTKEY_SIZE;
|
|
||||||
::WriteCompactSize(s, len);
|
|
||||||
unsigned char code[BIP32_EXTKEY_SIZE];
|
|
||||||
Encode(code);
|
|
||||||
s.write((const char *)&code[0], len);
|
|
||||||
}
|
|
||||||
template <typename Stream>
|
|
||||||
void Unserialize(Stream& s)
|
|
||||||
{
|
|
||||||
unsigned int len = ::ReadCompactSize(s);
|
|
||||||
unsigned char code[BIP32_EXTKEY_SIZE];
|
|
||||||
if (len != BIP32_EXTKEY_SIZE)
|
|
||||||
throw std::runtime_error("Invalid extended key size\n");
|
|
||||||
s.read((char *)&code[0], len);
|
|
||||||
Decode(code);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */
|
/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */
|
||||||
|
@ -136,7 +136,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
|
|||||||
AddMineableCommitment(qc);
|
AddMineableCommitment(qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck, bool fBLSChecks)
|
bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
|
|||||||
const auto numCommitmentsInNewBlock = qcs.count(params.type);
|
const auto numCommitmentsInNewBlock = qcs.count(params.type);
|
||||||
|
|
||||||
if (numCommitmentsRequired < numCommitmentsInNewBlock) {
|
if (numCommitmentsRequired < numCommitmentsInNewBlock) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-not-allowed");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-not-allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numCommitmentsRequired > numCommitmentsInNewBlock) {
|
if (numCommitmentsRequired > numCommitmentsInNewBlock) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-missing");
|
||||||
}
|
}
|
||||||
if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
|
if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
|
||||||
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
|
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
|
||||||
@ -210,7 +210,7 @@ static std::tuple<std::string, Consensus::LLMQType, int, uint32_t> BuildInversed
|
|||||||
return std::make_tuple(DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT_Q_INDEXED, llmqType, quorumIndex, htobe32(std::numeric_limits<uint32_t>::max() - nMinedHeight));
|
return std::make_tuple(DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT_Q_INDEXED, llmqType, quorumIndex, htobe32(std::numeric_limits<uint32_t>::max() - nMinedHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck, bool fBLSChecks)
|
bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, bool fJustCheck, bool fBLSChecks)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -234,31 +234,31 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
|
|||||||
if (quorumHash.IsNull()) {
|
if (quorumHash.IsNull()) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-block");
|
||||||
}
|
}
|
||||||
if (quorumHash != qc.quorumHash) {
|
if (quorumHash != qc.quorumHash) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-block");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qc.IsNull()) {
|
if (qc.IsNull()) {
|
||||||
if (!qc.VerifyNull()) {
|
if (!qc.VerifyNull()) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid-null");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasMinedCommitment(llmq_params.type, quorumHash)) {
|
if (HasMinedCommitment(llmq_params.type, quorumHash)) {
|
||||||
// should not happen as it's already handled in ProcessBlock
|
// should not happen as it's already handled in ProcessBlock
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsMiningPhase(llmq_params, nHeight)) {
|
if (!IsMiningPhase(llmq_params, nHeight)) {
|
||||||
// should not happen as it's already handled in ProcessBlock
|
// should not happen as it's already handled in ProcessBlock
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash);
|
const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash);
|
||||||
@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
|
|||||||
if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
|
if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fJustCheck) {
|
if (fJustCheck) {
|
||||||
@ -313,7 +313,7 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
|
|||||||
llmq::utils::PreComputeQuorumMembers(pindex, true);
|
llmq::utils::PreComputeQuorumMembers(pindex, true);
|
||||||
|
|
||||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||||
CValidationState dummy;
|
BlockValidationState dummy;
|
||||||
if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) {
|
if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -378,7 +378,7 @@ bool CQuorumBlockProcessor::UpgradeDB()
|
|||||||
assert(r);
|
assert(r);
|
||||||
|
|
||||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||||
CValidationState dummyState;
|
BlockValidationState dummyState;
|
||||||
GetCommitmentsFromBlock(block, pindex, qcs, dummyState);
|
GetCommitmentsFromBlock(block, pindex, qcs, dummyState);
|
||||||
|
|
||||||
for (const auto& p : qcs) {
|
for (const auto& p : qcs) {
|
||||||
@ -407,7 +407,7 @@ bool CQuorumBlockProcessor::UpgradeDB()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& state)
|
bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, BlockValidationState& state)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
|
|||||||
if (!GetTxPayload(*tx, qc)) {
|
if (!GetTxPayload(*tx, qc)) {
|
||||||
// should not happen as it was verified before processing the block
|
// should not happen as it was verified before processing the block
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight);
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
|
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
// should not happen as it was verified before processing the block
|
// should not happen as it was verified before processing the block
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
// only allow one commitment per type and per block (This was changed with rotation)
|
// only allow one commitment per type and per block (This was changed with rotation)
|
||||||
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
|
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
|
||||||
if (ret.count(qc.commitment.llmqType) != 0) {
|
if (ret.count(qc.commitment.llmqType) != 0) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +442,7 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) {
|
if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-premature");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-premature");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
class BlockValidationState;
|
||||||
class CNode;
|
class CNode;
|
||||||
class CConnman;
|
class CConnman;
|
||||||
class CValidationState;
|
|
||||||
class CEvoDB;
|
class CEvoDB;
|
||||||
|
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
@ -49,7 +49,7 @@ public:
|
|||||||
|
|
||||||
void ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv);
|
void ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv);
|
||||||
|
|
||||||
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
void AddMineableCommitment(const CFinalCommitment& fqc);
|
void AddMineableCommitment(const CFinalCommitment& fqc);
|
||||||
@ -67,8 +67,8 @@ public:
|
|||||||
std::vector<std::pair<int, const CBlockIndex*>> GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const;
|
std::vector<std::pair<int, const CBlockIndex*>> GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const;
|
||||||
std::optional<const CBlockIndex*> GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const;
|
std::optional<const CBlockIndex*> GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const;
|
||||||
private:
|
private:
|
||||||
static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap<Consensus::LLMQType, CFinalCommitment>& ret, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
static bool IsMiningPhase(const Consensus::LLMQParams& llmqParams, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
static bool IsMiningPhase(const Consensus::LLMQParams& llmqParams, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
static uint256 GetQuorumBlockHash(const Consensus::LLMQParams& llmqParams, int nHeight, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
static uint256 GetQuorumBlockHash(const Consensus::LLMQParams& llmqParams, int nHeight, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
@ -494,20 +494,20 @@ void CChainLocksHandler::EnforceBestChainLock()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState dummy_state;
|
||||||
const auto ¶ms = Params();
|
const auto ¶ms = Params();
|
||||||
|
|
||||||
// Go backwards through the chain referenced by clsig until we find a block that is part of the main chain.
|
// Go backwards through the chain referenced by clsig until we find a block that is part of the main chain.
|
||||||
// For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig
|
// For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig
|
||||||
// and mark all of them as conflicting.
|
// and mark all of them as conflicting.
|
||||||
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString());
|
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString());
|
||||||
::ChainstateActive().EnforceBlock(state, params, pindex);
|
::ChainstateActive().EnforceBlock(dummy_state, params, pindex);
|
||||||
|
|
||||||
bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex;
|
bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex;
|
||||||
|
|
||||||
if (activateNeeded) {
|
if (activateNeeded) {
|
||||||
if (!::ChainstateActive().ActivateBestChain(state, params)) {
|
if (!::ChainstateActive().ActivateBestChain(dummy_state, params)) {
|
||||||
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state));
|
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(dummy_state));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
@ -176,18 +176,18 @@ bool CFinalCommitment::VerifySizes(const Consensus::LLMQParams& params) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state)
|
||||||
{
|
{
|
||||||
CFinalCommitmentTxPayload qcTx;
|
CFinalCommitmentTxPayload qcTx;
|
||||||
if (!GetTxPayload(tx, qcTx)) {
|
if (!GetTxPayload(tx, qcTx)) {
|
||||||
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
|
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
|
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType));
|
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType));
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-commitment-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LogAcceptCategory(BCLog::LLMQ)) {
|
if (LogAcceptCategory(BCLog::LLMQ)) {
|
||||||
@ -201,36 +201,36 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
|
|||||||
|
|
||||||
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
|
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion);
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-version");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) {
|
if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight);
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash));
|
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash));
|
||||||
if (pQuorumBaseBlockIndex == nullptr) {
|
if (pQuorumBaseBlockIndex == nullptr) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) {
|
if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) {
|
||||||
// not part of active chain
|
// not part of active chain
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcTx.commitment.IsNull()) {
|
if (qcTx.commitment.IsNull()) {
|
||||||
if (!qcTx.commitment.VerifyNull()) {
|
if (!qcTx.commitment.VerifyNull()) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid-null");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) {
|
if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight);
|
LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
namespace llmq
|
namespace llmq
|
||||||
{
|
{
|
||||||
@ -168,7 +168,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);
|
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state);
|
||||||
|
|
||||||
} // namespace llmq
|
} // namespace llmq
|
||||||
|
|
||||||
|
@ -1477,7 +1477,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
|
|||||||
|
|
||||||
LogPrintf("CInstantSendManager::%s -- invalidating block %s\n", __func__, pindex->GetBlockHash().ToString());
|
LogPrintf("CInstantSendManager::%s -- invalidating block %s\n", __func__, pindex->GetBlockHash().ToString());
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
// need non-const pointer
|
// need non-const pointer
|
||||||
auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash()));
|
auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash()));
|
||||||
if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) {
|
if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) {
|
||||||
@ -1495,7 +1495,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (activateBestChain) {
|
if (activateBestChain) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!::ChainstateActive().ActivateBestChain(state, Params())) {
|
if (!::ChainstateActive().ActivateBestChain(state, Params())) {
|
||||||
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state));
|
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state));
|
||||||
// This should not have happened and we are in a state were it's not safe to continue anymore
|
// This should not have happened and we are in a state were it's not safe to continue anymore
|
||||||
|
@ -205,7 +205,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
|
|||||||
|
|
||||||
cbTx.nHeight = nHeight;
|
cbTx.nHeight = nHeight;
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
|
if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
|
||||||
throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootMNList failed: %s", __func__, FormatStateMessage(state)));
|
throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootMNList failed: %s", __func__, FormatStateMessage(state)));
|
||||||
}
|
}
|
||||||
@ -233,8 +233,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
|
|||||||
pblocktemplate->nPrevBits = pindexPrev->nBits;
|
pblocktemplate->nPrevBits = pindexPrev->nBits;
|
||||||
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);
|
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);
|
||||||
|
|
||||||
CValidationState state;
|
|
||||||
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
|
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
|
||||||
|
BlockValidationState state;
|
||||||
if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) {
|
if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) {
|
||||||
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
|
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
|
||||||
}
|
}
|
||||||
|
@ -173,8 +173,8 @@ namespace {
|
|||||||
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sources of received blocks, saved to be able to send them reject
|
* Sources of received blocks, saved to be able punish them when processing
|
||||||
* messages or ban them when processing happens afterwards.
|
* happens afterwards.
|
||||||
* Set mapBlockSource[hash].second to false if the node should not be
|
* Set mapBlockSource[hash].second to false if the node should not be
|
||||||
* punished if the block is invalid.
|
* punished if the block is invalid.
|
||||||
*/
|
*/
|
||||||
@ -1222,7 +1222,7 @@ bool IsBanned(NodeId pnode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Potentially mark a node discouraged based on the contents of a CValidationState object
|
* Potentially mark a node discouraged based on the contents of a BlockValidationState object
|
||||||
*
|
*
|
||||||
* @param[in] via_compact_block this bool is passed in because net_processing should
|
* @param[in] via_compact_block this bool is passed in because net_processing should
|
||||||
* punish peers differently depending on whether the data was provided in a compact
|
* punish peers differently depending on whether the data was provided in a compact
|
||||||
@ -1231,20 +1231,20 @@ bool IsBanned(NodeId pnode)
|
|||||||
*
|
*
|
||||||
* @return Returns true if the peer was punished (probably disconnected)
|
* @return Returns true if the peer was punished (probably disconnected)
|
||||||
*/
|
*/
|
||||||
static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "")
|
static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "")
|
||||||
{
|
{
|
||||||
switch (state.GetReason()) {
|
switch (state.GetResult()) {
|
||||||
case ValidationInvalidReason::NONE:
|
case BlockValidationResult::BLOCK_RESULT_UNSET:
|
||||||
break;
|
break;
|
||||||
// The node is providing invalid data:
|
// The node is providing invalid data:
|
||||||
case ValidationInvalidReason::CONSENSUS:
|
case BlockValidationResult::BLOCK_CONSENSUS:
|
||||||
case ValidationInvalidReason::BLOCK_MUTATED:
|
case BlockValidationResult::BLOCK_MUTATED:
|
||||||
if (!via_compact_block) {
|
if (!via_compact_block) {
|
||||||
Misbehaving(nodeid, 100, message);
|
Misbehaving(nodeid, 100, message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ValidationInvalidReason::CACHED_INVALID:
|
case BlockValidationResult::BLOCK_CACHED_INVALID:
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CNodeState *node_state = State(nodeid);
|
CNodeState *node_state = State(nodeid);
|
||||||
@ -1260,25 +1260,18 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ValidationInvalidReason::BLOCK_INVALID_HEADER:
|
case BlockValidationResult::BLOCK_INVALID_HEADER:
|
||||||
case ValidationInvalidReason::BLOCK_CHECKPOINT:
|
case BlockValidationResult::BLOCK_CHECKPOINT:
|
||||||
case ValidationInvalidReason::BLOCK_INVALID_PREV:
|
case BlockValidationResult::BLOCK_INVALID_PREV:
|
||||||
Misbehaving(nodeid, 100, message);
|
Misbehaving(nodeid, 100, message);
|
||||||
return true;
|
return true;
|
||||||
// Conflicting (but not necessarily invalid) data or different policy:
|
// Conflicting (but not necessarily invalid) data or different policy:
|
||||||
case ValidationInvalidReason::BLOCK_MISSING_PREV:
|
case BlockValidationResult::BLOCK_MISSING_PREV:
|
||||||
case ValidationInvalidReason::BLOCK_CHAINLOCK:
|
case BlockValidationResult::BLOCK_CHAINLOCK:
|
||||||
case ValidationInvalidReason::TX_BAD_SPECIAL:
|
|
||||||
case ValidationInvalidReason::TX_CONFLICT_LOCK:
|
|
||||||
Misbehaving(nodeid, 10, message);
|
Misbehaving(nodeid, 10, message);
|
||||||
return true;
|
return true;
|
||||||
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
|
case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
|
||||||
case ValidationInvalidReason::BLOCK_TIME_FUTURE:
|
case BlockValidationResult::BLOCK_TIME_FUTURE:
|
||||||
case ValidationInvalidReason::TX_NOT_STANDARD:
|
|
||||||
case ValidationInvalidReason::TX_MISSING_INPUTS:
|
|
||||||
case ValidationInvalidReason::TX_PREMATURE_SPEND:
|
|
||||||
case ValidationInvalidReason::TX_CONFLICT:
|
|
||||||
case ValidationInvalidReason::TX_MEMPOOL_POLICY:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (message != "") {
|
if (message != "") {
|
||||||
@ -1287,6 +1280,41 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Potentially ban a node based on the contents of a TxValidationState object
|
||||||
|
*
|
||||||
|
* @return Returns true if the peer was punished (probably disconnected)
|
||||||
|
*
|
||||||
|
* Changes here may need to be reflected in TxRelayMayResultInDisconnect().
|
||||||
|
*/
|
||||||
|
static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") {
|
||||||
|
switch (state.GetResult()) {
|
||||||
|
case TxValidationResult::TX_RESULT_UNSET:
|
||||||
|
break;
|
||||||
|
// The node is providing invalid data:
|
||||||
|
case TxValidationResult::TX_CONSENSUS:
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
Misbehaving(nodeid, 100, message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Conflicting (but not necessarily invalid) data or different policy:
|
||||||
|
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
|
||||||
|
case TxValidationResult::TX_NOT_STANDARD:
|
||||||
|
case TxValidationResult::TX_MISSING_INPUTS:
|
||||||
|
case TxValidationResult::TX_PREMATURE_SPEND:
|
||||||
|
case TxValidationResult::TX_CONFLICT:
|
||||||
|
case TxValidationResult::TX_MEMPOOL_POLICY:
|
||||||
|
// moved from BLOCK
|
||||||
|
case TxValidationResult::TX_BAD_SPECIAL:
|
||||||
|
case TxValidationResult::TX_CONFLICT_LOCK:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (message != "") {
|
||||||
|
LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@ -1507,17 +1535,18 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
|
|||||||
* Handle invalid block rejection and consequent peer discouragement, maintain which
|
* Handle invalid block rejection and consequent peer discouragement, maintain which
|
||||||
* peers announce compact blocks.
|
* peers announce compact blocks.
|
||||||
*/
|
*/
|
||||||
void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
|
void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
const uint256 hash(block.GetHash());
|
const uint256 hash(block.GetHash());
|
||||||
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
|
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
|
||||||
|
|
||||||
if (state.IsInvalid()) {
|
// If the block failed validation, we know where it came from and we're still connected
|
||||||
// Don't send reject message with code 0 or an internal reject code.
|
// to that peer, maybe punish.
|
||||||
if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) {
|
if (state.IsInvalid() &&
|
||||||
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
it != mapBlockSource.end() &&
|
||||||
}
|
State(it->second.first)) {
|
||||||
|
MaybePunishNodeForBlock(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||||
}
|
}
|
||||||
// Check that:
|
// Check that:
|
||||||
// 1. The block is valid
|
// 1. The block is valid
|
||||||
@ -1710,7 +1739,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|||||||
}
|
}
|
||||||
} // release cs_main before calling ActivateBestChain
|
} // release cs_main before calling ActivateBestChain
|
||||||
if (need_activate_chain) {
|
if (need_activate_chain) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
|
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
|
||||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
@ -2126,11 +2155,10 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
CBlockHeader first_invalid_header;
|
if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
|
||||||
if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
|
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
MaybePunishNode(pfrom.GetId(), state, via_compact_block, "invalid header received");
|
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2265,14 +2293,13 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
|
|||||||
const CTransactionRef porphanTx = orphan_it->second.tx;
|
const CTransactionRef porphanTx = orphan_it->second.tx;
|
||||||
const CTransaction& orphanTx = *porphanTx;
|
const CTransaction& orphanTx = *porphanTx;
|
||||||
NodeId fromPeer = orphan_it->second.fromPeer;
|
NodeId fromPeer = orphan_it->second.fromPeer;
|
||||||
bool fMissingInputs2 = false;
|
// Use a new TxValidationState because orphans come from different peers (and we call
|
||||||
// Use a new CValidationState because orphans come from different peers (and we call
|
// MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer
|
||||||
// MaybePunishNode based on the source peer from the orphan map, not based on the peer
|
|
||||||
// that relayed the previous transaction).
|
// that relayed the previous transaction).
|
||||||
CValidationState orphan_state;
|
TxValidationState orphan_state;
|
||||||
|
|
||||||
if (setMisbehaving.count(fromPeer)) continue;
|
if (setMisbehaving.count(fromPeer)) continue;
|
||||||
if (AcceptToMemoryPool(::ChainstateActive(), mempool, orphan_state, porphanTx, &fMissingInputs2 /* pfMissingInputs */,
|
if (AcceptToMemoryPool(::ChainstateActive(), mempool, orphan_state, porphanTx,
|
||||||
false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
||||||
RelayTransaction(orphanTx.GetHash(), connman);
|
RelayTransaction(orphanTx.GetHash(), connman);
|
||||||
@ -2286,10 +2313,10 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
|
|||||||
}
|
}
|
||||||
EraseOrphanTx(orphanHash);
|
EraseOrphanTx(orphanHash);
|
||||||
done = true;
|
done = true;
|
||||||
} else if (!fMissingInputs2) {
|
} else if (orphan_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
|
||||||
if (orphan_state.IsInvalid()) {
|
if (orphan_state.IsInvalid()) {
|
||||||
// Punish peer that gave us an invalid orphan tx
|
// Punish peer that gave us an invalid orphan tx
|
||||||
if (MaybePunishNode(fromPeer, orphan_state, /*via_compact_block*/ false)) {
|
if (MaybePunishNodeForTx(fromPeer, orphan_state)) {
|
||||||
setMisbehaving.insert(fromPeer);
|
setMisbehaving.insert(fromPeer);
|
||||||
}
|
}
|
||||||
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
||||||
@ -2297,7 +2324,6 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
|
|||||||
// Has inputs but not accepted to mempool
|
// Has inputs but not accepted to mempool
|
||||||
// Probably non-standard or insufficient fee
|
// Probably non-standard or insufficient fee
|
||||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
||||||
assert(IsTransactionReason(orphan_state.GetReason()));
|
|
||||||
assert(recentRejects);
|
assert(recentRejects);
|
||||||
recentRejects->insert(orphanHash);
|
recentRejects->insert(orphanHash);
|
||||||
EraseOrphanTx(orphanHash);
|
EraseOrphanTx(orphanHash);
|
||||||
@ -2523,25 +2549,6 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
|
|||||||
connman.PushMessage(&peer, std::move(msg));
|
connman.PushMessage(&peer, std::move(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RejectCodeToString(const unsigned char code)
|
|
||||||
{
|
|
||||||
if (code == REJECT_MALFORMED)
|
|
||||||
return "malformed";
|
|
||||||
if (code == REJECT_INVALID)
|
|
||||||
return "invalid";
|
|
||||||
if (code == REJECT_OBSOLETE)
|
|
||||||
return "obsolete";
|
|
||||||
if (code == REJECT_DUPLICATE)
|
|
||||||
return "duplicate";
|
|
||||||
if (code == REJECT_NONSTANDARD)
|
|
||||||
return "nonstandard";
|
|
||||||
if (code == REJECT_INSUFFICIENTFEE)
|
|
||||||
return "insufficientfee";
|
|
||||||
if (code == REJECT_CHECKPOINT)
|
|
||||||
return "checkpoint";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx)
|
std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx)
|
||||||
{
|
{
|
||||||
if (!dstx.IsValidStructure()) {
|
if (!dstx.IsValidStructure()) {
|
||||||
@ -3148,7 +3155,7 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
LOCK(cs_most_recent_block);
|
LOCK(cs_most_recent_block);
|
||||||
a_recent_block = most_recent_block;
|
a_recent_block = most_recent_block;
|
||||||
}
|
}
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
|
if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) {
|
||||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
@ -3364,10 +3371,9 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
|
|
||||||
LOCK2(cs_main, g_cs_orphans);
|
LOCK2(cs_main, g_cs_orphans);
|
||||||
|
|
||||||
bool fMissingInputs = false;
|
TxValidationState state;
|
||||||
CValidationState state;
|
|
||||||
|
|
||||||
if (!AlreadyHave(inv, m_mempool, *m_llmq_ctx) && AcceptToMemoryPool(::ChainstateActive(), m_mempool, state, ptx, &fMissingInputs /* pfMissingInputs */,
|
if (!AlreadyHave(inv, m_mempool, *m_llmq_ctx) && AcceptToMemoryPool(::ChainstateActive(), m_mempool, state, ptx,
|
||||||
false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
// Process custom txes, this changes AlreadyHave to "true"
|
// Process custom txes, this changes AlreadyHave to "true"
|
||||||
if (nInvType == MSG_DSTX) {
|
if (nInvType == MSG_DSTX) {
|
||||||
@ -3398,7 +3404,7 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
// Recursively process any orphan transactions that depended on this one
|
// Recursively process any orphan transactions that depended on this one
|
||||||
ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set);
|
ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set);
|
||||||
}
|
}
|
||||||
else if (fMissingInputs)
|
else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
|
||||||
{
|
{
|
||||||
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
|
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
|
||||||
for (const CTxIn& txin : tx.vin) {
|
for (const CTxIn& txin : tx.vin) {
|
||||||
@ -3435,7 +3441,6 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
|
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(IsTransactionReason(state.GetReason()));
|
|
||||||
assert(recentRejects);
|
assert(recentRejects);
|
||||||
recentRejects->insert(tx.GetHash());
|
recentRejects->insert(tx.GetHash());
|
||||||
if (RecursiveDynamicUsage(*ptx) < 100000) {
|
if (RecursiveDynamicUsage(*ptx) < 100000) {
|
||||||
@ -3478,7 +3483,7 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
|
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
|
||||||
pfrom.GetId(),
|
pfrom.GetId(),
|
||||||
FormatStateMessage(state));
|
FormatStateMessage(state));
|
||||||
MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ false);
|
MaybePunishNodeForTx(pfrom.GetId(), state);
|
||||||
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
|
m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -3513,10 +3518,10 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex *pindex = nullptr;
|
const CBlockIndex *pindex = nullptr;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
|
MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3750,11 +3755,12 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
// been run). This is handled below, so just treat this as
|
// been run). This is handled below, so just treat this as
|
||||||
// though the block was successfully read, and rely on the
|
// though the block was successfully read, and rely on the
|
||||||
// handling in ProcessNewBlock to ensure the block index is
|
// handling in ProcessNewBlock to ensure the block index is
|
||||||
// updated, reject messages go out, etc.
|
// updated, etc.
|
||||||
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
||||||
fBlockRead = true;
|
fBlockRead = true;
|
||||||
// mapBlockSource is only used for sending reject messages and DoS scores,
|
// mapBlockSource is used for potentially punishing peers and
|
||||||
// so the race between here and cs_main in ProcessNewBlock is fine.
|
// updating which peers send us compact blocks, so the race
|
||||||
|
// between here and cs_main in ProcessNewBlock is fine.
|
||||||
// BIP 152 permits peers to relay compact blocks after validating
|
// BIP 152 permits peers to relay compact blocks after validating
|
||||||
// the header only; we should not punish peers if the block turns
|
// the header only; we should not punish peers if the block turns
|
||||||
// out to be invalid.
|
// out to be invalid.
|
||||||
@ -3835,8 +3841,9 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
// Also always process if we requested the block explicitly, as we may
|
// Also always process if we requested the block explicitly, as we may
|
||||||
// need it even though it is not a candidate for a new best tip.
|
// need it even though it is not a candidate for a new best tip.
|
||||||
forceProcessing |= MarkBlockAsReceived(hash);
|
forceProcessing |= MarkBlockAsReceived(hash);
|
||||||
// mapBlockSource is only used for sending reject messages and DoS scores,
|
// mapBlockSource is only used for punishing peers and setting
|
||||||
// so the race between here and cs_main in ProcessNewBlock is fine.
|
// which peers send us compact blocks, so the race between here and
|
||||||
|
// cs_main in ProcessNewBlock is fine.
|
||||||
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
|
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
|
||||||
}
|
}
|
||||||
bool fNewBlock = false;
|
bool fNewBlock = false;
|
||||||
|
@ -52,7 +52,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Overridden from CValidationInterface.
|
* Overridden from CValidationInterface.
|
||||||
*/
|
*/
|
||||||
void BlockChecked(const CBlock& block, const CValidationState& state) override;
|
void BlockChecked(const CBlock& block, const BlockValidationState& state) override;
|
||||||
/**
|
/**
|
||||||
* Overridden from CValidationInterface.
|
* Overridden from CValidationInterface.
|
||||||
*/
|
*/
|
||||||
|
@ -39,18 +39,16 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
|
|||||||
}
|
}
|
||||||
if (!node.mempool->exists(hashTx)) {
|
if (!node.mempool->exists(hashTx)) {
|
||||||
// Transaction is not already in the mempool. Submit it.
|
// Transaction is not already in the mempool. Submit it.
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
bool fMissingInputs;
|
if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx),
|
||||||
if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx), &fMissingInputs,
|
|
||||||
bypass_limits, max_tx_fee)) {
|
bypass_limits, max_tx_fee)) {
|
||||||
|
err_string = FormatStateMessage(state);
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
err_string = FormatStateMessage(state);
|
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
||||||
return TransactionError::MEMPOOL_REJECTED;
|
|
||||||
} else {
|
|
||||||
if (fMissingInputs) {
|
|
||||||
return TransactionError::MISSING_INPUTS;
|
return TransactionError::MISSING_INPUTS;
|
||||||
}
|
}
|
||||||
err_string = FormatStateMessage(state);
|
return TransactionError::MEMPOOL_REJECTED;
|
||||||
|
} else {
|
||||||
return TransactionError::MEMPOOL_ERROR;
|
return TransactionError::MEMPOOL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
/** Fee rate of 0 satoshis per kB */
|
/** Fee rate of 0 satoshis per kB */
|
||||||
CFeeRate() : nSatoshisPerK(0) { }
|
CFeeRate() : nSatoshisPerK(0) { }
|
||||||
template<typename I>
|
template<typename I>
|
||||||
CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
|
explicit CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
|
||||||
// We've previously had bugs creep in from silent double->int conversion...
|
// We've previously had bugs creep in from silent double->int conversion...
|
||||||
static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
|
static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,7 @@ public:
|
|||||||
currentUnit = unit;
|
currentUnit = unit;
|
||||||
amountValidator->updateUnit(unit);
|
amountValidator->updateUnit(unit);
|
||||||
|
|
||||||
|
setPlaceholderText(BitcoinUnits::format(currentUnit, m_min_amount, false, BitcoinUnits::separatorAlways));
|
||||||
if(valid)
|
if(valid)
|
||||||
setValue(val);
|
setValue(val);
|
||||||
else
|
else
|
||||||
|
@ -1811,7 +1811,7 @@ static UniValue preciousblock(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
::ChainstateActive().PreciousBlock(state, Params(), pblockindex);
|
::ChainstateActive().PreciousBlock(state, Params(), pblockindex);
|
||||||
|
|
||||||
if (!state.IsValid()) {
|
if (!state.IsValid()) {
|
||||||
@ -1836,7 +1836,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
|
|||||||
}.Check(request);
|
}.Check(request);
|
||||||
|
|
||||||
uint256 hash(ParseHashV(request.params[0], "blockhash"));
|
uint256 hash(ParseHashV(request.params[0], "blockhash"));
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
|
|
||||||
CBlockIndex* pblockindex;
|
CBlockIndex* pblockindex;
|
||||||
{
|
{
|
||||||
@ -1886,7 +1886,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
|
|||||||
::ChainstateActive().ResetBlockFailureFlags(pblockindex);
|
::ChainstateActive().ResetBlockFailureFlags(pblockindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
::ChainstateActive().ActivateBestChain(state, Params());
|
::ChainstateActive().ActivateBestChain(state, Params());
|
||||||
|
|
||||||
if (!state.IsValid()) {
|
if (!state.IsValid()) {
|
||||||
|
@ -326,7 +326,7 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const CMu
|
|||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
if (!CheckSpecialTx(CTransaction(tx), ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) {
|
if (!CheckSpecialTx(CTransaction(tx), ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) {
|
||||||
throw std::runtime_error(FormatStateMessage(state));
|
throw std::runtime_error(FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,7 @@ static UniValue generateblock(const JSONRPCRequest& request)
|
|||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
|
if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
|
||||||
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.GetRejectReason()));
|
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.GetRejectReason()));
|
||||||
}
|
}
|
||||||
@ -483,7 +483,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
|
|
||||||
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
|
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
|
||||||
static UniValue BIP22ValidationResult(const CValidationState& state)
|
static UniValue BIP22ValidationResult(const BlockValidationState& state)
|
||||||
{
|
{
|
||||||
if (state.IsValid())
|
if (state.IsValid())
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
@ -670,7 +670,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
|
|||||||
// TestBlockValidity only supports blocks built on the current Tip
|
// TestBlockValidity only supports blocks built on the current Tip
|
||||||
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
||||||
return "inconclusive-not-best-prevblk";
|
return "inconclusive-not-best-prevblk";
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true);
|
TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true);
|
||||||
return BIP22ValidationResult(state);
|
return BIP22ValidationResult(state);
|
||||||
}
|
}
|
||||||
@ -951,12 +951,12 @@ class submitblock_StateCatcher : public CValidationInterface
|
|||||||
public:
|
public:
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
bool found;
|
bool found;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
|
|
||||||
explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
|
explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
|
void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override {
|
||||||
if (block.GetHash() != hash)
|
if (block.GetHash() != hash)
|
||||||
return;
|
return;
|
||||||
found = true;
|
found = true;
|
||||||
@ -1046,8 +1046,8 @@ static UniValue submitheader(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params(), /* ppindex */ nullptr, /* first_invalid */ nullptr);
|
EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params());
|
||||||
if (state.IsValid()) return NullUniValue;
|
if (state.IsValid()) return NullUniValue;
|
||||||
if (state.IsError()) {
|
if (state.IsError()) {
|
||||||
throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state));
|
throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state));
|
||||||
|
@ -918,20 +918,21 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
|||||||
UniValue result_0(UniValue::VOBJ);
|
UniValue result_0(UniValue::VOBJ);
|
||||||
result_0.pushKV("txid", tx_hash.GetHex());
|
result_0.pushKV("txid", tx_hash.GetHex());
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
bool missing_inputs;
|
|
||||||
bool test_accept_res;
|
bool test_accept_res;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
test_accept_res = AcceptToMemoryPool(::ChainstateActive(), mempool, state, std::move(tx), &missing_inputs,
|
test_accept_res = AcceptToMemoryPool(::ChainstateActive(), mempool, state, std::move(tx),
|
||||||
false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true);
|
false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true);
|
||||||
}
|
}
|
||||||
result_0.pushKV("allowed", test_accept_res);
|
result_0.pushKV("allowed", test_accept_res);
|
||||||
if (!test_accept_res) {
|
if (!test_accept_res) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
|
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
||||||
} else if (missing_inputs) {
|
result_0.pushKV("reject-reason", "missing-inputs");
|
||||||
result_0.pushKV("reject-reason", "missing-inputs");
|
} else {
|
||||||
|
result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result_0.pushKV("reject-reason", state.GetRejectReason());
|
result_0.pushKV("reject-reason", state.GetRejectReason());
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <util/spanparsing.h>
|
#include <util/spanparsing.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -549,22 +550,13 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Construct a vector with one element, which is moved into it. */
|
|
||||||
template<typename T>
|
|
||||||
std::vector<T> Singleton(T elem)
|
|
||||||
{
|
|
||||||
std::vector<T> ret;
|
|
||||||
ret.emplace_back(std::move(elem));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A parsed addr(A) descriptor. */
|
/** A parsed addr(A) descriptor. */
|
||||||
class AddressDescriptor final : public DescriptorImpl
|
class AddressDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
const CTxDestination m_destination;
|
const CTxDestination m_destination;
|
||||||
protected:
|
protected:
|
||||||
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
|
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(m_destination)); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
|
||||||
public:
|
public:
|
||||||
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
|
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
|
||||||
bool IsSolvable() const final { return false; }
|
bool IsSolvable() const final { return false; }
|
||||||
@ -576,7 +568,7 @@ class RawDescriptor final : public DescriptorImpl
|
|||||||
const CScript m_script;
|
const CScript m_script;
|
||||||
protected:
|
protected:
|
||||||
std::string ToStringExtra() const override { return HexStr(m_script); }
|
std::string ToStringExtra() const override { return HexStr(m_script); }
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(m_script); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
|
||||||
public:
|
public:
|
||||||
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
|
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
|
||||||
bool IsSolvable() const final { return false; }
|
bool IsSolvable() const final { return false; }
|
||||||
@ -586,9 +578,9 @@ public:
|
|||||||
class PKDescriptor final : public DescriptorImpl
|
class PKDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForRawPubKey(keys[0])); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
|
||||||
public:
|
public:
|
||||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pk") {}
|
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A parsed pkh(P) descriptor. */
|
/** A parsed pkh(P) descriptor. */
|
||||||
@ -599,10 +591,10 @@ protected:
|
|||||||
{
|
{
|
||||||
CKeyID id = keys[0].GetID();
|
CKeyID id = keys[0].GetID();
|
||||||
out.pubkeys.emplace(id, keys[0]);
|
out.pubkeys.emplace(id, keys[0]);
|
||||||
return Singleton(GetScriptForDestination(PKHash(id)));
|
return Vector(GetScriptForDestination(PKHash(id)));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {}
|
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A parsed multi(...) or sortedmulti(...) descriptor */
|
/** A parsed multi(...) or sortedmulti(...) descriptor */
|
||||||
@ -616,9 +608,9 @@ protected:
|
|||||||
if (m_sorted) {
|
if (m_sorted) {
|
||||||
std::vector<CPubKey> sorted_keys(keys);
|
std::vector<CPubKey> sorted_keys(keys);
|
||||||
std::sort(sorted_keys.begin(), sorted_keys.end());
|
std::sort(sorted_keys.begin(), sorted_keys.end());
|
||||||
return Singleton(GetScriptForMultisig(m_threshold, sorted_keys));
|
return Vector(GetScriptForMultisig(m_threshold, sorted_keys));
|
||||||
}
|
}
|
||||||
return Singleton(GetScriptForMultisig(m_threshold, keys));
|
return Vector(GetScriptForMultisig(m_threshold, keys));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
|
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
|
||||||
@ -628,7 +620,7 @@ public:
|
|||||||
class SHDescriptor final : public DescriptorImpl
|
class SHDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
|
||||||
public:
|
public:
|
||||||
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
|
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
|
||||||
};
|
};
|
||||||
@ -653,7 +645,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "combo") {}
|
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -118,22 +118,6 @@ static void RunTest(const TestVector &test) {
|
|||||||
}
|
}
|
||||||
key = keyNew;
|
key = keyNew;
|
||||||
pubkey = pubkeyNew;
|
pubkey = pubkeyNew;
|
||||||
|
|
||||||
CDataStream ssPub(SER_DISK, CLIENT_VERSION);
|
|
||||||
ssPub << pubkeyNew;
|
|
||||||
BOOST_CHECK(ssPub.size() == 75);
|
|
||||||
|
|
||||||
CDataStream ssPriv(SER_DISK, CLIENT_VERSION);
|
|
||||||
ssPriv << keyNew;
|
|
||||||
BOOST_CHECK(ssPriv.size() == 75);
|
|
||||||
|
|
||||||
CExtPubKey pubCheck;
|
|
||||||
CExtKey privCheck;
|
|
||||||
ssPub >> pubCheck;
|
|
||||||
ssPriv >> privCheck;
|
|
||||||
|
|
||||||
BOOST_CHECK(pubCheck == pubkeyNew);
|
|
||||||
BOOST_CHECK(privCheck == keyNew);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +100,8 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
|
|||||||
block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
|
block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
|
||||||
CBlockHeader header = block->GetBlockHeader();
|
CBlockHeader header = block->GetBlockHeader();
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
|
if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,12 +294,12 @@ void FuncDIP3Protx(TestChainSetup& setup)
|
|||||||
// payload itself. This means, we need to rely on script verification, which takes the hash of the extra payload
|
// payload itself. This means, we need to rely on script verification, which takes the hash of the extra payload
|
||||||
// into account
|
// into account
|
||||||
auto tx2 = MalleateProTxPayout<CProRegTx>(tx);
|
auto tx2 = MalleateProTxPayout<CProRegTx>(tx);
|
||||||
CValidationState dummyState;
|
TxValidationState dummy_state;
|
||||||
// Technically, the payload is still valid...
|
// Technically, the payload is still valid...
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true));
|
BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
|
||||||
BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true));
|
BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
|
||||||
}
|
}
|
||||||
// But the signature should not verify anymore
|
// But the signature should not verify anymore
|
||||||
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
|
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
|
||||||
@ -401,11 +401,11 @@ void FuncDIP3Protx(TestChainSetup& setup)
|
|||||||
tx = CreateProUpRegTx(*(setup.m_node.mempool), utxos, dmnHashes[0], ownerKeys[dmnHashes[0]], newOperatorKey.GetPublicKey(), ownerKeys[dmnHashes[0]].GetPubKey().GetID(), dmn->pdmnState->scriptPayout, setup.coinbaseKey);
|
tx = CreateProUpRegTx(*(setup.m_node.mempool), utxos, dmnHashes[0], ownerKeys[dmnHashes[0]], newOperatorKey.GetPublicKey(), ownerKeys[dmnHashes[0]].GetPubKey().GetID(), dmn->pdmnState->scriptPayout, setup.coinbaseKey);
|
||||||
// check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx
|
// check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx
|
||||||
auto tx2 = MalleateProTxPayout<CProUpRegTx>(tx);
|
auto tx2 = MalleateProTxPayout<CProUpRegTx>(tx);
|
||||||
CValidationState dummyState;
|
TxValidationState dummy_state;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true));
|
BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
|
||||||
BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true));
|
BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true));
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
|
BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx));
|
||||||
BOOST_ASSERT(!CheckTransactionSignature(*(setup.m_node.mempool), tx2));
|
BOOST_ASSERT(!CheckTransactionSignature(*(setup.m_node.mempool), tx2));
|
||||||
|
@ -36,17 +36,17 @@ FUZZ_TARGET_INIT(block, initialize_block)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Consensus::Params& consensus_params = Params().GetConsensus();
|
const Consensus::Params& consensus_params = Params().GetConsensus();
|
||||||
CValidationState validation_state_pow_and_merkle;
|
BlockValidationState validation_state_pow_and_merkle;
|
||||||
const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true);
|
const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true);
|
||||||
assert(validation_state_pow_and_merkle.IsValid() || validation_state_pow_and_merkle.IsInvalid() || validation_state_pow_and_merkle.IsError());
|
assert(validation_state_pow_and_merkle.IsValid() || validation_state_pow_and_merkle.IsInvalid() || validation_state_pow_and_merkle.IsError());
|
||||||
(void)validation_state_pow_and_merkle.Error("");
|
(void)validation_state_pow_and_merkle.Error("");
|
||||||
CValidationState validation_state_pow;
|
BlockValidationState validation_state_pow;
|
||||||
const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false);
|
const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false);
|
||||||
assert(validation_state_pow.IsValid() || validation_state_pow.IsInvalid() || validation_state_pow.IsError());
|
assert(validation_state_pow.IsValid() || validation_state_pow.IsInvalid() || validation_state_pow.IsError());
|
||||||
CValidationState validation_state_merkle;
|
BlockValidationState validation_state_merkle;
|
||||||
const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true);
|
const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true);
|
||||||
assert(validation_state_merkle.IsValid() || validation_state_merkle.IsInvalid() || validation_state_merkle.IsError());
|
assert(validation_state_merkle.IsValid() || validation_state_merkle.IsInvalid() || validation_state_merkle.IsError());
|
||||||
CValidationState validation_state_none;
|
BlockValidationState validation_state_none;
|
||||||
const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false);
|
const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false);
|
||||||
assert(validation_state_none.IsValid() || validation_state_none.IsInvalid() || validation_state_none.IsError());
|
assert(validation_state_none.IsValid() || validation_state_none.IsInvalid() || validation_state_none.IsError());
|
||||||
if (valid_incl_pow_and_merkle) {
|
if (valid_incl_pow_and_merkle) {
|
||||||
|
@ -223,12 +223,12 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
|
|||||||
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
|
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
|
||||||
},
|
},
|
||||||
[&] {
|
[&] {
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
CAmount tx_fee_out;
|
CAmount tx_fee_out;
|
||||||
const CTransaction transaction{random_mutable_transaction};
|
const CTransaction transaction{random_mutable_transaction};
|
||||||
if (ContainsSpentInput(transaction, coins_view_cache)) {
|
if (ContainsSpentInput(transaction, coins_view_cache)) {
|
||||||
// Avoid:
|
// Avoid:
|
||||||
// consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, CValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
|
// consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState&, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -60,7 +60,7 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state_with_dupe_check;
|
TxValidationState state_with_dupe_check;
|
||||||
(void)CheckTransaction(tx, state_with_dupe_check);
|
(void)CheckTransaction(tx, state_with_dupe_check);
|
||||||
|
|
||||||
std::string reason;
|
std::string reason;
|
||||||
|
@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(findCommonAncestor)
|
|||||||
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
||||||
auto* orig_tip = active.Tip();
|
auto* orig_tip = active.Tip();
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
ChainstateActive().InvalidateBlock(state, Params(), active.Tip());
|
ChainstateActive().InvalidateBlock(state, Params(), active.Tip());
|
||||||
}
|
}
|
||||||
BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10);
|
BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10);
|
||||||
|
@ -536,7 +536,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
|
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
|
||||||
} // unlock cs_main while calling InvalidateBlock
|
} // unlock cs_main while calling InvalidateBlock
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip()));
|
::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip()));
|
||||||
|
|
||||||
SetMockTime(0);
|
SetMockTime(0);
|
||||||
|
@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
|||||||
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
stream >> tx;
|
stream >> tx;
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
|
BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
|
|
||||||
|
@ -18,15 +18,15 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state)
|
bool VerifyMNHFTx(const CTransaction& tx, TxValidationState& state)
|
||||||
{
|
{
|
||||||
MNHFTxPayload mnhfTx;
|
MNHFTxPayload mnhfTx;
|
||||||
if (!GetTxPayload(tx, mnhfTx)) {
|
if (!GetTxPayload(tx, mnhfTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests)
|
|||||||
BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash));
|
BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash));
|
||||||
|
|
||||||
const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver);
|
const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver);
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state));
|
BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
|||||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
CTransaction tx(deserialize, stream);
|
CTransaction tx(deserialize, stream);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
|||||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
CTransaction tx(deserialize, stream);
|
CTransaction tx(deserialize, stream);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
fValid = CheckTransaction(tx, state) && state.IsValid();
|
fValid = CheckTransaction(tx, state) && state.IsValid();
|
||||||
|
|
||||||
PrecomputedTransactionData txdata(tx);
|
PrecomputedTransactionData txdata(tx);
|
||||||
@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
|||||||
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
||||||
CMutableTransaction tx;
|
CMutableTransaction tx;
|
||||||
stream >> tx;
|
stream >> tx;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
||||||
|
|
||||||
// Check that duplicate txins fail
|
// Check that duplicate txins fail
|
||||||
|
@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
|||||||
|
|
||||||
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
|
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
@ -39,7 +39,6 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
|||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
false,
|
false,
|
||||||
AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx),
|
AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx),
|
||||||
nullptr /* pfMissingInputs */,
|
|
||||||
true /* bypass_limits */,
|
true /* bypass_limits */,
|
||||||
0 /* nAbsurdFee */));
|
0 /* nAbsurdFee */));
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
|||||||
// Check that the validation state reflects the unsuccessful attempt.
|
// Check that the validation state reflects the unsuccessful attempt.
|
||||||
BOOST_CHECK(state.IsInvalid());
|
BOOST_CHECK(state.IsInvalid());
|
||||||
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
|
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
|
||||||
BOOST_CHECK(state.GetReason() == ValidationInvalidReason::CONSENSUS);
|
BOOST_CHECK(state.GetResult() == TxValidationResult::TX_CONSENSUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
|
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(txvalidationcache_tests)
|
BOOST_AUTO_TEST_SUITE(txvalidationcache_tests)
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
|||||||
const auto ToMemPool = [this](const CMutableTransaction& tx) {
|
const auto ToMemPool = [this](const CMutableTransaction& tx) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState validationState;
|
||||||
return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */,
|
return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, validationState, MakeTransactionRef(tx),
|
||||||
true /* bypass_limits */, 0 /* nAbsurdFee */);
|
true /* bypass_limits */, 0 /* nAbsurdFee */);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
|||||||
// If we add many more flags, this loop can get too expensive, but we can
|
// If we add many more flags, this loop can get too expensive, but we can
|
||||||
// rewrite in the future to randomly pick a set of flags to evaluate.
|
// rewrite in the future to randomly pick a set of flags to evaluate.
|
||||||
for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) {
|
for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) {
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
// Filter out incompatible flag choices
|
// Filter out incompatible flag choices
|
||||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
||||||
// CLEANSTACK requires P2SH, see VerifyScript() in
|
// CLEANSTACK requires P2SH, see VerifyScript() in
|
||||||
@ -193,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData ptd_spend_tx;
|
PrecomputedTransactionData ptd_spend_tx;
|
||||||
|
|
||||||
BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
||||||
@ -262,7 +262,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
|
|
||||||
// Make it valid, and check again
|
// Make it valid, and check again
|
||||||
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData txdata;
|
PrecomputedTransactionData txdata;
|
||||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
|
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
|
|
||||||
// Make it valid, and check again
|
// Make it valid, and check again
|
||||||
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData txdata;
|
PrecomputedTransactionData txdata;
|
||||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
||||||
}
|
}
|
||||||
|
@ -253,7 +253,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
|
|||||||
m_node.connman->Init(options);
|
m_node.connman->Init(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!::ChainstateActive().ActivateBestChain(state, chainparams)) {
|
if (!::ChainstateActive().ActivateBestChain(state, chainparams)) {
|
||||||
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
|
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns,
|
|||||||
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
||||||
BOOST_ASSERT(false);
|
BOOST_ASSERT(false);
|
||||||
}
|
}
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!CalcCbTxMerkleRootMNList(block, ::ChainActive().Tip(), cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
|
if (!CalcCbTxMerkleRootMNList(block, ::ChainActive().Tip(), cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) {
|
||||||
BOOST_ASSERT(false);
|
BOOST_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ignored;
|
bool ignored;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
std::vector<CBlockHeader> headers;
|
std::vector<CBlockHeader> headers;
|
||||||
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
|
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
|
||||||
|
|
||||||
@ -296,14 +296,13 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
|
|||||||
// Add the txs to the tx pool
|
// Add the txs to the tx pool
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
for (const auto& tx : txs) {
|
for (const auto& tx : txs) {
|
||||||
BOOST_REQUIRE(AcceptToMemoryPool(
|
BOOST_REQUIRE(AcceptToMemoryPool(
|
||||||
::ChainstateActive(),
|
::ChainstateActive(),
|
||||||
*m_node.mempool,
|
*m_node.mempool,
|
||||||
state,
|
state,
|
||||||
tx,
|
tx,
|
||||||
/* pfMissingInputs */ &ignored,
|
|
||||||
/* bypass_limits */ false,
|
/* bypass_limits */ false,
|
||||||
/* nAbsurdFee */ 0));
|
/* nAbsurdFee */ 0));
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
|
|||||||
WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23));
|
WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23));
|
||||||
// Unlike c1, which doesn't have any blocks. Gets us different tip, height.
|
// Unlike c1, which doesn't have any blocks. Gets us different tip, height.
|
||||||
c2.LoadGenesisBlock(chainparams);
|
c2.LoadGenesisBlock(chainparams);
|
||||||
CValidationState _;
|
BlockValidationState dummy_state;
|
||||||
BOOST_CHECK(c2.ActivateBestChain(_, chainparams, nullptr));
|
BOOST_CHECK(c2.ActivateBestChain(dummy_state, chainparams, nullptr));
|
||||||
|
|
||||||
BOOST_CHECK(manager.IsSnapshotActive());
|
BOOST_CHECK(manager.IsSnapshotActive());
|
||||||
BOOST_CHECK(!manager.IsSnapshotValidated());
|
BOOST_CHECK(!manager.IsSnapshotValidated());
|
||||||
|
@ -1023,9 +1023,9 @@ void CTxMemPool::clear()
|
|||||||
|
|
||||||
static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight)
|
static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight)
|
||||||
{
|
{
|
||||||
CValidationState state;
|
TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass
|
||||||
CAmount txfee = 0;
|
CAmount txfee = 0;
|
||||||
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee);
|
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee);
|
||||||
assert(fCheckResult);
|
assert(fCheckResult);
|
||||||
UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max());
|
UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max());
|
||||||
}
|
}
|
||||||
@ -1207,7 +1207,7 @@ void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
|
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
|
||||||
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()};
|
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
|
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
|
||||||
|
@ -343,8 +343,11 @@ struct TxMempoolInfo
|
|||||||
/** Time the transaction entered the mempool. */
|
/** Time the transaction entered the mempool. */
|
||||||
std::chrono::seconds m_time;
|
std::chrono::seconds m_time;
|
||||||
|
|
||||||
/** Feerate of the transaction. */
|
/** Fee of the transaction. */
|
||||||
CFeeRate feeRate;
|
CAmount fee;
|
||||||
|
|
||||||
|
/** Virtual size of the transaction. */
|
||||||
|
size_t vsize;
|
||||||
|
|
||||||
/** The fee delta. */
|
/** The fee delta. */
|
||||||
int64_t nFeeDelta;
|
int64_t nFeeDelta;
|
||||||
|
@ -8,11 +8,10 @@
|
|||||||
#include <consensus/validation.h>
|
#include <consensus/validation.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
|
|
||||||
/** Convert CValidationState to a human-readable message for logging */
|
/** Convert ValidationState to a human-readable message for logging */
|
||||||
std::string FormatStateMessage(const CValidationState &state)
|
std::string FormatStateMessage(const ValidationState &state)
|
||||||
{
|
{
|
||||||
return strprintf("%s%s (code %i)",
|
return strprintf("%s%s",
|
||||||
state.GetRejectReason(),
|
state.GetRejectReason(),
|
||||||
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
|
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage());
|
||||||
state.GetRejectCode());
|
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class CValidationState;
|
class ValidationState;
|
||||||
|
|
||||||
/** Convert CValidationState to a human-readable message for logging */
|
/** Convert ValidationState to a human-readable message for logging */
|
||||||
std::string FormatStateMessage(const CValidationState &state);
|
std::string FormatStateMessage(const ValidationState &state);
|
||||||
|
|
||||||
#endif // BITCOIN_UTIL_VALIDATION_H
|
#endif // BITCOIN_UTIL_VALIDATION_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,7 @@ class CQuorumBlockProcessor;
|
|||||||
class CEvoDB;
|
class CEvoDB;
|
||||||
|
|
||||||
class CChainState;
|
class CChainState;
|
||||||
|
class BlockValidationState;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CBlockTreeDB;
|
class CBlockTreeDB;
|
||||||
class CBlockUndo;
|
class CBlockUndo;
|
||||||
@ -52,7 +53,7 @@ class CInv;
|
|||||||
class CConnman;
|
class CConnman;
|
||||||
class CScriptCheck;
|
class CScriptCheck;
|
||||||
class CTxMemPool;
|
class CTxMemPool;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
class ChainstateManager;
|
class ChainstateManager;
|
||||||
struct PrecomputedTransactionData;
|
struct PrecomputedTransactionData;
|
||||||
struct ChainTxData;
|
struct ChainTxData;
|
||||||
@ -215,8 +216,8 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
|
|||||||
void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
|
void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
|
||||||
|
|
||||||
/** (try to) add transaction to memory pool */
|
/** (try to) add transaction to memory pool */
|
||||||
bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
|
bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||||
bool* pfMissingInputs, bool bypass_limits,
|
bool bypass_limits,
|
||||||
const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin);
|
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin);
|
||||||
@ -315,10 +316,10 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
|
|||||||
/** Functions for validating blocks and updating the block tree */
|
/** Functions for validating blocks and updating the block tree */
|
||||||
|
|
||||||
/** Context-independent validity checks */
|
/** Context-independent validity checks */
|
||||||
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
/** Check a block is completely valid from start to finish (only works on top of our current best block) */
|
/** Check a block is completely valid from start to finish (only works on top of our current best block) */
|
||||||
bool TestBlockValidity(CValidationState& state,
|
bool TestBlockValidity(BlockValidationState& state,
|
||||||
llmq::CChainLocksHandler& clhandler,
|
llmq::CChainLocksHandler& clhandler,
|
||||||
CEvoDB& evoDb,
|
CEvoDB& evoDb,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
@ -454,7 +455,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool AcceptBlockHeader(
|
bool AcceptBlockHeader(
|
||||||
const CBlockHeader& block,
|
const CBlockHeader& block,
|
||||||
CValidationState& state,
|
BlockValidationState& state,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
@ -681,7 +682,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool FlushStateToDisk(
|
bool FlushStateToDisk(
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
CValidationState &state,
|
BlockValidationState &state,
|
||||||
FlushStateMode mode,
|
FlushStateMode mode,
|
||||||
int nManualPruneHeight = 0);
|
int nManualPruneHeight = 0);
|
||||||
|
|
||||||
@ -708,29 +709,29 @@ public:
|
|||||||
* @returns true unless a system error occurred
|
* @returns true unless a system error occurred
|
||||||
*/
|
*/
|
||||||
bool ActivateBestChain(
|
bool ActivateBestChain(
|
||||||
CValidationState& state,
|
BlockValidationState& state,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
std::shared_ptr<const CBlock> pblock = nullptr) LOCKS_EXCLUDED(cs_main);
|
std::shared_ptr<const CBlock> pblock = nullptr) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
// Block (dis)connection on a given view:
|
// Block (dis)connection on a given view:
|
||||||
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
// Apply the effects of a block disconnection on the UTXO set.
|
// Apply the effects of a block disconnection on the UTXO set.
|
||||||
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
|
bool DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
|
||||||
|
|
||||||
// Manual block validity manipulation:
|
// Manual block validity manipulation:
|
||||||
/** Mark a block as precious and reorganize.
|
/** Mark a block as precious and reorganize.
|
||||||
*
|
*
|
||||||
* May not be called in a validationinterface callback.
|
* May not be called in a validationinterface callback.
|
||||||
*/
|
*/
|
||||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
bool PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
/** Mark a block as invalid. */
|
/** Mark a block as invalid. */
|
||||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
bool InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
/** Enforce a block marking all the other chains as conflicting. */
|
/** Enforce a block marking all the other chains as conflicting. */
|
||||||
void EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
void EnforceBlock(BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
/** Remove invalidity status from a block and its descendants. */
|
/** Remove invalidity status from a block and its descendants. */
|
||||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
@ -738,7 +739,7 @@ public:
|
|||||||
bool ReplayBlocks(const CChainParams& params);
|
bool ReplayBlocks(const CChainParams& params);
|
||||||
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
|
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
|
||||||
bool LoadGenesisBlock(const CChainParams& chainparams);
|
bool LoadGenesisBlock(const CChainParams& chainparams);
|
||||||
bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
void PruneBlockIndexCandidates();
|
void PruneBlockIndexCandidates();
|
||||||
|
|
||||||
@ -774,10 +775,10 @@ public:
|
|||||||
std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
|
bool ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
|
||||||
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
|
bool ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs);
|
||||||
|
|
||||||
void InvalidBlockFound(CBlockIndex* pindex, const CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
@ -785,7 +786,7 @@ private:
|
|||||||
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
//! Mark a block as conflicting
|
//! Mark a block as conflicting
|
||||||
bool MarkConflictingBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool MarkConflictingBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
//! Mark a block as not having block data
|
//! Mark a block as not having block data
|
||||||
void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
@ -990,7 +991,7 @@ public:
|
|||||||
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
|
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
|
||||||
* @param[out] first_invalid First header that fails validation, if one exists
|
* @param[out] first_invalid First header that fails validation, if one exists
|
||||||
*/
|
*/
|
||||||
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main);
|
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex
|
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex
|
||||||
bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
@ -1031,14 +1032,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
|
|||||||
*/
|
*/
|
||||||
bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
|
bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
|
||||||
|
|
||||||
/** Reject codes greater or equal to this can be returned by AcceptToMemPool
|
|
||||||
* for transactions, to signal internal conditions. They cannot and should not
|
|
||||||
* be sent over the P2P network.
|
|
||||||
*/
|
|
||||||
static const unsigned int REJECT_INTERNAL = 0x100;
|
|
||||||
/** Too high fee. Can not be triggered by P2P transactions */
|
|
||||||
static const unsigned int REJECT_HIGHFEE = 0x100;
|
|
||||||
|
|
||||||
/** Get block file info entry for one block file */
|
/** Get block file info entry for one block file */
|
||||||
CBlockFileInfo* GetBlockFileInfo(size_t n);
|
CBlockFileInfo* GetBlockFileInfo(size_t n);
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ struct MainSignalsInstance {
|
|||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
|
||||||
boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
|
boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
||||||
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
||||||
boost::signals2::signal<void (const CBlockIndex *)>AcceptedBlockHeader;
|
boost::signals2::signal<void (const CBlockIndex *)>AcceptedBlockHeader;
|
||||||
boost::signals2::signal<void (const CBlockIndex *, bool)>NotifyHeaderTip;
|
boost::signals2::signal<void (const CBlockIndex *, bool)>NotifyHeaderTip;
|
||||||
@ -198,7 +198,7 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
|
void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
||||||
m_internals->BlockChecked(block, state);
|
m_internals->BlockChecked(block, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
|
class BlockValidationState;
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
struct CBlockLocator;
|
struct CBlockLocator;
|
||||||
class CConnman;
|
class CConnman;
|
||||||
class CValidationInterface;
|
class CValidationInterface;
|
||||||
class CValidationState;
|
|
||||||
class CGovernanceVote;
|
class CGovernanceVote;
|
||||||
class CGovernanceObject;
|
class CGovernanceObject;
|
||||||
class CDeterministicMNList;
|
class CDeterministicMNList;
|
||||||
@ -185,11 +185,11 @@ protected:
|
|||||||
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
||||||
/**
|
/**
|
||||||
* Notifies listeners of a block validation result.
|
* Notifies listeners of a block validation result.
|
||||||
* If the provided CValidationState IsValid, the provided block
|
* If the provided BlockValidationState IsValid, the provided block
|
||||||
* is guaranteed to be the current best block at the time the
|
* is guaranteed to be the current best block at the time the
|
||||||
* callback was generated (not necessarily now)
|
* callback was generated (not necessarily now)
|
||||||
*/
|
*/
|
||||||
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
|
virtual void BlockChecked(const CBlock&, const BlockValidationState&) {}
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a block which builds directly on our current tip
|
* Notifies listeners that a block which builds directly on our current tip
|
||||||
* has been received and connected to the headers tree, though not validated yet */
|
* has been received and connected to the headers tree, though not validated yet */
|
||||||
@ -236,7 +236,7 @@ public:
|
|||||||
void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig);
|
void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig);
|
||||||
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman);
|
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman);
|
||||||
void ChainStateFlushed(const CBlockLocator &);
|
void ChainStateFlushed(const CBlockLocator &);
|
||||||
void BlockChecked(const CBlock&, const CValidationState&);
|
void BlockChecked(const CBlock&, const BlockValidationState&);
|
||||||
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
|
|||||||
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
|
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
|
||||||
"Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
|
"Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
|
||||||
CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE);
|
CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE);
|
||||||
argsman.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)",
|
argsman.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data. 0 to entirely disable the fallbackfee feature. (default: %s)",
|
||||||
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE);
|
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE);
|
||||||
argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",
|
argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",
|
||||||
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
|
@ -2315,7 +2315,7 @@ static UniValue settxfee(const JSONRPCRequest& request)
|
|||||||
CAmount nAmount = AmountFromValue(request.params[0]);
|
CAmount nAmount = AmountFromValue(request.params[0]);
|
||||||
CFeeRate tx_fee_rate(nAmount, 1000);
|
CFeeRate tx_fee_rate(nAmount, 1000);
|
||||||
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
|
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
|
||||||
if (tx_fee_rate == 0) {
|
if (tx_fee_rate == CFeeRate(0)) {
|
||||||
// automatic selection
|
// automatic selection
|
||||||
} else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
|
} else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
|
||||||
|
@ -178,6 +178,7 @@ public:
|
|||||||
int nChangePosRet = -1;
|
int nChangePosRet = -1;
|
||||||
bilingual_str strError;
|
bilingual_str strError;
|
||||||
CCoinControl coinControl;
|
CCoinControl coinControl;
|
||||||
|
coinControl.m_feerate = CFeeRate(1000);
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
BOOST_CHECK(reserveDest.GetReservedDestination(tallyItem.txdest, false));
|
BOOST_CHECK(reserveDest.GetReservedDestination(tallyItem.txdest, false));
|
||||||
|
@ -38,6 +38,10 @@ extern RecursiveMutex cs_wallets;
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr CAmount fallbackFee = 1000;
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
|
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
|
||||||
{
|
{
|
||||||
DatabaseOptions options;
|
DatabaseOptions options;
|
||||||
@ -869,7 +873,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
coinControl.Select(GetCoins({{100000, false}})[0]);
|
coinControl.Select(GetCoins({{100000, false}})[0]);
|
||||||
|
|
||||||
// Start with fallback feerate
|
// Start with fallback feerate
|
||||||
runTest(1, DEFAULT_FALLBACK_FEE, {
|
runTest(1, fallbackFee, {
|
||||||
{0, {true, ChangeTest::ChangeExpected}},
|
{0, {true, ChangeTest::ChangeExpected}},
|
||||||
{1, {true, ChangeTest::ChangeExpected}},
|
{1, {true, ChangeTest::ChangeExpected}},
|
||||||
{2, {true, ChangeTest::ChangeExpected}},
|
{2, {true, ChangeTest::ChangeExpected}},
|
||||||
@ -886,7 +890,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
{13, {false, ChangeTest::Skip}}
|
{13, {false, ChangeTest::Skip}}
|
||||||
});
|
});
|
||||||
// Now with 100x fallback feerate
|
// Now with 100x fallback feerate
|
||||||
runTest(2, DEFAULT_FALLBACK_FEE * 100, {
|
runTest(2, fallbackFee * 100, {
|
||||||
{0, {true, ChangeTest::ChangeExpected}},
|
{0, {true, ChangeTest::ChangeExpected}},
|
||||||
{1, {false, ChangeTest::Skip}},
|
{1, {false, ChangeTest::Skip}},
|
||||||
{2, {true, ChangeTest::ChangeExpected}},
|
{2, {true, ChangeTest::ChangeExpected}},
|
||||||
@ -912,7 +916,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start with fallback feerate
|
// Start with fallback feerate
|
||||||
runTest(3, DEFAULT_FALLBACK_FEE, {
|
runTest(3, fallbackFee, {
|
||||||
{0, {true, ChangeTest::ChangeExpected}},
|
{0, {true, ChangeTest::ChangeExpected}},
|
||||||
{1, {false, ChangeTest::Skip}},
|
{1, {false, ChangeTest::Skip}},
|
||||||
{2, {true, ChangeTest::ChangeExpected}},
|
{2, {true, ChangeTest::ChangeExpected}},
|
||||||
@ -929,7 +933,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
{13, {false, ChangeTest::Skip}}
|
{13, {false, ChangeTest::Skip}}
|
||||||
});
|
});
|
||||||
// Now with 100x fallback feerate
|
// Now with 100x fallback feerate
|
||||||
runTest(4, DEFAULT_FALLBACK_FEE * 100, {
|
runTest(4, fallbackFee * 100, {
|
||||||
{0, {true, ChangeTest::ChangeExpected}},
|
{0, {true, ChangeTest::ChangeExpected}},
|
||||||
{1, {false, ChangeTest::Skip}},
|
{1, {false, ChangeTest::Skip}},
|
||||||
{2, {true, ChangeTest::ChangeExpected}},
|
{2, {true, ChangeTest::ChangeExpected}},
|
||||||
@ -958,7 +962,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start with fallback feerate
|
// Start with fallback feerate
|
||||||
runTest(5, DEFAULT_FALLBACK_FEE, {
|
runTest(5, fallbackFee, {
|
||||||
{0, {true, ChangeTest::ChangeExpected}},
|
{0, {true, ChangeTest::ChangeExpected}},
|
||||||
{1, {false, ChangeTest::Skip}},
|
{1, {false, ChangeTest::Skip}},
|
||||||
{2, {true, ChangeTest::ChangeExpected}},
|
{2, {true, ChangeTest::ChangeExpected}},
|
||||||
@ -975,7 +979,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
{13, {false, ChangeTest::Skip}}
|
{13, {false, ChangeTest::Skip}}
|
||||||
});
|
});
|
||||||
// Now with 100x fallback feerate
|
// Now with 100x fallback feerate
|
||||||
runTest(6, DEFAULT_FALLBACK_FEE * 100, {
|
runTest(6, fallbackFee * 100, {
|
||||||
{0, {false, ChangeTest::Skip}},
|
{0, {false, ChangeTest::Skip}},
|
||||||
{1, {false, ChangeTest::Skip}},
|
{1, {false, ChangeTest::Skip}},
|
||||||
{2, {false, ChangeTest::Skip}},
|
{2, {false, ChangeTest::Skip}},
|
||||||
@ -996,6 +1000,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
// which inputs to use
|
// which inputs to use
|
||||||
{
|
{
|
||||||
coinControl.SetNull();
|
coinControl.SetNull();
|
||||||
|
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||||
auto setCoins = GetCoins({{1000, false}, {1000, false}, {1000, false}, {1000, false}, {1000, false},
|
auto setCoins = GetCoins({{1000, false}, {1000, false}, {1000, false}, {1000, false}, {1000, false},
|
||||||
{1100, false}, {1200, false}, {1300, false}, {1400, false}, {1500, false},
|
{1100, false}, {1200, false}, {1300, false}, {1400, false}, {1500, false},
|
||||||
{3000, false}, {3000, false}, {2000, false}, {2000, false}, {1000, false}});
|
{3000, false}, {3000, false}, {2000, false}, {2000, false}, {1000, false}});
|
||||||
@ -1044,6 +1049,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
// Test if the change output ends up at the requested position
|
// Test if the change output ends up at the requested position
|
||||||
{
|
{
|
||||||
coinControl.SetNull();
|
coinControl.SetNull();
|
||||||
|
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||||
coinControl.Select(GetCoins({{100000, false}})[0]);
|
coinControl.Select(GetCoins({{100000, false}})[0]);
|
||||||
|
|
||||||
BOOST_CHECK(CreateTransaction({{25000, false}, {25000, false}, {25000, false}}, {}, 0, true, ChangeTest::ChangeExpected));
|
BOOST_CHECK(CreateTransaction({{25000, false}, {25000, false}, {25000, false}}, {}, 0, true, ChangeTest::ChangeExpected));
|
||||||
@ -1054,6 +1060,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
// Test error cases
|
// Test error cases
|
||||||
{
|
{
|
||||||
coinControl.SetNull();
|
coinControl.SetNull();
|
||||||
|
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||||
// First try to send something without any coins available
|
// First try to send something without any coins available
|
||||||
{
|
{
|
||||||
// Lock all other coins
|
// Lock all other coins
|
||||||
@ -1090,6 +1097,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
|
|||||||
};
|
};
|
||||||
|
|
||||||
coinControl.SetNull();
|
coinControl.SetNull();
|
||||||
|
coinControl.m_feerate = CFeeRate(fallbackFee);
|
||||||
coinControl.Select(GetCoins({{100 * COIN, false}})[0]);
|
coinControl.Select(GetCoins({{100 * COIN, false}})[0]);
|
||||||
|
|
||||||
BOOST_CHECK(CreateTransaction({{-5000, false}}, strAmountNotNegative, false));
|
BOOST_CHECK(CreateTransaction({{-5000, false}}, strAmountNotNegative, false));
|
||||||
|
@ -4610,7 +4610,6 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
|
|||||||
walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
|
walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
|
||||||
}
|
}
|
||||||
|
|
||||||
walletInstance->m_allow_fallback_fee = Params().IsTestChain();
|
|
||||||
if (gArgs.IsArgSet("-fallbackfee")) {
|
if (gArgs.IsArgSet("-fallbackfee")) {
|
||||||
std::optional<CAmount> fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", ""));
|
std::optional<CAmount> fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", ""));
|
||||||
if (!fallback_fee) {
|
if (!fallback_fee) {
|
||||||
@ -4621,8 +4620,10 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
|
|||||||
_("This is the transaction fee you may pay when fee estimates are not available."));
|
_("This is the transaction fee you may pay when fee estimates are not available."));
|
||||||
}
|
}
|
||||||
walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
|
walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
|
||||||
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0; //disable fallback fee in case value was set to 0, enable if non-null value
|
|
||||||
}
|
}
|
||||||
|
// Disable fallback fee in case value was set to 0, enable if non-null value
|
||||||
|
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-discardfee")) {
|
if (gArgs.IsArgSet("-discardfee")) {
|
||||||
std::optional<CAmount> discard_fee = ParseMoney(gArgs.GetArg("-discardfee", ""));
|
std::optional<CAmount> discard_fee = ParseMoney(gArgs.GetArg("-discardfee", ""));
|
||||||
if (!discard_fee) {
|
if (!discard_fee) {
|
||||||
|
@ -67,7 +67,7 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
|
|||||||
//! -paytxfee default
|
//! -paytxfee default
|
||||||
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
|
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
|
||||||
//! -fallbackfee default
|
//! -fallbackfee default
|
||||||
static const CAmount DEFAULT_FALLBACK_FEE = 1000;
|
static const CAmount DEFAULT_FALLBACK_FEE = 0;
|
||||||
//! -discardfee default
|
//! -discardfee default
|
||||||
static const CAmount DEFAULT_DISCARD_FEE = 10000;
|
static const CAmount DEFAULT_DISCARD_FEE = 10000;
|
||||||
//! -mintxfee default
|
//! -mintxfee default
|
||||||
@ -1070,7 +1070,7 @@ public:
|
|||||||
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
|
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
|
||||||
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
|
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
|
||||||
bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
|
bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
|
||||||
bool m_allow_fallback_fee{true}; //!< will be defined via chainparams
|
bool m_allow_fallback_fee{true}; //!< will be false if -fallbackfee=0
|
||||||
CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee
|
CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee
|
||||||
/**
|
/**
|
||||||
* If fee estimation does not have enough data to provide estimates, use this fee instead.
|
* If fee estimation does not have enough data to provide estimates, use this fee instead.
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
#include <wallet/walletdb.h>
|
#include <wallet/walletdb.h>
|
||||||
|
|
||||||
#include <consensus/tx_check.h>
|
|
||||||
#include <consensus/validation.h>
|
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <governance/object.h>
|
#include <governance/object.h>
|
||||||
@ -255,8 +253,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
ssKey >> hash;
|
ssKey >> hash;
|
||||||
CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
|
CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
|
||||||
ssValue >> wtx;
|
ssValue >> wtx;
|
||||||
CValidationState state;
|
if (wtx.GetHash() != hash)
|
||||||
if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Undo serialize changes in 31600
|
// Undo serialize changes in 31600
|
||||||
|
@ -22,7 +22,7 @@ SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift
|
|||||||
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
||||||
|
|
||||||
# RPC error for non-BIP68 final transactions
|
# RPC error for non-BIP68 final transactions
|
||||||
NOT_FINAL_ERROR = "non-BIP68-final (code 64)"
|
NOT_FINAL_ERROR = "non-BIP68-final"
|
||||||
|
|
||||||
class BIP68Test(BitcoinTestFramework):
|
class BIP68Test(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
|
@ -130,7 +130,7 @@ class BIP65Test(BitcoinTestFramework):
|
|||||||
|
|
||||||
# First we show that this tx is valid except for CLTV by getting it
|
# First we show that this tx is valid except for CLTV by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
block.vtx.append(spendtx)
|
block.vtx.append(spendtx)
|
||||||
|
@ -112,7 +112,7 @@ class BIP66Test(BitcoinTestFramework):
|
|||||||
|
|
||||||
# First we show that this tx is valid except for DERSIG by getting it
|
# First we show that this tx is valid except for DERSIG by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
block.vtx.append(spendtx)
|
block.vtx.append(spendtx)
|
||||||
|
@ -232,7 +232,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
|
|||||||
|
|
||||||
# Assert that the conflicting tx got mined and the locked TX is not valid
|
# Assert that the conflicting tx got mined and the locked TX is not valid
|
||||||
assert self.nodes[0].getrawtransaction(rawtx1_txid, True)['confirmations'] > 0
|
assert self.nodes[0].getrawtransaction(rawtx1_txid, True)['confirmations'] > 0
|
||||||
assert_raises_rpc_error(-25, "Missing inputs", self.nodes[0].sendrawtransaction, rawtx2)
|
assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[0].sendrawtransaction, rawtx2)
|
||||||
|
|
||||||
# Create the block and the corresponding clsig but do not relay clsig yet
|
# Create the block and the corresponding clsig but do not relay clsig yet
|
||||||
cl_block = self.create_block(self.nodes[0])
|
cl_block = self.create_block(self.nodes[0])
|
||||||
|
@ -20,7 +20,7 @@ from test_framework.test_framework import BitcoinTestFramework
|
|||||||
from test_framework.util import assert_equal, assert_raises_rpc_error
|
from test_framework.util import assert_equal, assert_raises_rpc_error
|
||||||
|
|
||||||
|
|
||||||
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)"
|
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
|
||||||
|
|
||||||
def trueDummy(tx):
|
def trueDummy(tx):
|
||||||
scriptSig = CScript(tx.vin[0].scriptSig)
|
scriptSig = CScript(tx.vin[0].scriptSig)
|
||||||
|
@ -77,7 +77,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
node.generate(1)
|
node.generate(1)
|
||||||
self.mempool_size = 0
|
self.mempool_size = 0
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': '18: txn-already-known'}],
|
result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}],
|
||||||
rawtxs=[raw_tx_in_block],
|
rawtxs=[raw_tx_in_block],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
node.sendrawtransaction(hexstring=raw_tx_0)
|
node.sendrawtransaction(hexstring=raw_tx_0)
|
||||||
self.mempool_size += 1
|
self.mempool_size += 1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': '18: txn-already-in-mempool'}],
|
result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}],
|
||||||
rawtxs=[raw_tx_0],
|
rawtxs=[raw_tx_0],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
txid_0_reject = tx.rehash()
|
txid_0_reject = tx.rehash()
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
# No RBF in DASH
|
# No RBF in DASH
|
||||||
result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],
|
result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
|
||||||
rawtxs=[raw_tx_0_reject],
|
rawtxs=[raw_tx_0_reject],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
|
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
|
||||||
# skip re-signing the tx
|
# skip re-signing the tx
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
maxfeerate=0,
|
maxfeerate=0,
|
||||||
)
|
)
|
||||||
@ -199,7 +199,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
# Skip re-signing the transaction for context independent checks from now on
|
# Skip re-signing the transaction for context independent checks from now on
|
||||||
# tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
|
# tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize()))
|
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize()))
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].nValue *= -1
|
tx.vout[0].nValue *= -1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -224,7 +224,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].nValue = MAX_MONEY + 1
|
tx.vout[0].nValue = MAX_MONEY + 1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vout = [tx.vout[0]] * 2
|
tx.vout = [tx.vout[0]] * 2
|
||||||
tx.vout[0].nValue = MAX_MONEY
|
tx.vout[0].nValue = MAX_MONEY
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin = [tx.vin[0]] * 2
|
tx.vin = [tx.vin[0]] * 2
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
|
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'coinbase'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -258,13 +258,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.nVersion = 4 # A version currently non-standard
|
tx.nVersion = 4 # A version currently non-standard
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
|
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
@ -273,25 +273,25 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
pubkey = key.get_pubkey().get_bytes()
|
pubkey = key.get_pubkey().get_bytes()
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3)
|
tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3)
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: bare-multisig'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
|
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
@ -299,21 +299,21 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy
|
num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy
|
||||||
tx.vout = [output_p2sh_burn] * num_scripts
|
tx.vout = [output_p2sh_burn] * num_scripts
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0] = output_p2sh_burn
|
tx.vout[0] = output_p2sh_burn
|
||||||
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
|
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
||||||
tx.vout = [tx.vout[0]] * 2
|
tx.vout = [tx.vout[0]] * 2
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -322,7 +322,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored
|
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored
|
||||||
tx.nLockTime = node.getblockcount() + 1
|
tx.nLockTime = node.getblockcount() + 1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-final'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -331,7 +331,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
|
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
|
||||||
# Can skip re-signing the tx because of early rejection
|
# Can skip re-signing the tx because of early rejection
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
maxfeerate=0,
|
maxfeerate=0,
|
||||||
)
|
)
|
||||||
|
@ -151,7 +151,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)
|
rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)
|
||||||
|
|
||||||
# This will raise an exception since there are missing inputs
|
# This will raise an exception since there are missing inputs
|
||||||
assert_raises_rpc_error(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex'])
|
assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx['hex'])
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
# getrawtransaction with block hash #
|
# getrawtransaction with block hash #
|
||||||
@ -388,7 +388,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
# Thus, testmempoolaccept should reject
|
# Thus, testmempoolaccept should reject
|
||||||
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
|
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
|
||||||
assert_equal(testres['allowed'], False)
|
assert_equal(testres['allowed'], False)
|
||||||
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
|
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
|
||||||
# and sendrawtransaction should throw
|
# and sendrawtransaction should throw
|
||||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
||||||
# and the following calls should both succeed
|
# and the following calls should both succeed
|
||||||
@ -412,7 +412,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
# Thus, testmempoolaccept should reject
|
# Thus, testmempoolaccept should reject
|
||||||
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
|
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
|
||||||
assert_equal(testres['allowed'], False)
|
assert_equal(testres['allowed'], False)
|
||||||
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
|
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
|
||||||
# and sendrawtransaction should throw
|
# and sendrawtransaction should throw
|
||||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
|
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
|
||||||
# and the following calls should both succeed
|
# and the following calls should both succeed
|
||||||
|
@ -340,6 +340,7 @@ def initialize_datadir(dirname, n, chain):
|
|||||||
f.write("[{}]\n".format(chain_name_conf_section))
|
f.write("[{}]\n".format(chain_name_conf_section))
|
||||||
f.write("port=" + str(p2p_port(n)) + "\n")
|
f.write("port=" + str(p2p_port(n)) + "\n")
|
||||||
f.write("rpcport=" + str(rpc_port(n)) + "\n")
|
f.write("rpcport=" + str(rpc_port(n)) + "\n")
|
||||||
|
f.write("fallbackfee=0.00001\n")
|
||||||
f.write("server=1\n")
|
f.write("server=1\n")
|
||||||
f.write("keypool=1\n")
|
f.write("keypool=1\n")
|
||||||
f.write("discover=0\n")
|
f.write("discover=0\n")
|
||||||
|
Loading…
Reference in New Issue
Block a user