aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/init.cpp10
-rw-r--r--src/net.h1
-rw-r--r--src/rpc/net.cpp3
-rw-r--r--src/test/fuzz/bitdeque.cpp7
-rw-r--r--src/test/fuzz/pow.cpp2
-rw-r--r--src/test/fuzz/txorphan.cpp2
-rw-r--r--src/wallet/spend.cpp8
-rw-r--r--src/wallet/test/coinselector_tests.cpp47
-rw-r--r--src/wallet/wallet.cpp7
-rw-r--r--src/wallet/wallet.h2
10 files changed, 77 insertions, 12 deletions
diff --git a/src/init.cpp b/src/init.cpp
index ad894f7f11..25b40c6c6e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1285,6 +1285,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
if (!args.IsArgSet("-cjdnsreachable")) {
+ if (args.IsArgSet("-onlynet") && IsReachable(NET_CJDNS)) {
+ return InitError(
+ _("Outbound connections restricted to CJDNS (-onlynet=cjdns) but "
+ "-cjdnsreachable is not provided"));
+ }
SetReachable(NET_CJDNS, false);
}
// Now IsReachable(NET_CJDNS) is true if:
@@ -1757,6 +1762,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
SetProxy(NET_I2P, Proxy{addr});
} else {
+ if (args.IsArgSet("-onlynet") && IsReachable(NET_I2P)) {
+ return InitError(
+ _("Outbound connections restricted to i2p (-onlynet=i2p) but "
+ "-i2psam is not provided"));
+ }
SetReachable(NET_I2P, false);
}
diff --git a/src/net.h b/src/net.h
index 66a228b3ec..044701a339 100644
--- a/src/net.h
+++ b/src/net.h
@@ -164,6 +164,7 @@ bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr);
CService GetLocalAddress(const CNetAddr& addrPeer);
+CService MaybeFlipIPv6toCJDNS(const CService& service);
extern bool fDiscover;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index e221b3462d..d701a180ab 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -947,7 +947,8 @@ static RPCHelpMan addpeeraddress()
bool success{false};
if (LookupHost(addr_string, net_addr, false)) {
- CAddress address{{net_addr, port}, ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
+ CService service{net_addr, port};
+ CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
address.nTime = Now<NodeSeconds>();
// The source address is set equal to the address. This is equivalent to the peer
// announcing itself.
diff --git a/src/test/fuzz/bitdeque.cpp b/src/test/fuzz/bitdeque.cpp
index 01af8320b5..634a3de346 100644
--- a/src/test/fuzz/bitdeque.cpp
+++ b/src/test/fuzz/bitdeque.cpp
@@ -2,11 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/bitdeque.h>
-
#include <random.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/util.h>
+#include <util/bitdeque.h>
#include <deque>
#include <vector>
@@ -54,7 +53,8 @@ FUZZ_TARGET_INIT(bitdeque, InitRandData)
--initlen;
}
- while (provider.remaining_bytes()) {
+ LIMITED_WHILE(provider.remaining_bytes() > 0, 900)
+ {
{
assert(deq.size() == bitdeq.size());
auto it = deq.begin();
@@ -538,5 +538,4 @@ FUZZ_TARGET_INIT(bitdeque, InitRandData)
}
);
}
-
}
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 507ce57ec0..eba03da773 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -114,7 +114,7 @@ FUZZ_TARGET_INIT(pow_transition, initialize_pow)
auto current_block{std::make_unique<CBlockIndex>(header)};
current_block->pprev = blocks.empty() ? nullptr : blocks.back().get();
current_block->nHeight = height;
- blocks.emplace_back(std::move(current_block)).get();
+ blocks.emplace_back(std::move(current_block));
}
auto last_block{blocks.back().get()};
unsigned int new_nbits{GetNextWorkRequired(last_block, nullptr, consensus_params)};
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index 943f3f5fdf..55060f31cf 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -45,7 +45,7 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
// if true, allow duplicate input when constructing tx
const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
- LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
+ LIMITED_WHILE(outpoints.size() < 200'000 && fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
{
// construct transaction
const CTransactionRef tx = [&] {
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index d84310c323..ce41a4e954 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -590,7 +590,13 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
if (coin_control.HasSelected() && !coin_control.m_allow_other_inputs) {
SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL);
result.AddInput(preset_inputs);
- if (result.GetSelectedValue() < nTargetValue) return std::nullopt;
+
+ if (!coin_selection_params.m_subtract_fee_outputs && result.GetSelectedEffectiveValue() < nTargetValue) {
+ return std::nullopt;
+ } else if (result.GetSelectedValue() < nTargetValue) {
+ return std::nullopt;
+ }
+
result.ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
return result;
}
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 30a7fb9eb6..23f024247d 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -922,5 +922,52 @@ BOOST_AUTO_TEST_CASE(effective_value_test)
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
}
+BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
+{
+ // Test that the effective value is used to check whether preset inputs provide sufficient funds when subtract_fee_outputs is not used.
+ // This test creates a coin whose value is higher than the target but whose effective value is lower than the target.
+ // The coin is selected using coin control, with m_allow_other_inputs = false. SelectCoins should fail due to insufficient funds.
+
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ CoinsResult available_coins;
+ {
+ std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase());
+ dummyWallet->LoadWallet();
+ LOCK(dummyWallet->cs_wallet);
+ dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ dummyWallet->SetupDescriptorScriptPubKeyMans();
+
+ add_coin(available_coins, *dummyWallet, 100000); // 0.001 BTC
+ }
+
+ CAmount target{99900}; // 0.000999 BTC
+
+ FastRandomContext rand;
+ CoinSelectionParams cs_params{
+ rand,
+ /*change_output_size=*/34,
+ /*change_spend_size=*/148,
+ /*min_change_target=*/1000,
+ /*effective_feerate=*/CFeeRate(3000),
+ /*long_term_feerate=*/CFeeRate(1000),
+ /*discard_feerate=*/CFeeRate(1000),
+ /*tx_noinputs_size=*/0,
+ /*avoid_partial=*/false,
+ };
+ CCoinControl cc;
+ cc.m_allow_other_inputs = false;
+ COutput output = available_coins.All().at(0);
+ cc.SetInputWeight(output.outpoint, 148);
+ cc.SelectExternal(output.outpoint, output.txout);
+
+ const auto result = SelectCoins(*wallet, available_coins, target, cc, cs_params);
+ BOOST_CHECK(!result);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index e0f1655ab7..5889de2e36 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1907,7 +1907,7 @@ std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
// mempool to relay them. On startup, we will do this for all unconfirmed
// transactions but will not ask the mempool to relay them. We do this on startup
// to ensure that our own mempool is aware of our transactions, and to also
-// initialize nNextResend so that the actual rebroadcast is scheduled. There
+// initialize m_next_resend so that the actual rebroadcast is scheduled. There
// is a privacy side effect here as not broadcasting on startup also means that we won't
// inform the world of our wallet's state, particularly if the wallet (or node) is not
// yet synced.
@@ -1941,9 +1941,9 @@ void CWallet::ResubmitWalletTransactions(bool relay, bool force)
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
- if (!force && GetTime() < nNextResend) return;
+ if (!force && GetTime() < m_next_resend) return;
// resend 12-36 hours from now, ~1 day on average.
- nNextResend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60);
+ m_next_resend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60);
int submitted_tx_count = 0;
@@ -2110,6 +2110,7 @@ SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkh
CScript script_pub_key = GetScriptForDestination(pkhash);
for (const auto& spk_man_pair : m_spk_managers) {
if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
+ LOCK(cs_wallet); // DescriptorScriptPubKeyMan calls IsLocked which can lock cs_wallet in a deadlocking order
return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index f4ea5f1920..6a1b76505c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -250,7 +250,7 @@ private:
int nWalletVersion GUARDED_BY(cs_wallet){FEATURE_BASE};
/** The next scheduled rebroadcast of wallet transactions. */
- int64_t nNextResend = 0;
+ std::atomic<int64_t> m_next_resend{};
/** Whether this wallet will submit newly created transactions to the node's mempool and
* prompt rebroadcasts (see ResendWalletTransactions()). */
bool fBroadcastTransactions = false;