Skip to content

Commit 540f1ad

Browse files
committed
Replace toaddress argument with options dictionary.
This replaces the "toaddress" optional arguments that name_firstupdate and name_update have with an "options" dictionary, where "destAddress" can be set instead: name_update foo bar addr becomes name_upate foo bar {"destAddress": addr} This is a first step towards namecoin/namecoin-core#194. In the future, more options keys can and will be defined.
1 parent 0d3d726 commit 540f1ad

File tree

9 files changed

+139
-80
lines changed

9 files changed

+139
-80
lines changed

src/rpc/client.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
147147
{ "name_filter", 1, "maxage" },
148148
{ "name_filter", 2, "from" },
149149
{ "name_filter", 3, "nb" },
150+
{ "name_firstupdate", 4, "options" },
150151
{ "name_firstupdate", 5, "allow_active" },
152+
{ "name_update", 2, "options" },
151153
{ "namerawtransaction", 1, "vout" },
152154
{ "namerawtransaction", 2, "nameop" },
153155
{ "sendtoname", 1, "amount" },

src/wallet/rpcnames.cpp

Lines changed: 113 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#include <univalue.h>
2323

24+
#include <memory>
25+
2426
namespace
2527
{
2628

@@ -66,6 +68,98 @@ getNamePrevout (const uint256& txid, CTxOut& txOut, CTxIn& txIn)
6668
return false;
6769
}
6870

71+
/**
72+
* A simple helper class that handles determination of the address to which
73+
* name outputs should be sent. It handles the CReserveKey reservation
74+
* as well as parsing the explicit options given by the user (if any).
75+
*/
76+
class DestinationAddressHelper
77+
{
78+
79+
private:
80+
81+
/** Reference to the wallet that should be used. */
82+
CWallet& wallet;
83+
84+
/**
85+
* The reserve key that was used if no override is given. When finalising
86+
* (after the sending succeeded), this key needs to be marked as KeepKey().
87+
*/
88+
std::unique_ptr<CReserveKey> reserveKey;
89+
90+
/** Set if a valid override destination was added. */
91+
std::unique_ptr<CTxDestination> overrideDest;
92+
93+
public:
94+
95+
explicit DestinationAddressHelper (CWallet& w)
96+
: wallet(w)
97+
{}
98+
99+
/**
100+
* Processes the given options object to see if it contains an override
101+
* destination. If it does, remembers it.
102+
*/
103+
void setOptions (const UniValue& opt);
104+
105+
/**
106+
* Returns the script that should be used as destination.
107+
*/
108+
CScript getScript ();
109+
110+
/**
111+
* Marks the key as used if one has been reserved. This should be called
112+
* when sending succeeded.
113+
*/
114+
void finalise ();
115+
116+
};
117+
118+
void DestinationAddressHelper::setOptions (const UniValue& opt)
119+
{
120+
RPCTypeCheckObj (opt,
121+
{
122+
{"destAddress", UniValueType (UniValue::VSTR)},
123+
},
124+
true, false);
125+
if (!opt.exists ("destAddress"))
126+
return;
127+
128+
CTxDestination dest = DecodeDestination (opt["destAddress"].get_str ());
129+
if (!IsValidDestination (dest))
130+
throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address");
131+
overrideDest.reset (new CTxDestination (std::move (dest)));
132+
}
133+
134+
CScript DestinationAddressHelper::getScript ()
135+
{
136+
if (overrideDest != nullptr)
137+
return GetScriptForDestination (*overrideDest);
138+
139+
reserveKey.reset (new CReserveKey (&wallet));
140+
CPubKey pubKeyReserve;
141+
const bool ok = reserveKey->GetReservedKey (pubKeyReserve, true);
142+
assert (ok);
143+
144+
return GetScriptForDestination (pubKeyReserve.GetID ());
145+
}
146+
147+
void DestinationAddressHelper::finalise ()
148+
{
149+
if (reserveKey != nullptr)
150+
reserveKey->KeepKey ();
151+
}
152+
153+
/**
154+
* Returns the help text for the options argument for name operations.
155+
*/
156+
std::string getNameOpOptionsHelp ()
157+
{
158+
return " {\n"
159+
" \"destAddress\" (string, optional) The address to send the name output to\n"
160+
" }\n";
161+
}
162+
69163
} // namespace
70164

71165
/* ************************************************************************** */
@@ -267,7 +361,7 @@ name_firstupdate (const JSONRPCRequest& request)
267361

268362
if (request.fHelp || request.params.size () < 4 || request.params.size () > 6)
269363
throw std::runtime_error (
270-
"name_firstupdate \"name\" \"rand\" \"tx\" \"value\" (\"toaddress\")\n"
364+
"name_firstupdate \"name\" \"rand\" \"tx\" \"value\" (\"options\")\n"
271365
"\nFinish the registration of a name. Depends on name_new being"
272366
" already issued.\n"
273367
+ HelpRequiringPassphrase (pwallet) +
@@ -276,18 +370,18 @@ name_firstupdate (const JSONRPCRequest& request)
276370
"2. \"rand\" (string, required) the rand value of name_new\n"
277371
"3. \"tx\" (string, required) the name_new txid\n"
278372
"4. \"value\" (string, required) value for the name\n"
279-
"5. \"toaddress\" (string, optional) address to send the name to\n"
373+
"5. \"options\" (object, optional)\n"
374+
+ getNameOpOptionsHelp () +
280375
"\nResult:\n"
281376
"\"txid\" (string) the name_firstupdate's txid\n"
282377
"\nExamples:\n"
283378
+ HelpExampleCli ("name_firstupdate", "\"myname\", \"555844f2db9c7f4b25da6cb8277596de45021ef2\" \"a77ceb22aa03304b7de64ec43328974aeaca211c37dd29dcce4ae461bb80ca84\", \"my-value\"")
284-
+ HelpExampleCli ("name_firstupdate", "\"myname\", \"555844f2db9c7f4b25da6cb8277596de45021ef2\" \"a77ceb22aa03304b7de64ec43328974aeaca211c37dd29dcce4ae461bb80ca84\", \"my-value\", \"NEX4nME5p3iyNK3gFh4FUeUriHXxEFemo9\"")
285379
+ HelpExampleRpc ("name_firstupdate", "\"myname\", \"555844f2db9c7f4b25da6cb8277596de45021ef2\" \"a77ceb22aa03304b7de64ec43328974aeaca211c37dd29dcce4ae461bb80ca84\", \"my-value\"")
286380
);
287381

288382
RPCTypeCheck (request.params,
289383
{UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VSTR,
290-
UniValue::VSTR});
384+
UniValue::VOBJ});
291385

292386
const std::string nameStr = request.params[0].get_str ();
293387
const valtype name = ValtypeFromString (nameStr);
@@ -343,40 +437,20 @@ name_firstupdate (const JSONRPCRequest& request)
343437

344438
EnsureWalletIsUnlocked (pwallet);
345439

346-
CReserveKey keyName(pwallet);
347-
CPubKey pubKeyReserve;
348-
const bool ok = keyName.GetReservedKey (pubKeyReserve, true);
349-
assert (ok);
350-
bool usedKey = false;
351-
352-
CScript addrName;
440+
DestinationAddressHelper destHelper(*pwallet);
353441
if (request.params.size () >= 5)
354-
{
355-
keyName.ReturnKey ();
356-
const CTxDestination dest
357-
= DecodeDestination(request.params[4].get_str ());
358-
if (!IsValidDestination(dest))
359-
throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address");
360-
361-
addrName = GetScriptForDestination (dest);
362-
}
363-
else
364-
{
365-
usedKey = true;
366-
addrName = GetScriptForDestination (pubKeyReserve.GetID ());
367-
}
442+
destHelper.setOptions (request.params[4].get_obj ());
368443

369444
const CScript nameScript
370-
= CNameScript::buildNameFirstupdate (addrName, name, value, rand);
445+
= CNameScript::buildNameFirstupdate (destHelper.getScript (), name, value,
446+
rand);
371447

372448
CCoinControl coinControl;
373449
CTransactionRef tx = SendMoneyToScript (pwallet, nameScript, &txIn,
374450
NAME_LOCKED_AMOUNT, false,
375451
coinControl, {}, {});
376452

377-
if (usedKey)
378-
keyName.KeepKey ();
379-
453+
destHelper.finalise ();
380454
return tx->GetHash ().GetHex ();
381455
}
382456

@@ -394,23 +468,23 @@ name_update (const JSONRPCRequest& request)
394468
if (request.fHelp
395469
|| (request.params.size () != 2 && request.params.size () != 3))
396470
throw std::runtime_error (
397-
"name_update \"name\" \"value\" (\"toaddress\")\n"
471+
"name_update \"name\" \"value\" (\"options\")\n"
398472
"\nUpdate a name and possibly transfer it.\n"
399473
+ HelpRequiringPassphrase (pwallet) +
400474
"\nArguments:\n"
401475
"1. \"name\" (string, required) the name to update\n"
402-
"4. \"value\" (string, required) value for the name\n"
403-
"5. \"toaddress\" (string, optional) address to send the name to\n"
476+
"2. \"value\" (string, required) value for the name\n"
477+
"3. \"options\" (object, optional)\n"
478+
+ getNameOpOptionsHelp () +
404479
"\nResult:\n"
405480
"\"txid\" (string) the name_update's txid\n"
406481
"\nExamples:\n"
407482
+ HelpExampleCli ("name_update", "\"myname\", \"new-value\"")
408-
+ HelpExampleCli ("name_update", "\"myname\", \"new-value\", \"NEX4nME5p3iyNK3gFh4FUeUriHXxEFemo9\"")
409483
+ HelpExampleRpc ("name_update", "\"myname\", \"new-value\"")
410484
);
411485

