Compare commits

...

9 Commits

Author SHA1 Message Date
Vijay
1cfe7c506f
Merge 8a58b5e244 into ad7a373529 2024-12-19 22:22:52 +00:00
pasta
ad7a373529
Merge #6498: docs: fixes for Release Notes v22.0.0 and v21.0.0
Some checks failed
Label Merge Conflicts / main (push) Failing after 11s
Guix Build / build-image (push) Failing after 1m30s
Guix Build / build (aarch64-linux-gnu) (push) Has been skipped
Guix Build / build (arm-linux-gnueabihf) (push) Has been skipped
Guix Build / build (arm64-apple-darwin) (push) Has been skipped
Guix Build / build (powerpc64-linux-gnu) (push) Has been skipped
Guix Build / build (riscv64-linux-gnu) (push) Has been skipped
Guix Build / build (x86_64-apple-darwin) (push) Has been skipped
Guix Build / build (x86_64-linux-gnu) (push) Has been skipped
Guix Build / build (x86_64-w64-mingw32) (push) Has been skipped
Check Merge Fast-Forward Only / check_merge (push) Successful in 1m21s
CI / Build Image (push) Failing after 2m3s
CI / Build Dependencies (arm-linux, arm-linux-gnueabihf) (push) Has been skipped
CI / Build Dependencies (linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (arm-linux, arm-linux, arm-linux-gnueabihf) (push) Has been skipped
CI / Build (linux64, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_cxx20, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_fuzz, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_nowallet, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_sqlite, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_tsan, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_ubsan, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
d75ee3a9e1 docs: fixes for Release Notes v22.0.0 and v21.0.0 (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  I noticed that we announced in current release new RPC `quorum platformsign` which has been actually released with v21.
  Though, in release notes for v21 it has a wrong name.

  ## What was done?
  Removed `quorum platformsign` from v22 release notes; fixed name in v21.
  Also mentioned build for Freebsd and minor typo `s/MN_R/MN_RR/` with name of forks on regtest.

  ## How Has This Been Tested?
  N/A

  ## Breaking Changes
  N/A

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone

ACKs for top commit:
  UdjinM6:
    utACK d75ee3a9e1

Tree-SHA512: 2d2309e81607c25a512577c96f15ee36b04b585c5751dc1500f2b432d90fc19e70f1b72cf1f7bf843abf854b7869481765902c7c61e9ea7e21b087a126c49a99
2024-12-19 16:22:31 -06:00
Konstantin Akimov
d75ee3a9e1
docs: fixes for Release Notes v22.0.0 and v21.0.0
platformsign has been released in v21 and name there is wrong: platformsign vs signplatform
2024-12-19 21:22:09 +07:00
Samuel Dobson
8a58b5e244
Merge bitcoin/bitcoin#22100: refactor: Clean up new wallet spend, receive files added #21207
b11a195ef450bd138aa03204a5e74fdd3ddced26 refactor: Detach wallet transaction methods (followup for move-only) (Russell Yanofsky)

Pull request description:

  This makes `CWallet` and `CWalletTx` methods in `spend.cpp` and `receive.cpp` files into standalone functions.

  It's a followup to [#21207 MOVEONLY: CWallet transaction code out of wallet.cpp/.h](https://github.com/bitcoin/bitcoin/pull/21207), which moved code from `wallet.cpp` to new `spend.cpp` and `receive.cpp` files.

  There are no changes in behavior. This is just making methods into functions and removing circular dependencies created by #21207. There are no comment or documentation changes, either. Removed comments from `transaction.h` are just migrated to `spend.h`, `receive.h`, and `wallet.h`.

  ---

  This commit was split off from #21206 so there are a few earlier review comments there

ACKs for top commit:
  achow101:
    ACK b11a195ef450bd138aa03204a5e74fdd3ddced26
  Sjors:
    utACK b11a195ef450bd138aa03204a5e74fdd3ddced26
  meshcollider:
    light ACK b11a195ef450bd138aa03204a5e74fdd3ddced26

Tree-SHA512: 75ce818d3f03b728b14b12e2d21bd20b7be73978601989cb37ff98254393300d1bb7823281449cd3d9e40756d67d42bd9a46bbdafd2e8baa95aaf2cb1c84549f
2024-11-27 12:38:23 +05:30
Andrew Chow
18ddb83fbc
Merge #22008: wallet: Cleanup and refactor CreateTransactionInternal
-BEGIN VERIFY SCRIPT-
sed -i 's/SelectCoinsMinConf/AttemptSelection/g' $(git grep -l SelectCoinsMinConf ./src)
-END VERIFY SCRIPT-
2024-11-27 12:38:22 +05:30
MarcoFalke
9e7f0e0d6e
Merge bitcoin/bitcoin#23640: MOVEONLY: Move helper functions from rpcwallet to wallet/rpc/util
ff945e553affbb7e25da1257a0dd47e413ec5164 MOVEONLY: Move utility functions from rpcwallet to wallet/rpc/util (Samuel Dobson)
7b04a064f6e8ee9d93e5a5ad54dab20b769083f2 Introduce wallet/rpc/util (Samuel Dobson)

Pull request description:

  This is part one of multiple to split up rpcwallet.cpp into smaller, more logical units.

  See #23622 for context and overall plan. I'll open PRs in stages to hopefully minimise conflicts.

  Can be reviewed with `--color-moved=dimmed-zebra`

  The end goal can be seen here: https://github.com/meshcollider/bitcoin/tree/202111_split_walletrpc

ACKs for top commit:
  MarcoFalke:
    nice, ACK ff945e553affbb7e25da1257a0dd47e413ec5164 🐰
  shaavan:
    ACK ff945e553affbb7e25da1257a0dd47e413ec5164

Tree-SHA512: 6e3d1de6db770fe2fca540c8c4f30183ab8258c26e3a1fb46937714d28818a52933eafbfcafe2995f6a6e2551a3f3dd3ec93363b81de7912c0d81f5749d1c86d
2024-11-27 12:32:06 +05:30
MarcoFalke
7bfcbb2f89
Merge bitcoin/bitcoin#23120: test: Remove unused and confusing main parameter from script_util
fa54efda9bc8f8f742dacbc3673516d88d9d601d test: pep-8 touched test (MarcoFalke)
fa4676805910bfea5549f5b51460c8456bc8945c test: Remove unused and confusing main parameter from script_util (MarcoFalke)

Pull request description:

ACKs for top commit:
  fanquake:
    ACK fa54efda9bc8f8f742dacbc3673516d88d9d601d

Tree-SHA512: 124e888e16c92bb24ab4d6f68a768d295500a48f8c6c0b4f069493effcd761f80be78dd93b31edbb529ebe4c8aaca764aaff48d1e3b23659dde722981dc787a5
2024-11-27 12:32:06 +05:30
MarcoFalke
6801e0d1ed
Merge bitcoin/bitcoin#23346: util, refactor: Improve headers for bitcoin-wallet tool
3431839c33fa3892c982322e4add39e28ddba719 util, refactor: Improve headers for bitcoin-wallet tool (Hennadii Stepanov)

Pull request description:

  This PR:
  - removes unneeded `#include <wallet/wallet.h>` from `<wallet/wallettool.h>`
  - introduces class forward declaration in `<wallet/wallettool.h>`
  - added `#include <config/bitcoin-config.h>` to `wallet/wallettool.cpp` where the `USE_BDB` macro is used

Top commit has no ACKs.

Tree-SHA512: a0de560d821f8b570ae806a1165b9b382c9e0b339687d932052fa4c38ab2ba493e7e050f19adc02ad7db40c42cf88ac1d37209f9071494a0ab268ed33ff22b9f
2024-11-27 12:32:05 +05:30
MarcoFalke
0469c6a9ae
Merge bitcoin/bitcoin#23712: test: interface_bitcoin_cli.py: check specified wallet type availability
b57bf25cfee3d3d0e08e5565b23e5e12ea88aee5 test: interface_bitcoin_cli.py: check specified wallet type availability (Sebastian Falbesoner)

Pull request description:

  Currently the test `interface_bitcoin_cli.py` performs the wallet-relevant parts if _any_ wallet type support is compiled in, independently of
  whether the test is run with legacy or descriptor wallet specified. This leads to a failure if the test is started with the `--legacy-wallet` parameter, but bitcoind is compiled without BDB support, see e.g
   https://github.com/bitcoin/bitcoin/pull/23686#issuecomment-987705540

  Fix this by checking if the specified wallet type (BDB for legacy wallet, SQLite for descriptor wallet) is available.

  Should further pave the way for #23682.

ACKs for top commit:
  achow101:
    ACK b57bf25cfee3d3d0e08e5565b23e5e12ea88aee5

Tree-SHA512: ddb5a94ba61133eff8de79d4946b3b9d476232b26e83bf768894cac4691e72602f88b6c02c72b992e12c2feb9bff1f0a2e0a265948a00954311104add1347184
2024-11-27 12:32:00 +05:30
23 changed files with 407 additions and 373 deletions

View File

@ -86,10 +86,10 @@ likely require a reindex.
- **glibc Requirement** - **glibc Requirement**
- The minimum required glibc to run Dash Core is now **2.31**. This means that **RHEL 8** and **Ubuntu 18.04 (Bionic)** are no longer supported. - The minimum required glibc to run Dash Core is now **2.31**. This means that **RHEL 8** and **Ubuntu 18.04 (Bionic)** are no longer supported.
## New RPCs - **FreeBSD Improvements**
- Fixed issues with building Dash Core on FreeBSD.
- **`quorum platformsign`** ## New RPCs
- A new subcommand has been introduced, offering a structured way to perform platform-related quorum signing operations.
- **`coinjoinsalt`** - **`coinjoinsalt`**
- Allows manipulation of a CoinJoin salt stored in a wallet. - Allows manipulation of a CoinJoin salt stored in a wallet.
@ -153,7 +153,7 @@ likely require a reindex.
## Devnet Breaking Changes ## Devnet Breaking Changes
- **Hardfork Activation Changes** - **Hardfork Activation Changes**
- `BRR` (`realloc`), `DIP0020`, `DIP0024`, `V19`, `V20`, and `MN_R` hardforks are now activated at **block 2** instead of block **300** on devnets. - `BRR` (`realloc`), `DIP0020`, `DIP0024`, `V19`, `V20`, and `MN_RR` hardforks are now activated at **block 2** instead of block **300** on devnets.
- **Implications:** - **Implications:**
- Breaking change. - Breaking change.
- Inability to sync on devnets created with earlier Dash Core versions and vice versa. - Inability to sync on devnets created with earlier Dash Core versions and vice versa.

View File

@ -235,7 +235,7 @@ Remote Procedure Calls (RPCs)
support for coin selection and a custom fee rate. The `send` RPC is experimental support for coin selection and a custom fee rate. The `send` RPC is experimental
and may change in subsequent releases. Using it is encouraged once it's no and may change in subsequent releases. Using it is encouraged once it's no
longer experimental: `sendmany` and `sendtoaddress` may be deprecated in a future release. longer experimental: `sendmany` and `sendtoaddress` may be deprecated in a future release.
- A new `quorum signplatform` RPC is added for Platform needs. This composite command limits Platform to only request signatures from the Platform quorum type. It is equivalent to `quorum sign <platform type>`. - A new `quorum platformsign` RPC is added for Platform needs. This composite command limits Platform to only request signatures from the Platform quorum type. It is equivalent to `quorum sign <platform type>`.
### RPC changes ### RPC changes
- `createwallet` has an updated argument list: `createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup )` - `createwallet` has an updated argument list: `createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup )`

View File

@ -400,6 +400,7 @@ BITCOIN_CORE_H = \
wallet/ismine.h \ wallet/ismine.h \
wallet/load.h \ wallet/load.h \
wallet/rpcwallet.h \ wallet/rpcwallet.h \
wallet/rpc/util.h \
wallet/salvage.h \ wallet/salvage.h \
wallet/scriptpubkeyman.h \ wallet/scriptpubkeyman.h \
wallet/sqlite.h \ wallet/sqlite.h \
@ -590,8 +591,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/hdchain.cpp \ wallet/hdchain.cpp \
wallet/interfaces.cpp \ wallet/interfaces.cpp \
wallet/load.cpp \ wallet/load.cpp \
wallet/rpc/util.cpp \
wallet/rpcdump.cpp \ wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/scriptpubkeyman.cpp \ wallet/scriptpubkeyman.cpp \
wallet/wallet.cpp \ wallet/wallet.cpp \
wallet/walletdb.cpp \ wallet/walletdb.cpp \

View File

@ -6,6 +6,7 @@
#include <interfaces/chain.h> #include <interfaces/chain.h>
#include <node/context.h> #include <node/context.h>
#include <wallet/coinselection.h> #include <wallet/coinselection.h>
#include <wallet/spend.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
#include <set> #include <set>
@ -17,7 +18,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<st
tx.nLockTime = nextLockTime++; // so all transactions get different hashes tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = nValue; tx.vout[0].nValue = nValue;
wtxs.push_back(std::make_unique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx)))); wtxs.push_back(std::make_unique<CWalletTx>(MakeTransactionRef(std::move(tx))));
} }
// Simple benchmark for wallet coin selection. Note that it maybe be necessary // Simple benchmark for wallet coin selection. Note that it maybe be necessary
@ -45,7 +46,7 @@ static void CoinSelection(benchmark::Bench& bench)
// Create coins // Create coins
std::vector<COutput> coins; std::vector<COutput> coins;
for (const auto& wtx : wtxs) { for (const auto& wtx : wtxs) {
coins.emplace_back(wtx.get(), 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */); coins.emplace_back(wallet, *wtx, 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
} }
const CoinEligibilityFilter filter_standard(1, 6, 0); const CoinEligibilityFilter filter_standard(1, 6, 0);
const CoinSelectionParams coin_selection_params(/* use_bnb= */ true, /* change_output_size= */ 34, const CoinSelectionParams coin_selection_params(/* use_bnb= */ true, /* change_output_size= */ 34,
@ -56,7 +57,7 @@ static void CoinSelection(benchmark::Bench& bench)
std::set<CInputCoin> setCoinsRet; std::set<CInputCoin> setCoinsRet;
CAmount nValueRet; CAmount nValueRet;
bool bnb_used; bool bnb_used;
bool success = wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used); bool success = AttemptSelection(wallet, 1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
assert(success); assert(success);
assert(nValueRet == 1003 * COIN); assert(nValueRet == 1003 * COIN);
assert(setCoinsRet.size() == 2); assert(setCoinsRet.size() == 2);

View File

@ -9,6 +9,7 @@
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <test/util/wallet.h> #include <test/util/wallet.h>
#include <validationinterface.h> #include <validationinterface.h>
#include <wallet/receive.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
#include <optional> #include <optional>
@ -34,11 +35,11 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
} }
SyncWithValidationInterfaceQueue(); SyncWithValidationInterfaceQueue();
auto bal = wallet.GetBalance(); // Cache auto bal = GetBalance(wallet); // Cache
bench.minEpochIterations(epoch_iters).run([&] { bench.minEpochIterations(epoch_iters).run([&] {
if (set_dirty) wallet.MarkDirty(); if (set_dirty) wallet.MarkDirty();
bal = wallet.GetBalance(); bal = GetBalance(wallet);
if (add_mine) assert(bal.m_mine_trusted > 0); if (add_mine) assert(bal.m_mine_trusted > 0);
if (add_watchonly) assert(bal.m_watchonly_trusted > 0); if (add_watchonly) assert(bal.m_watchonly_trusted > 0);
}); });

View File

@ -11,11 +11,18 @@
#include <compat/compat.h> #include <compat/compat.h>
#include <logging.h> #include <logging.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <clientversion.h>
#include <key.h>
#include <pubkey.h>
#include <tinyformat.h>
#include <util/system.h> #include <util/system.h>
#include <util/translation.h> #include <util/translation.h>
#include <util/url.h> #include <util/url.h>
#include <wallet/wallettool.h> #include <wallet/wallettool.h>
#include <exception>
#include <string>
#include <tuple>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = nullptr; UrlDecodeFn* const URL_DECODE = nullptr;

View File

@ -25,7 +25,9 @@
#include <wallet/fees.h> #include <wallet/fees.h>
#include <wallet/ismine.h> #include <wallet/ismine.h>
#include <wallet/load.h> #include <wallet/load.h>
#include <wallet/receive.h>
#include <wallet/rpcwallet.h> #include <wallet/rpcwallet.h>
#include <wallet/spend.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
#include <memory> #include <memory>
@ -76,9 +78,9 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
fOutputDenomFound = true; fOutputDenomFound = true;
} }
} }
result.credit = wtx.GetCredit(ISMINE_ALL); result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL);
result.debit = wtx.GetDebit(ISMINE_ALL); result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL);
result.change = wtx.GetChange(); result.change = CachedTxGetChange(wallet, wtx);
result.time = wtx.GetTxTime(); result.time = wtx.GetTxTime();
result.value_map = wtx.mapValue; result.value_map = wtx.mapValue;
result.is_coinbase = wtx.IsCoinBase(); result.is_coinbase = wtx.IsCoinBase();
@ -96,15 +98,15 @@ WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
{ {
WalletTxStatus result; WalletTxStatus result;
result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max(); result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max();
result.blocks_to_maturity = wtx.GetBlocksToMaturity(); result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx);
result.depth_in_main_chain = wtx.GetDepthInMainChain(); result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx);
result.time_received = wtx.nTimeReceived; result.time_received = wtx.nTimeReceived;
result.lock_time = wtx.tx->nLockTime; result.lock_time = wtx.tx->nLockTime;
result.is_final = wallet.chain().checkFinalTx(*wtx.tx); result.is_final = wallet.chain().checkFinalTx(*wtx.tx);
result.is_trusted = wtx.IsTrusted(); result.is_trusted = CachedTxIsTrusted(wallet, wtx);
result.is_abandoned = wtx.isAbandoned(); result.is_abandoned = wtx.isAbandoned();
result.is_coinbase = wtx.IsCoinBase(); result.is_coinbase = wtx.IsCoinBase();
result.is_in_main_chain = wtx.IsInMainChain(); result.is_in_main_chain = wallet.IsTxInMainChain(wtx);
result.is_chainlocked = wtx.IsChainLocked(); result.is_chainlocked = wtx.IsChainLocked();
result.is_islocked = wtx.IsLockedByInstantSend(); result.is_islocked = wtx.IsLockedByInstantSend();
return result; return result;
@ -274,7 +276,7 @@ public:
ReserveDestination m_dest(m_wallet.get()); ReserveDestination m_dest(m_wallet.get());
CTransactionRef tx; CTransactionRef tx;
FeeCalculation fee_calc_out; FeeCalculation fee_calc_out;
if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos, if (!CreateTransaction(*m_wallet, recipients, tx, fee, change_pos,
fail_reason, coin_control, fee_calc_out, sign)) { fail_reason, coin_control, fee_calc_out, sign)) {
return {}; return {};
} }
@ -378,7 +380,7 @@ public:
} }
WalletBalances getBalances() override WalletBalances getBalances() override
{ {
const auto bal = m_wallet->GetBalance(); const auto bal = GetBalance(*m_wallet);
WalletBalances result; WalletBalances result;
result.balance = bal.m_mine_trusted; result.balance = bal.m_mine_trusted;
result.unconfirmed_balance = bal.m_mine_untrusted_pending; result.unconfirmed_balance = bal.m_mine_untrusted_pending;
@ -404,7 +406,7 @@ public:
} }
CAmount getBalance() override CAmount getBalance() override
{ {
return m_wallet->GetBalance().m_mine_trusted; return GetBalance(*m_wallet).m_mine_trusted;
} }
CAmount getAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) override CAmount getAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) override
{ {
@ -436,13 +438,13 @@ public:
if (coin_control.IsUsingCoinJoin()) { if (coin_control.IsUsingCoinJoin()) {
return m_wallet->GetBalance(0, coin_control.m_avoid_address_reuse, false, &coin_control).m_anonymized; return m_wallet->GetBalance(0, coin_control.m_avoid_address_reuse, false, &coin_control).m_anonymized;
} else { } else {
return m_wallet->GetAvailableBalance(&coin_control); return GetAvailableBalance(*m_wallet, &coin_control);
} }
} }
isminetype txinIsMine(const CTxIn& txin) override isminetype txinIsMine(const CTxIn& txin) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return m_wallet->IsMine(txin); return InputIsMine(*m_wallet, txin);
} }
isminetype txoutIsMine(const CTxOut& txout) override isminetype txoutIsMine(const CTxOut& txout) override
{ {
@ -457,13 +459,13 @@ public:
CAmount getCredit(const CTxOut& txout, isminefilter filter) override CAmount getCredit(const CTxOut& txout, isminefilter filter) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return m_wallet->GetCredit(txout, filter); return OutputGetCredit(*m_wallet, txout, filter);
} }
CoinsList listCoins() override CoinsList listCoins() override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
CoinsList result; CoinsList result;
for (const auto& entry : m_wallet->ListCoins()) { for (const auto& entry : ListCoins(*m_wallet)) {
auto& group = result[entry.first]; auto& group = result[entry.first];
for (const auto& coin : entry.second) { for (const auto& coin : entry.second) {
group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i), group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
@ -481,7 +483,7 @@ public:
result.emplace_back(); result.emplace_back();
auto it = m_wallet->mapWallet.find(output.hash); auto it = m_wallet->mapWallet.find(output.hash);
if (it != m_wallet->mapWallet.end()) { if (it != m_wallet->mapWallet.end()) {
int depth = it->second.GetDepthInMainChain(); int depth = m_wallet->GetTxDepthInMainChain(it->second);
if (depth >= 0) { if (depth >= 0) {
result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth); result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
} }

View File

@ -14,6 +14,7 @@
#include <util/string.h> #include <util/string.h>
#include <util/system.h> #include <util/system.h>
#include <util/translation.h> #include <util/translation.h>
#include <wallet/spend.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
#include <wallet/walletdb.h> #include <wallet/walletdb.h>

122
src/wallet/rpc/util.cpp Normal file
View File

@ -0,0 +1,122 @@
// Copyright (c) 2011-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <wallet/rpc/util.h>
#include <rpc/util.h>
#include <util/url.h>
#include <wallet/context.h>
#include <wallet/wallet.h>
#include <univalue.h>
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
if (avoid_reuse && !can_avoid_reuse) {
throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
}
return avoid_reuse;
}
/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn't
* explicitly set.
*/
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
{
if (include_watchonly.isNull()) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}
// otherwise return whatever include_watchonly was set to
return include_watchonly.get_bool();
}
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
return true;
}
return false;
}
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
WalletContext& context = EnsureWalletContext(request.context);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
std::vector<std::shared_ptr<CWallet>> wallets = GetWallets(context);
if (wallets.size() == 1) {
return wallets[0];
}
if (wallets.empty()) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}
throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
void EnsureWalletIsUnlocked(const CWallet& wallet)
{
if (wallet.IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
}
WalletContext& EnsureWalletContext(const std::any& context)
{
auto wallet_context = util::AnyPtr<WalletContext>(context);
if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
return *wallet_context;
}
// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}
const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet)
{
const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}
std::string LabelFromValue(const UniValue& value)
{
std::string label = value.get_str();
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}

