Compare commits

..

18 Commits

Author SHA1 Message Date
MarcoFalke
b3f866a8df Merge bitcoin/bitcoin#26647: 24.0.1 final changes
a9ea715835 doc: adjust release notes for 24.0.1 (fanquake)
c119b0a176 doc: generate manual pages for 24.0.1 final (fanquake)
1b19c894a2 build: bump version to 24.0.1 final (fanquake)

Pull request description:

  Changes for 24.0.1.

  At this stage, I don't think an rc is necessary here, and would just add another 5-x days delay to fixing these issues.

  This will be accompanied by a pull request to master to add a note in the 24.0.md that already exists there. Similar to what was done with 0.19.0.1.

ACKs for top commit:
  gruve-p:
    ACK a9ea715835
  instagibbs:
    ACK a9ea715835
  hebasto:
    ACK a9ea715835, I have reviewed the changes and they look OK.
  josibake:
    ACK a9ea715835
  w0xlt:
    ACK a9ea715835

Tree-SHA512: 2e0d81ef91d947c9d55dcadcb6168fbb5251a5e613642c6250075add6a4f14f54cbb452934fa46aec035decb339e611fe721f5e9d9156e47a0341c3be26f5aa9
2022-12-06 16:54:10 +01:00
fanquake
a9ea715835 doc: adjust release notes for 24.0.1
This will be accompianied by a change to release-notes-24.0.md on
master.
2022-12-06 12:39:24 +00:00
fanquake
c119b0a176 doc: generate manual pages for 24.0.1 final 2022-12-06 12:23:26 +00:00
fanquake
1b19c894a2 build: bump version to 24.0.1 final 2022-12-06 12:13:42 +00:00
MarcoFalke
3afbc7d67d Merge bitcoin/bitcoin#26616: [24.x] Backports for 24.0.1
8b726bf556 test: Coin Selection, duplicated preset inputs selection (furszy)
9d73176d00 test: wallet, coverage for CoinsResult::Erase function (furszy)
195f0dfd0e wallet: bugfix, 'CoinsResult::Erase' is erasing only one output of the set (furszy)
e5d097b639 [test] Add p2p_tx_privacy.py (dergoegge)
c8426706de [net processing] Assume that TxRelay::m_tx_inventory_to_send is empty pre-verack (dergoegge)
e15b306017 [net processing] Ensure transaction announcements are only queued for fully connected peers (dergoegge)
95fded1069 wallet: Explicitly say migratewallet on encrypted wallets is unsupported (Andrew Chow)
d464b2af30 tests: Test for migrating encrypted wallets (Andrew Chow)
7a97a56ffb wallet: Avoid null pointer deref when cleaning up migratewallet (Andrew Chow)

Pull request description:

  Backports remaining changes on the 24.0.1 milestone.

  Currently backports:
  * https://github.com/bitcoin/bitcoin/pull/26594
  * https://github.com/bitcoin/bitcoin/pull/26569
  * https://github.com/bitcoin/bitcoin/pull/26560

ACKs for top commit:
  josibake:
    ACK 8b726bf556

Tree-SHA512: db77ec1a63a7b6a4412750a0f4c0645681fc346a5df0a7cd38d5d27384e1d0fa95f3953af90042afe131ddbd4b6a6e009527095f13e9f58c0190cd378738a9e5
2022-12-06 12:35:55 +01:00
furszy
8b726bf556 test: Coin Selection, duplicated preset inputs selection
This exercises the bug inside CoinsResult::Erase that
ends up on (1) a wallet crash or (2) a created and
broadcasted tx that contains a reduced recipient's amount.

This is covered by making the wallet selects the preset
inputs twice during the coin selection process.

Making the wallet think that the selection process result covers
the entire tx target when it does not. It's actually creating
a tx that sends more coins than what inputs are covering for.

Which, combined with the SFFO option, makes the wallet
incorrectly reduce the recipient's amount by the difference
between the original target and the wrongly counted inputs.
Which means, a created and relayed tx sending less coins to
the destination than what the user inputted.

