diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/init.cpp | 10 | ||||
-rw-r--r-- | src/net.h | 1 | ||||
-rw-r--r-- | src/rpc/net.cpp | 3 | ||||
-rw-r--r-- | src/test/fuzz/bitdeque.cpp | 7 | ||||
-rw-r--r-- | src/test/fuzz/pow.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/txorphan.cpp | 2 | ||||
-rw-r--r-- | src/wallet/spend.cpp | 8 | ||||
-rw-r--r-- | src/wallet/test/coinselector_tests.cpp | 47 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 7 | ||||
-rw-r--r-- | src/wallet/wallet.h | 2 |
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); } @@ -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; |