diff --git a/src/init.cpp b/src/init.cpp index f09f044..af06a89 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -496,21 +496,25 @@ bool AppInit2(int argc, char* argv[]) fNoListen = !GetBoolArg("-listen", true); // This code can be removed once a super-majority of the network has upgraded. - if (GetBoolArg("-bip16", true)) { if (fTestNet) SoftSetArg("-paytoscripthashtime", "1329264000"); // Feb 15 else SoftSetArg("-paytoscripthashtime", "1330578000"); // Mar 1 - // Put "/P2SH/" in the coinbase so everybody can tell when - // a majority of miners support it - const char* pszP2SH = "/P2SH/"; - COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); - } - else - { - const char* pszP2SH = "NOP2SH"; + const char* pszP2SH; + if (GetBoolArg("-bip16", true)) + { + if (GetBoolArg("-bip17", true)) + pszP2SH = "/P2SH/\1p2sh/CHV"; + else + pszP2SH = "/P2SH/\1p2sh/NOCHV"; + } else { + if (GetBoolArg("-bip17", true)) + pszP2SH = "NOP2SH\1p2sh/CHV"; + else + pszP2SH = "NOP2SH\1p2sh/NOCHV"; + } COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); } diff --git a/src/main.cpp b/src/main.cpp index b73037f..ee642a0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -260,7 +260,7 @@ bool CTransaction::IsStandard() const // ~65-byte public keys, plus a few script ops. if (txin.scriptSig.size() > 500) return false; - if (!txin.scriptSig.IsPushOnly()) + if (!::IsStandardInput(txin.scriptSig)) return false; } BOOST_FOREACH(const CTxOut& txout, vout) @@ -303,7 +303,8 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const // beside "push data" in the scriptSig the // IsStandard() call returns false vector > stack; - if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0)) + std::vector vchLastScript; + if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0, false, vchLastScript)) return false; if (whichType == TX_SCRIPTHASH) @@ -1131,6 +1132,20 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs, if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) return DoS(100, error("ConnectInputs() : txin values out of range")); + bool fStrictPayToScriptHash = true; + if (fBlock) + { + // To avoid being on the short end of a block-chain split, + // don't do validation of pay-to-script-hash transactions + // until blocks with timestamps after p2shtime: + int64 nP2SHSwitchTime = GetArg("-p2shtime", 1332460800); // Mar 23, 2012 @ 00:00:00 UTC + fStrictPayToScriptHash = (pindexBlock->nTime >= nP2SHSwitchTime); + } + // if !fBlock, then always be strict-- don't accept + // invalid-under-new-rules pay-to-script-hash transactions into + // our memory pool (don't relay them, don't include them + // in blocks we mine). + // Skip ECDSA signature verification when connecting blocks (fBlock=true) // before the last blockchain checkpoint. This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. diff --git a/src/script.cpp b/src/script.cpp index b6f1202..ef15fa6 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -205,7 +205,7 @@ const char* GetOpName(opcodetype opcode) // expanson case OP_NOP1 : return "OP_NOP1"; - case OP_NOP2 : return "OP_NOP2"; + case OP_CHECKHASHVERIFY : return "OP_CHECKHASHVERIFY"; case OP_NOP3 : return "OP_NOP3"; case OP_NOP4 : return "OP_NOP4"; case OP_NOP5 : return "OP_NOP5"; @@ -218,6 +218,7 @@ const char* GetOpName(opcodetype opcode) // template matching params + case OP_SCRIPTHASH : return "OP_SCRIPTHASH"; case OP_PUBKEYHASH : return "OP_PUBKEYHASH"; case OP_PUBKEY : return "OP_PUBKEY"; @@ -227,7 +228,7 @@ const char* GetOpName(opcodetype opcode) } } -bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType) +bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType, bool fValidatePayToScriptHash, std::vector &vchLastScript) { CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); @@ -312,7 +313,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // Control // case OP_NOP: - case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: + case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: break; @@ -928,6 +929,36 @@ bool EvalScript(vector >& stack, const CScript& script, co } break; + case OP_CHECKHASHVERIFY: + { + // This was OP_NOP2 in old scripts + if (!fValidatePayToScriptHash) + break; + + if (stack.size() < 1) + return false; + + // The only stack item here is what we expect the code to hash to + valtype& vchHashCheck = stacktop(-1); + + // This hashes the code with RIPEMD160(SHA256(vchLastScript)) + valtype vchHash(20); + { + uint160 hash160 = Hash160(vchLastScript); + memcpy(&vchHash[0], &hash160, sizeof(hash160)); + } + + bool fEqual = (vchHash == vchHashCheck); + + // Don't pop anything off the stack, for backward compatibility + + if (!fEqual) + // If the hash doesn't match, abort + return false; + // If the hash matches, we're good: act like OP_NOP2 for compatibility + } + break; + case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { @@ -1009,6 +1040,9 @@ bool EvalScript(vector >& stack, const CScript& script, co if (stack.size() + altstack.size() > 1000) return false; } + + // Save the last code segment (from the last executed OP_CODESEPARATOR onward) + vchLastScript = std::vector(pbegincodehash, pend); } catch (...) { @@ -1137,6 +1171,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector& pubkeys, const CKeyStore& keystore) { @@ -1471,11 +1545,16 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C bool fValidatePayToScriptHash, int nHashType) { vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType)) + std::vector vchLastScript; + bool fBIP17 = fValidatePayToScriptHash; + if (scriptPubKey.IsPayToScriptHash()) + // Don't allow combination BIP16+BIP17 transactions + fBIP17 = false; + if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType, fBIP17, vchLastScript)) return false; if (fValidatePayToScriptHash) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType)) + if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType, fBIP17, vchLastScript)) return false; if (stack.empty()) return false; @@ -1493,7 +1572,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType)) + if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType, fValidatePayToScriptHash, vchLastScript)) return false; if (stackCopy.empty()) return false; diff --git a/src/script.h b/src/script.h index 46f2d31..b5744de 100644 --- a/src/script.h +++ b/src/script.h @@ -160,7 +160,7 @@ enum opcodetype // expansion OP_NOP1, - OP_NOP2, + OP_CHECKHASHVERIFY, // "crypto" OP_NOP3, OP_NOP4, OP_NOP5, @@ -175,6 +175,7 @@ enum opcodetype // template matching params OP_SMALLINTEGER = 0xfa, OP_PUBKEYS = 0xfb, + OP_SCRIPTHASH = 0xfc, OP_PUBKEYHASH = 0xfd, OP_PUBKEY = 0xfe, @@ -558,10 +559,11 @@ public: -bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType); +bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType, bool fValidatePayToScriptHash, std::vector &vchLastScript); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions); bool IsStandard(const CScript& scriptPubKey); +bool IsStandardInput(const CScript& scriptSig); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet); bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 493ea69..62764a9 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -22,18 +22,19 @@ BOOST_AUTO_TEST_CASE(script_PushData) static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0)); + vector vchLastScript; + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0, true, vchLastScript)); vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0, true, vchLastScript)); BOOST_CHECK(pushdata1Stack == directStack); vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0, true, vchLastScript)); BOOST_CHECK(pushdata2Stack == directStack); vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0, true, vchLastScript)); BOOST_CHECK(pushdata4Stack == directStack); }