412486
RPCTypeCheck (request.params,
413-
{UniValue::VSTR, UniValue::VSTR, UniValue::VSTR});
487+
{UniValue::VSTR, UniValue::VSTR, UniValue::VOBJ});
414488

415489
const std::string nameStr = request.params[0].get_str ();
416490
const valtype name = ValtypeFromString (nameStr);
@@ -447,40 +521,19 @@ name_update (const JSONRPCRequest& request)
447521

448522
EnsureWalletIsUnlocked (pwallet);
449523

450-
CReserveKey keyName(pwallet);
451-
CPubKey pubKeyReserve;
452-
const bool ok = keyName.GetReservedKey (pubKeyReserve, true);
453-
assert (ok);
454-
bool usedKey = false;
455-
456-
CScript addrName;
457-
if (request.params.size () == 3)
458-
{
459-
keyName.ReturnKey ();
460-
const CTxDestination dest
461-
= DecodeDestination (request.params[2].get_str ());
462-
if (!IsValidDestination (dest))
463-
throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address");
464-
465-
addrName = GetScriptForDestination (dest);
466-
}
467-
else
468-
{
469-
usedKey = true;
470-
addrName = GetScriptForDestination (pubKeyReserve.GetID ());
471-
}
524+
DestinationAddressHelper destHelper(*pwallet);
525+
if (request.params.size () >= 3)
526+
destHelper.setOptions (request.params[2].get_obj ());
472527

473528
const CScript nameScript
474-
= CNameScript::buildNameUpdate (addrName, name, value);
529+
= CNameScript::buildNameUpdate (destHelper.getScript (), name, value);
475530

476531
CCoinControl coinControl;
477532
CTransactionRef tx = SendMoneyToScript (pwallet, nameScript, &txIn,
478533
NAME_LOCKED_AMOUNT, false,
479534
coinControl, {}, {});
480535

481-
if (usedKey)
482-
keyName.KeepKey ();
483-
536+
destHelper.finalise ();
484537
return tx->GetHash ().GetHex ();
485538
}
486539

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4525,8 +4525,8 @@ static const CRPCCommand commands[] =
45254525
// Name-related wallet calls.
45264526
{ "names", "name_list", &name_list, {"name"} },
45274527
{ "names", "name_new", &name_new, {"name"} },
4528-
{ "names", "name_firstupdate", &name_firstupdate, {"name","rand","tx","value","toaddress","allow_active"} },
4529-
{ "names", "name_update", &name_update, {"name","value","toaddress"} },
4528+
{ "names", "name_firstupdate", &name_firstupdate, {"name","rand","tx","value","options","allow_active"} },
4529+
{ "names", "name_update", &name_update, {"name","value","options"} },
45304530
{ "names", "sendtoname", &sendtoname, {"name","amount","comment","comment_to","subtractfeefromamount"} },
45314531
};
45324532

test/functional/name_list.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
# Copyright (c) 2014-2017 Daniel Kraft
2+
# Copyright (c) 2014-2018 Daniel Kraft
33
# Distributed under the MIT/X11 software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -37,7 +37,7 @@ def run_test (self):
3737
# Transfer a name away and check that name_list updates accordingly.
3838

3939
addrB = self.nodes[1].getnewaddress ()
40-
self.nodes[0].name_update ("name-a", "enjoy", addrB)
40+
self.nodes[0].name_update ("name-a", "enjoy", {"destAddress":addrB})
4141
arr = self.nodes[0].name_list ()
4242
assert_equal (len (arr), 1)
4343
self.checkNameStatus (arr[0], "name-a", "value-a", False, False)
@@ -64,7 +64,7 @@ def run_test (self):
6464

6565
# Transfer it back and see that it updates in wallet A.
6666
addrA = self.nodes[0].getnewaddress ()
67-
self.nodes[1].name_update ("name-a", "sent", addrA)
67+
self.nodes[1].name_update ("name-a", "sent", {"destAddress": addrA})
6868
self.generate (0, 1)
6969
arr = self.nodes[0].name_list ()
7070
assert_equal (len (arr), 1)