Github-Pull: #26560
Rebased-From: cf79384697
2022-12-05 17:43:46 +00:00
furszy
9d73176d00 test: wallet, coverage for CoinsResult::Erase function
Github-Pull: #26560
Rebased-From: 341ba7ffd8
2022-12-05 17:43:31 +00:00
furszy
195f0dfd0e wallet: bugfix, 'CoinsResult::Erase' is erasing only one output of the set
The loop break shouldn't have being there.

Github-Pull: #26560
Rebased-From: f930aefff9
2022-12-05 17:40:54 +00:00
dergoegge
e5d097b639 [test] Add p2p_tx_privacy.py
Github-Pull: #26569
Rebased-From: 8f2dac5409
2022-12-02 16:04:27 +00:00
dergoegge
c8426706de [net processing] Assume that TxRelay::m_tx_inventory_to_send is empty pre-verack
This commit documents our assumption about
TxRelay::m_tx_inventory_to_send being empty prior to version handshake
completion.

The added Assume acts as testing oracle for our fuzzing tests to
potentially detect if the assumption is violated.

Github-Pull: #26569
Rebased-From: ce63fca13e
2022-12-02 16:04:13 +00:00
dergoegge
e15b306017 [net processing] Ensure transaction announcements are only queued for fully connected peers
Github-Pull: #26569
Rebased-From: 845e3a34c4
2022-12-02 15:58:24 +00:00
Andrew Chow
95fded1069 wallet: Explicitly say migratewallet on encrypted wallets is unsupported
Github-Pull: #26594
Rebased-From: 5e65a216d1
2022-12-01 10:22:14 +00:00
Andrew Chow
d464b2af30 tests: Test for migrating encrypted wallets
Due to an oversight, we cannot currently migrate encrypted wallets,
regardless of whether they are unlocked. Migrating such wallets will
trigger an error, and result in the cleanup being run. This conveniently
allows us to check some parts of the cleanup code.

Github-Pull: #26594
Rebased-From: 88afc73ae0
2022-12-01 10:21:37 +00:00
Andrew Chow
7a97a56ffb wallet: Avoid null pointer deref when cleaning up migratewallet
If migratewallet fails, we do a cleanup which removes the watchonly and
solvables wallets if they were created. However, if they were not, their
pointers are nullptr and we don't check for that, which causes a
segfault during the cleanup. So check that they aren't nullptr before
cleaning them up.

Github-Pull: #26594
Rebased-From: 86ef7b3c7b
2022-12-01 10:21:00 +00:00
MarcoFalke
f668a3a859 Merge bitcoin/bitcoin#26591: [24.x] ci: Skip COMMIT_RANGE if no CIRRUS_PR
fad1c55301 lint: Skip COMMIT_RANGE if no CIRRUS_PR (MarcoFalke)

Pull request description:

  Identical commit from https://github.com/bitcoin/bitcoin/pull/26588

  Untested, but this may fix the red-ness in https://cirrus-ci.com/github/bitcoin/bitcoin/24.x, e.g. https://cirrus-ci.com/task/4697153604419584:

  Backport requested in https://github.com/bitcoin/bitcoin/pull/26588#issuecomment-1328916876

ACKs for top commit:
  hebasto:
    ACK fad1c55301, the same commit as in #26588.

Tree-SHA512: 8d8a735e25bc1f774f8cbf058b95b7019941138ab78fb7819852755c7a416a783ee116457b97031d447639002353d7bf12ee8445275b7b5eec4abc7421cc171d
2022-11-28 17:27:34 +01:00
MarcoFalke
fad1c55301 lint: Skip COMMIT_RANGE if no CIRRUS_PR 2022-11-28 11:09:30 +01:00
fanquake
c1061be14a Merge bitcoin/bitcoin#26523: [24.x] GUI backports
39af5f2164 Fixes bitcoin#26490 by preventing notifications (John Moffett)

Pull request description:

  Backports:
  - bitcoin-core/gui#680

ACKs for top commit:
  jarolrod:
    ACK 39af5f2164

Tree-SHA512: 1c84703395cc750611922aa2c59dc2e2f2e98c92845859f9f57e30ee5371c9a31690318230ab514f2d9b71e75a716a30280aa1e585b6da31e45fd970017bc74e
2022-11-18 10:16:01 +00:00
John Moffett
39af5f2164 Fixes bitcoin#26490 by preventing notifications
MacOS 13 sends a window focus change notification after the main
window has been destroyed but before the QTApplication has been
destroyed. This results in the menu bar receiving a notification
despite it no longer existing. The solution is to pass the main
window as context when subscribing to the notifications. Qt
automatically unsubscribes to notifications if the sender OR
context is destroyed.

Github-Pull: bitcoin-core/gui#680
Rebased-From: 8a5014cd8a
2022-11-17 14:43:34 +00:00
23 changed files with 291 additions and 43 deletions

View File

@@ -9,7 +9,12 @@ export LC_ALL=C
GIT_HEAD=$(git rev-parse HEAD)
if [ -n "$CIRRUS_PR" ]; then
COMMIT_RANGE="${CIRRUS_BASE_SHA}..$GIT_HEAD"
echo
git log --no-merges --oneline "$COMMIT_RANGE"
echo
test/lint/commit-script-check.sh "$COMMIT_RANGE"
else
COMMIT_RANGE="SKIP_EMPTY_NOT_A_PR"
fi
export COMMIT_RANGE
@@ -36,8 +41,3 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "bitcoin/bitcoin" ] && [ "$CIRRUS_PR" = "" ] ; t
${CI_RETRY_EXE} gpg --keyserver hkps://keys.openpgp.org --recv-keys "${KEYS[@]}" &&
./contrib/verify-commits/verify-commits.py;
fi
if [ -n "$COMMIT_RANGE" ]; then
echo
git log --no-merges --oneline "$COMMIT_RANGE"
fi

View File

@@ -1,7 +1,7 @@
AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 24)
define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_BUILD, 1)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2022)

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH BITCOIN-CLI "1" "November 2022" "bitcoin-cli v24.0.0" "User Commands"
.TH BITCOIN-CLI "1" "December 2022" "bitcoin-cli v24.0.1" "User Commands"
.SH NAME
bitcoin-cli \- manual page for bitcoin-cli v24.0.0
bitcoin-cli \- manual page for bitcoin-cli v24.0.1
.SH SYNOPSIS
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR] \fI\,Send command to Bitcoin Core\/\fR
@@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v24.0.0
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,help <command> Get help for a command\/\fR
.SH DESCRIPTION
Bitcoin Core RPC client version v24.0.0
Bitcoin Core RPC client version v24.0.1
.SH OPTIONS
.HP
\-?

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH BITCOIN-QT "1" "November 2022" "bitcoin-qt v24.0.0" "User Commands"
.TH BITCOIN-QT "1" "December 2022" "bitcoin-qt v24.0.1" "User Commands"
.SH NAME
bitcoin-qt \- manual page for bitcoin-qt v24.0.0
bitcoin-qt \- manual page for bitcoin-qt v24.0.1
.SH SYNOPSIS
.B bitcoin-qt
[\fI\,command-line options\/\fR]
.SH DESCRIPTION
Bitcoin Core version v24.0.0
Bitcoin Core version v24.0.1
.SH OPTIONS
.HP
\-?

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH BITCOIN-TX "1" "November 2022" "bitcoin-tx v24.0.0" "User Commands"
.TH BITCOIN-TX "1" "December 2022" "bitcoin-tx v24.0.1" "User Commands"
.SH NAME
bitcoin-tx \- manual page for bitcoin-tx v24.0.0
bitcoin-tx \- manual page for bitcoin-tx v24.0.1
.SH SYNOPSIS
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR] \fI\,Update hex-encoded bitcoin transaction\/\fR
@@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v24.0.0
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] \fI\,Create hex-encoded bitcoin transaction\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-tx utility version v24.0.0
Bitcoin Core bitcoin\-tx utility version v24.0.1
.SH OPTIONS
.HP
\-?

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH BITCOIN-UTIL "1" "November 2022" "bitcoin-util v24.0.0" "User Commands"
.TH BITCOIN-UTIL "1" "December 2022" "bitcoin-util v24.0.1" "User Commands"
.SH NAME
bitcoin-util \- manual page for bitcoin-util v24.0.0
bitcoin-util \- manual page for bitcoin-util v24.0.1
.SH SYNOPSIS
.B bitcoin-util
[\fI\,options\/\fR] [\fI\,commands\/\fR] \fI\,Do stuff\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-util utility version v24.0.0
Bitcoin Core bitcoin\-util utility version v24.0.1
.SH OPTIONS
.HP
\-?

View File

@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH BITCOIN-WALLET "1" "November 2022" "bitcoin-wallet v24.0.0" "User Commands"
.TH BITCOIN-WALLET "1" "December 2022" "bitcoin-wallet v24.0.1" "User Commands"
.SH NAME
bitcoin-wallet \- manual page for bitcoin-wallet v24.0.0
bitcoin-wallet \- manual page for bitcoin-wallet v24.0.1
.SH DESCRIPTION
Bitcoin Core bitcoin\-wallet version v24.0.0
Bitcoin Core bitcoin\-wallet version v24.0.1
.PP
bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files.
By default bitcoin\-wallet will act on wallets in the default mainnet wallet directory in the datadir.

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH BITCOIND "1" "November 2022" "bitcoind v24.0.0" "User Commands"
.TH BITCOIND "1" "December 2022" "bitcoind v24.0.1" "User Commands"
.SH NAME
bitcoind \- manual page for bitcoind v24.0.0
bitcoind \- manual page for bitcoind v24.0.1
.SH SYNOPSIS
.B bitcoind
[\fI\,options\/\fR] \fI\,Start Bitcoin Core\/\fR
.SH DESCRIPTION
Bitcoin Core version v24.0.0
Bitcoin Core version v24.0.1
.SH OPTIONS
.HP
\-?

View File

@@ -1,9 +1,12 @@
24.0 Release Notes
==================
24.0.1 Release Notes
====================
Bitcoin Core version 24.0 is now available from:
Due to last-minute issues (#26616), 24.0, although tagged, was never fully
announced or released.
<https://bitcoincore.org/bin/bitcoin-core-24.0/>
Bitcoin Core version 24.0.1 is now available from:
<https://bitcoincore.org/bin/bitcoin-core-24.0.1/>
This release includes new features, various bug fixes and performance
improvements, as well as updated translations.

View File

@@ -2007,8 +2007,15 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid
auto tx_relay = peer.GetTxRelay();
if (!tx_relay) continue;
const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
LOCK(tx_relay->m_tx_inventory_mutex);
// Only queue transactions for announcement once the version handshake
// is completed. The time of arrival for these transactions is
// otherwise at risk of leaking to a spy, if the spy is able to
// distinguish transactions received during the handshake from the rest
// in the announcement.
if (tx_relay->m_next_inv_send_time == 0s) continue;
const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
if (!tx_relay->m_tx_inventory_known_filter.contains(hash)) {
tx_relay->m_tx_inventory_to_send.insert(hash);
}
@@ -3396,6 +3403,21 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// they may wish to request compact blocks from us
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION));
}
if (auto tx_relay = peer->GetTxRelay()) {
// `TxRelay::m_tx_inventory_to_send` must be empty before the
// version handshake is completed as
// `TxRelay::m_next_inv_send_time` is first initialised in
// `SendMessages` after the verack is received. Any transactions
// received during the version handshake would otherwise
// immediately be advertised without random delay, potentially
// leaking the time of arrival to a spy.
Assume(WITH_LOCK(
tx_relay->m_tx_inventory_mutex,
return tx_relay->m_tx_inventory_to_send.empty() &&
tx_relay->m_next_inv_send_time == 0s));
}
pfrom.fSuccessfullyConnected = true;
return;
}

View File

