Browse Source

Merge pull request #3592

c117d9e Support for error messages and a few more rejection reasons (Luke Dashjr)
14e7ffc Use standard BIP 22 rejection reasons where applicable (Luke Dashjr)
0.10
Wladimir J. van der Laan 11 years ago
parent
commit
19007cf552
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 86
      src/main.cpp
  2. 6
      src/main.h

86
src/main.cpp

@ -637,14 +637,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) @@ -637,14 +637,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;
@ -652,14 +652,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) @@ -652,14 +652,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
@ -668,7 +668,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) @@ -668,7 +668,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);
}
@ -676,14 +676,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) @@ -676,14 +676,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;
@ -791,7 +791,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa @@ -791,7 +791,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();
@ -1410,30 +1410,30 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach @@ -1410,30 +1410,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.
@ -1630,7 +1630,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C @@ -1630,7 +1630,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");
}
}
@ -1660,13 +1660,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C @@ -1660,13 +1660,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)
{
@ -1676,7 +1676,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C @@ -1676,7 +1676,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();
@ -1703,7 +1703,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C @@ -1703,7 +1703,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);
@ -1762,7 +1762,7 @@ bool static WriteChainState(CValidationState &state) { @@ -1762,7 +1762,7 @@ bool static WriteChainState(CValidationState &state) {
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
return state.Error();
return state.Error("out of disk space");
FlushBlockFile();
pblocktree->Sync();
if (!pcoinsTip->Flush())
@ -1987,7 +1987,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos @@ -1987,7 +1987,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
// Check for duplicate
uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString()));
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString()), 0, "duplicate");
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(block);
@ -2082,7 +2082,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd @@ -2082,7 +2082,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
}
}
else
return state.Error();
return state.Error("out of disk space");
}
}
@ -2128,7 +2128,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne @@ -2128,7 +2128,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
}
}
else
return state.Error();
return state.Error("out of disk space");
}
return true;
@ -2143,26 +2143,26 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo @@ -2143,26 +2143,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)
@ -2182,7 +2182,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo @@ -2182,7 +2182,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)
@ -2191,12 +2191,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo @@ -2191,12 +2191,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;
}
@ -2206,7 +2206,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) @@ -2206,7 +2206,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
// Check for duplicate
uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"), 0, "duplicate");
// Get prev block index
CBlockIndex* pindexPrev = NULL;
@ -2214,25 +2214,25 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) @@ -2214,25 +2214,25 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
if (hash != Params().HashGenesisBlock()) {
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
return state.DoS(10, error("AcceptBlock() : prev block not found"));
return state.DoS(10, error("AcceptBlock() : prev block not found"), 0, "bad-prevblk");
pindexPrev = (*mi).second;
nHeight = pindexPrev->nHeight+1;
// 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))
@ -2246,7 +2246,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) @@ -2246,7 +2246,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
@ -2260,7 +2260,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) @@ -2260,7 +2260,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");
}
}
}
@ -2337,9 +2337,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl @@ -2337,9 +2337,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
// Check for duplicate
uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString()));
return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString()), 0, "duplicate");
if (mapOrphanBlocks.count(hash))
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()));
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()), 0, "duplicate");
// Preliminary checks
if (!CheckBlock(*pblock, state)) {
@ -2356,7 +2356,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl @@ -2356,7 +2356,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);
@ -2365,7 +2365,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl @@ -2365,7 +2365,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");
}
}

6
src/main.h

@ -952,13 +952,15 @@ public: @@ -952,13 +952,15 @@ public:
unsigned char _chRejectCode=0, std::string _strRejectReason="") {
return DoS(0, ret, _chRejectCode, _strRejectReason);
}
bool Error() {
bool Error(std::string strRejectReasonIn="") {
if (mode == MODE_VALID)
strRejectReason = strRejectReasonIn;
mode = MODE_ERROR;
return false;
}
bool Abort(const std::string &msg) {
AbortNode(msg);
return Error();
return Error(msg);
}
bool IsValid() const {
return mode == MODE_VALID;

Loading…
Cancel
Save