Browse Source

Report script evaluation failures in log and reject messages

0.10
Pieter Wuille 10 years ago
parent
commit
307f7d48d4
  1. 19
      src/main.cpp
  2. 12
      src/main.h

19
src/main.cpp

@ -1327,7 +1327,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
if (state.IsInvalid(nDoS)) { if (state.IsInvalid(nDoS)) {
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash()); std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
if (it != mapBlockSource.end() && State(it->second)) { if (it != mapBlockSource.end() && State(it->second)) {
CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason(), pindex->GetBlockHash()}; CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
State(it->second)->rejects.push_back(reject); State(it->second)->rejects.push_back(reject);
if (nDoS > 0) if (nDoS > 0)
Misbehaving(it->second, nDoS); Misbehaving(it->second, nDoS);
@ -1357,10 +1357,11 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
} }
bool CScriptCheck::operator()() const { bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore))) if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore), &error)) {
return error("CScriptCheck() : %s:%d VerifySignature failed", ptxTo->GetHash().ToString(), nIn); return ::error("CScriptCheck() : %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
}
return true; return true;
} }
@ -1448,7 +1449,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
CScriptCheck check(*coins, tx, i, CScriptCheck check(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
if (check()) if (check())
return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag"); return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
} }
// Failures of other flags indicate a transaction that is // Failures of other flags indicate a transaction that is
// invalid in new blocks, e.g. a invalid P2SH. We DoS ban // invalid in new blocks, e.g. a invalid P2SH. We DoS ban
@ -1457,7 +1458,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// as to the correct behavior - we may want to continue // as to the correct behavior - we may want to continue
// peering with non-upgraded nodes even after a soft-fork // peering with non-upgraded nodes even after a soft-fork
// super-majority vote has passed. // super-majority vote has passed.
return state.DoS(100,false, REJECT_INVALID, "mandatory-script-verify-flag-failed"); return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
} }
} }
} }
@ -3975,7 +3976,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->id, pfrom->cleanSubVer, pfrom->id, pfrom->cleanSubVer,
state.GetRejectReason()); state.GetRejectReason());
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
state.GetRejectReason(), inv.hash); state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS); Misbehaving(pfrom->GetId(), nDoS);
} }
@ -4049,7 +4050,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS; int nDoS;
if (state.IsInvalid(nDoS)) { if (state.IsInvalid(nDoS)) {
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
state.GetRejectReason(), inv.hash); state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) { if (nDoS > 0) {
LOCK(cs_main); LOCK(cs_main);
Misbehaving(pfrom->GetId(), nDoS); Misbehaving(pfrom->GetId(), nDoS);
@ -4256,7 +4257,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (fDebug) { if (fDebug) {
try { try {
string strMsg; unsigned char ccode; string strReason; string strMsg; unsigned char ccode; string strReason;
vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111); vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);
ostringstream ss; ostringstream ss;
ss << strMsg << " code " << itostr(ccode) << ": " << strReason; ss << strMsg << " code " << itostr(ccode) << ": " << strReason;

12
src/main.h

@ -96,6 +96,8 @@ static const unsigned int MAX_HEADERS_RESULTS = 2000;
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024; static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** Time to wait (in seconds) between writing blockchain state to disk. */ /** Time to wait (in seconds) between writing blockchain state to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 3600; static const unsigned int DATABASE_WRITE_INTERVAL = 3600;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
/** "reject" message codes **/ /** "reject" message codes **/
static const unsigned char REJECT_MALFORMED = 0x01; static const unsigned char REJECT_MALFORMED = 0x01;
@ -325,14 +327,15 @@ private:
unsigned int nIn; unsigned int nIn;
unsigned int nFlags; unsigned int nFlags;
bool cacheStore; bool cacheStore;
ScriptError error;
public: public:
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false) {} CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn) { } ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
bool operator()() const; bool operator()();
void swap(CScriptCheck &check) { void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey); scriptPubKey.swap(check.scriptPubKey);
@ -340,7 +343,10 @@ public:
std::swap(nIn, check.nIn); std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags); std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore); std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
} }
ScriptError GetScriptError() const { return error; }
}; };
/** Data structure that represents a partial merkle tree. /** Data structure that represents a partial merkle tree.

Loading…
Cancel
Save