From a6d4946580617f93b5dfbbbf2b1514e9bd28ce8e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 10 Oct 2019 12:09:25 -0400 Subject: [PATCH] Merge #16786: test: add unit test for wallet watch-only methods involving PubKeys a57a1d42d52fe51e5b413a1fd3a5ef2b7a2120e3 test: add unit test for wallet watch-only methods involving PubKeys (Sebastian Falbesoner) Pull request description: The motivation for this addition was to unit test the function `wallet.cpp:ExtractPubKey()` (see recent change in commit 798a589aff64b83a0844688a661f4bd987c3340c) which is however static and only indirectly available via the public methods `AddWatchOnly()`, `LoadWatchOnly()` and `RemoveWatchOnly()`. Since the first of those methods also stores the addresses to the disk, the second, simpler one was chosen which only operates in memory. ACKs for top commit: Sjors: ACK a57a1d4 instagibbs: reACK https://github.com/bitcoin/bitcoin/pull/16786/commits/a57a1d42d52fe51e5b413a1fd3a5ef2b7a2120e3 Sjors: re-ACK a57a1d4 Tree-SHA512: 92a242204ab533022cd848662997372c41815b1265d07b3d96305697f801db29a5ba5668337faf4bea702bec1451972529afd6665927fb142aaf91700a338b26 --- src/wallet/test/wallet_tests.cpp | 78 ++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 17c7ca2e69..5c4df64b83 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -498,6 +498,84 @@ BOOST_AUTO_TEST_CASE(LoadReceiveRequests) BOOST_CHECK_EQUAL(values[1], "val_rr1"); } +// Test some watch-only wallet methods by the procedure of loading (LoadWatchOnly), +// checking (HaveWatchOnly), getting (GetWatchPubKey) and removing (RemoveWatchOnly) a +// given PubKey, resp. its corresponding P2PK Script. Results of the the impact on +// the address -> PubKey map is dependent on whether the PubKey is a point on the curve +static void TestWatchOnlyPubKey(CWallet& wallet, const CPubKey& add_pubkey) +{ + CScript p2pk = GetScriptForRawPubKey(add_pubkey); + CKeyID add_address = add_pubkey.GetID(); + CPubKey found_pubkey; + LOCK(wallet.cs_wallet); + + // all Scripts (i.e. also all PubKeys) are added to the general watch-only set + BOOST_CHECK(!wallet.HaveWatchOnly(p2pk)); + wallet.LoadWatchOnly(p2pk); + BOOST_CHECK(wallet.HaveWatchOnly(p2pk)); + + // only PubKeys on the curve shall be added to the watch-only address -> PubKey map + bool is_pubkey_fully_valid = add_pubkey.IsFullyValid(); + if (is_pubkey_fully_valid) { + BOOST_CHECK(wallet.GetWatchPubKey(add_address, found_pubkey)); + BOOST_CHECK(found_pubkey == add_pubkey); + } else { + BOOST_CHECK(!wallet.GetWatchPubKey(add_address, found_pubkey)); + BOOST_CHECK(found_pubkey == CPubKey()); // passed key is unchanged + } + + wallet.RemoveWatchOnly(p2pk); + BOOST_CHECK(!wallet.HaveWatchOnly(p2pk)); + + if (is_pubkey_fully_valid) { + BOOST_CHECK(!wallet.GetWatchPubKey(add_address, found_pubkey)); + BOOST_CHECK(found_pubkey == add_pubkey); // passed key is unchanged + } +} + +// Cryptographically invalidate a PubKey whilst keeping length and first byte +static void PollutePubKey(CPubKey& pubkey) +{ + std::vector pubkey_raw(pubkey.begin(), pubkey.end()); + std::fill(pubkey_raw.begin()+1, pubkey_raw.end(), 0); + pubkey = CPubKey(pubkey_raw); + assert(!pubkey.IsFullyValid()); + assert(pubkey.IsValid()); +} + +// Test watch-only wallet logic for PubKeys +BOOST_AUTO_TEST_CASE(WatchOnlyPubKeys) +{ + CKey key; + CPubKey pubkey; + + BOOST_CHECK(!m_wallet.HaveWatchOnly()); + + // uncompressed valid PubKey + key.MakeNewKey(false); + pubkey = key.GetPubKey(); + assert(!pubkey.IsCompressed()); + TestWatchOnlyPubKey(m_wallet, pubkey); + + // uncompressed cryptographically invalid PubKey + PollutePubKey(pubkey); + TestWatchOnlyPubKey(m_wallet, pubkey); + + // compressed valid PubKey + key.MakeNewKey(true); + pubkey = key.GetPubKey(); + assert(pubkey.IsCompressed()); + TestWatchOnlyPubKey(m_wallet, pubkey); + + // compressed cryptographically invalid PubKey + PollutePubKey(pubkey); + TestWatchOnlyPubKey(m_wallet, pubkey); + + // invalid empty PubKey + pubkey = CPubKey(); + TestWatchOnlyPubKey(m_wallet, pubkey); +} + class ListCoinsTestingSetup : public TestChain100Setup { public: