Changeset View
Changeset View
Standalone View
Standalone View
src/consensus/tx_verify.cpp
// Copyright (c) 2018 The Bitcoin developers | // Copyright (c) 2018 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <consensus/tx_verify.h> | #include <consensus/tx_verify.h> | ||||
#include <amount.h> | |||||
#include <chain.h> | #include <chain.h> | ||||
#include <coins.h> | #include <coins.h> | ||||
#include <consensus/activation.h> | #include <consensus/activation.h> | ||||
#include <consensus/consensus.h> | #include <consensus/consensus.h> | ||||
#include <consensus/validation.h> | #include <consensus/validation.h> | ||||
#include <primitives/transaction.h> | #include <primitives/transaction.h> | ||||
#include <script/script_flags.h> | #include <script/script_flags.h> | ||||
#include <utilmoneystr.h> // For FormatMoney | #include <utilmoneystr.h> // For FormatMoney | ||||
▲ Show 20 Lines • Show All 256 Lines • ▼ Show 20 Lines | for (const auto &txin : tx.vin) { | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
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, | ||||
// This doesn't trigger the DoS code on purpose; if it did, it would make it | Amount &txfee) { | ||||
// easier for an attacker to attempt to split the network. | // are the actual inputs available? | ||||
if (!inputs.HaveInputs(tx)) { | if (!inputs.HaveInputs(tx)) { | ||||
return state.Invalid(false, 0, "", "Inputs unavailable"); | return state.DoS(100, false, REJECT_INVALID, | ||||
"bad-txns-inputs-missingorspent", false, | |||||
strprintf("%s: inputs missing/spent", __func__)); | |||||
} | } | ||||
Amount nValueIn = Amount::zero(); | Amount nValueIn = Amount::zero(); | ||||
Amount nFees = 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()) { | ||||
if (nSpendHeight - coin.GetHeight() < COINBASE_MATURITY) { | if (nSpendHeight - coin.GetHeight() < COINBASE_MATURITY) { | ||||
return state.Invalid( | return state.Invalid( | ||||
false, REJECT_INVALID, | false, REJECT_INVALID, | ||||
"bad-txns-premature-spend-of-coinbase", | "bad-txns-premature-spend-of-coinbase", | ||||
strprintf("tried to spend coinbase at depth %d", | strprintf("tried to spend coinbase at depth %d", | ||||
nSpendHeight - coin.GetHeight())); | 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, false, REJECT_INVALID, | return state.DoS(100, false, REJECT_INVALID, | ||||
"bad-txns-inputvalues-outofrange"); | "bad-txns-inputvalues-outofrange"); | ||||
} | } | ||||
} | } | ||||
if (nValueIn < tx.GetValueOut()) { | const Amount value_out = tx.GetValueOut(); | ||||
if (nValueIn < value_out) { | |||||
return state.DoS( | return state.DoS( | ||||
100, false, REJECT_INVALID, "bad-txns-in-belowout", false, | 100, false, REJECT_INVALID, "bad-txns-in-belowout", false, | ||||
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), | strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), | ||||
FormatMoney(tx.GetValueOut()))); | FormatMoney(value_out))); | ||||
} | } | ||||
// Tally transaction fees | // Tally transaction fees | ||||
Amount nTxFee = nValueIn - tx.GetValueOut(); | const Amount txfee_aux = nValueIn - value_out; | ||||
if (nTxFee < Amount::zero()) { | if (!MoneyRange(txfee_aux)) { | ||||
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 state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); | ||||
} | } | ||||
txfee = txfee_aux; | |||||
return true; | return true; | ||||
} | } | ||||
} // namespace Consensus | } // namespace Consensus |