Skip to content

Commit 67d1ae5

Browse files
committed
Merge bitcoin#354: rpc: Make name_show RPC command error for expired names
ac4bd9c rpc: Amend copyright notice in names.cpp (yanmaani) 9d333c1 doc: Add release notes for PR bitcoin#354 (yanmaani) fd5987a rpc: Change default value of allow_expired to false (yanmaani) bac4eff test: Make name tests explicitly set -allowexpired parameter (yanmaani) ffa06a6 test: Add functional test for allow_expired options and parameters (yanmaani) 36bdf42 cli: Add parameter -allowexpired for whether to allow expired names by default (yanmaani) 866dafd rpc: Make name_show take option for whether to error on expired names (yanmaani) 3915272 rpc: Let name_show error for expired names (disabled by default) (yanmaani) Pull request description: This set of changes makes `name_show` throw an error for expired names. This behavior can be overridden by setting the `allowExpired` RPC option to true, or by using the `-allowexpired` command-line parameter. This behavior is discussed in issue bitcoin#194. Top commit has no ACKs. Tree-SHA512: 8e41f54f32b1aaf180d410526f2442d261d9861b9a194dbb25feb3ea3eb7ec4748e4be669a12a32ec9ad0ead4c7b4129ab35dd08e635bc578ac2e81a2ae180c4
2 parents 774b638 + ac4bd9c commit 67d1ae5

11 files changed

+125
-7
lines changed

doc/release-notes-namecoin.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Version 0.21
44

