From 0c8ea6380c9f402ed9777fd015b117ba13125a35 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 30 Nov 2017 16:48:31 -0800 Subject: Abstract out IsSolvable from Witnessifier --- src/script/sign.cpp | 19 +++++++++++++++++++ src/script/sign.h | 6 ++++++ 2 files changed, 25 insertions(+) (limited to 'src/script') diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 117a4d8a52..49099bf7b0 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -422,3 +422,22 @@ bool DummySignatureCreator::CreateSig(std::vector& vchSig, const vchSig[6 + 33 + 32] = SIGHASH_ALL; return true; } + +bool IsSolvable(const CKeyStore& store, const CScript& script) +{ + // This check is to make sure that the script we created can actually be solved for and signed by us + // if we were to have the private keys. This is just to make sure that the script is valid and that, + // if found in a transaction, we would still accept and relay that transaction. In particular, + // it will reject witness outputs that require signing with an uncompressed public key. + DummySignatureCreator creator(&store); + SignatureData sigs; + // Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most + // important property this function is designed to test for. + static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE"); + if (ProduceSignature(creator, script, sigs)) { + // VerifyScript check is just defensive, and should never fail. + assert(VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker())); + return true; + } + return false; +} diff --git a/src/script/sign.h b/src/script/sign.h index 400c0c0865..ef6aa7f311 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -81,4 +81,10 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); +/* Check whether we know how to sign for an output like this, assuming we + * have all private keys. While this function does not need private keys, the passed + * keystore is used to look up public keys and redeemscripts by hash. + * Solvability is unrelated to whether we consider this output to be ours. */ +bool IsSolvable(const CKeyStore& store, const CScript& script); + #endif // BITCOIN_SCRIPT_SIGN_H -- cgit v1.2.3 From 985c79552ceb6a5f5812d421dc5c86fa3b1cc41d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 30 Nov 2017 16:48:38 -0800 Subject: Improve witness destination types and use them more --- src/script/standard.cpp | 11 +++-------- src/script/standard.h | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'src/script') diff --git a/src/script/standard.cpp b/src/script/standard.cpp index b7b33fade6..0d9f6ae1f9 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -348,19 +348,14 @@ CScript GetScriptForWitness(const CScript& redeemscript) 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; + return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); } else if (typ == TX_PUBKEYHASH) { - ret << OP_0 << vSolutions[0]; - return ret; + return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); } } uint256 hash; CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin()); - ret << OP_0 << ToByteVector(hash); - return ret; + return GetScriptForDestination(WitnessV0ScriptHash(hash)); } bool IsValidDestination(const CTxDestination& dest) { diff --git a/src/script/standard.h b/src/script/standard.h index 3eeeabdc15..b1c314fa72 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -73,8 +73,19 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; -struct WitnessV0ScriptHash : public uint256 {}; -struct WitnessV0KeyHash : public uint160 {}; +struct WitnessV0ScriptHash : public uint256 +{ + WitnessV0ScriptHash() : uint256() {} + explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {} + using uint256::uint256; +}; + +struct WitnessV0KeyHash : public uint160 +{ + WitnessV0KeyHash() : uint160() {} + explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} + using uint160::uint160; +}; //! CTxDestination subtype to encode any future Witness version struct WitnessUnknown @@ -164,6 +175,9 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys); * Generate a pay-to-witness script for the given redeem script. If the redeem * script is P2PK or P2PKH, this returns a P2WPKH script, otherwise it returns a * P2WSH script. + * + * TODO: replace calls to GetScriptForWitness with GetScriptForDestination using + * the various witness-specific CTxDestination subtypes. */ CScript GetScriptForWitness(const CScript& redeemscript); -- cgit v1.2.3 From 3eaa003c888f80207e8ff132f78417ff373ddfa3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 30 Nov 2017 16:48:45 -0800 Subject: Extend validateaddress information for P2SH-embedded witness This adds new fields 'pubkeys' and 'embedded' to the RPC's output, and improves the documentation for previously added 'witness_version' and 'witness_program' fields. --- src/script/standard.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/script') diff --git a/src/script/standard.h b/src/script/standard.h index b1c314fa72..f46d692259 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -155,6 +155,10 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) * addressRet is populated with a single value and nRequiredRet is set to 1. * Returns true if successful. Currently does not extract address from * pay-to-witness scripts. + * + * Note: this function confuses destinations (a subset of CScripts that are + * encodable as an address) with key identifiers (of keys involved in a + * CScript), and its use should be phased out. */ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); -- cgit v1.2.3