diff options
-rw-r--r-- | src/bloom.cpp | 6 | ||||
-rw-r--r-- | src/core_write.cpp | 3 | ||||
-rw-r--r-- | src/policy/policy.cpp | 23 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 3 | ||||
-rw-r--r-- | src/script/ismine.cpp | 3 | ||||
-rw-r--r-- | src/script/sign.cpp | 10 | ||||
-rw-r--r-- | src/script/standard.cpp | 57 | ||||
-rw-r--r-- | src/script/standard.h | 5 | ||||
-rw-r--r-- | src/test/script_standard_tests.cpp | 47 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 3 |
10 files changed, 62 insertions, 98 deletions
diff --git a/src/bloom.cpp b/src/bloom.cpp index f8e28edded..4bc0eab011 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -164,11 +164,11 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) insert(COutPoint(hash, i)); else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY) { - txnouttype type; std::vector<std::vector<unsigned char> > vSolutions; - if (Solver(txout.scriptPubKey, type, vSolutions) && - (type == TX_PUBKEY || type == TX_MULTISIG)) + txnouttype type = Solver(txout.scriptPubKey, vSolutions); + if (type == TX_PUBKEY || type == TX_MULTISIG) { insert(COutPoint(hash, i)); + } } break; } diff --git a/src/core_write.cpp b/src/core_write.cpp index 1272266235..ec6a7d1321 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -141,8 +141,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address) out.pushKV("hex", HexStr(script.begin(), script.end())); std::vector<std::vector<unsigned char>> solns; - txnouttype type; - Solver(script, type, solns); + txnouttype type = Solver(script, solns); out.pushKV("type", GetTxnOutputType(type)); CTxDestination address; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 3a592e40d3..f1ba09d4d2 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) { std::vector<std::vector<unsigned char> > vSolutions; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + whichType = Solver(scriptPubKey, vSolutions); - if (whichType == TX_MULTISIG) - { + if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) { + return false; + } else if (whichType == TX_MULTISIG) { unsigned char m = vSolutions.front()[0]; unsigned char n = vSolutions.back()[0]; // Support up to x-of-3 multisig txns as standard @@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) if (m < 1 || m > n) return false; } else if (whichType == TX_NULL_DATA && - (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) + (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) { return false; + } - return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN; + return true; } bool IsStandardTx(const CTransaction& tx, std::string& reason) @@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out; std::vector<std::vector<unsigned char> > vSolutions; - txnouttype whichType; - // get the scriptPubKey corresponding to this input: - const CScript& prevScript = prev.scriptPubKey; - if (!Solver(prevScript, whichType, vSolutions)) + txnouttype whichType = Solver(prev.scriptPubKey, vSolutions); + if (whichType == TX_NONSTANDARD) { return false; - - if (whichType == TX_SCRIPTHASH) - { + } else if (whichType == TX_SCRIPTHASH) { std::vector<std::vector<unsigned char> > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index bb94e11fea..eed70d730f 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -627,9 +627,8 @@ static UniValue decodescript(const JSONRPCRequest& request) // P2SH and witness programs cannot be wrapped in P2WSH, if this script // is a witness program, don't return addresses for a segwit programs. if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") { - txnouttype which_type; std::vector<std::vector<unsigned char>> solutions_data; - Solver(script, which_type, solutions_data); + txnouttype which_type = Solver(script, solutions_data); // Uncompressed pubkeys cannot be used with segwit checksigs. // If the script contains an uncompressed pubkey, skip encoding of a segwit program. if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) { diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 8c26866483..7e7087663a 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineResult ret = IsMineResult::NO; std::vector<valtype> vSolutions; - txnouttype whichType; - Solver(scriptPubKey, whichType, vSolutions); + txnouttype whichType = Solver(scriptPubKey, vSolutions); CKeyID keyID; switch (whichType) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index c2ae4ff2ea..f0090800aa 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -102,8 +102,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator std::vector<unsigned char> sig; std::vector<valtype> vSolutions; - if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) - return false; + whichTypeRet = Solver(scriptPubKey, vSolutions); switch (whichTypeRet) { @@ -314,9 +313,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI } // Get scripts - txnouttype script_type; std::vector<std::vector<unsigned char>> solutions; - Solver(txout.scriptPubKey, script_type, solutions); + txnouttype script_type = Solver(txout.scriptPubKey, solutions); SigVersion sigversion = SigVersion::BASE; CScript next_script = txout.scriptPubKey; @@ -327,7 +325,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI next_script = std::move(redeem_script); // Get redeemScript type - Solver(next_script, script_type, solutions); + script_type = Solver(next_script, solutions); stack.script.pop_back(); } if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) { @@ -337,7 +335,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI next_script = std::move(witness_script); // Get witnessScript type - Solver(next_script, script_type, solutions); + script_type = Solver(next_script, solutions); stack.witness.pop_back(); stack.script = std::move(stack.witness); stack.witness.clear(); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index d7b1724790..d309420d35 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -87,7 +87,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve return (it + 1 == script.end()); } -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) +txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet) { vSolutionsRet.clear(); @@ -95,33 +95,28 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) { - typeRet = TX_SCRIPTHASH; std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); - return true; + return TX_SCRIPTHASH; } int witnessversion; std::vector<unsigned char> witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) { - typeRet = TX_WITNESS_V0_KEYHASH; vSolutionsRet.push_back(witnessprogram); - return true; + return TX_WITNESS_V0_KEYHASH; } if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) { - typeRet = TX_WITNESS_V0_SCRIPTHASH; vSolutionsRet.push_back(witnessprogram); - return true; + return TX_WITNESS_V0_SCRIPTHASH; } if (witnessversion != 0) { - typeRet = TX_WITNESS_UNKNOWN; vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); - return true; + return TX_WITNESS_UNKNOWN; } - typeRet = TX_NONSTANDARD; - return false; + return TX_NONSTANDARD; } // Provably prunable, data-carrying output @@ -130,47 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v // byte passes the IsPushOnly() test we don't care what exactly is in the // script. if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { - typeRet = TX_NULL_DATA; - return true; + return TX_NULL_DATA; } std::vector<unsigned char> data; if (MatchPayToPubkey(scriptPubKey, data)) { - typeRet = TX_PUBKEY; vSolutionsRet.push_back(std::move(data)); - return true; + return TX_PUBKEY; } if (MatchPayToPubkeyHash(scriptPubKey, data)) { - typeRet = TX_PUBKEYHASH; vSolutionsRet.push_back(std::move(data)); - return true; + return TX_PUBKEYHASH; } unsigned int required; std::vector<std::vector<unsigned char>> keys; if (MatchMultisig(scriptPubKey, required, keys)) { - typeRet = TX_MULTISIG; vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16 vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16 - return true; + return TX_MULTISIG; } vSolutionsRet.clear(); - typeRet = TX_NONSTANDARD; - return false; + return TX_NONSTANDARD; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { std::vector<valtype> vSolutions; - txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + txnouttype whichType = Solver(scriptPubKey, vSolutions); - if (whichType == TX_PUBKEY) - { + if (whichType == TX_PUBKEY) { CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) return false; @@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet) { addressRet.clear(); - typeRet = TX_NONSTANDARD; std::vector<valtype> vSolutions; - if (!Solver(scriptPubKey, typeRet, vSolutions)) + typeRet = Solver(scriptPubKey, vSolutions); + if (typeRet == TX_NONSTANDARD) { return false; - if (typeRet == TX_NULL_DATA){ + } else if (typeRet == TX_NULL_DATA) { // This is data, not addresses return false; } @@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) CScript GetScriptForWitness(const CScript& redeemscript) { - txnouttype typ; std::vector<std::vector<unsigned char> > vSolutions; - if (Solver(redeemscript, typ, vSolutions)) { - if (typ == TX_PUBKEY) { - return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); - } else if (typ == TX_PUBKEYHASH) { - return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); - } + txnouttype typ = Solver(redeemscript, vSolutions); + if (typ == TX_PUBKEY) { + return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); + } else if (typ == TX_PUBKEYHASH) { + return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); } return GetScriptForDestination(WitnessV0ScriptHash(redeemscript)); } diff --git a/src/script/standard.h b/src/script/standard.h index 1380030871..4728b056dd 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t); * script hash, for P2PKH it will contain the key hash, etc. * * @param[in] scriptPubKey Script to parse - * @param[out] typeRet The script type * @param[out] vSolutionsRet Vector of parsed pubkeys and hashes - * @return True if script matches standard template + * @return The script type. TX_NONSTANDARD represents a failed solve. */ -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); +txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet); /** * Parse a standard scriptPubKey for the destination address. Assigns result to diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 7d4734986a..ded0a8ac1a 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -25,22 +25,19 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) } CScript s; - txnouttype whichType; std::vector<std::vector<unsigned char> > solutions; // TX_PUBKEY s.clear(); s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0])); // TX_PUBKEYHASH s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEYHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); @@ -48,8 +45,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) CScript redeemScript(s); // initialize with leftover P2PKH script s.clear(); s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_SCRIPTHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript))); @@ -59,8 +55,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) ToByteVector(pubkeys[0]) << ToByteVector(pubkeys[1]) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG); BOOST_CHECK_EQUAL(solutions.size(), 4U); BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1})); BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); @@ -73,8 +68,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) ToByteVector(pubkeys[1]) << ToByteVector(pubkeys[2]) << OP_3 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG); BOOST_CHECK_EQUAL(solutions.size(), 5U); BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2})); BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); @@ -88,15 +82,13 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) std::vector<unsigned char>({0}) << std::vector<unsigned char>({75}) << std::vector<unsigned char>({255}); - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NULL_DATA); BOOST_CHECK_EQUAL(solutions.size(), 0U); // TX_WITNESS_V0_KEYHASH s.clear(); s << OP_0 << ToByteVector(pubkeys[0].GetID()); - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); @@ -107,16 +99,14 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) s.clear(); s << OP_0 << ToByteVector(scriptHash); - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); // TX_NONSTANDARD s.clear(); s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; - BOOST_CHECK(!Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); } BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) @@ -127,53 +117,52 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) pubkey = key.GetPubKey(); CScript s; - txnouttype whichType; std::vector<std::vector<unsigned char> > solutions; // TX_PUBKEY with incorrectly sized pubkey s.clear(); s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_PUBKEYHASH with incorrectly sized key hash s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_SCRIPTHASH with incorrectly sized script hash s.clear(); s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG 0/2 s.clear(); s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG 2/1 s.clear(); s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG n = 2 with 1 pubkey s.clear(); s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG n = 1 with 0 pubkeys s.clear(); s << OP_1 << OP_1 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_NULL_DATA with other opcodes s.clear(); s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_WITNESS with incorrect program size s.clear(); s << OP_0 << std::vector<unsigned char>(19, 0x01); - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); } BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 73dfebf114..eb1e5ba3fb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4021,9 +4021,8 @@ public: void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const { // Always present: script type and redeemscript - txnouttype which_type; std::vector<std::vector<unsigned char>> solutions_data; - Solver(subscript, which_type, solutions_data); + txnouttype which_type = Solver(subscript, solutions_data); obj.pushKV("script", GetTxnOutputType(which_type)); obj.pushKV("hex", HexStr(subscript.begin(), subscript.end())); |