From 8da543f279a6be117eba809b619b4f3675c0931a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 31 Mar 2016 14:51:29 +0200 Subject: [PATCH 1/6] Refactor script validation to observe amounts This is a preparation for BIP143 support. --- src/dash-tx.cpp | 3 ++- src/rpc/rawtransaction.cpp | 3 ++- src/script/dashconsensus.cpp | 3 ++- src/script/dashconsensus.h | 2 ++ src/script/interpreter.h | 6 +++--- src/script/sigcache.h | 2 +- src/script/sign.cpp | 3 ++- src/test/multisig_tests.cpp | 17 +++++++++-------- src/test/script_P2SH_tests.cpp | 2 +- src/test/script_tests.cpp | 29 +++++++++++++++-------------- src/test/transaction_tests.cpp | 6 ++++-- src/validation.cpp | 2 +- src/validation.h | 6 ++++-- 13 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/dash-tx.cpp b/src/dash-tx.cpp index 70322e01de..8069c5948f 100644 --- a/src/dash-tx.cpp +++ b/src/dash-tx.cpp @@ -577,6 +577,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) continue; } const CScript& prevPubKey = coin.out.scriptPubKey; + const CAmount& amount = coin.out.nValue; txin.scriptSig.clear(); // Only sign SIGHASH_SINGLE if there's a corresponding output: @@ -587,7 +588,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) for (const CTransaction& txv : txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i))) + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount))) fComplete = false; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4ce06ed5b0..d3314994f7 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -818,6 +818,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) continue; } const CScript& prevPubKey = coin.out.scriptPubKey; + const CAmount& amount = coin.out.nValue; txin.scriptSig.clear(); // Only sign SIGHASH_SINGLE if there's a corresponding output: @@ -831,7 +832,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) } } ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i), &serror)) { + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); } } diff --git a/src/script/dashconsensus.cpp b/src/script/dashconsensus.cpp index 0d7d624e26..4bb30381ee 100644 --- a/src/script/dashconsensus.cpp +++ b/src/script/dashconsensus.cpp @@ -95,7 +95,8 @@ int dashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int set_error(err, dashconsensus_ERR_OK); PrecomputedTransactionData txdata(tx); - return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, txdata), nullptr); + CAmount am(0); + return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), nullptr); } catch (const std::exception&) { return set_error(err, dashconsensus_ERR_TX_DESERIALIZE); // Error deserializing } diff --git a/src/script/dashconsensus.h b/src/script/dashconsensus.h index 887e4cdec9..917117b8be 100644 --- a/src/script/dashconsensus.h +++ b/src/script/dashconsensus.h @@ -6,6 +6,8 @@ #ifndef BITCOIN_BITCOINCONSENSUS_H #define BITCOIN_BITCOINCONSENSUS_H +#include + #if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H) #include "config/dash-config.h" #if defined(_WIN32) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 002dbab1c7..4cb8ebbaac 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -135,8 +135,8 @@ protected: virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn), txdata(nullptr) {} - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), txdata(&txdataIn) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : txTo(txToIn), nIn(nInIn), txdata(nullptr) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), txdata(&txdataIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; @@ -148,7 +148,7 @@ private: const CTransaction txTo; public: - MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {} + MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {} }; bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr); diff --git a/src/script/sigcache.h b/src/script/sigcache.h index bc963067ac..d44dfe7648 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -46,7 +46,7 @@ private: bool store; public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, PrecomputedTransactionData& txdataIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, txdataIn), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, PrecomputedTransactionData& txdataIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override; }; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index a60bd1f0ee..dbc8f45837 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -15,7 +15,8 @@ typedef std::vector valtype; -TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {} +static const CAmount amountZero = 0; +TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn, amountZero) {} bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode) const { diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 44013b94e3..4876f63c26 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -43,6 +43,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify) ScriptError err; CKey key[4]; + CAmount amount = 0; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); @@ -78,20 +79,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys.assign(1,key[0]); keys.push_back(key[1]); s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err)); + BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); for (int i = 0; i < 4; i++) { keys.assign(1,key[i]); s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); keys.assign(1,key[1]); keys.push_back(key[i]); s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } @@ -102,18 +103,18 @@ BOOST_AUTO_TEST_CASE(multisig_verify) s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) { - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err)); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); @@ -125,12 +126,12 @@ BOOST_AUTO_TEST_CASE(multisig_verify) s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) { - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 5a7700ca6d..02743392ad 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -41,7 +41,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err); + return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index f3d4fcd98d..10ccab5141 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -148,7 +148,8 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, co ScriptError err; CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)); CMutableTransaction tx2 = tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message); + static const CAmount amountZero = 0; + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, amountZero), &err) == expect, message); BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); @@ -800,18 +801,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } @@ -833,54 +834,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) std::vector keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 4a86ecd865..1f28506497 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -149,9 +149,10 @@ BOOST_AUTO_TEST_CASE(tx_valid) break; } + CAmount amount = 0; unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - verify_flags, TransactionSignatureChecker(&tx, i, txdata), &err), + verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err), strTest); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } @@ -226,8 +227,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid) } unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); + CAmount amount = 0; fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - verify_flags, TransactionSignatureChecker(&tx, i, txdata), &err); + verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err); } BOOST_CHECK_MESSAGE(!fValid, strTest); BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err)); diff --git a/src/validation.cpp b/src/validation.cpp index 0249bc6317..bdb2336326 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1234,7 +1234,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; PrecomputedTransactionData txdata(*ptxTo); - return VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, txdata, cacheStore), &error); + return VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, txdata, cacheStore), &error); } int GetSpendHeight(const CCoinsViewCache& inputs) diff --git a/src/validation.h b/src/validation.h index b3d37d101a..db8130a4d2 100644 --- a/src/validation.h +++ b/src/validation.h @@ -366,6 +366,7 @@ class CScriptCheck { private: CScript scriptPubKey; + CAmount amount; const CTransaction *ptxTo; unsigned int nIn; unsigned int nFlags; @@ -374,9 +375,9 @@ private: PrecomputedTransactionData *txdata; public: - CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} + CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} CScriptCheck(const CScript& scriptPubKeyIn, const CAmount amountIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : - scriptPubKey(scriptPubKeyIn), + scriptPubKey(scriptPubKeyIn), amount(amountIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } bool operator()(); @@ -384,6 +385,7 @@ public: void swap(CScriptCheck &check) { scriptPubKey.swap(check.scriptPubKey); std::swap(ptxTo, check.ptxTo); + std::swap(amount, check.amount); std::swap(nIn, check.nIn); std::swap(nFlags, check.nFlags); std::swap(cacheStore, check.cacheStore); From fff708d3a315b0e0673edee8e06524646b2ecd92 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 27 Dec 2015 19:49:08 +0100 Subject: [PATCH 2/6] BIP143: Verification logic Includes simplifications by Eric Lombrozo. --- src/policy/policy.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- src/script/interpreter.cpp | 82 ++++++++++++++++++++++++---- src/script/interpreter.h | 19 +++++-- src/script/sign.cpp | 17 +++--- src/script/sign.h | 5 +- src/test/multisig_tests.cpp | 2 +- src/test/script_tests.cpp | 57 +++++++++---------- src/test/sighash_tests.cpp | 4 +- src/test/txvalidationcache_tests.cpp | 2 +- 10 files changed, 130 insertions(+), 62 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 09013c5c7e..36e8c34040 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -160,7 +160,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { std::vector > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), 0)) + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) return false; if (stack.empty()) return false; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d3314994f7..8febebe516 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -828,7 +828,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) // ... and merge in other signatures: for (const CMutableTransaction& txv : txVariants) { if (txv.vin.size() > i) { - txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, txin.scriptSig, txv.vin[i].scriptSig); + txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, amount, txin.scriptSig, txv.vin[i].scriptSig); } } ScriptError serror = SCRIPT_ERR_OK; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index a2d0b3f194..9f8d5084b2 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -227,7 +227,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { return true; } -bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) +bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -867,13 +867,15 @@ bool EvalScript(std::vector >& stack, const CScript& CScript scriptCode(pbegincodehash, pend); // Drop the signature, since there's no way for a signature to sign itself - scriptCode.FindAndDelete(CScript(vchSig)); + if (sigversion == SIGVERSION_BASE) { + scriptCode.FindAndDelete(CScript(vchSig)); + } if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { //serror is set return false; } - bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode); + bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); @@ -929,7 +931,9 @@ bool EvalScript(std::vector >& stack, const CScript& for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); - scriptCode.FindAndDelete(CScript(vchSig)); + if (sigversion == SIGVERSION_BASE) { + scriptCode.FindAndDelete(CScript(vchSig)); + } } bool fSuccess = true; @@ -947,7 +951,7 @@ bool EvalScript(std::vector >& stack, const CScript& } // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode); + bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); if (fOk) { isig++; @@ -1150,8 +1154,64 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) hashOutputs = GetOutputsHash(txTo); } -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const PrecomputedTransactionData* cache) +uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { + if (sigversion == SIGVERSION_WITNESS_V0) { + uint256 hashPrevouts; + uint256 hashSequence; + uint256 hashOutputs; + + if (!(nHashType & SIGHASH_ANYONECANPAY)) { + CHashWriter ss(SER_GETHASH, 0); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].prevout; + } + hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction + } + + if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { + CHashWriter ss(SER_GETHASH, 0); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].nSequence; + } + hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction + } + + if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { + CHashWriter ss(SER_GETHASH, 0); + for (unsigned int n = 0; n < txTo.vout.size(); n++) { + ss << txTo.vout[n]; + } + hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction + } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { + CHashWriter ss(SER_GETHASH, 0); + ss << txTo.vout[nIn]; + hashOutputs = ss.GetHash(); + } + + CHashWriter ss(SER_GETHASH, 0); + // Version + ss << txTo.nVersion; + // Input prevouts/nSequence (none/all, depending on flags) + ss << hashPrevouts; + ss << hashSequence; + // The input being signed (replacing the scriptSig with scriptCode + amount) + // The prevout may already be contained in hashPrevout, and the nSequence + // may already be contain in hashSequence. + ss << txTo.vin[nIn].prevout; + ss << static_cast(scriptCode); + ss << amount; + ss << txTo.vin[nIn].nSequence; + // Outputs (none/one/all, depending on flags) + ss << hashOutputs; + // Locktime + ss << txTo.nLockTime; + // Sighash type + ss << nHashType; + + return ss.GetHash(); + } + static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { // nIn out of range @@ -1180,7 +1240,7 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode) const +bool TransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1193,7 +1253,7 @@ bool TransactionSignatureChecker::CheckSig(const std::vector& vch int nHashType = vchSig.back(); vchSig.pop_back(); - uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, this->txdata); + uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); if (!VerifySignature(vchSig, pubkey, sighash)) return false; @@ -1292,12 +1352,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne } std::vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, serror)) + if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) + if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror)) // serror is set return false; if (stack.empty()) @@ -1324,7 +1384,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); - if (!EvalScript(stack, pubKey2, flags, checker, serror)) + if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror)) // serror is set return false; if (stack.empty()) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 4cb8ebbaac..ff2e714997 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -101,12 +101,18 @@ struct PrecomputedTransactionData PrecomputedTransactionData(const CTransaction& tx); }; -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const PrecomputedTransactionData* cache = nullptr); +enum SigVersion +{ + SIGVERSION_BASE = 0, + SIGVERSION_WITNESS_V0 = 1, +}; + +uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); class BaseSignatureChecker { public: - virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const + virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { return false; } @@ -129,15 +135,16 @@ class TransactionSignatureChecker : public BaseSignatureChecker private: const CTransaction* txTo; unsigned int nIn; + const CAmount amount; const PrecomputedTransactionData* txdata; protected: virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : txTo(txToIn), nIn(nInIn), txdata(nullptr) {} - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), txdata(&txdataIn) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const override; + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; }; @@ -151,7 +158,7 @@ public: MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {} }; -bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr); +bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr); #endif // BITCOIN_SCRIPT_INTERPRETER_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index dbc8f45837..cfc2f1a0bf 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -15,8 +15,7 @@ typedef std::vector valtype; -static const CAmount amountZero = 0; -TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn, amountZero) {} +TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode) const { @@ -24,7 +23,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, if (!keystore->GetKey(address, key)) return false; - uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType); + uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, SIGVERSION_BASE); if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); @@ -183,7 +182,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (checker.CheckSig(sig, pubkey, scriptPubKey)) + if (checker.CheckSig(sig, pubkey, scriptPubKey, SIGVERSION_BASE)) { sigs[pubkey] = sig; break; @@ -253,10 +252,10 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatur return CScript(); } -CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, +CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CAmount& amount, const CScript& scriptSig1, const CScript& scriptSig2) { - TransactionSignatureChecker checker(&txTo, nIn); + TransactionSignatureChecker checker(&txTo, nIn, amount); return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2); } @@ -268,9 +267,9 @@ CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecke Solver(scriptPubKey, txType, vSolutions); std::vector stack1; - EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); + EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); std::vector stack2; - EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); + EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2); } @@ -282,7 +281,7 @@ class DummySignatureChecker : public BaseSignatureChecker public: DummySignatureChecker() {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const override + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } diff --git a/src/script/sign.h b/src/script/sign.h index ee8f551807..978040ae9f 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -35,10 +35,11 @@ class TransactionSignatureCreator : public BaseSignatureCreator { const CTransaction* txTo; unsigned int nIn; int nHashType; + CAmount amount; const TransactionSignatureChecker checker; public: - TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL); + TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); const BaseSignatureChecker& Checker() const override{ return checker; } bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const override; }; @@ -62,6 +63,6 @@ bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutab CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2); /** Combine two script signatures on transactions. */ -CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); +CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CAmount& amount, const CScript& scriptSig1, const CScript& scriptSig2); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 4876f63c26..fee01492c2 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -23,7 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, int whichIn) { - uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL); + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE); CScript result; result << OP_0; // CHECKMULTISIG bug workaround diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 10ccab5141..65de9cfe0f 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -308,7 +308,7 @@ public: TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32) { - uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType); + uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, SIGVERSION_BASE); std::vector vchSig, r, s; uint32_t iter = 0; do { @@ -735,21 +735,21 @@ BOOST_AUTO_TEST_CASE(script_PushData) ScriptError err; std::vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } @@ -757,7 +757,7 @@ BOOST_AUTO_TEST_CASE(script_PushData) CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL); + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); CScript result; // @@ -888,6 +888,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function + CAmount amount; CBasicKeyStore keystore; std::vector keys; std::vector pubkeys; @@ -906,19 +907,19 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript& scriptSig = txTo.vin[0].scriptSig; CScript empty; - CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty); + CScript combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, empty); BOOST_CHECK(combined.empty()); // Single signature case: SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, empty); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, scriptSig); BOOST_CHECK(combined == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); // P2SH, single-signature case: @@ -926,41 +927,41 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, empty); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, scriptSig); BOOST_CHECK(combined == scriptSig); scriptSigCopy = scriptSig; SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, scriptSigCopy); BOOST_CHECK(combined == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, empty); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, scriptSig); BOOST_CHECK(combined == scriptSig); // A couple of partially-signed versions: std::vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL); + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE); + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE); + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); @@ -976,21 +977,21 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; - combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1a, partial1b); BOOST_CHECK(combined == partial1a); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1a, partial2a); BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial1a); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial2a, partial1a); BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial1b, partial2b); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1b, partial2b); BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial1b); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial1b); BOOST_CHECK(combined == complete13); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial3a); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial2a, partial3a); BOOST_CHECK(combined == complete23); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial2b); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial2b); BOOST_CHECK(combined == complete23); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial3a); + combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial3a); BOOST_CHECK(combined == partial3c); } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index e84ec4c256..05d59c56ef 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -140,7 +140,7 @@ BOOST_AUTO_TEST_CASE(sighash_test) uint256 sh, sho; sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); - sh = SignatureHash(scriptCode, txTo, nIn, nHashType); + sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SIGVERSION_BASE); #if defined(PRINT_SIGHASH_JSON) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << txTo; @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) continue; } - sh = SignatureHash(scriptCode, *tx, nIn, nHashType); + sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SIGVERSION_BASE); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index ce7ea16834..158c28026d 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -55,7 +55,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) // Sign: std::vector vchSig; - uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL); + uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); spends[i].vin[0].scriptSig << vchSig; From 21eca6481f1429c1dc077283a5b8b43afb365183 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 31 Mar 2016 14:54:58 +0200 Subject: [PATCH 3/6] BIP143: Signing logic --- src/dash-tx.cpp | 25 ++- src/rpc/rawtransaction.cpp | 15 +- src/script/ismine.cpp | 19 ++- src/script/sign.cpp | 303 ++++++++++++++++++++++----------- src/script/sign.h | 34 +++- src/script/standard.cpp | 41 +++++ src/script/standard.h | 3 + src/test/DoS_tests.cpp | 4 +- src/test/multisig_tests.cpp | 2 +- src/test/script_P2SH_tests.cpp | 11 +- src/test/script_tests.cpp | 94 +++++----- src/wallet/wallet.cpp | 13 +- 12 files changed, 390 insertions(+), 174 deletions(-) diff --git a/src/dash-tx.cpp b/src/dash-tx.cpp index 8069c5948f..74c2336726 100644 --- a/src/dash-tx.cpp +++ b/src/dash-tx.cpp @@ -474,6 +474,18 @@ static bool findSighashFlags(int& flags, const std::string& flagStr) return false; } +static CAmount AmountFromValue(const UniValue& value) +{ + if (!value.isNum() && !value.isStr()) + throw std::runtime_error("Amount is not a number or string"); + CAmount amount; + if (!ParseFixedPoint(value.getValStr(), 8, &amount)) + throw std::runtime_error("Invalid amount"); + if (!MoneyRange(amount)) + throw std::runtime_error("Amount out of range"); + return amount; +} + static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) { int nHashType = SIGHASH_ALL; @@ -548,6 +560,9 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) Coin newcoin; newcoin.out.scriptPubKey = scriptPubKey; newcoin.out.nValue = 0; // we don't know the actual output value + if (prevOut.exists("amount")) { + newcoin.out.nValue = AmountFromValue(prevOut["amount"]); + } newcoin.nHeight = 1; view.AddCoin(out, std::move(newcoin), true); } @@ -579,15 +594,15 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) const CScript& prevPubKey = coin.out.scriptPubKey; const CAmount& amount = coin.out.nValue; - txin.scriptSig.clear(); + SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); // ... and merge in other signatures: - for (const CTransaction& txv : txVariants) { - txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); - } + for (const CTransaction& txv : txVariants) + sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i)); + UpdateTransaction(mergedTx, i, sigdata); if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount))) fComplete = false; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 8febebe516..7c0a379e5e 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -611,7 +611,8 @@ UniValue signrawtransaction(const JSONRPCRequest& request) " \"txid\":\"id\", (string, required) The transaction id\n" " \"vout\":n, (numeric, required) The output number\n" " \"scriptPubKey\": \"hex\", (string, required) script key\n" - " \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n" + " \"redeemScript\": \"hex\", (string, required for P2SH) redeem script\n" + " \"amount\": value (numeric, required) The amount spent\n" " }\n" " ,...\n" " ]\n" @@ -754,6 +755,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request) Coin newcoin; newcoin.out.scriptPubKey = scriptPubKey; newcoin.out.nValue = 0; + if (prevOut.exists("amount")) { + newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount")); + } newcoin.nHeight = 1; view.AddCoin(out, std::move(newcoin), true); } @@ -820,17 +824,20 @@ UniValue signrawtransaction(const JSONRPCRequest& request) const CScript& prevPubKey = coin.out.scriptPubKey; const CAmount& amount = coin.out.nValue; - txin.scriptSig.clear(); + SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); // ... and merge in other signatures: for (const CMutableTransaction& txv : txVariants) { if (txv.vin.size() > i) { - txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, amount, txin.scriptSig, txv.vin[i].scriptSig); + sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i)); } } + + UpdateTransaction(mergedTx, i, sigdata); + ScriptError serror = SCRIPT_ERR_OK; if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index ce6033fa70..530d269b78 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -54,6 +54,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) return ISMINE_SPENDABLE; break; case TX_PUBKEYHASH: + case TX_WITNESS_V0_KEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; @@ -69,6 +70,20 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) } break; } + case TX_WITNESS_V0_SCRIPTHASH: + { + uint160 hash; + CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin()); + CScriptID scriptID = CScriptID(hash); + CScript subscript; + if (keystore.GetCScript(scriptID, subscript)) { + isminetype ret = IsMine(keystore, subscript); + if (ret == ISMINE_SPENDABLE) + return ret; + } + break; + } + case TX_MULTISIG: { // Only consider transactions "mine" if we own ALL the @@ -85,8 +100,8 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) if (keystore.HaveWatchOnly(scriptPubKey)) { // TODO: This could be optimized some by doing some work after the above solver - CScript scriptSig; - return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, scriptSig) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE; + SignatureData sigs; + return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE; } return ISMINE_NO; } diff --git a/src/script/sign.cpp b/src/script/sign.cpp index cfc2f1a0bf..fe4f258602 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -17,29 +17,29 @@ typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} -bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode) const +bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const { CKey key; if (!keystore->GetKey(address, key)) return false; - uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); return true; } -static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet) +static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) { std::vector vchSig; - if (!creator.CreateSig(vchSig, address, scriptCode)) + if (!creator.CreateSig(vchSig, address, scriptCode, sigversion)) return false; - scriptSigRet << vchSig; + ret.push_back(vchSig); return true; } -static bool SignN(const std::vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet) +static bool SignN(const std::vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -47,7 +47,7 @@ static bool SignN(const std::vector& multisigdata, const BaseSignatureC { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); - if (Sign1(keyID, creator, scriptCode, scriptSigRet)) + if (Sign1(keyID, creator, scriptCode, ret, sigversion)) ++nSigned; } return nSigned==nRequired; @@ -60,9 +60,11 @@ static bool SignN(const std::vector& multisigdata, const BaseSignatureC * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, - CScript& scriptSigRet, txnouttype& whichTypeRet) + std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion) { - scriptSigRet.clear(); + CScript scriptRet; + uint160 h160; + ret.clear(); std::vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) @@ -76,62 +78,142 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return Sign1(keyID, creator, scriptPubKey, scriptSigRet); + return Sign1(keyID, creator, scriptPubKey, ret, sigversion); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet)) + if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion)) return false; else { CPubKey vch; creator.KeyStore().GetPubKey(keyID, vch); - scriptSigRet << ToByteVector(vch); + ret.push_back(ToByteVector(vch)); } return true; case TX_SCRIPTHASH: - return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet); - - case TX_MULTISIG: - scriptSigRet << OP_0; // workaround CHECKMULTISIG bug - return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet)); - } - return false; -} - -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig) -{ - txnouttype whichType; - if (!SignStep(creator, fromPubKey, scriptSig, whichType)) + if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) { + ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); + return true; + } return false; - if (whichType == TX_SCRIPTHASH) - { - // Solver returns the subscript that need to be evaluated; - // the final scriptSig is the signatures from that - // and then the serialized subscript: - CScript subscript = scriptSig; + case TX_MULTISIG: + ret.push_back(valtype()); // workaround CHECKMULTISIG bug + return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion)); - txnouttype subType; - bool fSolved = - SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH; - // Append serialized subscript whether or not it is completely signed: - scriptSig << valtype(subscript.begin(), subscript.end()); - if (!fSolved) return false; + case TX_WITNESS_V0_KEYHASH: + ret.push_back(vSolutions[0]); + return true; + + case TX_WITNESS_V0_SCRIPTHASH: + CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); + if (creator.KeyStore().GetCScript(h160, scriptRet)) { + ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); + return true; + } + return false; + + default: + return false; } - - // Test solution - return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); } -bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType) +static CScript PushAll(const vector& values) +{ + CScript result; + BOOST_FOREACH(const valtype& v, values) { + if (v.size() == 0) { + result << OP_0; + } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { + result << CScript::EncodeOP_N(v[0]); + } else { + result << v; + } + } + return result; +} + +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) +{ + CScript script = fromPubKey; + bool solved = true; + std::vector result; + txnouttype whichType; + solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); + bool P2SH = false; + CScript subscript; + sigdata.scriptWitness.stack.clear(); + + if (solved && whichType == TX_SCRIPTHASH) + { + // Solver returns the subscript that needs to be evaluated; + // the final scriptSig is the signatures from that + // and then the serialized subscript: + script = subscript = CScript(result[0].begin(), result[0].end()); + solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; + P2SH = true; + } + + if (solved && whichType == TX_WITNESS_V0_KEYHASH) + { + CScript witnessscript; + witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; + txnouttype subType; + solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0); + sigdata.scriptWitness.stack = result; + result.clear(); + } + else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH) + { + CScript witnessscript(result[0].begin(), result[0].end()); + txnouttype subType; + solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; + result.push_back(std::vector(witnessscript.begin(), witnessscript.end())); + sigdata.scriptWitness.stack = result; + result.clear(); + } + + if (P2SH) { + result.push_back(std::vector(subscript.begin(), subscript.end())); + } + sigdata.scriptSig = PushAll(result); + + // Test solution + return solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); +} + +SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) +{ + SignatureData data; + assert(tx.vin.size() > nIn); + data.scriptSig = tx.vin[nIn].scriptSig; + if (tx.wit.vtxinwit.size() > nIn) { + data.scriptWitness = tx.wit.vtxinwit[nIn].scriptWitness; + } + return data; +} + +void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data) +{ + assert(tx.vin.size() > nIn); + tx.vin[nIn].scriptSig = data.scriptSig; + if (!data.scriptWitness.IsNull() || tx.wit.vtxinwit.size() > nIn) { + tx.wit.vtxinwit.resize(tx.vin.size()); + tx.wit.vtxinwit[nIn].scriptWitness = data.scriptWitness; + } +} + +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) { assert(nIn < txTo.vin.size()); - CTxIn& txin = txTo.vin[nIn]; CTransaction txToConst(txTo); - TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType); + TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); - return ProduceSignature(creator, fromPubKey, txin.scriptSig); + SignatureData sigdata; + bool ret = ProduceSignature(creator, fromPubKey, sigdata); + UpdateTransaction(txTo, nIn, sigdata); + return ret; } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) @@ -141,20 +223,12 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; - return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); + return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); } -static CScript PushAll(const std::vector& values) -{ - CScript result; - for (const valtype& v : values) - result << v; - return result; -} - -static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, +static std::vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const std::vector& vSolutions, - const std::vector& sigs1, const std::vector& sigs2) + const std::vector& sigs1, const std::vector& sigs2, SigVersion sigversion) { // Combine all the signatures we've got: std::set allsigs; @@ -182,7 +256,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (checker.CheckSig(sig, pubkey, scriptPubKey, SIGVERSION_BASE)) + if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion)) { sigs[pubkey] = sig; break; @@ -191,87 +265,126 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC } // Now build a merged CScript: unsigned int nSigsHave = 0; - CScript result; result << OP_0; // pop-one-too-many workaround + std::vector result; result.push_back(valtype()); // pop-one-too-many workaround for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i+1])) { - result << sigs[vSolutions[i+1]]; + result.push_back(sigs[vSolutions[i+1]]); ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) - result << OP_0; + result.push_back(valtype()); return result; } -static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, +namespace +{ +struct Stacks +{ + std::vector script; + std::vector witness; + + Stacks() {} + explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_), witness() {} + explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { + EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); + } + + SignatureData Output() const { + SignatureData result; + result.scriptSig = PushAll(script); + result.scriptWitness.stack = witness; + return result; + } +}; +} + +static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const txnouttype txType, const std::vector& vSolutions, - std::vector& sigs1, std::vector& sigs2) + Stacks sigs1, Stacks sigs2, SigVersion sigversion) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: - if (sigs1.size() >= sigs2.size()) - return PushAll(sigs1); - return PushAll(sigs2); + if (sigs1.script.size() >= sigs2.script.size()) + return sigs1; + return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: - if (sigs1.empty() || sigs1[0].empty()) - return PushAll(sigs2); - return PushAll(sigs1); + if (sigs1.script.empty() || sigs1.script[0].empty()) + return sigs2; + return sigs1; + case TX_WITNESS_V0_KEYHASH: + // Signatures are bigger than placeholders or empty scripts: + if (sigs1.witness.empty() || sigs1.witness[0].empty()) + return sigs2; + return sigs1; case TX_SCRIPTHASH: - if (sigs1.empty() || sigs1.back().empty()) - return PushAll(sigs2); - else if (sigs2.empty() || sigs2.back().empty()) - return PushAll(sigs1); + if (sigs1.script.empty() || sigs1.script.back().empty()) + return sigs2; + else if (sigs2.script.empty() || sigs2.script.back().empty()) + return sigs1; else { // Recur to combine: - valtype spk = sigs1.back(); + valtype spk = sigs1.script.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; std::vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); - sigs1.pop_back(); - sigs2.pop_back(); - CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2); - result << spk; + sigs1.script.pop_back(); + sigs2.script.pop_back(); + Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion); + result.script.push_back(spk); return result; } case TX_MULTISIG: - return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2); + return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion)); + case TX_WITNESS_V0_SCRIPTHASH: + if (sigs1.witness.empty() || sigs1.witness.back().empty()) + return sigs2; + else if (sigs2.witness.empty() || sigs2.witness.back().empty()) + return sigs1; + else + { + // Recur to combine: + CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end()); + txnouttype txType2; + vector vSolutions2; + Solver(pubKey2, txType2, vSolutions2); + sigs1.witness.pop_back(); + sigs1.script = sigs1.witness; + sigs1.witness.clear(); + sigs2.witness.pop_back(); + sigs2.script = sigs2.witness; + sigs2.witness.clear(); + Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0); + result.witness = result.script; + result.script.clear(); + result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end())); + return result; + } + default: + return Stacks(); } - - return CScript(); } -CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CAmount& amount, - const CScript& scriptSig1, const CScript& scriptSig2) -{ - TransactionSignatureChecker checker(&txTo, nIn, amount); - return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2); -} - -CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const CScript& scriptSig1, const CScript& scriptSig2) +SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, + const SignatureData& scriptSig1, const SignatureData& scriptSig2) { txnouttype txType; std::vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); - std::vector stack1; - EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); - std::vector stack2; - EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); - - return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2); + return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); } namespace { @@ -294,7 +407,7 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const return dummyChecker; } -bool DummySignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const +bool DummySignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); diff --git a/src/script/sign.h b/src/script/sign.h index 978040ae9f..e1e93c1e4f 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -27,7 +27,7 @@ public: virtual const BaseSignatureChecker& Checker() const =0; /** Create a singular (non-script) signature. */ - virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0; + virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0; }; /** A signature creator for transactions. */ @@ -41,7 +41,14 @@ class TransactionSignatureCreator : public BaseSignatureCreator { public: TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); const BaseSignatureChecker& Checker() const override{ return checker; } - bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const override; + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override; +}; + +class MutableTransactionSignatureCreator : public TransactionSignatureCreator { + CTransaction tx; + +public: + MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {} }; /** A signature creator that just produces 72-byte empty signatures. */ @@ -49,20 +56,29 @@ class DummySignatureCreator : public BaseSignatureCreator { public: DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} const BaseSignatureChecker& Checker() const override; - bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const override; + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override; +}; + +struct SignatureData { + CScript scriptSig; + CScriptWitness scriptWitness; + + SignatureData() {} + explicit SignatureData(const CScript& script) : scriptSig(script) {} }; /** Produce a script signature using a generic signature creator. */ -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig); +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata); /** Produce a script signature for a transaction. */ -bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); +bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); /** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ -CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2); +SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2); -/** Combine two script signatures on transactions. */ -CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CAmount& amount, const CScript& scriptSig1, const CScript& scriptSig2); +/** Extract signature data from a transaction, and insert it. */ +SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); +void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index a6958f5173..e94e93f8b1 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -28,6 +28,8 @@ const char* GetTxnOutputType(txnouttype t) case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; + case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash"; + case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; } return nullptr; } @@ -63,6 +65,22 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector witnessprogram; + if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { + if (witnessversion == 0 && witnessprogram.size() == 20) { + typeRet = TX_WITNESS_V0_KEYHASH; + vSolutionsRet.push_back(witnessprogram); + return true; + } + if (witnessversion == 0 && witnessprogram.size() == 32) { + typeRet = TX_WITNESS_V0_SCRIPTHASH; + vSolutionsRet.push_back(witnessprogram); + return true; + } + return false; + } + // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first @@ -279,3 +297,26 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys) script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; return script; } + +CScript GetScriptForWitness(const CScript& redeemscript) +{ + CScript ret; + + txnouttype typ; + std::vector > vSolutions; + if (Solver(redeemscript, typ, vSolutions)) { + if (typ == TX_PUBKEY) { + unsigned char h160[20]; + CHash160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160); + ret << OP_0 << std::vector(&h160[0], &h160[20]); + return ret; + } else if (typ == TX_PUBKEYHASH) { + ret << OP_0 << vSolutions[0]; + return ret; + } + } + uint256 hash; + CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin()); + ret << OP_0 << ToByteVector(hash); + return ret; +} diff --git a/src/script/standard.h b/src/script/standard.h index f348da8e19..72aaea0b7b 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -51,6 +51,8 @@ enum txnouttype TX_SCRIPTHASH, TX_MULTISIG, TX_NULL_DATA, + TX_WITNESS_V0_SCRIPTHASH, + TX_WITNESS_V0_KEYHASH, }; class CNoDestination { @@ -77,5 +79,6 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: CScript GetScriptForDestination(const CTxDestination& dest); CScript GetScriptForRawPubKey(const CPubKey& pubkey); CScript GetScriptForMultisig(int nRequired, const std::vector& keys); +CScript GetScriptForWitness(const CScript& redeemscript); #endif // BITCOIN_SCRIPT_STANDARD_H diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 2b251a8b1a..961b18c454 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - SignSignature(keystore, *txPrev, tx, 0); + SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL); AddOrphanTx(MakeTransactionRef(tx), i); } @@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[j].prevout.n = j; tx.vin[j].prevout.hash = txPrev->GetHash(); } - SignSignature(keystore, *txPrev, tx, 0); + SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL); // Re-use same signature for other inputs // (they don't have to be valid for this test) for (unsigned int j = 1; j < tx.vin.size(); j++) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index fee01492c2..b6520a3060 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -300,7 +300,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign) for (int i = 0; i < 3; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i)); } } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 02743392ad..5b7793c939 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "consensus/tx_verify.h" +#include "core_io.h" #include "key.h" #include "keystore.h" #include "validation.h" @@ -101,7 +102,7 @@ BOOST_AUTO_TEST_CASE(sign) } for (int i = 0; i < 8; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i)); } // All of the above should be OK, and the txTos have valid signatures // Check to make sure signature verification fails if we use the wrong ScriptSig: @@ -199,7 +200,7 @@ BOOST_AUTO_TEST_CASE(set) } for (int i = 0; i < 4; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); } } @@ -328,9 +329,9 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txTo.vin[i].prevout.n = i; txTo.vin[i].prevout.hash = txFrom.GetHash(); } - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0)); - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1)); - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL)); // SignSignature doesn't know how to sign these. We're // not testing validating signatures, so just create // dummy signatures that DO include the correct P2SH scripts: diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 65de9cfe0f..a80644d8ad 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -146,10 +146,10 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, co { bool expect = (scriptError == SCRIPT_ERR_OK); ScriptError err; - CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)); + CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey); + CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx2 = tx; - static const CAmount amountZero = 0; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, amountZero), &err) == expect, message); + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message); BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); @@ -906,50 +906,50 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; CScript& scriptSig = txTo.vin[0].scriptSig; - CScript empty; - CScript combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, empty); - BOOST_CHECK(combined.empty()); + SignatureData empty; + SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); + BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: - SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, empty); - BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, scriptSig); - BOOST_CHECK(combined == scriptSig); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); + BOOST_CHECK(combined.scriptSig == scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); + BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: - SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig); - BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); + BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); - SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, empty); - BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, scriptSig); - BOOST_CHECK(combined == scriptSig); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); + BOOST_CHECK(combined.scriptSig == scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); + BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; - SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig); - BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); + BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig); - BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, scriptSigCopy); - BOOST_CHECK(combined == scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); + BOOST_CHECK(combined.scriptSig == scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); + BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); - SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, empty); - BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, empty, scriptSig); - BOOST_CHECK(combined == scriptSig); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); + BOOST_CHECK(combined.scriptSig == scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); + BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: std::vector sig1; @@ -977,22 +977,22 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1a, partial1b); - BOOST_CHECK(combined == partial1a); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1a, partial2a); - BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial2a, partial1a); - BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1b, partial2b); - BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial1b); - BOOST_CHECK(combined == complete13); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial2a, partial3a); - BOOST_CHECK(combined == complete23); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial2b); - BOOST_CHECK(combined == complete23); - combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial3a); - BOOST_CHECK(combined == partial3c); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); + BOOST_CHECK(combined.scriptSig == partial1a); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); + BOOST_CHECK(combined.scriptSig == complete12); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); + BOOST_CHECK(combined.scriptSig == complete12); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); + BOOST_CHECK(combined.scriptSig == complete12); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); + BOOST_CHECK(combined.scriptSig == complete13); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); + BOOST_CHECK(combined.scriptSig == complete23); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); + BOOST_CHECK(combined.scriptSig == complete23); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); + BOOST_CHECK(combined.scriptSig == partial3c); } BOOST_AUTO_TEST_CASE(script_standard_push) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 279d670878..caf88d9988 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3798,12 +3798,15 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT for (const auto& txdsin : vecTxDSInTmp) { const CScript& scriptPubKey = txdsin.prevPubKey; - CScript& scriptSigRes = txNew.vin[nIn].scriptSig; - if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes)) + SignatureData sigdata; + if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata)) { strFailReason = _("Signing transaction failed"); return false; + } else { + UpdateTransaction(txNew, nIn, sigdata); } + nIn++; } @@ -3906,12 +3909,14 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT for(const auto& txdsin : vecTxDSInTmp) { const CScript& scriptPubKey = txdsin.prevPubKey; - CScript& scriptSigRes = txNew.vin[nIn].scriptSig; + SignatureData sigdata; - if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes)) + if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, sigdata)) { strFailReason = _("Signing transaction failed"); return false; + } else { + UpdateTransaction(txNew, nIn, sigdata); } nIn++; From 16bd20e57cf1c116b196fab26ecab56f0bdd4f11 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 19 Sep 2019 19:21:53 +0200 Subject: [PATCH 4/6] Remove segwit related code --- src/script/interpreter.cpp | 56 -------------------------- src/script/interpreter.h | 1 - src/script/ismine.cpp | 15 ------- src/script/sign.cpp | 80 +++----------------------------------- src/script/sign.h | 1 - src/script/standard.cpp | 18 --------- src/script/standard.h | 2 - 7 files changed, 5 insertions(+), 168 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 9f8d5084b2..30a42b16fc 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1156,62 +1156,6 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { - if (sigversion == SIGVERSION_WITNESS_V0) { - uint256 hashPrevouts; - uint256 hashSequence; - uint256 hashOutputs; - - if (!(nHashType & SIGHASH_ANYONECANPAY)) { - CHashWriter ss(SER_GETHASH, 0); - for (unsigned int n = 0; n < txTo.vin.size(); n++) { - ss << txTo.vin[n].prevout; - } - hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction - } - - if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - CHashWriter ss(SER_GETHASH, 0); - for (unsigned int n = 0; n < txTo.vin.size(); n++) { - ss << txTo.vin[n].nSequence; - } - hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction - } - - if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - CHashWriter ss(SER_GETHASH, 0); - for (unsigned int n = 0; n < txTo.vout.size(); n++) { - ss << txTo.vout[n]; - } - hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction - } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { - CHashWriter ss(SER_GETHASH, 0); - ss << txTo.vout[nIn]; - hashOutputs = ss.GetHash(); - } - - CHashWriter ss(SER_GETHASH, 0); - // Version - ss << txTo.nVersion; - // Input prevouts/nSequence (none/all, depending on flags) - ss << hashPrevouts; - ss << hashSequence; - // The input being signed (replacing the scriptSig with scriptCode + amount) - // The prevout may already be contained in hashPrevout, and the nSequence - // may already be contain in hashSequence. - ss << txTo.vin[nIn].prevout; - ss << static_cast(scriptCode); - ss << amount; - ss << txTo.vin[nIn].nSequence; - // Outputs (none/one/all, depending on flags) - ss << hashOutputs; - // Locktime - ss << txTo.nLockTime; - // Sighash type - ss << nHashType; - - return ss.GetHash(); - } - static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { // nIn out of range diff --git a/src/script/interpreter.h b/src/script/interpreter.h index ff2e714997..7ba43c76a1 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -104,7 +104,6 @@ struct PrecomputedTransactionData enum SigVersion { SIGVERSION_BASE = 0, - SIGVERSION_WITNESS_V0 = 1, }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 530d269b78..5addea63f1 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -54,7 +54,6 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) return ISMINE_SPENDABLE; break; case TX_PUBKEYHASH: - case TX_WITNESS_V0_KEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; @@ -70,20 +69,6 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) } break; } - case TX_WITNESS_V0_SCRIPTHASH: - { - uint160 hash; - CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin()); - CScriptID scriptID = CScriptID(hash); - CScript subscript; - if (keystore.GetCScript(scriptID, subscript)) { - isminetype ret = IsMine(keystore, subscript); - if (ret == ISMINE_SPENDABLE) - return ret; - } - break; - } - case TX_MULTISIG: { // Only consider transactions "mine" if we own ALL the diff --git a/src/script/sign.cpp b/src/script/sign.cpp index fe4f258602..8b3999a785 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -101,27 +101,15 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP ret.push_back(valtype()); // workaround CHECKMULTISIG bug return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion)); - case TX_WITNESS_V0_KEYHASH: - ret.push_back(vSolutions[0]); - return true; - - case TX_WITNESS_V0_SCRIPTHASH: - CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); - if (creator.KeyStore().GetCScript(h160, scriptRet)) { - ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); - return true; - } - return false; - default: return false; } } -static CScript PushAll(const vector& values) +static CScript PushAll(const std::vector& values) { CScript result; - BOOST_FOREACH(const valtype& v, values) { + for(const valtype& v : values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { @@ -142,7 +130,6 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); bool P2SH = false; CScript subscript; - sigdata.scriptWitness.stack.clear(); if (solved && whichType == TX_SCRIPTHASH) { @@ -154,32 +141,13 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu P2SH = true; } - if (solved && whichType == TX_WITNESS_V0_KEYHASH) - { - CScript witnessscript; - witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; - txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0); - sigdata.scriptWitness.stack = result; - result.clear(); - } - else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH) - { - CScript witnessscript(result[0].begin(), result[0].end()); - txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; - result.push_back(std::vector(witnessscript.begin(), witnessscript.end())); - sigdata.scriptWitness.stack = result; - result.clear(); - } - if (P2SH) { result.push_back(std::vector(subscript.begin(), subscript.end())); } sigdata.scriptSig = PushAll(result); // Test solution - return solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); + return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); } SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) @@ -187,9 +155,6 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI SignatureData data; assert(tx.vin.size() > nIn); data.scriptSig = tx.vin[nIn].scriptSig; - if (tx.wit.vtxinwit.size() > nIn) { - data.scriptWitness = tx.wit.vtxinwit[nIn].scriptWitness; - } return data; } @@ -197,10 +162,6 @@ void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const Signatur { assert(tx.vin.size() > nIn); tx.vin[nIn].scriptSig = data.scriptSig; - if (!data.scriptWitness.IsNull() || tx.wit.vtxinwit.size() > nIn) { - tx.wit.vtxinwit.resize(tx.vin.size()); - tx.wit.vtxinwit[nIn].scriptWitness = data.scriptWitness; - } } bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) @@ -286,18 +247,16 @@ namespace struct Stacks { std::vector script; - std::vector witness; Stacks() {} - explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_), witness() {} - explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { + explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_) {} + explicit Stacks(const SignatureData& data) { EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); } SignatureData Output() const { SignatureData result; result.scriptSig = PushAll(script); - result.scriptWitness.stack = witness; return result; } }; @@ -321,11 +280,6 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature if (sigs1.script.empty() || sigs1.script[0].empty()) return sigs2; return sigs1; - case TX_WITNESS_V0_KEYHASH: - // Signatures are bigger than placeholders or empty scripts: - if (sigs1.witness.empty() || sigs1.witness[0].empty()) - return sigs2; - return sigs1; case TX_SCRIPTHASH: if (sigs1.script.empty() || sigs1.script.back().empty()) return sigs2; @@ -348,30 +302,6 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature } case TX_MULTISIG: return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion)); - case TX_WITNESS_V0_SCRIPTHASH: - if (sigs1.witness.empty() || sigs1.witness.back().empty()) - return sigs2; - else if (sigs2.witness.empty() || sigs2.witness.back().empty()) - return sigs1; - else - { - // Recur to combine: - CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end()); - txnouttype txType2; - vector vSolutions2; - Solver(pubKey2, txType2, vSolutions2); - sigs1.witness.pop_back(); - sigs1.script = sigs1.witness; - sigs1.witness.clear(); - sigs2.witness.pop_back(); - sigs2.script = sigs2.witness; - sigs2.witness.clear(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0); - result.witness = result.script; - result.script.clear(); - result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end())); - return result; - } default: return Stacks(); } diff --git a/src/script/sign.h b/src/script/sign.h index e1e93c1e4f..a371937818 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -61,7 +61,6 @@ public: struct SignatureData { CScript scriptSig; - CScriptWitness scriptWitness; SignatureData() {} explicit SignatureData(const CScript& script) : scriptSig(script) {} diff --git a/src/script/standard.cpp b/src/script/standard.cpp index e94e93f8b1..17c1d1af0a 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -28,8 +28,6 @@ const char* GetTxnOutputType(txnouttype t) case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; - case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash"; - case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; } return nullptr; } @@ -65,22 +63,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector witnessprogram; - if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { - if (witnessversion == 0 && witnessprogram.size() == 20) { - typeRet = TX_WITNESS_V0_KEYHASH; - vSolutionsRet.push_back(witnessprogram); - return true; - } - if (witnessversion == 0 && witnessprogram.size() == 32) { - typeRet = TX_WITNESS_V0_SCRIPTHASH; - vSolutionsRet.push_back(witnessprogram); - return true; - } - return false; - } - // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first diff --git a/src/script/standard.h b/src/script/standard.h index 72aaea0b7b..d355d0dae9 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -51,8 +51,6 @@ enum txnouttype TX_SCRIPTHASH, TX_MULTISIG, TX_NULL_DATA, - TX_WITNESS_V0_SCRIPTHASH, - TX_WITNESS_V0_KEYHASH, }; class CNoDestination { From 7662c0b79aba6bbe2ed175f2798f0b634bb45875 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 19 Sep 2019 21:00:27 +0200 Subject: [PATCH 5/6] A couple of fixes --- src/privatesend/privatesend-client.cpp | 3 ++- src/privatesend/privatesend-server.cpp | 3 ++- src/test/evo_deterministicmns_tests.cpp | 5 +++-- src/test/txvalidationcache_tests.cpp | 6 +++--- src/wallet/wallet.cpp | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index 91649b687d..318537c872 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -619,7 +619,8 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr const CKeyStore& keystore = *vpwallets[0]; LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SignFinalTransaction -- Signing my input %i\n", nMyInputIndex); - if (!SignSignature(keystore, prevPubKey, finalMutableTransaction, nMyInputIndex, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig + // TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit) + if (!SignSignature(keystore, prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SignFinalTransaction -- Unable to sign my own transaction!\n"); // not sure what to do here, it will timeout...? } diff --git a/src/privatesend/privatesend-server.cpp b/src/privatesend/privatesend-server.cpp index 7afea3914e..061c6e12db 100644 --- a/src/privatesend/privatesend-server.cpp +++ b/src/privatesend/privatesend-server.cpp @@ -605,7 +605,8 @@ bool CPrivateSendServer::IsInputScriptSigValid(const CTxIn& txin) if (nTxInIndex >= 0) { //might have to do this one input at a time? txNew.vin[nTxInIndex].scriptSig = txin.scriptSig; LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- verifying scriptSig %s\n", ScriptToAsmStr(txin.scriptSig).substr(0, 24)); - if (!VerifyScript(txNew.vin[nTxInIndex].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, nTxInIndex))) { + // TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit) + if (!VerifyScript(txNew.vin[nTxInIndex].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, nTxInIndex, 0))) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- VerifyScript() failed on input %d\n", nTxInIndex); return false; } diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index fa89d97cb8..cd9c130038 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -86,7 +86,7 @@ static void SignTransaction(CMutableTransaction& tx, const CKey& coinbaseKey) CTransactionRef txFrom; uint256 hashBlock; BOOST_ASSERT(GetTransaction(tx.vin[i].prevout.hash, txFrom, Params().GetConsensus(), hashBlock)); - BOOST_ASSERT(SignSignature(tempKeystore, *txFrom, tx, i)); + BOOST_ASSERT(SignSignature(tempKeystore, *txFrom, tx, i, SIGHASH_ALL)); } } @@ -231,7 +231,8 @@ static bool CheckTransactionSignature(const CMutableTransaction& tx) uint256 hashBlock; BOOST_ASSERT(GetTransaction(txin.prevout.hash, txFrom, Params().GetConsensus(), hashBlock)); - if (!VerifyScript(txin.scriptSig, txFrom->vout[txin.prevout.n].scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&tx, i))) { + CAmount amount = txFrom->vout[txin.prevout.n].nValue; + if (!VerifyScript(txin.scriptSig, txFrom->vout[txin.prevout.n].scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&tx, i, amount))) { return false; } } diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 158c28026d..ff8406b60e 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -179,7 +179,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign, with a non-DER signature { std::vector vchSig; - uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL); + uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER vchSig.push_back((unsigned char)SIGHASH_ALL); @@ -251,7 +251,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL); + uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; @@ -279,7 +279,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL); + uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index caf88d9988..729a7dfd95 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3488,7 +3488,7 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std txCollateral.vout.push_back(CTxOut(0, CScript() << OP_RETURN)); } - if (!SignSignature(*this, txdsinCollateral.prevPubKey, txCollateral, 0)) { + if (!SignSignature(*this, txdsinCollateral.prevPubKey, txCollateral, 0, nValue, SIGHASH_ALL)) { strReason = "Unable to sign collateral transaction!"; return false; } From 689eff3aa00cc10a3c629c4c64c71b60955c0e71 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 20 Sep 2019 19:36:28 +0200 Subject: [PATCH 6/6] Drop unused GetScriptForWitness --- src/script/standard.cpp | 23 ----------------------- src/script/standard.h | 1 - 2 files changed, 24 deletions(-) diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 17c1d1af0a..a6958f5173 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -279,26 +279,3 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys) script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; return script; } - -CScript GetScriptForWitness(const CScript& redeemscript) -{ - CScript ret; - - txnouttype typ; - std::vector > vSolutions; - if (Solver(redeemscript, typ, vSolutions)) { - if (typ == TX_PUBKEY) { - unsigned char h160[20]; - CHash160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160); - ret << OP_0 << std::vector(&h160[0], &h160[20]); - return ret; - } else if (typ == TX_PUBKEYHASH) { - ret << OP_0 << vSolutions[0]; - return ret; - } - } - uint256 hash; - CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin()); - ret << OP_0 << ToByteVector(hash); - return ret; -} diff --git a/src/script/standard.h b/src/script/standard.h index d355d0dae9..f348da8e19 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -77,6 +77,5 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: CScript GetScriptForDestination(const CTxDestination& dest); CScript GetScriptForRawPubKey(const CPubKey& pubkey); CScript GetScriptForMultisig(int nRequired, const std::vector& keys); -CScript GetScriptForWitness(const CScript& redeemscript); #endif // BITCOIN_SCRIPT_STANDARD_H