@@ -512,7 +512,7 @@ void BitcoinGUI::createMenuBar()
connect(minimize_action, &QAction::triggered, [] {
QApplication::activeWindow()->showMinimized();
});
connect(qApp, &QApplication::focusWindowChanged, [minimize_action] (QWindow* window) {
connect(qApp, &QApplication::focusWindowChanged, this, [minimize_action] (QWindow* window) {
minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized);
});
@@ -527,7 +527,7 @@ void BitcoinGUI::createMenuBar()
}
});
connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) {
connect(qApp, &QApplication::focusWindowChanged, this, [zoom_action] (QWindow* window) {
zoom_action->setEnabled(window != nullptr);
});
#endif

View File

@@ -730,7 +730,9 @@ static RPCHelpMan migratewallet()
std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
EnsureWalletIsUnlocked(*wallet);
if (wallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
}
WalletContext& context = EnsureWalletContext(request.context);

View File

@@ -102,15 +102,13 @@ void CoinsResult::Clear() {
coins.clear();
}
void CoinsResult::Erase(std::set<COutPoint>& preset_coins)
void CoinsResult::Erase(const std::set<COutPoint>& coins_to_remove)
{
for (auto& it : coins) {
auto& vec = it.second;
auto i = std::find_if(vec.begin(), vec.end(), [&](const COutput &c) { return preset_coins.count(c.outpoint);});
if (i != vec.end()) {
vec.erase(i);
break;
}
for (auto& [type, vec] : coins) {
auto remove_it = std::remove_if(vec.begin(), vec.end(), [&](const COutput& coin) {
return coins_to_remove.count(coin.outpoint) == 1;
});
vec.erase(remove_it, vec.end());
}
}

View File

@@ -47,7 +47,7 @@ struct CoinsResult {
* i.e., methods can work with individual OutputType vectors or on the entire object */
size_t Size() const;
void Clear();
void Erase(std::set<COutPoint>& preset_coins);
void Erase(const std::set<COutPoint>& coins_to_remove);
void Shuffle(FastRandomContext& rng_fast);
void Add(OutputType type, const COutput& out);

View File

@@ -969,5 +969,45 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
BOOST_CHECK(!result);
}
BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
{
// Test case to verify CoinsResult object sanity.
CoinsResult available_coins;
{
std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase());
BOOST_CHECK_EQUAL(dummyWallet->LoadWallet(), DBErrors::LOAD_OK);
LOCK(dummyWallet->cs_wallet);
dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
dummyWallet->SetupDescriptorScriptPubKeyMans();
// Add some coins to 'available_coins'
for (int i=0; i<10; i++) {
add_coin(available_coins, *dummyWallet, 1 * COIN);
}
}
{
// First test case, check that 'CoinsResult::Erase' function works as expected.
// By trying to erase two elements from the 'available_coins' object.
std::set<COutPoint> outs_to_remove;
const auto& coins = available_coins.All();
for (int i = 0; i < 2; i++) {
outs_to_remove.emplace(coins[i].outpoint);
}
available_coins.Erase(outs_to_remove);
// Check that the elements were actually removed.
const auto& updated_coins = available_coins.All();
for (const auto& out: outs_to_remove) {
auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&out](const COutput &coin) {
return coin.outpoint == out;
});
BOOST_CHECK(it == updated_coins.end());
}
// And verify that no extra element were removed
BOOST_CHECK_EQUAL(available_coins.Size(), 8);
}
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet

View File

