mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Compare commits
9 Commits
416984e562
...
1cfe7c506f
Author | SHA1 | Date | |
---|---|---|---|
|
1cfe7c506f | ||
|
ad7a373529 | ||
|
d75ee3a9e1 | ||
|
8a58b5e244 | ||
|
18ddb83fbc | ||
|
9e7f0e0d6e | ||
|
7bfcbb2f89 | ||
|
6801e0d1ed | ||
|
0469c6a9ae |
@ -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.
|
||||||
|
@ -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 )`
|
||||||
|
@ -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 \
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
122
src/wallet/rpc/util.cpp
Normal 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
38
src/wallet/rpc/util.h
Normal 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
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user