mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge pull request #4442 from UdjinM6/pr4319_new
Backport #14023, #13825, #14411 (and revert #14441)
This commit is contained in:
commit
b6640644eb
8
doc/release-notes-14023.md
Normal file
8
doc/release-notes-14023.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Account API removed
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The 'account' API was deprecated in v0.17 and has been fully removed in v0.18.
|
||||||
|
The 'label' API was introduced in v0.17 as a replacement for accounts.
|
||||||
|
|
||||||
|
See the release notes from v0.17 for a full description of the changes from the
|
||||||
|
'account' API to the 'label' API.
|
@ -198,7 +198,6 @@ BITCOIN_TESTS =\
|
|||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
BITCOIN_TESTS += \
|
BITCOIN_TESTS += \
|
||||||
wallet/test/coinjoin_tests.cpp \
|
wallet/test/coinjoin_tests.cpp \
|
||||||
wallet/test/accounting_tests.cpp \
|
|
||||||
wallet/test/db_tests.cpp \
|
wallet/test/db_tests.cpp \
|
||||||
wallet/test/psbt_wallet_tests.cpp \
|
wallet/test/psbt_wallet_tests.cpp \
|
||||||
wallet/test/wallet_tests.cpp \
|
wallet/test/wallet_tests.cpp \
|
||||||
|
@ -306,7 +306,7 @@ bool CTransactionBuilder::Commit(std::string& strResult)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!pwallet->CommitTransaction(tx, {}, {}, {}, dummyReserveKey, g_connman.get(), state)) {
|
if (!pwallet->CommitTransaction(tx, {}, {}, dummyReserveKey, g_connman.get(), state)) {
|
||||||
strResult = state.GetRejectReason();
|
strResult = state.GetRejectReason();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -40,13 +40,12 @@ public:
|
|||||||
|
|
||||||
bool commit(WalletValueMap value_map,
|
bool commit(WalletValueMap value_map,
|
||||||
WalletOrderForm order_form,
|
WalletOrderForm order_form,
|
||||||
std::string from_account,
|
|
||||||
std::string& reject_reason) override
|
std::string& reject_reason) override
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, mempool.cs);
|
LOCK2(cs_main, mempool.cs);
|
||||||
LOCK(m_wallet.cs_wallet);
|
LOCK(m_wallet.cs_wallet);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), std::move(from_account), m_key, g_connman.get(), state)) {
|
if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_key, g_connman.get(), state)) {
|
||||||
reject_reason = state.GetRejectReason();
|
reject_reason = state.GetRejectReason();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,6 @@ public:
|
|||||||
//! Send pending transaction and commit to wallet.
|
//! Send pending transaction and commit to wallet.
|
||||||
virtual bool commit(WalletValueMap value_map,
|
virtual bool commit(WalletValueMap value_map,
|
||||||
WalletOrderForm order_form,
|
WalletOrderForm order_form,
|
||||||
std::string from_account,
|
|
||||||
std::string& reject_reason) = 0;
|
std::string& reject_reason) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
|||||||
|
|
||||||
auto& newTx = transaction.getWtx();
|
auto& newTx = transaction.getWtx();
|
||||||
std::string rejectReason;
|
std::string rejectReason;
|
||||||
if (!newTx->commit(std::move(mapValue), std::move(vOrderForm), {} /* fromAccount */, rejectReason))
|
if (!newTx->commit(std::move(mapValue), std::move(vOrderForm), rejectReason))
|
||||||
return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(rejectReason));
|
return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(rejectReason));
|
||||||
|
|
||||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
@ -44,8 +44,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "settxfee", 0, "amount" },
|
{ "settxfee", 0, "amount" },
|
||||||
{ "getreceivedbyaddress", 1, "minconf" },
|
{ "getreceivedbyaddress", 1, "minconf" },
|
||||||
{ "getreceivedbyaddress", 2, "addlocked" },
|
{ "getreceivedbyaddress", 2, "addlocked" },
|
||||||
{ "getreceivedbyaccount", 1, "minconf" },
|
|
||||||
{ "getreceivedbyaccount", 2, "addlocked" },
|
|
||||||
{ "getreceivedbylabel", 1, "minconf" },
|
{ "getreceivedbylabel", 1, "minconf" },
|
||||||
{ "getreceivedbylabel", 2, "addlocked" },
|
{ "getreceivedbylabel", 2, "addlocked" },
|
||||||
{ "listaddressbalances", 0, "minamount" },
|
{ "listaddressbalances", 0, "minamount" },
|
||||||
@ -53,10 +51,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "listreceivedbyaddress", 1, "addlocked" },
|
{ "listreceivedbyaddress", 1, "addlocked" },
|
||||||
{ "listreceivedbyaddress", 2, "include_empty" },
|
{ "listreceivedbyaddress", 2, "include_empty" },
|
||||||
{ "listreceivedbyaddress", 3, "include_watchonly" },
|
{ "listreceivedbyaddress", 3, "include_watchonly" },
|
||||||
{ "listreceivedbyaccount", 0, "minconf" },
|
|
||||||
{ "listreceivedbyaccount", 1, "addlocked" },
|
|
||||||
{ "listreceivedbyaccount", 2, "include_empty" },
|
|
||||||
{ "listreceivedbyaccount", 3, "include_watchonly" },
|
|
||||||
{ "listreceivedbylabel", 0, "minconf" },
|
{ "listreceivedbylabel", 0, "minconf" },
|
||||||
{ "listreceivedbylabel", 1, "addlocked" },
|
{ "listreceivedbylabel", 1, "addlocked" },
|
||||||
{ "listreceivedbylabel", 2, "include_empty" },
|
{ "listreceivedbylabel", 2, "include_empty" },
|
||||||
@ -72,17 +66,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "waitforblockheight", 1, "timeout" },
|
{ "waitforblockheight", 1, "timeout" },
|
||||||
{ "waitforblock", 1, "timeout" },
|
{ "waitforblock", 1, "timeout" },
|
||||||
{ "waitfornewblock", 0, "timeout" },
|
{ "waitfornewblock", 0, "timeout" },
|
||||||
{ "move", 2, "amount" },
|
|
||||||
{ "move", 3, "minconf" },
|
|
||||||
{ "sendfrom", 2, "amount" },
|
|
||||||
{ "sendfrom", 3, "minconf" },
|
|
||||||
{ "sendfrom", 4, "addlocked" },
|
|
||||||
{ "listtransactions", 1, "count" },
|
{ "listtransactions", 1, "count" },
|
||||||
{ "listtransactions", 2, "skip" },
|
{ "listtransactions", 2, "skip" },
|
||||||
{ "listtransactions", 3, "include_watchonly" },
|
{ "listtransactions", 3, "include_watchonly" },
|
||||||
{ "listaccounts", 0, "minconf" },
|
|
||||||
{ "listaccounts", 1, "addlocked" },
|
|
||||||
{ "listaccounts", 2, "include_watchonly" },
|
|
||||||
{ "walletpassphrase", 1, "timeout" },
|
{ "walletpassphrase", 1, "timeout" },
|
||||||
{ "walletpassphrase", 2, "mixingonly" },
|
{ "walletpassphrase", 2, "mixingonly" },
|
||||||
{ "getblocktemplate", 0, "template_request" },
|
{ "getblocktemplate", 0, "template_request" },
|
||||||
|
@ -227,7 +227,7 @@ static UniValue gobject_prepare(const JSONRPCRequest& request)
|
|||||||
CReserveKey reservekey(pwallet);
|
CReserveKey reservekey(pwallet);
|
||||||
// -- send the tx to the network
|
// -- send the tx to the network
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!pwallet->CommitTransaction(tx, {}, {}, {}, reservekey, g_connman.get(), state)) {
|
if (!pwallet->CommitTransaction(tx, {}, {}, reservekey, g_connman.get(), state)) {
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "CommitTransaction failed! Reason given: " + state.GetRejectReason());
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "CommitTransaction failed! Reason given: " + state.GetRejectReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ void WalletInit::AddWalletOptions() const
|
|||||||
gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", false, OptionsCategory::WALLET);
|
gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", false, OptionsCategory::WALLET);
|
||||||
gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
|
gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
|
||||||
gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
|
gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
|
||||||
" (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET);
|
" (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET);
|
||||||
|
|
||||||
gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
|
gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
|
||||||
"Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
|
"Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
|
||||||
|
@ -1353,7 +1353,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
|||||||
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
|
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
|
||||||
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments aka change\n"
|
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments aka change\n"
|
||||||
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
|
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
|
||||||
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
|
" \"label\": <label> , (string, optional, default: '') Label to assign to the address, only allowed with internal=false\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,137 +0,0 @@
|
|||||||
// Copyright (c) 2012-2015 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/wallet.h>
|
|
||||||
#include <validation.h> // for cs_main because of AddToWallet
|
|
||||||
|
|
||||||
#include <wallet/test/wallet_test_fixture.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
|
|
||||||
|
|
||||||
static void
|
|
||||||
GetResults(CWallet& wallet, std::map<CAmount, CAccountingEntry>& results)
|
|
||||||
{
|
|
||||||
std::list<CAccountingEntry> aes;
|
|
||||||
|
|
||||||
results.clear();
|
|
||||||
BOOST_CHECK(wallet.ReorderTransactions() == DBErrors::LOAD_OK);
|
|
||||||
wallet.ListAccountCreditDebit("", aes);
|
|
||||||
for (CAccountingEntry& ae : aes)
|
|
||||||
{
|
|
||||||
results[ae.nOrderPos] = ae;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(acc_orderupgrade)
|
|
||||||
{
|
|
||||||
std::vector<CWalletTx*> vpwtx;
|
|
||||||
CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
|
|
||||||
CAccountingEntry ae;
|
|
||||||
std::map<CAmount, CAccountingEntry> results;
|
|
||||||
|
|
||||||
LOCK2(cs_main, m_wallet.cs_wallet);
|
|
||||||
|
|
||||||
ae.strAccount = "";
|
|
||||||
ae.nCreditDebit = 1;
|
|
||||||
ae.nTime = 1333333333;
|
|
||||||
ae.strOtherAccount = "b";
|
|
||||||
ae.strComment = "";
|
|
||||||
m_wallet.AddAccountingEntry(ae);
|
|
||||||
|
|
||||||
wtx.mapValue["comment"] = "z";
|
|
||||||
m_wallet.AddToWallet(wtx);
|
|
||||||
vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
|
|
||||||
vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
|
|
||||||
vpwtx[0]->nOrderPos = -1;
|
|
||||||
|
|
||||||
ae.nTime = 1333333336;
|
|
||||||
ae.strOtherAccount = "c";
|
|
||||||
m_wallet.AddAccountingEntry(ae);
|
|
||||||
|
|
||||||
GetResults(m_wallet, results);
|
|
||||||
|
|
||||||
BOOST_CHECK(m_wallet.nOrderPosNext == 3);
|
|
||||||
BOOST_CHECK(2 == results.size());
|
|
||||||
BOOST_CHECK(results[0].nTime == 1333333333);
|
|
||||||
BOOST_CHECK(results[0].strComment.empty());
|
|
||||||
BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
|
|
||||||
BOOST_CHECK(results[2].nTime == 1333333336);
|
|
||||||
BOOST_CHECK(results[2].strOtherAccount == "c");
|
|
||||||
|
|
||||||
|
|
||||||
ae.nTime = 1333333330;
|
|
||||||
ae.strOtherAccount = "d";
|
|
||||||
ae.nOrderPos = m_wallet.IncOrderPosNext();
|
|
||||||
m_wallet.AddAccountingEntry(ae);
|
|
||||||
|
|
||||||
GetResults(m_wallet, results);
|
|
||||||
|
|
||||||
BOOST_CHECK(results.size() == 3);
|
|
||||||
BOOST_CHECK(m_wallet.nOrderPosNext == 4);
|
|
||||||
BOOST_CHECK(results[0].nTime == 1333333333);
|
|
||||||
BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
|
|
||||||
BOOST_CHECK(results[2].nTime == 1333333336);
|
|
||||||
BOOST_CHECK(results[3].nTime == 1333333330);
|
|
||||||
BOOST_CHECK(results[3].strComment.empty());
|
|
||||||
|
|
||||||
|
|
||||||
wtx.mapValue["comment"] = "y";
|
|
||||||
{
|
|
||||||
CMutableTransaction tx(*wtx.tx);
|
|
||||||
++tx.nLockTime; // Just to change the hash :)
|
|
||||||
wtx.SetTx(MakeTransactionRef(std::move(tx)));
|
|
||||||
}
|
|
||||||
m_wallet.AddToWallet(wtx);
|
|
||||||
vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
|
|
||||||
vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
|
|
||||||
|
|
||||||
wtx.mapValue["comment"] = "x";
|
|
||||||
{
|
|
||||||
CMutableTransaction tx(*wtx.tx);
|
|
||||||
++tx.nLockTime; // Just to change the hash :)
|
|
||||||
wtx.SetTx(MakeTransactionRef(std::move(tx)));
|
|
||||||
}
|
|
||||||
m_wallet.AddToWallet(wtx);
|
|
||||||
vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
|
|
||||||
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
|
|
||||||
vpwtx[2]->nOrderPos = -1;
|
|
||||||
|
|
||||||
GetResults(m_wallet, results);
|
|
||||||
|
|
||||||
BOOST_CHECK(results.size() == 3);
|
|
||||||
BOOST_CHECK(m_wallet.nOrderPosNext == 6);
|
|
||||||
BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
|
|
||||||
BOOST_CHECK(results[1].nTime == 1333333333);
|
|
||||||
BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
|
|
||||||
BOOST_CHECK(results[3].nTime == 1333333336);
|
|
||||||
BOOST_CHECK(results[4].nTime == 1333333330);
|
|
||||||
BOOST_CHECK(results[4].strComment.empty());
|
|
||||||
BOOST_CHECK(5 == vpwtx[1]->nOrderPos);
|
|
||||||
|
|
||||||
|
|
||||||
ae.nTime = 1333333334;
|
|
||||||
ae.strOtherAccount = "e";
|
|
||||||
ae.nOrderPos = -1;
|
|
||||||
m_wallet.AddAccountingEntry(ae);
|
|
||||||
|
|
||||||
GetResults(m_wallet, results);
|
|
||||||
|
|
||||||
BOOST_CHECK(results.size() == 4);
|
|
||||||
BOOST_CHECK(m_wallet.nOrderPosNext == 7);
|
|
||||||
BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
|
|
||||||
BOOST_CHECK(results[1].nTime == 1333333333);
|
|
||||||
BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
|
|
||||||
BOOST_CHECK(results[3].nTime == 1333333336);
|
|
||||||
BOOST_CHECK(results[3].strComment.empty());
|
|
||||||
BOOST_CHECK(results[4].nTime == 1333333330);
|
|
||||||
BOOST_CHECK(results[4].strComment.empty());
|
|
||||||
BOOST_CHECK(results[5].nTime == 1333333334);
|
|
||||||
BOOST_CHECK(6 == vpwtx[1]->nOrderPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -89,7 +89,7 @@ public:
|
|||||||
for (CAmount nAmount : vecAmounts) {
|
for (CAmount nAmount : vecAmounts) {
|
||||||
BOOST_CHECK(wallet->CreateTransaction({{GetScriptForDestination(tallyItem.txdest), nAmount, false}}, tx, reserveKey, nFeeRet, nChangePosRet, strError, coinControl));
|
BOOST_CHECK(wallet->CreateTransaction({{GetScriptForDestination(tallyItem.txdest), nAmount, false}}, tx, reserveKey, nFeeRet, nChangePosRet, strError, coinControl));
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, {}, reserveKey, nullptr, state));
|
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reserveKey, nullptr, state));
|
||||||
AddTxToChain(tx->GetHash());
|
AddTxToChain(tx->GetHash());
|
||||||
for (size_t n = 0; n < tx->vout.size(); ++n) {
|
for (size_t n = 0; n < tx->vout.size(); ++n) {
|
||||||
if (nChangePosRet != -1 && n == nChangePosRet) {
|
if (nChangePosRet != -1 && n == nChangePosRet) {
|
||||||
|
@ -310,7 +310,7 @@ public:
|
|||||||
CCoinControl dummy;
|
CCoinControl dummy;
|
||||||
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy));
|
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy));
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, {}, reservekey, nullptr, state));
|
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, nullptr, state));
|
||||||
CMutableTransaction blocktx;
|
CMutableTransaction blocktx;
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
@ -512,7 +512,7 @@ public:
|
|||||||
CCoinControl coinControl;
|
CCoinControl coinControl;
|
||||||
BOOST_CHECK(wallet->CreateTransaction(GetRecipients(vecEntries), tx, reserveKey, nFeeRet, nChangePosRet, strError, coinControl));
|
BOOST_CHECK(wallet->CreateTransaction(GetRecipients(vecEntries), tx, reserveKey, nFeeRet, nChangePosRet, strError, coinControl));
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, {}, reserveKey, nullptr, state));
|
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reserveKey, nullptr, state));
|
||||||
CMutableTransaction blocktx;
|
CMutableTransaction blocktx;
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
@ -853,7 +853,7 @@ BOOST_FIXTURE_TEST_CASE(select_coins_grouped_by_addresses, ListCoinsTestingSetup
|
|||||||
BOOST_CHECK(wallet->CreateTransaction({CRecipient{GetScriptForRawPubKey({}), 1 * COIN, true /* subtract fee */}},
|
BOOST_CHECK(wallet->CreateTransaction({CRecipient{GetScriptForRawPubKey({}), 1 * COIN, true /* subtract fee */}},
|
||||||
tx2, reservekey2, fee, changePos, error, dummy));
|
tx2, reservekey2, fee, changePos, error, dummy));
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
BOOST_CHECK(wallet->CommitTransaction(tx1, {}, {}, {}, reservekey1, nullptr, state));
|
BOOST_CHECK(wallet->CommitTransaction(tx1, {}, {}, reservekey1, nullptr, state));
|
||||||
reservekey2.KeepKey();
|
reservekey2.KeepKey();
|
||||||
BOOST_CHECK_EQUAL(wallet->GetAvailableBalance(), 0);
|
BOOST_CHECK_EQUAL(wallet->GetAvailableBalance(), 0);
|
||||||
CreateAndProcessBlock({CMutableTransaction(*tx2)}, GetScriptForRawPubKey({}));
|
CreateAndProcessBlock({CMutableTransaction(*tx2)}, GetScriptForRawPubKey({}));
|
||||||
|
@ -776,7 +776,6 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
|
|||||||
// nTimeReceived not copied on purpose
|
// nTimeReceived not copied on purpose
|
||||||
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
||||||
copyTo->fFromMe = copyFrom->fFromMe;
|
copyTo->fFromMe = copyFrom->fFromMe;
|
||||||
copyTo->strFromAccount = copyFrom->strFromAccount;
|
|
||||||
// nOrderPos not copied on purpose
|
// nOrderPos not copied on purpose
|
||||||
// cached members not copied on purpose
|
// cached members not copied on purpose
|
||||||
}
|
}
|
||||||
@ -968,44 +967,30 @@ DBErrors CWallet::ReorderTransactions()
|
|||||||
// Old wallets didn't have any defined order for transactions
|
// Old wallets didn't have any defined order for transactions
|
||||||
// Probably a bad idea to change the output of this
|
// Probably a bad idea to change the output of this
|
||||||
|
|
||||||
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
|
// First: get all CWalletTx into a sorted-by-time multimap.
|
||||||
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
|
typedef std::multimap<int64_t, CWalletTx*> TxItems;
|
||||||
typedef std::multimap<int64_t, TxPair > TxItems;
|
|
||||||
TxItems txByTime;
|
TxItems txByTime;
|
||||||
|
|
||||||
for (auto& entry : mapWallet)
|
for (auto& entry : mapWallet)
|
||||||
{
|
{
|
||||||
CWalletTx* wtx = &entry.second;
|
CWalletTx* wtx = &entry.second;
|
||||||
txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr)));
|
txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx));
|
||||||
}
|
|
||||||
std::list<CAccountingEntry> acentries;
|
|
||||||
batch.ListAccountCreditDebit("", acentries);
|
|
||||||
for (CAccountingEntry& entry : acentries)
|
|
||||||
{
|
|
||||||
txByTime.insert(std::make_pair(entry.nTime, TxPair(nullptr, &entry)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nOrderPosNext = 0;
|
nOrderPosNext = 0;
|
||||||
std::vector<int64_t> nOrderPosOffsets;
|
std::vector<int64_t> nOrderPosOffsets;
|
||||||
for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
|
for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
|
||||||
{
|
{
|
||||||
CWalletTx *const pwtx = (*it).second.first;
|
CWalletTx *const pwtx = (*it).second;
|
||||||
CAccountingEntry *const pacentry = (*it).second.second;
|
int64_t& nOrderPos = pwtx->nOrderPos;
|
||||||
int64_t& nOrderPos = (pwtx != nullptr) ? pwtx->nOrderPos : pacentry->nOrderPos;
|
|
||||||
|
|
||||||
if (nOrderPos == -1)
|
if (nOrderPos == -1)
|
||||||
{
|
{
|
||||||
nOrderPos = nOrderPosNext++;
|
nOrderPos = nOrderPosNext++;
|
||||||
nOrderPosOffsets.push_back(nOrderPos);
|
nOrderPosOffsets.push_back(nOrderPos);
|
||||||
|
|
||||||
if (pwtx)
|
if (!batch.WriteTx(*pwtx))
|
||||||
{
|
return DBErrors::LOAD_FAIL;
|
||||||
if (!batch.WriteTx(*pwtx))
|
|
||||||
return DBErrors::LOAD_FAIL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!batch.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
|
|
||||||
return DBErrors::LOAD_FAIL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1022,14 +1007,8 @@ DBErrors CWallet::ReorderTransactions()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Since we're changing the order, write it back
|
// Since we're changing the order, write it back
|
||||||
if (pwtx)
|
if (!batch.WriteTx(*pwtx))
|
||||||
{
|
return DBErrors::LOAD_FAIL;
|
||||||
if (!batch.WriteTx(*pwtx))
|
|
||||||
return DBErrors::LOAD_FAIL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!batch.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
|
|
||||||
return DBErrors::LOAD_FAIL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch.WriteOrderPosNext(nOrderPosNext);
|
batch.WriteOrderPosNext(nOrderPosNext);
|
||||||
@ -1049,81 +1028,6 @@ int64_t CWallet::IncOrderPosNext(WalletBatch *batch)
|
|||||||
return nRet;
|
return nRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment)
|
|
||||||
{
|
|
||||||
WalletBatch batch(*database);
|
|
||||||
if (!batch.TxnBegin())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int64_t nNow = GetAdjustedTime();
|
|
||||||
|
|
||||||
// Debit
|
|
||||||
CAccountingEntry debit;
|
|
||||||
debit.nOrderPos = IncOrderPosNext(&batch);
|
|
||||||
debit.strAccount = strFrom;
|
|
||||||
debit.nCreditDebit = -nAmount;
|
|
||||||
debit.nTime = nNow;
|
|
||||||
debit.strOtherAccount = strTo;
|
|
||||||
debit.strComment = strComment;
|
|
||||||
AddAccountingEntry(debit, &batch);
|
|
||||||
|
|
||||||
// Credit
|
|
||||||
CAccountingEntry credit;
|
|
||||||
credit.nOrderPos = IncOrderPosNext(&batch);
|
|
||||||
credit.strAccount = strTo;
|
|
||||||
credit.nCreditDebit = nAmount;
|
|
||||||
credit.nTime = nNow;
|
|
||||||
credit.strOtherAccount = strFrom;
|
|
||||||
credit.strComment = strComment;
|
|
||||||
AddAccountingEntry(credit, &batch);
|
|
||||||
|
|
||||||
if (!batch.TxnCommit())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CWallet::GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew)
|
|
||||||
{
|
|
||||||
AssertLockHeld(cs_wallet);
|
|
||||||
|
|
||||||
WalletBatch batch(*database);
|
|
||||||
|
|
||||||
CAccount account;
|
|
||||||
batch.ReadAccount(label, account);
|
|
||||||
|
|
||||||
if (!bForceNew) {
|
|
||||||
if (!account.vchPubKey.IsValid())
|
|
||||||
bForceNew = true;
|
|
||||||
else {
|
|
||||||
// Check if the current key has been used
|
|
||||||
CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
|
|
||||||
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin();
|
|
||||||
it != mapWallet.end() && account.vchPubKey.IsValid();
|
|
||||||
++it)
|
|
||||||
for (const CTxOut& txout : (*it).second.tx->vout)
|
|
||||||
if (txout.scriptPubKey == scriptPubKey) {
|
|
||||||
bForceNew = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a new key
|
|
||||||
if (bForceNew) {
|
|
||||||
if (!GetKeyFromPool(account.vchPubKey, false))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dest = account.vchPubKey.GetID();
|
|
||||||
SetAddressBook(dest, label, "receive");
|
|
||||||
batch.WriteAccount(label, account);
|
|
||||||
} else {
|
|
||||||
dest = account.vchPubKey.GetID();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CWallet::MarkDirty()
|
void CWallet::MarkDirty()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -1153,7 +1057,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
|
|||||||
if (fInsertedNew) {
|
if (fInsertedNew) {
|
||||||
wtx.nTimeReceived = GetAdjustedTime();
|
wtx.nTimeReceived = GetAdjustedTime();
|
||||||
wtx.nOrderPos = IncOrderPosNext(&batch);
|
wtx.nOrderPos = IncOrderPosNext(&batch);
|
||||||
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
|
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
|
||||||
wtx.nTimeSmart = ComputeTimeSmart(wtx);
|
wtx.nTimeSmart = ComputeTimeSmart(wtx);
|
||||||
AddToSpends(hash);
|
AddToSpends(hash);
|
||||||
|
|
||||||
@ -1243,7 +1147,7 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn)
|
|||||||
CWalletTx& wtx = ins.first->second;
|
CWalletTx& wtx = ins.first->second;
|
||||||
wtx.BindWallet(this);
|
wtx.BindWallet(this);
|
||||||
if (/* insertion took place */ ins.second) {
|
if (/* insertion took place */ ins.second) {
|
||||||
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
|
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
|
||||||
}
|
}
|
||||||
AddToSpends(hash);
|
AddToSpends(hash);
|
||||||
for (const CTxIn& txin : wtx.tx->vin) {
|
for (const CTxIn& txin : wtx.tx->vin) {
|
||||||
@ -2134,12 +2038,11 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
||||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
|
std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
nFee = 0;
|
nFee = 0;
|
||||||
listReceived.clear();
|
listReceived.clear();
|
||||||
listSent.clear();
|
listSent.clear();
|
||||||
strSentAccount = strFromAccount;
|
|
||||||
|
|
||||||
// Compute fee:
|
// Compute fee:
|
||||||
CAmount nDebit = GetDebit(filter);
|
CAmount nDebit = GetDebit(filter);
|
||||||
@ -2920,7 +2823,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
|
|||||||
// wallet, and then subtracts the values of TxIns spending from the wallet. This
|
// wallet, and then subtracts the values of TxIns spending from the wallet. This
|
||||||
// also has fewer restrictions on which unconfirmed transactions are considered
|
// also has fewer restrictions on which unconfirmed transactions are considered
|
||||||
// trusted.
|
// trusted.
|
||||||
CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account, const bool fAddLocked) const
|
CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const bool fAddLocked) const
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, cs_wallet);
|
LOCK2(cs_main, cs_wallet);
|
||||||
|
|
||||||
@ -2939,21 +2842,17 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons
|
|||||||
for (const CTxOut& out : wtx.tx->vout) {
|
for (const CTxOut& out : wtx.tx->vout) {
|
||||||
if (outgoing && IsChange(out)) {
|
if (outgoing && IsChange(out)) {
|
||||||
debit -= out.nValue;
|
debit -= out.nValue;
|
||||||
} else if (IsMine(out) & filter && (depth >= minDepth || (fAddLocked && wtx.IsLockedByInstantSend())) && (!account || *account == GetLabelName(out.scriptPubKey))) {
|
} else if (IsMine(out) & filter && (depth >= minDepth || (fAddLocked && wtx.IsLockedByInstantSend()))) {
|
||||||
balance += out.nValue;
|
balance += out.nValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For outgoing txs, subtract amount debited.
|
// For outgoing txs, subtract amount debited.
|
||||||
if (outgoing && (!account || *account == wtx.strFromAccount)) {
|
if (outgoing) {
|
||||||
balance -= debit;
|
balance -= debit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account) {
|
|
||||||
balance += WalletBatch(*database).GetAccountCreditDebit(*account);
|
|
||||||
}
|
|
||||||
|
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4016,7 +3915,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
|
|||||||
/**
|
/**
|
||||||
* Call after CreateTransaction unless you want to abort
|
* Call after CreateTransaction unless you want to abort
|
||||||
*/
|
*/
|
||||||
bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state)
|
bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, mempool.cs);
|
LOCK2(cs_main, mempool.cs);
|
||||||
@ -4025,7 +3924,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
|
|||||||
CWalletTx wtxNew(this, std::move(tx));
|
CWalletTx wtxNew(this, std::move(tx));
|
||||||
wtxNew.mapValue = std::move(mapValue);
|
wtxNew.mapValue = std::move(mapValue);
|
||||||
wtxNew.vOrderForm = std::move(orderForm);
|
wtxNew.vOrderForm = std::move(orderForm);
|
||||||
wtxNew.strFromAccount = std::move(fromAccount);
|
|
||||||
wtxNew.fTimeReceivedIsTxTime = true;
|
wtxNew.fTimeReceivedIsTxTime = true;
|
||||||
wtxNew.fFromMe = true;
|
wtxNew.fFromMe = true;
|
||||||
|
|
||||||
@ -4070,31 +3968,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {
|
|
||||||
WalletBatch batch(*database);
|
|
||||||
return batch.ListAccountCreditDebit(strAccount, entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)
|
|
||||||
{
|
|
||||||
WalletBatch batch(*database);
|
|
||||||
|
|
||||||
return AddAccountingEntry(acentry, &batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, WalletBatch *batch)
|
|
||||||
{
|
|
||||||
if (!batch->WriteAccountingEntry(++nAccountingEntryNumber, acentry)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
laccentries.push_back(acentry);
|
|
||||||
CAccountingEntry & entry = laccentries.back();
|
|
||||||
wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair(nullptr, &entry)));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, cs_wallet);
|
LOCK2(cs_main, cs_wallet);
|
||||||
@ -4675,12 +4548,6 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::DeleteLabel(const std::string& label)
|
|
||||||
{
|
|
||||||
WalletBatch batch(*database);
|
|
||||||
batch.EraseAccount(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool fInternalIn)
|
bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool fInternalIn)
|
||||||
{
|
{
|
||||||
if (nIndex == -1)
|
if (nIndex == -1)
|
||||||
@ -4897,19 +4764,14 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
|
|||||||
int64_t latestTolerated = latestNow + 300;
|
int64_t latestTolerated = latestNow + 300;
|
||||||
const TxItems& txOrdered = wtxOrdered;
|
const TxItems& txOrdered = wtxOrdered;
|
||||||
for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
|
for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
|
||||||
CWalletTx* const pwtx = it->second.first;
|
CWalletTx* const pwtx = it->second;
|
||||||
if (pwtx == &wtx) {
|
if (pwtx == &wtx) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CAccountingEntry* const pacentry = it->second.second;
|
|
||||||
int64_t nSmartTime;
|
int64_t nSmartTime;
|
||||||
if (pwtx) {
|
nSmartTime = pwtx->nTimeSmart;
|
||||||
nSmartTime = pwtx->nTimeSmart;
|
if (!nSmartTime) {
|
||||||
if (!nSmartTime) {
|
nSmartTime = pwtx->nTimeReceived;
|
||||||
nSmartTime = pwtx->nTimeReceived;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nSmartTime = pacentry->nTime;
|
|
||||||
}
|
}
|
||||||
if (nSmartTime <= latestTolerated) {
|
if (nSmartTime <= latestTolerated) {
|
||||||
latestEntry = nSmartTime;
|
latestEntry = nSmartTime;
|
||||||
@ -5339,7 +5201,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const WalletLocation& loc
|
|||||||
copyTo->nTimeReceived = copyFrom->nTimeReceived;
|
copyTo->nTimeReceived = copyFrom->nTimeReceived;
|
||||||
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
||||||
copyTo->fFromMe = copyFrom->fFromMe;
|
copyTo->fFromMe = copyFrom->fFromMe;
|
||||||
copyTo->strFromAccount = copyFrom->strFromAccount;
|
|
||||||
copyTo->nOrderPos = copyFrom->nOrderPos;
|
copyTo->nOrderPos = copyFrom->nOrderPos;
|
||||||
batch.WriteTx(*copyTo);
|
batch.WriteTx(*copyTo);
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ public:
|
|||||||
* serialized in the wallet database:
|
* serialized in the wallet database:
|
||||||
*
|
*
|
||||||
* "comment", "to" - comment strings provided to sendtoaddress,
|
* "comment", "to" - comment strings provided to sendtoaddress,
|
||||||
* sendfrom, sendmany wallet RPCs
|
* and sendmany wallet RPCs
|
||||||
* "replaces_txid" - txid (as HexStr) of transaction replaced by
|
* "replaces_txid" - txid (as HexStr) of transaction replaced by
|
||||||
* bumpfee on transaction created by bumpfee
|
* bumpfee on transaction created by bumpfee
|
||||||
* "replaced_by_txid" - txid (as HexStr) of transaction created by
|
* "replaced_by_txid" - txid (as HexStr) of transaction created by
|
||||||
@ -347,9 +347,8 @@ public:
|
|||||||
* externally and came in through the network or sendrawtransaction RPC.
|
* externally and came in through the network or sendrawtransaction RPC.
|
||||||
*/
|
*/
|
||||||
char fFromMe;
|
char fFromMe;
|
||||||
std::string strFromAccount;
|
|
||||||
int64_t nOrderPos; //!< position in ordered transaction list
|
int64_t nOrderPos; //!< position in ordered transaction list
|
||||||
std::multimap<int64_t, std::pair<CWalletTx*, CAccountingEntry*>>::const_iterator m_it_wtxOrdered;
|
std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
|
||||||
|
|
||||||
// memory only
|
// memory only
|
||||||
mutable bool fDebitCached;
|
mutable bool fDebitCached;
|
||||||
@ -392,7 +391,6 @@ public:
|
|||||||
nTimeReceived = 0;
|
nTimeReceived = 0;
|
||||||
nTimeSmart = 0;
|
nTimeSmart = 0;
|
||||||
fFromMe = false;
|
fFromMe = false;
|
||||||
strFromAccount.clear();
|
|
||||||
fDebitCached = false;
|
fDebitCached = false;
|
||||||
fCreditCached = false;
|
fCreditCached = false;
|
||||||
fImmatureCreditCached = false;
|
fImmatureCreditCached = false;
|
||||||
@ -427,7 +425,7 @@ public:
|
|||||||
char fSpent = false;
|
char fSpent = false;
|
||||||
mapValue_t mapValueCopy = mapValue;
|
mapValue_t mapValueCopy = mapValue;
|
||||||
|
|
||||||
mapValueCopy["fromaccount"] = strFromAccount;
|
mapValueCopy["fromaccount"] = "";
|
||||||
WriteOrderPos(nOrderPos, mapValueCopy);
|
WriteOrderPos(nOrderPos, mapValueCopy);
|
||||||
if (nTimeSmart) {
|
if (nTimeSmart) {
|
||||||
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
|
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
|
||||||
@ -448,7 +446,6 @@ public:
|
|||||||
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
|
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
|
||||||
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;
|
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;
|
||||||
|
|
||||||
strFromAccount = std::move(mapValue["fromaccount"]);
|
|
||||||
ReadOrderPos(nOrderPos, mapValue);
|
ReadOrderPos(nOrderPos, mapValue);
|
||||||
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
|
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
|
||||||
|
|
||||||
@ -508,7 +505,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GetAmounts(std::list<COutputEntry>& listReceived,
|
void GetAmounts(std::list<COutputEntry>& listReceived,
|
||||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
|
std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const;
|
||||||
|
|
||||||
bool IsFromMe(const isminefilter& filter) const
|
bool IsFromMe(const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
@ -623,89 +620,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED Internal transfers.
|
|
||||||
* Database key is acentry<account><counter>.
|
|
||||||
*/
|
|
||||||
class CAccountingEntry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string strAccount;
|
|
||||||
CAmount nCreditDebit;
|
|
||||||
int64_t nTime;
|
|
||||||
std::string strOtherAccount;
|
|
||||||
std::string strComment;
|
|
||||||
mapValue_t mapValue;
|
|
||||||
int64_t nOrderPos; //!< position in ordered transaction list
|
|
||||||
uint64_t nEntryNo;
|
|
||||||
|
|
||||||
CAccountingEntry()
|
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNull()
|
|
||||||
{
|
|
||||||
nCreditDebit = 0;
|
|
||||||
nTime = 0;
|
|
||||||
strAccount.clear();
|
|
||||||
strOtherAccount.clear();
|
|
||||||
strComment.clear();
|
|
||||||
nOrderPos = -1;
|
|
||||||
nEntryNo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Stream>
|
|
||||||
void Serialize(Stream& s) const {
|
|
||||||
int nVersion = s.GetVersion();
|
|
||||||
if (!(s.GetType() & SER_GETHASH)) {
|
|
||||||
s << nVersion;
|
|
||||||
}
|
|
||||||
//! Note: strAccount is serialized as part of the key, not here.
|
|
||||||
s << nCreditDebit << nTime << strOtherAccount;
|
|
||||||
|
|
||||||
mapValue_t mapValueCopy = mapValue;
|
|
||||||
WriteOrderPos(nOrderPos, mapValueCopy);
|
|
||||||
|
|
||||||
std::string strCommentCopy = strComment;
|
|
||||||
if (!mapValueCopy.empty() || !_ssExtra.empty()) {
|
|
||||||
CDataStream ss(s.GetType(), s.GetVersion());
|
|
||||||
ss.insert(ss.begin(), '\0');
|
|
||||||
ss << mapValueCopy;
|
|
||||||
ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
|
|
||||||
strCommentCopy.append(ss.str());
|
|
||||||
}
|
|
||||||
s << strCommentCopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Stream>
|
|
||||||
void Unserialize(Stream& s) {
|
|
||||||
int nVersion = s.GetVersion();
|
|
||||||
if (!(s.GetType() & SER_GETHASH)) {
|
|
||||||
s >> nVersion;
|
|
||||||
}
|
|
||||||
//! Note: strAccount is serialized as part of the key, not here.
|
|
||||||
s >> nCreditDebit >> nTime >> LIMITED_STRING(strOtherAccount, 65536) >> LIMITED_STRING(strComment, 65536);
|
|
||||||
|
|
||||||
size_t nSepPos = strComment.find("\0", 0, 1);
|
|
||||||
mapValue.clear();
|
|
||||||
if (std::string::npos != nSepPos) {
|
|
||||||
CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion());
|
|
||||||
ss >> mapValue;
|
|
||||||
_ssExtra = std::vector<char>(ss.begin(), ss.end());
|
|
||||||
}
|
|
||||||
ReadOrderPos(nOrderPos, mapValue);
|
|
||||||
if (std::string::npos != nSepPos) {
|
|
||||||
strComment.erase(nSepPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
mapValue.erase("n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<char> _ssExtra;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CoinSelectionParams
|
struct CoinSelectionParams
|
||||||
{
|
{
|
||||||
bool use_bnb = true;
|
bool use_bnb = true;
|
||||||
@ -905,10 +819,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
|
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
|
||||||
std::list<CAccountingEntry> laccentries;
|
|
||||||
|
|
||||||
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
|
typedef std::multimap<int64_t, CWalletTx*> TxItems;
|
||||||
typedef std::multimap<int64_t, TxPair > TxItems;
|
|
||||||
TxItems wtxOrdered;
|
TxItems wtxOrdered;
|
||||||
|
|
||||||
int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
|
int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
|
||||||
@ -1055,8 +967,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
int64_t IncOrderPosNext(WalletBatch *batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
int64_t IncOrderPosNext(WalletBatch *batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
DBErrors ReorderTransactions();
|
DBErrors ReorderTransactions();
|
||||||
bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = "") EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
|
||||||
bool GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew = false);
|
|
||||||
|
|
||||||
void MarkDirty();
|
void MarkDirty();
|
||||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
||||||
@ -1082,7 +992,7 @@ public:
|
|||||||
CAmount GetImmatureBalance() const;
|
CAmount GetImmatureBalance() const;
|
||||||
CAmount GetUnconfirmedWatchOnlyBalance() const;
|
CAmount GetUnconfirmedWatchOnlyBalance() const;
|
||||||
CAmount GetImmatureWatchOnlyBalance() const;
|
CAmount GetImmatureWatchOnlyBalance() const;
|
||||||
CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account, const bool fAddLocked) const;
|
CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const bool fAddLocked) const;
|
||||||
|
|
||||||
CAmount GetAnonymizableBalance(bool fSkipDenominated = false, bool fSkipUnconfirmed = true) const;
|
CAmount GetAnonymizableBalance(bool fSkipDenominated = false, bool fSkipUnconfirmed = true) const;
|
||||||
CAmount GetAnonymizedBalance(const CCoinControl* coinControl = nullptr) const;
|
CAmount GetAnonymizedBalance(const CCoinControl* coinControl = nullptr) const;
|
||||||
@ -1107,11 +1017,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
|
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
|
||||||
std::string& strFailReason, const CCoinControl& coin_control, bool sign = true, int nExtraPayloadSize = 0);
|
std::string& strFailReason, const CCoinControl& coin_control, bool sign = true, int nExtraPayloadSize = 0);
|
||||||
bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
|
bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
|
||||||
|
|
||||||
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
|
|
||||||
bool AddAccountingEntry(const CAccountingEntry&);
|
|
||||||
bool AddAccountingEntry(const CAccountingEntry&, WalletBatch *batch);
|
|
||||||
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());
|
||||||
@ -1168,7 +1075,6 @@ public:
|
|||||||
std::map<CTxDestination, CAmount> GetAddressBalances() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
std::map<CTxDestination, CAmount> GetAddressBalances() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
|
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
|
||||||
void DeleteLabel(const std::string& label);
|
|
||||||
|
|
||||||
isminetype IsMine(const CTxIn& txin) const;
|
isminetype IsMine(const CTxIn& txin) const;
|
||||||
/**
|
/**
|
||||||
@ -1383,36 +1289,6 @@ public:
|
|||||||
void KeepScript() override { KeepKey(); }
|
void KeepScript() override { KeepKey(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED Account information.
|
|
||||||
* Stored in wallet with key "acc"+string account name.
|
|
||||||
*/
|
|
||||||
class CAccount
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CPubKey vchPubKey;
|
|
||||||
|
|
||||||
CAccount()
|
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNull()
|
|
||||||
{
|
|
||||||
vchPubKey = CPubKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
SERIALIZE_METHODS(CAccount, obj)
|
|
||||||
{
|
|
||||||
int nVersion = s.GetVersion();
|
|
||||||
if (!(s.GetType() & SER_GETHASH))
|
|
||||||
READWRITE(nVersion);
|
|
||||||
READWRITE(obj.vchPubKey);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** RAII object to check and reserve a wallet rescan */
|
/** RAII object to check and reserve a wallet rescan */
|
||||||
class WalletRescanReserver
|
class WalletRescanReserver
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
//
|
//
|
||||||
// WalletBatch
|
// WalletBatch
|
||||||
@ -156,27 +157,6 @@ bool WalletBatch::WriteMinVersion(int nVersion)
|
|||||||
return WriteIC(std::string("minversion"), nVersion);
|
return WriteIC(std::string("minversion"), nVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletBatch::ReadAccount(const std::string& strAccount, CAccount& account)
|
|
||||||
{
|
|
||||||
account.SetNull();
|
|
||||||
return m_batch.Read(std::make_pair(std::string("acc"), strAccount), account);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletBatch::WriteAccount(const std::string& strAccount, const CAccount& account)
|
|
||||||
{
|
|
||||||
return WriteIC(std::make_pair(std::string("acc"), strAccount), account);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletBatch::EraseAccount(const std::string& strAccount)
|
|
||||||
{
|
|
||||||
return EraseIC(std::make_pair(std::string("acc"), strAccount));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletBatch::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
|
|
||||||
{
|
|
||||||
return WriteIC(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletBatch::ReadCoinJoinSalt(uint256& salt, bool fLegacy)
|
bool WalletBatch::ReadCoinJoinSalt(uint256& salt, bool fLegacy)
|
||||||
{
|
{
|
||||||
// TODO: Remove legacy checks after few major releases
|
// TODO: Remove legacy checks after few major releases
|
||||||
@ -193,60 +173,6 @@ bool WalletBatch::WriteGovernanceObject(const CGovernanceObject& obj)
|
|||||||
return WriteIC(std::make_pair(std::string("gobject"), obj.GetHash()), obj, false);
|
return WriteIC(std::make_pair(std::string("gobject"), obj.GetHash()), obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount WalletBatch::GetAccountCreditDebit(const std::string& strAccount)
|
|
||||||
{
|
|
||||||
std::list<CAccountingEntry> entries;
|
|
||||||
ListAccountCreditDebit(strAccount, entries);
|
|
||||||
|
|
||||||
CAmount nCreditDebit = 0;
|
|
||||||
for (const CAccountingEntry& entry : entries)
|
|
||||||
nCreditDebit += entry.nCreditDebit;
|
|
||||||
|
|
||||||
return nCreditDebit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletBatch::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
|
|
||||||
{
|
|
||||||
bool fAllAccounts = (strAccount == "*");
|
|
||||||
|
|
||||||
Dbc* pcursor = m_batch.GetCursor();
|
|
||||||
if (!pcursor)
|
|
||||||
throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
|
|
||||||
bool setRange = true;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
// Read next record
|
|
||||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
|
||||||
if (setRange)
|
|
||||||
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
|
|
||||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
|
||||||
int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
|
|
||||||
setRange = false;
|
|
||||||
if (ret == DB_NOTFOUND)
|
|
||||||
break;
|
|
||||||
else if (ret != 0)
|
|
||||||
{
|
|
||||||
pcursor->close();
|
|
||||||
throw std::runtime_error(std::string(__func__) + ": error scanning DB");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unserialize
|
|
||||||
std::string strType;
|
|
||||||
ssKey >> strType;
|
|
||||||
if (strType != "acentry")
|
|
||||||
break;
|
|
||||||
CAccountingEntry acentry;
|
|
||||||
ssKey >> acentry.strAccount;
|
|
||||||
if (!fAllAccounts && acentry.strAccount != strAccount)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ssValue >> acentry;
|
|
||||||
ssKey >> acentry.nEntryNo;
|
|
||||||
entries.push_back(acentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
pcursor->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
class CWalletScanState {
|
class CWalletScanState {
|
||||||
public:
|
public:
|
||||||
@ -303,9 +229,10 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
{
|
{
|
||||||
char fTmp;
|
char fTmp;
|
||||||
char fUnused;
|
char fUnused;
|
||||||
ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
|
std::string unused_string;
|
||||||
strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
|
ssValue >> fTmp >> fUnused >> unused_string;
|
||||||
wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
|
strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
|
||||||
|
wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
|
||||||
wtx.fTimeReceivedIsTxTime = fTmp;
|
wtx.fTimeReceivedIsTxTime = fTmp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -321,24 +248,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
|
|
||||||
pwallet->LoadToWallet(wtx);
|
pwallet->LoadToWallet(wtx);
|
||||||
}
|
}
|
||||||
else if (strType == "acentry")
|
|
||||||
{
|
|
||||||
std::string strAccount;
|
|
||||||
ssKey >> strAccount;
|
|
||||||
uint64_t nNumber;
|
|
||||||
ssKey >> nNumber;
|
|
||||||
if (nNumber > pwallet->nAccountingEntryNumber) {
|
|
||||||
pwallet->nAccountingEntryNumber = nNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wss.fAnyUnordered)
|
|
||||||
{
|
|
||||||
CAccountingEntry acentry;
|
|
||||||
ssValue >> acentry;
|
|
||||||
if (acentry.nOrderPos == -1)
|
|
||||||
wss.fAnyUnordered = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strType == "watchs")
|
else if (strType == "watchs")
|
||||||
{
|
{
|
||||||
wss.nWatchKeys++;
|
wss.nWatchKeys++;
|
||||||
@ -578,7 +487,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strType != "bestblock" && strType != "bestblock_nomerkle" &&
|
else if (strType != "bestblock" && strType != "bestblock_nomerkle" &&
|
||||||
strType != "minversion"){
|
strType != "minversion" && strType != "acentry"){
|
||||||
wss.m_unknown_records++;
|
wss.m_unknown_records++;
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@ -702,12 +611,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
|
|||||||
if (wss.fAnyUnordered)
|
if (wss.fAnyUnordered)
|
||||||
result = pwallet->ReorderTransactions();
|
result = pwallet->ReorderTransactions();
|
||||||
|
|
||||||
pwallet->laccentries.clear();
|
|
||||||
ListAccountCreditDebit("*", pwallet->laccentries);
|
|
||||||
for (CAccountingEntry& entry : pwallet->laccentries) {
|
|
||||||
pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
static const bool DEFAULT_FLUSHWALLET = true;
|
static const bool DEFAULT_FLUSHWALLET = true;
|
||||||
|
|
||||||
class CAccount;
|
|
||||||
class CAccountingEntry;
|
|
||||||
struct CBlockLocator;
|
struct CBlockLocator;
|
||||||
class CGovernanceObject;
|
class CGovernanceObject;
|
||||||
class CKeyPool;
|
class CKeyPool;
|
||||||
@ -154,13 +152,6 @@ public:
|
|||||||
|
|
||||||
bool WriteMinVersion(int nVersion);
|
bool WriteMinVersion(int nVersion);
|
||||||
|
|
||||||
/// This writes directly to the database, and will not update the CWallet's cached accounting entries!
|
|
||||||
/// Use wallet.AddAccountingEntry instead, to write *and* update its caches.
|
|
||||||
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
|
|
||||||
bool ReadAccount(const std::string& strAccount, CAccount& account);
|
|
||||||
bool WriteAccount(const std::string& strAccount, const CAccount& account);
|
|
||||||
bool EraseAccount(const std::string& strAccount);
|
|
||||||
|
|
||||||
bool ReadCoinJoinSalt(uint256& salt, bool fLegacy = false);
|
bool ReadCoinJoinSalt(uint256& salt, bool fLegacy = false);
|
||||||
bool WriteCoinJoinSalt(const uint256& salt);
|
bool WriteCoinJoinSalt(const uint256& salt);
|
||||||
|
|
||||||
@ -172,9 +163,6 @@ public:
|
|||||||
/// Erase destination data tuple from wallet database
|
/// Erase destination data tuple from wallet database
|
||||||
bool EraseDestData(const std::string &address, const std::string &key);
|
bool EraseDestData(const std::string &address, const std::string &key);
|
||||||
|
|
||||||
CAmount GetAccountCreditDebit(const std::string& strAccount);
|
|
||||||
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
|
|
||||||
|
|
||||||
DBErrors LoadWallet(CWallet* pwallet);
|
DBErrors LoadWallet(CWallet* pwallet);
|
||||||
DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
|
DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
|
||||||
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
"""Test deprecation of RPC calls."""
|
"""Test deprecation of RPC calls."""
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import assert_raises_rpc_error
|
|
||||||
|
|
||||||
class DeprecatedRpcTest(BitcoinTestFramework):
|
class DeprecatedRpcTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.num_nodes = 2
|
self.num_nodes = 2
|
||||||
self.setup_clean_chain = True
|
self.setup_clean_chain = True
|
||||||
self.extra_args = [[], ["-deprecatedrpc=validateaddress", "-deprecatedrpc=accounts"]]
|
self.extra_args = [[], ["-deprecatedrpc=validateaddress"]]
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# This test should be used to verify correct behaviour of deprecated
|
# This test should be used to verify correct behaviour of deprecated
|
||||||
@ -21,82 +20,5 @@ class DeprecatedRpcTest(BitcoinTestFramework):
|
|||||||
# self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()])
|
# self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()])
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.log.info("Test accounts deprecation")
|
|
||||||
# The following account RPC methods are deprecated:
|
|
||||||
# - getaccount
|
|
||||||
# - getaccountaddress
|
|
||||||
# - getaddressesbyaccount
|
|
||||||
# - getreceivedbyaccount
|
|
||||||
# - listaccouts
|
|
||||||
# - listreceivedbyaccount
|
|
||||||
# - move
|
|
||||||
# - setaccount
|
|
||||||
#
|
|
||||||
# The following 'label' RPC methods are usable both with and without the
|
|
||||||
# -deprecatedrpc=accounts switch enabled.
|
|
||||||
# - getaddressesbylabel
|
|
||||||
# - getreceivedbylabel
|
|
||||||
# - listlabels
|
|
||||||
# - listreceivedbylabel
|
|
||||||
# - setlabel
|
|
||||||
#
|
|
||||||
address0 = self.nodes[0].getnewaddress()
|
|
||||||
self.nodes[0].generatetoaddress(101, address0)
|
|
||||||
self.sync_all()
|
|
||||||
address1 = self.nodes[1].getnewaddress()
|
|
||||||
self.nodes[1].generatetoaddress(101, address1)
|
|
||||||
|
|
||||||
self.log.info("- getaccount")
|
|
||||||
assert_raises_rpc_error(-32, "getaccount is deprecated", self.nodes[0].getaccount, address0)
|
|
||||||
self.nodes[1].getaccount(address1)
|
|
||||||
|
|
||||||
self.log.info("- setaccount")
|
|
||||||
assert_raises_rpc_error(-32, "setaccount is deprecated", self.nodes[0].setaccount, address0, "label0")
|
|
||||||
self.nodes[1].setaccount(address1, "label1")
|
|
||||||
|
|
||||||
self.log.info("- setlabel")
|
|
||||||
self.nodes[0].setlabel(address0, "label0")
|
|
||||||
self.nodes[1].setlabel(address1, "label1")
|
|
||||||
|
|
||||||
self.log.info("- getaccountaddress")
|
|
||||||
assert_raises_rpc_error(-32, "getaccountaddress is deprecated", self.nodes[0].getaccountaddress, "label0")
|
|
||||||
self.nodes[1].getaccountaddress("label1")
|
|
||||||
|
|
||||||
self.log.info("- getaddressesbyaccount")
|
|
||||||
assert_raises_rpc_error(-32, "getaddressesbyaccount is deprecated", self.nodes[0].getaddressesbyaccount, "label0")
|
|
||||||
self.nodes[1].getaddressesbyaccount("label1")
|
|
||||||
|
|
||||||
self.log.info("- getaddressesbylabel")
|
|
||||||
self.nodes[0].getaddressesbylabel("label0")
|
|
||||||
self.nodes[1].getaddressesbylabel("label1")
|
|
||||||
|
|
||||||
self.log.info("- getreceivedbyaccount")
|
|
||||||
assert_raises_rpc_error(-32, "getreceivedbyaccount is deprecated", self.nodes[0].getreceivedbyaccount, "label0")
|
|
||||||
self.nodes[1].getreceivedbyaccount("label1")
|
|
||||||
|
|
||||||
self.log.info("- getreceivedbylabel")
|
|
||||||
self.nodes[0].getreceivedbylabel("label0")
|
|
||||||
self.nodes[1].getreceivedbylabel("label1")
|
|
||||||
|
|
||||||
self.log.info("- listaccounts")
|
|
||||||
assert_raises_rpc_error(-32, "listaccounts is deprecated", self.nodes[0].listaccounts)
|
|
||||||
self.nodes[1].listaccounts()
|
|
||||||
|
|
||||||
self.log.info("- listlabels")
|
|
||||||
self.nodes[0].listlabels()
|
|
||||||
self.nodes[1].listlabels()
|
|
||||||
|
|
||||||
self.log.info("- listreceivedbyaccount")
|
|
||||||
assert_raises_rpc_error(-32, "listreceivedbyaccount is deprecated", self.nodes[0].listreceivedbyaccount)
|
|
||||||
self.nodes[1].listreceivedbyaccount()
|
|
||||||
|
|
||||||
self.log.info("- listreceivedbylabel")
|
|
||||||
self.nodes[0].listreceivedbylabel()
|
|
||||||
self.nodes[1].listreceivedbylabel()
|
|
||||||
|
|
||||||
self.log.info("- move")
|
|
||||||
assert_raises_rpc_error(-32, "move is deprecated", self.nodes[0].move, "label0", "label0b", 10)
|
|
||||||
self.nodes[1].move("label1", "label1b", 10)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
DeprecatedRpcTest().main()
|
DeprecatedRpcTest().main()
|
||||||
|
@ -69,7 +69,7 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
|
|||||||
def check(self, txid=None, amount=None, confirmations=None):
|
def check(self, txid=None, amount=None, confirmations=None):
|
||||||
"""Verify that listtransactions/listreceivedbyaddress return expected values."""
|
"""Verify that listtransactions/listreceivedbyaddress return expected values."""
|
||||||
|
|
||||||
txs = self.node.listtransactions(label=self.label, count=10000, skip=0, include_watchonly=True)
|
txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True)
|
||||||
assert_equal(len(txs), self.expected_txs)
|
assert_equal(len(txs), self.expected_txs)
|
||||||
|
|
||||||
addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])
|
addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])
|
||||||
|
@ -5,15 +5,9 @@
|
|||||||
"""Test label RPCs.
|
"""Test label RPCs.
|
||||||
|
|
||||||
RPCs tested are:
|
RPCs tested are:
|
||||||
- getaccountaddress
|
- getaddressesbylabel
|
||||||
- getaddressesbyaccount/getaddressesbylabel
|
|
||||||
- listaddressgroupings
|
- listaddressgroupings
|
||||||
- setlabel
|
- setlabel
|
||||||
- sendfrom (with account arguments)
|
|
||||||
- move (with account arguments)
|
|
||||||
|
|
||||||
Run the test twice - once using the accounts API and once using the labels API.
|
|
||||||
The accounts API test can be removed in V0.18.
|
|
||||||
"""
|
"""
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
@ -23,19 +17,11 @@ from test_framework.util import assert_equal, assert_raises_rpc_error
|
|||||||
class WalletLabelsTest(BitcoinTestFramework):
|
class WalletLabelsTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.setup_clean_chain = True
|
self.setup_clean_chain = True
|
||||||
self.num_nodes = 2
|
self.num_nodes = 1
|
||||||
self.extra_args = [['-deprecatedrpc=accounts', "-paytxfee=0.0001"], ["-paytxfee=0.0001"]]
|
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
"""Run the test twice - once using the accounts API and once using the labels API."""
|
# Check that there's no UTXO on the node
|
||||||
self.log.info("Test accounts API")
|
node = self.nodes[0]
|
||||||
self.nodes[0].setnetworkactive(False)
|
|
||||||
self._run_subtest(True, self.nodes[0])
|
|
||||||
self.log.info("Test labels API")
|
|
||||||
self._run_subtest(False, self.nodes[1])
|
|
||||||
|
|
||||||
def _run_subtest(self, accounts_api, node):
|
|
||||||
# Check that there's no UTXO on any of the nodes
|
|
||||||
assert_equal(len(node.listunspent()), 0)
|
assert_equal(len(node.listunspent()), 0)
|
||||||
|
|
||||||
# Note each time we call generate, all generated coins go into
|
# Note each time we call generate, all generated coins go into
|
||||||
@ -58,19 +44,14 @@ class WalletLabelsTest(BitcoinTestFramework):
|
|||||||
linked_addresses.add(address_group[0][0])
|
linked_addresses.add(address_group[0][0])
|
||||||
|
|
||||||
# send 500 from each address to a third address not in this wallet
|
# send 500 from each address to a third address not in this wallet
|
||||||
# There's some fee that will come back to us when the miner reward
|
|
||||||
# matures.
|
|
||||||
common_address = "yd5KMREs3GLMe6mTJYr3YrH1juwNwrFCfB"
|
common_address = "yd5KMREs3GLMe6mTJYr3YrH1juwNwrFCfB"
|
||||||
txid = node.sendmany(
|
node.sendmany(
|
||||||
fromaccount="",
|
|
||||||
amounts={common_address: 1000},
|
amounts={common_address: 1000},
|
||||||
minconf=1,
|
minconf=1,
|
||||||
addlocked=False,
|
addlocked=False,
|
||||||
comment="",
|
comment="",
|
||||||
subtractfeefrom=[common_address],
|
subtractfeefrom=[common_address],
|
||||||
)
|
)
|
||||||
tx_details = node.gettransaction(txid)
|
|
||||||
fee = -tx_details['details'][0]['fee']
|
|
||||||
# there should be 1 address group, with the previously
|
# there should be 1 address group, with the previously
|
||||||
# unlinked addresses now linked (they both have 0 balance)
|
# unlinked addresses now linked (they both have 0 balance)
|
||||||
address_groups = node.listaddressgroupings()
|
address_groups = node.listaddressgroupings()
|
||||||
@ -84,32 +65,22 @@ class WalletLabelsTest(BitcoinTestFramework):
|
|||||||
# we want to reset so that the "" label has what's expected.
|
# we want to reset so that the "" label has what's expected.
|
||||||
# otherwise we're off by exactly the fee amount as that's mined
|
# otherwise we're off by exactly the fee amount as that's mined
|
||||||
# and matures in the next 100 blocks
|
# and matures in the next 100 blocks
|
||||||
if accounts_api:
|
|
||||||
node.sendfrom("", common_address, fee)
|
|
||||||
amount_to_send = 1.0
|
amount_to_send = 1.0
|
||||||
|
|
||||||
# Create labels and make sure subsequent label API calls
|
# Create labels and make sure subsequent label API calls
|
||||||
# recognize the label/address associations.
|
# recognize the label/address associations.
|
||||||
labels = [Label(name, accounts_api) for name in ("a", "b", "c", "d", "e")]
|
labels = [Label(name) for name in ("a", "b", "c", "d", "e")]
|
||||||
for label in labels:
|
for label in labels:
|
||||||
if accounts_api:
|
address = node.getnewaddress(label.name)
|
||||||
address = node.getaccountaddress(label.name)
|
|
||||||
else:
|
|
||||||
address = node.getnewaddress(label.name)
|
|
||||||
label.add_receive_address(address)
|
label.add_receive_address(address)
|
||||||
label.verify(node)
|
label.verify(node)
|
||||||
|
|
||||||
# Check all labels are returned by listlabels.
|
# Check all labels are returned by listlabels.
|
||||||
assert_equal(node.listlabels(), [label.name for label in labels])
|
assert_equal(node.listlabels(), [label.name for label in labels])
|
||||||
|
|
||||||
# Send a transaction to each label, and make sure this forces
|
# Send a transaction to each label.
|
||||||
# getaccountaddress to generate a new receiving address.
|
|
||||||
for label in labels:
|
for label in labels:
|
||||||
if accounts_api:
|
node.sendtoaddress(label.addresses[0], amount_to_send)
|
||||||
node.sendtoaddress(label.receive_address, amount_to_send)
|
|
||||||
label.add_receive_address(node.getaccountaddress(label.name))
|
|
||||||
else:
|
|
||||||
node.sendtoaddress(label.addresses[0], amount_to_send)
|
|
||||||
label.verify(node)
|
label.verify(node)
|
||||||
|
|
||||||
# Check the amounts received.
|
# Check the amounts received.
|
||||||
@ -119,32 +90,17 @@ class WalletLabelsTest(BitcoinTestFramework):
|
|||||||
node.getreceivedbyaddress(label.addresses[0]), amount_to_send)
|
node.getreceivedbyaddress(label.addresses[0]), amount_to_send)
|
||||||
assert_equal(node.getreceivedbylabel(label.name), amount_to_send)
|
assert_equal(node.getreceivedbylabel(label.name), amount_to_send)
|
||||||
|
|
||||||
# Check that sendfrom label reduces listaccounts balances.
|
|
||||||
for i, label in enumerate(labels):
|
for i, label in enumerate(labels):
|
||||||
to_label = labels[(i + 1) % len(labels)]
|
to_label = labels[(i + 1) % len(labels)]
|
||||||
if accounts_api:
|
node.sendtoaddress(to_label.addresses[0], amount_to_send)
|
||||||
node.sendfrom(label.name, to_label.receive_address, amount_to_send)
|
|
||||||
else:
|
|
||||||
node.sendtoaddress(to_label.addresses[0], amount_to_send)
|
|
||||||
node.generate(1)
|
node.generate(1)
|
||||||
for label in labels:
|
for label in labels:
|
||||||
if accounts_api:
|
address = node.getnewaddress(label.name)
|
||||||
address = node.getaccountaddress(label.name)
|
|
||||||
else:
|
|
||||||
address = node.getnewaddress(label.name)
|
|
||||||
label.add_receive_address(address)
|
label.add_receive_address(address)
|
||||||
label.verify(node)
|
label.verify(node)
|
||||||
assert_equal(node.getreceivedbylabel(label.name), 2)
|
assert_equal(node.getreceivedbylabel(label.name), 2)
|
||||||
if accounts_api:
|
|
||||||
node.move(label.name, "", node.getbalance(label.name))
|
|
||||||
label.verify(node)
|
label.verify(node)
|
||||||
node.generate(101)
|
node.generate(101)
|
||||||
expected_account_balances = {"": 52000}
|
|
||||||
for label in labels:
|
|
||||||
expected_account_balances[label.name] = 0
|
|
||||||
if accounts_api:
|
|
||||||
assert_equal(node.listaccounts(), expected_account_balances)
|
|
||||||
assert_equal(node.getbalance(""), 52000)
|
|
||||||
|
|
||||||
# Check that setlabel can assign a label to a new unused address.
|
# Check that setlabel can assign a label to a new unused address.
|
||||||
for label in labels:
|
for label in labels:
|
||||||
@ -152,10 +108,7 @@ class WalletLabelsTest(BitcoinTestFramework):
|
|||||||
node.setlabel(address, label.name)
|
node.setlabel(address, label.name)
|
||||||
label.add_address(address)
|
label.add_address(address)
|
||||||
label.verify(node)
|
label.verify(node)
|
||||||
if accounts_api:
|
assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
|
||||||
assert address not in node.getaddressesbyaccount("")
|
|
||||||
else:
|
|
||||||
assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
|
|
||||||
|
|
||||||
# Check that addmultisigaddress can assign labels.
|
# Check that addmultisigaddress can assign labels.
|
||||||
for label in labels:
|
for label in labels:
|
||||||
@ -166,35 +119,20 @@ class WalletLabelsTest(BitcoinTestFramework):
|
|||||||
label.add_address(multisig_address)
|
label.add_address(multisig_address)
|
||||||
label.purpose[multisig_address] = "send"
|
label.purpose[multisig_address] = "send"
|
||||||
label.verify(node)
|
label.verify(node)
|
||||||
if accounts_api:
|
|
||||||
node.sendfrom("", multisig_address, 50)
|
|
||||||
node.generate(101)
|
node.generate(101)
|
||||||
if accounts_api:
|
|
||||||
for label in labels:
|
|
||||||
assert_equal(node.getbalance(label.name), 50)
|
|
||||||
|
|
||||||
# Check that setlabel can change the label of an address from a
|
# Check that setlabel can change the label of an address from a
|
||||||
# different label.
|
# different label.
|
||||||
change_label(node, labels[0].addresses[0], labels[0], labels[1], accounts_api)
|
change_label(node, labels[0].addresses[0], labels[0], labels[1])
|
||||||
|
|
||||||
# Check that setlabel can set the label of an address already
|
# Check that setlabel can set the label of an address already
|
||||||
# in the label. This is a no-op.
|
# in the label. This is a no-op.
|
||||||
change_label(node, labels[2].addresses[0], labels[2], labels[2], accounts_api)
|
change_label(node, labels[2].addresses[0], labels[2], labels[2])
|
||||||
|
|
||||||
if accounts_api:
|
|
||||||
# Check that setaccount can change the label of an address which
|
|
||||||
# is the receiving address of a different label.
|
|
||||||
change_label(node, labels[0].receive_address, labels[0], labels[1], accounts_api)
|
|
||||||
|
|
||||||
# Check that setaccount can set the label of an address which is
|
|
||||||
# already the receiving address of the label. This is a no-op.
|
|
||||||
change_label(node, labels[2].receive_address, labels[2], labels[2], accounts_api)
|
|
||||||
|
|
||||||
class Label:
|
class Label:
|
||||||
def __init__(self, name, accounts_api):
|
def __init__(self, name):
|
||||||
# Label name
|
# Label name
|
||||||
self.name = name
|
self.name = name
|
||||||
self.accounts_api = accounts_api
|
|
||||||
# Current receiving address associated with this label.
|
# Current receiving address associated with this label.
|
||||||
self.receive_address = None
|
self.receive_address = None
|
||||||
# List of all addresses assigned with this label
|
# List of all addresses assigned with this label
|
||||||
@ -208,56 +146,31 @@ class Label:
|
|||||||
|
|
||||||
def add_receive_address(self, address):
|
def add_receive_address(self, address):
|
||||||
self.add_address(address)
|
self.add_address(address)
|
||||||
if self.accounts_api:
|
|
||||||
self.receive_address = address
|
|
||||||
|
|
||||||
def verify(self, node):
|
def verify(self, node):
|
||||||
if self.receive_address is not None:
|
if self.receive_address is not None:
|
||||||
assert self.receive_address in self.addresses
|
assert self.receive_address in self.addresses
|
||||||
if self.accounts_api:
|
|
||||||
assert_equal(node.getaccountaddress(self.name), self.receive_address)
|
|
||||||
|
|
||||||
for address in self.addresses:
|
for address in self.addresses:
|
||||||
assert_equal(
|
assert_equal(
|
||||||
node.getaddressinfo(address)['labels'][0],
|
node.getaddressinfo(address)['labels'][0],
|
||||||
{"name": self.name,
|
{"name": self.name,
|
||||||
"purpose": self.purpose[address]})
|
"purpose": self.purpose[address]})
|
||||||
if self.accounts_api:
|
assert_equal(node.getaddressinfo(address)['label'], self.name)
|
||||||
assert_equal(node.getaccount(address), self.name)
|
|
||||||
else:
|
|
||||||
assert_equal(node.getaddressinfo(address)['label'], self.name)
|
|
||||||
|
|
||||||
assert_equal(
|
assert_equal(
|
||||||
node.getaddressesbylabel(self.name),
|
node.getaddressesbylabel(self.name),
|
||||||
{address: {"purpose": self.purpose[address]} for address in self.addresses})
|
{address: {"purpose": self.purpose[address]} for address in self.addresses})
|
||||||
if self.accounts_api:
|
|
||||||
assert_equal(set(node.getaddressesbyaccount(self.name)), set(self.addresses))
|
|
||||||
|
|
||||||
|
def change_label(node, address, old_label, new_label):
|
||||||
def change_label(node, address, old_label, new_label, accounts_api):
|
|
||||||
assert_equal(address in old_label.addresses, True)
|
assert_equal(address in old_label.addresses, True)
|
||||||
if accounts_api:
|
node.setlabel(address, new_label.name)
|
||||||
node.setaccount(address, new_label.name)
|
|
||||||
else:
|
|
||||||
node.setlabel(address, new_label.name)
|
|
||||||
|
|
||||||
old_label.addresses.remove(address)
|
old_label.addresses.remove(address)
|
||||||
new_label.add_address(address)
|
new_label.add_address(address)
|
||||||
|
|
||||||
# Calling setaccount on an address which was previously the receiving
|
|
||||||
# address of a different account should reset the receiving address of
|
|
||||||
# the old account, causing getaccountaddress to return a brand new
|
|
||||||
# address.
|
|
||||||
if accounts_api:
|
|
||||||
if old_label.name != new_label.name and address == old_label.receive_address:
|
|
||||||
new_address = node.getaccountaddress(old_label.name)
|
|
||||||
assert_equal(new_address not in old_label.addresses, True)
|
|
||||||
assert_equal(new_address not in new_label.addresses, True)
|
|
||||||
old_label.add_receive_address(new_address)
|
|
||||||
|
|
||||||
old_label.verify(node)
|
old_label.verify(node)
|
||||||
new_label.verify(node)
|
new_label.verify(node)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
WalletLabelsTest().main()
|
WalletLabelsTest().main()
|
||||||
|
@ -80,8 +80,8 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||||||
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
|
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
assert len(self.nodes[0].listtransactions(label="watchonly", count=100, skip=0, include_watchonly=False)) == 0
|
assert len(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=False)) == 0
|
||||||
assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, skip=0, include_watchonly=True),
|
assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True),
|
||||||
{"category": "receive", "amount": Decimal("0.1")},
|
{"category": "receive", "amount": Decimal("0.1")},
|
||||||
{"txid": txid, "label": "watchonly"})
|
{"txid": txid, "label": "watchonly"})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user