38
src/wallet/rpc/util.h Normal file
View File

@ -0,0 +1,38 @@
// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLET_RPC_UTIL_H
#define BITCOIN_WALLET_RPC_UTIL_H
#include <any>
#include <memory>
#include <string>
class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
class UniValue;
struct WalletContext;
extern const std::string HELP_REQUIRING_PASSPHRASE;
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name);
void EnsureWalletIsUnlocked(const CWallet&);
WalletContext& EnsureWalletContext(const std::any& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet);
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
std::string LabelFromValue(const UniValue& value);
#endif // BITCOIN_WALLET_RPC_UTIL_H

View File

@ -30,8 +30,11 @@
#include <wallet/coincontrol.h> #include <wallet/coincontrol.h>
#include <wallet/context.h> #include <wallet/context.h>
#include <wallet/load.h> #include <wallet/load.h>
#include <wallet/receive.h>
#include <wallet/rpcwallet.h> #include <wallet/rpcwallet.h>
#include <wallet/scriptpubkeyman.h> #include <wallet/scriptpubkeyman.h>
#include <wallet/rpc/util.h>
#include <wallet/spend.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
#include <wallet/walletdb.h> #include <wallet/walletdb.h>
#include <wallet/walletutil.h> #include <wallet/walletutil.h>
@ -49,35 +52,6 @@
using interfaces::FoundBlock; using interfaces::FoundBlock;
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
if (avoid_reuse && !can_avoid_reuse) {
throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
}
return avoid_reuse;
}
/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn't
* explicitly set.
*/
static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
{
if (include_watchonly.isNull()) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}
// otherwise return whatever include_watchonly was set to
return include_watchonly.get_bool();
}
/** Checks if a CKey is in the given CWallet compressed or otherwise*/ /** Checks if a CKey is in the given CWallet compressed or otherwise*/
bool HaveKey(const SigningProvider& wallet, const CKey& key) bool HaveKey(const SigningProvider& wallet, const CKey& key)
@ -87,72 +61,11 @@ bool HaveKey(const SigningProvider& wallet, const CKey& key)
return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID()); return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
} }
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name) static void WalletTxToJSON(const JSONRPCRequest& request, interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
{
if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
return true;
}
return false;
}
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
if (wallets.size() == 1) {
return wallets[0];
}
if (wallets.empty()) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}
throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
void EnsureWalletIsUnlocked(const CWallet& wallet)
{
if (wallet.IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
}
// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}
WalletContext& EnsureWalletContext(const CoreContext& context)
{
auto* wallet_context = GetContext<WalletContext>(context);
if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
return *wallet_context;
}
static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
{ {
int confirms = wtx.GetDepthInMainChain(); int confirms = wtx.GetDepthInMainChain();
interfaces::Chain& chain = wallet.chain();
int confirms = wallet.GetTxDepthInMainChain(wtx);
bool fLocked = chain.isInstantSendLockedTx(wtx.GetHash()); bool fLocked = chain.isInstantSendLockedTx(wtx.GetHash());
bool chainlock = false; bool chainlock = false;
if (confirms > 0) { if (confirms > 0) {
@ -175,12 +88,12 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
CHECK_NONFATAL(chain.findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(block_time))); CHECK_NONFATAL(chain.findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(block_time)));
entry.pushKV("blocktime", block_time); entry.pushKV("blocktime", block_time);
} else { } else {
entry.pushKV("trusted", wtx.IsTrusted()); entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx));
} }
uint256 hash = wtx.GetHash(); uint256 hash = wtx.GetHash();
entry.pushKV("txid", hash.GetHex()); entry.pushKV("txid", hash.GetHex());
UniValue conflicts(UniValue::VARR); UniValue conflicts(UniValue::VARR);
for (const uint256& conflict : wtx.GetConflicts()) for (const uint256& conflict : wallet.GetTxConflicts(wtx))
conflicts.push_back(conflict.GetHex()); conflicts.push_back(conflict.GetHex());
entry.pushKV("walletconflicts", conflicts); entry.pushKV("walletconflicts", conflicts);
entry.pushKV("time", wtx.GetTxTime()); entry.pushKV("time", wtx.GetTxTime());
@ -191,14 +104,6 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
} }
static std::string LabelFromValue(const UniValue& value)
{
std::string label = value.get_str();
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}
/** /**
* Update coin control with fee estimation based on the given parameters * Update coin control with fee estimation based on the given parameters
* *
@ -399,7 +304,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
bilingual_str error; bilingual_str error;
CTransactionRef tx; CTransactionRef tx;
FeeCalculation fee_calc_out; FeeCalculation fee_calc_out;
const bool fCreated = wallet.CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true); const bool fCreated = CreateTransaction(wallet, recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true);
if (!fCreated) { if (!fCreated) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
} }
@ -571,8 +476,8 @@ static RPCHelpMan listaddressgroupings()
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR); UniValue jsonGroupings(UniValue::VARR);
std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(); std::map<CTxDestination, CAmount> balances = GetAddressBalances(*pwallet);
for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) { for (const std::set<CTxDestination>& grouping : GetAddressGroupings(*pwallet)) {
UniValue jsonGrouping(UniValue::VARR); UniValue jsonGrouping(UniValue::VARR);
for (const CTxDestination& address : grouping) for (const CTxDestination& address : grouping)
{ {
@ -729,7 +634,7 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) { if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) {
continue; continue;
} }
if (wtx.GetDepthInMainChain() < min_depth && !(fAddLocked && wtx.IsLockedByInstantSend())) continue; if (wallet.GetTxDepthInMainChain(wtx) < min_depth && !(fAddLocked && wtx.IsLockedByInstantSend())) continue;
for (const CTxOut& txout : wtx.tx->vout) { for (const CTxOut& txout : wtx.tx->vout) {
CTxDestination address; CTxDestination address;
@ -875,7 +780,7 @@ static RPCHelpMan getbalance()
bool include_watchonly = ParseIncludeWatchonly(request.params[3], *pwallet); bool include_watchonly = ParseIncludeWatchonly(request.params[3], *pwallet);
bool avoid_reuse = GetAvoidReuseFlag(*pwallet, request.params[4]); bool avoid_reuse = GetAvoidReuseFlag(*pwallet, request.params[4]);
const auto bal = pwallet->GetBalance(min_depth, avoid_reuse, fAddLocked); const auto bal = GetBalance(*pwallet, min_depth, avoid_reuse, fAddLocked);
return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0)); return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
}, },
@ -900,7 +805,7 @@ static RPCHelpMan getunconfirmedbalance()
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetBalance().m_mine_untrusted_pending); return ValueFromAmount(GetBalance(*pwallet).m_mine_untrusted_pending);
}, },
}; };
} }
@ -1126,7 +1031,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx))
continue; continue;
int nDepth = wtx.GetDepthInMainChain(); int nDepth = wallet.GetTxDepthInMainChain(wtx);
if ((nDepth < nMinDepth) && !(fAddLocked && wtx.IsLockedByInstantSend())) if ((nDepth < nMinDepth) && !(fAddLocked && wtx.IsLockedByInstantSend()))
continue; continue;
@ -1359,9 +1264,9 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
std::list<COutputEntry> listReceived; std::list<COutputEntry> listReceived;
std::list<COutputEntry> listSent; std::list<COutputEntry> listSent;
wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine); CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, filter_ismine);
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY);
// Sent // Sent
if (!filter_label) if (!filter_label)
@ -1383,14 +1288,14 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
entry.pushKV("vout", s.vout); entry.pushKV("vout", s.vout);
entry.pushKV("fee", ValueFromAmount(-nFee)); entry.pushKV("fee", ValueFromAmount(-nFee));
if (fLong) if (fLong)
WalletTxToJSON(wallet.chain(), wtx, entry); WalletTxToJSON(wallet, wtx, entry);
entry.pushKV("abandoned", wtx.isAbandoned()); entry.pushKV("abandoned", wtx.isAbandoned());
ret.push_back(entry); ret.push_back(entry);
} }
} }
// Received // Received
if (listReceived.size() > 0 && ((wtx.GetDepthInMainChain() >= nMinDepth) || wtx.IsLockedByInstantSend())) if (listReceived.size() > 0 && ((wallet.GetTxDepthInMainChain(wtx) >= nMinDepth) || wtx.IsLockedByInstantSend()))
{ {
for (const COutputEntry& r : listReceived) for (const COutputEntry& r : listReceived)
{ {
@ -1409,9 +1314,9 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
MaybePushAddress(entry, r.destination); MaybePushAddress(entry, r.destination);
if (wtx.IsCoinBase()) if (wtx.IsCoinBase())
{ {
if (wtx.GetDepthInMainChain() < 1) if (wallet.GetTxDepthInMainChain(wtx) < 1)
entry.pushKV("category", "orphan"); entry.pushKV("category", "orphan");
else if (wtx.IsImmatureCoinBase()) else if (wallet.IsTxImmatureCoinBase(wtx))
entry.pushKV("category", "immature"); entry.pushKV("category", "immature");
else else
entry.pushKV("category", "generate"); entry.pushKV("category", "generate");
@ -1430,7 +1335,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
} }
entry.pushKV("vout", r.vout); entry.pushKV("vout", r.vout);
if (fLong) if (fLong)
WalletTxToJSON(wallet.chain(), wtx, entry); WalletTxToJSON(wallet, wtx, entry);
ret.push_back(entry); ret.push_back(entry);
} }
} }
@ -1673,7 +1578,7 @@ static RPCHelpMan listsinceblock()
for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) { for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
const CWalletTx& tx = pairWtx.second; const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) { if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */); ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
} }
} }
@ -1793,16 +1698,16 @@ static RPCHelpMan gettransaction()
} }
const CWalletTx& wtx = it->second; const CWalletTx& wtx = it->second;
CAmount nCredit = wtx.GetCredit(filter); CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, filter);
CAmount nDebit = wtx.GetDebit(filter); CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, filter);
CAmount nNet = nCredit - nDebit; CAmount nNet = nCredit - nDebit;
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0); CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx, filter) ? wtx.tx->GetValueOut() - nDebit : 0);
entry.pushKV("amount", ValueFromAmount(nNet - nFee)); entry.pushKV("amount", ValueFromAmount(nNet - nFee));
if (wtx.IsFromMe(filter)) if (CachedTxIsFromMe(*pwallet, wtx, filter))
entry.pushKV("fee", ValueFromAmount(nFee)); entry.pushKV("fee", ValueFromAmount(nFee));
WalletTxToJSON(pwallet->chain(), wtx, entry); WalletTxToJSON(*pwallet, wtx, entry);
UniValue details(UniValue::VARR); UniValue details(UniValue::VARR);
ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */); ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
@ -2517,7 +2422,7 @@ static RPCHelpMan getbalances()
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
const auto bal = wallet.GetBalance(); const auto bal = GetBalance(wallet);
UniValue balances{UniValue::VOBJ}; UniValue balances{UniValue::VOBJ};
{ {
UniValue balances_mine{UniValue::VOBJ}; UniValue balances_mine{UniValue::VOBJ};
@ -2527,7 +2432,7 @@ static RPCHelpMan getbalances()
if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) { if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
// the total balance, and then subtract bal to get the reused address balance. // the total balance, and then subtract bal to get the reused address balance.
const auto full_bal = wallet.GetBalance(0, false); const auto full_bal = GetBalance(wallet, 0, false);
balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending)); balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
} }
balances_mine.pushKV("coinjoin", ValueFromAmount(bal.m_anonymized)); balances_mine.pushKV("coinjoin", ValueFromAmount(bal.m_anonymized));
@ -2610,7 +2515,7 @@ static RPCHelpMan getwalletinfo()
bool fHDEnabled = spk_man && spk_man->GetHDChain(hdChainCurrent); bool fHDEnabled = spk_man && spk_man->GetHDChain(hdChainCurrent);
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
const auto bal = pwallet->GetBalance(); const auto bal = GetBalance(*pwallet);
int64_t kp_oldest = pwallet->GetOldestKeyPoolTime(); int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
obj.pushKV("walletname", pwallet->GetName()); obj.pushKV("walletname", pwallet->GetName());
obj.pushKV("walletversion", pwallet->GetVersion()); obj.pushKV("walletversion", pwallet->GetVersion());
@ -3326,7 +3231,7 @@ static RPCHelpMan listunspent()
coinControl.m_include_unsafe_inputs = include_unsafe; coinControl.m_include_unsafe_inputs = include_unsafe;
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
pwallet->AvailableCoins(vecOutputs, &coinControl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount); AvailableCoins(*pwallet, vecOutputs, &coinControl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount);
} }
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
@ -3505,7 +3410,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
bilingual_str error; bilingual_str error;
if (!wallet.FundTransaction(tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) { if (!FundTransaction(wallet, tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
throw JSONRPCError(RPC_WALLET_ERROR, error.original); throw JSONRPCError(RPC_WALLET_ERROR, error.original);
} }
} }
@ -4019,7 +3924,7 @@ RPCHelpMan getaddressinfo()
UniValue detail = DescribeWalletAddress(*pwallet, dest); UniValue detail = DescribeWalletAddress(*pwallet, dest);
ret.pushKVs(detail); ret.pushKVs(detail);
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey)); ret.pushKV("ischange", ScriptIsChange(*pwallet, scriptPubKey));
ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey); ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
if (spk_man) { if (spk_man) {

View File

@ -8,35 +8,10 @@
#include <context.h> #include <context.h>
#include <span.h> #include <span.h>
#include <memory>
#include <string>
#include <vector>
class CRPCCommand; class CRPCCommand;
class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
class UniValue;
class CTransaction;
struct PartiallySignedTransaction;
struct WalletContext;
static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
Span<const CRPCCommand> GetWalletRPCCommands(); Span<const CRPCCommand> GetWalletRPCCommands();
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
void EnsureWalletIsUnlocked(const CWallet&);
WalletContext& EnsureWalletContext(const CoreContext& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
RPCHelpMan getaddressinfo(); RPCHelpMan getaddressinfo();
RPCHelpMan getrawchangeaddress(); RPCHelpMan getrawchangeaddress();
RPCHelpMan addmultisigaddress(); RPCHelpMan addmultisigaddress();

View File

@ -12,6 +12,7 @@
#include <validation.h> #include <validation.h>
#include <wallet/coincontrol.h> #include <wallet/coincontrol.h>
#include <wallet/coinselection.h> #include <wallet/coinselection.h>
#include <wallet/spend.h>
#include <wallet/test/wallet_test_fixture.h> #include <wallet/test/wallet_test_fixture.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
@ -80,7 +81,7 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1); wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
wtx->m_is_cache_empty = false; wtx->m_is_cache_empty = false;
} }
COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */); COutput output(wallet, *wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
coins.push_back(output); coins.push_back(output);
} }
@ -255,7 +256,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 1 * CENT, 2 * CENT, selection, value_ret, not_input_fees)); BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 1 * CENT, 2 * CENT, selection, value_ret, not_input_fees));
} }
// Make sure that effective value is working in SelectCoinsMinConf when BnB is used // Make sure that effective value is working in AttemptSelection when BnB is used
CoinSelectionParams coin_selection_params_bnb(/* use_bnb= */ true, /* change_output_size= */ 0, CoinSelectionParams coin_selection_params_bnb(/* use_bnb= */ true, /* change_output_size= */ 0,
/* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(3000), /* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(3000),
/* long_term_feerate= */ CFeeRate(1000), /* discard_feerate= */ CFeeRate(1000), /* long_term_feerate= */ CFeeRate(1000), /* discard_feerate= */ CFeeRate(1000),
@ -273,14 +274,14 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(coins, *wallet, 1); add_coin(coins, *wallet, 1);
coins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail coins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
BOOST_CHECK(!wallet->SelectCoinsMinConf(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
// Test fees subtracted from output: // Test fees subtracted from output:
coins.clear(); coins.clear();
add_coin(coins, *wallet, 1 * CENT); add_coin(coins, *wallet, 1 * CENT);
coins.at(0).nInputBytes = 40; coins.at(0).nInputBytes = 40;
coin_selection_params_bnb.m_subtract_fee_outputs = true; coin_selection_params_bnb.m_subtract_fee_outputs = true;
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
} }
@ -302,7 +303,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_control.fAllowOtherInputs = true; coin_control.fAllowOtherInputs = true;
coin_control.Select(COutPoint(coins.at(0).tx->GetHash(), coins.at(0).i)); coin_control.Select(COutPoint(coins.at(0).tx->GetHash(), coins.at(0).i));
coin_selection_params_bnb.m_effective_feerate = CFeeRate(0); coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
BOOST_CHECK(wallet->SelectCoins(coins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used)); BOOST_CHECK(SelectCoins(*wallet, coins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used));
BOOST_CHECK(bnb_used); BOOST_CHECK(bnb_used);
BOOST_CHECK(coin_selection_params_bnb.use_bnb); BOOST_CHECK(coin_selection_params_bnb.use_bnb);
} }
@ -326,24 +327,24 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
coins.clear(); coins.clear();
// with an empty wallet we can't even pay one cent // with an empty wallet we can't even pay one cent
BOOST_CHECK(!wallet->SelectCoinsMinConf( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
add_coin(coins, *wallet, 1*CENT, 4); // add a new 1 cent coin add_coin(coins, *wallet, 1*CENT, 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent // with a new 1 cent coin, we still can't find a mature 1 cent
BOOST_CHECK(!wallet->SelectCoinsMinConf( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// but we can find a new 1 cent // but we can find a new 1 cent
BOOST_CHECK(wallet->SelectCoinsMinConf( 1 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection( 1 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
add_coin(coins, *wallet, 2*CENT); // add a mature 2 cent coin add_coin(coins, *wallet, 2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins // we can't make 3 cents of mature coins
BOOST_CHECK(!wallet->SelectCoinsMinConf( 3 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection( 3 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// we can make 3 cents of new coins // we can make 3 cents of new coins
BOOST_CHECK(wallet->SelectCoinsMinConf( 3 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection( 3 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
add_coin(coins, *wallet, 5*CENT); // add a mature 5 cent coin, add_coin(coins, *wallet, 5*CENT); // add a mature 5 cent coin,
@ -353,33 +354,33 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38 // now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins: // we can't make 38 cents only if we disallow new coins:
BOOST_CHECK(!wallet->SelectCoinsMinConf(38 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection(38 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// we can't even make 37 cents if we don't allow new coins even if they're from us // we can't even make 37 cents if we don't allow new coins even if they're from us
BOOST_CHECK(!wallet->SelectCoinsMinConf(38 * CENT, filter_standard_extra, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection(38 * CENT, filter_standard_extra, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// but we can make 37 cents if we accept new coins from ourself // but we can make 37 cents if we accept new coins from ourself
BOOST_CHECK(wallet->SelectCoinsMinConf(37 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(37 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
// and we can make 38 cents if we accept all new coins // and we can make 38 cents if we accept all new coins
BOOST_CHECK(wallet->SelectCoinsMinConf(38 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(38 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly // try making 34 cents from 1,2,5,10,20 - we can't do it exactly
BOOST_CHECK(wallet->SelectCoinsMinConf(34 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(34 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible) BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5 // when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
BOOST_CHECK(wallet->SelectCoinsMinConf( 7 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection( 7 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough. // when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
BOOST_CHECK(wallet->SelectCoinsMinConf( 8 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection( 8 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(nValueRet == 8 * CENT); BOOST_CHECK(nValueRet == 8 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10) // when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
BOOST_CHECK(wallet->SelectCoinsMinConf( 9 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection( 9 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@ -393,30 +394,30 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total add_coin(coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72 // check that we have 71 and not 72
BOOST_CHECK(wallet->SelectCoinsMinConf(71 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(71 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->SelectCoinsMinConf(72 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(!wallet->AttemptSelection(72 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20 // now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
BOOST_CHECK(wallet->SelectCoinsMinConf(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
add_coin(coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total add_coin(coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20 // now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
BOOST_CHECK(wallet->SelectCoinsMinConf(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
add_coin(coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30 add_coin(coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18 // and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
BOOST_CHECK(wallet->SelectCoinsMinConf(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6 // now try making 11 cents. we should get 5+6
BOOST_CHECK(wallet->SelectCoinsMinConf(11 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(11 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@ -425,11 +426,11 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, 2*COIN); add_coin(coins, *wallet, 2*COIN);
add_coin(coins, *wallet, 3*COIN); add_coin(coins, *wallet, 3*COIN);
add_coin(coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents add_coin(coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
BOOST_CHECK(wallet->SelectCoinsMinConf(95 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(95 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
BOOST_CHECK(wallet->SelectCoinsMinConf(195 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(195 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@ -444,14 +445,14 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
// we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly // we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);
// but if we add a bigger coin, small change is avoided // but if we add a bigger coin, small change is avoided
add_coin(coins, *wallet, 1111*MIN_CHANGE); add_coin(coins, *wallet, 1111*MIN_CHANGE);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// if we add more small coins: // if we add more small coins:
@ -459,7 +460,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 7 / 10); add_coin(coins, *wallet, MIN_CHANGE * 7 / 10);
// and try again to make 1.0 * MIN_CHANGE // and try again to make 1.0 * MIN_CHANGE
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) // run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
@ -468,7 +469,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
for (int j = 0; j < 20; j++) for (int j = 0; j < 20; j++)
add_coin(coins, *wallet, 50000 * COIN); add_coin(coins, *wallet, 50000 * COIN);
BOOST_CHECK(wallet->SelectCoinsMinConf(500000 * COIN, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(500000 * COIN, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
@ -481,7 +482,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 6 / 10); add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
add_coin(coins, *wallet, MIN_CHANGE * 7 / 10); add_coin(coins, *wallet, MIN_CHANGE * 7 / 10);
add_coin(coins, *wallet, 1111 * MIN_CHANGE); add_coin(coins, *wallet, 1111 * MIN_CHANGE);
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@ -491,7 +492,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 6 / 10); add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
add_coin(coins, *wallet, MIN_CHANGE * 8 / 10); add_coin(coins, *wallet, MIN_CHANGE * 8 / 10);
add_coin(coins, *wallet, 1111 * MIN_CHANGE); add_coin(coins, *wallet, 1111 * MIN_CHANGE);
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
@ -502,12 +503,12 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 100); add_coin(coins, *wallet, MIN_CHANGE * 100);
// trying to make 100.01 from these three coins // trying to make 100.01 from these three coins
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE * 10001 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change // but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE * 9990 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
} }
@ -521,7 +522,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times. // We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
for (int i = 0; i < RUN_TESTS; i++) { for (int i = 0; i < RUN_TESTS; i++) {
BOOST_CHECK(wallet->SelectCoinsMinConf(2000, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(2000, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
if (amt - 2000 < MIN_CHANGE) { if (amt - 2000 < MIN_CHANGE) {
// needs more than one input: // needs more than one input:
@ -547,8 +548,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
for (int i = 0; i < RUN_TESTS; i++) { for (int i = 0; i < RUN_TESTS; i++) {
// picking 50 from 100 coins doesn't depend on the shuffle, // picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code // but does depend on randomness in the stochastic approximation code
BOOST_CHECK(wallet->SelectCoinsMinConf(50 * COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(50 * COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->SelectCoinsMinConf(50 * COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(50 * COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0; int fails = 0;
@ -556,8 +557,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{ {
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail // run the test RANDOM_REPEATS times and only complain if all of them fail
BOOST_CHECK(wallet->SelectCoinsMinConf(COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->SelectCoinsMinConf(COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
if (equal_sets(setCoinsRet, setCoinsRet2)) if (equal_sets(setCoinsRet, setCoinsRet2))
fails++; fails++;
} }
@ -579,8 +580,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{ {
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail // run the test RANDOM_REPEATS times and only complain if all of them fail
BOOST_CHECK(wallet->SelectCoinsMinConf(90*CENT, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(90*CENT, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->SelectCoinsMinConf(90*CENT, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(90*CENT, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
if (equal_sets(setCoinsRet, setCoinsRet2)) if (equal_sets(setCoinsRet, setCoinsRet2))
fails++; fails++;
} }
@ -606,7 +607,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
add_coin(coins, *wallet, 1000 * COIN); add_coin(coins, *wallet, 1000 * COIN);
add_coin(coins, *wallet, 3 * COIN); add_coin(coins, *wallet, 3 * COIN);
BOOST_CHECK(wallet->SelectCoinsMinConf(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK(wallet->AttemptSelection(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN); BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
} }
@ -656,8 +657,8 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
CoinSet out_set; CoinSet out_set;
CAmount out_value = 0; CAmount out_value = 0;
bool bnb_used = false; bool bnb_used = false;
BOOST_CHECK(wallet->SelectCoinsMinConf(target, filter_standard, coins, out_set, out_value, coin_selection_params_bnb, bnb_used) || BOOST_CHECK(AttemptSelection(wallet, target, filter_standard, coins, out_set, out_value, coin_selection_params_bnb, bnb_used) ||
wallet->SelectCoinsMinConf(target, filter_standard, coins, out_set, out_value, coin_selection_params_knapsack, bnb_used)); AttemptSelection(wallet, target, filter_standard, coins, out_set, out_value, coin_selection_params_knapsack, bnb_used));
BOOST_CHECK_GE(out_value, target); BOOST_CHECK_GE(out_value, target);
} }
} }

View File

@ -23,12 +23,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION); CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1; CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1; s_prev_tx1 >> prev_tx1;
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx1)); m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1));
CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION); CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx2; CTransactionRef prev_tx2;
s_prev_tx2 >> prev_tx2; s_prev_tx2 >> prev_tx2;
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx2)); m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2));
// Add scripts // Add scripts
CScript rs1; CScript rs1;

View File

@ -25,8 +25,9 @@
#include <util/translation.h> #include <util/translation.h>
#include <validation.h> #include <validation.h>
#include <wallet/coincontrol.h> #include <wallet/coincontrol.h>
#include <wallet/receive.h>
#include <wallet/spend.h>
#include <wallet/test/wallet_test_fixture.h> #include <wallet/test/wallet_test_fixture.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <univalue.h> #include <univalue.h>
@ -123,7 +124,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull()); BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK(result.last_scanned_block.IsNull()); BOOST_CHECK(result.last_scanned_block.IsNull());
BOOST_CHECK(!result.last_scanned_height); BOOST_CHECK(!result.last_scanned_height);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0); BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 0);
} }
// Verify ScanForWalletTransactions picks up transactions in both the old // Verify ScanForWalletTransactions picks up transactions in both the old
@ -142,7 +143,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull()); BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 1000 * COIN); BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 1000 * COIN);
} }
// Prune the older block file. // Prune the older block file.
@ -170,7 +171,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash()); BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 500 * COIN); BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 500 * COIN);
} }
// Prune the remaining block file. // Prune the remaining block file.
@ -196,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
BOOST_CHECK(result.last_scanned_block.IsNull()); BOOST_CHECK(result.last_scanned_block.IsNull());
BOOST_CHECK(!result.last_scanned_height); BOOST_CHECK(!result.last_scanned_height);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0); BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 0);
} }
} }
@ -412,7 +413,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{ {
CWallet wallet(m_node.chain.get(), m_node.coinjoin_loader.get(), "", CreateDummyWalletDatabase()); CWallet wallet(m_node.chain.get(), m_node.coinjoin_loader.get(), "", CreateDummyWalletDatabase());
auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan(); auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
CWalletTx wtx(&wallet, m_coinbase_txns.back()); CWalletTx wtx(m_coinbase_txns.back());
LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore); LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore);
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash()); wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
@ -422,13 +423,13 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
// Call GetImmatureCredit() once before adding the key to the wallet to // Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0. // cache the current immature credit amount, which is 0.
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0); BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0);
// Invalidate the cached value, add the key, and make sure a new immature // Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated. // credit amount is calculated.
wtx.MarkDirty(); wtx.MarkDirty();
BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey())); BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 500*COIN); BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 500*COIN);
} }
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime) static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
@ -613,7 +614,7 @@ public:
bilingual_str error; bilingual_str error;
CCoinControl dummy; CCoinControl dummy;
FeeCalculation fee_calc_out; FeeCalculation fee_calc_out;
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy, fee_calc_out)); BOOST_CHECK(CreateTransaction(*wallet, {recipient}, tx, fee, changePos, error, dummy, fee_calc_out));
wallet->CommitTransaction(tx, {}, {}); wallet->CommitTransaction(tx, {}, {});
CMutableTransaction blocktx; CMutableTransaction blocktx;
{ {
@ -634,7 +635,7 @@ public:
std::unique_ptr<CWallet> wallet; std::unique_ptr<CWallet> wallet;
}; };
BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
{ {
std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString(); std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
@ -643,14 +644,14 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
std::map<CTxDestination, std::vector<COutput>> list; std::map<CTxDestination, std::vector<COutput>> list;
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
list = wallet->ListCoins(); list = ListCoins(*wallet);
} }
BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
// Check initial balance from one mature coinbase transaction. // Check initial balance from one mature coinbase transaction.
BOOST_CHECK_EQUAL(500 * COIN, wallet->GetAvailableBalance()); BOOST_CHECK_EQUAL(500 * COIN, GetAvailableBalance(*wallet));
// Add a transaction creating a change address, and confirm ListCoins still // Add a transaction creating a change address, and confirm ListCoins still
// returns the coin associated with the change address underneath the // returns the coin associated with the change address underneath the
@ -659,7 +660,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
list = wallet->ListCoins(); list = ListCoins(*wallet);
} }
BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
@ -669,7 +670,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
std::vector<COutput> available; std::vector<COutput> available;
wallet->AvailableCoins(available); AvailableCoins(*wallet, available);
BOOST_CHECK_EQUAL(available.size(), 2U); BOOST_CHECK_EQUAL(available.size(), 2U);
} }
for (const auto& group : list) { for (const auto& group : list) {
@ -681,14 +682,14 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
std::vector<COutput> available; std::vector<COutput> available;
wallet->AvailableCoins(available); AvailableCoins(*wallet, available);
BOOST_CHECK_EQUAL(available.size(), 0U); BOOST_CHECK_EQUAL(available.size(), 0U);
} }
// Confirm ListCoins still returns same result as before, despite coins // Confirm ListCoins still returns same result as before, despite coins
// being locked. // being locked.
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
list = wallet->ListCoins(); list = ListCoins(*wallet);
} }
BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);

View File

@ -617,7 +617,7 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
const uint256& wtxid = it->second; const uint256& wtxid = it->second;
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid); std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) { if (mit != mapWallet.end()) {
int depth = mit->second.GetDepthInMainChain(); int depth = GetTxDepthInMainChain(mit->second);
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
return true; // Spent return true; // Spent
} }
@ -905,7 +905,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
} }
// Inserts only if not already there, returns tx inserted or tx found // Inserts only if not already there, returns tx inserted or tx found
auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, tx)); auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx));
CWalletTx& wtx = (*ret.first).second; CWalletTx& wtx = (*ret.first).second;
bool fInsertedNew = ret.second; bool fInsertedNew = ret.second;
bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew); bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
@ -1014,7 +1014,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
{ {
const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, nullptr)); const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr));
CWalletTx& wtx = ins.first->second; CWalletTx& wtx = ins.first->second;
if (!fill_wtx(wtx, ins.second)) { if (!fill_wtx(wtx, ins.second)) {
return false; return false;
@ -1112,7 +1112,7 @@ bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
const CWalletTx* wtx = GetWalletTx(hashTx); const CWalletTx* wtx = GetWalletTx(hashTx);
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool(); return wtx && !wtx->isAbandoned() && GetTxDepthInMainChain(*wtx) == 0 && !wtx->InMempool();
} }
bool CWallet::TransactionCanBeResent(const uint256& hashTx) const bool CWallet::TransactionCanBeResent(const uint256& hashTx) const
@ -1145,7 +1145,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(hashTx); auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end()); assert(it != mapWallet.end());
const CWalletTx& origtx = it->second; const CWalletTx& origtx = it->second;
if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool() || origtx.IsLockedByInstantSend()) { if (GetTxDepthInMainChain(origtx) != 0 || origtx.InMempool() || origtx.IsLockedByInstantSend()) {
return false; return false;
} }
@ -1158,7 +1158,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(now); auto it = mapWallet.find(now);
assert(it != mapWallet.end()); assert(it != mapWallet.end());
CWalletTx& wtx = it->second; CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain(); int currentconfirm = GetTxDepthInMainChain(wtx);
// If the orig tx was not in block, none of its spends can be // If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0); assert(currentconfirm <= 0);
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon} // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
@ -1228,7 +1228,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
auto it = mapWallet.find(now); auto it = mapWallet.find(now);
assert(it != mapWallet.end()); assert(it != mapWallet.end());
CWalletTx& wtx = it->second; CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain(); int currentconfirm = GetTxDepthInMainChain(wtx);
if (conflictconfirms < currentconfirm) { if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update. // Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block. // Mark transaction as conflicted with this block.
@ -2141,7 +2141,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = item.second; CWalletTx& wtx = item.second;
assert(wtx.GetHash() == wtxid); assert(wtx.GetHash() == wtxid);
int nDepth = wtx.GetDepthInMainChain(); int nDepth = GetTxDepthInMainChain(wtx);
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.IsLockedByInstantSend() && !wtx.isAbandoned())) { if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.IsLockedByInstantSend() && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
@ -2152,7 +2152,7 @@ void CWallet::ReacceptWalletTransactions()
for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) { for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
CWalletTx& wtx = *(item.second); CWalletTx& wtx = *(item.second);
bilingual_str unused_err_string; bilingual_str unused_err_string;
wtx.SubmitMemoryPoolAndRelay(unused_err_string, false); SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, false);
} }
} }
@ -2177,7 +2177,7 @@ bool CWalletTx::SubmitMemoryPoolAndRelay(bilingual_str& err_string, bool relay)
if (!CanBeResent()) return false; if (!CanBeResent()) return false;
// Submit transaction to mempool for relay // Submit transaction to mempool for relay
pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", GetHash().ToString()); WalletLogPrintf("Submitting wtx %s to mempool for relay\n", wtx.GetHash().ToString());
// We must set fInMempool here - while it will be re-set to true by the // We must set fInMempool here - while it will be re-set to true by the
// entered-mempool callback, if we did not there would be a race where a // entered-mempool callback, if we did not there would be a race where a
// user could call sendmoney in a loop and hit spurious out of funds errors // user could call sendmoney in a loop and hit spurious out of funds errors
@ -2187,19 +2187,18 @@ bool CWalletTx::SubmitMemoryPoolAndRelay(bilingual_str& err_string, bool relay)
// Irrespective of the failure reason, un-marking fInMempool // Irrespective of the failure reason, un-marking fInMempool
// out-of-order is incorrect - it should be unmarked when // out-of-order is incorrect - it should be unmarked when
// TransactionRemovedFromMempool fires. // TransactionRemovedFromMempool fires.
bool ret = pwallet->chain().broadcastTransaction(tx, pwallet->m_default_max_tx_fee, relay, err_string); bool ret = chain().broadcastTransaction(wtx.tx, m_default_max_tx_fee, relay, err_string);
fInMempool |= ret; wtx.fInMempool |= ret;
return ret; return ret;
} }
std::set<uint256> CWalletTx::GetConflicts() const std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
{ {
std::set<uint256> result; std::set<uint256> result;
if (pwallet != nullptr)
{ {
AssertLockHeld(pwallet->cs_wallet); AssertLockHeld(pwallet->cs_wallet);
uint256 myHash = GetHash(); uint256 myHash = wtx.GetHash();
result = pwallet->GetConflicts(myHash); result = GetConflicts(myHash);
result.erase(myHash); result.erase(myHash);
} }
return result; return result;
@ -2485,11 +2484,11 @@ void CWallet::ResendWalletTransactions()
for (std::pair<const uint256, CWalletTx>& item : mapWallet) { for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
CWalletTx& wtx = item.second; CWalletTx& wtx = item.second;
// Attempt to rebroadcast all txes more than 5 minutes older than // Attempt to rebroadcast all txes more than 5 minutes older than
// the last block. SubmitMemoryPoolAndRelay() will not rebroadcast // the last block. SubmitTxMemoryPoolAndRelay() will not rebroadcast
// any confirmed or conflicting txs. // any confirmed or conflicting txs.
if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue; if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
bilingual_str unused_err_string; bilingual_str unused_err_string;
if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true)) ++submitted_tx_count; if (SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, true)) ++submitted_tx_count;
} }
} // cs_wallet } // cs_wallet
@ -2882,7 +2881,7 @@ static bool isGroupISLocked(const OutputGroup& group, interfaces::Chain& chain)
}); });
} }
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, bool CWallet::AttemptSelection(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType) const std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType) const
{ {
setCoinsRet.clear(); setCoinsRet.clear();
@ -3015,32 +3014,32 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
// confirmations on outputs received from other wallets and only spend confirmed change. // confirmations on outputs received from other wallets and only spend confirmed change.
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true; if (AttemptSelection(value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true; if (AttemptSelection(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as // Fall back to using zero confirmation change (but with as few ancestors in the mempool as
// possible) if we cannot fund the transaction otherwise. // possible) if we cannot fund the transaction otherwise.
if (m_spend_zero_conf_change) { if (m_spend_zero_conf_change) {
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true; if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) { vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true; return true;
} }
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) { vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true; return true;
} }
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups // If partial groups are allowed, relax the requirement of spending OutputGroups (groups
// of UTXOs sent to the same address, which are obviously controlled by a single wallet) // of UTXOs sent to the same address, which are obviously controlled by a single wallet)
// in their entirety. // in their entirety.
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) { vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true; return true;
} }
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
// received from other wallets. // received from other wallets.
if (coin_control.m_include_unsafe_inputs if (coin_control.m_include_unsafe_inputs
&& SelectCoinsMinConf(value_to_select, && AttemptSelection(value_to_select,
CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) { vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true; return true;
@ -3048,7 +3047,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
// Try with unlimited ancestors/descendants. The transaction will still need to meet // Try with unlimited ancestors/descendants. The transaction will still need to meet
// mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but // mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
// OutputGroups use heuristics that may overestimate ancestor/descendant counts. // OutputGroups use heuristics that may overestimate ancestor/descendant counts.
if (!fRejectLongChains && SelectCoinsMinConf(value_to_select, if (!fRejectLongChains && AttemptSelection(value_to_select,
CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */), CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) { vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true; return true;
@ -3058,7 +3057,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
return false; return false;
}(); }();
// SelectCoinsMinConf clears setCoinsRet, so add the preset inputs from coin_control to the coinset // AttemptSelection clears setCoinsRet, so add the preset inputs from coin_control to the coinset
util::insert(setCoinsRet, setPresetCoins); util::insert(setCoinsRet, setPresetCoins);
// add preset inputs to the total value selected // add preset inputs to the total value selected
@ -3995,7 +3994,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
} }
bilingual_str err_string; bilingual_str err_string;
if (!wtx.SubmitMemoryPoolAndRelay(err_string, true)) { if (!SubmitTxMemoryPoolAndRelay(wtx, err_string, true)) {
WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string.original); WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string.original);
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure. // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} }
@ -5451,13 +5450,12 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn)
fInternal = fInternalIn; fInternal = fInternalIn;
} }
int CWalletTx::GetDepthInMainChain() const int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
{ {
assert(pwallet != nullptr); AssertLockHeld(cs_wallet);
AssertLockHeld(pwallet->cs_wallet); if (wtx.isUnconfirmed() || wtx.isAbandoned()) return 0;
if (isUnconfirmed() || isAbandoned()) return 0;
return (pwallet->GetLastBlockHeight() - m_confirm.block_height + 1) * (isConflicted() ? -1 : 1); return (GetLastBlockHeight() - wtx.m_confirm.block_height + 1) * (wtx.isConflicted() ? -1 : 1);
} }
bool CWalletTx::IsLockedByInstantSend() const bool CWalletTx::IsLockedByInstantSend() const
@ -5484,19 +5482,19 @@ bool CWalletTx::IsChainLocked() const
return fIsChainlocked; return fIsChainlocked;
} }
int CWalletTx::GetBlocksToMaturity() const int CWallet::GetTxBlocksToMaturity(const CWalletTx& wtx) const
{ {
if (!IsCoinBase()) if (!wtx.IsCoinBase())
return 0; return 0;
int chain_depth = GetDepthInMainChain(); int chain_depth = GetTxDepthInMainChain(wtx);
assert(chain_depth >= 0); // coinbase tx should not be conflicted assert(chain_depth >= 0); // coinbase tx should not be conflicted
return std::max(0, (COINBASE_MATURITY+1) - chain_depth); return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
} }
bool CWalletTx::IsImmatureCoinBase() const bool CWallet::IsTxImmatureCoinBase(const CWalletTx& wtx) const
{ {
// note GetBlocksToMaturity is 0 for non-coinbase tx // note GetBlocksToMaturity is 0 for non-coinbase tx
return GetBlocksToMaturity() > 0; return GetTxBlocksToMaturity(wtx) > 0;
} }
std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, bool separate_coins, const CFeeRate& effective_feerate, const CFeeRate& long_term_feerate, const CoinEligibilityFilter& filter, bool positive_only) const std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, bool separate_coins, const CFeeRate& effective_feerate, const CFeeRate& long_term_feerate, const CoinEligibilityFilter& filter, bool positive_only) const

View File

@ -541,7 +541,6 @@ public:
bool IsEquivalentTo(const CWalletTx& tx) const; bool IsEquivalentTo(const CWalletTx& tx) const;
bool InMempool() const; bool InMempool() const;
bool IsTrusted() const;
int64_t GetTxTime() const; int64_t GetTxTime() const;
@ -858,8 +857,6 @@ private:
// ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure // ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure
std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers; std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers;
bool CreateTransactionInternal(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign, int nExtraPayloadSize);
/** /**
* Catch wallet up to current chain, scanning new blocks, updating the best * Catch wallet up to current chain, scanning new blocks, updating the best
* block locator and m_last_block_processed, and registering for * block locator and m_last_block_processed, and registering for
@ -880,17 +877,6 @@ public:
return *m_database; return *m_database;
} }
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
* all coins from coin_control are selected; never select unconfirmed coins if they are not ours
* param@[out] setCoinsRet Populated with inputs including pre-selected inputs from
* coin_control and Coin Selection if successful.
* param@[out] nValueRet Total value of selected coins including pre-selected ones
* from coin_control and Coin Selection if successful.
*/
bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet,
const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Get a name for this wallet for logging/debugging purposes. /** Get a name for this wallet for logging/debugging purposes.
*/ */
const std::string& GetName() const { return m_name; } const std::string& GetName() const { return m_name; }
@ -972,25 +958,37 @@ public:
bool coinjoin_available() { return m_coinjoin_loader != nullptr; } bool coinjoin_available() { return m_coinjoin_loader != nullptr; }
const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! check whether we support the named feature // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return IsFeatureSupported(nWalletVersion, wf); } // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
// resolve the issue of member access into incomplete type CWallet. Note
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
// in place.
std::set<uint256> GetTxConflicts(const CWalletTx& wtx) const NO_THREAD_SAFETY_ANALYSIS;
/** /**
* populate vCoins with vector of available COutputs. * Return depth of transaction in blockchain:
* <0 : conflicts with a transaction this deep in the blockchain
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/ */
void AvailableCoins(std::vector<COutput>& vCoins, const CCoinControl* coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
// resolve the issue of member access into incomplete type CWallet. Note
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
// in place.
int GetTxDepthInMainChain(const CWalletTx& wtx) const NO_THREAD_SAFETY_ANALYSIS;
bool IsTxInMainChain(const CWalletTx& wtx) const { return GetTxDepthInMainChain(wtx) > 0; }
/** /**
* Return list of available coins and locked coins grouped by non-change output address. * @return number of blocks to maturity for this transaction:
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
* >0 : is a coinbase transaction which matures in this many blocks
*/ */
std::map<CTxDestination, std::vector<COutput>> ListCoins() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); int GetTxBlocksToMaturity(const CWalletTx& wtx) const;
bool IsTxImmatureCoinBase(const CWalletTx& wtx) const;
/**
* Find non-change parent output.
*/
const CTxOut& FindNonChangeParentOutput(const CTransaction& tx, int output) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** /**
* Shuffle and select coins until nTargetValue is reached while avoiding * Shuffle and select coins until nTargetValue is reached while avoiding
@ -1003,7 +1001,7 @@ public:
* param@[out] setCoinsRet Populated with the coins selected if successful. * param@[out] setCoinsRet Populated with the coins selected if successful.
* param@[out] nValueRet Used to return the total value of selected coins. * param@[out] nValueRet Used to return the total value of selected coins.
*/ */
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType = CoinType::ALL_COINS) const; bool AttemptSelection(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType = CoinType::ALL_COINS) const;
// Coin selection // Coin selection
bool SelectTxDSInsByDenomination(int nDenom, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet); bool SelectTxDSInsByDenomination(int nDenom, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet);
@ -1030,8 +1028,6 @@ public:
bool IsSpentKey(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsSpentKey(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool separate_coins, const CFeeRate& effective_feerate, const CFeeRate& long_term_feerate, const CoinEligibilityFilter& filter, bool positive_only) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void LockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void UnlockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void UnlockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -1115,31 +1111,12 @@ public:
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override; void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void ResendWalletTransactions(); void ResendWalletTransactions();
struct Balance {
CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more
CAmount m_mine_untrusted_pending{0}; //!< Untrusted, but in mempool (pending)
CAmount m_mine_immature{0}; //!< Immature coinbases in the main chain
CAmount m_watchonly_trusted{0};
CAmount m_watchonly_untrusted_pending{0};
CAmount m_watchonly_immature{0};
CAmount m_anonymized{0};
CAmount m_denominated_trusted{0};
CAmount m_denominated_untrusted_pending{0};
};
Balance GetBalance(const int min_depth = 0, const bool avoid_reuse = true, const bool fAddLocked = false, const CCoinControl* coinControl = nullptr) const;
CAmount GetAnonymizableBalance(bool fSkipDenominated = false, bool fSkipUnconfirmed = true) const; CAmount GetAnonymizableBalance(bool fSkipDenominated = false, bool fSkipUnconfirmed = true) const;
float GetAverageAnonymizedRounds() const; float GetAverageAnonymizedRounds() const;
CAmount GetNormalizedAnonymizedBalance() const; CAmount GetNormalizedAnonymizedBalance() const;
bool GetBudgetSystemCollateralTX(CTransactionRef& tx, uint256 hash, CAmount amount, const COutPoint& outpoint=COutPoint()/*defaults null*/); bool GetBudgetSystemCollateralTX(CTransactionRef& tx, uint256 hash, CAmount amount, const COutPoint& outpoint=COutPoint()/*defaults null*/);
CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
/**
* Insert additional inputs into the transaction by
* calling CreateTransaction();
*/
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
/** Fetch the inputs and sign with SIGHASH_ALL. */ /** Fetch the inputs and sign with SIGHASH_ALL. */
bool SignTransaction(CMutableTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool SignTransaction(CMutableTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Sign the tx given the input coins and sighash. */ /** Sign the tx given the input coins and sighash. */
@ -1171,12 +1148,6 @@ public:
bool bip32derivs = true, bool bip32derivs = true,
size_t* n_signed = nullptr) const; size_t* n_signed = nullptr) const;
/**
* Create a new transaction paying the recipients with a set of coins
* selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign = true, int nExtraPayloadSize = 0);
/** /**
* Submit the transaction to the node's mempool and then relay to peers. * Submit the transaction to the node's mempool and then relay to peers.
* Should be called after CreateTransaction unless you want to abort * Should be called after CreateTransaction unless you want to abort
@ -1188,6 +1159,9 @@ public:
*/ */
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm); void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
/** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */
bool SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_string, bool relay) const;
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const
{ {
std::vector<CTxOut> v_txouts(txouts.size()); std::vector<CTxOut> v_txouts(txouts.size());
@ -1230,9 +1204,6 @@ public:
int64_t GetOldestKeyPoolTime() const; int64_t GetOldestKeyPoolTime() const;
std::set<std::set<CTxDestination>> GetAddressGroupings() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::map<CTxDestination, CAmount> GetAddressBalances() const;
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const; std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
/** /**
@ -1246,25 +1217,16 @@ public:
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** /**
* Returns amount of debit if the input matches the * Returns amount of debit if the input matches the
* filter, otherwise returns 0 * filter, otherwise returns 0
*/ */
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** should probably be renamed to IsRelevantToMe */ /** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const; bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
/** Returns whether all of the inputs match the filter */
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetChange(const CTransaction& tx) const;
void chainStateFlushed(const CBlockLocator& loc) override; void chainStateFlushed(const CBlockLocator& loc) override;
DBErrors LoadWallet(); DBErrors LoadWallet();
@ -1564,15 +1526,6 @@ public:
} }
} }
};
/** Calculate the size of the transaction assuming all signatures are max size
* Use DummySignatureCreator, which inserts 71 byte signatures everywhere.
* NOTE: this requires that all inputs must be in mapWallet (eg the tx should
* be IsAllFromMe). */
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
//! Add wallet name to persistent configuration so it will be loaded on startup. //! Add wallet name to persistent configuration so it will be loaded on startup.
bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name); bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);

View File

@ -953,7 +953,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
uint256 hash; uint256 hash;
ssKey >> hash; ssKey >> hash;
vTxHash.push_back(hash); vTxHash.push_back(hash);
vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */); vWtx.emplace_back(nullptr /* tx */);
ssValue >> vWtx.back(); ssValue >> vWtx.back();
} }
} }

View File

@ -2,6 +2,12 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <wallet/wallettool.h>
#include <fs.h> #include <fs.h>
#include <util/translation.h> #include <util/translation.h>
#include <util/system.h> #include <util/system.h>

View File

@ -5,11 +5,12 @@
#ifndef BITCOIN_WALLET_WALLETTOOL_H #ifndef BITCOIN_WALLET_WALLETTOOL_H
#define BITCOIN_WALLET_WALLETTOOL_H #define BITCOIN_WALLET_WALLETTOOL_H
#include <wallet/wallet.h> #include <string>
class ArgsManager;
namespace WalletTool { namespace WalletTool {
void WalletShowInfo(CWallet* wallet_instance);
bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command); bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command);
} // namespace WalletTool } // namespace WalletTool

View File

@ -66,10 +66,16 @@ def cli_get_info_string_to_dict(cli_get_info_string):
class TestBitcoinCli(BitcoinTestFramework): class TestBitcoinCli(BitcoinTestFramework):
def is_specified_wallet_compiled(self):
if self.options.descriptors:
return self.is_sqlite_compiled()
else:
return self.is_bdb_compiled()
def set_test_params(self): def set_test_params(self):
self.setup_clean_chain = True self.setup_clean_chain = True
self.num_nodes = 1 self.num_nodes = 1
if self.is_wallet_compiled(): if self.is_specified_wallet_compiled():
self.requires_wallet = True self.requires_wallet = True
def skip_test_if_missing_module(self): def skip_test_if_missing_module(self):
@ -122,7 +128,7 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_raises_process_error(1, "Invalid value for -color option. Valid values: always, auto, never.", self.nodes[0].cli('-getinfo', '-color=foo').send_cli) assert_raises_process_error(1, "Invalid value for -color option. Valid values: always, auto, never.", self.nodes[0].cli('-getinfo', '-color=foo').send_cli)
self.log.info("Test -getinfo returns expected network and blockchain info") self.log.info("Test -getinfo returns expected network and blockchain info")
if self.is_wallet_compiled(): if self.is_specified_wallet_compiled():
self.nodes[0].encryptwallet(password) self.nodes[0].encryptwallet(password)
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli() cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string) cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
@ -147,7 +153,7 @@ class TestBitcoinCli(BitcoinTestFramework):
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string) cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
assert_equal(cli_get_info["Proxies"], "127.0.0.1:9050 (ipv4, ipv6, onion, cjdns), 127.0.0.1:7656 (i2p)") assert_equal(cli_get_info["Proxies"], "127.0.0.1:9050 (ipv4, ipv6, onion, cjdns), 127.0.0.1:7656 (i2p)")
if self.is_wallet_compiled(): if self.is_specified_wallet_compiled():
self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info") self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info")
assert_equal(Decimal(cli_get_info['Balance']), BALANCE) assert_equal(Decimal(cli_get_info['Balance']), BALANCE)
assert 'Balances' not in cli_get_info_string assert 'Balances' not in cli_get_info_string

