@ -189,7 +189,6 @@ UniValue getnewaddress(const JSONRPCRequest& request)
return EncodeDestination ( dest ) ;
}
CTxDestination GetLabelDestination ( CWallet * const pwallet , const std : : string & label , bool bForceNew = false )
{
CTxDestination dest ;
@ -207,14 +206,16 @@ UniValue getlabeladdress(const JSONRPCRequest& request)
return NullUniValue ;
}
if ( request . fHelp | | request . params . size ( ) != 1 )
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
throw std : : runtime_error (
" getlabeladdress \" label \" \n "
" \n Returns the current Bitcoin address for receiving payments to this label .\n "
" getlabeladdress \" label \" ( force ) \n "
" \n Returns the default receiving address for this label. This will reset to a fresh address once there's a transaction that spends to it .\n "
" \n Arguments: \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 "
" 1. \" label \" (string, required) The label for the address. It can also be set to the empty string \" \" to represent the default label. \n "
" 2. \" force \" (bool, optional) Whether the label should be created if it does not yet exist. If False, the RPC will return an error if called with a label that doesn't exist. \n "
" Defaults to false (unless the getaccountaddress method alias is being called, in which case defaults to true for backwards compatibility). \n "
" \n Result: \n "
" \" address \" (string) The label bitcoin address \n "
" \" address \" (string) The current receiving address for the label. \n "
" \n Examples: \n "
+ HelpExampleCli ( " getlabeladdress " , " " )
+ HelpExampleCli ( " getlabeladdress " , " \" \" " )
@ -226,6 +227,21 @@ UniValue getlabeladdress(const JSONRPCRequest& request)
// Parse the label first so we don't generate a key if there's an error
std : : string label = LabelFromValue ( request . params [ 0 ] ) ;
bool force = request . strMethod = = " getaccountaddress " ? true : false ;
if ( ! request . params [ 1 ] . isNull ( ) ) {
force = request . params [ 1 ] . get_bool ( ) ;
}
bool label_found = false ;
for ( const std : : pair < CTxDestination , CAddressBookData > & item : pwallet - > mapAddressBook ) {
if ( item . second . name = = label ) {
label_found = true ;
break ;
}
}
if ( ! force & & ! label_found ) {
throw JSONRPCError ( RPC_WALLET_INVALID_LABEL_NAME , std : : string ( " No addresses with label " + label ) ) ;
}
UniValue ret ( UniValue : : VSTR ) ;
@ -290,13 +306,13 @@ UniValue setlabel(const JSONRPCRequest& request)
return NullUniValue ;
}
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
if ( request . fHelp | | request . params . size ( ) != 2 )
throw std : : runtime_error (
" setlabel \" address \" \" label \" \n "
" \n Sets the label associated with the given address. \n "
" \n Arguments: \n "
" 1. \" address \" (string, required) The bitcoin address to be associated with a label. \n "
" 2. \" label \" (string, required) The label to assign t he address to .\n "
" 2. \" label \" (string, required) The label to assign t o t he address.\n "
" \n Examples: \n "
+ HelpExampleCli ( " setlabel " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" \" tabby \" " )
+ HelpExampleRpc ( " setlabel " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" , \" tabby \" " )
@ -309,23 +325,22 @@ UniValue setlabel(const JSONRPCRequest& request)
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Bitcoin address " ) ;
}
std : : string label ;
if ( ! request . params [ 1 ] . isNull ( ) )
label = LabelFromValue ( request . params [ 1 ] ) ;
std : : string label = LabelFromValue ( request . params [ 1 ] ) ;
// Only add the label if the address is yours.
if ( IsMine ( * pwallet , dest ) ) {
// Detect when changing the label of an address that is the 'unused current key' of another label:
// Detect when changing the label of an address that is the receiving address of another label:
// If so, delete the account record for it. Labels, unlike addresses, can be deleted,
// and if we wouldn't do this, the record would stick around forever.
if ( pwallet - > mapAddressBook . count ( dest ) ) {
std : : string old_label = pwallet - > mapAddressBook [ dest ] . name ;
if ( dest = = GetLabelDestination ( pwallet , old_label ) ) {
GetLabelDestination( pwallet , old_label , true ) ;
if ( old_label ! = label & & dest = = GetLabelDestination ( pwallet , old_label ) ) {
pwallet- > DeleteLabel ( old_label ) ;
}
}
pwallet - > SetAddressBook ( dest , label , " receive " ) ;
} else {
pwallet - > SetAddressBook ( dest , label , " send " ) ;
}
else
throw JSONRPCError ( RPC_MISC_ERROR , " setlabel can only be used with own address " ) ;
return NullUniValue ;
}
@ -3720,6 +3735,17 @@ UniValue DescribeWalletAddress(CWallet* pwallet, const CTxDestination& dest)
return ret ;
}
/** Convert CAddressBookData to JSON record. */
static UniValue AddressBookDataToJSON ( const CAddressBookData & data , const bool verbose )
{
UniValue ret ( UniValue : : VOBJ ) ;
if ( verbose ) {
ret . pushKV ( " name " , data . name ) ;
}
ret . pushKV ( " purpose " , data . purpose ) ;
return ret ;
}
UniValue getaddressinfo ( const JSONRPCRequest & request )
{
CWallet * const pwallet = GetWalletForJSONRPCRequest ( request ) ;
@ -3759,6 +3785,13 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" \" timestamp \" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT) \n "
" \" hdkeypath \" : \" keypath \" (string, optional) The HD keypath if the key is HD and available \n "
" \" hdmasterkeyid \" : \" <hash160> \" (string, optional) The Hash160 of the HD master pubkey \n "
" \" labels \" (object) Array of labels associated with the address. \n "
" [ \n "
" { (json object of label data) \n "
" \" name \" : \" labelname \" (string) The label \n "
" \" purpose \" : \" string \" (string) Purpose of address ( \" send \" for sending address, \" receive \" for receiving address) \n "
" },... \n "
" ] \n "
" } \n "
" \n Examples: \n "
+ HelpExampleCli ( " getaddressinfo " , " \" 1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc \" " )
@ -3811,6 +3844,112 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
ret . pushKV ( " hdmasterkeyid " , meta - > hdMasterKeyID . GetHex ( ) ) ;
}
}
// Currently only one label can be associated with an address, return an array
// so the API remains stable if we allow multiple labels to be associated with
// an address.
UniValue labels ( UniValue : : VARR ) ;
std : : map < CTxDestination , CAddressBookData > : : iterator mi = pwallet - > mapAddressBook . find ( dest ) ;
if ( mi ! = pwallet - > mapAddressBook . end ( ) ) {
labels . push_back ( AddressBookDataToJSON ( mi - > second , true ) ) ;
}
ret . pushKV ( " labels " , std : : move ( labels ) ) ;
return ret ;
}
UniValue getaddressesbylabel ( const JSONRPCRequest & request )
{
CWallet * const pwallet = GetWalletForJSONRPCRequest ( request ) ;
if ( ! EnsureWalletIsAvailable ( pwallet , request . fHelp ) ) {
return NullUniValue ;
}
if ( request . fHelp | | request . params . size ( ) ! = 1 )
throw std : : runtime_error (
" getaddressesbylabel \" label \" \n "
" \n Returns the list of addresses assigned the specified label. \n "
" \n Arguments: \n "
" 1. \" label \" (string, required) The label. \n "
" \n Result: \n "
" { (json object with addresses as keys) \n "
" \" address \" : { (json object with information about address) \n "
" \" purpose \" : \" string \" (string) Purpose of address ( \" send \" for sending address, \" receive \" for receiving address) \n "
" },... \n "
" } \n "
" \n Examples: \n "
+ HelpExampleCli ( " getaddressesbylabel " , " \" tabby \" " )
+ HelpExampleRpc ( " getaddressesbylabel " , " \" tabby \" " )
) ;
LOCK ( pwallet - > cs_wallet ) ;
std : : string label = LabelFromValue ( request . params [ 0 ] ) ;
// Find all addresses that have the given label
UniValue ret ( UniValue : : VOBJ ) ;
for ( const std : : pair < CTxDestination , CAddressBookData > & item : pwallet - > mapAddressBook ) {
if ( item . second . name = = label ) {
ret . pushKV ( EncodeDestination ( item . first ) , AddressBookDataToJSON ( item . second , false ) ) ;
}
}
if ( ret . empty ( ) ) {
throw JSONRPCError ( RPC_WALLET_INVALID_LABEL_NAME , std : : string ( " No addresses with label " + label ) ) ;
}
return ret ;
}
UniValue listlabels ( const JSONRPCRequest & request )
{
CWallet * const pwallet = GetWalletForJSONRPCRequest ( request ) ;
if ( ! EnsureWalletIsAvailable ( pwallet , request . fHelp ) ) {
return NullUniValue ;
}
if ( request . fHelp | | request . params . size ( ) > 1 )
throw std : : runtime_error (
" listlabels ( \" purpose \" ) \n "
" \n Returns the list of all labels, or labels that are assigned to addresses with a specific purpose. \n "
" \n Arguments: \n "
" 1. \" purpose \" (string, optional) Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument. \n "
" \n Result: \n "
" [ (json array of string) \n "
" \" label \" , (string) Label name \n "
" ... \n "
" ] \n "
" \n Examples: \n "
" \n List all labels \n "
+ HelpExampleCli ( " listlabels " , " " ) +
" \n List labels that have receiving addresses \n "
+ HelpExampleCli ( " listlabels " , " receive " ) +
" \n List labels that have sending addresses \n "
+ HelpExampleCli ( " listlabels " , " send " ) +
" \n As json rpc call \n "
+ HelpExampleRpc ( " listlabels " , " receive " )
) ;
LOCK ( pwallet - > cs_wallet ) ;
std : : string purpose ;
if ( ! request . params [ 0 ] . isNull ( ) ) {
purpose = request . params [ 0 ] . get_str ( ) ;
}
// Add to a set to sort by label name, then insert into Univalue array
std : : set < std : : string > label_set ;
for ( const std : : pair < CTxDestination , CAddressBookData > & entry : pwallet - > mapAddressBook ) {
if ( purpose . empty ( ) | | entry . second . purpose = = purpose ) {
label_set . insert ( entry . second . name ) ;
}
}
UniValue ret ( UniValue : : VARR ) ;
for ( const std : : string & name : label_set ) {
ret . push_back ( name ) ;
}
return ret ;
}
@ -3840,16 +3979,10 @@ static const CRPCCommand commands[] =
{ " wallet " , " dumpprivkey " , & dumpprivkey , { " address " } } ,
{ " wallet " , " dumpwallet " , & dumpwallet , { " filename " } } ,
{ " wallet " , " encryptwallet " , & encryptwallet , { " passphrase " } } ,
{ " wallet " , " getlabeladdress " , & getlabeladdress , { " label " } } ,
{ " wallet " , " getaccountaddress " , & getlabeladdress , { " account " } } ,
{ " wallet " , " getaccount " , & getaccount , { " address " } } ,
{ " wallet " , " getaddressesbyaccount " , & getaddressesbyaccount , { " account " } } ,
{ " wallet " , " getaddressinfo " , & getaddressinfo , { " address " } } ,
{ " wallet " , " getbalance " , & getbalance , { " account " , " minconf " , " include_watchonly " } } ,
{ " wallet " , " getnewaddress " , & getnewaddress , { " label|account " , " address_type " } } ,
{ " wallet " , " getrawchangeaddress " , & getrawchangeaddress , { " address_type " } } ,
{ " wallet " , " getreceivedbylabel " , & getreceivedbylabel , { " label " , " minconf " } } ,
{ " wallet " , " getreceivedbyaccount " , & getreceivedbylabel , { " account " , " minconf " } } ,
{ " wallet " , " getreceivedbyaddress " , & getreceivedbyaddress , { " address " , " minconf " } } ,
{ " wallet " , " gettransaction " , & gettransaction , { " txid " , " include_watchonly " } } ,
{ " wallet " , " getunconfirmedbalance " , & getunconfirmedbalance , { } } ,
@ -3861,7 +3994,6 @@ static const CRPCCommand commands[] =
{ " wallet " , " importprunedfunds " , & importprunedfunds , { " rawtransaction " , " txoutproof " } } ,
{ " wallet " , " importpubkey " , & importpubkey , { " pubkey " , " label " , " rescan " } } ,
{ " wallet " , " keypoolrefill " , & keypoolrefill , { " newsize " } } ,
{ " wallet " , " listaccounts " , & listaccounts , { " minconf " , " include_watchonly " } } ,
{ " wallet " , " listaddressgroupings " , & listaddressgroupings , { } } ,
{ " wallet " , " listlockunspent " , & listlockunspent , { } } ,
{ " wallet " , " listreceivedbylabel " , & listreceivedbylabel , { " minconf " , " include_empty " , " include_watchonly " } } ,
@ -3872,12 +4004,9 @@ static const CRPCCommand commands[] =
{ " wallet " , " listunspent " , & listunspent , { " minconf " , " maxconf " , " addresses " , " include_unsafe " , " query_options " } } ,
{ " wallet " , " listwallets " , & listwallets , { } } ,
{ " wallet " , " lockunspent " , & lockunspent , { " unlock " , " transactions " } } ,
{ " wallet " , " move " , & movecmd , { " fromaccount " , " toaccount " , " amount " , " minconf " , " comment " } } ,
{ " wallet " , " sendfrom " , & sendfrom , { " fromaccount " , " toaddress " , " amount " , " minconf " , " comment " , " comment_to " } } ,
{ " wallet " , " sendmany " , & sendmany , { " fromaccount " , " amounts " , " minconf " , " comment " , " subtractfeefrom " , " replaceable " , " conf_target " , " estimate_mode " } } ,
{ " wallet " , " sendtoaddress " , & sendtoaddress , { " address " , " amount " , " comment " , " comment_to " , " subtractfeefromamount " , " replaceable " , " conf_target " , " estimate_mode " } } ,
{ " wallet " , " setlabel " , & setlabel , { " address " , " label " } } ,
{ " wallet " , " setaccount " , & setlabel , { " address " , " account " } } ,
{ " wallet " , " settxfee " , & settxfee , { " amount " } } ,
{ " wallet " , " signmessage " , & signmessage , { " address " , " message " } } ,
{ " wallet " , " signrawtransactionwithwallet " , & signrawtransactionwithwallet , { " hexstring " , " prevtxs " , " sighashtype " } } ,
@ -3887,6 +4016,24 @@ static const CRPCCommand commands[] =
{ " wallet " , " removeprunedfunds " , & removeprunedfunds , { " txid " } } ,
{ " wallet " , " rescanblockchain " , & rescanblockchain , { " start_height " , " stop_height " } } ,
/** Account functions (deprecated) */
{ " wallet " , " getaccountaddress " , & getlabeladdress , { " account " } } ,
{ " wallet " , " getaccount " , & getaccount , { " address " } } ,
{ " wallet " , " getaddressesbyaccount " , & getaddressesbyaccount , { " account " } } ,
{ " wallet " , " getreceivedbyaccount " , & getreceivedbylabel , { " account " , " minconf " } } ,
{ " wallet " , " listaccounts " , & listaccounts , { " minconf " , " include_watchonly " } } ,
{ " wallet " , " listreceivedbyaccount " , & listreceivedbylabel , { " minconf " , " include_empty " , " include_watchonly " } } ,
{ " wallet " , " setaccount " , & setlabel , { " address " , " account " } } ,
{ " wallet " , " move " , & movecmd , { " fromaccount " , " toaccount " , " amount " , " minconf " , " comment " } } ,
/** Label functions (to replace non-balance account functions) */
{ " wallet " , " getlabeladdress " , & getlabeladdress , { " label " , " force " } } ,
{ " wallet " , " getaddressesbylabel " , & getaddressesbylabel , { " label " } } ,
{ " wallet " , " getreceivedbylabel " , & getreceivedbylabel , { " label " , " minconf " } } ,
{ " wallet " , " listlabels " , & listlabels , { " purpose " } } ,
{ " wallet " , " listreceivedbylabel " , & listreceivedbylabel , { " minconf " , " include_empty " , " include_watchonly " } } ,
{ " wallet " , " setlabel " , & setlabel , { " address " , " label " } } ,
{ " generating " , " generate " , & generate , { " nblocks " , " maxtries " } } ,
} ;