Skip to content

Commit

Permalink
Support names in "query" RPC command. (kyuupichan#875)
Browse files Browse the repository at this point in the history
This extends the "query" RPC command so that it also allows querying
for the name index in Namecoin (and potential future coins that support
a name index as well).

Previously, that was not possible even when passing the normalised
script itself:  In that case, hashX_from_script would strip off the name
prefix again, and thus the query would only be for OP_RETURN.  (Thanks to
JeremyRand for analysing this bug!)
  • Loading branch information
domob1812 authored and Neil committed Jul 26, 2019
1 parent 2a67f12 commit 5618902
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 23 deletions.
3 changes: 2 additions & 1 deletion docs/rpc-interface.rst
Expand Up @@ -204,7 +204,8 @@ query
-----

Run a query of the UTXO and history databases against one or more
addresses or hex scripts. `--limit <N>` or `-l <N>` limits the output
addresses, hex scripts or ASCII names (for coins that have an index
on names like Namecoin). `--limit <N>` or `-l <N>` limits the output
for each kind to that many entries. History is printed in blockchain
order; UTXOs in an arbitrary order.

Expand Down
41 changes: 25 additions & 16 deletions electrumx/lib/coins.py
Expand Up @@ -942,6 +942,27 @@ class Namecoin(NameMixin, AuxPowMixin, Coin):
]
BLOCK_PROCESSOR = block_proc.NamecoinBlockProcessor

# Name opcodes
OP_NAME_NEW = OpCodes.OP_1
OP_NAME_FIRSTUPDATE = OpCodes.OP_2
OP_NAME_UPDATE = OpCodes.OP_3

@classmethod
def build_name_index_script(cls, name):
"""Returns the normalised script by which names are indexed"""

from electrumx.lib.script import Script

normalized_name_op_script = bytearray()
normalized_name_op_script.append(cls.OP_NAME_UPDATE)
normalized_name_op_script.extend(Script.push_data(name))
normalized_name_op_script.extend(Script.push_data(bytes([])))
normalized_name_op_script.append(OpCodes.OP_2DROP)
normalized_name_op_script.append(OpCodes.OP_DROP)
normalized_name_op_script.append(OpCodes.OP_RETURN)

return bytes(normalized_name_op_script)

@classmethod
def split_name_script(cls, script):
from electrumx.lib.script import _match_ops, Script, ScriptError
Expand All @@ -953,16 +974,11 @@ def split_name_script(cls, script):

match = _match_ops

# Name opcodes
OP_NAME_NEW = OpCodes.OP_1
OP_NAME_FIRSTUPDATE = OpCodes.OP_2
OP_NAME_UPDATE = OpCodes.OP_3

# Opcode sequences for name operations
NAME_NEW_OPS = [OP_NAME_NEW, -1, OpCodes.OP_2DROP]
NAME_FIRSTUPDATE_OPS = [OP_NAME_FIRSTUPDATE, -1, -1, -1,
NAME_NEW_OPS = [cls.OP_NAME_NEW, -1, OpCodes.OP_2DROP]
NAME_FIRSTUPDATE_OPS = [cls.OP_NAME_FIRSTUPDATE, -1, -1, -1,
OpCodes.OP_2DROP, OpCodes.OP_2DROP]
NAME_UPDATE_OPS = [OP_NAME_UPDATE, -1, -1, OpCodes.OP_2DROP,
NAME_UPDATE_OPS = [cls.OP_NAME_UPDATE, -1, -1, OpCodes.OP_2DROP,
OpCodes.OP_DROP]

name_script_op_count = None
Expand Down Expand Up @@ -991,14 +1007,7 @@ def split_name_script(cls, script):
if name_pushdata is None:
return None, address_script

normalized_name_op_script = bytearray()
normalized_name_op_script.append(OP_NAME_UPDATE)
normalized_name_op_script.extend(Script.push_data(name_pushdata[1]))
normalized_name_op_script.extend(Script.push_data(bytes([])))
normalized_name_op_script.append(OpCodes.OP_2DROP)
normalized_name_op_script.append(OpCodes.OP_DROP)
normalized_name_op_script.append(OpCodes.OP_RETURN)

normalized_name_op_script = cls.build_name_index_script(name_pushdata[1])
return bytes(normalized_name_op_script), address_script

@classmethod
Expand Down
21 changes: 15 additions & 6 deletions electrumx/server/session.py
Expand Up @@ -490,7 +490,7 @@ async def rpc_peers(self):
return self.peer_mgr.rpc_data()

async def rpc_query(self, items, limit):
'''Return a list of data about server peers.'''
'''Returns data about a script, address or name.'''
coin = self.env.coin
db = self.db
lines = []
Expand All @@ -505,11 +505,20 @@ def arg_to_hashX(arg):

try:
hashX = coin.address_to_hashX(arg)
except Base58Error as e:
lines.append(e.args[0])
return None
lines.append(f'Address: {arg}')
return hashX
lines.append(f'Address: {arg}')
return hashX
except Base58Error:
pass

try:
script = coin.build_name_index_script(arg.encode("ascii"))
hashX = coin.name_hashX_from_script(script)
lines.append(f'Name: {arg}')
return hashX
except (AttributeError, UnicodeEncodeError):
pass

return None

for arg in items:
hashX = arg_to_hashX(arg)
Expand Down

0 comments on commit 5618902

Please sign in to comment.