View File

@ -3,7 +3,16 @@
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful Script constants and utils.""" """Useful Script constants and utils."""
from test_framework.script import CScript, hash160, OP_DUP, OP_HASH160, OP_CHECKSIG, OP_EQUAL, OP_EQUALVERIFY from test_framework.script import (
CScript,
hash160,
OP_0,
OP_DUP,
OP_HASH160,
OP_CHECKSIG,
OP_EQUAL,
OP_EQUALVERIFY,
)
# To prevent a "tx-size-small" policy rule error, a transaction has to have a # To prevent a "tx-size-small" policy rule error, a transaction has to have a
# size of at least 83 bytes (MIN_STANDARD_TX_SIZE in # size of at least 83 bytes (MIN_STANDARD_TX_SIZE in
@ -25,32 +34,38 @@ from test_framework.script import CScript, hash160, OP_DUP, OP_HASH160, OP_CHECK
DUMMY_P2SH_SCRIPT = CScript([b'a' * 22]) DUMMY_P2SH_SCRIPT = CScript([b'a' * 22])
DUMMY_2_P2SH_SCRIPT = CScript([b'b' * 22]) DUMMY_2_P2SH_SCRIPT = CScript([b'b' * 22])
def keyhash_to_p2pkh_script(hash, main = False):
def keyhash_to_p2pkh_script(hash):
assert len(hash) == 20 assert len(hash) == 20
return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG]) return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG])
def scripthash_to_p2sh_script(hash, main = False):
def scripthash_to_p2sh_script(hash):
assert len(hash) == 20 assert len(hash) == 20
return CScript([OP_HASH160, hash, OP_EQUAL]) return CScript([OP_HASH160, hash, OP_EQUAL])
def key_to_p2pkh_script(key, main = False):
key = check_key(key)
return keyhash_to_p2pkh_script(hash160(key), main)
def script_to_p2sh_script(script, main = False): def key_to_p2pkh_script(key):
key = check_key(key)
return keyhash_to_p2pkh_script(hash160(key))
def script_to_p2sh_script(script):
script = check_script(script) script = check_script(script)
return scripthash_to_p2sh_script(hash160(script), main) return scripthash_to_p2sh_script(hash160(script))
def check_key(key): def check_key(key):
if isinstance(key, str): if isinstance(key, str):
key = bytes.fromhex(key) # Assuming this is hex string key = bytes.fromhex(key) # Assuming this is hex string
if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65): if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):
return key return key
assert False assert False
def check_script(script): def check_script(script):
if isinstance(script, str): if isinstance(script, str):
script = bytes.fromhex(script) # Assuming this is hex string script = bytes.fromhex(script) # Assuming this is hex string
if isinstance(script, bytes) or isinstance(script, CScript): if isinstance(script, bytes) or isinstance(script, CScript):
return script return script
assert False assert False

View File

@ -617,7 +617,7 @@ class WalletTest(BitcoinTestFramework):
total_txs = len(self.nodes[0].listtransactions("*", 99999)) total_txs = len(self.nodes[0].listtransactions("*", 99999))
# Try with walletrejectlongchains # Try with walletrejectlongchains
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf # Double chain limit but require combining inputs, so we pass AttemptSelection
self.stop_node(0) self.stop_node(0)
extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)] extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]
self.start_node(0, extra_args=extra_args) self.start_node(0, extra_args=extra_args)