@@ -112,5 +112,50 @@ BOOST_FIXTURE_TEST_CASE(FillInputToWeightTest, BasicTestingSetup)
// Note: We don't test the next boundary because of memory allocation constraints.
}
BOOST_FIXTURE_TEST_CASE(wallet_duplicated_preset_inputs_test, TestChain100Setup)
{
// Verify that the wallet's Coin Selection process does not include pre-selected inputs twice in a transaction.
// Add 4 spendable UTXO, 50 BTC each, to the wallet (total balance 200 BTC)
for (int i = 0; i < 4; i++) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), m_args, coinbaseKey);
LOCK(wallet->cs_wallet);
auto available_coins = AvailableCoins(*wallet);
std::vector<COutput> coins = available_coins.All();
// Preselect the first 3 UTXO (150 BTC total)
std::set<COutPoint> preset_inputs = {coins[0].outpoint, coins[1].outpoint, coins[2].outpoint};
// Try to create a tx that spends more than what preset inputs + wallet selected inputs are covering for.
// The wallet can cover up to 200 BTC, and the tx target is 299 BTC.
std::vector<CRecipient> recipients = {{GetScriptForDestination(*Assert(wallet->GetNewDestination(OutputType::BECH32, "dummy"))),
/*nAmount=*/299 * COIN, /*fSubtractFeeFromAmount=*/true}};
CCoinControl coin_control;
coin_control.m_allow_other_inputs = true;
for (const auto& outpoint : preset_inputs) {
coin_control.Select(outpoint);
}
// Attempt to send 299 BTC from a wallet that only has 200 BTC. The wallet should exclude
// the preset inputs from the pool of available coins, realize that there is not enough
// money to fund the 299 BTC payment, and fail with "Insufficient funds".
//
// Even with SFFO, the wallet can only afford to send 200 BTC.
// If the wallet does not properly exclude preset inputs from the pool of available coins
// prior to coin selection, it may create a transaction that does not fund the full payment
// amount or, through SFFO, incorrectly reduce the recipient's amount by the difference
// between the original target and the wrongly counted inputs (in this case 99 BTC)
// so that the recipient's amount is no longer equal to the user's selected target of 299 BTC.
// First case, use 'subtract_fee_from_outputs=true'
util::Result<CreatedTransactionResult> res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
BOOST_CHECK(!res_tx.has_value());
// Second case, don't use 'subtract_fee_from_outputs'.
recipients[0].fSubtractFeeFromAmount = false;
res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
BOOST_CHECK(!res_tx.has_value());
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet

View File

