mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-13 11:25:02 -05:00
![Gregory Maxwell](/assets/img/avatar_default.png)
Some people keep thinking that MAX_BLOCK_BASE_SIZE is a separate size limit from the weight limit when it fact it is superfluous, and used in early tests before the witness data has been validated or just to compute worst case sizes. The size checks that use it would not behave any differently consensus wise if they were eliminated completely. Its correct value is not independently settable but is a function of the weight limit and weight formula. This patch just eliminates it and uses the scale factor as required to compute the worse case constants. It also moves the weight factor out of primitives into consensus, which is a more logical place for it.
250 lines
9.6 KiB
C++
250 lines
9.6 KiB
C++
// 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;
|
|
}
|
|
|
|
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)
|
|
{
|
|
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
|
|
|
|
if (tx.IsCoinBase())
|
|
return nSigOps;
|
|
|
|
if (flags & SCRIPT_VERIFY_P2SH) {
|
|
nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
|
|
}
|
|
|
|
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;
|
|
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags);
|
|
}
|
|
return nSigOps;
|
|
}
|
|
|
|
bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
|
|
{
|
|
// Basic checks that don't depend on any context
|
|
if (tx.vin.empty())
|
|
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
|
|
if (tx.vout.empty())
|
|
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
|
|
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
|
|
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-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 - note that this check is slow so we skip it in CheckBlock
|
|
if (fCheckDuplicateInputs) {
|
|
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())
|
|
{
|
|
if (tx.vin[0].scriptSig.size() < 2 || 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;
|
|
}
|