Merge #17004: validation: Remove REJECT code from CValidationState

9075d13153ce06cd59a45644831ecc43126e1e82 [docs] Add release notes for removal of REJECT reasons (John Newbery)
04a2f326ec0f06fb4fce1c4f93500752f05dede8 [validation] Fix REJECT message comments (John Newbery)
e9d5a59e34ff2d538d8f5315efd9908bf24d0fdc [validation] Remove REJECT code from CValidationState (John Newbery)
0053e16714323c1694c834fdca74f064a1a33529 [logging] Don't log REJECT code when transaction is rejected (John Newbery)
a1a07cfe99fc8cee30ba5976dc36b47b1f6532ab [validation] Fix peer punishment for bad blocks (John Newbery)

Pull request description:

  We no longer send BIP 61 REJECT messages, so there's no need to set
  a REJECT code in the CValidationState object.

  Note that there is a minor bug fix in p2p behaviour here. Because the
  call to `MaybePunishNode()` in `PeerLogicValidation::BlockChecked()` only
  previously happened if the REJECT code was > 0 and < `REJECT_INTERNAL`,
  then there are cases were `MaybePunishNode()` can get called where it
  wasn't previously:

  - when `AcceptBlockHeader()` fails with `CACHED_INVALID`.
  - when `AcceptBlockHeader()` fails with `BLOCK_MISSING_PREV`.

  Note that `BlockChecked()` cannot fail with an 'internal' reject code. The
  only internal reject code was `REJECT_HIGHFEE`, which was only set in
  ATMP.

  This reverts a minor bug introduced in 5d08c9c579.

ACKs for top commit:
  ariard:
    ACK 9075d13, changes since last reviewed are splitting them in separate commits to ease understanding and fix nits
  fjahr:
    ACK 9075d13153ce06cd59a45644831ecc43126e1e82, confirmed diff to last review was fixing nits in docs/comments.
  ryanofsky:
    Code review ACK 9075d13153ce06cd59a45644831ecc43126e1e82. Only changes since last review are splitting the main commit and updating comments

Tree-SHA512: 58e8a1a4d4e6f156da5d29fb6ad6a62fc9c594bbfc6432b3252e962d0e9e10149bf3035185dc5320c46c09f3e49662bc2973ec759679c0f3412232087cb8a3a7
This commit is contained in:
Wladimir J. van der Laan 2019-10-24 10:43:02 +02:00 committed by PastaPastaPasta
parent 97b1f6875e
commit 091d813e00
22 changed files with 290 additions and 293 deletions

View File

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

View File

@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null");
} }
return true; return true;

View File

@ -162,7 +162,8 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
{ {
// 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(ValidationInvalidReason::TX_MISSING_INPUTS, false, "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(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange");
} }
txfee = txfee_aux; txfee = txfee_aux;

View File

