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)
This commit is contained in:
Wladimir J. van der Laan 2014-01-30 16:45:11 +01:00
commit 19007cf552
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
2 changed files with 47 additions and 45 deletions

View File

@ -637,14 +637,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
// Basic checks that don't depend on any context // Basic checks that don't depend on any context
if (tx.vin.empty()) if (tx.vin.empty())
return state.DoS(10, error("CheckTransaction() : vin empty"), return state.DoS(10, error("CheckTransaction() : vin empty"),
REJECT_INVALID, "vin empty"); REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty()) if (tx.vout.empty())
return state.DoS(10, error("CheckTransaction() : vout empty"), return state.DoS(10, error("CheckTransaction() : vout empty"),
REJECT_INVALID, "vout empty"); REJECT_INVALID, "bad-txns-vout-empty");
// Size limits // Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckTransaction() : size limits failed"), return state.DoS(100, error("CheckTransaction() : size limits failed"),
REJECT_INVALID, "oversize"); REJECT_INVALID, "bad-txns-oversize");
// Check for negative or overflow output values // Check for negative or overflow output values
int64_t nValueOut = 0; int64_t nValueOut = 0;
@ -652,14 +652,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{ {
if (txout.nValue < 0) if (txout.nValue < 0)
return state.DoS(100, error("CheckTransaction() : txout.nValue negative"), return state.DoS(100, error("CheckTransaction() : txout.nValue negative"),
REJECT_INVALID, "vout negative"); REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY) if (txout.nValue > MAX_MONEY)
return state.DoS(100, error("CheckTransaction() : txout.nValue too high"), return state.DoS(100, error("CheckTransaction() : txout.nValue too high"),
REJECT_INVALID, "vout too large"); REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue; nValueOut += txout.nValue;
if (!MoneyRange(nValueOut)) if (!MoneyRange(nValueOut))
return state.DoS(100, error("CheckTransaction() : txout total out of range"), 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 // Check for duplicate inputs
@ -668,7 +668,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{ {
if (vInOutPoints.count(txin.prevout)) if (vInOutPoints.count(txin.prevout))
return state.DoS(100, error("CheckTransaction() : duplicate inputs"), return state.DoS(100, error("CheckTransaction() : duplicate inputs"),
REJECT_INVALID, "duplicate inputs"); REJECT_INVALID, "bad-txns-inputs-duplicate");
vInOutPoints.insert(txin.prevout); 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) if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, error("CheckTransaction() : coinbase script size"), return state.DoS(100, error("CheckTransaction() : coinbase script size"),
REJECT_INVALID, "coinbase script too large"); REJECT_INVALID, "bad-cb-length");
} }
else else
{ {
BOOST_FOREACH(const CTxIn& txin, tx.vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull()) if (txin.prevout.IsNull())
return state.DoS(10, error("CheckTransaction() : prevout is null"), return state.DoS(10, error("CheckTransaction() : prevout is null"),
REJECT_INVALID, "prevout null"); REJECT_INVALID, "bad-txns-prevout-null");
} }
return true; return true;
@ -791,7 +791,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// are the actual inputs available? // are the actual inputs available?
if (!view.HaveInputs(tx)) if (!view.HaveInputs(tx))
return state.Invalid(error("AcceptToMemoryPool : inputs already spent"), return state.Invalid(error("AcceptToMemoryPool : inputs already spent"),
REJECT_DUPLICATE, "inputs spent"); REJECT_DUPLICATE, "bad-txns-inputs-spent");
// Bring the best block into scope // Bring the best block into scope
view.GetBestBlock(); view.GetBestBlock();
@ -1410,30 +1410,30 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
if (nSpendHeight - coins.nHeight < COINBASE_MATURITY) if (nSpendHeight - coins.nHeight < COINBASE_MATURITY)
return state.Invalid( return state.Invalid(
error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight), 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 // Check for negative or overflow input values
nValueIn += coins.vout[prevout.n].nValue; nValueIn += coins.vout[prevout.n].nValue;
if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs() : txin values out of range"), 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()) if (nValueIn < tx.GetValueOut())
return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString()), 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 // Tally transaction fees
int64_t nTxFee = nValueIn - tx.GetValueOut(); int64_t nTxFee = nValueIn - tx.GetValueOut();
if (nTxFee < 0) if (nTxFee < 0)
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()),
REJECT_INVALID, "fee < 0"); REJECT_INVALID, "bad-txns-fee-negative");
nFees += nTxFee; nFees += nTxFee;
if (!MoneyRange(nFees)) if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs() : nFees out of range"), 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. // The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature 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); uint256 hash = block.GetTxHash(i);
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), 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); nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many sigops"), return state.DoS(100, error("ConnectBlock() : too many sigops"),
REJECT_INVALID, "too many sigops"); REJECT_INVALID, "bad-blk-sigops");
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
{ {
if (!view.HaveInputs(tx)) if (!view.HaveInputs(tx))
return state.DoS(100, error("ConnectBlock() : inputs missing/spent"), return state.DoS(100, error("ConnectBlock() : inputs missing/spent"),
REJECT_INVALID, "inputs missing/spent"); REJECT_INVALID, "bad-txns-inputs-missingorspent");
if (fStrictPayToScriptHash) if (fStrictPayToScriptHash)
{ {
@ -1676,7 +1676,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
nSigOps += GetP2SHSigOpCount(tx, view); nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many 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(); nFees += view.GetValueIn(tx)-tx.GetValueOut();
@ -1703,7 +1703,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
return state.DoS(100, return state.DoS(100,
error("ConnectBlock() : coinbase pays too much (actual=%"PRId64" vs limit=%"PRId64")", error("ConnectBlock() : coinbase pays too much (actual=%"PRId64" vs limit=%"PRId64")",
block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)), block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)),
REJECT_INVALID, "coinbase too large"); REJECT_INVALID, "bad-cb-amount");
if (!control.Wait()) if (!control.Wait())
return state.DoS(100, false); return state.DoS(100, false);
@ -1762,7 +1762,7 @@ bool static WriteChainState(CValidationState &state) {
// an overestimation, as most will delete an existing entry or // an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2. // overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize())) if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
return state.Error(); return state.Error("out of disk space");
FlushBlockFile(); FlushBlockFile();
pblocktree->Sync(); pblocktree->Sync();
if (!pcoinsTip->Flush()) if (!pcoinsTip->Flush())
@ -1987,7 +1987,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash)) 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 // Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(block); CBlockIndex* pindexNew = new CBlockIndex(block);
@ -2082,7 +2082,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
} }
} }
else 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 else
return state.Error(); return state.Error("out of disk space");
} }
return true; return true;
@ -2143,26 +2143,26 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// Size limits // Size limits
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) 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"), 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 // Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
return state.DoS(50, error("CheckBlock() : proof of work failed"), return state.DoS(50, error("CheckBlock() : proof of work failed"),
REJECT_INVALID, "invalid pow"); REJECT_INVALID, "high-hash");
// Check timestamp // Check timestamp
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"), 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 // First transaction must be coinbase, the rest must not be
if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"), 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++) for (unsigned int i = 1; i < block.vtx.size(); i++)
if (block.vtx[i].IsCoinBase()) if (block.vtx[i].IsCoinBase())
return state.DoS(100, error("CheckBlock() : more than one coinbase"), return state.DoS(100, error("CheckBlock() : more than one coinbase"),
REJECT_INVALID, "duplicate coinbase"); REJECT_INVALID, "bad-cb-multiple");
// Check transactions // Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx) 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()) if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction"), return state.DoS(100, error("CheckBlock() : duplicate transaction"),
REJECT_INVALID, "duplicate transaction", true); REJECT_INVALID, "bad-txns-duplicate", true);
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, block.vtx) 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) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"), 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 // Check merkle root
if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back()) if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
REJECT_INVALID, "bad merkle root", true); REJECT_INVALID, "bad-txnmrklroot", true);
return true; return true;
} }
@ -2206,7 +2206,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash)) 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 // Get prev block index
CBlockIndex* pindexPrev = NULL; CBlockIndex* pindexPrev = NULL;
@ -2214,25 +2214,25 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
if (hash != Params().HashGenesisBlock()) { if (hash != Params().HashGenesisBlock()) {
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock); map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end()) 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; pindexPrev = (*mi).second;
nHeight = pindexPrev->nHeight+1; nHeight = pindexPrev->nHeight+1;
// Check proof of work // Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block)) if (block.nBits != GetNextWorkRequired(pindexPrev, &block))
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"), return state.DoS(100, error("AcceptBlock() : incorrect proof of work"),
REJECT_INVALID, "bad pow"); REJECT_INVALID, "bad-diffbits");
// Check timestamp against prev // Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"), 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 // Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, block.vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"), 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 // Check that the block chain matches the known block chain up to a checkpoint
if (!Checkpoints::CheckBlock(nHeight, hash)) if (!Checkpoints::CheckBlock(nHeight, hash))
@ -2246,7 +2246,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
{ {
return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), 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 // 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() || if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), 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 // Check for duplicate
uint256 hash = pblock->GetHash(); uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash)) 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)) 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 // Preliminary checks
if (!CheckBlock(*pblock, state)) { if (!CheckBlock(*pblock, state)) {
@ -2356,7 +2356,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
if (deltaTime < 0) if (deltaTime < 0)
{ {
return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"), return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"),
REJECT_CHECKPOINT, "timestamp before checkpoint"); REJECT_CHECKPOINT, "time-too-old");
} }
CBigNum bnNewBlock; CBigNum bnNewBlock;
bnNewBlock.SetCompact(pblock->nBits); bnNewBlock.SetCompact(pblock->nBits);
@ -2365,7 +2365,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
if (bnNewBlock > bnRequired) if (bnNewBlock > bnRequired)
{ {
return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"), return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"),
REJECT_INVALID, "invalid pow"); REJECT_INVALID, "bad-diffbits");
} }
} }

View File

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