Browse Source

Merge pull request #5394

307f7d4 Report script evaluation failures in log and reject messages (Pieter Wuille)
0.10
Wladimir J. van der Laan 10 years ago
parent
commit
9ddc8c63ab
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 19
      src/main.cpp
  2. 12
      src/main.h

19
src/main.cpp

@ -1334,7 +1334,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);
@ -1364,10 +1364,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;
} }
@ -1455,7 +1456,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
@ -1464,7 +1465,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())));
} }
} }
} }
@ -3990,7 +3991,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);
} }
@ -4064,7 +4065,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);
@ -4271,7 +4272,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;
@ -334,14 +336,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);
@ -349,7 +352,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