@ -8,20 +8,8 @@
#include <string> #include <string>
/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
static const unsigned char REJECT_INVALID = 0x10;
static const unsigned char REJECT_OBSOLETE = 0x11;
static const unsigned char REJECT_DUPLICATE = 0x12;
static const unsigned char REJECT_NONSTANDARD = 0x40;
// static const unsigned char REJECT_DUST = 0x41; // part of BIP 61
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
static const unsigned char REJECT_CHECKPOINT = 0x43;
/** A "reason" why something was invalid, suitable for determining whether the /** A "reason" why something was invalid, suitable for determining whether the
* provider of the object should be banned/ignored/disconnected/etc. * 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 ValidationInvalidReason {
// txn and blocks: // txn and blocks:
@ -94,15 +82,13 @@ private:
} mode; } mode;
ValidationInvalidReason m_reason; ValidationInvalidReason m_reason;
std::string strRejectReason; std::string strRejectReason;
unsigned int chRejectCode;
std::string strDebugMessage; std::string strDebugMessage;
public: public:
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {} CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE) {}
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false, bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="", const std::string &strRejectReasonIn="",
const std::string &strDebugMessageIn="") { const std::string &strDebugMessageIn="") {
m_reason = reasonIn; m_reason = reasonIn;
chRejectCode = chRejectCodeIn;
strRejectReason = strRejectReasonIn; strRejectReason = strRejectReasonIn;
strDebugMessage = strDebugMessageIn; strDebugMessage = strDebugMessageIn;
if (mode == MODE_ERROR) if (mode == MODE_ERROR)
@ -126,7 +112,6 @@ public:
return mode == MODE_ERROR; return mode == MODE_ERROR;
} }
ValidationInvalidReason GetReason() const { return m_reason; } ValidationInvalidReason GetReason() const { return m_reason; }
unsigned int GetRejectCode() const { return chRejectCode; }
std::string GetRejectReason() const { return strRejectReason; } std::string GetRejectReason() const { return strRejectReason; }
std::string GetDebugMessage() const { return strDebugMessage; } std::string GetDebugMessage() const { return strDebugMessage; }
}; };

View File

@ -18,30 +18,30 @@
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-type");
} }
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-invalid"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version");
} }
} }
@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-quorummerkleroot");
} }
} }
@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "failed-calc-cb-mnmerkleroot");
} }
} }
@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cbtx-quorummerkleroot");
} }
return true; return true;

View File

@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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);
} }
@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash");
} }
HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs); HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs);
@ -1351,23 +1351,23 @@ template <typename ProTx>
static bool CheckService(const ProTx& proTx, CValidationState& state) static bool CheckService(const ProTx& proTx, CValidationState& 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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr");
} }
return true; return true;
@ -1377,35 +1377,35 @@ template <typename ProTx>
static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state) static bool CheckPlatformFields(const ProTx& proTx, CValidationState& 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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-dup-ports");
} }
return true; return true;
@ -1416,7 +1416,7 @@ static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, CValidationSt
{ {
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(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
} }
return true; return true;
} }
@ -1426,7 +1426,7 @@ static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, CValidation
{ {
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(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
} }
return true; return true;
} }
@ -1435,7 +1435,7 @@ template <typename ProTx>
static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state) static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
} }
return true; return true;
} }
@ -1443,16 +1443,16 @@ static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValid
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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, false, 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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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, false, std::string(maybe_err.error_str));
} }
if (keyForPayloadSig) { if (keyForPayloadSig) {
@ -1553,7 +1553,7 @@ 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(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
} }
} }
@ -1563,16 +1563,16 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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, false, 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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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, false, 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
@ -1631,66 +1631,66 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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, false, 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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "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, false, 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
@ -1704,26 +1704,26 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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, false, 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(ValidationInvalidReason::CONSENSUS, false, "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, false, std::string(maybe_err.error_str));
} }
if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) { if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) {
// pass the state returned by the function above // pass the state returned by the function above

View File

@ -38,29 +38,29 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidat
{ {
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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-invalid");
} }
return true; return true;

View File

@ -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(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type");
} }
try { try {
@ -46,10 +46,10 @@ 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(ValidationInvalidReason::CONSENSUS, false, "failed-check-special-tx");
} }
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type-check"); return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type-check");
} }
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state) bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state)
@ -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(ValidationInvalidReason::CONSENSUS, false, "bad-tx-type-proc");
} }
bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex) bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
@ -154,7 +154,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(ValidationInvalidReason::CONSENSUS, false, "failed-procspectxsinblock");
} }
return true; return true;

View File

@ -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(ValidationInvalidReason::CONSENSUS, false, "bad-qc-not-allowed");
} }
if (numCommitmentsRequired > numCommitmentsInNewBlock) { if (numCommitmentsRequired > numCommitmentsInNewBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "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);
@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid");
} }
if (fJustCheck) { if (fJustCheck) {
@ -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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-qc-premature");
} }
return true; return true;

View File

@ -181,13 +181,13 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid");
} }
LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight); LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight);

View File

@ -173,8 +173,8 @@ namespace {
int nSyncStarted GUARDED_BY(cs_main) = 0; int nSyncStarted GUARDED_BY(cs_main) = 0;
/** /**
* Sources of received blocks, saved to be able to send them reject * Sources of received blocks, saved to be able punish them when processing
* messages or ban them when processing happens afterwards. * happens afterwards.
* Set mapBlockSource[hash].second to false if the node should not be * Set mapBlockSource[hash].second to false if the node should not be
* punished if the block is invalid. * punished if the block is invalid.
*/ */
@ -1513,11 +1513,12 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
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() &&
it != mapBlockSource.end() &&
State(it->second.first)) {
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second); MaybePunishNode(/*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
@ -2523,25 +2524,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()) {
@ -3750,11 +3732,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 +3818,9 @@ void PeerLogicValidation::ProcessMessage(
// Also always process if we requested the block explicitly, as we may // Also always process if we requested the block explicitly, as we may
// need it even though it is not a candidate for a new best tip. // need it even though it is not a candidate for a new best tip.
forceProcessing |= MarkBlockAsReceived(hash); forceProcessing |= MarkBlockAsReceived(hash);
// mapBlockSource is only used for sending reject messages and DoS scores, // mapBlockSource is only used for punishing peers and setting
// so the race between here and cs_main in ProcessNewBlock is fine. // which peers send us compact blocks, so the race between here and
// cs_main in ProcessNewBlock is fine.
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true)); mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
} }
bool fNewBlock = false; bool fNewBlock = false;

View File

@ -929,7 +929,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
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())); result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
} else if (missing_inputs) { } else if (missing_inputs) {
result_0.pushKV("reject-reason", "missing-inputs"); result_0.pushKV("reject-reason", "missing-inputs");
} else { } else {

View File

@ -22,11 +22,11 @@ bool VerifyMNHFTx(const CTransaction& tx, CValidationState& 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(ValidationInvalidReason::CONSENSUS, false, "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(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version");
} }
return true; return true;

View File

@ -11,8 +11,7 @@
/** Convert CValidationState to a human-readable message for logging */ /** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state) std::string FormatStateMessage(const CValidationState &state)
{ {
return strprintf("%s%s (code %i)", return strprintf("%s%s",
state.GetRejectReason(), state.GetRejectReason(),
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(), state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage());
state.GetRejectCode());
} }

View File

@ -379,18 +379,18 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
tx.nType != TRANSACTION_COINBASE && tx.nType != TRANSACTION_COINBASE &&
tx.nType != TRANSACTION_QUORUM_COMMITMENT && tx.nType != TRANSACTION_QUORUM_COMMITMENT &&
tx.nType != TRANSACTION_MNHF_SIGNAL) { tx.nType != TRANSACTION_MNHF_SIGNAL) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type");
} }
if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE) if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-cb-type"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-cb-type");
} else if (tx.nType != TRANSACTION_NORMAL) { } else if (tx.nType != TRANSACTION_NORMAL) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type");
} }
} }
// Size limits // Size limits
if (fDIP0001Active_context && ::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE) if (fDIP0001Active_context && ::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize");
return true; return true;
} }
@ -597,11 +597,11 @@ private:
{ {
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
} }
if (package_fee < ::minRelayTxFee.GetFee(package_size)) { if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
} }
return true; return true;
} }
@ -655,35 +655,35 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) { if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
// quorum commitment is not allowed outside of blocks // quorum commitment is not allowed outside of blocks
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "qc-not-allowed"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "qc-not-allowed");
} }
// Coinbase is only valid in a block, not as a loose transaction // Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase()) if (tx.IsCoinBase())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "coinbase"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "coinbase");
// Rather not work on nonstandard transactions (unless -testnet/-regtest) // Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason; std::string reason;
if (fRequireStandard && !IsStandardTx(tx, reason)) if (fRequireStandard && !IsStandardTx(tx, reason))
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, reason); return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, reason);
// Do not work on transactions that are too small. // Do not work on transactions that are too small.
// A transaction with 1 empty scriptSig input and 1 P2SH output has size of 83 bytes. // A transaction with 1 empty scriptSig input and 1 P2SH output has size of 83 bytes.
// Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying // Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying
// 64-byte transactions. // 64-byte transactions.
if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE) if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE)
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "tx-size-small"); return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "tx-size-small");
// Only accept nLockTime-using transactions that can be mined in the next // Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't // block; we don't want our mempool filled up with transactions that can't
// be mined yet. // be mined yet.
if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-final"); return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-final");
// is it already in the memory pool? // is it already in the memory pool?
if (m_pool.exists(hash)) { if (m_pool.exists(hash)) {
statsClient.inc("transactions.duplicate", 1.0f); statsClient.inc("transactions.duplicate", 1.0f);
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-in-mempool"); return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-in-mempool");
} }
llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx); llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx);
@ -693,7 +693,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (txConflict) { if (txConflict) {
GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict); GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict);
} }
return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), REJECT_INVALID, "tx-txlock-conflict"); return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), "tx-txlock-conflict");
} }
if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) { if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) {
@ -707,7 +707,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (ptxConflicting) if (ptxConflicting)
{ {
// Transaction conflicts with mempool and RBF doesn't exist in Dash // Transaction conflicts with mempool and RBF doesn't exist in Dash
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-mempool-conflict"); return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-mempool-conflict");
} }
} }
} }
@ -731,7 +731,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
for (size_t out = 0; out < tx.vout.size(); out++) { for (size_t out = 0; out < tx.vout.size(); out++) {
// Optimistically just do efficient check of cache for outputs // Optimistically just do efficient check of cache for outputs
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) { if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known"); return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-known");
} }
} }
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
@ -757,7 +757,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// CoinsViewCache instead of create its own // CoinsViewCache instead of create its own
assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final"); return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-BIP68-final");
assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman)); assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman));
CAmount nFees = 0; CAmount nFees = 0;
@ -767,7 +767,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Check for non-standard pay-to-script-hash in inputs // Check for non-standard pay-to-script-hash in inputs
if (fRequireStandard && !AreInputsStandard(tx, m_view)) if (fRequireStandard && !AreInputsStandard(tx, m_view))
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs");
unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS); unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
@ -792,7 +792,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
unsigned int nSize = entry->GetTxSize(); unsigned int nSize = entry->GetTxSize();
if (nSigOps > MAX_STANDARD_TX_SIGOPS) if (nSigOps > MAX_STANDARD_TX_SIGOPS)
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops",
strprintf("%d", nSigOps)); strprintf("%d", nSigOps));
// No transactions are allowed below minRelayTxFee except from disconnected // No transactions are allowed below minRelayTxFee except from disconnected
@ -801,8 +801,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (nAbsurdFee && nFees > nAbsurdFee) if (nAbsurdFee && nFees > nAbsurdFee)
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false,
REJECT_HIGHFEE, "absurdly-high-fee", "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
strprintf("%d > %d", nFees, nAbsurdFee));
// Calculate in-mempool ancestors, up to a limit. // Calculate in-mempool ancestors, up to a limit.
std::string errString; std::string errString;
@ -822,7 +821,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { !m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString);
} }
} }
@ -834,7 +833,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return false; return false;
if (m_pool.existsProviderTxConflict(tx)) { if (m_pool.existsProviderTxConflict(tx)) {
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "protx-dup"); return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "protx-dup");
} }
return true; return true;
@ -935,7 +934,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip())); assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip()));
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
if (!m_pool.exists(hash)) if (!m_pool.exists(hash))
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full"); return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool full");
} }
return true; return true;
} }
@ -1593,7 +1592,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
CScriptCheck check2(coin.out, tx, i, CScriptCheck check2(coin.out, tx, i,
(flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata); (flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata);
if (check2()) if (check2())
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
} }
// MANDATORY flag failures correspond to // MANDATORY flag failures correspond to
// ValidationInvalidReason::CONSENSUS. Because CONSENSUS // ValidationInvalidReason::CONSENSUS. Because CONSENSUS
@ -1604,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// support, to avoid splitting the network (but this // support, to avoid splitting the network (but this
// depends on the details of how net_processing handles // depends on the details of how net_processing handles
// such errors). // such errors).
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
} }
} }
@ -2126,7 +2125,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
} }
if (pindex->pprev && pindex->phashBlock && m_clhandler->HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { if (pindex->pprev && pindex->phashBlock && m_clhandler->HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) {
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock"); return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), "bad-chainlock");
} }
// verify that the view's current state corresponds to the previous block // verify that the view's current state corresponds to the previous block
@ -2214,7 +2213,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
for (const auto& tx : block.vtx) { for (const auto& tx : block.vtx) {
for (size_t o = 0; o < tx->vout.size(); o++) { for (size_t o = 0; o < tx->vout.size(); o++) {
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), "bad-txns-BIP30");
} }
} }
} }
@ -2226,7 +2225,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (pindex->nHeight == chainparams.GetConsensus().nSuperblockStartBlock && if (pindex->nHeight == chainparams.GetConsensus().nSuperblockStartBlock &&
chainparams.GetConsensus().nSuperblockStartHash != uint256() && chainparams.GetConsensus().nSuperblockStartHash != uint256() &&
block_hash != chainparams.GetConsensus().nSuperblockStartHash) { block_hash != chainparams.GetConsensus().nSuperblockStartHash) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), REJECT_INVALID, "bad-sb-start"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), "bad-sb-start");
} }
/// END DASH /// END DASH
@ -2289,13 +2288,14 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// defined for a block, so we reset the reason flag to // defined for a block, so we reset the reason flag to
// CONSENSUS here. // CONSENSUS here.
state.Invalid(ValidationInvalidReason::CONSENSUS, false, state.Invalid(ValidationInvalidReason::CONSENSUS, false,
state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage()); state.GetRejectReason(), state.GetDebugMessage());
} }
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
} }
nFees += txfee; nFees += txfee;
if (!MoneyRange(nFees)) { if (!MoneyRange(nFees)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__), REJECT_INVALID, "bad-txns-accumulated-fee-outofrange"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__),
"bad-txns-accumulated-fee-outofrange");
} }
// Check that transaction is BIP68 final // Check that transaction is BIP68 final
@ -2307,7 +2307,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
} }
if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) { if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__),
"bad-txns-nonfinal");
} }
if (fAddressIndex || fSpentIndex) if (fAddressIndex || fSpentIndex)
@ -2357,7 +2358,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// * p2sh (when P2SH enabled in flags and excludes coinbase) // * p2sh (when P2SH enabled in flags and excludes coinbase)
nSigOps += GetTransactionSigOpCount(tx, view, flags); nSigOps += GetTransactionSigOpCount(tx, view, flags);
if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) { if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"),
"bad-blk-sigops");
} }
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
@ -2374,7 +2376,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// consider whether rewriting to CONSENSUS or // consider whether rewriting to CONSENSUS or
// RECENT_CONSENSUS_CHANGE would be more appropriate. // RECENT_CONSENSUS_CHANGE would be more appropriate.
state.Invalid(ValidationInvalidReason::CONSENSUS, false, state.Invalid(ValidationInvalidReason::CONSENSUS, false,
state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage()); state.GetRejectReason(), state.GetDebugMessage());
} }
return error("ConnectBlock(): CheckInputs on %s failed with %s", return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state)); tx.GetHash().ToString(), FormatStateMessage(state));
@ -2425,7 +2427,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
LogPrint(BCLog::BENCHMARK, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal); LogPrint(BCLog::BENCHMARK, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
if (!control.Wait()) if (!control.Wait())
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed");
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
LogPrint(BCLog::BENCHMARK, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal); LogPrint(BCLog::BENCHMARK, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
@ -2453,7 +2455,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
} else { } else {
// The node which relayed this should switch to correct chain. // The node which relayed this should switch to correct chain.
// TODO: relay instantsend data/proof. // TODO: relay instantsend data/proof.
return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), REJECT_INVALID, "conflict-tx-lock"); return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), "conflict-tx-lock");
} }
} }
} }
@ -2473,7 +2475,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (!IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) { if (!IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) {
// NOTE: Do not punish, the node might be missing governance data // NOTE: Do not punish, the node might be missing governance data
return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), REJECT_INVALID, "bad-cb-amount"); return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), "bad-cb-amount");
} }
int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2; int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2;
@ -2481,7 +2483,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) { if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) {
// NOTE: Do not punish, the node might be missing governance data // NOTE: Do not punish, the node might be missing governance data
return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), REJECT_INVALID, "bad-cb-payee"); return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), "bad-cb-payee");
} }
int64_t nTime5_4 = GetTimeMicros(); nTimePayeeValid += nTime5_4 - nTime5_3; int64_t nTime5_4 = GetTimeMicros(); nTimePayeeValid += nTime5_4 - nTime5_3;
@ -3806,13 +3808,13 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
{ {
// Check proof of work matches claimed amount // Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "high-hash", "proof of work failed"); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed");
// Check DevNet // Check DevNet
if (!consensusParams.hashDevnetGenesisBlock.IsNull() && if (!consensusParams.hashDevnetGenesisBlock.IsNull() &&
block.hashPrevBlock == consensusParams.hashGenesisBlock && block.hashPrevBlock == consensusParams.hashGenesisBlock &&
block.GetHash() != consensusParams.hashDevnetGenesisBlock) { block.GetHash() != consensusParams.hashDevnetGenesisBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), REJECT_INVALID, "devnet-genesis"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), "devnet-genesis");
} }
return true; return true;
@ -3837,13 +3839,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
bool mutated; bool mutated;
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
if (block.hashMerkleRoot != hashMerkleRoot2) if (block.hashMerkleRoot != hashMerkleRoot2)
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txnmrklroot", "hashMerkleRoot mismatch"); return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch");
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences // Check for merkle tree malleability (CVE-2012-2459): repeating sequences
// of transactions in a block without affecting the merkle root of a block, // of transactions in a block without affecting the merkle root of a block,
// while still invalidating it. // while still invalidating it.
if (mutated) if (mutated)
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txns-duplicate", "duplicate transaction"); return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction");
} }
// All potential-corruption validation must be done before we do any // All potential-corruption validation must be done before we do any
@ -3852,19 +3854,19 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
// Size limits (relaxed) // Size limits (relaxed)
if (block.vtx.empty() || block.vtx.size() > MaxBlockSize() || ::GetSerializeSize(block, PROTOCOL_VERSION) > MaxBlockSize()) if (block.vtx.empty() || block.vtx.size() > MaxBlockSize() || ::GetSerializeSize(block, PROTOCOL_VERSION) > MaxBlockSize())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed");
// First transaction must be coinbase, the rest must not be // First transaction must be coinbase, the rest must not be
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-missing", "first tx is not coinbase"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase");
for (unsigned int i = 1; i < block.vtx.size(); i++) for (unsigned int i = 1; i < block.vtx.size(); i++)
if (block.vtx[i]->IsCoinBase()) if (block.vtx[i]->IsCoinBase())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-multiple", "more than one coinbase"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
// Check transactions // Check transactions
for (const auto& tx : block.vtx) for (const auto& tx : block.vtx)
if (!CheckTransaction(*tx, state)) if (!CheckTransaction(*tx, state))
return state.Invalid(state.GetReason(), false, state.GetRejectCode(), state.GetRejectReason(), return state.Invalid(state.GetReason(), false, state.GetRejectReason(),
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
@ -3874,7 +3876,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
} }
// sigops limits (relaxed) // sigops limits (relaxed)
if (nSigOps > MaxBlockSigOps()) if (nSigOps > MaxBlockSigOps())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
if (fCheckPOW && fCheckMerkleRoot) if (fCheckPOW && fCheckMerkleRoot)
block.fChecked = true; block.fChecked = true;
@ -3926,10 +3928,10 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
if (abs(n1-n2) > n1*0.5) if (abs(n1-n2) > n1*0.5)
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1-n2), n1, n2, nHeight), return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1-n2), n1, n2, nHeight),
REJECT_INVALID, "bad-diffbits"); "bad-diffbits");
} else { } else {
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight)); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight));
} }
// Check against checkpoints // Check against checkpoints
@ -3940,22 +3942,23 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints()); CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight) if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint"); return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint");
} }
// Check timestamp against prev // Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast())); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast()));
// Check timestamp // Check timestamp
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME) if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, REJECT_INVALID, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60)); return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60));
// check for version 2, 3 and 4 upgrades // check for version 2, 3 and 4 upgrades
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) || (block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) (block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), strprintf("rejected nVersion=0x%08x block", block.nVersion)); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion),
strprintf("rejected nVersion=0x%08x block", block.nVersion));
return true; return true;
} }
@ -3988,14 +3991,14 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// Size limits // Size limits
unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context); unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context);
if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, PROTOCOL_VERSION) > nMaxBlockSize) if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, PROTOCOL_VERSION) > nMaxBlockSize)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed");
// Check that all transactions are finalized and not over-sized // Check that all transactions are finalized and not over-sized
// Also count sigops // Also count sigops
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
for (const auto& tx : block.vtx) { for (const auto& tx : block.vtx) {
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) { if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-nonfinal", "non-final transaction"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction");
} }
if (!ContextualCheckTransaction(*tx, state, consensusParams, pindexPrev)) { if (!ContextualCheckTransaction(*tx, state, consensusParams, pindexPrev)) {
return false; return false;
@ -4005,7 +4008,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// Check sigops // Check sigops
if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) if (nSigOps > MaxBlockSigOps(fDIP0001Active_context))
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
// Enforce rule that the coinbase starts with serialized block height // Enforce rule that the coinbase starts with serialized block height
// After DIP3/DIP4 activation, we don't enforce the height in the input script anymore. // After DIP3/DIP4 activation, we don't enforce the height in the input script anymore.
@ -4015,13 +4018,13 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
CScript expect = CScript() << nHeight; CScript expect = CScript() << nHeight;
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) { !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-height", "block height mismatch in coinbase"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase");
} }
} }
if (fDIP0003Active_context) { if (fDIP0003Active_context) {
if (block.vtx[0]->nType != TRANSACTION_COINBASE) { if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-type", "coinbase is not a CbTx"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-type", "coinbase is not a CbTx");
} }
} }
@ -4044,9 +4047,9 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
if (ppindex) if (ppindex)
*ppindex = pindex; *ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK) if (pindex->nStatus & BLOCK_FAILED_MASK)
return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), 0, "duplicate"); return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate");
if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK) if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK)
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), 0, "duplicate"); return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), "duplicate");
return true; return true;
} }
@ -4057,16 +4060,16 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
CBlockIndex* pindexPrev = nullptr; CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock); BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
if (mi == m_block_index.end()) if (mi == m_block_index.end())
return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), 0, "prev-blk-not-found"); return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found");
pindexPrev = (*mi).second; pindexPrev = (*mi).second;
assert(pindexPrev); assert(pindexPrev);
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK) if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK)
// it's ok-ish, the other node is probably missing the latest chainlock // it's ok-ish, the other node is probably missing the latest chainlock
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), REJECT_INVALID, "bad-prevblk-chainlock"); return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), "bad-prevblk-chainlock");
if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime())) if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
@ -4104,7 +4107,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
setDirtyBlockIndex.insert(invalid_walk); setDirtyBlockIndex.insert(invalid_walk);
invalid_walk = invalid_walk->pprev; invalid_walk = invalid_walk->pprev;
} }
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
} }
} }
} }
@ -4113,7 +4116,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
if (pindex == nullptr) { if (pindex == nullptr) {
AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK); AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK);
} }
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), REJECT_INVALID, "bad-chainlock"); return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), "bad-chainlock");
} }
} }
if (pindex == nullptr) if (pindex == nullptr)
@ -4324,7 +4327,7 @@ bool TestBlockValidity(CValidationState& state,
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock"); return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), "bad-chainlock");
} }
CCoinsViewCache viewNew(&chainstate.CoinsTip()); CCoinsViewCache viewNew(&chainstate.CoinsTip());

View File

@ -1031,14 +1031,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
*/ */
bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
/** Reject codes greater or equal to this can be returned by AcceptToMemPool
* for transactions, to signal internal conditions. They cannot and should not
* be sent over the P2P network.
*/
static const unsigned int REJECT_INTERNAL = 0x100;
/** Too high fee. Can not be triggered by P2P transactions */
static const unsigned int REJECT_HIGHFEE = 0x100;
/** Get block file info entry for one block file */ /** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n); CBlockFileInfo* GetBlockFileInfo(size_t n);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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