|
|
|
@ -605,14 +605,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
@@ -605,14 +605,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|
|
|
|
// Basic checks that don't depend on any context
|
|
|
|
|
if (tx.vin.empty()) |
|
|
|
|
return state.DoS(10, error("CheckTransaction() : vin empty"), |
|
|
|
|
REJECT_INVALID, "vin empty"); |
|
|
|
|
REJECT_INVALID, "bad-txns-vin-empty"); |
|
|
|
|
if (tx.vout.empty()) |
|
|
|
|
return state.DoS(10, error("CheckTransaction() : vout empty"), |
|
|
|
|
REJECT_INVALID, "vout empty"); |
|
|
|
|
REJECT_INVALID, "bad-txns-vout-empty"); |
|
|
|
|
// Size limits
|
|
|
|
|
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) |
|
|
|
|
return state.DoS(100, error("CheckTransaction() : size limits failed"), |
|
|
|
|
REJECT_INVALID, "oversize"); |
|
|
|
|
REJECT_INVALID, "bad-txns-oversize"); |
|
|
|
|
|
|
|
|
|
// Check for negative or overflow output values
|
|
|
|
|
int64_t nValueOut = 0; |
|
|
|
@ -620,14 +620,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
@@ -620,14 +620,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|
|
|
|
{ |
|
|
|
|
if (txout.nValue < 0) |
|
|
|
|
return state.DoS(100, error("CheckTransaction() : txout.nValue negative"), |
|
|
|
|
REJECT_INVALID, "vout negative"); |
|
|
|
|
REJECT_INVALID, "bad-txns-vout-negative"); |
|
|
|
|
if (txout.nValue > MAX_MONEY) |
|
|
|
|
return state.DoS(100, error("CheckTransaction() : txout.nValue too high"), |
|
|
|
|
REJECT_INVALID, "vout too large"); |
|
|
|
|
REJECT_INVALID, "bad-txns-vout-toolarge"); |
|
|
|
|
nValueOut += txout.nValue; |
|
|
|
|
if (!MoneyRange(nValueOut)) |
|
|
|
|
return state.DoS(100, error("CheckTransaction() : txout total out of range"), |
|
|
|
|
REJECT_INVALID, "txout total too large"); |
|
|
|
|
REJECT_INVALID, "bad-txns-txouttotal-toolarge"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check for duplicate inputs
|
|
|
|
@ -636,7 +636,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
@@ -636,7 +636,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|
|
|
|
{ |
|
|
|
|
if (vInOutPoints.count(txin.prevout)) |
|
|
|
|
return state.DoS(100, error("CheckTransaction() : duplicate inputs"), |
|
|
|
|
REJECT_INVALID, "duplicate inputs"); |
|
|
|
|
REJECT_INVALID, "bad-txns-inputs-duplicate"); |
|
|
|
|
vInOutPoints.insert(txin.prevout); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -644,14 +644,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
@@ -644,14 +644,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|
|
|
|
{ |
|
|
|
|
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) |
|
|
|
|
return state.DoS(100, error("CheckTransaction() : coinbase script size"), |
|
|
|
|
REJECT_INVALID, "coinbase script too large"); |
|
|
|
|
REJECT_INVALID, "bad-cb-length"); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) |
|
|
|
|
if (txin.prevout.IsNull()) |
|
|
|
|
return state.DoS(10, error("CheckTransaction() : prevout is null"), |
|
|
|
|
REJECT_INVALID, "prevout null"); |
|
|
|
|
REJECT_INVALID, "bad-txns-prevout-null"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
@ -759,7 +759,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
@@ -759,7 +759,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|
|
|
|
// are the actual inputs available?
|
|
|
|
|
if (!view.HaveInputs(tx)) |
|
|
|
|
return state.Invalid(error("AcceptToMemoryPool : inputs already spent"), |
|
|
|
|
REJECT_DUPLICATE, "inputs spent"); |
|
|
|
|
REJECT_DUPLICATE, "bad-txns-inputs-spent"); |
|
|
|
|
|
|
|
|
|
// Bring the best block into scope
|
|
|
|
|
view.GetBestBlock(); |
|
|
|
@ -1404,30 +1404,30 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
@@ -1404,30 +1404,30 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
|
|
|
|
if (nSpendHeight - coins.nHeight < COINBASE_MATURITY) |
|
|
|
|
return state.Invalid( |
|
|
|
|
error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight), |
|
|
|
|
REJECT_INVALID, "premature spend of coinbase"); |
|
|
|
|
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check for negative or overflow input values
|
|
|
|
|
nValueIn += coins.vout[prevout.n].nValue; |
|
|
|
|
if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) |
|
|
|
|
return state.DoS(100, error("CheckInputs() : txin values out of range"), |
|
|
|
|
REJECT_INVALID, "input values out of range"); |
|
|
|
|
REJECT_INVALID, "bad-txns-inputvalues-outofrange"); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nValueIn < tx.GetValueOut()) |
|
|
|
|
return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString()), |
|
|
|
|
REJECT_INVALID, "in < out"); |
|
|
|
|
REJECT_INVALID, "bad-txns-in-belowout"); |
|
|
|
|
|
|
|
|
|
// Tally transaction fees
|
|
|
|
|
int64_t nTxFee = nValueIn - tx.GetValueOut(); |
|
|
|
|
if (nTxFee < 0) |
|
|
|
|
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), |
|
|
|
|
REJECT_INVALID, "fee < 0"); |
|
|
|
|
REJECT_INVALID, "bad-txns-fee-negative"); |
|
|
|
|
nFees += nTxFee; |
|
|
|
|
if (!MoneyRange(nFees)) |
|
|
|
|
return state.DoS(100, error("CheckInputs() : nFees out of range"), |
|
|
|
|
REJECT_INVALID, "fee out of range"); |
|
|
|
|
REJECT_INVALID, "bad-txns-fee-outofrange"); |
|
|
|
|
|
|
|
|
|
// The first loop above does all the inexpensive checks.
|
|
|
|
|
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
|
|
|
|
@ -1624,7 +1624,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
@@ -1624,7 +1624,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|
|
|
|
uint256 hash = block.GetTxHash(i); |
|
|
|
|
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) |
|
|
|
|
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), |
|
|
|
|
REJECT_INVALID, "BIP30"); |
|
|
|
|
REJECT_INVALID, "bad-txns-BIP30"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1654,13 +1654,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
@@ -1654,13 +1654,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|
|
|
|
nSigOps += GetLegacySigOpCount(tx); |
|
|
|
|
if (nSigOps > MAX_BLOCK_SIGOPS) |
|
|
|
|
return state.DoS(100, error("ConnectBlock() : too many sigops"), |
|
|
|
|
REJECT_INVALID, "too many sigops"); |
|
|
|
|
REJECT_INVALID, "bad-blk-sigops"); |
|
|
|
|
|
|
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
|
{ |
|
|
|
|
if (!view.HaveInputs(tx)) |
|
|
|
|
return state.DoS(100, error("ConnectBlock() : inputs missing/spent"), |
|
|
|
|
REJECT_INVALID, "inputs missing/spent"); |
|
|
|
|
REJECT_INVALID, "bad-txns-inputs-missingorspent"); |
|
|
|
|
|
|
|
|
|
if (fStrictPayToScriptHash) |
|
|
|
|
{ |
|
|
|
@ -1670,7 +1670,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
@@ -1670,7 +1670,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|
|
|
|
nSigOps += GetP2SHSigOpCount(tx, view); |
|
|
|
|
if (nSigOps > MAX_BLOCK_SIGOPS) |
|
|
|
|
return state.DoS(100, error("ConnectBlock() : too many sigops"), |
|
|
|
|
REJECT_INVALID, "too many sigops"); |
|
|
|
|
REJECT_INVALID, "bad-blk-sigops"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nFees += view.GetValueIn(tx)-tx.GetValueOut(); |
|
|
|
@ -1697,7 +1697,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
@@ -1697,7 +1697,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|
|
|
|
return state.DoS(100, |
|
|
|
|
error("ConnectBlock() : coinbase pays too much (actual=%"PRId64" vs limit=%"PRId64")", |
|
|
|
|
block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)), |
|
|
|
|
REJECT_INVALID, "coinbase too large"); |
|
|
|
|
REJECT_INVALID, "bad-cb-amount"); |
|
|
|
|
|
|
|
|
|
if (!control.Wait()) |
|
|
|
|
return state.DoS(100, false); |
|
|
|
@ -2075,26 +2075,26 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
@@ -2075,26 +2075,26 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|
|
|
|
// Size limits
|
|
|
|
|
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) |
|
|
|
|
return state.DoS(100, error("CheckBlock() : size limits failed"), |
|
|
|
|
REJECT_INVALID, "block size too large"); |
|
|
|
|
REJECT_INVALID, "bad-blk-length"); |
|
|
|
|
|
|
|
|
|
// Check proof of work matches claimed amount
|
|
|
|
|
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) |
|
|
|
|
return state.DoS(50, error("CheckBlock() : proof of work failed"), |
|
|
|
|
REJECT_INVALID, "invalid pow"); |
|
|
|
|
REJECT_INVALID, "high-hash"); |
|
|
|
|
|
|
|
|
|
// Check timestamp
|
|
|
|
|
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) |
|
|
|
|
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"), |
|
|
|
|
REJECT_INVALID, "time in future"); |
|
|
|
|
REJECT_INVALID, "time-too-new"); |
|
|
|
|
|
|
|
|
|
// First transaction must be coinbase, the rest must not be
|
|
|
|
|
if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) |
|
|
|
|
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"), |
|
|
|
|
REJECT_INVALID, "no coinbase"); |
|
|
|
|
REJECT_INVALID, "bad-cb-missing"); |
|
|
|
|
for (unsigned int i = 1; i < block.vtx.size(); i++) |
|
|
|
|
if (block.vtx[i].IsCoinBase()) |
|
|
|
|
return state.DoS(100, error("CheckBlock() : more than one coinbase"), |
|
|
|
|
REJECT_INVALID, "duplicate coinbase"); |
|
|
|
|
REJECT_INVALID, "bad-cb-multiple"); |
|
|
|
|
|
|
|
|
|
// Check transactions
|
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) |
|
|
|
@ -2114,7 +2114,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
@@ -2114,7 +2114,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|
|
|
|
} |
|
|
|
|
if (uniqueTx.size() != block.vtx.size()) |
|
|
|
|
return state.DoS(100, error("CheckBlock() : duplicate transaction"), |
|
|
|
|
REJECT_INVALID, "duplicate transaction", true); |
|
|
|
|
REJECT_INVALID, "bad-txns-duplicate", true); |
|
|
|
|
|
|
|
|
|
unsigned int nSigOps = 0; |
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) |
|
|
|
@ -2123,12 +2123,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
@@ -2123,12 +2123,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|
|
|
|
} |
|
|
|
|
if (nSigOps > MAX_BLOCK_SIGOPS) |
|
|
|
|
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"), |
|
|
|
|
REJECT_INVALID, "sig op count", true); |
|
|
|
|
REJECT_INVALID, "bad-blk-sigops", true); |
|
|
|
|
|
|
|
|
|
// Check merkle root
|
|
|
|
|
if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back()) |
|
|
|
|
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), |
|
|
|
|
REJECT_INVALID, "bad merkle root", true); |
|
|
|
|
REJECT_INVALID, "bad-txnmrklroot", true); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -2153,18 +2153,18 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
@@ -2153,18 +2153,18 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
|
|
|
|
// Check proof of work
|
|
|
|
|
if (block.nBits != GetNextWorkRequired(pindexPrev, &block)) |
|
|
|
|
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"), |
|
|
|
|
REJECT_INVALID, "bad pow"); |
|
|
|
|
REJECT_INVALID, "bad-diffbits"); |
|
|
|
|
|
|
|
|
|
// Check timestamp against prev
|
|
|
|
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) |
|
|
|
|
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"), |
|
|
|
|
REJECT_INVALID, "timestamp too early"); |
|
|
|
|
REJECT_INVALID, "time-too-old"); |
|
|
|
|
|
|
|
|
|
// Check that all transactions are finalized
|
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) |
|
|
|
|
if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) |
|
|
|
|
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"), |
|
|
|
|
REJECT_INVALID, "non-final tx"); |
|
|
|
|
REJECT_INVALID, "bad-txns-nonfinal"); |
|
|
|
|
|
|
|
|
|
// Check that the block chain matches the known block chain up to a checkpoint
|
|
|
|
|
if (!Checkpoints::CheckBlock(nHeight, hash)) |
|
|
|
@ -2178,7 +2178,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
@@ -2178,7 +2178,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
|
|
|
|
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) |
|
|
|
|
{ |
|
|
|
|
return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), |
|
|
|
|
REJECT_OBSOLETE, "version 1 blocks obsolete"); |
|
|
|
|
REJECT_OBSOLETE, "bad-version"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
|
|
|
|
@ -2192,7 +2192,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
@@ -2192,7 +2192,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
|
|
|
|
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || |
|
|
|
|
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) |
|
|
|
|
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), |
|
|
|
|
REJECT_INVALID, "height incorrect in coinbase"); |
|
|
|
|
REJECT_INVALID, "bad-cb-height"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -2285,7 +2285,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
@@ -2285,7 +2285,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|
|
|
|
if (deltaTime < 0) |
|
|
|
|
{ |
|
|
|
|
return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"), |
|
|
|
|
REJECT_CHECKPOINT, "timestamp before checkpoint"); |
|
|
|
|
REJECT_CHECKPOINT, "time-too-old"); |
|
|
|
|
} |
|
|
|
|
CBigNum bnNewBlock; |
|
|
|
|
bnNewBlock.SetCompact(pblock->nBits); |
|
|
|
@ -2294,7 +2294,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
@@ -2294,7 +2294,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|
|
|
|
if (bnNewBlock > bnRequired) |
|
|
|
|
{ |
|
|
|
|
return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"), |
|
|
|
|
REJECT_INVALID, "invalid pow"); |
|
|
|
|
REJECT_INVALID, "bad-diffbits"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|