@@ -4102,8 +4102,8 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
// Make list of wallets to cleanup
std::vector<std::shared_ptr<CWallet>> created_wallets;
created_wallets.push_back(std::move(res.watchonly_wallet));
created_wallets.push_back(std::move(res.solvables_wallet));
if (res.watchonly_wallet) created_wallets.push_back(std::move(res.watchonly_wallet));
if (res.solvables_wallet) created_wallets.push_back(std::move(res.solvables_wallet));
// Get the directories to remove after unloading
for (std::shared_ptr<CWallet>& w : created_wallets) {

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# Copyright (c) 2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
Test that transaction announcements are only queued for peers that have
successfully completed the version handshake.
Topology:
tx_originator ----> node[0] <---- spy
We test that a transaction sent by tx_originator is only relayed to spy
if it was received after spy's version handshake completed.
1. Fully connect tx_originator
2. Connect spy (no version handshake)
3. tx_originator sends tx1
4. spy completes the version handshake
5. tx_originator sends tx2
6. We check that only tx2 is announced on the spy interface
"""
from test_framework.messages import (
msg_wtxidrelay,
msg_verack,
msg_tx,
CInv,
MSG_WTX,
)
from test_framework.p2p import (
P2PInterface,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.wallet import MiniWallet
class P2PTxSpy(P2PInterface):
def __init__(self):
super().__init__()
self.all_invs = []
def on_version(self, message):
self.send_message(msg_wtxidrelay())
def on_inv(self, message):
self.all_invs += message.inv
def wait_for_inv_match(self, expected_inv):
self.wait_until(lambda: len(self.all_invs) == 1 and self.all_invs[0] == expected_inv)
class TxPrivacyTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
self.wallet.rescan_utxos()
tx_originator = self.nodes[0].add_p2p_connection(P2PInterface())
spy = self.nodes[0].add_p2p_connection(P2PTxSpy(), wait_for_verack=False)
spy.wait_for_verack()
# tx_originator sends tx1
tx1 = self.wallet.create_self_transfer()["tx"]
tx_originator.send_and_ping(msg_tx(tx1))
# Spy sends the verack
spy.send_and_ping(msg_verack())
# tx_originator sends tx2
tx2 = self.wallet.create_self_transfer()["tx"]
tx_originator.send_and_ping(msg_tx(tx2))
# Spy should only get an inv for the second transaction as the first
# one was received pre-verack with the spy
spy.wait_for_inv_match(CInv(MSG_WTX, tx2.calc_sha256(True)))
if __name__ == '__main__':
TxPrivacyTest().main()

View File

@@ -107,6 +107,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 121)
self.test_add_inputs_default_value()
self.test_preset_inputs_selection()
self.test_weight_calculation()
self.test_change_position()
self.test_simple()
@@ -1189,6 +1190,50 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].unloadwallet("test_preset_inputs")
def test_preset_inputs_selection(self):
self.log.info('Test wallet preset inputs are not double-counted or reused in coin selection')
# Create and fund the wallet with 4 UTXO of 5 BTC each (20 BTC total)
self.nodes[2].createwallet("test_preset_inputs_selection")
wallet = self.nodes[2].get_wallet_rpc("test_preset_inputs_selection")
outputs = {}
for _ in range(4):
outputs[wallet.getnewaddress(address_type="bech32")] = 5
self.nodes[0].sendmany("", outputs)
self.generate(self.nodes[0], 1)
# Select the preset inputs
coins = wallet.listunspent()
preset_inputs = [coins[0], coins[1], coins[2]]
# Now let's create the tx creation options
options = {
"inputs": preset_inputs,
"add_inputs": True, # automatically add coins from the wallet to fulfill the target
"subtract_fee_from_outputs": [0], # deduct fee from first output
"add_to_wallet": False
}
# Attempt to send 29 BTC from a wallet that only has 20 BTC. The wallet should exclude
# the preset inputs from the pool of available coins, realize that there is not enough
# money to fund the 29 BTC payment, and fail with "Insufficient funds".
#
# Even with SFFO, the wallet can only afford to send 20 BTC.
# If the wallet does not properly exclude preset inputs from the pool of available coins
# prior to coin selection, it may create a transaction that does not fund the full payment
# amount or, through SFFO, incorrectly reduce the recipient's amount by the difference
# between the original target and the wrongly counted inputs (in this case 9 BTC)
# so that the recipient's amount is no longer equal to the user's selected target of 29 BTC.
# First case, use 'subtract_fee_from_outputs = true'
assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options)
# Second case, don't use 'subtract_fee_from_outputs'
del options["subtract_fee_from_outputs"]
assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options)
self.nodes[2].unloadwallet("test_preset_inputs_selection")
def test_weight_calculation(self):
self.log.info("Test weight calculation with external inputs")

View File

@@ -316,6 +316,7 @@ BASE_SCRIPTS = [
'rpc_deriveaddresses.py',
'rpc_deriveaddresses.py --usecli',
'p2p_ping.py',
'p2p_tx_privacy.py',
'rpc_scantxoutset.py',
'feature_txindex_compatibility.py',
'feature_unsupported_utxo_db.py',

View File

@@ -393,6 +393,15 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(bals, wallet.getbalances())
def test_encrypted(self):
self.log.info("Test migration of an encrypted wallet")
wallet = self.create_legacy_wallet("encrypted")
wallet.encryptwallet("pass")
assert_raises_rpc_error(-15, "Error: migratewallet on encrypted wallets is currently unsupported.", wallet.migratewallet)
# TODO: Fix migratewallet so that we can actually migrate encrypted wallets
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -402,6 +411,7 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_other_watchonly()
self.test_no_privkeys()
self.test_pk_coinbases()
self.test_encrypted()
if __name__ == '__main__':
WalletMigrationTest().main()

View File

@@ -46,6 +46,8 @@ def main():
commit_range = merge_base + "..HEAD"
else:
commit_range = os.getenv("COMMIT_RANGE")
if commit_range == "SKIP_EMPTY_NOT_A_PR":
sys.exit(0)
commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], universal_newlines=True, encoding="utf8").splitlines()

View File

@@ -97,6 +97,8 @@ def main():
commit_range = merge_base + "..HEAD"
else:
commit_range = os.getenv("COMMIT_RANGE")
if commit_range == "SKIP_EMPTY_NOT_A_PR":
sys.exit(0)
whitespace_selection = []
tab_selection = []