diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-01-30 16:45:11 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-01-30 16:45:26 +0100 |
commit | 19007cf5529bc35a3baf53b14c6559bda3b2b206 (patch) | |
tree | 5a4e03f7a07a2d6185c06ce941eff40ba6b29bce /src | |
parent | 2df5e3427c127f69a958be4201ce543aaaf8bcc3 (diff) | |
parent | c117d9e93a712c3f1e2001bdb6e20e7a1c5e339b (diff) |
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)
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 86 | ||||
-rw-r--r-- | src/main.h | 6 |
2 files changed, 47 insertions, 45 deletions
diff --git a/src/main.cpp b/src/main.cpp index 3c174a4650..4532b776c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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) { 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) { 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) { 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 // 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 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 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 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 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 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) { // 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 // 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 } } else - return state.Error(); + return state.Error("out of disk space"); } } @@ -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 // 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 } 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 } 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) // 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) 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) (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) 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 // 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 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 if (bnNewBlock > bnRequired) { return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"), - REJECT_INVALID, "invalid pow"); + REJECT_INVALID, "bad-diffbits"); } } diff --git a/src/main.h b/src/main.h index ba353a885b..bbf6fce48b 100644 --- a/src/main.h +++ b/src/main.h @@ -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; |