From 47565b5c44a73c3188093e1602b8c02b595f7492 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Tue, 3 Sep 2019 10:11:17 +0200 Subject: [PATCH] Add name index for Xaya (#890) * Rename NamecoinBlockProcessor. For Xaya, we will use the same kind of logic for keeping track of an index of names in addition to the index of addresses. Thus it makes sense to call it by some more generic name. Here, we rename it to NameIndexBlockProcessor. * Create NameIndexMixin from Namecoin. This factors out some code from Namecoin to a new NameIndexMixin. This code is what we need to keep track of a name index in addition to the address index, as done by the NameIndexBlockProcessor. With the code factored out, the Coin itself only needs to define the set of possible name operations it allows (and where they have the name by which the index will be built). For now, this is only used by Namecoin. But in the future, we will use it for Xaya as well. * Add name indexing to Xaya. Change the Xaya definition so that it handles name scripts correctly: We want to strip them off the "real" address for indexing by address, and we want to keep a separate index on names like Namecoin does. --- electrumx/lib/coins.py | 144 ++++++++++-------- electrumx/server/block_processor.py | 2 +- .../xaya_mainnet_namereg_a32f38.json | 60 ++++++++ .../xaya_mainnet_nameupd_83747d.json | 69 +++++++++ 4 files changed, 210 insertions(+), 65 deletions(-) create mode 100644 tests/transactions/xaya_mainnet_namereg_a32f38.json create mode 100644 tests/transactions/xaya_mainnet_nameupd_83747d.json diff --git a/electrumx/lib/coins.py b/electrumx/lib/coins.py index 9cbc98e..9721759 100644 --- a/electrumx/lib/coins.py +++ b/electrumx/lib/coins.py @@ -427,6 +427,58 @@ class NameMixin(object): return named_values, address_script +class NameIndexMixin(NameMixin): + """Shared definitions for coins that have a name index + + This class defines common functions and logic for coins that have + a name index in addition to the index by address / script.""" + + BLOCK_PROCESSOR = block_proc.NameIndexBlockProcessor + + @classmethod + def build_name_index_script(cls, name): + """Returns the script by which names are indexed""" + + from electrumx.lib.script import Script + + res = bytearray() + res.append(cls.OP_NAME_UPDATE) + res.extend(Script.push_data(name)) + res.extend(Script.push_data(bytes([]))) + res.append(OpCodes.OP_2DROP) + res.append(OpCodes.OP_DROP) + res.append(OpCodes.OP_RETURN) + + return bytes(res) + + @classmethod + def split_name_script(cls, script): + named_values, address_script = cls.interpret_name_prefix(script, cls.NAME_OPERATIONS) + if named_values is None or "name" not in named_values: + return None, address_script + + name_index_script = cls.build_name_index_script(named_values["name"][1]) + return name_index_script, address_script + + @classmethod + def hashX_from_script(cls, script): + _, address_script = cls.split_name_script(script) + return super().hashX_from_script(address_script) + + @classmethod + def address_from_script(cls, script): + _, address_script = cls.split_name_script(script) + return super().address_from_script(address_script) + + @classmethod + def name_hashX_from_script(cls, script): + name_index_script, _ = cls.split_name_script(script) + if name_index_script is None: + return None + + return super().hashX_from_script(name_index_script) + + class HOdlcoin(Coin): NAME = "HOdlcoin" SHORTNAME = "HODLC" @@ -959,7 +1011,7 @@ class Unitus(Coin): # Source: namecoin.org -class Namecoin(NameMixin, AuxPowMixin, Coin): +class Namecoin(NameIndexMixin, AuxPowMixin, Coin): NAME = "Namecoin" SHORTNAME = "NMC" NET = "mainnet" @@ -979,74 +1031,24 @@ class Namecoin(NameMixin, AuxPowMixin, Coin): 'luggscoqbymhvnkp.onion t82', 'ulrichard.ch s50006 t50005', ] - BLOCK_PROCESSOR = block_proc.NamecoinBlockProcessor + BLOCK_PROCESSOR = block_proc.NameIndexBlockProcessor # 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 Script - - # Opcode sequences for name operations - NAME_NEW_OPS = [cls.OP_NAME_NEW, -1, OpCodes.OP_2DROP] - NAME_FIRSTUPDATE_OPS = [cls.OP_NAME_FIRSTUPDATE, "name", -1, -1, - OpCodes.OP_2DROP, OpCodes.OP_2DROP] - NAME_UPDATE_OPS = [cls.OP_NAME_UPDATE, "name", -1, OpCodes.OP_2DROP, - OpCodes.OP_DROP] - - ops = [ - NAME_NEW_OPS, - NAME_FIRSTUPDATE_OPS, - NAME_UPDATE_OPS, - ] - - named_values, address_script = cls.interpret_name_prefix(script, ops) - - if named_values is None or "name" not in named_values: - return None, address_script - - normalized_name_op_script = cls.build_name_index_script(named_values["name"][1]) - return bytes(normalized_name_op_script), address_script - - @classmethod - def hashX_from_script(cls, script): - _name_op_script, address_script = cls.split_name_script(script) - - return super().hashX_from_script(address_script) - - @classmethod - def address_from_script(cls, script): - _name_op_script, address_script = cls.split_name_script(script) - - return super().address_from_script(address_script) - - @classmethod - def name_hashX_from_script(cls, script): - name_op_script, _address_script = cls.split_name_script(script) - - if name_op_script is None: - return None - - return super().hashX_from_script(name_op_script) + # Valid name prefixes. + NAME_NEW_OPS = [OP_NAME_NEW, -1, OpCodes.OP_2DROP] + NAME_FIRSTUPDATE_OPS = [OP_NAME_FIRSTUPDATE, "name", -1, -1, + OpCodes.OP_2DROP, OpCodes.OP_2DROP] + NAME_UPDATE_OPS = [OP_NAME_UPDATE, "name", -1, OpCodes.OP_2DROP, + OpCodes.OP_DROP] + NAME_OPERATIONS = [ + NAME_NEW_OPS, + NAME_FIRSTUPDATE_OPS, + NAME_UPDATE_OPS, + ] class NamecoinTestnet(Namecoin): @@ -3181,7 +3183,7 @@ class CPUchain(Coin): return cpupower.getPoWHash(header) -class Xaya(AuxPowMixin, Coin): +class Xaya(NameIndexMixin, AuxPowMixin, Coin): NAME = "Xaya" SHORTNAME = "CHI" NET = "mainnet" @@ -3203,6 +3205,20 @@ class Xaya(AuxPowMixin, Coin): 'xaya.domob.eu s50002', ] + # Op-codes for name operations + OP_NAME_REGISTER = OpCodes.OP_1 + OP_NAME_UPDATE = OpCodes.OP_2 + + # Valid name prefixes. + NAME_REGISTER_OPS = [OP_NAME_REGISTER, "name", -1, OpCodes.OP_2DROP, + OpCodes.OP_DROP] + NAME_UPDATE_OPS = [OP_NAME_UPDATE, "name", -1, OpCodes.OP_2DROP, + OpCodes.OP_DROP] + NAME_OPERATIONS = [ + NAME_REGISTER_OPS, + NAME_UPDATE_OPS, + ] + @classmethod def genesis_block(cls, block): super().genesis_block(block) diff --git a/electrumx/server/block_processor.py b/electrumx/server/block_processor.py index 883fc5f..fc98400 100644 --- a/electrumx/server/block_processor.py +++ b/electrumx/server/block_processor.py @@ -690,7 +690,7 @@ class DecredBlockProcessor(BlockProcessor): return start, count -class NamecoinBlockProcessor(BlockProcessor): +class NameIndexBlockProcessor(BlockProcessor): def advance_txs(self, txs): result = super().advance_txs(txs) diff --git a/tests/transactions/xaya_mainnet_namereg_a32f38.json b/tests/transactions/xaya_mainnet_namereg_a32f38.json new file mode 100644 index 0000000..22842bc --- /dev/null +++ b/tests/transactions/xaya_mainnet_namereg_a32f38.json @@ -0,0 +1,60 @@ +{ + "txid": "a32f38a463b75f2cb9955f5660063e7888f9120b40f27312b65e53fad6a226fd", + "hash": "a32f38a463b75f2cb9955f5660063e7888f9120b40f27312b65e53fad6a226fd", + "version": 2, + "size": 240, + "vsize": 240, + "weight": 960, + "locktime": 0, + "vin": [ + { + "txid": "c87eb7b9c71146a18f8ebaea93b74bfeb4795b265f151ba5a1e62ef32017bc34", + "vout": 0, + "scriptSig": { + "asm": "3045022100df2c9fdfa19e145a3d1f3b995e2925e6270f02dd13a9d5e79edc0bf7841517d40220722d8c694a21890bb24b82530f7e553371b9123d1e0e8c1ad818fe87c53e3cbb[ALL] 03a2bfae3cc2b43c7ac5e8ae402e1552b9edca7a2ff73ac1950ca52dae73791e95", + "hex": "483045022100df2c9fdfa19e145a3d1f3b995e2925e6270f02dd13a9d5e79edc0bf7841517d40220722d8c694a21890bb24b82530f7e553371b9123d1e0e8c1ad818fe87c53e3cbb012103a2bfae3cc2b43c7ac5e8ae402e1552b9edca7a2ff73ac1950ca52dae73791e95" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 1996928100, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 5026b54aec9036aaf02473481356acb3fe45846a OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9145026b54aec9036aaf02473481356acb3fe45846a88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "CPmgzsvaWeSNvXd5CNfzSLnX2ymjJ7jwtw" + ] + } + }, + { + "value": 1000000, + "n": 1, + "scriptPubKey": { + "nameOp": { + "op": "name_register", + "name": "p/domob", + "name_encoding": "utf8", + "value": "{}", + "value_encoding": "ascii" + }, + "asm": "OP_NAME_REGISTER 702f646f6d6f62 32123 OP_2DROP OP_DROP OP_DUP OP_HASH160 eed2f5ecba300e6137c3a966d60cab012b490e01 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "5107702f646f6d6f62027b7d6d7576a914eed2f5ecba300e6137c3a966d60cab012b490e0188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "CeEg7VvAJ6rtz7MQ9sbkmEEb4zxRbSU4JT" + ] + } + } + ], + "hex": "020000000134bc1720f32ee6a1a51b155f265b79b4fe4bb793eaba8e8fa14611c7b9b77ec8000000006b483045022100df2c9fdfa19e145a3d1f3b995e2925e6270f02dd13a9d5e79edc0bf7841517d40220722d8c694a21890bb24b82530f7e553371b9123d1e0e8c1ad818fe87c53e3cbb012103a2bfae3cc2b43c7ac5e8ae402e1552b9edca7a2ff73ac1950ca52dae73791e95feffffff0264b40677000000001976a9145026b54aec9036aaf02473481356acb3fe45846a88ac40420f0000000000275107702f646f6d6f62027b7d6d7576a914eed2f5ecba300e6137c3a966d60cab012b490e0188ac00000000", + "blockhash": "1efbbbe72b0198a68bd3a9f5d349f4bcb5d87c660262a6c6731c37b1cb61a73e", + "confirmations": 1032707, + "time": 1531484387, + "blocktime": 1531484387 +} diff --git a/tests/transactions/xaya_mainnet_nameupd_83747d.json b/tests/transactions/xaya_mainnet_nameupd_83747d.json new file mode 100644 index 0000000..a0b5a99 --- /dev/null +++ b/tests/transactions/xaya_mainnet_nameupd_83747d.json @@ -0,0 +1,69 @@ +{ + "txid": "83747d1e69e264644f425bc2dae3bedca6d72274a0f2f82b00d9a0a70714c2be", + "hash": "83747d1e69e264644f425bc2dae3bedca6d72274a0f2f82b00d9a0a70714c2be", + "version": 2, + "size": 413, + "vsize": 413, + "weight": 1652, + "locktime": 244772, + "vin": [ + { + "txid": "59d8a63955615b49b550ca9207ae9c5853898370a37efe8fcb4cfbff7eba989e", + "vout": 0, + "scriptSig": { + "asm": "304402202f16982264f61a1bdd08cf5f5aa620fd761419416aceaf65226ba74a932e8ea50220520d2a8755da0f85c257afeb841fab9692807d177fd4693e0697308f658940ed[ALL] 02d9ce309aa25d552cc1e6e2557e4b91b8ad9d055ff74fc4241e6b5b1039792eae", + "hex": "47304402202f16982264f61a1bdd08cf5f5aa620fd761419416aceaf65226ba74a932e8ea50220520d2a8755da0f85c257afeb841fab9692807d177fd4693e0697308f658940ed012102d9ce309aa25d552cc1e6e2557e4b91b8ad9d055ff74fc4241e6b5b1039792eae" + }, + "sequence": 4294967294 + }, + { + "txid": "a32f38a463b75f2cb9955f5660063e7888f9120b40f27312b65e53fad6a226fd", + "vout": 1, + "scriptSig": { + "asm": "3044022030710158479236b1e8da22cbe5710f0b1b1210fdfa3c68dcb955af8137340db8022064f8f2d2c4047f51f0e62ebe2ee2aac7d3eb574f57f497ad828fb2381234d81e[ALL] 03611ff32dd36a49b75873dc3770c1e5f6a83ea8a4f56fa1fd08400b7686eb4c21", + "hex": "473044022030710158479236b1e8da22cbe5710f0b1b1210fdfa3c68dcb955af8137340db8022064f8f2d2c4047f51f0e62ebe2ee2aac7d3eb574f57f497ad828fb2381234d81e012103611ff32dd36a49b75873dc3770c1e5f6a83ea8a4f56fa1fd08400b7686eb4c21" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 473277800, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 13f261c11e7471063893a4821331a1bd4496f5fb OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91413f261c11e7471063893a4821331a1bd4496f5fb88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "CJHMmfxKEypZd9oF5Ui9cSgWD7eaUC6cGT" + ] + } + }, + { + "value": 1000000, + "n": 1, + "scriptPubKey": { + "nameOp": { + "op": "name_update", + "name": "p/domob", + "name_encoding": "utf8", + "value": "{\"g\":{\"mv\":{\"d\":\"u\",\"n\":10}}}", + "value_encoding": "ascii" + }, + "asm": "OP_NAME_UPDATE 702f646f6d6f62 7b2267223a7b226d76223a7b2264223a2275222c226e223a31307d7d7d OP_2DROP OP_DROP OP_DUP OP_HASH160 9375d04e6c8a332e0dd06dff3e9c037ac80d31a0 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "5207702f646f6d6f621d7b2267223a7b226d76223a7b2264223a2275222c226e223a31307d7d7d6d7576a9149375d04e6c8a332e0dd06dff3e9c037ac80d31a088ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "CVub35ZeaqJajwUxr7ib3sYBfQg19AhKRs" + ] + } + } + ], + "hex": "02000000029e98ba7efffb4ccb8ffe7ea370838953589cae0792ca50b5495b615539a6d859000000006a47304402202f16982264f61a1bdd08cf5f5aa620fd761419416aceaf65226ba74a932e8ea50220520d2a8755da0f85c257afeb841fab9692807d177fd4693e0697308f658940ed012102d9ce309aa25d552cc1e6e2557e4b91b8ad9d055ff74fc4241e6b5b1039792eaefefffffffd26a2d6fa535eb61273f2400b12f988783e0660565f95b92c5fb763a4382fa3010000006a473044022030710158479236b1e8da22cbe5710f0b1b1210fdfa3c68dcb955af8137340db8022064f8f2d2c4047f51f0e62ebe2ee2aac7d3eb574f57f497ad828fb2381234d81e012103611ff32dd36a49b75873dc3770c1e5f6a83ea8a4f56fa1fd08400b7686eb4c21feffffff0268a5351c000000001976a91413f261c11e7471063893a4821331a1bd4496f5fb88ac40420f0000000000425207702f646f6d6f621d7b2267223a7b226d76223a7b2264223a2275222c226e223a31307d7d7d6d7576a9149375d04e6c8a332e0dd06dff3e9c037ac80d31a088ac24bc0300", + "blockhash": "6d8071aa2e91e13004d9cc185e3a51a1975f33f190b171ce3d638ae17fdb1154", + "confirmations": 787951, + "time": 1539182355, + "blocktime": 1539182355 +}