Changeset View
Changeset View
Standalone View
Standalone View
src/consensus/tx_verify.cpp
Show All 38 Lines | |||||
bool ContextualCheckTransaction(const Consensus::Params ¶ms, | bool ContextualCheckTransaction(const Consensus::Params ¶ms, | ||||
const CTransaction &tx, CValidationState &state, | const CTransaction &tx, CValidationState &state, | ||||
int nHeight, int64_t nLockTimeCutoff, | int nHeight, int64_t nLockTimeCutoff, | ||||
int64_t nMedianTimePast) { | int64_t nMedianTimePast) { | ||||
if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { | if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { | ||||
// While this is only one transaction, we use txns in the error to | // While this is only one transaction, we use txns in the error to | ||||
// ensure continuity with other clients. | // ensure continuity with other clients. | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); | ||||
REJECT_INVALID, "bad-txns-nonfinal", false, | |||||
"non-final transaction"); | |||||
} | } | ||||
if (IsMagneticAnomalyEnabled(params, nHeight)) { | if (IsMagneticAnomalyEnabled(params, nHeight)) { | ||||
// Size limit | // Size limit | ||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_TX_SIZE) { | if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_TX_SIZE) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-undersize"); | ||||
REJECT_INVALID, "bad-txns-undersize"); | |||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Calculates the block height and previous block's median time past at | * Calculates the block height and previous block's median time past at | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
namespace Consensus { | namespace Consensus { | ||||
bool CheckTxInputs(const CTransaction &tx, CValidationState &state, | bool CheckTxInputs(const CTransaction &tx, CValidationState &state, | ||||
const CCoinsViewCache &inputs, int nSpendHeight, | const CCoinsViewCache &inputs, int nSpendHeight, | ||||
Amount &txfee) { | Amount &txfee) { | ||||
// are the actual inputs available? | // are the actual inputs available? | ||||
if (!inputs.HaveInputs(tx)) { | if (!inputs.HaveInputs(tx)) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_MISSING_INPUTS, false, | return state.DoS(0, ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false, strprintf("%s: inputs missing/spent", __func__)); | ||||
REJECT_INVALID, "bad-txns-inputs-missingorspent", | |||||
false, | |||||
strprintf("%s: inputs missing/spent", __func__)); | |||||
} | } | ||||
Amount nValueIn = Amount::zero(); | Amount nValueIn = Amount::zero(); | ||||
for (const auto &in : tx.vin) { | for (const auto &in : tx.vin) { | ||||
const COutPoint &prevout = in.prevout; | const COutPoint &prevout = in.prevout; | ||||
const Coin &coin = inputs.AccessCoin(prevout); | const Coin &coin = inputs.AccessCoin(prevout); | ||||
assert(!coin.IsSpent()); | assert(!coin.IsSpent()); | ||||
// If prev is coinbase, check that it's matured | // If prev is coinbase, check that it's matured | ||||
if (coin.IsCoinBase() && | if (coin.IsCoinBase() && | ||||
nSpendHeight - coin.GetHeight() < COINBASE_MATURITY) { | nSpendHeight - coin.GetHeight() < COINBASE_MATURITY) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_MISSING_INPUTS, | return state.DoS(0, ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", false, strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.GetHeight())); | ||||
false, REJECT_INVALID, | |||||
"bad-txns-premature-spend-of-coinbase", false, | |||||
strprintf("tried to spend coinbase at depth %d", | |||||
nSpendHeight - coin.GetHeight())); | |||||
} | } | ||||
// Check for negative or overflow input values | // Check for negative or overflow input values | ||||
nValueIn += coin.GetTxOut().nValue; | nValueIn += coin.GetTxOut().nValue; | ||||
if (!MoneyRange(coin.GetTxOut().nValue) || !MoneyRange(nValueIn)) { | if (!MoneyRange(coin.GetTxOut().nValue) || !MoneyRange(nValueIn)) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); | ||||
REJECT_INVALID, "bad-txns-inputvalues-outofrange"); | |||||
} | } | ||||
} | } | ||||
const Amount value_out = tx.GetValueOut(); | const Amount value_out = tx.GetValueOut(); | ||||
if (nValueIn < value_out) { | if (nValueIn < value_out) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout", false, strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out))); | ||||
REJECT_INVALID, "bad-txns-in-belowout", false, | |||||
strprintf("value in (%s) < value out (%s)", | |||||
FormatMoney(nValueIn), | |||||
FormatMoney(value_out))); | |||||
} | } | ||||
// Tally transaction fees | // Tally transaction fees | ||||
const Amount txfee_aux = nValueIn - value_out; | const Amount txfee_aux = nValueIn - value_out; | ||||
if (!MoneyRange(txfee_aux)) { | if (!MoneyRange(txfee_aux)) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange"); | ||||
REJECT_INVALID, "bad-txns-fee-outofrange"); | |||||
} | } | ||||
txfee = txfee_aux; | txfee = txfee_aux; | ||||
return true; | return true; | ||||
} | } | ||||
} // namespace Consensus | } // namespace Consensus |