Auto merge of #5271 - nuttycom:backport/13825_kill_accounts, r=str4d
[Backport] bitcoin/bitcoin#13825 kill accounts This is a backport of the following commits: - from bitcoin/bitcoin#13825 - pick bitcoin/bitcoin@c9c32e6b84 - from bitcoin/bitcoin#14023 - pick bitcoin/bitcoin@f0dc850bf6 - from bitcoin/bitcoin#13566 - pick bitcoin/bitcoin@702ae1e21a - pick bitcoin/bitcoin@cf15761f6d - pick bitcoin/bitcoin@0f3d6e9ab7 - pick bitcoin/bitcoin@7110c830f8 - pick bitcoin/bitcoin@ef7bc8893c - pick bitcoin/bitcoin@4279da4785 - pick bitcoin/bitcoin@c410f41575 - from bitcoin/bitcoin#9614 - pick bitcoin/bitcoin@02d9f50d5f - pick bitcoin/bitcoin@82b7dc373a - from bitcoin/bitcoin#8061 - pick bitcoin/bitcoin@ecb9741ec3 - from bitcoin/bitcoin#6851 - pick bitcoin/bitcoin@3e7c89196c - from bitcoin/bitcoin#8828 - pick bitcoin/bitcoin@86029e72c9 - from bitcoin/bitcoin#8696 - just the first two commits, as AccountingEntry is going away - pick bitcoin/bitcoin@d2e678d7d2 - pick bitcoin/bitcoin@59adc86680 - from bitcoin/bitcoin#8028 - pick bitcoin/bitcoin@0fd599767d
This commit is contained in:
commit
5b194067ea
|
@ -42,20 +42,20 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||
self.sync_all()
|
||||
check_array_result(self.nodes[0].listtransactions(),
|
||||
{"txid":txid},
|
||||
{"category":"send","account":"","amount":Decimal("-0.1"),"amountZat":-10000000,"confirmations":0})
|
||||
{"category":"send","amount":Decimal("-0.1"),"amountZat":-10000000,"confirmations":0})
|
||||
check_array_result(self.nodes[1].listtransactions(),
|
||||
{"txid":txid},
|
||||
{"category":"receive","account":"","amount":Decimal("0.1"),"amountZat":10000000,"confirmations":0})
|
||||
{"category":"receive","amount":Decimal("0.1"),"amountZat":10000000,"confirmations":0})
|
||||
|
||||
# mine a block, confirmations should change:
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
check_array_result(self.nodes[0].listtransactions(),
|
||||
{"txid":txid},
|
||||
{"category":"send","account":"","amount":Decimal("-0.1"),"amountZat":-10000000,"confirmations":1})
|
||||
{"category":"send","amount":Decimal("-0.1"),"amountZat":-10000000,"confirmations":1})
|
||||
check_array_result(self.nodes[1].listtransactions(),
|
||||
{"txid":txid},
|
||||
{"category":"receive","account":"","amount":Decimal("0.1"),"amountZat":10000000,"confirmations":1})
|
||||
{"category":"receive","amount":Decimal("0.1"),"amountZat":10000000,"confirmations":1})
|
||||
|
||||
# send-to-self:
|
||||
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
|
||||
|
@ -67,10 +67,14 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||
{"amount":Decimal("0.2"),"amountZat":20000000})
|
||||
|
||||
# sendmany from node1: twice to self, twice to node2:
|
||||
send_to = { self.nodes[0].getnewaddress() : 0.11,
|
||||
self.nodes[1].getnewaddress() : 0.22,
|
||||
self.nodes[0].getaccountaddress("") : 0.33,
|
||||
self.nodes[1].getaccountaddress("") : 0.44 }
|
||||
node_0_addr_0 = self.nodes[0].getnewaddress()
|
||||
node_0_addr_1 = self.nodes[0].getnewaddress()
|
||||
node_1_addr_0 = self.nodes[1].getnewaddress()
|
||||
node_1_addr_1 = self.nodes[1].getnewaddress()
|
||||
send_to = { node_0_addr_0 : 0.11,
|
||||
node_1_addr_0 : 0.22,
|
||||
node_0_addr_1 : 0.33,
|
||||
node_1_addr_1 : 0.44 }
|
||||
txid = self.nodes[1].sendmany("", send_to)
|
||||
self.sync_all()
|
||||
check_array_result(self.nodes[1].listtransactions(),
|
||||
|
@ -90,23 +94,22 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||
{"txid":txid} )
|
||||
check_array_result(self.nodes[0].listtransactions(),
|
||||
{"category":"receive","amount":Decimal("0.33"),"amountZat":33000000},
|
||||
{"txid":txid, "account" : ""} )
|
||||
{"txid":txid} )
|
||||
check_array_result(self.nodes[1].listtransactions(),
|
||||
{"category":"send","amount":Decimal("-0.44"),"amountZat":-44000000},
|
||||
{"txid":txid, "account" : ""} )
|
||||
{"txid":txid} )
|
||||
check_array_result(self.nodes[1].listtransactions(),
|
||||
{"category":"receive","amount":Decimal("0.44"),"amountZat":44000000},
|
||||
{"txid":txid, "account" : ""} )
|
||||
{"txid":txid} )
|
||||
|
||||
multisig = self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()])
|
||||
self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True)
|
||||
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
|
||||
self.nodes[1].generate(1)
|
||||
self.sync_all()
|
||||
assert(len(self.nodes[0].listtransactions("watchonly", 100, 0, False)) == 0)
|
||||
check_array_result(self.nodes[0].listtransactions("watchonly", 100, 0, True),
|
||||
check_array_result(self.nodes[0].listtransactions("*", 100, 0, True),
|
||||
{"category":"receive","amount":Decimal("0.1"),"amountZat":10000000},
|
||||
{"txid":txid, "account" : "watchonly"} )
|
||||
{"txid":txid, "involvesWatchonly": True} )
|
||||
|
||||
if __name__ == '__main__':
|
||||
ListTransactionsTest().main()
|
||||
|
|
|
@ -52,8 +52,8 @@ class TxnMallTest(BitcoinTestFramework):
|
|||
# Create two transaction from node[0] to node[1]; the
|
||||
# second must spend change from the first because the first
|
||||
# spends all mature inputs:
|
||||
txid1 = self.nodes[0].sendfrom("", node1_address, (starting_balance - (mining_reward - 2)), 0)
|
||||
txid2 = self.nodes[0].sendfrom("", node1_address, 5, 0)
|
||||
txid1 = self.nodes[0].sendtoaddress(node1_address, (starting_balance - (mining_reward - 2)))
|
||||
txid2 = self.nodes[0].sendtoaddress(node1_address, 5)
|
||||
|
||||
# Have node0 mine a block:
|
||||
if (self.options.mine_block):
|
||||
|
@ -75,7 +75,7 @@ class TxnMallTest(BitcoinTestFramework):
|
|||
assert_equal(tx1["confirmations"], 1)
|
||||
assert_equal(tx2["confirmations"], 1)
|
||||
# Node1's total balance should be its starting balance plus both transaction amounts:
|
||||
assert_equal(self.nodes[1].getbalance(""), starting_balance - (tx1["amount"]+tx2["amount"]))
|
||||
assert_equal(self.nodes[1].getbalance("*"), starting_balance - (tx1["amount"]+tx2["amount"]))
|
||||
else:
|
||||
assert_equal(tx1["confirmations"], 0)
|
||||
assert_equal(tx2["confirmations"], 0)
|
||||
|
@ -105,7 +105,7 @@ class TxnMallTest(BitcoinTestFramework):
|
|||
assert_equal(self.nodes[0].getbalance("*"), expected)
|
||||
|
||||
# Node1's total balance should be its starting balance plus the amount of the mutated send:
|
||||
assert_equal(self.nodes[1].getbalance(""), starting_balance + (starting_balance - (mining_reward - 2)))
|
||||
assert_equal(self.nodes[1].getbalance("*"), starting_balance + (starting_balance - (mining_reward - 2)))
|
||||
|
||||
if __name__ == '__main__':
|
||||
TxnMallTest().main()
|
||||
|
|
|
@ -119,7 +119,6 @@ if ENABLE_WALLET
|
|||
BITCOIN_TESTS += \
|
||||
wallet/test/wallet_test_fixture.cpp \
|
||||
wallet/test/wallet_test_fixture.h \
|
||||
wallet/test/accounting_tests.cpp \
|
||||
wallet/test/wallet_tests.cpp \
|
||||
wallet/test/crypto_tests.cpp \
|
||||
wallet/test/rpc_wallet_tests.cpp
|
||||
|
|
|
@ -38,27 +38,16 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "settxfee", 0 },
|
||||
{ "getreceivedbyaddress", 1 },
|
||||
{ "getreceivedbyaddress", 2 },
|
||||
{ "getreceivedbyaccount", 1 },
|
||||
{ "getreceivedbyaccount", 2 },
|
||||
{ "listreceivedbyaddress", 0 },
|
||||
{ "listreceivedbyaddress", 1 },
|
||||
{ "listreceivedbyaddress", 2 },
|
||||
{ "listreceivedbyaccount", 0 },
|
||||
{ "listreceivedbyaccount", 1 },
|
||||
{ "listreceivedbyaccount", 2 },
|
||||
{ "getbalance", 1 },
|
||||
{ "getbalance", 2 },
|
||||
{ "getbalance", 3 },
|
||||
{ "getblockhash", 0 },
|
||||
{ "move", 2 },
|
||||
{ "move", 3 },
|
||||
{ "sendfrom", 2 },
|
||||
{ "sendfrom", 3 },
|
||||
{ "listtransactions", 1 },
|
||||
{ "listtransactions", 2 },
|
||||
{ "listtransactions", 3 },
|
||||
{ "listaccounts", 0 },
|
||||
{ "listaccounts", 1 },
|
||||
{ "walletpassphrase", 1 },
|
||||
{ "getblocktemplate", 0 },
|
||||
{ "listsinceblock", 1 },
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
MOCK_METHOD0(TxnCommit, bool());
|
||||
MOCK_METHOD0(TxnAbort, bool());
|
||||
|
||||
MOCK_METHOD2(WriteTx, bool(uint256 hash, const CWalletTx& wtx));
|
||||
MOCK_METHOD1(WriteTx, bool(const CWalletTx& wtx));
|
||||
MOCK_METHOD1(WriteWitnessCacheSize, bool(int64_t nWitnessCacheSize));
|
||||
MOCK_METHOD1(WriteBestBlock, bool(const CBlockLocator& loc));
|
||||
};
|
||||
|
@ -1572,19 +1572,19 @@ TEST(WalletTests, WriteWitnessCache) {
|
|||
.WillRepeatedly(Return(true));
|
||||
|
||||
// WriteTx fails
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(walletdb, TxnAbort())
|
||||
.Times(1);
|
||||
wallet.SetBestChain(walletdb, loc);
|
||||
|
||||
// WriteTx throws
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx))
|
||||
.WillOnce(ThrowLogicError());
|
||||
EXPECT_CALL(walletdb, TxnAbort())
|
||||
.Times(1);
|
||||
wallet.SetBestChain(walletdb, loc);
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// WriteWitnessCacheSize fails
|
||||
|
@ -1694,15 +1694,15 @@ TEST(WalletTests, SetBestChainIgnoresTxsWithoutShieldedData) {
|
|||
|
||||
EXPECT_CALL(walletdb, TxnBegin())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxTransparent.GetHash(), wtxTransparent))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxTransparent))
|
||||
.Times(0);
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSprout.GetHash(), wtxSprout))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSprout))
|
||||
.Times(1).WillOnce(Return(true));
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSproutTransparent.GetHash(), wtxSproutTransparent))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSproutTransparent))
|
||||
.Times(0);
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSapling.GetHash(), wtxSapling))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSapling))
|
||||
.Times(1).WillOnce(Return(true));
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSaplingTransparent.GetHash(), wtxSaplingTransparent))
|
||||
EXPECT_CALL(walletdb, WriteTx(wtxSaplingTransparent))
|
||||
.Times(0);
|
||||
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
|
||||
.WillOnce(Return(true));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,140 +0,0 @@
|
|||
// Copyright (c) 2012-2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include "wallet/wallet.h"
|
||||
#include "wallet/walletdb.h"
|
||||
|
||||
#include "wallet/test/wallet_test_fixture.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
extern CWallet* pwalletMain;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
|
||||
|
||||
static void
|
||||
GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results)
|
||||
{
|
||||
std::list<CAccountingEntry> aes;
|
||||
|
||||
results.clear();
|
||||
BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK);
|
||||
walletdb.ListAccountCreditDebit("", aes);
|
||||
for (CAccountingEntry& ae : aes)
|
||||
{
|
||||
results[ae.nOrderPos] = ae;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(acc_orderupgrade)
|
||||
{
|
||||
CWalletDB walletdb(pwalletMain->strWalletFile);
|
||||
std::vector<CWalletTx*> vpwtx;
|
||||
CWalletTx wtx;
|
||||
CAccountingEntry ae;
|
||||
std::map<CAmount, CAccountingEntry> results;
|
||||
|
||||
LOCK(pwalletMain->cs_wallet);
|
||||
|
||||
ae.strAccount = "";
|
||||
ae.nCreditDebit = 1;
|
||||
ae.nTime = 1333333333;
|
||||
ae.strOtherAccount = "b";
|
||||
ae.strComment = "";
|
||||
walletdb.WriteAccountingEntry(ae);
|
||||
|
||||
wtx.mapValue["comment"] = "z";
|
||||
pwalletMain->AddToWallet(wtx, false, &walletdb);
|
||||
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
|
||||
vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
|
||||
vpwtx[0]->nOrderPos = -1;
|
||||
|
||||
ae.nTime = 1333333336;
|
||||
ae.strOtherAccount = "c";
|
||||
walletdb.WriteAccountingEntry(ae);
|
||||
|
||||
GetResults(walletdb, results);
|
||||
|
||||
BOOST_CHECK(pwalletMain->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 = pwalletMain->IncOrderPosNext();
|
||||
walletdb.WriteAccountingEntry(ae);
|
||||
|
||||
GetResults(walletdb, results);
|
||||
|
||||
BOOST_CHECK(results.size() == 3);
|
||||
BOOST_CHECK(pwalletMain->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.nLockTime; // Just to change the hash :)
|
||||
*static_cast<CTransaction*>(&wtx) = CTransaction(tx);
|
||||
}
|
||||
pwalletMain->AddToWallet(wtx, false, &walletdb);
|
||||
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
|
||||
vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
|
||||
|
||||
wtx.mapValue["comment"] = "x";
|
||||
{
|
||||
CMutableTransaction tx(wtx);
|
||||
--tx.nLockTime; // Just to change the hash :)
|
||||
*static_cast<CTransaction*>(&wtx) = CTransaction(tx);
|
||||
}
|
||||
pwalletMain->AddToWallet(wtx, false, &walletdb);
|
||||
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
|
||||
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
|
||||
vpwtx[2]->nOrderPos = -1;
|
||||
|
||||
GetResults(walletdb, results);
|
||||
|
||||
BOOST_CHECK(results.size() == 3);
|
||||
BOOST_CHECK(pwalletMain->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;
|
||||
walletdb.WriteAccountingEntry(ae);
|
||||
|
||||
GetResults(walletdb, results);
|
||||
|
||||
BOOST_CHECK(results.size() == 4);
|
||||
BOOST_CHECK(pwalletMain->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()
|
|
@ -120,6 +120,7 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
|
|||
BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
{
|
||||
// Test RPC calls for various wallet statistics
|
||||
KeyIO keyIO(Params());
|
||||
UniValue r;
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
@ -127,33 +128,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
CPubKey demoPubkey = pwalletMain->GenerateNewKey();
|
||||
CTxDestination demoAddress(CTxDestination(demoPubkey.GetID()));
|
||||
UniValue retValue;
|
||||
string strAccount = "";
|
||||
string strPurpose = "receive";
|
||||
BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
|
||||
BOOST_CHECK_NO_THROW({ /*Initialize Wallet with the demo pubkey*/
|
||||
CWalletDB walletdb(pwalletMain->strWalletFile);
|
||||
CAccount account;
|
||||
account.vchPubKey = demoPubkey;
|
||||
pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
|
||||
walletdb.WriteAccount(strAccount, account);
|
||||
pwalletMain->SetAddressBook(demoPubkey.GetID(), "", strPurpose);
|
||||
});
|
||||
|
||||
CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
|
||||
CTxDestination setaccountDemoAddress(CTxDestination(setaccountDemoPubkey.GetID()));
|
||||
|
||||
/*********************************
|
||||
* setaccount
|
||||
*********************************/
|
||||
KeyIO keyIO(Params());
|
||||
BOOST_CHECK_NO_THROW(CallRPC("setaccount " + keyIO.EncodeDestination(setaccountDemoAddress) + " \"\""));
|
||||
/* Accounts are disabled */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount " + keyIO.EncodeDestination(setaccountDemoAddress) + " nullaccount"), runtime_error);
|
||||
/* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV is not owned by the test wallet. */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV nullaccount"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
|
||||
/* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg (34 chars) is an illegal address (should be 35 chars) */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg nullaccount"), runtime_error);
|
||||
|
||||
|
||||
/*********************************
|
||||
* getbalance
|
||||
*********************************/
|
||||
|
@ -181,16 +164,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
|
||||
|
||||
/*********************************
|
||||
* listreceivedbyaccount
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
|
||||
|
||||
/*********************************
|
||||
* listsinceblock
|
||||
*********************************/
|
||||
|
@ -200,9 +173,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
* listtransactions
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress)));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " 20"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " 20 0"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions *"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions * 20"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions * 20 0"));
|
||||
BOOST_CHECK_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " not_int"), runtime_error);
|
||||
|
||||
/*********************************
|
||||
|
@ -210,11 +183,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listlockunspent"));
|
||||
|
||||
/*********************************
|
||||
* listaccounts
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listaccounts"));
|
||||
|
||||
/*********************************
|
||||
* listaddressgroupings
|
||||
*********************************/
|
||||
|
@ -229,24 +197,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
* getnewaddress
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress \"\""));
|
||||
/* Accounts are deprecated */
|
||||
BOOST_CHECK_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"), runtime_error);
|
||||
|
||||
/*********************************
|
||||
* getaccountaddress
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
|
||||
/* Accounts are deprecated */
|
||||
BOOST_CHECK_THROW(CallRPC("getaccountaddress accountThatDoesntExists"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
|
||||
BOOST_CHECK(keyIO.DecodeDestination(retValue.get_str()) == demoAddress);
|
||||
|
||||
/*********************************
|
||||
* getaccount
|
||||
*********************************/
|
||||
BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getaccount " + keyIO.EncodeDestination(demoAddress)));
|
||||
|
||||
/*********************************
|
||||
* signmessage + verifymessage
|
||||
|
@ -268,19 +218,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
/* Correct address, message and signature*/
|
||||
BOOST_CHECK(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str() + " mymessage").get_bool() == true);
|
||||
|
||||
/*********************************
|
||||
* getaddressesbyaccount
|
||||
*********************************/
|
||||
BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
|
||||
UniValue arr = retValue.get_array();
|
||||
BOOST_CHECK_EQUAL(4, arr.size());
|
||||
bool notFound = true;
|
||||
for (auto a : arr.getValues()) {
|
||||
notFound &= keyIO.DecodeDestination(a.get_str()) != demoAddress;
|
||||
}
|
||||
BOOST_CHECK(!notFound);
|
||||
|
||||
/*********************************
|
||||
* fundrawtransaction
|
||||
*********************************/
|
||||
|
@ -1907,9 +1844,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
|
|||
BOOST_CHECK( find_error(objError, "Recipient parameter missing"));
|
||||
}
|
||||
|
||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs =
|
||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs =
|
||||
{MergeToAddressInputSproutNote{JSOutPoint(), SproutNote(), 0, SproutSpendingKey()}};
|
||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs =
|
||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs =
|
||||
{MergeToAddressInputSaplingNote{SaplingOutPoint(), SaplingNote({}, uint256(), 0, uint256(), Zip212Enabled::BeforeZip212), 0, SaplingExpandedSpendingKey()}};
|
||||
|
||||
// Sprout and Sapling inputs -> throw
|
||||
|
|
|
@ -976,7 +976,6 @@ void CWallet::SyncMetaData(pair<typename TxSpendMap<T>::iterator, typename TxSpe
|
|||
// nTimeReceived not copied on purpose
|
||||
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
||||
copyTo->fFromMe = copyFrom->fFromMe;
|
||||
copyTo->strFromAccount = copyFrom->strFromAccount;
|
||||
// nOrderPos not copied on purpose
|
||||
// cached members not copied on purpose
|
||||
}
|
||||
|
@ -1405,6 +1404,63 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
|||
return true;
|
||||
}
|
||||
|
||||
DBErrors CWallet::ReorderTransactions()
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
|
||||
// Old wallets didn't have any defined order for transactions
|
||||
// Probably a bad idea to change the output of this
|
||||
|
||||
// First: get all CWalletTx into a sorted-by-time multimap.
|
||||
typedef std::multimap<int64_t, CWalletTx*> TxItems;
|
||||
TxItems txByTime;
|
||||
|
||||
for (auto &entry : mapWallet)
|
||||
{
|
||||
CWalletTx *wtx = &entry.second;
|
||||
txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx));
|
||||
}
|
||||
|
||||
nOrderPosNext = 0;
|
||||
std::vector<int64_t> nOrderPosOffsets;
|
||||
for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
|
||||
{
|
||||
CWalletTx *const pwtx = (*it).second;
|
||||
int64_t& nOrderPos = pwtx->nOrderPos;
|
||||
|
||||
if (nOrderPos == -1)
|
||||
{
|
||||
nOrderPos = nOrderPosNext++;
|
||||
nOrderPosOffsets.push_back(nOrderPos);
|
||||
|
||||
if (!walletdb.WriteTx(*pwtx))
|
||||
return DB_LOAD_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t nOrderPosOff = 0;
|
||||
for(const int64_t& nOffsetStart : nOrderPosOffsets)
|
||||
{
|
||||
if (nOrderPos >= nOffsetStart)
|
||||
++nOrderPosOff;
|
||||
}
|
||||
nOrderPos += nOrderPosOff;
|
||||
nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
|
||||
|
||||
if (!nOrderPosOff)
|
||||
continue;
|
||||
|
||||
// Since we're changing the order, write it back
|
||||
if (!walletdb.WriteTx(*pwtx))
|
||||
return DB_LOAD_FAIL;
|
||||
}
|
||||
}
|
||||
walletdb.WriteOrderPosNext(nOrderPosNext);
|
||||
|
||||
return DB_LOAD_OK;
|
||||
}
|
||||
|
||||
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // nOrderPosNext
|
||||
|
@ -1417,31 +1473,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
|
|||
return nRet;
|
||||
}
|
||||
|
||||
CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapWallet
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
|
||||
// First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
|
||||
TxItems txOrdered;
|
||||
|
||||
// Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
|
||||
// would make this much faster for applications that do this a lot.
|
||||
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
CWalletTx* wtx = &((*it).second);
|
||||
txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
|
||||
}
|
||||
acentries.clear();
|
||||
walletdb.ListAccountCreditDebit(strAccount, acentries);
|
||||
for (CAccountingEntry& entry : acentries)
|
||||
{
|
||||
txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
|
||||
}
|
||||
|
||||
return txOrdered;
|
||||
}
|
||||
|
||||
void CWallet::MarkDirty()
|
||||
{
|
||||
{
|
||||
|
@ -1584,7 +1615,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
|||
if (fFromLoadWallet)
|
||||
{
|
||||
mapWallet[hash] = wtxIn;
|
||||
mapWallet[hash].BindWallet(this);
|
||||
CWalletTx& wtx = mapWallet[hash];
|
||||
wtx.BindWallet(this);
|
||||
wtxOrdered.insert(make_pair(wtx.nOrderPos, &wtx));
|
||||
UpdateNullifierNoteMapWithTx(mapWallet[hash]);
|
||||
AddToSpends(hash);
|
||||
}
|
||||
|
@ -1601,6 +1634,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
|||
{
|
||||
wtx.nTimeReceived = GetTime();
|
||||
wtx.nOrderPos = IncOrderPosNext(pwalletdb);
|
||||
wtxOrdered.insert(make_pair(wtx.nOrderPos, &wtx));
|
||||
|
||||
wtx.nTimeSmart = wtx.nTimeReceived;
|
||||
if (!wtxIn.hashBlock.IsNull())
|
||||
|
@ -1612,23 +1646,16 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
|||
{
|
||||
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
|
||||
int64_t latestTolerated = latestNow + 300;
|
||||
std::list<CAccountingEntry> acentries;
|
||||
TxItems txOrdered = OrderedTxItems(acentries);
|
||||
for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
|
||||
const TxItems & txOrdered = wtxOrdered;
|
||||
for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
|
||||
{
|
||||
CWalletTx *const pwtx = (*it).second.first;
|
||||
CWalletTx *const pwtx = (*it).second;
|
||||
if (pwtx == &wtx)
|
||||
continue;
|
||||
CAccountingEntry *const pacentry = (*it).second.second;
|
||||
int64_t nSmartTime;
|
||||
if (pwtx)
|
||||
{
|
||||
nSmartTime = pwtx->nTimeSmart;
|
||||
if (!nSmartTime)
|
||||
nSmartTime = pwtx->nTimeReceived;
|
||||
}
|
||||
else
|
||||
nSmartTime = pacentry->nTime;
|
||||
nSmartTime = pwtx->nTimeSmart;
|
||||
if (!nSmartTime)
|
||||
nSmartTime = pwtx->nTimeReceived;
|
||||
if (nSmartTime <= latestTolerated)
|
||||
{
|
||||
latestEntry = nSmartTime;
|
||||
|
@ -1680,7 +1707,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
|||
|
||||
// Write to disk
|
||||
if (fInsertedNew || fUpdated)
|
||||
if (!wtx.WriteToDisk(pwalletdb))
|
||||
if (!pwalletdb->WriteTx(wtx))
|
||||
return false;
|
||||
|
||||
// Break debit/credit balance caches:
|
||||
|
@ -2538,13 +2565,12 @@ int CWalletTx::GetRequestCount() const
|
|||
}
|
||||
|
||||
// GetAmounts will determine the transparent debits and credits for a given wallet tx.
|
||||
void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
||||
list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
|
||||
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
||||
std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const
|
||||
{
|
||||
nFee = 0;
|
||||
listReceived.clear();
|
||||
listSent.clear();
|
||||
strSentAccount = strFromAccount;
|
||||
|
||||
// Is this tx sent/signed by me?
|
||||
CAmount nDebit = GetDebit(filter);
|
||||
|
@ -2653,47 +2679,6 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
|||
|
||||
}
|
||||
|
||||
void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
|
||||
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
|
||||
{
|
||||
nReceived = nSent = nFee = 0;
|
||||
|
||||
CAmount allFee;
|
||||
string strSentAccount;
|
||||
list<COutputEntry> listReceived;
|
||||
list<COutputEntry> listSent;
|
||||
GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
|
||||
|
||||
if (strAccount == strSentAccount)
|
||||
{
|
||||
for (const COutputEntry& s : listSent)
|
||||
nSent += s.amount;
|
||||
nFee = allFee;
|
||||
}
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
for (const COutputEntry& r : listReceived)
|
||||
{
|
||||
if (pwallet->mapAddressBook.count(r.destination))
|
||||
{
|
||||
map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
|
||||
if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
|
||||
nReceived += r.amount;
|
||||
}
|
||||
else if (strAccount.empty())
|
||||
{
|
||||
nReceived += r.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
|
||||
{
|
||||
return pwalletdb->WriteTx(GetHash(), *this);
|
||||
}
|
||||
|
||||
void CWallet::WitnessNoteCommitment(std::vector<uint256> commitments,
|
||||
std::vector<std::optional<SproutWitness>>& witnesses,
|
||||
uint256 &final_anchor)
|
||||
|
@ -2820,7 +2805,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
|||
for (auto hash : myTxHashes) {
|
||||
CWalletTx wtx = mapWallet[hash];
|
||||
if (!wtx.mapSaplingNoteData.empty()) {
|
||||
if (!wtx.WriteToDisk(&walletdb)) {
|
||||
if (!walletdb.WriteTx(wtx)) {
|
||||
LogPrintf("Rescanning... WriteToDisk failed to update Sapling note data for: %s\n", hash.ToString());
|
||||
}
|
||||
}
|
||||
|
@ -2964,17 +2949,29 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
|
||||
CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const
|
||||
{
|
||||
if (pwallet == 0)
|
||||
if (pwallet == nullptr)
|
||||
return 0;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
if (fUseCache && fAvailableCreditCached)
|
||||
return nAvailableCreditCached;
|
||||
CAmount* cache = nullptr;
|
||||
bool* cache_used = nullptr;
|
||||
|
||||
if (filter == ISMINE_SPENDABLE) {
|
||||
cache = &nAvailableCreditCached;
|
||||
cache_used = &fAvailableCreditCached;
|
||||
} else if (filter == ISMINE_WATCH_ONLY) {
|
||||
cache = &nAvailableWatchCreditCached;
|
||||
cache_used = &fAvailableWatchCreditCached;
|
||||
}
|
||||
|
||||
if (fUseCache && cache_used && *cache_used) {
|
||||
return *cache;
|
||||
}
|
||||
|
||||
CAmount nCredit = 0;
|
||||
uint256 hashTx = GetHash();
|
||||
|
@ -2983,18 +2980,20 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
|
|||
if (!pwallet->IsSpent(hashTx, i))
|
||||
{
|
||||
const CTxOut &txout = vout[i];
|
||||
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
|
||||
nCredit += pwallet->GetCredit(txout, filter);
|
||||
if (!MoneyRange(nCredit))
|
||||
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
nAvailableCreditCached = nCredit;
|
||||
fAvailableCreditCached = true;
|
||||
if (cache) {
|
||||
*cache = nCredit;
|
||||
*cache_used = true;
|
||||
}
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
|
||||
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
|
||||
{
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
|
||||
{
|
||||
|
@ -3008,35 +3007,6 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
|
||||
{
|
||||
if (pwallet == 0)
|
||||
return 0;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
if (fUseCache && fAvailableWatchCreditCached)
|
||||
return nAvailableWatchCreditCached;
|
||||
|
||||
CAmount nCredit = 0;
|
||||
for (unsigned int i = 0; i < vout.size(); i++)
|
||||
{
|
||||
if (!pwallet->IsSpent(GetHash(), i))
|
||||
{
|
||||
const CTxOut &txout = vout[i];
|
||||
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
|
||||
if (!MoneyRange(nCredit))
|
||||
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
nAvailableWatchCreditCached = nCredit;
|
||||
fAvailableWatchCreditCached = true;
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetChange() const
|
||||
{
|
||||
if (fChangeCached)
|
||||
|
@ -3131,16 +3101,17 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
|
|||
*/
|
||||
|
||||
|
||||
CAmount CWallet::GetBalance() const
|
||||
CAmount CWallet::GetBalance(const isminefilter& filter, const int min_depth) const
|
||||
{
|
||||
CAmount nTotal = 0;
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
for (const auto& entry : mapWallet)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
if (pcoin->IsTrusted())
|
||||
nTotal += pcoin->GetAvailableCredit();
|
||||
const CWalletTx* pcoin = &entry.second;
|
||||
if (pcoin->IsTrusted() && pcoin->GetDepthInMainChain() >= min_depth) {
|
||||
nTotal += pcoin->GetAvailableCredit(true, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3152,9 +3123,9 @@ CAmount CWallet::GetUnconfirmedBalance() const
|
|||
CAmount nTotal = 0;
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
for (const auto& entry : mapWallet)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
const CWalletTx* pcoin = &entry.second;
|
||||
if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
|
||||
nTotal += pcoin->GetAvailableCredit();
|
||||
}
|
||||
|
@ -3167,41 +3138,25 @@ CAmount CWallet::GetImmatureBalance() const
|
|||
CAmount nTotal = 0;
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
for (const auto& entry : mapWallet)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
const CWalletTx* pcoin = &entry.second;
|
||||
nTotal += pcoin->GetImmatureCredit();
|
||||
}
|
||||
}
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
CAmount CWallet::GetWatchOnlyBalance() const
|
||||
{
|
||||
CAmount nTotal = 0;
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
if (pcoin->IsTrusted())
|
||||
nTotal += pcoin->GetAvailableWatchOnlyCredit();
|
||||
}
|
||||
}
|
||||
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
|
||||
{
|
||||
CAmount nTotal = 0;
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
for (const auto& entry : mapWallet)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
const CWalletTx* pcoin = &entry.second;
|
||||
if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
|
||||
nTotal += pcoin->GetAvailableWatchOnlyCredit();
|
||||
nTotal += pcoin->GetAvailableCredit(true, ISMINE_WATCH_ONLY);
|
||||
}
|
||||
}
|
||||
return nTotal;
|
||||
|
@ -3212,15 +3167,54 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
|
|||
CAmount nTotal = 0;
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
for (const auto& entry : mapWallet)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
const CWalletTx* pcoin = &entry.second;
|
||||
nTotal += pcoin->GetImmatureWatchOnlyCredit();
|
||||
}
|
||||
}
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
// Calculate total balance in a different way from GetBalance. The biggest
|
||||
// difference is that GetBalance sums up all unspent TxOuts paying to the
|
||||
// wallet, while this sums up both spent and unspent TxOuts paying to the
|
||||
// wallet, and then subtracts the values of TxIns spending from the wallet. This
|
||||
// also has fewer restrictions on which unconfirmed transactions are considered
|
||||
// trusted.
|
||||
CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
||||
CAmount balance = 0;
|
||||
for (const auto& entry : mapWallet) {
|
||||
const CWalletTx& wtx = entry.second;
|
||||
const int depth = wtx.GetDepthInMainChain();
|
||||
if (depth < 0 || !CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Loop through tx outputs and add incoming payments. For outgoing txs,
|
||||
// treat change outputs specially, as part of the amount debited.
|
||||
CAmount debit = wtx.GetDebit(filter);
|
||||
const bool outgoing = debit > 0;
|
||||
for (const CTxOut& out : wtx.vout) {
|
||||
if (outgoing && IsChange(out)) {
|
||||
debit -= out.nValue;
|
||||
} else if (IsMine(out) & filter && depth >= minDepth) {
|
||||
balance += out.nValue;
|
||||
}
|
||||
}
|
||||
|
||||
// For outgoing txs, subtract amount debited.
|
||||
if (outgoing) {
|
||||
balance -= debit;
|
||||
}
|
||||
}
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
void CWallet::AvailableCoins(vector<COutput>& vCoins,
|
||||
bool fOnlyConfirmed,
|
||||
const CCoinControl *coinControl,
|
||||
|
@ -4348,20 +4342,6 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
set<CTxDestination> result;
|
||||
for (const std::pair<CTxDestination, CAddressBookData>& item : mapAddressBook)
|
||||
{
|
||||
const CTxDestination& address = item.first;
|
||||
const string& strName = item.second.name;
|
||||
if (strName == strAccount)
|
||||
result.insert(address);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CReserveKey::GetReservedKey(CPubKey& pubkey)
|
||||
{
|
||||
if (nIndex == -1)
|
||||
|
@ -4627,8 +4607,8 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
|
|||
}
|
||||
|
||||
// Extract block timestamps for those keys
|
||||
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) {
|
||||
mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be off
|
||||
for (const auto& entry : mapKeyFirstBlock) {
|
||||
mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4857,9 +4837,8 @@ bool CWallet::InitLoadWallet(bool clearWitnessCaches)
|
|||
copyTo->nTimeReceived = copyFrom->nTimeReceived;
|
||||
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
||||
copyTo->fFromMe = copyFrom->fFromMe;
|
||||
copyTo->strFromAccount = copyFrom->strFromAccount;
|
||||
copyTo->nOrderPos = copyFrom->nOrderPos;
|
||||
copyTo->WriteToDisk(&walletdb);
|
||||
walletdb.WriteTx(*copyTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ public:
|
|||
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* A transaction with a bunch of additional info that only the owner cares about.
|
||||
* It includes any unrecorded transactions needed to link it back to the block chain.
|
||||
*/
|
||||
|
@ -409,6 +409,30 @@ private:
|
|||
const CWallet* pwallet;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Key/value map with information about the transaction.
|
||||
*
|
||||
* The following keys can be read and written through the map and are
|
||||
* serialized in the wallet database:
|
||||
*
|
||||
* "comment", "to" - comment strings provided to sendtoaddress,
|
||||
* and sendmany wallet RPCs
|
||||
* "replaces_txid" - txid (as HexStr) of transaction replaced by
|
||||
* bumpfee on transaction created by bumpfee
|
||||
* "replaced_by_txid" - txid (as HexStr) of transaction created by
|
||||
* bumpfee on transaction replaced by bumpfee
|
||||
* "from", "message" - obsolete fields that could be set in UI prior to
|
||||
* 2011 (removed in commit 4d9b223)
|
||||
*
|
||||
* The following keys are serialized in the wallet database, but shouldn't
|
||||
* be read or written through the map (they will be temporarily added and
|
||||
* removed from the map during serialization):
|
||||
*
|
||||
* "n" - serialized nOrderPos value
|
||||
* "timesmart" - serialized nTimeSmart value
|
||||
* "spent" - serialized vfSpent value that existed prior to
|
||||
* 2014 (removed in commit 93a18a3)
|
||||
*/
|
||||
mapValue_t mapValue;
|
||||
mapSproutNoteData_t mapSproutNoteData;
|
||||
mapSaplingNoteData_t mapSaplingNoteData;
|
||||
|
@ -417,7 +441,6 @@ public:
|
|||
unsigned int nTimeReceived; //!< time received by this node
|
||||
unsigned int nTimeSmart;
|
||||
char fFromMe;
|
||||
std::string strFromAccount;
|
||||
int64_t nOrderPos; //!< position in ordered transaction list
|
||||
|
||||
// memory only
|
||||
|
@ -471,7 +494,6 @@ public:
|
|||
nTimeReceived = 0;
|
||||
nTimeSmart = 0;
|
||||
fFromMe = false;
|
||||
strFromAccount.clear();
|
||||
fDebitCached = false;
|
||||
fCreditCached = false;
|
||||
fImmatureCreditCached = false;
|
||||
|
@ -503,7 +525,7 @@ public:
|
|||
|
||||
if (!ser_action.ForRead())
|
||||
{
|
||||
mapValue["fromaccount"] = strFromAccount;
|
||||
mapValue["fromaccount"] = "";
|
||||
|
||||
WriteOrderPos(nOrderPos, mapValue);
|
||||
|
||||
|
@ -528,10 +550,7 @@ public:
|
|||
|
||||
if (ser_action.ForRead())
|
||||
{
|
||||
strFromAccount = mapValue["fromaccount"];
|
||||
|
||||
ReadOrderPos(nOrderPos, mapValue);
|
||||
|
||||
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
|
||||
}
|
||||
|
||||
|
@ -584,16 +603,12 @@ public:
|
|||
CAmount GetDebit(const isminefilter& filter) const;
|
||||
CAmount GetCredit(const isminefilter& filter) const;
|
||||
CAmount GetImmatureCredit(bool fUseCache=true) const;
|
||||
CAmount GetAvailableCredit(bool fUseCache=true) const;
|
||||
CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const;
|
||||
CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const;
|
||||
CAmount GetAvailableCredit(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const;
|
||||
CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const;
|
||||
CAmount GetChange() const;
|
||||
|
||||
void GetAmounts(std::list<COutputEntry>& listReceived,
|
||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
|
||||
|
||||
void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
|
||||
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
|
||||
std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const;
|
||||
|
||||
bool IsFromMe(const isminefilter& filter) const
|
||||
{
|
||||
|
@ -602,8 +617,6 @@ public:
|
|||
|
||||
bool IsTrusted() const;
|
||||
|
||||
bool WriteToDisk(CWalletDB *pwalletdb);
|
||||
|
||||
int64_t GetTxTime() const;
|
||||
int GetRequestCount() const;
|
||||
|
||||
|
@ -662,89 +675,6 @@ public:
|
|||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
//! Note: strAccount is serialized as part of the key, not here.
|
||||
READWRITE(nCreditDebit);
|
||||
READWRITE(nTime);
|
||||
READWRITE(LIMITED_STRING(strOtherAccount, 65536));
|
||||
|
||||
if (!ser_action.ForRead())
|
||||
{
|
||||
WriteOrderPos(nOrderPos, mapValue);
|
||||
|
||||
if (!(mapValue.empty() && _ssExtra.empty()))
|
||||
{
|
||||
CDataStream ss(s.GetType(), s.GetVersion());
|
||||
ss.insert(ss.begin(), '\0');
|
||||
ss << mapValue;
|
||||
ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
|
||||
strComment.append(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
READWRITE(LIMITED_STRING(strComment, 65536));
|
||||
|
||||
size_t nSepPos = strComment.find("\0", 0, 1);
|
||||
if (ser_action.ForRead())
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
|
||||
* and provides the ability to create new transactions.
|
||||
*/
|
||||
|
@ -836,7 +766,7 @@ protected:
|
|||
// (i.e. are purely transparent), as well as shielding and unshielding
|
||||
// transactions in which we only have transparent addresses involved.
|
||||
if (!(wtx.mapSproutNoteData.empty() && wtx.mapSaplingNoteData.empty())) {
|
||||
if (!walletdb.WriteTx(wtxItem.first, wtx)) {
|
||||
if (!walletdb.WriteTx(wtx)) {
|
||||
LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n");
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
|
@ -991,6 +921,9 @@ public:
|
|||
|
||||
std::map<uint256, CWalletTx> mapWallet;
|
||||
|
||||
typedef std::multimap<int64_t, CWalletTx*> TxItems;
|
||||
TxItems wtxOrdered;
|
||||
|
||||
int64_t nOrderPosNext;
|
||||
std::map<uint256, int> mapRequestCount;
|
||||
|
||||
|
@ -1153,21 +1086,13 @@ public:
|
|||
bool LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||
const std::vector<unsigned char> &vchCryptedSecret);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Increment the next transaction order id
|
||||
* @return next transaction order id
|
||||
*/
|
||||
int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
|
||||
|
||||
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
|
||||
typedef std::multimap<int64_t, TxPair > TxItems;
|
||||
|
||||
/**
|
||||
* Get the wallet's activity log
|
||||
* @return multimap of ordered transactions and accounting entries
|
||||
* @warning Returned pointers are *only* valid within the scope of passed acentries
|
||||
*/
|
||||
TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
|
||||
DBErrors ReorderTransactions();
|
||||
|
||||
void MarkDirty();
|
||||
bool UpdateNullifierNoteMap();
|
||||
|
@ -1186,12 +1111,12 @@ public:
|
|||
void ReacceptWalletTransactions();
|
||||
void ResendWalletTransactions(int64_t nBestBlockTime);
|
||||
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
|
||||
CAmount GetBalance() const;
|
||||
CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
|
||||
CAmount GetUnconfirmedBalance() const;
|
||||
CAmount GetImmatureBalance() const;
|
||||
CAmount GetWatchOnlyBalance() const;
|
||||
CAmount GetUnconfirmedWatchOnlyBalance() const;
|
||||
CAmount GetImmatureWatchOnlyBalance() const;
|
||||
CAmount GetLegacyBalance(const isminefilter& filter, int minDepth) const;
|
||||
|
||||
/**
|
||||
* Insert additional inputs into the transaction by
|
||||
|
@ -1231,8 +1156,6 @@ public:
|
|||
std::set< std::set<CTxDestination> > GetAddressGroupings();
|
||||
std::map<CTxDestination, CAmount> GetAddressBalances();
|
||||
|
||||
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
|
||||
|
||||
std::optional<uint256> GetSproutNoteNullifier(
|
||||
const JSDescription& jsdesc,
|
||||
const libzcash::SproutPaymentAddress& address,
|
||||
|
@ -1302,7 +1225,7 @@ public:
|
|||
LOCK(cs_wallet);
|
||||
mapRequestCount[hash] = 0;
|
||||
};
|
||||
|
||||
|
||||
unsigned int GetKeyPoolSize()
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // setKeyPool
|
||||
|
@ -1328,8 +1251,8 @@ public:
|
|||
|
||||
//! Verify the wallet database and perform salvage if required
|
||||
static bool Verify();
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Address book entry changed.
|
||||
* @note called with lock cs_wallet held.
|
||||
*/
|
||||
|
@ -1338,7 +1261,7 @@ public:
|
|||
const std::string &purpose,
|
||||
ChangeType status)> NotifyAddressBookChanged;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Wallet transaction added, removed or updated.
|
||||
* @note called with lock cs_wallet held.
|
||||
*/
|
||||
|
@ -1379,7 +1302,7 @@ public:
|
|||
bool LoadHDSeed(const HDSeed& key);
|
||||
/* Set the current encrypted HD seed, without saving it to disk (used by LoadWallet) */
|
||||
bool LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed);
|
||||
|
||||
|
||||
/* Find notes filtered by payment address, min depth, ability to spend */
|
||||
void GetFilteredNotes(std::vector<SproutNoteEntry>& sproutEntries,
|
||||
std::vector<SaplingNoteEntry>& saplingEntries,
|
||||
|
@ -1434,37 +1357,6 @@ public:
|
|||
void KeepScript() { KeepKey(); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Account information.
|
||||
* Stored in wallet with key "acc"+string account name.
|
||||
*/
|
||||
class CAccount
|
||||
{
|
||||
public:
|
||||
CPubKey vchPubKey;
|
||||
|
||||
CAccount()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
vchPubKey = CPubKey();
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(vchPubKey);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Shielded key and address generalizations
|
||||
//
|
||||
|
@ -1549,7 +1441,7 @@ private:
|
|||
std::optional<std::string> hdKeypath; // currently sapling only
|
||||
std::optional<std::string> seedFpStr; // currently sapling only
|
||||
bool log;
|
||||
public:
|
||||
public:
|
||||
AddSpendingKeyToWallet(CWallet *wallet, const Consensus::Params ¶ms) :
|
||||
m_wallet(wallet), params(params), nTime(1), hdKeypath(std::nullopt), seedFpStr(std::nullopt), log(false) {}
|
||||
AddSpendingKeyToWallet(
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -60,10 +61,10 @@ bool CWalletDB::ErasePurpose(const string& strPurpose)
|
|||
return Erase(make_pair(string("purpose"), strPurpose));
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
|
||||
bool CWalletDB::WriteTx(const CWalletTx& wtx)
|
||||
{
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("tx"), hash), wtx);
|
||||
return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
|
||||
}
|
||||
|
||||
bool CWalletDB::EraseTx(uint256 hash)
|
||||
|
@ -284,158 +285,6 @@ bool CWalletDB::WriteMinVersion(int nVersion)
|
|||
return Write(std::string("minversion"), nVersion);
|
||||
}
|
||||
|
||||
bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
|
||||
{
|
||||
account.SetNull();
|
||||
return Read(make_pair(string("acc"), strAccount), account);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
|
||||
{
|
||||
return Write(make_pair(string("acc"), strAccount), account);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
|
||||
{
|
||||
return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
|
||||
{
|
||||
return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
|
||||
}
|
||||
|
||||
CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
|
||||
{
|
||||
list<CAccountingEntry> entries;
|
||||
ListAccountCreditDebit(strAccount, entries);
|
||||
|
||||
CAmount nCreditDebit = 0;
|
||||
for (const CAccountingEntry& entry : entries)
|
||||
nCreditDebit += entry.nCreditDebit;
|
||||
|
||||
return nCreditDebit;
|
||||
}
|
||||
|
||||
void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
|
||||
{
|
||||
bool fAllAccounts = (strAccount == "*");
|
||||
|
||||
Dbc* pcursor = GetCursor();
|
||||
if (!pcursor)
|
||||
throw runtime_error("CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
|
||||
unsigned int fFlags = DB_SET_RANGE;
|
||||
while (true)
|
||||
{
|
||||
// Read next record
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
if (fFlags == DB_SET_RANGE)
|
||||
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
|
||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
||||
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
|
||||
fFlags = DB_NEXT;
|
||||
if (ret == DB_NOTFOUND)
|
||||
break;
|
||||
else if (ret != 0)
|
||||
{
|
||||
pcursor->close();
|
||||
throw runtime_error("CWalletDB::ListAccountCreditDebit(): error scanning DB");
|
||||
}
|
||||
|
||||
// Unserialize
|
||||
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();
|
||||
}
|
||||
|
||||
DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
// Old wallets didn't have any defined order for transactions
|
||||
// Probably a bad idea to change the output of this
|
||||
|
||||
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
|
||||
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
|
||||
typedef multimap<int64_t, TxPair > TxItems;
|
||||
TxItems txByTime;
|
||||
|
||||
for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
|
||||
{
|
||||
CWalletTx* wtx = &((*it).second);
|
||||
txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
|
||||
}
|
||||
list<CAccountingEntry> acentries;
|
||||
ListAccountCreditDebit("", acentries);
|
||||
for (CAccountingEntry& entry : acentries)
|
||||
{
|
||||
txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
|
||||
}
|
||||
|
||||
int64_t& nOrderPosNext = pwallet->nOrderPosNext;
|
||||
nOrderPosNext = 0;
|
||||
std::vector<int64_t> nOrderPosOffsets;
|
||||
for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
|
||||
{
|
||||
CWalletTx *const pwtx = (*it).second.first;
|
||||
CAccountingEntry *const pacentry = (*it).second.second;
|
||||
int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
|
||||
|
||||
if (nOrderPos == -1)
|
||||
{
|
||||
nOrderPos = nOrderPosNext++;
|
||||
nOrderPosOffsets.push_back(nOrderPos);
|
||||
|
||||
if (pwtx)
|
||||
{
|
||||
if (!WriteTx(pwtx->GetHash(), *pwtx))
|
||||
return DB_LOAD_FAIL;
|
||||
}
|
||||
else
|
||||
if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
|
||||
return DB_LOAD_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t nOrderPosOff = 0;
|
||||
for (const int64_t& nOffsetStart : nOrderPosOffsets)
|
||||
{
|
||||
if (nOrderPos >= nOffsetStart)
|
||||
++nOrderPosOff;
|
||||
}
|
||||
nOrderPos += nOrderPosOff;
|
||||
nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
|
||||
|
||||
if (!nOrderPosOff)
|
||||
continue;
|
||||
|
||||
// Since we're changing the order, write it back
|
||||
if (pwtx)
|
||||
{
|
||||
if (!WriteTx(pwtx->GetHash(), *pwtx))
|
||||
return DB_LOAD_FAIL;
|
||||
}
|
||||
else
|
||||
if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
|
||||
return DB_LOAD_FAIL;
|
||||
}
|
||||
}
|
||||
WriteOrderPosNext(nOrderPosNext);
|
||||
|
||||
return DB_LOAD_OK;
|
||||
}
|
||||
|
||||
class CWalletScanState {
|
||||
public:
|
||||
unsigned int nKeys;
|
||||
|
@ -506,9 +355,10 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
{
|
||||
char fTmp;
|
||||
char fUnused;
|
||||
ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
|
||||
strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
|
||||
wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
|
||||
std::string unused_string;
|
||||
ssValue >> fTmp >> fUnused >> unused_string;
|
||||
strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
|
||||
wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
|
||||
wtx.fTimeReceivedIsTxTime = fTmp;
|
||||
}
|
||||
else
|
||||
|
@ -524,23 +374,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
|
||||
pwallet->AddToWallet(wtx, true, NULL);
|
||||
}
|
||||
else if (strType == "acentry")
|
||||
{
|
||||
string strAccount;
|
||||
ssKey >> strAccount;
|
||||
uint64_t nNumber;
|
||||
ssKey >> nNumber;
|
||||
if (nNumber > nAccountingEntryNumber)
|
||||
nAccountingEntryNumber = nNumber;
|
||||
|
||||
if (!wss.fAnyUnordered)
|
||||
{
|
||||
CAccountingEntry acentry;
|
||||
ssValue >> acentry;
|
||||
if (acentry.nOrderPos == -1)
|
||||
wss.fAnyUnordered = true;
|
||||
}
|
||||
}
|
||||
else if (strType == "watchs")
|
||||
{
|
||||
CScript script;
|
||||
|
@ -998,7 +831,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
||||
|
||||
for (uint256 hash : wss.vWalletUpgrade)
|
||||
WriteTx(hash, pwallet->mapWallet[hash]);
|
||||
WriteTx(pwallet->mapWallet[hash]);
|
||||
|
||||
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
|
||||
if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
|
||||
|
@ -1008,7 +841,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
WriteVersion(CLIENT_VERSION);
|
||||
|
||||
if (wss.fAnyUnordered)
|
||||
result = ReorderTransactions(pwallet);
|
||||
result = pwallet->ReorderTransactions();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
static const bool DEFAULT_FLUSHWALLET = true;
|
||||
|
||||
class CAccount;
|
||||
class CAccountingEntry;
|
||||
struct CBlockLocator;
|
||||
class CKeyPool;
|
||||
class CMasterKey;
|
||||
|
@ -132,7 +130,7 @@ public:
|
|||
bool WritePurpose(const std::string& strAddress, const std::string& purpose);
|
||||
bool ErasePurpose(const std::string& strAddress);
|
||||
|
||||
bool WriteTx(uint256 hash, const CWalletTx& wtx);
|
||||
bool WriteTx(const CWalletTx& wtx);
|
||||
bool EraseTx(uint256 hash);
|
||||
|
||||
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);
|
||||
|
@ -159,19 +157,11 @@ public:
|
|||
|
||||
bool WriteMinVersion(int nVersion);
|
||||
|
||||
bool ReadAccount(const std::string& strAccount, CAccount& account);
|
||||
bool WriteAccount(const std::string& strAccount, const CAccount& account);
|
||||
|
||||
/// Write destination data key,value tuple to database
|
||||
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
|
||||
/// Erase destination data tuple from wallet database
|
||||
bool EraseDestData(const std::string &address, const std::string &key);
|
||||
|
||||
bool WriteAccountingEntry(const CAccountingEntry& acentry);
|
||||
CAmount GetAccountCreditDebit(const std::string& strAccount);
|
||||
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
|
||||
|
||||
DBErrors ReorderTransactions(CWallet* pwallet);
|
||||
DBErrors LoadWallet(CWallet* pwallet);
|
||||
DBErrors FindWalletTxToZap(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
|
||||
DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
|
||||
|
@ -209,7 +199,6 @@ private:
|
|||
CWalletDB(const CWalletDB&);
|
||||
void operator=(const CWalletDB&);
|
||||
|
||||
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
|
||||
};
|
||||
|
||||
bool BackupWallet(const CWallet& wallet, const std::string& strDest);
|
||||
|
|
Loading…
Reference in New Issue