@@ -1426,6 +1426,17 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1426
1426
entry.push_back (Pair (" address" , addr.ToString ()));
1427
1427
}
1428
1428
1429
+ /* *
1430
+ * List transactions based on the given criteria.
1431
+ *
1432
+ * @param pwallet The wallet.
1433
+ * @param wtx The wallet transaction.
1434
+ * @param strAccount The account, if any, or "*" for all.
1435
+ * @param nMinDepth The minimum confirmation depth.
1436
+ * @param fLong Whether to include the JSON version of the transaction.
1437
+ * @param ret The UniValue into which the result is stored.
1438
+ * @param filter The "is mine" filter bool.
1439
+ */
1429
1440
void ListTransactions (CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong , UniValue& ret, const isminefilter& filter)
1430
1441
{
1431
1442
CAmount nFee;
@@ -1742,14 +1753,18 @@ UniValue listsinceblock(const JSONRPCRequest& request)
1742
1753
return NullUniValue;
1743
1754
}
1744
1755
1745
- if (request.fHelp || request.params .size () > 3 )
1756
+ if (request.fHelp || request.params .size () > 4 )
1746
1757
throw std::runtime_error (
1747
- " listsinceblock ( \" blockhash\" target_confirmations include_watchonly)\n "
1748
- " \n Get all transactions in blocks since block [blockhash], or all transactions if omitted\n "
1758
+ " listsinceblock ( \" blockhash\" target_confirmations include_watchonly include_removed )\n "
1759
+ " \n Get all transactions in blocks since block [blockhash], or all transactions if omitted.\n "
1760
+ " If \" blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n "
1761
+ " Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \" removed\" array.\n "
1749
1762
" \n Arguments:\n "
1750
1763
" 1. \" blockhash\" (string, optional) The block hash to list transactions since\n "
1751
- " 2. target_confirmations: (numeric, optional) The confirmations required, must be 1 or more\n "
1752
- " 3. include_watchonly: (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')"
1764
+ " 2. target_confirmations: (numeric, optional, default=1) The confirmations required, must be 1 or more\n "
1765
+ " 3. include_watchonly: (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n "
1766
+ " 4. include_removed: (bool, optional, default=true) Show transactions that were removed due to a reorg in the \" removed\" array\n "
1767
+ " (not guaranteed to work on pruned nodes)\n "
1753
1768
" \n Result:\n "
1754
1769
" {\n "
1755
1770
" \" transactions\" : [\n "
@@ -1774,7 +1789,11 @@ UniValue listsinceblock(const JSONRPCRequest& request)
1774
1789
" \" comment\" : \" ...\" , (string) If a comment is associated with the transaction.\n "
1775
1790
" \" label\" : \" label\" (string) A comment for the address/transaction, if any\n "
1776
1791
" \" to\" : \" ...\" , (string) If a comment to is associated with the transaction.\n "
1777
- " ],\n "
1792
+ " ],\n "
1793
+ " \" removed\" : [\n "
1794
+ " <structure is the same as \" transactions\" above, only present if include_removed=true>\n "
1795
+ " Note: transactions that were readded in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n "
1796
+ " ],\n "
1778
1797
" \" lastblock\" : \" lastblockhash\" (string) The hash of the last block\n "
1779
1798
" }\n "
1780
1799
" \n Examples:\n "
@@ -1785,21 +1804,19 @@ UniValue listsinceblock(const JSONRPCRequest& request)
1785
1804
1786
1805
LOCK2 (cs_main, pwallet->cs_wallet );
1787
1806
1788
- const CBlockIndex *pindex = NULL ;
1807
+ const CBlockIndex* pindex = NULL ; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
1808
+ const CBlockIndex* paltindex = NULL ; // Block index of the specified block, even if it's in a deactivated chain.
1789
1809
int target_confirms = 1 ;
1790
1810
isminefilter filter = ISMINE_SPENDABLE;
1791
1811
1792
- if (!request.params [0 ].isNull ())
1793
- {
1812
+ if (!request.params [0 ].isNull ()) {
1794
1813
uint256 blockId;
1795
1814
1796
1815
blockId.SetHex (request.params [0 ].get_str ());
1797
1816
BlockMap::iterator it = mapBlockIndex.find (blockId);
1798
- if (it != mapBlockIndex.end ())
1799
- {
1800
- pindex = it->second ;
1801
- if (chainActive[pindex->nHeight ] != pindex)
1802
- {
1817
+ if (it != mapBlockIndex.end ()) {
1818
+ paltindex = pindex = it->second ;
1819
+ if (chainActive[pindex->nHeight ] != pindex) {
1803
1820
// the block being asked for is a part of a deactivated chain;
1804
1821
// we don't want to depend on its perceived height in the block
1805
1822
// chain, we want to instead use the last common ancestor
@@ -1808,35 +1825,56 @@ UniValue listsinceblock(const JSONRPCRequest& request)
1808
1825
}
1809
1826
}
1810
1827
1811
- if (!request.params [1 ].isNull ())
1812
- {
1828
+ if (!request.params [1 ].isNull ()) {
1813
1829
target_confirms = request.params [1 ].get_int ();
1814
1830
1815
- if (target_confirms < 1 )
1831
+ if (target_confirms < 1 ) {
1816
1832
throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter" );
1833
+ }
1817
1834
}
1818
1835
1819
- if (request.params .size () > 2 && request.params [2 ].get_bool ())
1820
- {
1836
+ if (!request.params [2 ].isNull () && request.params [2 ].get_bool ()) {
1821
1837
filter = filter | ISMINE_WATCH_ONLY;
1822
1838
}
1823
1839
1840
+ bool include_removed = (request.params [3 ].isNull () || request.params [3 ].get_bool ());
1841
+
1824
1842
int depth = pindex ? (1 + chainActive.Height () - pindex->nHeight ) : -1 ;
1825
1843
1826
1844
UniValue transactions (UniValue::VARR);
1827
1845
1828
1846
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet ) {
1829
1847
CWalletTx tx = pairWtx.second ;
1830
1848
1831
- if (depth == -1 || tx.GetDepthInMainChain () < depth)
1849
+ if (depth == -1 || tx.GetDepthInMainChain () < depth) {
1832
1850
ListTransactions (pwallet, tx, " *" , 0 , true , transactions, filter);
1851
+ }
1852
+ }
1853
+
1854
+ // when a reorg'd block is requested, we also list any relevant transactions
1855
+ // in the blocks of the chain that was detached
1856
+ UniValue removed (UniValue::VARR);
1857
+ while (include_removed && paltindex && paltindex != pindex) {
1858
+ CBlock block;
1859
+ if (!ReadBlockFromDisk (block, paltindex, Params ().GetConsensus ())) {
1860
+ throw JSONRPCError (RPC_INTERNAL_ERROR, " Can't read block from disk" );
1861
+ }
1862
+ for (const CTransactionRef& tx : block.vtx ) {
1863
+ if (pwallet->mapWallet .count (tx->GetHash ()) > 0 ) {
1864
+ // We want all transactions regardless of confirmation count to appear here,
1865
+ // even negative confirmation ones, hence the big negative.
1866
+ ListTransactions (pwallet, pwallet->mapWallet [tx->GetHash ()], " *" , -100000000 , true , removed, filter);
1867
+ }
1868
+ }
1869
+ paltindex = paltindex->pprev ;
1833
1870
}
1834
1871
1835
1872
CBlockIndex *pblockLast = chainActive[chainActive.Height () + 1 - target_confirms];
1836
1873
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash () : uint256 ();
1837
1874
1838
1875
UniValue ret (UniValue::VOBJ);
1839
1876
ret.push_back (Pair (" transactions" , transactions));
1877
+ if (include_removed) ret.push_back (Pair (" removed" , removed));
1840
1878
ret.push_back (Pair (" lastblock" , lastblock.GetHex ()));
1841
1879
1842
1880
return ret;
@@ -3082,7 +3120,7 @@ static const CRPCCommand commands[] =
3082
3120
{ " wallet" , " listlockunspent" , &listlockunspent, false , {} },
3083
3121
{ " wallet" , " listreceivedbyaccount" , &listreceivedbyaccount, false , {" minconf" ," include_empty" ," include_watchonly" } },
3084
3122
{ " wallet" , " listreceivedbyaddress" , &listreceivedbyaddress, false , {" minconf" ," include_empty" ," include_watchonly" } },
3085
- { " wallet" , " listsinceblock" , &listsinceblock, false , {" blockhash" ," target_confirmations" ," include_watchonly" } },
3123
+ { " wallet" , " listsinceblock" , &listsinceblock, false , {" blockhash" ," target_confirmations" ," include_watchonly" , " include_removed " } },
3086
3124
{ " wallet" , " listtransactions" , &listtransactions, false , {" account" ," count" ," skip" ," include_watchonly" } },
3087
3125
{ " wallet" , " listunspent" , &listunspent, false , {" minconf" ," maxconf" ," addresses" ," include_unsafe" ," query_options" } },
3088
3126
{ " wallet" , " lockunspent" , &lockunspent, true , {" unlock" ," transactions" } },
0 commit comments