5+
- `name_show` now (by default) shows an error for expired names. This can be
6+
overridden by setting the `allowExpired` RPC option to true, or by using the
7+
`-allowexpired` command-line parameter.
8+
For more context,
9+
see [issue #194](https://github.com/namecoin/namecoin-core/issues/194).
10+
511
- By enabling `-namehashindex`, Namecoin Core can now keep track of a separate
612
database that maps hashes to preimages for all registered names. With this,
713
`name_show` and `name_history` can now optionally look up names by hash.

src/init.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <policy/policy.h>
4141
#include <policy/settings.h>
4242
#include <rpc/blockchain.h>
43+
#include <rpc/names.h>
4344
#include <rpc/register.h>
4445
#include <rpc/server.h>
4546
#include <rpc/util.h>
@@ -584,6 +585,7 @@ void SetupServerArgs(NodeContext& node)
584585
gArgs.AddArg("-nameencoding=<enc>", strprintf("Sets the default encoding used for names in the RPC interface (default: %s)", EncodingToString(DEFAULT_NAME_ENCODING)), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
585586
gArgs.AddArg("-valueencoding=<enc>", strprintf("Sets the default encoding used for values in the RPC interface (default: %s)", EncodingToString(DEFAULT_VALUE_ENCODING)), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
586587
gArgs.AddArg("-limitnamechains=<n>", strprintf("Limit pending chains of name operations for name_update to <n> (default: %u)", DEFAULT_NAME_CHAIN_LIMIT), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
588+
gArgs.AddArg("-allowexpired", strprintf("Throw error on expired names (default: %u)", DEFAULT_ALLOWEXPIRED), ArgsManager::ALLOW_BOOL, OptionsCategory::RPC);
587589

588590
#if HAVE_DECL_DAEMON
589591
argsman.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);

src/rpc/names.cpp

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright (c) 2014-2020 Daniel Kraft
2+
// Copyright (c) 2020 yanmaani
23
// Distributed under the MIT/X11 software license, see the accompanying
34
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
45

@@ -437,11 +438,15 @@ namespace
437438
UniValue
438439
name_show (const JSONRPCRequest& request)
439440
{
441+
const bool allow_expired_default = gArgs.GetBoolArg("-allowexpired", DEFAULT_ALLOWEXPIRED);
442+
440443
NameOptionsHelp optHelp;
441444
optHelp
442445
.withNameEncoding ()
443446
.withValueEncoding ()
444-
.withByHash ();
447+
.withByHash ()
448+
.withArg ("allowExpired", RPCArg::Type::BOOL, allow_expired_default ? "true" : "false",
449+
"Whether to throw error for expired names");
445450

446451
RPCHelpMan ("name_show",
447452
"\nLooks up the current data for the given name. Fails if the name doesn't exist.\n",
@@ -454,6 +459,7 @@ name_show (const JSONRPCRequest& request)
454459
.finish (),
455460
RPCExamples {
456461
HelpExampleCli ("name_show", "\"myname\"")
462+
+ HelpExampleCli ("name_show", R"("myname" '{"allowExpired": false}')")
457463
+ HelpExampleRpc ("name_show", "\"myname\"")
458464
}
459465
).Check (request);
@@ -468,6 +474,17 @@ name_show (const JSONRPCRequest& request)
468474
if (request.params.size () >= 2)
469475
options = request.params[1].get_obj ();
470476

477+
/* Parse and interpret the name_show-specific options. */
478+
RPCTypeCheckObj(options,
479+
{
480+
{"allowExpired", UniValueType(UniValue::VBOOL)},
481+
},
482+
true, false);
483+
484+
bool allow_expired = allow_expired_default;
485+
if (options.exists("allowExpired"))
486+
allow_expired = options["allowExpired"].get_bool();
487+
471488
const valtype name = GetNameForLookup (request.params[0], options);
472489

473490
CNameData data;
@@ -483,7 +500,16 @@ name_show (const JSONRPCRequest& request)
483500

484501
MaybeWalletForRequest wallet(request);
485502
LOCK2 (wallet.getLock (), cs_main);
486-
return getNameInfo (options, name, data, wallet);
503+
UniValue name_object = getNameInfo(options, name, data, wallet);
504+
assert(!name_object["expired"].isNull());
505+
const bool is_expired = name_object["expired"].get_bool();
506+
if (is_expired && !allow_expired)
507+
{
508+
std::ostringstream msg;
509+
msg << "name not found: " << EncodeNameForMessage(name);
510+
throw JSONRPCError(RPC_WALLET_ERROR, msg.str());
511+
}
512+
return name_object;
487513
}
488514

489515
/* ************************************************************************** */

src/rpc/names.h

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#include <string>
1414
#include <vector>
1515

16+
/** Default value for the -allowexpired argument. */
17+
static constexpr bool DEFAULT_ALLOWEXPIRED = false;
18+
1619
class CNameData;
1720
class COutPoint;
1821
class CScript;

test/functional/name_allowexpired.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python3
2+
# Licensed under CC0 (Public domain)
3+
4+
# Test that name_show displays expired names if allow_expired = true,
5+
# and otherwise throws "not found" errors (if allow_expired = false).
6+
7+
from test_framework.names import NameTestFramework
8+
from test_framework.util import *
9+
10+
class NameExpirationTest(NameTestFramework):
11+
12+
def set_test_params(self):
13+
self.num_nodes = 2
14+
self.setup_name_test([
15+
["-allowexpired"],
16+
["-noallowexpired"]
17+
])
18+
19+
def run_test(self):
20+
idx_allow = 0
21+
idx_disallow = 1
22+
node = self.nodes[idx_allow]
23+
node_disallow = self.nodes[idx_disallow]
24+
node.generate(200)
25+
26+
self.log.info("Begin registration of two names.")
27+
# "d/active" and (2) "d/expired".
28+
# "d/active" will be renewed.
29+
# "d/expired" will be let to lapse.
30+
#
31+
# To look up "d/expired" should either succeed or throw an error,
32+
# depending on the values of (1) the JSON option allowExpired
33+
# and (2) the command-line parameter -allowexpired.
34+
# Looking up "d/active" should always succeed regardless.
35+
new_active = node.name_new("d/active")
36+
new_expired = node.name_new("d/expired")
37+
node.generate(12)
38+
39+
self.log.info("Register the names.")
40+
self.firstupdateName(0, "d/active", new_active, "value")
41+
self.firstupdateName(0, "d/expired", new_expired, "value")
42+
node.generate(1)
43+
# names on regtest expire after 30 blocks
44+
self.log.info("Wait 1 block, make sure domains registered.")
45+
self.checkName(0, "d/active", "value", 30, False)
46+
self.checkName(0, "d/expired", "value", 30, False)
47+
48+
self.log.info("Let half a registration interval pass.")
49+
node.generate(15)
50+
51+
self.log.info("Renew d/active.")
52+
node.name_update("d/active", "renewed")
53+
# Don't renew d/expired.
54+
self.log.info("Let d/expired lapse.")
55+
node.generate(16)
56+
# 30 - 15 = 15
57+
58+
self.log.info("Check default behaviors.")
59+
self.sync_blocks(self.nodes)
60+
self.checkName(idx_allow, "d/expired", "value", -1, True)
61+
assert_raises_rpc_error(-4, 'name not found',
62+
node_disallow.name_show, "d/expired")
63+
64+
self.log.info("Check positive JSON overrides.")
65+
# checkName only accepts one parameter, use checkNameData
66+
self.checkNameData(
67+
node.name_show("d/expired", {"allowExpired": True}),
68+
"d/expired", "value", -1, True)
69+
self.checkNameData(
70+
node_disallow.name_show("d/expired", {"allowExpired": True}),
71+
"d/expired", "value", -1, True)
72+
73+
self.log.info("Check negative JSON overrides.")
74+
assert_raises_rpc_error(-4, 'name not found',
75+
node.name_show, "d/expired", {"allowExpired": False})
76+
assert_raises_rpc_error(-4, 'name not found',
77+
node_disallow.name_show, "d/expired", {"allowExpired": False})
78+
79+
if __name__ == '__main__':
80+
NameExpirationTest ().main ()

test/functional/name_expiration.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class NameExpirationTest (NameTestFramework):
1313

1414
def set_test_params (self):
1515
self.setup_clean_chain = True
16-
self.setup_name_test ([["-namehistory"]])
16+
self.setup_name_test ([["-namehistory", "-allowexpired"]])
1717

1818
def checkUTXO (self, name, shouldBeThere):
1919
"""

test/functional/name_listunspent.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class NameListUnspentTest (NameTestFramework):
1212

1313
def set_test_params (self):
14-
self.setup_name_test ([[]] * 2)
14+
self.setup_name_test ([["-allowexpired"]] * 2)
1515

1616
def lookupName (self, ind, name, **kwargs):
1717
"""Wrapper around lookup that gets txid and vout from the name."""

test/functional/name_registration.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class NameRegistrationTest (NameTestFramework):
1313

1414
def set_test_params (self):
1515
self.setup_clean_chain = True
16-
self.setup_name_test ([["-namehistory"], []])
16+
self.setup_name_test ([["-namehistory", "-allowexpired"], []])
1717

1818
def generateToOther (self, n):
1919
"""

test/functional/name_utxo.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class NameUtxoTest (NameTestFramework):
1313

1414
def set_test_params (self):
15-
self.setup_name_test ([[]] * 1)
15+
self.setup_name_test ([["-allowexpired"]] * 1)
1616

1717
def run_test (self):
1818
node = self.nodes[0]

test/functional/name_wallet.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class NameWalletTest (NameTestFramework):
2222

2323
def set_test_params (self):
2424
self.setup_clean_chain = True
25-
self.setup_name_test ([["-paytxfee=%s" % txFee]] * 2)
25+
self.setup_name_test ([["-paytxfee=%s" % txFee, "-allowexpired"]] * 2)
2626

2727
def generateToOther (self, ind, n):
2828
"""

test/functional/test_runner.py

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@
262262
'auxpow_zerohash.py',
263263

264264
# name tests
265+
'name_allowexpired.py',
265266
'name_ant_workflow.py',
266267
'name_byhash.py',
267268
'name_encodings.py',

0 commit comments

Comments
 (0)