test/functional/name_multisig.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def run_test (self):
2828
# Register a new name to that address.
2929
new = self.nodes[0].name_new ("name")
3030
self.generate (0, 10)
31-
self.firstupdateName (0, "name", new, "value", p2sh)
31+
self.firstupdateName (0, "name", new, "value", {"destAddress": p2sh})
3232
self.generate (1, 5)
3333
data = self.checkName (2, "name", "value", None, False)
3434
assert_equal (data['address'], p2sh)

test/functional/name_pending.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def run_test (self):
8383
assert_equal (pending['vout'], confirmed['vout'])
8484

8585
# Send a name and check that ismine is handled correctly.
86-
tx = self.nodes[1].name_update ('a', 'sent-a', addrC)
86+
tx = self.nodes[1].name_update ('a', 'sent-a', {"destAddress":addrC})
8787
self.sync_with_mode ('mempool')
8888
self.checkPendingName (1, 'a', 'name_update', 'sent-a', tx, False)
8989
self.checkPendingName (3, 'a', 'name_update', 'sent-a', tx, True)

test/functional/name_registration.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
# Copyright (c) 2014-2017 Daniel Kraft
2+
# Copyright (c) 2014-2018 Daniel Kraft
33
# Distributed under the MIT/X11 software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -29,7 +29,8 @@ def run_test (self):
2929

3030
# first_update the names. Check for too long values.
3131
addrA = self.nodes[0].getnewaddress ()
32-
txidA = self.firstupdateName (0, "node-0", newA, "value-0", addrA)
32+
txidA = self.firstupdateName (0, "node-0", newA, "value-0",
33+
{"destAddress": addrA})
3334
assert_raises_rpc_error (-8, 'value is too long',
3435
self.firstupdateName, 1, "node-1", newB, "x" * 521)
3536
self.firstupdateName (1, "node-1", newB, "x" * 520)
@@ -107,7 +108,7 @@ def run_test (self):
107108
self.checkNameHistory (1, "test-name", ["test-value", "x" * 520])
108109

109110
addrB = self.nodes[1].getnewaddress ()
110-
self.nodes[0].name_update ("test-name", "sent", addrB)
111+
self.nodes[0].name_update ("test-name", "sent", {"destAddress": addrB})
111112
self.generate (0, 1)
112113
data = self.checkName (0, "test-name", "sent", 30, False)
113114
assert_equal (data['address'], addrB)
@@ -153,7 +154,7 @@ def run_test (self):
153154
addr0 = self.nodes[0].getnewaddress ()
154155
self.nodes[1].sendtoaddress (addr0, balance - keep, "", "", True)
155156
addr1 = self.nodes[1].getnewaddress ()
156-
self.nodes[0].name_update ("node-1", "value", addr1)
157+
self.nodes[0].name_update ("node-1", "value", {"destAddress": addr1})
157158
self.generate (0, 1)
158159
assert_equal (self.nodes[1].getbalance (), keep)
159160
self.nodes[1].name_update ("node-1", "new value")

test/functional/name_wallet.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,15 @@ def run_test (self):
152152
fee += self.getFee (2, newC[0], nameFee)
153153
self.generate (0, 5)
154154
self.checkBalances (fee)
155-
firstB = self.firstupdateName (2, "name-b", newB, "value", addrB)
155+
firstB = self.firstupdateName (2, "name-b", newB, "value",
156+
{"destAddress": addrB})
156157
fee = self.getFee (2, firstB)
157158
firstC = self.firstupdateName (2, "name-c", newC, "value")
158159
fee += self.getFee (2, firstC)
159160
self.generate (0, 10)
160161
self.checkBalances (fee)
161-
updC = self.nodes[2].name_update ("name-c", "new value", addrB)
162+
updC = self.nodes[2].name_update ("name-c", "new value",
163+
{"destAddress": addrB})
162164
fee = self.getFee (2, updC)
163165
self.generate (0, 1)
164166
self.checkBalances (fee)
@@ -191,7 +193,8 @@ def run_test (self):
191193
addrDest = self.nodes[2].getnewaddress ()
192194
newDest = self.nodes[0].name_new ("destination")
193195
self.generate (0, 5)
194-
self.firstupdateName (0, "destination", newDest, "value", addrDest)
196+
self.firstupdateName (0, "destination", newDest, "value",
197+
{"destAddress": addrDest})
195198
self.generate (0, 10)
196199
self.checkName (3, "destination", "value", None, False)
197200

0 commit comments

Comments
 (0)