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
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())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-empty");
// Size limits
if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize");
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-payload-oversize");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-payload-oversize");
// Check for negative or overflow output values (see CVE-2010-5139)
CAmount nValueOut = 0;
for (const auto& txout : tx.vout) {
if (txout.nValue < 0)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-negative");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-negative");
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;
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)
@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
std::set<COutPoint> vInOutPoints;
for (const auto& txin : tx.vin) {
if (!vInOutPoints.insert(txin.prevout).second)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
}
if (tx.IsCoinBase()) {
@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
minCbSize = 1;
}
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-length");
} else {
for (const auto& txin : tx.vin)
if (txin.prevout.IsNull())
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-prevout-null");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null");
}
return true;

View File

@ -162,7 +162,8 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
{
// are the actual inputs available?
if (!inputs.HaveInputs(tx)) {
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", strprintf("%s: inputs missing/spent", __func__));
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
strprintf("%s: inputs missing/spent", __func__));
}
CAmount nValueIn = 0;
@ -173,25 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
// If prev is coinbase, check that it's matured
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
return state.Invalid(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
nValueIn += coin.out.nValue;
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputvalues-outofrange");
}
}
const CAmount value_out = tx.GetValueOut();
if (nValueIn < value_out) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout", strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-in-belowout",
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
}
// Tally transaction fees
const CAmount txfee_aux = nValueIn - value_out;
if (!MoneyRange(txfee_aux)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange");
}
txfee = txfee_aux;

View File

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

View File

@ -18,30 +18,30 @@
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
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()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-invalid");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-invalid");
}
CCbTx 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) {
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) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-height");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-height");
}
if (pindexPrev) {
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
if (fDIP0008Active && cbTx.nVersion < 2) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version");
}
}
@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
CCbTx cbTx;
if (!GetTxPayload(*block.vtx[0], cbTx)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload");
}
int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
return false;
}
if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-mnmerkleroot");
}
int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
return false;
}
if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-quorummerkleroot");
}
}
@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
if (sml == smlCached) {
merkleRootRet = merkleRootCached;
if (mutatedCached) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-cached-calc-cb-mnmerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-cached-calc-cb-mnmerkleroot");
}
return true;
}
@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
mutatedCached = mutated;
if (mutated) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cb-mnmerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cb-mnmerkleroot");
}
return true;
} catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-calc-cb-mnmerkleroot");
return state.Invalid(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);
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
auto [qcHashes, qcIndexedHashes] = retVal.value();
@ -249,7 +249,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
llmq::CFinalCommitmentTxPayload qc;
if (!GetTxPayload(*tx, qc)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload-calc-cbtx-quorummerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload-calc-cbtx-quorummerkleroot");
}
if (qc.commitment.IsNull()) {
// having null commitments is ok but we don't use them here, move to the next tx
@ -257,7 +257,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
}
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
}
const auto& llmq_params = llmq_params_opt.value();
auto qcHash = ::SerializeHash(qc.commitment);
@ -291,7 +291,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "excess-quorums-calc-cbtx-quorummerkleroot");
}
// Copy vec_hashes into vec_hashes_final
std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final));
@ -308,7 +308,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);
if (mutated) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cbtx-quorummerkleroot");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cbtx-quorummerkleroot");
}
return true;

View File

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

View File

@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
return true;
if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) {
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type");
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type");
}
try {
@ -46,10 +46,10 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
}
} catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-check-special-tx");
return state.Invalid(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)
@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
return true; // handled per block
}
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-tx-type-proc");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-tx-type-proc");
}
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);
} catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-procspectxsinblock");
}
return true;

View File

@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
const auto numCommitmentsInNewBlock = qcs.count(params.type);
if (numCommitmentsRequired < numCommitmentsInNewBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-not-allowed");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-not-allowed");
}
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)) {
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()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block");
}
if (quorumHash != qc.quorumHash) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block");
}
if (qc.IsNull()) {
if (!qc.VerifyNull()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null");
}
return true;
}
if (HasMinedCommitment(llmq_params.type, quorumHash)) {
// should not happen as it's already handled in ProcessBlock
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup");
}
if (!IsMiningPhase(llmq_params, nHeight)) {
// should not happen as it's already handled in ProcessBlock
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height");
}
const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash);
@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid");
}
if (fJustCheck) {
@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
if (!GetTxPayload(*tx, qc)) {
// should not happen as it was verified before processing the block
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload");
}
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
// should not happen as it was verified before processing the block
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type");
}
// only allow one commitment per type and per block (This was changed with rotation)
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
if (ret.count(qc.commitment.llmqType) != 0) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
return state.Invalid(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()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-premature");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-premature");
}
return true;

View File

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

View File

@ -173,8 +173,8 @@ namespace {
int nSyncStarted GUARDED_BY(cs_main) = 0;
/**
* Sources of received blocks, saved to be able to send them reject
* messages or ban them when processing happens afterwards.
* Sources of received blocks, saved to be able punish them when processing
* happens afterwards.
* Set mapBlockSource[hash].second to false if the node should not be
* punished if the block is invalid.
*/
@ -1513,11 +1513,12 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
const uint256 hash(block.GetHash());
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
if (state.IsInvalid()) {
// Don't send reject message with code 0 or an internal reject code.
if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) {
// If the block failed validation, we know where it came from and we're still connected
// to that peer, maybe punish.
if (state.IsInvalid() &&
it != mapBlockSource.end() &&
State(it->second.first)) {
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
}
}
// Check that:
// 1. The block is valid
@ -2523,25 +2524,6 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
connman.PushMessage(&peer, std::move(msg));
}
std::string RejectCodeToString(const unsigned char code)
{
if (code == REJECT_MALFORMED)
return "malformed";
if (code == REJECT_INVALID)
return "invalid";
if (code == REJECT_OBSOLETE)
return "obsolete";
if (code == REJECT_DUPLICATE)
return "duplicate";
if (code == REJECT_NONSTANDARD)
return "nonstandard";
if (code == REJECT_INSUFFICIENTFEE)
return "insufficientfee";
if (code == REJECT_CHECKPOINT)
return "checkpoint";
return "";
}
std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx)
{
if (!dstx.IsValidStructure()) {
@ -3750,11 +3732,12 @@ void PeerLogicValidation::ProcessMessage(
// been run). This is handled below, so just treat this as
// though the block was successfully read, and rely on the
// handling in ProcessNewBlock to ensure the block index is
// updated, reject messages go out, etc.
// updated, etc.
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
fBlockRead = true;
// mapBlockSource is only used for sending reject messages and DoS scores,
// so the race between here and cs_main in ProcessNewBlock is fine.
// mapBlockSource is used for potentially punishing peers and
// updating which peers send us compact blocks, so the race
// between here and cs_main in ProcessNewBlock is fine.
// BIP 152 permits peers to relay compact blocks after validating
// the header only; we should not punish peers if the block turns
// out to be invalid.
@ -3835,8 +3818,9 @@ void PeerLogicValidation::ProcessMessage(
// Also always process if we requested the block explicitly, as we may
// need it even though it is not a candidate for a new best tip.
forceProcessing |= MarkBlockAsReceived(hash);
// mapBlockSource is only used for sending reject messages and DoS scores,
// so the race between here and cs_main in ProcessNewBlock is fine.
// mapBlockSource is only used for punishing peers and setting
// which peers send us compact blocks, so the race between here and
// cs_main in ProcessNewBlock is fine.
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
}
bool fNewBlock = false;

View File

@ -929,7 +929,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
result_0.pushKV("allowed", test_accept_res);
if (!test_accept_res) {
if (state.IsInvalid()) {
result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
} else if (missing_inputs) {
result_0.pushKV("reject-reason", "missing-inputs");
} else {

View File

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

View File

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

View File

@ -379,18 +379,18 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
tx.nType != TRANSACTION_COINBASE &&
tx.nType != TRANSACTION_QUORUM_COMMITMENT &&
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)
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) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type");
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type");
}
}
// Size limits
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;
}
@ -597,11 +597,11 @@ private:
{
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
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)) {
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;
}
@ -655,35 +655,35 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
// 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
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)
std::string 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.
// 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
// 64-byte transactions.
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
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
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?
if (m_pool.exists(hash)) {
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);
@ -693,7 +693,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (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)) {
@ -707,7 +707,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (ptxConflicting)
{
// 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++) {
// Optimistically just do efficient check of cache for outputs
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
@ -757,7 +757,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// CoinsViewCache instead of create its own
assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
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));
CAmount nFees = 0;
@ -767,7 +767,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Check for non-standard pay-to-script-hash in inputs
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);
@ -792,7 +792,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
unsigned int nSize = entry->GetTxSize();
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));
// No transactions are allowed below minRelayTxFee except from disconnected
@ -801,8 +801,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (nAbsurdFee && nFees > nAbsurdFee)
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false,
REJECT_HIGHFEE, "absurdly-high-fee",
strprintf("%d > %d", nFees, nAbsurdFee));
"absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
// Calculate in-mempool ancestors, up to a limit.
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
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)) {
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;
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;
@ -935,7 +934,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
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)});
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;
}
@ -1593,7 +1592,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
CScriptCheck check2(coin.out, tx, i,
(flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata);
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
// 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
// depends on the details of how net_processing handles
// 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())) {
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
@ -2214,7 +2213,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
for (const auto& tx : block.vtx) {
for (size_t o = 0; o < tx->vout.size(); 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 &&
chainparams.GetConsensus().nSuperblockStartHash != uint256() &&
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
@ -2289,13 +2288,14 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// defined for a block, so we reset the reason flag to
// CONSENSUS here.
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));
}
nFees += txfee;
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
@ -2307,7 +2307,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
}
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)
@ -2357,7 +2358,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// * p2sh (when P2SH enabled in flags and excludes coinbase)
nSigOps += GetTransactionSigOpCount(tx, view, flags);
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())
@ -2374,7 +2376,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// consider whether rewriting to CONSENSUS or
// RECENT_CONSENSUS_CHANGE would be more appropriate.
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
state.GetRejectReason(), state.GetDebugMessage());
}
return error("ConnectBlock(): CheckInputs on %s failed with %s",
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);
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;
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 {
// The node which relayed this should switch to correct chain.
// 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)) {
// 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;
@ -2481,7 +2483,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) {
// 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;
@ -3806,13 +3808,13 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
{
// Check proof of work matches claimed amount
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
if (!consensusParams.hashDevnetGenesisBlock.IsNull() &&
block.hashPrevBlock == consensusParams.hashGenesisBlock &&
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;
@ -3837,13 +3839,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
bool mutated;
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
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
// of transactions in a block without affecting the merkle root of a block,
// while still invalidating it.
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
@ -3852,19 +3854,19 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
// Size limits (relaxed)
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
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++)
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
for (const auto& tx : block.vtx)
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()));
unsigned int nSigOps = 0;
@ -3874,7 +3876,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
}
// sigops limits (relaxed)
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)
block.fChecked = true;
@ -3926,10 +3928,10 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
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),
REJECT_INVALID, "bad-diffbits");
"bad-diffbits");
} else {
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
@ -3940,22 +3942,23 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints());
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
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
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
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
(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;
}
@ -3988,14 +3991,14 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// Size limits
unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context);
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
// Also count sigops
unsigned int nSigOps = 0;
for (const auto& tx : block.vtx) {
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)) {
return false;
@ -4005,7 +4008,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// Check sigops
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
// 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;
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
!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 (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)
*ppindex = pindex;
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)
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;
}
@ -4057,16 +4060,16 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
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;
assert(pindexPrev);
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)
// 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()))
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);
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) {
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)
@ -4324,7 +4327,7 @@ bool TestBlockValidity(CValidationState& state,
uint256 hash = block.GetHash();
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());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -388,7 +388,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
# and sendrawtransaction should throw
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
# and the following calls should both succeed
@ -412,7 +412,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
# and sendrawtransaction should throw
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
# and the following calls should both succeed