-
Notifications
You must be signed in to change notification settings - Fork 37.7k
rpc: Add option to list transactions from oldest to newest in listtransactions
RPC command
#22775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I think the underlying RPCs of the console commands are primarily for machines and not for humans. So it seems it's not a big deal to make two calls, and it might be even preferable than adding more parameters. Why is it important for the desired use case to work from console rather than from GUI? |
There are cases where the RPC is used remotely, for example as a hidden service exposed over Tor. Then latency can be very bad and every call takes a long time, so reducing the number of calls is very important in these cases. In Specter, for example, we have many such users connecting to a remote Bitcoin Core over Tor, and so have to try and reduce the number of separate calls to the minimum. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a release note and should add a test
src/wallet/rpcwallet.cpp
Outdated
@@ -1414,6 +1414,7 @@ static RPCHelpMan listtransactions() | |||
{"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"}, | |||
{"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"}, | |||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"}, | |||
{"ascending_order", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for ascending order (newest to oldest), false for descending order (oldest to newest)"}, "The direction from which to start getting transactions"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably say which is the default in the hint
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
ddeff14
to
3f9112c
Compare
Added test and release note in 3f9112c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK 3f9112c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested ACK 3f9112c on Ubuntu 20.04
Agree with this
This also makes sense Since not including the new flag or setting it to true will not change the current behavior, its an improvement to Example: #22608 (comment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK 3f9112c
Have you seen #19443? There |
@kristapsk looks interesting. Will try today. |
3f9112c
to
024439d
Compare
Updated with d07577b to minimise code duplication. |
024439d
to
d07577b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK d07577b
Looks like it needs rebase |
Concept ACK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code ACK 3f9112c, unsure on concept (jamesob/ackr/22775.1.ben-kaufman.rpc_add_option_to_list_t
)
Code looks fine, tests were a little confusing but seem to be verifying the right thing. I built and ran functional tests locally.
This seems like a fairly specific option relative to the functionality introduced in #19443. My gut inclination would be that if we're going to change the RPC API, it would make sense to put thought into something that might allow more general sorting in the way the other PR does, though the benefit here is that this change is much simpler.
Since I don't myself have a great sense of what wallet providers would find useful, it'd be nice to get commentary from multiple external projects (e.g. Spectre, OP's project) about whether they would find this particular change worth special-casing instead of something more general, since we won't want to deprecate an arg like this shortly after introducing it if another sorting ask comes around.
Show signature data
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
code ACK 3f9112c6291cbc22a3e14bbc6f39f454b40032ca ([`jamesob/ackr/22775.1.ben-kaufman.rpc_add_option_to_list_t`](https://github.com/jamesob/bitcoin/tree/ackr/22775.1.ben-kaufman.rpc_add_option_to_list_t))
Code looks fine, tests were a little confusing but seem to be verifying the right thing. I built and ran functional tests locally.
This seems like a fairly specific option relative to the functionality introduced in #19443. My gut inclination would be that if we're going to change the RPC API, it would make sense to put thought into something that might allow more general sorting in the way the other PR does, though the benefit here is that this change is much simpler.
Since I don't myself have a great sense of what wallet providers would find useful, it'd be nice to get commentary from multiple external projects (e.g. Spectre, OP's project) about whether they would find this particular change worth special-casing instead of something more general, since we won't want to deprecate an arg like this shortly after introducing it if another sorting ask comes around.
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCgAdFiEEGNRVI1NPYuZCSIrGepNdrbLETwUFAmEpNYsACgkQepNdrbLE
TwWNBxAAjRm9Dq84h1dVLeWjB9QQUQHLC0MGh5YBRf033gP8oFqChyrQELvFHA0B
QmT0bQtfq3JdRe+Y3XsgZ/SrcVhu4lQFFYbsY5DYAp14w9teW7VmZPNXrL23uXnn
7/D9Xg7kmggRBKnv896xKW5YIV+VSpvyQGw7lBGa8Tc/9yV8aUK6+/jTFo6j5kfo
abLLOq2oqvhUkJ9s/akzpvONWXmhmfjgSuWLfa7TD6qnO1m2BhbWGkGeuPvONyPH
vPs2vckxv4Mm6oBADTkb+Dsc9R8rDabETwnn4kvXwmMVOJpREfoQClxIvfMWfD47
222DvQU4ClUVFxZzMWjN7v4nxNXf5VA5c1SVc/uTeAyCpG7NRb00C7hqC5JYtYut
BEsoyPncH23X1y0JMWagUZkW/58xsvOjyvuM4tTTX5IfauPtoU+RadDzGRka5+qJ
1Fy/lrdq629oCrhvxDRI8lgFjVWRQpMBaRLYOCOPxTZhI04wm4PwCXjABBxCGWVt
pApZ21KgJMa4h+oVy7mcVPany6XcaFQh+gKHm8zfg1Q//GINJhhChEWg52LxlMRa
PUOgGv/TCar8pycY2ZXP5YDU2ON1yy4WXIc9Ygy7eu66pVZUJB9/2fvB/tTjD1SW
pHX40BH63G6mnm4kaYuRi74c/+eSAAGSARafWX7qmz6fbT9tpIY=
=89DY
-----END PGP SIGNATURE-----
Show platform data
Tested on Linux-4.19.0-17-amd64-x86_64-with-glibc2.28
Configured with ./configure LDFLAGS=-L/home/james/src/bitcoin/db4/lib/ CPPFLAGS=-I/home/james/src/bitcoin/db4/include/ CXXFLAGS=-fPIE -pipe -O2 -g -Wthread-safety-analysis -Wall -Werror=sign-compare --enable-wallet --with-daemon CXX=/usr/local/bin/clang++ CC=/usr/local/bin/clang --with-bignum=no PYTHONPATH= --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental --no-create --no-recursion
Compiled with /usr/bin/ccache /usr/local/bin/clang++ -std=c++17 -mavx -mavx2 -fPIE -pipe -O2 -g -Wthread-safety-analysis -Wall -Werror=sign-compare -fdebug-prefix-map=$(abs_srcdir)=. -Wstack-protector -fstack-protector-all -fcf-protection=full -fstack-clash-protection -msse4 -msha -msse4.1 -msse4.2 i
Compiler version: Debian clang version 11.1.0-++20210428103820+1fdec59bffc1-1~exp1~20210428204437.162
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is the best way to do this, but some review suggestions follow.
result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest | ||
} else { | ||
result.push_backV({ txs.cbegin() + nFrom, txs.cbegin() + nFrom + nCount }); // Return oldest to newest | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- This comment should be removed
- // ret is newest to oldest
-
- The second comment below seems incorrect (can probably drop them)
- Use clang format
if (ascending_order) {
- result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest
+ result.push_backV({txs.rend() - nFrom - nCount, txs.rend() - nFrom});
} else {
- result.push_backV({ txs.cbegin() + nFrom, txs.cbegin() + nFrom + nCount }); // Return oldest to newest
+ result.push_backV({txs.cbegin() + nFrom, txs.cbegin() + nFrom + nCount});
}
@@ -1414,6 +1414,7 @@ static RPCHelpMan listtransactions() | |||
{"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"}, | |||
{"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"}, | |||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"}, | |||
{"ascending_order", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for ascending order (newest to oldest), false for descending order (oldest to newest), default is true"}, "The direction from which to start getting transactions"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
Subjective: calling the argument
ascending
would be shorter and just as clear to me. -
The following is simpler and would print a help that seems clearer and easier to understand:
{"ascending_order", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for ascending order (newest to oldest), false for descending order (oldest to newest), default is true"}, "The direction from which to start getting transactions"}, | |
{"ascending_order", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to list transactions by ascending or descending order"}, |
returns
5. ascending (boolean, optional, default=true) Whether to list transactions by ascending or descending order
instead of
5. ascending_order (boolean, optional, default=true for ascending order (newest to oldest), false for descending order (oldest to newest), default is true) The direction from which to start getting transactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just a negative number for skip
?
At the very least, make it an options object...
|
||
if (!request.params[4].isNull()) { | ||
ascending_order = request.params[4].get_bool(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion
- // Default ascending_order to true if no value has been specified
- bool ascending_order = true;
-
- if (!request.params[4].isNull()) {
- ascending_order = request.params[4].get_bool();
- }
+ const bool ascending_order{request.params[4].isNull() ? true : request.params[4].get_bool()};
-------- | ||
- A new optional ascending_order flag in the `listtransactions` RPC | ||
will allow to go through the transactions list from the oldest to | ||
the newest in addition to the current newest to oldest behavior. (#22775) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion
New RPCs
--------
-- A new optional ascending_order flag in the `listtransactions` RPC
-will allow to go through the transactions list from the oldest to
-the newest in addition to the current newest to oldest behavior. (#22775)
+
+- RPC `listtransactions` has a new optional `ascending_order` argument that
+ allows selecting whether to return transactions in the default order of
+ ascending (oldest to newest) or descending (newest to oldest). (#22775)
self.nodes[0].listtransactions(count=1, skip=len(self.nodes[0].listtransactions(count=10000)) - 1, ascending_order=True)) | ||
# The second and third transactions counting from the oldest (descending order) should be the 2 before the last transaction counting from the newest (ascending order) | ||
assert_equal(self.nodes[0].listtransactions(count=2, skip=1, ascending_order=False), | ||
self.nodes[0].listtransactions(count=2, skip=len(self.nodes[0].listtransactions(count=10000)) - 3, ascending_order=True)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestions
- # The first transaction counting from the oldest (descending order) should be the last transaction counting from the newest (ascending order)
+ size = len(self.nodes[0].listtransactions(count=10000)) # get size of transactions list
+ # The first transaction in descending order should be the last transaction in ascending order.
assert_equal(self.nodes[0].listtransactions(count=1, ascending_order=False),
- self.nodes[0].listtransactions(count=1, skip=len(self.nodes[0].listtransactions(count=10000)) - 1, ascending_order=True))
- # The second and third transactions counting from the oldest (descending order) should be the 2 before the last transaction counting from the newest (ascending order)
+ self.nodes[0].listtransactions(count=1, ascending_order=True, skip=size - 1))
+ # The second and third txns in descending order should be the 2 before the last txn in ascending order.
assert_equal(self.nodes[0].listtransactions(count=2, skip=1, ascending_order=False),
- self.nodes[0].listtransactions(count=2, skip=len(self.nodes[0].listtransactions(count=10000)) - 3, ascending_order=True))
+ self.nodes[0].listtransactions(count=2, ascending_order=True, skip=size - 3))
@@ -1414,6 +1414,7 @@ static RPCHelpMan listtransactions() | |||
{"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"}, | |||
{"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"}, | |||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"}, | |||
{"ascending_order", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for ascending order (newest to oldest), false for descending order (oldest to newest), default is true"}, "The direction from which to start getting transactions"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just a negative number for skip
?
At the very least, make it an options object...
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
🐙 This pull request conflicts with the target branch and needs rebase. Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft". |
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
Closing for now. Let us know when you are working on this again and if it should be reopened. |
Currently, the RPC
listtransactions
command returns the latest X transactions of the wallet starting from Y. This means that to get the X oldest transacions would require first to callgetwalletinfo
command to get the total transactions count, and then use that to know what count to pass thelisttransactions
command.This PR adds an optional flag to allow instead to start going through the transactions list from the oldest to the newest, so it will be possible to get the oldest X transactions of the wallet starting from Y.
For example, this will return the oldest transaction of the wallet:
This will return the 2nd and 3rd oldest transactions of the wallet:
Not including the new flag or setting it to true will not change the current behavior.