Skip to content
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

rpc: introduce 'label' API for wallet #7729

Closed
wants to merge 2 commits into from

Conversation

@laanwj
Copy link
Member

@laanwj laanwj commented Mar 21, 2016

Add label API to wallet RPC.

This is one step towards #3816 ("Remove bolt-on account system") although it doesn't actually remove anything yet (that would be a follow-up pull).

These initially mirror the account functions, with the following differences:

  • These functions aren't DEPRECATED in the help
  • Help mentions 'label' instead of accounts. In the language used, labels are associated with addresses, instead of addresses associated with labels. (in contrast to accounts.)
  • Labels have no balance
    • No getreceivedbylabel
    • No balances in listlabels
    • listreceivedbylabel can show received transactions to addresses with a label, not use the account tally (currently it is removed, but according to discussion that goes too far as this doesn't inherently have to do with balance)
    • listlabels has no minconf or watchonly argument
    • Remove move
  • Like in the GUI, labels can be set on any address, not just receiving addreses
  • Unlike accounts, labels can be deleted. Being unable to delete them is a common annoyance (see #1231). Currently only by reassigning all addresses using setlabel, but an explicit call deletelabel which assigns all address to the default label may make sense.
  • These calls stay the same, with account argument renamed to label:
    • importaddress
    • importprivkey
    • importpubkey

API

Short description of every RPC call: for detailed information check RPC help. The general idea is to offer the same functionality as the GUI label system. Labels are simply a name for an address, or a group of addresses.

Do not use the deprecated account system and the label system with the same wallet at the same time. These APIs use the same underlying data in the database for (slightly) different purposes, using them interchangeably will give unexpected results. (Just like using the GUI labels and account system at the same time. Using the GUI labels and the label API at the same time, however, is no problem)

  • getlabel: returns the label (and other address book data) associated with an address
    • This exposes the fields in the CAddressBookData structure, which is currently the 'purpose' (sending address, receiving address) and 'destdata' (used for storing payment requests IIRC)
  • getaddressesbylabel: get addresses labelled with one label
  • listlabels: list all labels (or labels with a certain purpose, such as receive/send)
  • setlabel: assign a label to an address
  • getlabeladdress: get the 'label address' for the specified label. This gets an unused address with the label, creating one if necessary should be removed according to discussion

These calls have a deprecated account parameter, which can be turned into a label-parameter as is:

  • listtransactions

Open questions

  • Should there be such a thing as a 'label address'? My initial feeling about this was
    'no', labels are just a name for one or more addresses, intuitively there is no "default address",
    and it also isn't a GUI feature (->no)
@jonasschnelli
Copy link
Member

@jonasschnelli jonasschnelli commented Mar 21, 2016

Concept ACK.
I just wonder if this makes the wallet code more complex (add another layer).

My idea was it to duplicate the current wallet implementation (cp src/wallet src/newwallet-approach) and add such things there (after removing the accounts-related code). Also the Bip32 and @CodeShark multi-wallet PR could be added there.

The second wallet could come without API stableness (for the first two releases or so) and could be marked as experimental.

@laanwj
Copy link
Member Author

@laanwj laanwj commented Mar 21, 2016

I just wonder if this makes the wallet code more complex (add another layer).

I disagree:

  • All of this functionality is required anyway to support the GUI.
  • Yes, there is some intentional duplication, but only until the account calls are ripped out, which should be one of the next steps.
  • There are only added RPC calls in rpcwallet.cpp. The CWallet class is not complicated by this.

The point here is to give a non-deprecated equivalent to the 'label' system as used in the GUI, so the subset of the 'account system' that people are still allowed to use. This is a required, but up to now missing part of deprecating the account system.

I'm not trying to rule out any other work that is being done such as multi-wallet support. I think this is pretty much orthogonal. As for alternative wallets, they've been proposed since at least 2012 - but none have materialized yet. And none of this change rules them out.

@jonasschnelli
Copy link
Member

@jonasschnelli jonasschnelli commented Mar 21, 2016

As for alternative wallets, they've been proposed since at least 2012 - but none have materialized yet. And none of this change rules them out.

Yes. I agree.
This PR has a clear value.

@luke-jr
Copy link
Member

@luke-jr luke-jr commented Mar 21, 2016

Note getaccountaddress does not presently get a "default" address, it gets an unused address with the label, creating one if necessary. This seems useful only for mining, since no other context can guarantee an address hasn't been "used" but not sent to yet. I can't think of a good way to deprecate this, however.

@laanwj
Copy link
Member Author

@laanwj laanwj commented Mar 22, 2016

it gets an unused address with the label, creating one if necessary.

I wonder if we can find a better (or at least simpler, the GetAccountAddress function is pretty terrible) way to do this, now that we're creating a new API anyway. Need to think about this a bit.

@laanwj
Copy link
Member Author

@laanwj laanwj commented Mar 23, 2016

@luke-jr

I wonder if we can find a better (or at least simpler, the GetAccountAddress function is pretty terrible) way to do this, now that we're creating a new API anyway. Need to think about this a bit.

I thought of the following: you could use two labels, one for the 'active' address, one for the 'normal'. Say mining_active and mining.

When the miner needs an address it will:

  • addr = getaddressesbylabel mining_active (if no address returned, go to "if so" directly below and skip the first)
  • getreceivedbyaddress - check with wallet that addr has been used before (or maybe add a more convenient RPC call for checking a single address)
  • If so:
    • setlabel <addr> mining - move current address to normal label
    • addr = getnewaddress mining_active - generate new address in mining_active label
    • Use addr for mining to
  • If not:
    • Use addr for mining to

This is a little bit more involved at the user side, but it avoids special administration (needing to keep around CAccount structure per label) at the server side.

@luke-jr
Copy link
Member

@luke-jr luke-jr commented Apr 7, 2016

That looks like a lot of overhead, and this is a rather time-sensitive call, as the miner is working on stale work until it's done.

Also, why are there no getreceivedbylabel/listreceivedbylabel? These don't have anything to do with balances.

@laanwj
Copy link
Member Author

@laanwj laanwj commented Apr 7, 2016

That looks like a lot of overhead, and this is a rather time-sensitive call, as the miner is working on stale work until it's done.

I'd suggest to try it. It shouldn't be much slower.

Also, why are there no getreceivedbylabel/listreceivedbylabel? These don't have anything to do with balances.

Looks like you're right. getreceivedbyaccount doesn't actually return the account balance, but the total number of coins sent to the addresses that make up the account?

listreceivedbyaccount on the other hand goes over the account tally. But I agree if it only were to show actual transactions sent to addresses belonging to a label it'd be ok.

@sipa
Copy link
Member

@sipa sipa commented Apr 7, 2016

@luke-jr Wouldn't it be feasible to instead generate a sequence of deterministic addresses for mining, for example using BIP32 derivation with the block height as index?

@luke-jr
Copy link
Member

@luke-jr luke-jr commented Apr 7, 2016

I'd suggest to try it. It shouldn't be much slower.

@laanwj getreceivedbyaddress at least would loop over all the wtx... and then there's the additional latency from the back and forth of multiple calls. I haven't tried it yet, though.

Wouldn't it be feasible to instead generate a sequence of deterministic addresses for mining, for example using BIP32 derivation with the block height as index?

@sipa Perhaps, if the wallet had a way to do this. Using the height seems incompatible with gap limits, though?

@sipa
Copy link
Member

@sipa sipa commented Apr 7, 2016

@luke-jr I mean the mining software can do derivation, and import the keys into the wallet when a block is found.

@MarcoFalke
Copy link
Member

@MarcoFalke MarcoFalke commented May 22, 2016

The functional test coverage for accounts is minimal or not existent, I think we should move forward with this pull.

Needs rebase.

@jonasschnelli
Copy link
Member

@jonasschnelli jonasschnelli commented May 22, 2016

Re-Concept ACK.
I think this solution makes more sense than the closed #7830.
Needs tests, rebase and release-note mentioning.

@wallclockbuilder
Copy link

@wallclockbuilder wallclockbuilder commented May 22, 2016

Needs tests.

@laanwj
Copy link
Member Author

@laanwj laanwj commented Jun 2, 2016

@wallclockbuilder No shit, have you seen the TODOs at the bottom of the opening post?

@laanwj
Copy link
Member Author

@laanwj laanwj commented Jun 2, 2016

To be clear I posted this to get comments on the API, is there anything left to be done there? I'm going to write tests when it is clear that this is what we want at all.

@laanwj laanwj added this to the Future milestone Jun 13, 2016
@MarcoFalke
Copy link
Member

@MarcoFalke MarcoFalke commented Jul 14, 2016

Do not use the deprecated account system and the label system with the same wallet at the same time
[...]
optional: a flag in the wallet to prevent use of both the account and label API

I would not consider this optional. User will always do what you not want them to do.

@sipa
Copy link
Member

@sipa sipa commented Aug 25, 2016

Concept ACK

@andrewbaine
Copy link

@andrewbaine andrewbaine commented Sep 24, 2016

listtransactions has an "account" argument where you now you would pass "*" if you need to supply non-default args for count, from, and includeWatchOnly. Will there be a way to query for transactions affecting any address with a given label? Could we tack on a "label" argument to listtransactions?

@laanwj
Copy link
Member Author

@laanwj laanwj commented Sep 24, 2016

I think the account argument of listtransactions could simply be re-used as a label argument. As listing transactions to a label has nothing to do with per-label balances there is no need to drop that particular functionality,

@andrewbaine
Copy link

@andrewbaine andrewbaine commented Oct 3, 2016

repurposing the "account" argument to be "label" makes sense to me

@ryanofsky
Copy link
Contributor

@ryanofsky ryanofsky commented Mar 23, 2018

Rebased PR at https://github.com/ryanofsky/bitcoin/commits/pr/label:

  • 6a0d274 rpc: introduce 'label' API for wallet
  • fef4178 [wallet] Make setlabel idempotent

@laanwj laanwj force-pushed the 2016_03_wallet_label_api branch from 0e3ef24 to fef4178 Mar 23, 2018
@laanwj
Copy link
Member Author

@laanwj laanwj commented Mar 23, 2018

@ryanofsky Thank you! Replaced the branch with that one.

"\nExamples:\n"
+ HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
+ HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
+ HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
Copy link
Member

@MarcoFalke MarcoFalke Mar 23, 2018

Unrelated change?

If you really wanted to change that DummyAddress(Params()) would be a better choice.

Sjors
Sjors approved these changes Mar 28, 2018
Copy link
Member

@Sjors Sjors left a comment

tACK fef4178.

I just noticed that changing or removing a label in the console live updates the Receiving Addresses UI, nice! For a future PR we should figure out what to do with the Receive and Transaction tab "labels", as these seem to use an independent mechanism.

"\nArguments:\n"
"1. \"label\" (string, required) The label name for the address. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created and a new address created if there is no label by the given name.\n"
Copy link
Member

@Sjors Sjors Mar 28, 2018

I'm fine with removing this remark, but note that the behavior of creating a new address still exists (though without an address type param). It might make sense to deprecate that behavior in a followup PR, and require getnewaddress if getlabeladdress doesn't return anything. That also makes the choice of potentially reusing an address more explicit.

@laanwj
Copy link
Member Author

@laanwj laanwj commented Mar 28, 2018

For a future PR we should figure out what to do with the Receive and Transaction tab "labels", as these seem to use an independent mechanism.

Transaction tab labels use the same mechanism so it would be a matter of listening to a notification and repainting. Receive requests are stored separately, because they have extra metadata besides a label.

@Sjors
Copy link
Member

@Sjors Sjors commented Mar 28, 2018

Ah yes, I see it. Restarting QT doesn't change or remove a label from Requested payments history for me, as you point out. Switching tabs is enough to update labels in the transactions view.

Copy link
Member

@jnewbery jnewbery left a comment

Comments inline.

Feel free to squash my second commit into the first.

{ "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
{ "wallet", "getaccount", &getaccount, {"address"} },
{ "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
{ "wallet", "getaddressinfo", &getaddressinfo, {"address"} },
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

I don't think getaddressinfo should be deprecated. It's not an account rpc

Copy link
Contributor

@ryanofsky ryanofsky Mar 28, 2018

I don't think getaddressinfo should be deprecated. It's not an account rpc

Good catch. getaddressinfo should remain where it was above "getbalance". It's my fault for accidentally moving it into this section during a rebase.

@@ -290,14 +295,14 @@ UniValue setlabel(const JSONRPCRequest& request)

if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
"setlabel \"address\" \"label\"\n"
"setlabel \"bitcoinaddress\" \"label\"\n"
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

Why rename the arguments/return values to bitcoinaddress everywhere? Seems like a gratuitous API break.

address is used in many RPCs for a bitcoin address. Why not continue that convention? (and if you really must change this, current style guidelines call for snake_case for args)

Copy link
Contributor

@ryanofsky ryanofsky Mar 28, 2018

Why rename the arguments/return values to bitcoinaddress everywhere?

Agree it would be better to stick to address, but just as a historical note, this wasn't a "gratuitious" API break when it was originally written in 8571fee, because it preceded #11536, so the setlabel RPC was brand new.

"\nResult:\n"
" { (json object with information about address)\n"
" \"name\": \"labelname\" (string) The label\n"
" \"purpose\": \"string\" (string) Purpose of address (\"send\" for sending address, \"receive\" for receiving address)\n"
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

Comment: https://github.com/bitcoin/bitcoin/pull/7729/files#r121986789 not addressed. Result also includes an array of destdata. Please update help text.

EDIT: I think we should just drop the destdata from the response. It wasn't available in the old account RPCs, and it appears to me that the only place we add to destdata is in saveReceiveRequest().

We can always add destdata to the response in a later PR if required.

"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address for label lookup.\n"
"\nResult:\n"
" { (json object with information about address)\n"
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

Can we make this RPC return an array? We may want to be able to attach multiple labels to addresses in the future (#7729 (comment)), and making this RPC return an array will allow us to do that without a breaking API change

Copy link
Contributor

@ryanofsky ryanofsky Mar 28, 2018

Can we make this RPC return an array?

It might be better to not add a getlabel RPC at all but instead just return this information in getaddressinfo (recently added in #10583).

}
}
UniValue ret(UniValue::VARR);
for (const std::string &name : setLabels) {
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

Should we sort the label names before returning?

if (item.second.name == strLabel) {
ret.push_back(Pair(EncodeDestination(item.first), AddressBookDataToJSON(item.second, false)));
}
}
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

Should this throw an error if the label doesn't exist? Currently it returns an empty object.

@@ -208,11 +213,11 @@ UniValue getlabeladdress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"getlabeladdress \"label\"\n"
"\nReturns the current Bitcoin address for receiving payments to this label.\n"
"\nReturns the current 'label address' for this label.\n"
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

The behaviour for this RPC is weird. If called for a label that doesn't exist, it creates a new label, and then adds a new address as the 'label address' for that label. That's not very intuitive, and I think it's a bad experience (for example if a user typos an existing label name). Can we change this so that the rpc returns an error if called with a non-existent label name?

@@ -15,6 +15,7 @@

from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from collections import defaultdict
Copy link
Member

@jnewbery jnewbery Mar 28, 2018

nit: standard library imports before project imports please!

@jnewbery
Copy link
Member

@jnewbery jnewbery commented Apr 4, 2018

@laanwj - it seems like you're struggling to find time to maintain this PR.

I'd like to push this forwards and make sure it gets in for v0.17. Would you object if I took ownership?

@GSPP
Copy link

@GSPP GSPP commented Apr 5, 2018

Maybe there should be a call returning all addresses and all labels (a bulk call). If you want to dump all address-label pairs this would involve many RPC calls right now. This bulk call should even (optionally?) include internal addresses such as pool addresses. Simply all data. I have had the need many times to reflect over absolutely all wallet contents and such an API call would have been very welcome.

@jnewbery
Copy link
Member

@jnewbery jnewbery commented Apr 5, 2018

I've opened #12892 to supersede this PR. Thanks for all your work @laanwj !

@MarcoFalke
Copy link
Member

@MarcoFalke MarcoFalke commented Apr 5, 2018

Indeed thanks to @laanwj for initiating it and coming up with the original version of the code. And thx to @ryanofsky and @jnewbery for picking it up.

@MarcoFalke MarcoFalke closed this Apr 5, 2018
@jnewbery jnewbery mentioned this pull request Apr 11, 2018
6 tasks
HashUnlimited pushed a commit to HashUnlimited/chaincoin that referenced this issue Jul 31, 2018
This change only updates strings and adds RPC aliases, but should simplify the
implementation of address labels in
bitcoin#7729, by getting renaming out of the
way and letting it focus on semantics.

The difference between accounts and labels is that labels apply only to
addresses, while accounts apply to both addresses and transactions
(transactions have "from" and "to" accounts). The code associating accounts
with transactions is clumsy and unreliable so we would like get rid of it.
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 18, 2020
This change only updates strings and adds RPC aliases, but should simplify the
implementation of address labels in
bitcoin#7729, by getting renaming out of the
way and letting it focus on semantics.

The difference between accounts and labels is that labels apply only to
addresses, while accounts apply to both addresses and transactions
(transactions have "from" and "to" accounts). The code associating accounts
with transactions is clumsy and unreliable so we would like get rid of it.
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 18, 2020
This change only updates strings and adds RPC aliases, but should simplify the
implementation of address labels in
bitcoin#7729, by getting renaming out of the
way and letting it focus on semantics.

The difference between accounts and labels is that labels apply only to
addresses, while accounts apply to both addresses and transactions
(transactions have "from" and "to" accounts). The code associating accounts
with transactions is clumsy and unreliable so we would like get rid of it.
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 18, 2020
This change only updates strings and adds RPC aliases, but should simplify the
implementation of address labels in
bitcoin#7729, by getting renaming out of the
way and letting it focus on semantics.

The difference between accounts and labels is that labels apply only to
addresses, while accounts apply to both addresses and transactions
(transactions have "from" and "to" accounts). The code associating accounts
with transactions is clumsy and unreliable so we would like get rid of it.
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 18, 2020
This change only updates strings and adds RPC aliases, but should simplify the
implementation of address labels in
bitcoin#7729, by getting renaming out of the
way and letting it focus on semantics.

The difference between accounts and labels is that labels apply only to
addresses, while accounts apply to both addresses and transactions
(transactions have "from" and "to" accounts). The code associating accounts
with transactions is clumsy and unreliable so we would like get rid of it.
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 18, 2020
d2527bd Rename wallet_accounts.py test (Russell Yanofsky)
045eeb8 Rename account to label where appropriate (Russell Yanofsky)

Pull request description:

  Rename account to label where appropriate

  This change only updates strings and adds RPC aliases, but should simplify the implementation of address labels in bitcoin#7729, by getting renaming out of the way and letting that change focus on semantics.

  The difference between accounts and labels is that labels apply only to addresses, while accounts apply to both addresses and transactions (transactions have "from" and "to" accounts). The code associating accounts with transactions is clumsy and unreliable so we would like get rid of it.

  ---

  There is a rebased version of bitcoin#7729 atop this PR at https://github.com/ryanofsky/bitcoin/commits/pr/label, see bitcoin#7729 (comment).

Tree-SHA512: b3f934e612922d6290f50137f8ba71ddfaea4485713c7d97e89400a8b73b09b254f9186dffa462c77f5847721f5af9852b5572ade5443d8ee95dd150b3edb7ff
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 22, 2020
d2527bd Rename wallet_accounts.py test (Russell Yanofsky)
045eeb8 Rename account to label where appropriate (Russell Yanofsky)

Pull request description:

  Rename account to label where appropriate

  This change only updates strings and adds RPC aliases, but should simplify the implementation of address labels in bitcoin#7729, by getting renaming out of the way and letting that change focus on semantics.

  The difference between accounts and labels is that labels apply only to addresses, while accounts apply to both addresses and transactions (transactions have "from" and "to" accounts). The code associating accounts with transactions is clumsy and unreliable so we would like get rid of it.

  ---

  There is a rebased version of bitcoin#7729 atop this PR at https://github.com/ryanofsky/bitcoin/commits/pr/label, see bitcoin#7729 (comment).

Tree-SHA512: b3f934e612922d6290f50137f8ba71ddfaea4485713c7d97e89400a8b73b09b254f9186dffa462c77f5847721f5af9852b5572ade5443d8ee95dd150b3edb7ff
xdustinface added a commit to xdustinface/dash that referenced this issue Dec 22, 2020
d2527bd Rename wallet_accounts.py test (Russell Yanofsky)
045eeb8 Rename account to label where appropriate (Russell Yanofsky)

Pull request description:

  Rename account to label where appropriate

  This change only updates strings and adds RPC aliases, but should simplify the implementation of address labels in bitcoin#7729, by getting renaming out of the way and letting that change focus on semantics.

  The difference between accounts and labels is that labels apply only to addresses, while accounts apply to both addresses and transactions (transactions have "from" and "to" accounts). The code associating accounts with transactions is clumsy and unreliable so we would like get rid of it.

  ---

  There is a rebased version of bitcoin#7729 atop this PR at https://github.com/ryanofsky/bitcoin/commits/pr/label, see bitcoin#7729 (comment).

Tree-SHA512: b3f934e612922d6290f50137f8ba71ddfaea4485713c7d97e89400a8b73b09b254f9186dffa462c77f5847721f5af9852b5572ade5443d8ee95dd150b3edb7ff
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment