diff --git a/src/test/bip352_tests.cpp b/src/test/bip352_tests.cpp index 2a789bb9d668e9..871ac559adc968 100644 --- a/src/test/bip352_tests.cpp +++ b/src/test/bip352_tests.cpp @@ -174,7 +174,6 @@ BOOST_AUTO_TEST_CASE(bip352_send_and_receive_test_vectors) std::string pubkey_hex = output["pub_key"].get_str(); expected_outputs.emplace_back(ParseHex(pubkey_hex)); } - BOOST_TEST_MESSAGE(found_outputs->size()); BOOST_CHECK(found_outputs->size() == expected_outputs.size()); for (const auto& output : *found_outputs) { BOOST_CHECK(std::find(expected_outputs.begin(), expected_outputs.end(), output.output) != expected_outputs.end()); diff --git a/src/util/bip352.cpp b/src/util/bip352.cpp index 91596ab93cf0dd..53e4df99cc1d61 100644 --- a/src/util/bip352.cpp +++ b/src/util/bip352.cpp @@ -129,6 +129,7 @@ std::optional GetSilentPaymentTweakDataFromTxInputs(const std::vec std::vector pubkeys; std::vector xonly_pubkeys; std::vector tx_outpoints; + if (coins.empty()) return std::nullopt; for (const CTxIn& txin : vin) { const Coin& coin = coins.at(txin.prevout); Assert(!coin.IsSpent()); diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 05b340995d08fe..3ae7cfe34533cc 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -890,7 +890,9 @@ RPCHelpMan rescanblockchain() LOCK(pwallet->m_relock_mutex); { LOCK(pwallet->cs_wallet); - EnsureWalletIsUnlocked(*pwallet); + if (!pwallet->IsWalletFlagSet(WALLET_FLAG_SILENT_PAYMENTS)) { + EnsureWalletIsUnlocked(*pwallet); + } int tip_height = pwallet->GetLastBlockHeight(); if (!request.params[0].isNull()) { diff --git a/src/wallet/silentpayments.cpp b/src/wallet/silentpayments.cpp index ded788cd958a8f..9b5fab1ad160bb 100644 --- a/src/wallet/silentpayments.cpp +++ b/src/wallet/silentpayments.cpp @@ -56,11 +56,12 @@ SilentPaymentsSPKM::SilentPaymentsSPKM(WalletStorage& storage, int64_t labels_si } m_address.m_spend_pubkey = derived.key.GetPubKey(); if (m_storage.HasEncryptionKeys()) { + std::vector crypted_spend_key; CKeyingMaterial secret{UCharCast(derived.key.begin()), UCharCast(derived.key.end())}; - std::vector crypted_spend_key = m_spend_crypted_key; if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) { return EncryptSecret(encryption_key, secret, derived.key.GetPubKey().GetHash(), crypted_spend_key);})) { throw std::runtime_error("Unable to encrypt silent payments spend key"); } + m_spend_crypted_key = crypted_spend_key; } else { m_spend_key = derived.key; } @@ -151,8 +152,9 @@ bool SilentPaymentsSPKM::CheckDecryptionKey(const CKeyingMaterial& master_key) assert(!m_spend_key.IsValid()); CKey key; - if (!DecryptKey(master_key, m_spend_crypted_key, m_address.m_spend_pubkey, key)) { - LogPrintf("The wallet is probably corrupted: Unable to decrypt silent payments spend key"); + std::vector crypted_secret = m_spend_crypted_key; + CPubKey spend_pubkey = m_address.m_spend_pubkey; + if (!DecryptKey(master_key, crypted_secret, spend_pubkey, key)) { throw std::runtime_error("Error unlocking wallet: unable to decrypt silent payments spend key. Your wallet file may be corrupt."); } return true; @@ -190,7 +192,12 @@ util::Result SilentPaymentsSPKM::GetReservedDestination(const Ou bool SilentPaymentsSPKM::TopUp(unsigned int size) { - // Nothing to do here + LOCK(cs_sp_man); + std::set new_spks; + for (const auto& spk : m_spk_tweaks) { + new_spks.emplace(spk.first); + } + m_storage.TopUpCallback(new_spks, this); return true; } diff --git a/test/functional/wallet_silentpayments_receiving.py b/test/functional/wallet_silentpayments_receiving.py index 9a38337f200e78..44687029423b60 100755 --- a/test/functional/wallet_silentpayments_receiving.py +++ b/test/functional/wallet_silentpayments_receiving.py @@ -20,6 +20,43 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() self.skip_if_no_sqlite() + def test_encrypt_and_decrypt(self): + self.log.info("Check that a silent payments wallet can be encrypted and decrypted") + self.log.info("Create encrypted wallet") + self.nodes[0].createwallet(wallet_name="sp_encrypted", passphrase="unsigned integer", silent_payment=True) + wallet = self.nodes[0].get_wallet_rpc("sp_encrypted") + addr = wallet.getnewaddress(address_type="silent-payment") + self.def_wallet.sendtoaddress(addr, 10) + self.generate(self.nodes[0], 1) + self.log.info("Check that we can scan without the wallet being unlocked") + assert_equal(wallet.getbalance(), 10) + self.log.info("Check that we get an error if trying to send with the wallet locked") + assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wallet.sendtoaddress, addr, 9) + wallet.walletpassphrase(passphrase="unsigned integer", timeout=3) + self.log.info("Unlock wallet and send") + wallet.sendtoaddress(addr, 9) + self.generate(self.nodes[0], 1) + assert_approx(wallet.getbalance(), 10, 0.0001) + + def test_encrypting_unencrypted(self): + self.log.info("Check that a silent payments wallet can be encrypted after creation") + self.log.info("Create un-encrypted wallet") + self.nodes[0].createwallet(wallet_name="sp_unencrypted", silent_payment=True) + wallet = self.nodes[0].get_wallet_rpc("sp_unencrypted") + addr = wallet.getnewaddress(address_type="silent-payment") + self.def_wallet.sendtoaddress(addr, 10) + self.generate(self.nodes[0], 1) + assert_equal(wallet.getbalance(), 10) + self.log.info("Add a passphrase to the wallet") + wallet.encryptwallet(passphrase="unsigned integer") + self.log.info("Check that we get an error if trying to send with the wallet locked") + assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wallet.sendtoaddress, addr, 9) + wallet.walletpassphrase(passphrase="unsigned integer", timeout=3) + self.log.info("Unlock wallet and send") + wallet.sendtoaddress(addr, 9) + self.generate(self.nodes[0], 1) + assert_approx(wallet.getbalance(), 10, 0.0001) + def test_createwallet(self): self.log.info("Check createwallet silent payments option") @@ -69,6 +106,8 @@ def run_test(self): self.generate(self.nodes[0], 101) self.test_createwallet() + self.test_encrypt_and_decrypt() + self.test_encrypting_unencrypted() self.test_basic()