mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
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:
parent
97b1f6875e
commit
091d813e00
31
doc/release-notes-17004.md
Normal file
31
doc/release-notes-17004.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
P2P and network changes
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
#### Removal of reject network messages from Dash Core (BIP61)
|
||||||
|
|
||||||
|
The command line option to enable BIP61 (`-enablebip61`) has been removed.
|
||||||
|
|
||||||
|
This feature has been disabled by default since Dash Core version 0.19.0.
|
||||||
|
Nodes on the network can not generally be trusted to send valid ("reject")
|
||||||
|
messages, so this should only ever be used when connected to a trusted node.
|
||||||
|
|
||||||
|
Since Dash Core version 0.20.0 there are extra changes:
|
||||||
|
|
||||||
|
The removal of BIP61 REJECT message support also has the following minor RPC
|
||||||
|
and logging implications:
|
||||||
|
|
||||||
|
* `testmempoolaccept` and `sendrawtransaction` no longer return the P2P REJECT
|
||||||
|
code when a transaction is not accepted to the mempool. They still return the
|
||||||
|
verbal reject reason.
|
||||||
|
|
||||||
|
* Log messages that previously reported the REJECT code when a transaction was
|
||||||
|
not accepted to the mempool now no longer report the REJECT code. The reason
|
||||||
|
for rejection is still reported.
|
||||||
|
|
||||||
|
Updated RPCs
|
||||||
|
------------
|
||||||
|
|
||||||
|
- `testmempoolaccept` and `sendrawtransaction` no longer return the P2P REJECT
|
||||||
|
code when a transaction is not accepted to the mempool. See the Section
|
||||||
|
_Removal of reject network messages from Bitcoin Core (BIP61)_ for details on
|
||||||
|
the removal of BIP61 REJECT message support.
|
@ -19,25 +19,25 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
|
|
||||||
// Basic checks that don't depend on any context
|
// Basic checks that don't depend on any context
|
||||||
if (!allowEmptyTxInOut && tx.vin.empty())
|
if (!allowEmptyTxInOut && tx.vin.empty())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vin-empty");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vin-empty");
|
||||||
if (!allowEmptyTxInOut && tx.vout.empty())
|
if (!allowEmptyTxInOut && tx.vout.empty())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-empty");
|
||||||
// Size limits
|
// Size limits
|
||||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize");
|
||||||
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-payload-oversize");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-payload-oversize");
|
||||||
|
|
||||||
// Check for negative or overflow output values (see CVE-2010-5139)
|
// Check for negative or overflow output values (see CVE-2010-5139)
|
||||||
CAmount nValueOut = 0;
|
CAmount nValueOut = 0;
|
||||||
for (const auto& txout : tx.vout) {
|
for (const auto& txout : tx.vout) {
|
||||||
if (txout.nValue < 0)
|
if (txout.nValue < 0)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-negative");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-negative");
|
||||||
if (txout.nValue > MAX_MONEY)
|
if (txout.nValue > MAX_MONEY)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-toolarge");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-toolarge");
|
||||||
nValueOut += txout.nValue;
|
nValueOut += txout.nValue;
|
||||||
if (!MoneyRange(nValueOut))
|
if (!MoneyRange(nValueOut))
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate inputs (see CVE-2018-17144)
|
// Check for duplicate inputs (see CVE-2018-17144)
|
||||||
@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
std::set<COutPoint> vInOutPoints;
|
std::set<COutPoint> vInOutPoints;
|
||||||
for (const auto& txin : tx.vin) {
|
for (const auto& txin : tx.vin) {
|
||||||
if (!vInOutPoints.insert(txin.prevout).second)
|
if (!vInOutPoints.insert(txin.prevout).second)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.IsCoinBase()) {
|
if (tx.IsCoinBase()) {
|
||||||
@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
minCbSize = 1;
|
minCbSize = 1;
|
||||||
}
|
}
|
||||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-length");
|
||||||
} else {
|
} else {
|
||||||
for (const auto& txin : tx.vin)
|
for (const auto& txin : tx.vin)
|
||||||
if (txin.prevout.IsNull())
|
if (txin.prevout.IsNull())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-prevout-null");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -162,7 +162,8 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
|||||||
{
|
{
|
||||||
// are the actual inputs available?
|
// are the actual inputs available?
|
||||||
if (!inputs.HaveInputs(tx)) {
|
if (!inputs.HaveInputs(tx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", strprintf("%s: inputs missing/spent", __func__));
|
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
|
||||||
|
strprintf("%s: inputs missing/spent", __func__));
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount nValueIn = 0;
|
CAmount nValueIn = 0;
|
||||||
@ -173,25 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
|||||||
|
|
||||||
// If prev is coinbase, check that it's matured
|
// If prev is coinbase, check that it's matured
|
||||||
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
|
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
|
||||||
|
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for negative or overflow input values
|
// Check for negative or overflow input values
|
||||||
nValueIn += coin.out.nValue;
|
nValueIn += coin.out.nValue;
|
||||||
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputvalues-outofrange");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CAmount value_out = tx.GetValueOut();
|
const CAmount value_out = tx.GetValueOut();
|
||||||
if (nValueIn < value_out) {
|
if (nValueIn < value_out) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout", strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-in-belowout",
|
||||||
|
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tally transaction fees
|
// Tally transaction fees
|
||||||
const CAmount txfee_aux = nValueIn - value_out;
|
const CAmount txfee_aux = nValueIn - value_out;
|
||||||
if (!MoneyRange(txfee_aux)) {
|
if (!MoneyRange(txfee_aux)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange");
|
||||||
}
|
}
|
||||||
|
|
||||||
txfee = txfee_aux;
|
txfee = txfee_aux;
|
||||||
|
@ -8,20 +8,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/** "reject" message codes */
|
|
||||||
static const unsigned char REJECT_MALFORMED = 0x01;
|
|
||||||
static const unsigned char REJECT_INVALID = 0x10;
|
|
||||||
static const unsigned char REJECT_OBSOLETE = 0x11;
|
|
||||||
static const unsigned char REJECT_DUPLICATE = 0x12;
|
|
||||||
static const unsigned char REJECT_NONSTANDARD = 0x40;
|
|
||||||
// static const unsigned char REJECT_DUST = 0x41; // part of BIP 61
|
|
||||||
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
|
|
||||||
static const unsigned char REJECT_CHECKPOINT = 0x43;
|
|
||||||
|
|
||||||
/** A "reason" why something was invalid, suitable for determining whether the
|
/** A "reason" why something was invalid, suitable for determining whether the
|
||||||
* provider of the object should be banned/ignored/disconnected/etc.
|
* provider of the object should be banned/ignored/disconnected/etc.
|
||||||
* These are much more granular than the rejection codes, which may be more
|
|
||||||
* useful for some other use-cases.
|
|
||||||
*/
|
*/
|
||||||
enum class ValidationInvalidReason {
|
enum class ValidationInvalidReason {
|
||||||
// txn and blocks:
|
// txn and blocks:
|
||||||
@ -94,15 +82,13 @@ private:
|
|||||||
} mode;
|
} mode;
|
||||||
ValidationInvalidReason m_reason;
|
ValidationInvalidReason m_reason;
|
||||||
std::string strRejectReason;
|
std::string strRejectReason;
|
||||||
unsigned int chRejectCode;
|
|
||||||
std::string strDebugMessage;
|
std::string strDebugMessage;
|
||||||
public:
|
public:
|
||||||
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {}
|
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE) {}
|
||||||
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
|
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
|
||||||
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
|
const std::string &strRejectReasonIn="",
|
||||||
const std::string &strDebugMessageIn="") {
|
const std::string &strDebugMessageIn="") {
|
||||||
m_reason = reasonIn;
|
m_reason = reasonIn;
|
||||||
chRejectCode = chRejectCodeIn;
|
|
||||||
strRejectReason = strRejectReasonIn;
|
strRejectReason = strRejectReasonIn;
|
||||||
strDebugMessage = strDebugMessageIn;
|
strDebugMessage = strDebugMessageIn;
|
||||||
if (mode == MODE_ERROR)
|
if (mode == MODE_ERROR)
|
||||||
@ -126,7 +112,6 @@ public:
|
|||||||
return mode == MODE_ERROR;
|
return mode == MODE_ERROR;
|
||||||
}
|
}
|
||||||
ValidationInvalidReason GetReason() const { return m_reason; }
|
ValidationInvalidReason GetReason() const { return m_reason; }
|
||||||
unsigned int GetRejectCode() const { return chRejectCode; }
|
|
||||||
std::string GetRejectReason() const { return strRejectReason; }
|
std::string GetRejectReason() const { return strRejectReason; }
|
||||||
std::string GetDebugMessage() const { return strDebugMessage; }
|
std::string GetDebugMessage() const { return strDebugMessage; }
|
||||||
};
|
};
|
||||||
|
@ -18,30 +18,30 @@
|
|||||||
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_COINBASE) {
|
if (tx.nType != TRANSACTION_COINBASE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tx.IsCoinBase()) {
|
if (!tx.IsCoinBase()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-invalid");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
CCbTx cbTx;
|
CCbTx cbTx;
|
||||||
if (!GetTxPayload(tx, cbTx)) {
|
if (!GetTxPayload(tx, cbTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
|
if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
|
if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-height");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
|
bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height;
|
||||||
if (fDIP0008Active && cbTx.nVersion < 2) {
|
if (fDIP0008Active && cbTx.nVersion < 2) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
|
|
||||||
CCbTx cbTx;
|
CCbTx cbTx;
|
||||||
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
|
int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
|
||||||
@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
|
if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-mnmerkleroot");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
|
int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
|
||||||
@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
|
if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
|||||||
if (sml == smlCached) {
|
if (sml == smlCached) {
|
||||||
merkleRootRet = merkleRootCached;
|
merkleRootRet = merkleRootCached;
|
||||||
if (mutatedCached) {
|
if (mutatedCached) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-cached-calc-cb-mnmerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-cached-calc-cb-mnmerkleroot");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
|||||||
mutatedCached = mutated;
|
mutatedCached = mutated;
|
||||||
|
|
||||||
if (mutated) {
|
if (mutated) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cb-mnmerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cb-mnmerkleroot");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-calc-cb-mnmerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-calc-cb-mnmerkleroot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
|
|
||||||
auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor);
|
auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor);
|
||||||
if (!retVal) {
|
if (!retVal) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "commitment-not-found");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "commitment-not-found");
|
||||||
}
|
}
|
||||||
// The returned quorums are in reversed order, so the most recent one is at index 0
|
// The returned quorums are in reversed order, so the most recent one is at index 0
|
||||||
auto [qcHashes, qcIndexedHashes] = retVal.value();
|
auto [qcHashes, qcIndexedHashes] = retVal.value();
|
||||||
@ -249,7 +249,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
|
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
llmq::CFinalCommitmentTxPayload qc;
|
llmq::CFinalCommitmentTxPayload qc;
|
||||||
if (!GetTxPayload(*tx, qc)) {
|
if (!GetTxPayload(*tx, qc)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload-calc-cbtx-quorummerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
if (qc.commitment.IsNull()) {
|
if (qc.commitment.IsNull()) {
|
||||||
// having null commitments is ok but we don't use them here, move to the next tx
|
// having null commitments is ok but we don't use them here, move to the next tx
|
||||||
@ -257,7 +257,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
}
|
}
|
||||||
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
const auto& llmq_params = llmq_params_opt.value();
|
const auto& llmq_params = llmq_params_opt.value();
|
||||||
auto qcHash = ::SerializeHash(qc.commitment);
|
auto qcHash = ::SerializeHash(qc.commitment);
|
||||||
@ -291,7 +291,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
|
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
|
||||||
assert(llmq_params_opt.has_value());
|
assert(llmq_params_opt.has_value());
|
||||||
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
|
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "excess-quorums-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
// Copy vec_hashes into vec_hashes_final
|
// Copy vec_hashes into vec_hashes_final
|
||||||
std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final));
|
std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final));
|
||||||
@ -308,7 +308,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
|
|||||||
LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);
|
LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);
|
||||||
|
|
||||||
if (mutated) {
|
if (mutated) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cbtx-quorummerkleroot");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cbtx-quorummerkleroot");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -710,7 +710,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
|||||||
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
|
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
|
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-dmn-block");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-dmn-block");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't hold cs while calling signals
|
// Don't hold cs while calling signals
|
||||||
@ -723,7 +723,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
|||||||
if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {
|
if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {
|
||||||
LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__,
|
LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__,
|
||||||
pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight);
|
pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight);
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-dip3-enf-block");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-dip3-enf-block");
|
||||||
}
|
}
|
||||||
LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight);
|
LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight);
|
||||||
}
|
}
|
||||||
@ -820,11 +820,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
|
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
|
||||||
CProRegTx proTx;
|
CProRegTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType);
|
auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType);
|
||||||
@ -842,7 +842,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
|
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
|
||||||
// should actually never get to this point as CheckProRegTx should have handled this case.
|
// should actually never get to this point as CheckProRegTx should have handled this case.
|
||||||
// We do this additional check nevertheless to be 100% sure
|
// We do this additional check nevertheless to be 100% sure
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
|
auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
|
||||||
@ -858,10 +858,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newList.HasUniqueProperty(proTx.addr)) {
|
if (newList.HasUniqueProperty(proTx.addr)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
|
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-key");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
dmn->nOperatorReward = proTx.nOperatorReward;
|
dmn->nOperatorReward = proTx.nOperatorReward;
|
||||||
@ -883,26 +883,26 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
||||||
CProUpServTx proTx;
|
CProUpServTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) {
|
if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
|
|
||||||
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
if (proTx.nType != dmn->nType) {
|
if (proTx.nType != dmn->nType) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type-mismatch");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type-mismatch");
|
||||||
}
|
}
|
||||||
if (!IsValidMnType(proTx.nType)) {
|
if (!IsValidMnType(proTx.nType)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||||
@ -932,12 +932,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
||||||
CProUpRegTx proTx;
|
CProUpRegTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||||
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||||
@ -958,12 +958,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||||
CProUpRevTx proTx;
|
CProUpRevTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||||
newState->ResetOperatorFields();
|
newState->ResetOperatorFields();
|
||||||
@ -979,19 +979,19 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
|||||||
} else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
} else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
llmq::CFinalCommitmentTxPayload qc;
|
llmq::CFinalCommitmentTxPayload qc;
|
||||||
if (!GetTxPayload(tx, qc)) {
|
if (!GetTxPayload(tx, qc)) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload");
|
||||||
}
|
}
|
||||||
if (!qc.commitment.IsNull()) {
|
if (!qc.commitment.IsNull()) {
|
||||||
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type");
|
||||||
}
|
}
|
||||||
int qcnHeight = int(qc.nHeight);
|
int qcnHeight = int(qc.nHeight);
|
||||||
int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
|
int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
|
||||||
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
|
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
|
||||||
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
|
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
|
||||||
// we should actually never get into this case as validation should have caught it...but let's be sure
|
// we should actually never get into this case as validation should have caught it...but let's be sure
|
||||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
|
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs);
|
HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs);
|
||||||
@ -1351,23 +1351,23 @@ template <typename ProTx>
|
|||||||
static bool CheckService(const ProTx& proTx, CValidationState& state)
|
static bool CheckService(const ProTx& proTx, CValidationState& state)
|
||||||
{
|
{
|
||||||
if (!proTx.addr.IsValid()) {
|
if (!proTx.addr.IsValid()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr");
|
||||||
}
|
}
|
||||||
if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) {
|
if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
||||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||||
if (proTx.addr.GetPort() != mainnetDefaultPort) {
|
if (proTx.addr.GetPort() != mainnetDefaultPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr-port");
|
||||||
}
|
}
|
||||||
} else if (proTx.addr.GetPort() == mainnetDefaultPort) {
|
} else if (proTx.addr.GetPort() == mainnetDefaultPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr-port");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!proTx.addr.IsIPv4()) {
|
if (!proTx.addr.IsIPv4()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1377,35 +1377,35 @@ template <typename ProTx>
|
|||||||
static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state)
|
static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state)
|
||||||
{
|
{
|
||||||
if (proTx.platformNodeID.IsNull()) {
|
if (proTx.platformNodeID.IsNull()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-nodeid");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-nodeid");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort();
|
static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort();
|
||||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||||
if (proTx.platformP2PPort != mainnetPlatformP2PPort) {
|
if (proTx.platformP2PPort != mainnetPlatformP2PPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-p2p-port");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort();
|
static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort();
|
||||||
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||||
if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) {
|
if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-http-port");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
|
||||||
if (proTx.platformP2PPort == mainnetDefaultP2PPort) {
|
if (proTx.platformP2PPort == mainnetDefaultP2PPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-p2p-port");
|
||||||
}
|
}
|
||||||
if (proTx.platformHTTPPort == mainnetDefaultP2PPort) {
|
if (proTx.platformHTTPPort == mainnetDefaultP2PPort) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-http-port");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proTx.platformP2PPort == proTx.platformHTTPPort ||
|
if (proTx.platformP2PPort == proTx.platformHTTPPort ||
|
||||||
proTx.platformP2PPort == proTx.addr.GetPort() ||
|
proTx.platformP2PPort == proTx.addr.GetPort() ||
|
||||||
proTx.platformHTTPPort == proTx.addr.GetPort()) {
|
proTx.platformHTTPPort == proTx.addr.GetPort()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-dup-ports");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-dup-ports");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1416,7 +1416,7 @@ static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, CValidationSt
|
|||||||
{
|
{
|
||||||
std::string strError;
|
std::string strError;
|
||||||
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) {
|
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1426,7 +1426,7 @@ static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, CValidation
|
|||||||
{
|
{
|
||||||
std::string strError;
|
std::string strError;
|
||||||
if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) {
|
if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1435,7 +1435,7 @@ template <typename ProTx>
|
|||||||
static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state)
|
static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state)
|
||||||
{
|
{
|
||||||
if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) {
|
if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1443,16 +1443,16 @@ static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValid
|
|||||||
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_REGISTER) {
|
if (tx.nType != TRANSACTION_PROVIDER_REGISTER) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProRegTx ptx;
|
CProRegTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
|
// It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
|
||||||
@ -1477,31 +1477,31 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
if (!ptx.collateralOutpoint.hash.IsNull()) {
|
if (!ptx.collateralOutpoint.hash.IsNull()) {
|
||||||
Coin coin;
|
Coin coin;
|
||||||
if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) {
|
if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-dest");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
|
// Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
|
||||||
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
|
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
|
||||||
keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest);
|
keyForPayloadSig = std::get_if<PKHash>(&collateralTxDest);
|
||||||
if (!keyForPayloadSig) {
|
if (!keyForPayloadSig) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-pkh");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-pkh");
|
||||||
}
|
}
|
||||||
|
|
||||||
collateralOutpoint = ptx.collateralOutpoint;
|
collateralOutpoint = ptx.collateralOutpoint;
|
||||||
} else {
|
} else {
|
||||||
if (ptx.collateralOutpoint.n >= tx.vout.size()) {
|
if (ptx.collateralOutpoint.n >= tx.vout.size()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-index");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-index");
|
||||||
}
|
}
|
||||||
if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) {
|
if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) {
|
if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-dest");
|
||||||
}
|
}
|
||||||
|
|
||||||
collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n);
|
collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n);
|
||||||
@ -1510,7 +1510,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
||||||
// this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH
|
// this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH
|
||||||
if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-reuse");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
@ -1518,30 +1518,30 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
|
|
||||||
// only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
|
// only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
|
||||||
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) {
|
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
|
|
||||||
// never allow duplicate keys, even if this ProTx would replace an existing MN
|
// never allow duplicate keys, even if this ProTx would replace an existing MN
|
||||||
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
// never allow duplicate platformNodeIds for HPMNs
|
// never allow duplicate platformNodeIds for HPMNs
|
||||||
if (ptx.nType == MnType::HighPerformance) {
|
if (ptx.nType == MnType::HighPerformance) {
|
||||||
if (mnList.HasUniqueProperty(ptx.platformNodeID)) {
|
if (mnList.HasUniqueProperty(ptx.platformNodeID)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-platformnodeid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
||||||
if (ptx.keyIDOwner != ptx.keyIDVoting) {
|
if (ptx.keyIDOwner != ptx.keyIDVoting) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-key-not-same");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyForPayloadSig) {
|
if (keyForPayloadSig) {
|
||||||
@ -1553,7 +1553,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
} else {
|
} else {
|
||||||
// collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
|
// collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
|
||||||
if (!ptx.vchSig.empty()) {
|
if (!ptx.vchSig.empty()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1563,16 +1563,16 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
|||||||
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs)
|
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProUpServTx ptx;
|
CProUpServTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckService(ptx, state)) {
|
if (!CheckService(ptx, state)) {
|
||||||
@ -1590,34 +1590,34 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
|
|||||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||||
auto mn = mnList.GetMN(ptx.proTxHash);
|
auto mn = mnList.GetMN(ptx.proTxHash);
|
||||||
if (!mn) {
|
if (!mn) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow updating to addresses already used by other MNs
|
// don't allow updating to addresses already used by other MNs
|
||||||
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) {
|
if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-addr");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow updating to platformNodeIds already used by other HPMNs
|
// don't allow updating to platformNodeIds already used by other HPMNs
|
||||||
if (ptx.nType == MnType::HighPerformance) {
|
if (ptx.nType == MnType::HighPerformance) {
|
||||||
if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) {
|
if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-platformnodeid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptx.scriptOperatorPayout != CScript()) {
|
if (ptx.scriptOperatorPayout != CScript()) {
|
||||||
if (mn->nOperatorReward == 0) {
|
if (mn->nOperatorReward == 0) {
|
||||||
// don't allow setting operator reward payee in case no operatorReward was set
|
// don't allow setting operator reward payee in case no operatorReward was set
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-operator-payee");
|
||||||
}
|
}
|
||||||
if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) {
|
if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-operator-payee");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can only check the signature if pindexPrev != nullptr and the MN is known
|
// we can only check the signature if pindexPrev != nullptr and the MN is known
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) {
|
if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
@ -1631,66 +1631,66 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
|
|||||||
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProUpRegTx ptx;
|
CProUpRegTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination payoutDest;
|
CTxDestination payoutDest;
|
||||||
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
|
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
|
||||||
// should not happen as we checked script types before
|
// should not happen as we checked script types before
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-dest");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-payee-dest");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||||
auto dmn = mnList.GetMN(ptx.proTxHash);
|
auto dmn = mnList.GetMN(ptx.proTxHash);
|
||||||
if (!dmn) {
|
if (!dmn) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server)
|
// don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server)
|
||||||
if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-reuse");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-payee-reuse");
|
||||||
}
|
}
|
||||||
|
|
||||||
Coin coin;
|
Coin coin;
|
||||||
if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) {
|
if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) {
|
||||||
// this should never happen (there would be no dmn otherwise)
|
// this should never happen (there would be no dmn otherwise)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral");
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
||||||
CTxDestination collateralTxDest;
|
CTxDestination collateralTxDest;
|
||||||
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral-dest");
|
||||||
}
|
}
|
||||||
if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-reuse");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
||||||
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
|
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
|
||||||
if (ptx.proTxHash != otherDmn->proTxHash) {
|
if (ptx.proTxHash != otherDmn->proTxHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) {
|
||||||
if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
|
if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-key-not-same");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) {
|
if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
@ -1704,26 +1704,26 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
|
|||||||
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs)
|
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs)
|
||||||
{
|
{
|
||||||
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
CProUpRevTx ptx;
|
CProUpRevTx ptx;
|
||||||
if (!GetTxPayload(tx, ptx)) {
|
if (!GetTxPayload(tx, ptx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexPrev) {
|
if (pindexPrev) {
|
||||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
|
||||||
auto dmn = mnList.GetMN(ptx.proTxHash);
|
auto dmn = mnList.GetMN(ptx.proTxHash);
|
||||||
if (!dmn)
|
if (!dmn)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash");
|
||||||
|
|
||||||
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) {
|
||||||
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
|
return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str));
|
||||||
}
|
}
|
||||||
if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) {
|
if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) {
|
||||||
// pass the state returned by the function above
|
// pass the state returned by the function above
|
||||||
|
@ -38,29 +38,29 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidat
|
|||||||
{
|
{
|
||||||
MNHFTxPayload mnhfTx;
|
MNHFTxPayload mnhfTx;
|
||||||
if (!GetTxPayload(tx, mnhfTx)) {
|
if (!GetTxPayload(tx, mnhfTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash);
|
const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash);
|
||||||
if (!pindexQuorum) {
|
if (!pindexQuorum) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
|
if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
|
||||||
// not part of active chain
|
// not part of active chain
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
|
if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mnhfTx.signal.Verify(pindexQuorum)) {
|
if (!mnhfTx.signal.Verify(pindexQuorum)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-invalid");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) {
|
if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -46,10 +46,10 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
|||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-check-special-tx");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-check-special-tx");
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type-check");
|
return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type-check");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state)
|
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state)
|
||||||
@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
|
|||||||
return true; // handled per block
|
return true; // handled per block
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-tx-type-proc");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-tx-type-proc");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
||||||
@ -154,7 +154,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
|
|||||||
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
|
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-procspectxsinblock");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
|
|||||||
const auto numCommitmentsInNewBlock = qcs.count(params.type);
|
const auto numCommitmentsInNewBlock = qcs.count(params.type);
|
||||||
|
|
||||||
if (numCommitmentsRequired < numCommitmentsInNewBlock) {
|
if (numCommitmentsRequired < numCommitmentsInNewBlock) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-not-allowed");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-not-allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numCommitmentsRequired > numCommitmentsInNewBlock) {
|
if (numCommitmentsRequired > numCommitmentsInNewBlock) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-missing");
|
||||||
}
|
}
|
||||||
if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
|
if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
|
||||||
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
|
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
|
||||||
@ -234,31 +234,31 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
|
|||||||
if (quorumHash.IsNull()) {
|
if (quorumHash.IsNull()) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block");
|
||||||
}
|
}
|
||||||
if (quorumHash != qc.quorumHash) {
|
if (quorumHash != qc.quorumHash) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qc.IsNull()) {
|
if (qc.IsNull()) {
|
||||||
if (!qc.VerifyNull()) {
|
if (!qc.VerifyNull()) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasMinedCommitment(llmq_params.type, quorumHash)) {
|
if (HasMinedCommitment(llmq_params.type, quorumHash)) {
|
||||||
// should not happen as it's already handled in ProcessBlock
|
// should not happen as it's already handled in ProcessBlock
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsMiningPhase(llmq_params, nHeight)) {
|
if (!IsMiningPhase(llmq_params, nHeight)) {
|
||||||
// should not happen as it's already handled in ProcessBlock
|
// should not happen as it's already handled in ProcessBlock
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash);
|
const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash);
|
||||||
@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
|
|||||||
if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
|
if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
|
||||||
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fJustCheck) {
|
if (fJustCheck) {
|
||||||
@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
|
|||||||
if (!GetTxPayload(*tx, qc)) {
|
if (!GetTxPayload(*tx, qc)) {
|
||||||
// should not happen as it was verified before processing the block
|
// should not happen as it was verified before processing the block
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight);
|
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
|
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
// should not happen as it was verified before processing the block
|
// should not happen as it was verified before processing the block
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
// only allow one commitment per type and per block (This was changed with rotation)
|
// only allow one commitment per type and per block (This was changed with rotation)
|
||||||
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
|
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
|
||||||
if (ret.count(qc.commitment.llmqType) != 0) {
|
if (ret.count(qc.commitment.llmqType) != 0) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +442,7 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) {
|
if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-premature");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-premature");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -181,13 +181,13 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
|
|||||||
CFinalCommitmentTxPayload qcTx;
|
CFinalCommitmentTxPayload qcTx;
|
||||||
if (!GetTxPayload(tx, qcTx)) {
|
if (!GetTxPayload(tx, qcTx)) {
|
||||||
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
|
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
|
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
|
||||||
if (!llmq_params_opt.has_value()) {
|
if (!llmq_params_opt.has_value()) {
|
||||||
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType));
|
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType));
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LogAcceptCategory(BCLog::LLMQ)) {
|
if (LogAcceptCategory(BCLog::LLMQ)) {
|
||||||
@ -201,36 +201,36 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
|
|||||||
|
|
||||||
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
|
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion);
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-version");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) {
|
if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight);
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight);
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash));
|
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash));
|
||||||
if (pQuorumBaseBlockIndex == nullptr) {
|
if (pQuorumBaseBlockIndex == nullptr) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) {
|
if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) {
|
||||||
// not part of active chain
|
// not part of active chain
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcTx.commitment.IsNull()) {
|
if (qcTx.commitment.IsNull()) {
|
||||||
if (!qcTx.commitment.VerifyNull()) {
|
if (!qcTx.commitment.VerifyNull()) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) {
|
if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) {
|
||||||
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight);
|
LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight);
|
||||||
|
@ -173,8 +173,8 @@ namespace {
|
|||||||
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sources of received blocks, saved to be able to send them reject
|
* Sources of received blocks, saved to be able punish them when processing
|
||||||
* messages or ban them when processing happens afterwards.
|
* happens afterwards.
|
||||||
* Set mapBlockSource[hash].second to false if the node should not be
|
* Set mapBlockSource[hash].second to false if the node should not be
|
||||||
* punished if the block is invalid.
|
* punished if the block is invalid.
|
||||||
*/
|
*/
|
||||||
@ -1513,11 +1513,12 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
|
|||||||
const uint256 hash(block.GetHash());
|
const uint256 hash(block.GetHash());
|
||||||
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
|
std::map<uint256, std::pair<NodeId, bool> >::iterator it = mapBlockSource.find(hash);
|
||||||
|
|
||||||
if (state.IsInvalid()) {
|
// If the block failed validation, we know where it came from and we're still connected
|
||||||
// Don't send reject message with code 0 or an internal reject code.
|
// to that peer, maybe punish.
|
||||||
if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) {
|
if (state.IsInvalid() &&
|
||||||
|
it != mapBlockSource.end() &&
|
||||||
|
State(it->second.first)) {
|
||||||
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Check that:
|
// Check that:
|
||||||
// 1. The block is valid
|
// 1. The block is valid
|
||||||
@ -2523,25 +2524,6 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
|
|||||||
connman.PushMessage(&peer, std::move(msg));
|
connman.PushMessage(&peer, std::move(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RejectCodeToString(const unsigned char code)
|
|
||||||
{
|
|
||||||
if (code == REJECT_MALFORMED)
|
|
||||||
return "malformed";
|
|
||||||
if (code == REJECT_INVALID)
|
|
||||||
return "invalid";
|
|
||||||
if (code == REJECT_OBSOLETE)
|
|
||||||
return "obsolete";
|
|
||||||
if (code == REJECT_DUPLICATE)
|
|
||||||
return "duplicate";
|
|
||||||
if (code == REJECT_NONSTANDARD)
|
|
||||||
return "nonstandard";
|
|
||||||
if (code == REJECT_INSUFFICIENTFEE)
|
|
||||||
return "insufficientfee";
|
|
||||||
if (code == REJECT_CHECKPOINT)
|
|
||||||
return "checkpoint";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx)
|
std::pair<bool /*ret*/, bool /*do_return*/> static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx)
|
||||||
{
|
{
|
||||||
if (!dstx.IsValidStructure()) {
|
if (!dstx.IsValidStructure()) {
|
||||||
@ -3750,11 +3732,12 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
// been run). This is handled below, so just treat this as
|
// been run). This is handled below, so just treat this as
|
||||||
// though the block was successfully read, and rely on the
|
// though the block was successfully read, and rely on the
|
||||||
// handling in ProcessNewBlock to ensure the block index is
|
// handling in ProcessNewBlock to ensure the block index is
|
||||||
// updated, reject messages go out, etc.
|
// updated, etc.
|
||||||
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
||||||
fBlockRead = true;
|
fBlockRead = true;
|
||||||
// mapBlockSource is only used for sending reject messages and DoS scores,
|
// mapBlockSource is used for potentially punishing peers and
|
||||||
// so the race between here and cs_main in ProcessNewBlock is fine.
|
// updating which peers send us compact blocks, so the race
|
||||||
|
// between here and cs_main in ProcessNewBlock is fine.
|
||||||
// BIP 152 permits peers to relay compact blocks after validating
|
// BIP 152 permits peers to relay compact blocks after validating
|
||||||
// the header only; we should not punish peers if the block turns
|
// the header only; we should not punish peers if the block turns
|
||||||
// out to be invalid.
|
// out to be invalid.
|
||||||
@ -3835,8 +3818,9 @@ void PeerLogicValidation::ProcessMessage(
|
|||||||
// Also always process if we requested the block explicitly, as we may
|
// Also always process if we requested the block explicitly, as we may
|
||||||
// need it even though it is not a candidate for a new best tip.
|
// need it even though it is not a candidate for a new best tip.
|
||||||
forceProcessing |= MarkBlockAsReceived(hash);
|
forceProcessing |= MarkBlockAsReceived(hash);
|
||||||
// mapBlockSource is only used for sending reject messages and DoS scores,
|
// mapBlockSource is only used for punishing peers and setting
|
||||||
// so the race between here and cs_main in ProcessNewBlock is fine.
|
// which peers send us compact blocks, so the race between here and
|
||||||
|
// cs_main in ProcessNewBlock is fine.
|
||||||
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
|
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
|
||||||
}
|
}
|
||||||
bool fNewBlock = false;
|
bool fNewBlock = false;
|
||||||
|
@ -929,7 +929,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
|||||||
result_0.pushKV("allowed", test_accept_res);
|
result_0.pushKV("allowed", test_accept_res);
|
||||||
if (!test_accept_res) {
|
if (!test_accept_res) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
|
result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
|
||||||
} else if (missing_inputs) {
|
} else if (missing_inputs) {
|
||||||
result_0.pushKV("reject-reason", "missing-inputs");
|
result_0.pushKV("reject-reason", "missing-inputs");
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,11 +22,11 @@ bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state)
|
|||||||
{
|
{
|
||||||
MNHFTxPayload mnhfTx;
|
MNHFTxPayload mnhfTx;
|
||||||
if (!GetTxPayload(tx, mnhfTx)) {
|
if (!GetTxPayload(tx, mnhfTx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
/** Convert CValidationState to a human-readable message for logging */
|
/** Convert CValidationState to a human-readable message for logging */
|
||||||
std::string FormatStateMessage(const CValidationState &state)
|
std::string FormatStateMessage(const CValidationState &state)
|
||||||
{
|
{
|
||||||
return strprintf("%s%s (code %i)",
|
return strprintf("%s%s",
|
||||||
state.GetRejectReason(),
|
state.GetRejectReason(),
|
||||||
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
|
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage());
|
||||||
state.GetRejectCode());
|
|
||||||
}
|
}
|
||||||
|
@ -379,18 +379,18 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
|
|||||||
tx.nType != TRANSACTION_COINBASE &&
|
tx.nType != TRANSACTION_COINBASE &&
|
||||||
tx.nType != TRANSACTION_QUORUM_COMMITMENT &&
|
tx.nType != TRANSACTION_QUORUM_COMMITMENT &&
|
||||||
tx.nType != TRANSACTION_MNHF_SIGNAL) {
|
tx.nType != TRANSACTION_MNHF_SIGNAL) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type");
|
||||||
}
|
}
|
||||||
if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE)
|
if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-cb-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-cb-type");
|
||||||
} else if (tx.nType != TRANSACTION_NORMAL) {
|
} else if (tx.nType != TRANSACTION_NORMAL) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size limits
|
// Size limits
|
||||||
if (fDIP0001Active_context && ::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE)
|
if (fDIP0001Active_context && ::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -597,11 +597,11 @@ private:
|
|||||||
{
|
{
|
||||||
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
|
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
|
||||||
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
|
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
|
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
|
if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
|
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -655,35 +655,35 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
|
|
||||||
if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
// quorum commitment is not allowed outside of blocks
|
// quorum commitment is not allowed outside of blocks
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "qc-not-allowed");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "qc-not-allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coinbase is only valid in a block, not as a loose transaction
|
// Coinbase is only valid in a block, not as a loose transaction
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "coinbase");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "coinbase");
|
||||||
|
|
||||||
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
||||||
std::string reason;
|
std::string reason;
|
||||||
if (fRequireStandard && !IsStandardTx(tx, reason))
|
if (fRequireStandard && !IsStandardTx(tx, reason))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, reason);
|
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, reason);
|
||||||
|
|
||||||
// Do not work on transactions that are too small.
|
// Do not work on transactions that are too small.
|
||||||
// A transaction with 1 empty scriptSig input and 1 P2SH output has size of 83 bytes.
|
// A transaction with 1 empty scriptSig input and 1 P2SH output has size of 83 bytes.
|
||||||
// Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying
|
// Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying
|
||||||
// 64-byte transactions.
|
// 64-byte transactions.
|
||||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE)
|
if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE)
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "tx-size-small");
|
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "tx-size-small");
|
||||||
|
|
||||||
// Only accept nLockTime-using transactions that can be mined in the next
|
// Only accept nLockTime-using transactions that can be mined in the next
|
||||||
// block; we don't want our mempool filled up with transactions that can't
|
// block; we don't want our mempool filled up with transactions that can't
|
||||||
// be mined yet.
|
// be mined yet.
|
||||||
if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
|
if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-final");
|
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-final");
|
||||||
|
|
||||||
// is it already in the memory pool?
|
// is it already in the memory pool?
|
||||||
if (m_pool.exists(hash)) {
|
if (m_pool.exists(hash)) {
|
||||||
statsClient.inc("transactions.duplicate", 1.0f);
|
statsClient.inc("transactions.duplicate", 1.0f);
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-in-mempool");
|
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-in-mempool");
|
||||||
}
|
}
|
||||||
|
|
||||||
llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx);
|
llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx);
|
||||||
@ -693,7 +693,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
if (txConflict) {
|
if (txConflict) {
|
||||||
GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict);
|
GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict);
|
||||||
}
|
}
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), REJECT_INVALID, "tx-txlock-conflict");
|
return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), "tx-txlock-conflict");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) {
|
if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) {
|
||||||
@ -707,7 +707,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
if (ptxConflicting)
|
if (ptxConflicting)
|
||||||
{
|
{
|
||||||
// Transaction conflicts with mempool and RBF doesn't exist in Dash
|
// Transaction conflicts with mempool and RBF doesn't exist in Dash
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-mempool-conflict");
|
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-mempool-conflict");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -731,7 +731,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
for (size_t out = 0; out < tx.vout.size(); out++) {
|
for (size_t out = 0; out < tx.vout.size(); out++) {
|
||||||
// Optimistically just do efficient check of cache for outputs
|
// Optimistically just do efficient check of cache for outputs
|
||||||
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
|
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known");
|
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-known");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
|
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
|
||||||
@ -757,7 +757,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
// CoinsViewCache instead of create its own
|
// CoinsViewCache instead of create its own
|
||||||
assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
|
assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
|
||||||
if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
|
if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final");
|
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-BIP68-final");
|
||||||
|
|
||||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman));
|
assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman));
|
||||||
CAmount nFees = 0;
|
CAmount nFees = 0;
|
||||||
@ -767,7 +767,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
|
|
||||||
// Check for non-standard pay-to-script-hash in inputs
|
// Check for non-standard pay-to-script-hash in inputs
|
||||||
if (fRequireStandard && !AreInputsStandard(tx, m_view))
|
if (fRequireStandard && !AreInputsStandard(tx, m_view))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
|
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs");
|
||||||
|
|
||||||
unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
|
unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
|
||||||
|
|
||||||
@ -792,7 +792,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
unsigned int nSize = entry->GetTxSize();
|
unsigned int nSize = entry->GetTxSize();
|
||||||
|
|
||||||
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
|
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops",
|
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops",
|
||||||
strprintf("%d", nSigOps));
|
strprintf("%d", nSigOps));
|
||||||
|
|
||||||
// No transactions are allowed below minRelayTxFee except from disconnected
|
// No transactions are allowed below minRelayTxFee except from disconnected
|
||||||
@ -801,8 +801,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
|
|
||||||
if (nAbsurdFee && nFees > nAbsurdFee)
|
if (nAbsurdFee && nFees > nAbsurdFee)
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false,
|
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false,
|
||||||
REJECT_HIGHFEE, "absurdly-high-fee",
|
"absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
|
||||||
strprintf("%d > %d", nFees, nAbsurdFee));
|
|
||||||
|
|
||||||
// Calculate in-mempool ancestors, up to a limit.
|
// Calculate in-mempool ancestors, up to a limit.
|
||||||
std::string errString;
|
std::string errString;
|
||||||
@ -822,7 +821,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
|
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
|
||||||
if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
|
if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
|
||||||
!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
|
!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString);
|
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,7 +833,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_pool.existsProviderTxConflict(tx)) {
|
if (m_pool.existsProviderTxConflict(tx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "protx-dup");
|
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "protx-dup");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -935,7 +934,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
|
|||||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip()));
|
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip()));
|
||||||
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
|
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
|
||||||
if (!m_pool.exists(hash))
|
if (!m_pool.exists(hash))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full");
|
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool full");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1593,7 +1592,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||||||
CScriptCheck check2(coin.out, tx, i,
|
CScriptCheck check2(coin.out, tx, i,
|
||||||
(flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata);
|
(flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata);
|
||||||
if (check2())
|
if (check2())
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
||||||
}
|
}
|
||||||
// MANDATORY flag failures correspond to
|
// MANDATORY flag failures correspond to
|
||||||
// ValidationInvalidReason::CONSENSUS. Because CONSENSUS
|
// ValidationInvalidReason::CONSENSUS. Because CONSENSUS
|
||||||
@ -1604,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||||||
// support, to avoid splitting the network (but this
|
// support, to avoid splitting the network (but this
|
||||||
// depends on the details of how net_processing handles
|
// depends on the details of how net_processing handles
|
||||||
// such errors).
|
// such errors).
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2126,7 +2125,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pindex->pprev && pindex->phashBlock && m_clhandler->HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) {
|
if (pindex->pprev && pindex->phashBlock && m_clhandler->HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) {
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock");
|
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), "bad-chainlock");
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that the view's current state corresponds to the previous block
|
// verify that the view's current state corresponds to the previous block
|
||||||
@ -2214,7 +2213,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
for (const auto& tx : block.vtx) {
|
for (const auto& tx : block.vtx) {
|
||||||
for (size_t o = 0; o < tx->vout.size(); o++) {
|
for (size_t o = 0; o < tx->vout.size(); o++) {
|
||||||
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
|
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), "bad-txns-BIP30");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2226,7 +2225,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
if (pindex->nHeight == chainparams.GetConsensus().nSuperblockStartBlock &&
|
if (pindex->nHeight == chainparams.GetConsensus().nSuperblockStartBlock &&
|
||||||
chainparams.GetConsensus().nSuperblockStartHash != uint256() &&
|
chainparams.GetConsensus().nSuperblockStartHash != uint256() &&
|
||||||
block_hash != chainparams.GetConsensus().nSuperblockStartHash) {
|
block_hash != chainparams.GetConsensus().nSuperblockStartHash) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), REJECT_INVALID, "bad-sb-start");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), "bad-sb-start");
|
||||||
}
|
}
|
||||||
/// END DASH
|
/// END DASH
|
||||||
|
|
||||||
@ -2289,13 +2288,14 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
// defined for a block, so we reset the reason flag to
|
// defined for a block, so we reset the reason flag to
|
||||||
// CONSENSUS here.
|
// CONSENSUS here.
|
||||||
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
|
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
|
||||||
state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
|
state.GetRejectReason(), state.GetDebugMessage());
|
||||||
}
|
}
|
||||||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
|
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
nFees += txfee;
|
nFees += txfee;
|
||||||
if (!MoneyRange(nFees)) {
|
if (!MoneyRange(nFees)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__), REJECT_INVALID, "bad-txns-accumulated-fee-outofrange");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__),
|
||||||
|
"bad-txns-accumulated-fee-outofrange");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that transaction is BIP68 final
|
// Check that transaction is BIP68 final
|
||||||
@ -2307,7 +2307,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) {
|
if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__),
|
||||||
|
"bad-txns-nonfinal");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fAddressIndex || fSpentIndex)
|
if (fAddressIndex || fSpentIndex)
|
||||||
@ -2357,7 +2358,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
// * p2sh (when P2SH enabled in flags and excludes coinbase)
|
// * p2sh (when P2SH enabled in flags and excludes coinbase)
|
||||||
nSigOps += GetTransactionSigOpCount(tx, view, flags);
|
nSigOps += GetTransactionSigOpCount(tx, view, flags);
|
||||||
if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) {
|
if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"),
|
||||||
|
"bad-blk-sigops");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
@ -2374,7 +2376,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
// consider whether rewriting to CONSENSUS or
|
// consider whether rewriting to CONSENSUS or
|
||||||
// RECENT_CONSENSUS_CHANGE would be more appropriate.
|
// RECENT_CONSENSUS_CHANGE would be more appropriate.
|
||||||
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
|
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
|
||||||
state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
|
state.GetRejectReason(), state.GetDebugMessage());
|
||||||
}
|
}
|
||||||
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
||||||
tx.GetHash().ToString(), FormatStateMessage(state));
|
tx.GetHash().ToString(), FormatStateMessage(state));
|
||||||
@ -2425,7 +2427,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
LogPrint(BCLog::BENCHMARK, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
|
LogPrint(BCLog::BENCHMARK, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
|
||||||
|
|
||||||
if (!control.Wait())
|
if (!control.Wait())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed");
|
||||||
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
|
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
|
||||||
LogPrint(BCLog::BENCHMARK, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
|
LogPrint(BCLog::BENCHMARK, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
|
||||||
|
|
||||||
@ -2453,7 +2455,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
} else {
|
} else {
|
||||||
// The node which relayed this should switch to correct chain.
|
// The node which relayed this should switch to correct chain.
|
||||||
// TODO: relay instantsend data/proof.
|
// TODO: relay instantsend data/proof.
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), REJECT_INVALID, "conflict-tx-lock");
|
return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), "conflict-tx-lock");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2473,7 +2475,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
|
|
||||||
if (!IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) {
|
if (!IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) {
|
||||||
// NOTE: Do not punish, the node might be missing governance data
|
// NOTE: Do not punish, the node might be missing governance data
|
||||||
return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), REJECT_INVALID, "bad-cb-amount");
|
return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), "bad-cb-amount");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2;
|
int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2;
|
||||||
@ -2481,7 +2483,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
|
|
||||||
if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) {
|
if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) {
|
||||||
// NOTE: Do not punish, the node might be missing governance data
|
// NOTE: Do not punish, the node might be missing governance data
|
||||||
return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), REJECT_INVALID, "bad-cb-payee");
|
return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), "bad-cb-payee");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTime5_4 = GetTimeMicros(); nTimePayeeValid += nTime5_4 - nTime5_3;
|
int64_t nTime5_4 = GetTimeMicros(); nTimePayeeValid += nTime5_4 - nTime5_3;
|
||||||
@ -3806,13 +3808,13 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
|
|||||||
{
|
{
|
||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
|
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "high-hash", "proof of work failed");
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed");
|
||||||
|
|
||||||
// Check DevNet
|
// Check DevNet
|
||||||
if (!consensusParams.hashDevnetGenesisBlock.IsNull() &&
|
if (!consensusParams.hashDevnetGenesisBlock.IsNull() &&
|
||||||
block.hashPrevBlock == consensusParams.hashGenesisBlock &&
|
block.hashPrevBlock == consensusParams.hashGenesisBlock &&
|
||||||
block.GetHash() != consensusParams.hashDevnetGenesisBlock) {
|
block.GetHash() != consensusParams.hashDevnetGenesisBlock) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), REJECT_INVALID, "devnet-genesis");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), "devnet-genesis");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -3837,13 +3839,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|||||||
bool mutated;
|
bool mutated;
|
||||||
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
|
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
|
||||||
if (block.hashMerkleRoot != hashMerkleRoot2)
|
if (block.hashMerkleRoot != hashMerkleRoot2)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txnmrklroot", "hashMerkleRoot mismatch");
|
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch");
|
||||||
|
|
||||||
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences
|
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences
|
||||||
// of transactions in a block without affecting the merkle root of a block,
|
// of transactions in a block without affecting the merkle root of a block,
|
||||||
// while still invalidating it.
|
// while still invalidating it.
|
||||||
if (mutated)
|
if (mutated)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txns-duplicate", "duplicate transaction");
|
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
// All potential-corruption validation must be done before we do any
|
// All potential-corruption validation must be done before we do any
|
||||||
@ -3852,19 +3854,19 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|||||||
|
|
||||||
// Size limits (relaxed)
|
// Size limits (relaxed)
|
||||||
if (block.vtx.empty() || block.vtx.size() > MaxBlockSize() || ::GetSerializeSize(block, PROTOCOL_VERSION) > MaxBlockSize())
|
if (block.vtx.empty() || block.vtx.size() > MaxBlockSize() || ::GetSerializeSize(block, PROTOCOL_VERSION) > MaxBlockSize())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed");
|
||||||
|
|
||||||
// First transaction must be coinbase, the rest must not be
|
// First transaction must be coinbase, the rest must not be
|
||||||
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
|
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-missing", "first tx is not coinbase");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase");
|
||||||
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
||||||
if (block.vtx[i]->IsCoinBase())
|
if (block.vtx[i]->IsCoinBase())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-multiple", "more than one coinbase");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
|
||||||
|
|
||||||
// Check transactions
|
// Check transactions
|
||||||
for (const auto& tx : block.vtx)
|
for (const auto& tx : block.vtx)
|
||||||
if (!CheckTransaction(*tx, state))
|
if (!CheckTransaction(*tx, state))
|
||||||
return state.Invalid(state.GetReason(), false, state.GetRejectCode(), state.GetRejectReason(),
|
return state.Invalid(state.GetReason(), false, state.GetRejectReason(),
|
||||||
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
|
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
|
||||||
|
|
||||||
unsigned int nSigOps = 0;
|
unsigned int nSigOps = 0;
|
||||||
@ -3874,7 +3876,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|||||||
}
|
}
|
||||||
// sigops limits (relaxed)
|
// sigops limits (relaxed)
|
||||||
if (nSigOps > MaxBlockSigOps())
|
if (nSigOps > MaxBlockSigOps())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
|
||||||
|
|
||||||
if (fCheckPOW && fCheckMerkleRoot)
|
if (fCheckPOW && fCheckMerkleRoot)
|
||||||
block.fChecked = true;
|
block.fChecked = true;
|
||||||
@ -3926,10 +3928,10 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
|
|||||||
|
|
||||||
if (abs(n1-n2) > n1*0.5)
|
if (abs(n1-n2) > n1*0.5)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1-n2), n1, n2, nHeight),
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1-n2), n1, n2, nHeight),
|
||||||
REJECT_INVALID, "bad-diffbits");
|
"bad-diffbits");
|
||||||
} else {
|
} else {
|
||||||
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight));
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check against checkpoints
|
// Check against checkpoints
|
||||||
@ -3940,22 +3942,23 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
|
|||||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
|
assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
|
||||||
CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints());
|
CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints());
|
||||||
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
|
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
|
return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check timestamp against prev
|
// Check timestamp against prev
|
||||||
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast()));
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast()));
|
||||||
|
|
||||||
// Check timestamp
|
// Check timestamp
|
||||||
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
|
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, REJECT_INVALID, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60));
|
return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60));
|
||||||
|
|
||||||
// check for version 2, 3 and 4 upgrades
|
// check for version 2, 3 and 4 upgrades
|
||||||
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
|
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
|
||||||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
|
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
|
||||||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
|
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), strprintf("rejected nVersion=0x%08x block", block.nVersion));
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion),
|
||||||
|
strprintf("rejected nVersion=0x%08x block", block.nVersion));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3988,14 +3991,14 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
// Size limits
|
// Size limits
|
||||||
unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context);
|
unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context);
|
||||||
if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, PROTOCOL_VERSION) > nMaxBlockSize)
|
if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, PROTOCOL_VERSION) > nMaxBlockSize)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed");
|
||||||
|
|
||||||
// Check that all transactions are finalized and not over-sized
|
// Check that all transactions are finalized and not over-sized
|
||||||
// Also count sigops
|
// Also count sigops
|
||||||
unsigned int nSigOps = 0;
|
unsigned int nSigOps = 0;
|
||||||
for (const auto& tx : block.vtx) {
|
for (const auto& tx : block.vtx) {
|
||||||
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
|
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-nonfinal", "non-final transaction");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction");
|
||||||
}
|
}
|
||||||
if (!ContextualCheckTransaction(*tx, state, consensusParams, pindexPrev)) {
|
if (!ContextualCheckTransaction(*tx, state, consensusParams, pindexPrev)) {
|
||||||
return false;
|
return false;
|
||||||
@ -4005,7 +4008,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
|
|
||||||
// Check sigops
|
// Check sigops
|
||||||
if (nSigOps > MaxBlockSigOps(fDIP0001Active_context))
|
if (nSigOps > MaxBlockSigOps(fDIP0001Active_context))
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
|
||||||
|
|
||||||
// Enforce rule that the coinbase starts with serialized block height
|
// Enforce rule that the coinbase starts with serialized block height
|
||||||
// After DIP3/DIP4 activation, we don't enforce the height in the input script anymore.
|
// After DIP3/DIP4 activation, we don't enforce the height in the input script anymore.
|
||||||
@ -4015,13 +4018,13 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
CScript expect = CScript() << nHeight;
|
CScript expect = CScript() << nHeight;
|
||||||
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
|
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
|
||||||
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
|
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-height", "block height mismatch in coinbase");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fDIP0003Active_context) {
|
if (fDIP0003Active_context) {
|
||||||
if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
|
if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-type", "coinbase is not a CbTx");
|
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-type", "coinbase is not a CbTx");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4044,9 +4047,9 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
if (ppindex)
|
if (ppindex)
|
||||||
*ppindex = pindex;
|
*ppindex = pindex;
|
||||||
if (pindex->nStatus & BLOCK_FAILED_MASK)
|
if (pindex->nStatus & BLOCK_FAILED_MASK)
|
||||||
return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), 0, "duplicate");
|
return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate");
|
||||||
if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK)
|
if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), 0, "duplicate");
|
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), "duplicate");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4057,16 +4060,16 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
CBlockIndex* pindexPrev = nullptr;
|
CBlockIndex* pindexPrev = nullptr;
|
||||||
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
|
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
|
||||||
if (mi == m_block_index.end())
|
if (mi == m_block_index.end())
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), 0, "prev-blk-not-found");
|
return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found");
|
||||||
pindexPrev = (*mi).second;
|
pindexPrev = (*mi).second;
|
||||||
assert(pindexPrev);
|
assert(pindexPrev);
|
||||||
|
|
||||||
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
|
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
|
||||||
|
|
||||||
if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK)
|
if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK)
|
||||||
// it's ok-ish, the other node is probably missing the latest chainlock
|
// it's ok-ish, the other node is probably missing the latest chainlock
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), REJECT_INVALID, "bad-prevblk-chainlock");
|
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), "bad-prevblk-chainlock");
|
||||||
|
|
||||||
if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime()))
|
if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime()))
|
||||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
|
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
|
||||||
@ -4104,7 +4107,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
setDirtyBlockIndex.insert(invalid_walk);
|
setDirtyBlockIndex.insert(invalid_walk);
|
||||||
invalid_walk = invalid_walk->pprev;
|
invalid_walk = invalid_walk->pprev;
|
||||||
}
|
}
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4113,7 +4116,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
if (pindex == nullptr) {
|
if (pindex == nullptr) {
|
||||||
AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK);
|
AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK);
|
||||||
}
|
}
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), REJECT_INVALID, "bad-chainlock");
|
return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), "bad-chainlock");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pindex == nullptr)
|
if (pindex == nullptr)
|
||||||
@ -4324,7 +4327,7 @@ bool TestBlockValidity(CValidationState& state,
|
|||||||
|
|
||||||
uint256 hash = block.GetHash();
|
uint256 hash = block.GetHash();
|
||||||
if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
|
if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock");
|
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), "bad-chainlock");
|
||||||
}
|
}
|
||||||
|
|
||||||
CCoinsViewCache viewNew(&chainstate.CoinsTip());
|
CCoinsViewCache viewNew(&chainstate.CoinsTip());
|
||||||
|
@ -1031,14 +1031,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
|
|||||||
*/
|
*/
|
||||||
bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
|
bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
|
||||||
|
|
||||||
/** Reject codes greater or equal to this can be returned by AcceptToMemPool
|
|
||||||
* for transactions, to signal internal conditions. They cannot and should not
|
|
||||||
* be sent over the P2P network.
|
|
||||||
*/
|
|
||||||
static const unsigned int REJECT_INTERNAL = 0x100;
|
|
||||||
/** Too high fee. Can not be triggered by P2P transactions */
|
|
||||||
static const unsigned int REJECT_HIGHFEE = 0x100;
|
|
||||||
|
|
||||||
/** Get block file info entry for one block file */
|
/** Get block file info entry for one block file */
|
||||||
CBlockFileInfo* GetBlockFileInfo(size_t n);
|
CBlockFileInfo* GetBlockFileInfo(size_t n);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift
|
|||||||
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
||||||
|
|
||||||
# RPC error for non-BIP68 final transactions
|
# RPC error for non-BIP68 final transactions
|
||||||
NOT_FINAL_ERROR = "non-BIP68-final (code 64)"
|
NOT_FINAL_ERROR = "non-BIP68-final"
|
||||||
|
|
||||||
class BIP68Test(BitcoinTestFramework):
|
class BIP68Test(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
|
@ -130,7 +130,7 @@ class BIP65Test(BitcoinTestFramework):
|
|||||||
|
|
||||||
# First we show that this tx is valid except for CLTV by getting it
|
# First we show that this tx is valid except for CLTV by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
block.vtx.append(spendtx)
|
block.vtx.append(spendtx)
|
||||||
|
@ -112,7 +112,7 @@ class BIP66Test(BitcoinTestFramework):
|
|||||||
|
|
||||||
# First we show that this tx is valid except for DERSIG by getting it
|
# First we show that this tx is valid except for DERSIG by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
block.vtx.append(spendtx)
|
block.vtx.append(spendtx)
|
||||||
|
@ -20,7 +20,7 @@ from test_framework.test_framework import BitcoinTestFramework
|
|||||||
from test_framework.util import assert_equal, assert_raises_rpc_error
|
from test_framework.util import assert_equal, assert_raises_rpc_error
|
||||||
|
|
||||||
|
|
||||||
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)"
|
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
|
||||||
|
|
||||||
def trueDummy(tx):
|
def trueDummy(tx):
|
||||||
scriptSig = CScript(tx.vin[0].scriptSig)
|
scriptSig = CScript(tx.vin[0].scriptSig)
|
||||||
|
@ -77,7 +77,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
node.generate(1)
|
node.generate(1)
|
||||||
self.mempool_size = 0
|
self.mempool_size = 0
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': '18: txn-already-known'}],
|
result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}],
|
||||||
rawtxs=[raw_tx_in_block],
|
rawtxs=[raw_tx_in_block],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
node.sendrawtransaction(hexstring=raw_tx_0)
|
node.sendrawtransaction(hexstring=raw_tx_0)
|
||||||
self.mempool_size += 1
|
self.mempool_size += 1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': '18: txn-already-in-mempool'}],
|
result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}],
|
||||||
rawtxs=[raw_tx_0],
|
rawtxs=[raw_tx_0],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
txid_0_reject = tx.rehash()
|
txid_0_reject = tx.rehash()
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
# No RBF in DASH
|
# No RBF in DASH
|
||||||
result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],
|
result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
|
||||||
rawtxs=[raw_tx_0_reject],
|
rawtxs=[raw_tx_0_reject],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
|
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
|
||||||
# skip re-signing the tx
|
# skip re-signing the tx
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
maxfeerate=0,
|
maxfeerate=0,
|
||||||
)
|
)
|
||||||
@ -199,7 +199,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
# Skip re-signing the transaction for context independent checks from now on
|
# Skip re-signing the transaction for context independent checks from now on
|
||||||
# tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
|
# tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize()))
|
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize()))
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].nValue *= -1
|
tx.vout[0].nValue *= -1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -224,7 +224,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].nValue = MAX_MONEY + 1
|
tx.vout[0].nValue = MAX_MONEY + 1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vout = [tx.vout[0]] * 2
|
tx.vout = [tx.vout[0]] * 2
|
||||||
tx.vout[0].nValue = MAX_MONEY
|
tx.vout[0].nValue = MAX_MONEY
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin = [tx.vin[0]] * 2
|
tx.vin = [tx.vin[0]] * 2
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
|
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'coinbase'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -258,13 +258,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.nVersion = 4 # A version currently non-standard
|
tx.nVersion = 4 # A version currently non-standard
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
|
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
@ -273,25 +273,25 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
pubkey = key.get_pubkey().get_bytes()
|
pubkey = key.get_pubkey().get_bytes()
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3)
|
tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3)
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: bare-multisig'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
|
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
@ -299,21 +299,21 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy
|
num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy
|
||||||
tx.vout = [output_p2sh_burn] * num_scripts
|
tx.vout = [output_p2sh_burn] * num_scripts
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0] = output_p2sh_burn
|
tx.vout[0] = output_p2sh_burn
|
||||||
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
|
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
||||||
tx.vout = [tx.vout[0]] * 2
|
tx.vout = [tx.vout[0]] * 2
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -322,7 +322,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored
|
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored
|
||||||
tx.nLockTime = node.getblockcount() + 1
|
tx.nLockTime = node.getblockcount() + 1
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-final'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -331,7 +331,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||||||
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
|
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
|
||||||
# Can skip re-signing the tx because of early rejection
|
# Can skip re-signing the tx because of early rejection
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
maxfeerate=0,
|
maxfeerate=0,
|
||||||
)
|
)
|
||||||
|
@ -388,7 +388,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
# Thus, testmempoolaccept should reject
|
# Thus, testmempoolaccept should reject
|
||||||
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
|
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
|
||||||
assert_equal(testres['allowed'], False)
|
assert_equal(testres['allowed'], False)
|
||||||
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
|
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
|
||||||
# and sendrawtransaction should throw
|
# and sendrawtransaction should throw
|
||||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
||||||
# and the following calls should both succeed
|
# and the following calls should both succeed
|
||||||
@ -412,7 +412,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
# Thus, testmempoolaccept should reject
|
# Thus, testmempoolaccept should reject
|
||||||
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
|
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
|
||||||
assert_equal(testres['allowed'], False)
|
assert_equal(testres['allowed'], False)
|
||||||
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
|
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
|
||||||
# and sendrawtransaction should throw
|
# and sendrawtransaction should throw
|
||||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
|
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
|
||||||
# and the following calls should both succeed
|
# and the following calls should both succeed
|
||||||
|
Loading…
Reference in New Issue
Block a user