|
|
|
@ -13,7 +13,7 @@
@@ -13,7 +13,7 @@
|
|
|
|
|
#include "chain.h" |
|
|
|
|
#include "coins.h" |
|
|
|
|
#include "utilmoneystr.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) |
|
|
|
|
{ |
|
|
|
|
if (tx.nLockTime == 0) |
|
|
|
@ -207,44 +207,46 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
@@ -207,44 +207,46 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
|
|
|
|
|
|
|
|
|
|
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight) |
|
|
|
|
{ |
|
|
|
|
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
|
|
|
|
|
// for an attacker to attempt to split the network.
|
|
|
|
|
if (!inputs.HaveInputs(tx)) |
|
|
|
|
return state.Invalid(false, 0, "", "Inputs unavailable"); |
|
|
|
|
|
|
|
|
|
CAmount nValueIn = 0; |
|
|
|
|
CAmount nFees = 0; |
|
|
|
|
for (unsigned int i = 0; i < tx.vin.size(); i++) |
|
|
|
|
{ |
|
|
|
|
const COutPoint &prevout = tx.vin[i].prevout; |
|
|
|
|
const Coin& coin = inputs.AccessCoin(prevout); |
|
|
|
|
assert(!coin.IsSpent()); |
|
|
|
|
|
|
|
|
|
// If prev is coinbase, check that it's matured
|
|
|
|
|
if (coin.IsCoinBase()) { |
|
|
|
|
if (nSpendHeight - coin.nHeight < COINBASE_MATURITY) |
|
|
|
|
return state.Invalid(false, |
|
|
|
|
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", |
|
|
|
|
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check for negative or overflow input values
|
|
|
|
|
nValueIn += coin.out.nValue; |
|
|
|
|
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); |
|
|
|
|
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
|
|
|
|
|
// for an attacker to attempt to split the network.
|
|
|
|
|
if (!inputs.HaveInputs(tx)) { |
|
|
|
|
return state.Invalid(false, 0, "", "Inputs unavailable"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CAmount nValueIn = 0; |
|
|
|
|
CAmount nFees = 0; |
|
|
|
|
for (unsigned int i = 0; i < tx.vin.size(); ++i) { |
|
|
|
|
const COutPoint &prevout = tx.vin[i].prevout; |
|
|
|
|
const Coin& coin = inputs.AccessCoin(prevout); |
|
|
|
|
assert(!coin.IsSpent()); |
|
|
|
|
|
|
|
|
|
// If prev is coinbase, check that it's matured
|
|
|
|
|
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) { |
|
|
|
|
return state.Invalid(false, |
|
|
|
|
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", |
|
|
|
|
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check for negative or overflow input values
|
|
|
|
|
nValueIn += coin.out.nValue; |
|
|
|
|
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nValueIn < tx.GetValueOut()) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, |
|
|
|
|
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nValueIn < tx.GetValueOut()) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, |
|
|
|
|
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()))); |
|
|
|
|
|
|
|
|
|
// Tally transaction fees
|
|
|
|
|
CAmount nTxFee = nValueIn - tx.GetValueOut(); |
|
|
|
|
if (nTxFee < 0) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); |
|
|
|
|
nFees += nTxFee; |
|
|
|
|
if (!MoneyRange(nFees)) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); |
|
|
|
|
// Tally transaction fees
|
|
|
|
|
CAmount nTxFee = nValueIn - tx.GetValueOut(); |
|
|
|
|
if (nTxFee < 0) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); |
|
|
|
|
} |
|
|
|
|
nFees += nTxFee; |
|
|
|
|
if (!MoneyRange(nFees)) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|