diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2017-11-30 16:49:04 -0800 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2018-01-09 15:35:27 -0800 |
commit | f37c64e477d679853a4076f2f7888568bb034e90 (patch) | |
tree | c89e9c12f55bf306452d8cd20c45a7a81f9fed6e /src | |
parent | 57273f2b302949d4ca3511f703627b5d717be40c (diff) | |
download | bitcoin-f37c64e477d679853a4076f2f7888568bb034e90.tar.xz |
Implicitly know about P2WPKH redeemscripts
Make CKeyStore automatically known about the redeemscripts necessary for P2SH-P2WPKH
(and due to the extra checks in IsMine, also P2WPKH) spending.
Diffstat (limited to 'src')
-rw-r--r-- | src/keystore.cpp | 35 | ||||
-rw-r--r-- | src/keystore.h | 2 | ||||
-rw-r--r-- | src/test/script_standard_tests.cpp | 7 | ||||
-rw-r--r-- | src/wallet/crypter.cpp | 1 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 2 |
5 files changed, 38 insertions, 9 deletions
diff --git a/src/keystore.cpp b/src/keystore.cpp index cbcc6d7ca9..487784b0bf 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -11,6 +11,31 @@ bool CKeyStore::AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); } +void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) +{ + AssertLockHeld(cs_KeyStore); + CKeyID key_id = pubkey.GetID(); + // We must actually know about this key already. + assert(HaveKey(key_id) || mapWatchKeys.count(key_id)); + // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH + // outputs. Technically P2WPKH outputs don't have a redeemscript to be + // spent. However, our current IsMine logic requires the corresponding + // P2SH-P2WPKH redeemscript to be present in the wallet in order to accept + // payment even to P2WPKH outputs. + // Also note that having superfluous scripts in the keystore never hurts. + // They're only used to guide recursion in signing and IsMine logic - if + // a script is present but we can't do anything with it, it has no effect. + // "Implicitly" refers to fact that scripts are derived automatically from + // existing keys, and are present in memory, even without being explicitly + // loaded (e.g. from a file). + if (pubkey.IsCompressed()) { + CScript script = GetScriptForDestination(WitnessV0KeyHash(key_id)); + // This does not use AddCScript, as it may be overridden. + CScriptID id(script); + mapScripts[id] = std::move(script); + } +} + bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const { CKey key; @@ -31,6 +56,7 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) { LOCK(cs_KeyStore); mapKeys[pubkey.GetID()] = key; + ImplicitlyLearnRelatedKeyScripts(pubkey); return true; } @@ -110,8 +136,10 @@ bool CBasicKeyStore::AddWatchOnly(const CScript &dest) LOCK(cs_KeyStore); setWatchOnly.insert(dest); CPubKey pubKey; - if (ExtractPubKey(dest, pubKey)) + if (ExtractPubKey(dest, pubKey)) { mapWatchKeys[pubKey.GetID()] = pubKey; + ImplicitlyLearnRelatedKeyScripts(pubKey); + } return true; } @@ -120,8 +148,11 @@ bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest) LOCK(cs_KeyStore); setWatchOnly.erase(dest); CPubKey pubKey; - if (ExtractPubKey(dest, pubKey)) + if (ExtractPubKey(dest, pubKey)) { mapWatchKeys.erase(pubKey.GetID()); + } + // Related CScripts are not removed; having superfluous scripts around is + // harmless (see comment in ImplicitlyLearnRelatedKeyScripts). return true; } diff --git a/src/keystore.h b/src/keystore.h index 0f3b5706f2..b8656424be 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -59,6 +59,8 @@ protected: ScriptMap mapScripts; WatchOnlySet setWatchOnly; + void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey); + public: bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 19060eccc9..cd30fbeda7 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -508,12 +508,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) scriptPubKey.clear(); scriptPubKey << OP_0 << ToByteVector(pubkeys[0].GetID()); - // Keystore has key, but no P2SH redeemScript - result = IsMine(keystore, scriptPubKey, isInvalid); - BOOST_CHECK_EQUAL(result, ISMINE_NO); - BOOST_CHECK(!isInvalid); - - // Keystore has key and P2SH redeemScript + // Keystore implicitly has key and P2SH redeemScript keystore.AddCScript(scriptPubKey); result = IsMine(keystore, scriptPubKey, isInvalid); BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 4cd7db048b..72ed5af42d 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -245,6 +245,7 @@ bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector< } mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); + ImplicitlyLearnRelatedKeyScripts(vchPubKey); return true; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b366992dec..e4b2b020b7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1307,7 +1307,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types"); } } else { - pwallet->AddCScript(witprogram); + pwallet->AddCScript(witprogram); // Implicit for single-key now, but necessary for multisig and for compatibility with older software pwallet->SetAddressBook(w.result, "", "receive"); } |