Merge bitcoin#8329: Consensus: MOVEONLY: Move functions for tx verification (#3030)
* Merge #8329: Consensus: MOVEONLY: Move functions for tx verification 618d07f MOVEONLY: tx functions to consensus/tx_verify.o (Jorge Timón) Tree-SHA512: 63fa2777c070a344dbfe61974526a770d962e049881c6f371b0034b1682c1e6e24f47454f01ee35ded20ade34488e023d4467a05369662906b99a73bb5de8497 * remove GetTransactionSigOpCost Signed-off-by: Pasta <pasta@dashboost.org> * fix, properly copy (methods moved had diverged from upstream), more fixing Signed-off-by: Pasta <pasta@dashboost.org>
This commit is contained in:
parent
8231255dd3
commit
7e4318dda8
@ -122,6 +122,7 @@ BITCOIN_CORE_H = \
|
|||||||
compat/sanity.h \
|
compat/sanity.h \
|
||||||
compressor.h \
|
compressor.h \
|
||||||
consensus/consensus.h \
|
consensus/consensus.h \
|
||||||
|
consensus/tx_verify.h \
|
||||||
core_io.h \
|
core_io.h \
|
||||||
core_memusage.h \
|
core_memusage.h \
|
||||||
cuckoocache.h \
|
cuckoocache.h \
|
||||||
@ -261,6 +262,7 @@ libdash_server_a_SOURCES = \
|
|||||||
blockencodings.cpp \
|
blockencodings.cpp \
|
||||||
chain.cpp \
|
chain.cpp \
|
||||||
checkpoints.cpp \
|
checkpoints.cpp \
|
||||||
|
consensus/tx_verify.cpp \
|
||||||
dsnotificationinterface.cpp \
|
dsnotificationinterface.cpp \
|
||||||
evo/cbtx.cpp \
|
evo/cbtx.cpp \
|
||||||
evo/deterministicmns.cpp \
|
evo/deterministicmns.cpp \
|
||||||
|
239
src/consensus/tx_verify.cpp
Normal file
239
src/consensus/tx_verify.cpp
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
// Copyright (c) 2017-2017 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "tx_verify.h"
|
||||||
|
|
||||||
|
#include "consensus.h"
|
||||||
|
#include "primitives/transaction.h"
|
||||||
|
#include "script/interpreter.h"
|
||||||
|
#include "validation.h"
|
||||||
|
|
||||||
|
// TODO remove the following dependencies
|
||||||
|
#include "chain.h"
|
||||||
|
#include "coins.h"
|
||||||
|
#include "utilmoneystr.h"
|
||||||
|
|
||||||
|
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
|
||||||
|
{
|
||||||
|
if (tx.nLockTime == 0)
|
||||||
|
return true;
|
||||||
|
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
|
||||||
|
return true;
|
||||||
|
for (const auto& txin : tx.vin) {
|
||||||
|
if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
|
||||||
|
{
|
||||||
|
assert(prevHeights->size() == tx.vin.size());
|
||||||
|
|
||||||
|
// Will be set to the equivalent height- and time-based nLockTime
|
||||||
|
// values that would be necessary to satisfy all relative lock-
|
||||||
|
// time constraints given our view of block chain history.
|
||||||
|
// The semantics of nLockTime are the last invalid height/time, so
|
||||||
|
// use -1 to have the effect of any height or time being valid.
|
||||||
|
int nMinHeight = -1;
|
||||||
|
int64_t nMinTime = -1;
|
||||||
|
|
||||||
|
// tx.nVersion is signed integer so requires cast to unsigned otherwise
|
||||||
|
// we would be doing a signed comparison and half the range of nVersion
|
||||||
|
// wouldn't support BIP 68.
|
||||||
|
bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
|
||||||
|
&& flags & LOCKTIME_VERIFY_SEQUENCE;
|
||||||
|
|
||||||
|
// Do not enforce sequence numbers as a relative lock time
|
||||||
|
// unless we have been instructed to
|
||||||
|
if (!fEnforceBIP68) {
|
||||||
|
return std::make_pair(nMinHeight, nMinTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
||||||
|
const CTxIn& txin = tx.vin[txinIndex];
|
||||||
|
|
||||||
|
// Sequence numbers with the most significant bit set are not
|
||||||
|
// treated as relative lock-times, nor are they given any
|
||||||
|
// consensus-enforced meaning at this point.
|
||||||
|
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
|
||||||
|
// The height of this input is not relevant for sequence locks
|
||||||
|
(*prevHeights)[txinIndex] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nCoinHeight = (*prevHeights)[txinIndex];
|
||||||
|
|
||||||
|
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
|
||||||
|
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
|
||||||
|
// NOTE: Subtract 1 to maintain nLockTime semantics
|
||||||
|
// BIP 68 relative lock times have the semantics of calculating
|
||||||
|
// the first block or time at which the transaction would be
|
||||||
|
// valid. When calculating the effective block time or height
|
||||||
|
// for the entire transaction, we switch to using the
|
||||||
|
// semantics of nLockTime which is the last invalid block
|
||||||
|
// time or height. Thus we subtract 1 from the calculated
|
||||||
|
// time or height.
|
||||||
|
|
||||||
|
// Time-based relative lock-times are measured from the
|
||||||
|
// smallest allowed timestamp of the block containing the
|
||||||
|
// txout being spent, which is the median time past of the
|
||||||
|
// block prior.
|
||||||
|
nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
|
||||||
|
} else {
|
||||||
|
nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(nMinHeight, nMinTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
|
||||||
|
{
|
||||||
|
assert(block.pprev);
|
||||||
|
int64_t nBlockTime = block.pprev->GetMedianTimePast();
|
||||||
|
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
|
||||||
|
{
|
||||||
|
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetLegacySigOpCount(const CTransaction& tx)
|
||||||
|
{
|
||||||
|
unsigned int nSigOps = 0;
|
||||||
|
for (const auto& txin : tx.vin)
|
||||||
|
{
|
||||||
|
nSigOps += txin.scriptSig.GetSigOpCount(false);
|
||||||
|
}
|
||||||
|
for (const auto& txout : tx.vout)
|
||||||
|
{
|
||||||
|
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
|
||||||
|
}
|
||||||
|
return nSigOps;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
|
||||||
|
{
|
||||||
|
if (tx.IsCoinBase())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned int nSigOps = 0;
|
||||||
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
|
{
|
||||||
|
const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
|
||||||
|
assert(!coin.IsSpent());
|
||||||
|
const CTxOut &prevout = coin.out;
|
||||||
|
if (prevout.scriptPubKey.IsPayToScriptHash())
|
||||||
|
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
|
||||||
|
}
|
||||||
|
return nSigOps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||||
|
{
|
||||||
|
bool allowEmptyTxInOut = false;
|
||||||
|
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||||
|
allowEmptyTxInOut = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic checks that don't depend on any context
|
||||||
|
if (!allowEmptyTxInOut && tx.vin.empty())
|
||||||
|
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
|
||||||
|
if (!allowEmptyTxInOut && tx.vout.empty())
|
||||||
|
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
|
||||||
|
// Size limits
|
||||||
|
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
|
||||||
|
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-payload-oversize");
|
||||||
|
|
||||||
|
// Check for negative or overflow output values
|
||||||
|
CAmount nValueOut = 0;
|
||||||
|
for (const auto& txout : tx.vout)
|
||||||
|
{
|
||||||
|
if (txout.nValue < 0)
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
|
||||||
|
if (txout.nValue > MAX_MONEY)
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
|
||||||
|
nValueOut += txout.nValue;
|
||||||
|
if (!MoneyRange(nValueOut))
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for duplicate inputs
|
||||||
|
std::set<COutPoint> vInOutPoints;
|
||||||
|
for (const auto& txin : tx.vin)
|
||||||
|
{
|
||||||
|
if (!vInOutPoints.insert(txin.prevout).second)
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.IsCoinBase())
|
||||||
|
{
|
||||||
|
size_t minCbSize = 2;
|
||||||
|
if (tx.nType == TRANSACTION_COINBASE) {
|
||||||
|
// With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height
|
||||||
|
minCbSize = 1;
|
||||||
|
}
|
||||||
|
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto& txin : tx.vin)
|
||||||
|
if (txin.prevout.IsNull())
|
||||||
|
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
return true;
|
||||||
|
}
|
69
src/consensus/tx_verify.h
Normal file
69
src/consensus/tx_verify.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) 2017-2017 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_CONSENSUS_TX_VERIFY_H
|
||||||
|
#define BITCOIN_CONSENSUS_TX_VERIFY_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CBlockIndex;
|
||||||
|
class CCoinsViewCache;
|
||||||
|
class CTransaction;
|
||||||
|
class CValidationState;
|
||||||
|
|
||||||
|
/** Transaction validation functions */
|
||||||
|
|
||||||
|
/** Context-independent validity checks */
|
||||||
|
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||||
|
|
||||||
|
namespace Consensus {
|
||||||
|
/**
|
||||||
|
* Check whether all inputs of this transaction are valid (no double spends and amounts)
|
||||||
|
* This does not modify the UTXO set. This does not check scripts and sigs.
|
||||||
|
* Preconditions: tx.IsCoinBase() is false.
|
||||||
|
*/
|
||||||
|
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
|
||||||
|
} // namespace Consensus
|
||||||
|
|
||||||
|
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
||||||
|
* @return number of sigops this transaction's outputs will produce when spent
|
||||||
|
* @see CTransaction::FetchInputs
|
||||||
|
*/
|
||||||
|
unsigned int GetLegacySigOpCount(const CTransaction& tx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count ECDSA signature operations in pay-to-script-hash inputs.
|
||||||
|
*
|
||||||
|
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||||
|
* @return maximum number of sigops required to validate this transaction's inputs
|
||||||
|
* @see CTransaction::FetchInputs
|
||||||
|
*/
|
||||||
|
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if transaction is final and can be included in a block with the
|
||||||
|
* specified height and time. Consensus critical.
|
||||||
|
*/
|
||||||
|
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the block height and previous block's median time past at
|
||||||
|
* which the transaction will be considered final in the context of BIP 68.
|
||||||
|
* Also removes from the vector of input heights any entries which did not
|
||||||
|
* correspond to sequence locked inputs as they do not affect the calculation.
|
||||||
|
*/
|
||||||
|
std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
|
||||||
|
|
||||||
|
bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair);
|
||||||
|
/**
|
||||||
|
* Check if transaction is final per BIP 68 sequence numbers and can be included in a block.
|
||||||
|
* Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed.
|
||||||
|
*/
|
||||||
|
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
|
||||||
|
|
||||||
|
#endif // BITCOIN_CONSENSUS_TX_VERIFY_H
|
@ -11,6 +11,7 @@
|
|||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/tx_verify.h"
|
||||||
#include "consensus/merkle.h"
|
#include "consensus/merkle.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
#include "consensus/merkle.h"
|
#include "consensus/merkle.h"
|
||||||
|
#include "consensus/tx_verify.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "validation.h"
|
#include "validation.h"
|
||||||
#include "masternode/masternode-payments.h"
|
#include "masternode/masternode-payments.h"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "validation.h"
|
#include "validation.h"
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
// 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/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "data/sighash.json.h"
|
#include "data/sighash.json.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "validation.h" // For CheckTransaction
|
|
||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 "pubkey.h"
|
#include "pubkey.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
|
@ -8,11 +8,12 @@
|
|||||||
|
|
||||||
#include "clientversion.h"
|
#include "clientversion.h"
|
||||||
#include "checkqueue.h"
|
#include "checkqueue.h"
|
||||||
|
#include "consensus/tx_verify.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "validation.h" // For CheckTransaction
|
#include "validation.h"
|
||||||
#include "policy/policy.h"
|
#include "policy/policy.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
|
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/tx_verify.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "validation.h"
|
#include "validation.h"
|
||||||
#include "policy/policy.h"
|
#include "policy/policy.h"
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "checkqueue.h"
|
#include "checkqueue.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
#include "consensus/merkle.h"
|
#include "consensus/merkle.h"
|
||||||
|
#include "consensus/tx_verify.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
@ -207,19 +208,6 @@ static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfte
|
|||||||
static bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
|
static bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
|
||||||
static FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
static FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
||||||
|
|
||||||
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
|
|
||||||
{
|
|
||||||
if (tx.nLockTime == 0)
|
|
||||||
return true;
|
|
||||||
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
|
|
||||||
return true;
|
|
||||||
for (const auto& txin : tx.vin) {
|
|
||||||
if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckFinalTx(const CTransaction &tx, int flags)
|
bool CheckFinalTx(const CTransaction &tx, int flags)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
@ -252,89 +240,6 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
|
|||||||
return IsFinalTx(tx, nBlockHeight, nBlockTime);
|
return IsFinalTx(tx, nBlockHeight, nBlockTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the block height and previous block's median time past at
|
|
||||||
* which the transaction will be considered final in the context of BIP 68.
|
|
||||||
* Also removes from the vector of input heights any entries which did not
|
|
||||||
* correspond to sequence locked inputs as they do not affect the calculation.
|
|
||||||
*/
|
|
||||||
static std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
|
|
||||||
{
|
|
||||||
assert(prevHeights->size() == tx.vin.size());
|
|
||||||
|
|
||||||
// Will be set to the equivalent height- and time-based nLockTime
|
|
||||||
// values that would be necessary to satisfy all relative lock-
|
|
||||||
// time constraints given our view of block chain history.
|
|
||||||
// The semantics of nLockTime are the last invalid height/time, so
|
|
||||||
// use -1 to have the effect of any height or time being valid.
|
|
||||||
int nMinHeight = -1;
|
|
||||||
int64_t nMinTime = -1;
|
|
||||||
|
|
||||||
// tx.nVersion is signed integer so requires cast to unsigned otherwise
|
|
||||||
// we would be doing a signed comparison and half the range of nVersion
|
|
||||||
// wouldn't support BIP 68.
|
|
||||||
bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
|
|
||||||
&& flags & LOCKTIME_VERIFY_SEQUENCE;
|
|
||||||
|
|
||||||
// Do not enforce sequence numbers as a relative lock time
|
|
||||||
// unless we have been instructed to
|
|
||||||
if (!fEnforceBIP68) {
|
|
||||||
return std::make_pair(nMinHeight, nMinTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
|
||||||
const CTxIn& txin = tx.vin[txinIndex];
|
|
||||||
|
|
||||||
// Sequence numbers with the most significant bit set are not
|
|
||||||
// treated as relative lock-times, nor are they given any
|
|
||||||
// consensus-enforced meaning at this point.
|
|
||||||
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
|
|
||||||
// The height of this input is not relevant for sequence locks
|
|
||||||
(*prevHeights)[txinIndex] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nCoinHeight = (*prevHeights)[txinIndex];
|
|
||||||
|
|
||||||
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
|
|
||||||
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
|
|
||||||
// NOTE: Subtract 1 to maintain nLockTime semantics
|
|
||||||
// BIP 68 relative lock times have the semantics of calculating
|
|
||||||
// the first block or time at which the transaction would be
|
|
||||||
// valid. When calculating the effective block time or height
|
|
||||||
// for the entire transaction, we switch to using the
|
|
||||||
// semantics of nLockTime which is the last invalid block
|
|
||||||
// time or height. Thus we subtract 1 from the calculated
|
|
||||||
// time or height.
|
|
||||||
|
|
||||||
// Time-based relative lock-times are measured from the
|
|
||||||
// smallest allowed timestamp of the block containing the
|
|
||||||
// txout being spent, which is the median time past of the
|
|
||||||
// block prior.
|
|
||||||
nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
|
|
||||||
} else {
|
|
||||||
nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(nMinHeight, nMinTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
|
|
||||||
{
|
|
||||||
assert(block.pprev);
|
|
||||||
int64_t nBlockTime = block.pprev->GetMedianTimePast();
|
|
||||||
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
|
|
||||||
{
|
|
||||||
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TestLockPointValidity(const LockPoints* lp)
|
bool TestLockPointValidity(const LockPoints* lp)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
@ -423,37 +328,6 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
|
|||||||
return EvaluateSequenceLocks(index, lockPair);
|
return EvaluateSequenceLocks(index, lockPair);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int GetLegacySigOpCount(const CTransaction& tx)
|
|
||||||
{
|
|
||||||
unsigned int nSigOps = 0;
|
|
||||||
for (const auto& txin : tx.vin)
|
|
||||||
{
|
|
||||||
nSigOps += txin.scriptSig.GetSigOpCount(false);
|
|
||||||
}
|
|
||||||
for (const auto& txout : tx.vout)
|
|
||||||
{
|
|
||||||
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
|
|
||||||
}
|
|
||||||
return nSigOps;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
|
|
||||||
{
|
|
||||||
if (tx.IsCoinBase())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned int nSigOps = 0;
|
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
|
||||||
{
|
|
||||||
const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
|
|
||||||
assert(!coin.IsSpent());
|
|
||||||
const CTxOut &prevout = coin.out;
|
|
||||||
if (prevout.scriptPubKey.IsPayToScriptHash())
|
|
||||||
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
|
|
||||||
}
|
|
||||||
return nSigOps;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin)
|
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin)
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
@ -480,65 +354,6 @@ int GetUTXOConfirmations(const COutPoint& outpoint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|
||||||
{
|
|
||||||
bool allowEmptyTxInOut = false;
|
|
||||||
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
|
||||||
allowEmptyTxInOut = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic checks that don't depend on any context
|
|
||||||
if (!allowEmptyTxInOut && tx.vin.empty())
|
|
||||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
|
|
||||||
if (!allowEmptyTxInOut && tx.vout.empty())
|
|
||||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
|
|
||||||
// Size limits
|
|
||||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
|
|
||||||
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-payload-oversize");
|
|
||||||
|
|
||||||
// Check for negative or overflow output values
|
|
||||||
CAmount nValueOut = 0;
|
|
||||||
for (const auto& txout : tx.vout)
|
|
||||||
{
|
|
||||||
if (txout.nValue < 0)
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
|
|
||||||
if (txout.nValue > MAX_MONEY)
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
|
|
||||||
nValueOut += txout.nValue;
|
|
||||||
if (!MoneyRange(nValueOut))
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for duplicate inputs
|
|
||||||
std::set<COutPoint> vInOutPoints;
|
|
||||||
for (const auto& txin : tx.vin)
|
|
||||||
{
|
|
||||||
if (!vInOutPoints.insert(txin.prevout).second)
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.IsCoinBase())
|
|
||||||
{
|
|
||||||
size_t minCbSize = 2;
|
|
||||||
if (tx.nType == TRANSACTION_COINBASE) {
|
|
||||||
// With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height
|
|
||||||
minCbSize = 1;
|
|
||||||
}
|
|
||||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const auto& txin : tx.vin)
|
|
||||||
if (txin.prevout.IsNull())
|
|
||||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
|
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
|
||||||
{
|
{
|
||||||
int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
|
int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
|
||||||
@ -1381,52 +1196,6 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
|
|||||||
return pindexPrev->nHeight + 1;
|
return pindexPrev->nHeight + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Consensus {
|
|
||||||
bool 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");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}// namespace Consensus
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
|
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
|
||||||
* This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
|
* This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
|
||||||
|
@ -332,48 +332,11 @@ BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::D
|
|||||||
/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */
|
/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */
|
||||||
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);
|
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);
|
||||||
|
|
||||||
/**
|
|
||||||
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
|
||||||
* @return number of sigops this transaction's outputs will produce when spent
|
|
||||||
* @see CTransaction::FetchInputs
|
|
||||||
*/
|
|
||||||
unsigned int GetLegacySigOpCount(const CTransaction& tx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count ECDSA signature operations in pay-to-script-hash inputs.
|
|
||||||
*
|
|
||||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
|
||||||
* @return maximum number of sigops required to validate this transaction's inputs
|
|
||||||
* @see CTransaction::FetchInputs
|
|
||||||
*/
|
|
||||||
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
|
||||||
|
|
||||||
|
|
||||||
/** Apply the effects of this transaction on the UTXO set represented by view */
|
/** Apply the effects of this transaction on the UTXO set represented by view */
|
||||||
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
|
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
|
||||||
|
|
||||||
/** Transaction validation functions */
|
/** Transaction validation functions */
|
||||||
|
|
||||||
/** Context-independent validity checks */
|
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
|
||||||
|
|
||||||
namespace Consensus {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether all inputs of this transaction are valid (no double spends and amounts)
|
|
||||||
* This does not modify the UTXO set. This does not check scripts and sigs.
|
|
||||||
* Preconditions: tx.IsCoinBase() is false.
|
|
||||||
*/
|
|
||||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
|
|
||||||
|
|
||||||
} // namespace Consensus
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if transaction is final and can be included in a block with the
|
|
||||||
* specified height and time. Consensus critical.
|
|
||||||
*/
|
|
||||||
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if transaction will be final in the next block to be created.
|
* Check if transaction will be final in the next block to be created.
|
||||||
*
|
*
|
||||||
@ -388,12 +351,6 @@ bool CheckFinalTx(const CTransaction &tx, int flags = -1);
|
|||||||
*/
|
*/
|
||||||
bool TestLockPointValidity(const LockPoints* lp);
|
bool TestLockPointValidity(const LockPoints* lp);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if transaction is final per BIP 68 sequence numbers and can be included in a block.
|
|
||||||
* Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed.
|
|
||||||
*/
|
|
||||||
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if transaction will be BIP 68 final in the next block to be created.
|
* Check if transaction will be BIP 68 final in the next block to be created.
|
||||||
*
|
*
|
||||||
|
@ -7,15 +7,16 @@
|
|||||||
#include "wallet/walletdb.h"
|
#include "wallet/walletdb.h"
|
||||||
|
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
|
#include "consensus/tx_verify.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "validation.h" // For CheckTransaction
|
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utiltime.h"
|
#include "utiltime.h"
|
||||||
#include "wallet/wallet.h"
|
#include "wallet/wallet.h"
|
||||||
|
#include "validation.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user