diff --git a/.travis.yml b/.travis.yml index 9439f01..2b22bc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,11 +31,13 @@ install: - pip install blake256 - pip install scrypt - pip install x11_hash + - pip install git+https://github.com/bitcoinplusorg/x13-hash - pip install xevan_hash - pip install quark_hash - pip install groestlcoin_hash - pip install git+https://github.com/goacoincore/neoscrypt - pip install git+https://github.com/motioncrypto/x16r_hash + - pip install pycryptodomex # command to run tests script: - pytest --cov=electrumx diff --git a/README.rst b/README.rst index 03bdd8a..8dc06d4 100644 --- a/README.rst +++ b/README.rst @@ -22,3 +22,73 @@ See `readthedocs `_. **Neil Booth** kyuupichan@gmail.com https://github.com/kyuupichan bitcoincash:qzxpdlt8ehu9ehftw6rqsy2jgfq4nsltxvhrdmdfpn + + +Supported Coins +============= + +- Argentum - ARG +- Bitbay - BAY +- Bitcoin Cash - BCH +- Bitcoin Gold - BTG +- Bitcoin Segwit - BTC +- Bitcoin SV - BSV +- BitcoinAtom - BCA +- BitcoinGreen - BITG +- BitcoinPlus - XBC +- BitcoinZ - BTCZ +- Bitcore - BTX +- Bitzeny - ZNY +- Blackcoin - BLK +- CanadaeCoin - CDN +- Chips - CHIPS +- CivX - CIVX +- ColossusXT - COLX +- Crown - CRW +- Dash - DASH +- Decred - DCR +- Denarius - D +- Digibyte - DGB +- Dogecoin - DOGE +- Einsteninium - EMC2 +- EmerCoin - EMC +- Faircoin - FAIR +- Feathercoin - FTC +- Fujicoin - FJC +- GameCredits - GAME +- GoByte - GBX +- Groestlcoin - GRS +- HODLcoin - HODL +- Hush - HUSH +- Komodo - KMD +- Koto - KOTO +- Litecoin - LTC +- Machinecoin - MAC +- Minexcoin - MNX +- Monacoin - MONA +- Monaize - MNZ +- Monoeci - XMCC +- Motion - XMN +- Myriadcoin - XMY +- NIX - NIX +- Namecoin - NMC +- Neblio - NEBL +- NewYorkcoin - NYC +- Noir - NOR +- Paccoin - PAC +- Peercoin - PPC +- Pivx - PIVX +- Polis - POLIS +- Reddcoin - RDD +- Sibcoin - SIB +- SmartCash - SMART +- SnowGem - XSG +- TokenPay - TPAY +- Trezarcoin - TZC +- Uniform Fiscal Object - UFO +- Vertcoin - VTC +- Viacoin - VIA +- Xuez - XUEZ +- Zcash - ZEC +- Zclassic - ZCL +- ZelCash - ZEL diff --git a/docs/changelog.rst b/docs/changelog.rst index ca0f9d8..23cc13e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,58 @@ and memory consumption whilst serving clients. Those problems should not occur with Python 3.7. +.. note:: Bitcoin ABC developers have hastily introduced controversial + changes that break ElectrumX's block processing by requiring it to + be non-sequential. Unlike others with unique requirements they + refused to make their code coin-specific. ElectrumX continues to + require blocks be naturally ordered, and is compatible with any + non-CToR daemon, such as Bitcoin SV, and Bitcoin Unlimited / + Bitcoin XT with CToR disabled. + +Version 1.8.12 (10 Nov 2018) +============================ + +* bug fix + +Version 1.8.11 (07 Nov 2018) +============================ + +* require aiorpcX 0.10.1 + +Version 1.8.10 (05 Nov 2018) +============================ + +* require aiorpcX 0.10.0 +* fix `#632`_ +* coin additions / updates: ZelCash (TheTrunk) + +Version 1.8.9 (02 Nov 2018) +=========================== + +* fix `#630`_ + +Version 1.8.8 (01 Nov 2018) +=========================== + +* require aiorpcX 0.9.0 +* coin additions / updates: decred (dajohi, bolapara), zcash (erasmospunk), + namecoin (JeremyRand),CivX (turcol), NewYorkCoin (erasmospunk) +* fix `#603`_, `#608`_ +* other minor fixes and changes: FMCorz + +Version 1.8.7 (13 Sep 2018) +=========================== + +* require aiorpcX 0.8.1 +* fix reorg bug loading blocks from disk (erasmospunk) + +Version 1.8.6 (12 Sep 2018) +=========================== + +* require aiorpcX 0.8.0 +* suppress socket.send() errors +* new coin TokenPay (samfiragabriel) +* minor fix: wakiyamap Version 1.8.7 (13 Sep 2018) =========================== @@ -170,111 +222,14 @@ Version 1.5 * minor tweaks: romanz, you21979, SuBPaR42, sangaman, wakiyamap, DaShak -Version 1.4.3 -============= - -* Fix `#442`_. - -Version 1.4.2 -============= - -* proxy remote IP reported properly if :envvar:`FORCE_PROXY` is set. - Fixes `#301`_. -* requires aiorpcx 0.5.5 - -Version 1.4.1 -============= - -* minor bugfixes - cleaner shutdown; group handling -* set PROTOCOL_MIN to 1.0; this will prevent 2.9.x clients from connecting - and encourage upgrades to more recent clients without the security hole -* requires aiorpcx 0.5.4 - -Version 1.4 -=========== - -* switch to `aiorpcX `_ for all - networking, ``JSON RPC`` and proxy handling -* proxy detection improvements -* `documentation `_ rewrite -* new environment variable :envvar:`LOG_FORMAT` to control logging format -* new environment variable :envvar:`DROP_CLIENT` to cut off unsupported - client software -* coin updates: Litecoin (pooler), bitbayd (kongeo), BTG (wilsonmeier), - danny91, wakiyamap, snowgem, Dash (theLazier), fujicoin -* new coins: Decred (cipherzzz), axe (-k), -* typo fixes (dax, romanz) - -.. note:: the Dash-specific undocumented ``masternode.subscribe()`` - RPC call was not following the JSON RPC spec; this was shown up by - the switch to aiorpcX. I had to modify the code but it may break - Dash clients. - - The Decred implementation doesn't work on mainnet; I will remove it - if this remains unfixed. - -Version 1.3 -=========== - -* Switch to :ref:`version 1.2` of the protocol. - :func:`mempool.get_fee_histogram` implementation contributed by ecdsa, - verbose mode of :func:`blockchain.transaction.get` by gdassori. -* :func:`blockchain.scripthash.listunspent` now takes into account mempool - spends and receipts. -* Improved client notification handling. -* Wait for mempool to fully sync before serving. -* Documentation moved to `readthedocs.io - `_. Rewritten and improved - protocol documentation. -* new/updated coins: Chips (cipig), Feathercoin (lclc), Zclassic(heyrhett), - Dash (thelazier), NYC (xarakas), Koto (wo01), BitcoinZ (cipig), BitCore - (cipig), Fujicoin (fujicoin), Bitcoin Atom (erasmospunk), Deanrius (carsenk), - SNG (blackjok3rtt). -* Minor fixes and improvements: duckartes, blin00, bauerj, - erasmospunk, SomberNight, romanz. - -Version 1.2.1 -============= - -- remove IRC support. Most coins had empty IRC channels. Those that - don't have peers populated. -- use estimatesmartfee RPC call if available (SomberNight) -- new/updated coins: Emercoin (Sergii Vakula), Bitcoin Gold (erasmospunk), - Monacoin testnet (Wakiyama P), sibcoin (53r63rn4r), Komodo and Monaize - (cipig), Hush (Duke Leto) -- doc updates (fr3aker) -- issues fixed: `#302`_ - -Version 1.2 -=========== - -.. note:: version 1.2 changes script hash indexing in the database, so - you will need to rebuild your databases from scratch. Running this - version will refuse to open the DB and not corrupt it, so you can - revert to 1.1.x if you wish. The initial synchronisation process - should be around 10-15% faster than 1.1, owing to this change and - Justin Arthur's optimisations from 1.1.1. - -- separate P2PKH from P2PK entries in the history and UTXO databases. - These were previously amalgamated by address as that is what - electrum-server used to do. However Electrum didn't handle P2PK - spends correctly and now the protocol admits subscriptions by script - hash there is no need to have these merged any more. - -For Bitcoin (BitcoinSegwit/mainnet) you can download a leveldb database -synced up to block 490153 using this bittorrent magnet -`link (~24GB) `_. - **Neil Booth** kyuupichan@gmail.com https://github.com/kyuupichan bitcoincash:qzxpdlt8ehu9ehftw6rqsy2jgfq4nsltxvhrdmdfpn .. _#258: https://github.com/kyuupichan/electrumx/issues/258 -.. _#301: https://github.com/kyuupichan/electrumx/issues/301 .. _#315: https://github.com/kyuupichan/electrumx/issues/315 .. _#414: https://github.com/kyuupichan/electrumx/issues/414 -.. _#442: https://github.com/kyuupichan/electrumx/issues/442 .. _#443: https://github.com/kyuupichan/electrumx/issues/443 .. _#455: https://github.com/kyuupichan/electrumx/issues/455 .. _#479: https://github.com/kyuupichan/electrumx/issues/479 @@ -295,3 +250,7 @@ bitcoincash:qzxpdlt8ehu9ehftw6rqsy2jgfq4nsltxvhrdmdfpn .. _#567: https://github.com/kyuupichan/electrumx/issues/567 .. _#570: https://github.com/kyuupichan/electrumx/issues/570 .. _#577: https://github.com/kyuupichan/electrumx/issues/577 +.. _#603: https://github.com/kyuupichan/electrumx/issues/603 +.. _#608: https://github.com/kyuupichan/electrumx/issues/608 +.. _#630: https://github.com/kyuupichan/electrumx/issues/630 +.. _#632: https://github.com/kyuupichan/electrumx/issues/630 diff --git a/docs/conf.py b/docs/conf.py index 91e5f39..fc82fd3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ import os import sys sys.path.insert(0, os.path.abspath('..')) -VERSION="ElectrumX 1.8.7" +VERSION="ElectrumX 1.8.12" # -- Project information ----------------------------------------------------- diff --git a/docs/environment.rst b/docs/environment.rst index 5c1de25..d95e578 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -418,6 +418,5 @@ your available physical RAM: I do not recommend raising this above 2000. -.. _lib/coins.py: - https://github.com/kyuupichan/electrumx/blob/master/lib/coins.py +.. _lib/coins.py: https://github.com/kyuupichan/electrumx/blob/master/electrumx/lib/coins.py .. _uvloop: https://pypi.python.org/pypi/uvloop diff --git a/electrumx/__init__.py b/electrumx/__init__.py index 02d2af8..73c239f 100644 --- a/electrumx/__init__.py +++ b/electrumx/__init__.py @@ -1,4 +1,4 @@ -version = 'ElectrumX 1.8.7' +version = 'ElectrumX 1.8.12' version_short = version.split()[-1] from electrumx.server.controller import Controller diff --git a/electrumx/lib/coins.py b/electrumx/lib/coins.py index 4064da3..96a8c08 100644 --- a/electrumx/lib/coins.py +++ b/electrumx/lib/coins.py @@ -40,12 +40,14 @@ import base64 import electrumx.lib.util as util from electrumx.lib.hash import Base58, hash160, double_sha256, hash_to_hex_str -from electrumx.lib.hash import HASHX_LEN +from electrumx.lib.hash import HASHX_LEN, hex_str_to_hash from electrumx.lib.script import ScriptPubKey, OpCodes import electrumx.lib.tx as lib_tx +import electrumx.lib.tx_dash as lib_tx_dash import electrumx.server.block_processor as block_proc import electrumx.server.daemon as daemon -from electrumx.server.session import ElectrumX, DashElectrumX +from electrumx.server.session import (ElectrumX, DashElectrumX, + SmartCashElectrumX) Block = namedtuple("Block", "raw header transactions") @@ -364,25 +366,34 @@ class HOdlcoin(Coin): TX_PER_BLOCK = 5 -class BitcoinCash(BitcoinMixin, Coin): - NAME = "BitcoinCash" - SHORTNAME = "BCH" - TX_COUNT = 246362688 - TX_COUNT_HEIGHT = 511484 +class BitcoinSV(BitcoinMixin, Coin): + NAME = "BitcoinSV" + SHORTNAME = "BSV" + TX_COUNT = 267318795 + TX_COUNT_HEIGHT = 557037 TX_PER_BLOCK = 400 PEERS = [ - 'electroncash.cascharia.com s50002', - 'bch.electrumx.cash s t', - 'bccarihace4jdcnt.onion t52001 s52002', - 'abc1.hsmiths.com t60001 s60002', - 'electroncash.checksum0.com s t', - 'electrumx-cash.1209k.com s t', - 'electrum.leblancnet.us t50011 s50012', - 'electroncash.dk s t', - 'electrum.imaginary.cash s t', + 'sv.electrumx.cash s t', + 'sv1.hsmiths.com t60003 s60004', + 'satoshi.vision.cash s', + 'electroncash.cascharia.com s t', ] +class BitcoinCash(BitcoinMixin, Coin): + NAME = "BitcoinCashABC" # Some releases later remove the ABC suffix + SHORTNAME = "BCH" + TX_COUNT = 265479628 + TX_COUNT_HEIGHT = 556592 + TX_PER_BLOCK = 400 + PEERS = [ + 'bch.imaginary.cash s t', + 'electroncash.dk s t', + 'wallet.satoshiscoffeehouse.com s t', + ] + BLOCK_PROCESSOR = block_proc.LTORBlockProcessor + + class BitcoinSegwit(BitcoinMixin, Coin): NAME = "BitcoinSegwit" DESERIALIZER = lib_tx.DeserializerSegWit @@ -395,7 +406,6 @@ class BitcoinSegwit(BitcoinMixin, Coin): 'E-X.not.fyi s t', 'elec.luggs.co s443', 'electrum.vom-stausee.de s t', - 'electrum3.hachre.de s t', 'electrum.hsmiths.com s t', 'helicarrier.bauerj.eu s t', 'hsmiths4fyqlw5xw.onion s t', @@ -538,18 +548,15 @@ class BitcoinTestnetMixin(object): PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} -class BitcoinCashTestnet(BitcoinTestnetMixin, Coin): - '''Bitcoin Testnet for Bitcoin Cash daemons.''' - NAME = "BitcoinCash" +class BitcoinSVTestnet(BitcoinTestnetMixin, Coin): + '''Bitcoin Testnet for Bitcoin SV daemons.''' + NAME = "BitcoinSV" PEERS = [ - 'electrum-testnet-abc.criptolayer.net s50112', - 'bchtestnet.arihanc.com t53001 s53002', - 'ciiattqkgzebpp6jofjbrkhvhwmgnsfoayljdcrve2p3qmkbv3duaoyd.onion ' - 't53001 s53002', + 'electrontest.cascharia.com t51001 s51002', ] -class BitcoinCashRegtest(BitcoinCashTestnet): +class BitcoinSVRegtest(BitcoinSVTestnet): NET = "regtest" GENESIS_HASH = ('0f9188f13cb7b2c71f2a335e3a4fc328' 'bf5beb436012afca590b1a11466e2206') @@ -647,6 +654,26 @@ class LitecoinTestnet(Litecoin): ] +class LitecoinRegtest(LitecoinTestnet): + NET = "regtest" + GENESIS_HASH = ('530827f38f93b43ed12af0b3ad25a288' + 'dc02ed74d6d7857862df51fc56c416f9') + PEERS = [] + TX_COUNT = 1 + TX_COUNT_HEIGHT = 1 + + +class BitcoinCashRegtest(BitcoinTestnetMixin, Coin): + NAME = "BitcoinCashABC" # Some releases later remove the ABC suffix + NET = "regtest" + PEERS = [] + GENESIS_HASH = ('0f9188f13cb7b2c71f2a335e3a4fc328' + 'bf5beb436012afca590b1a11466e2206') + TX_COUNT = 1 + TX_COUNT_HEIGHT = 1 + BLOCK_PROCESSOR = block_proc.LTORBlockProcessor + + class Viacoin(AuxPowMixin, Coin): NAME = "Viacoin" SHORTNAME = "VIA" @@ -709,6 +736,109 @@ class Namecoin(AuxPowMixin, Coin): PEERS = [ 'elec.luggs.co s446', ] + BLOCK_PROCESSOR = block_proc.NamecoinBlockProcessor + + @classmethod + def split_name_script(cls, script): + from electrumx.lib.script import _match_ops, Script, ScriptError + + try: + ops = Script.get_ops(script) + except ScriptError: + return None, 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, + OpCodes.OP_2DROP, OpCodes.OP_2DROP] + NAME_UPDATE_OPS = [OP_NAME_UPDATE, -1, -1, OpCodes.OP_2DROP, + OpCodes.OP_DROP] + + name_script_op_count = None + name_pushdata = None + + # Detect name operations; determine count of opcodes. + # Also extract the name field -- we might use that for something in a + # future version. + if match(ops[:len(NAME_NEW_OPS)], NAME_NEW_OPS): + name_script_op_count = len(NAME_NEW_OPS) + elif match(ops[:len(NAME_FIRSTUPDATE_OPS)], NAME_FIRSTUPDATE_OPS): + name_script_op_count = len(NAME_FIRSTUPDATE_OPS) + name_pushdata = ops[1] + elif match(ops[:len(NAME_UPDATE_OPS)], NAME_UPDATE_OPS): + name_script_op_count = len(NAME_UPDATE_OPS) + name_pushdata = ops[1] + + if name_script_op_count is None: + return None, script + + # Find the end position of the name data + n = 0 + for i in range(name_script_op_count): + # Content of this loop is copied from Script.get_ops's loop + op = script[n] + n += 1 + + if op <= OpCodes.OP_PUSHDATA4: + # Raw bytes follow + if op < OpCodes.OP_PUSHDATA1: + dlen = op + elif op == OpCodes.OP_PUSHDATA1: + dlen = script[n] + n += 1 + elif op == OpCodes.OP_PUSHDATA2: + dlen, = struct.unpack(' len(script): + raise IndexError + op = (op, script[n:n + dlen]) + n += dlen + # Strip the name data to yield the address script + address_script = script[n:] + + 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) + + 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) class NamecoinTestnet(Namecoin): @@ -802,6 +932,7 @@ class Dash(Coin): ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon + DESERIALIZER = lib_tx_dash.DeserializerDash @classmethod def header_hash(cls, header): @@ -1010,6 +1141,23 @@ class Hush(EquihashMixin, Coin): REORG_LIMIT = 800 +class ZelCash(EquihashMixin, Coin): + NAME = "ZelCash" + SHORTNAME = "ZEL" + NET = "mainnet" + P2PKH_VERBYTE = bytes.fromhex("1CB8") + P2SH_VERBYTES = [bytes.fromhex("1CBD")] + WIF_BYTE = bytes.fromhex("80") + GENESIS_HASH = ('00052461a5006c2e3b74ce48992a0869' + '5607912d5604c3eb8da25749b0900444') + DESERIALIZER = lib_tx.DeserializerZcash + TX_COUNT = 450539 + TX_COUNT_HEIGHT = 167114 + TX_PER_BLOCK = 3 + RPC_PORT = 16124 + REORG_LIMIT = 800 + + class Zclassic(EquihashMixin, Coin): NAME = "Zclassic" SHORTNAME = "ZCL" @@ -1158,6 +1306,50 @@ class Peercoin(Coin): REORG_LIMIT = 5000 +class Trezarcoin(Coin): + NAME = "Trezarcoin" + SHORTNAME = "TZC" + NET = "mainnet" + VALUE_PER_COIN = 1000000 + XPUB_VERBYTES = bytes.fromhex("0488B21E") + XPRV_VERBYTES = bytes.fromhex("0488ADE4") + P2PKH_VERBYTE = bytes.fromhex("42") + P2SH_VERBYTES = [bytes.fromhex("08")] + WIF_BYTE = bytes.fromhex("c2") + GENESIS_HASH = ('24502ba55d673d2ee9170d83dae2d1ad' + 'b3bfb4718e4f200db9951382cc4f6ee6') + DESERIALIZER = lib_tx.DeserializerTrezarcoin + HEADER_HASH = lib_tx.DeserializerTrezarcoin.blake2s + HEADER_HASH_GEN = lib_tx.DeserializerTrezarcoin.blake2s_gen + BASIC_HEADER_SIZE = 80 + TX_COUNT = 742886 + TX_COUNT_HEIGHT = 643128 + TX_PER_BLOCK = 2 + RPC_PORT = 17299 + REORG_LIMIT = 2000 + PEERS = [ + 'electrumx1.trezarcoin.com s t', + ] + + @classmethod + def genesis_block(cls, block): + '''Check the Genesis block is the right one for this coin. + + Return the block less its unspendable coinbase. + ''' + header = cls.block_header(block, 0) + header_hex_hash = cls.HEADER_HASH_GEN(header) + if header_hex_hash != cls.GENESIS_HASH: + raise CoinError('genesis block has hash {} expected {}' + .format(header_hex_hash, cls.GENESIS_HASH)) + return header + bytes(1) + + @classmethod + def header_hash(cls, header): + '''Given a header return the hash.''' + return cls.HEADER_HASH(header) + + class Reddcoin(Coin): NAME = "Reddcoin" SHORTNAME = "RDD" @@ -1524,7 +1716,6 @@ class Newyorkcoin(AuxPowMixin, Coin): WIF_BYTE = bytes.fromhex("bc") GENESIS_HASH = ('5597f25c062a3038c7fd815fe46c67de' 'dfcb3c839fbc8e01ed4044540d08fe48') - DAEMON = daemon.LegacyRPCDaemon TX_COUNT = 5161944 TX_COUNT_HEIGHT = 3948743 TX_PER_BLOCK = 2 @@ -1539,7 +1730,6 @@ class NewyorkcoinTestnet(Newyorkcoin): WIF_BYTE = bytes.fromhex("f1") GENESIS_HASH = ('24463e4d3c625b0a9059f309044c2cf0' 'd7e196cf2a6ecce901f24f681be33c8f') - DAEMON = daemon.LegacyRPCDaemon TX_COUNT = 5161944 TX_COUNT_HEIGHT = 3948743 TX_PER_BLOCK = 2 @@ -1722,7 +1912,9 @@ class Axe(Dash): WIF_BYTE = bytes.fromhex("cc") GENESIS_HASH = ('00000c33631ca6f2f61368991ce2dc03' '306b5bb50bf7cede5cfbba6db38e52e6') + SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon + DESERIALIZER = lib_tx_dash.DeserializerDash TX_COUNT = 18405 TX_COUNT_HEIGHT = 30237 TX_PER_BLOCK = 1 @@ -1965,6 +2157,7 @@ class Minexcoin(EquihashMixin, Coin): RPC_PORT = 8022 CHUNK_SIZE = 960 PEERS = [ + 'electrumx.xpresit.net s t', 'elex01-ams.turinex.eu s t', 'eu.minexpool.nl s t' ] @@ -2174,3 +2367,189 @@ class FloTestnet(Flo): PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ ] + +class CivX(Coin): + NAME = "CivX" + SHORTNAME = "CIVX" + NET = "mainnet" + XPUB_VERBYTES = bytes.fromhex("0488b21e") + XPRV_VERBYTES = bytes.fromhex("0488ade4") + GENESIS_HASH = ('00000036090a68c523471da7a4f0f958' + 'c1b4403fef74a003be7f71877699cab7') + P2PKH_VERBYTE = bytes.fromhex("1C") + P2SH_VERBYTE = [bytes.fromhex("57")] + WIF_BYTE = bytes.fromhex("9C") + RPC_PORT = 4561 + TX_COUNT = 1000 + TX_COUNT_HEIGHT = 10000 + TX_PER_BLOCK = 4 + DAEMON = daemon.PreLegacyRPCDaemon + DESERIALIZER = lib_tx.DeserializerTxTime + + @classmethod + def header_hash(cls, header): + version, = util.unpack_le_uint32_from(header) + + if version > 2: + return double_sha256(header) + else: + return hex_str_to_hash(CivX.GENESIS_HASH) + + +class CivXTestnet(CivX): + SHORTNAME = "tCIVX" + NET = "testnet" + XPUB_VERBYTES = bytes.fromhex("043587cf") + XPRV_VERBYTES = bytes.fromhex("04358394") + GENESIS_HASH = ('0000059bb2c2048493efcb0f1a034972' + 'b3ce4089d54c93b69aaab212fb369887') + P2PKH_VERBYTE = bytes.fromhex("4B") + P2SH_VERBYTE = [bytes.fromhex("CE")] + WIF_BYTE = bytes.fromhex("CB") + RPC_PORT = 14561 + + @classmethod + def header_hash(cls, header): + version, = util.unpack_le_uint32_from(header) + + if version > 2: + return double_sha256(header) + else: + return hex_str_to_hash(CivXTestnet.GENESIS_HASH) + + +class SmartCash(Coin): + NAME = "SmartCash" + SHORTNAME = "SMART" + NET = "mainnet" + P2PKH_VERBYTE = bytes.fromhex("3f") + P2SH_VERBYTES = [bytes.fromhex("12")] + WIF_BYTE = bytes.fromhex("bf") + GENESIS_HASH = ('000007acc6970b812948d14ea5a0a13d' + 'b0fdd07d5047c7e69101fa8b361e05a4') + DESERIALIZER = lib_tx.DeserializerSmartCash + RPC_PORT = 9679 + REORG_LIMIT = 5000 + TX_COUNT = 1115016 + TX_COUNT_HEIGHT = 541656 + TX_PER_BLOCK = 1 + ENCODE_CHECK = partial(Base58.encode_check, + hash_fn=lib_tx.DeserializerSmartCash.keccak) + DECODE_CHECK = partial(Base58.decode_check, + hash_fn=lib_tx.DeserializerSmartCash.keccak) + HEADER_HASH = lib_tx.DeserializerSmartCash.keccak + DAEMON = daemon.SmartCashDaemon + SESSIONCLS = SmartCashElectrumX + + @classmethod + def header_hash(cls, header): + '''Given a header return the hash.''' + return cls.HEADER_HASH(header) + + +class NIX(Coin): + NAME = "NIX" + SHORTNAME = "NIX" + NET = "mainnet" + XPUB_VERBYTES = bytes.fromhex("0488b21e") + XPRV_VERBYTES = bytes.fromhex("0488ade4") + P2PKH_VERBYTE = bytes.fromhex("26") + P2SH_VERBYTES = [bytes.fromhex("35")] + WIF_BYTE = bytes.fromhex("80") + GENESIS_HASH = ('dd28ad86def767c3cfc34267a950d871' + 'fc7462bc57ea4a929fc3596d9b598e41') + DESERIALIZER = lib_tx.DeserializerSegWit + TX_COUNT = 114240 + TX_COUNT_HEIGHT = 87846 + TX_PER_BLOCK = 3 + RPC_PORT = 6215 + REORG_LIMIT = 1000 + + +class NIXTestnet(NIX): + SHORTNAME = "tNIX" + NET = "testnet" + XPUB_VERBYTES = bytes.fromhex("0488b21e") + XPRV_VERBYTES = bytes.fromhex("0488ade4") + GENESIS_HASH = ('dd28ad86def767c3cfc34267a950d871' + 'fc7462bc57ea4a929fc3596d9b598e41') + P2PKH_VERBYTE = bytes.fromhex("01") + P2SH_VERBYTE = [bytes.fromhex("03")] + WIF_BYTE = bytes.fromhex("80") + RPC_PORT = 16215 + DESERIALIZER = lib_tx.DeserializerSegWit + + +class Noir(Coin): + NAME = "Noir" + SHORTNAME = "NOR" + NET = "mainnet" + XPUB_VERBYTES = bytes.fromhex("0488b21e") + XPRV_VERBYTES = bytes.fromhex("0488ade4") + P2PKH_VERBYTE = bytes.fromhex("80") + P2SH_VERBYTES = [bytes.fromhex("07")] + WIF_BYTE = bytes.fromhex("D0") + GENESIS_HASH = ('23911212a525e3d149fcad6c559c8b17' + 'f1e8326a272a75ff9bb315c8d96433ef') + RPC_PORT = 8825 + TX_COUNT = 586369 + TX_COUNT_HEIGHT = 379290 + TX_PER_BLOCK = 5 + + +class BitcoinPlus(Coin): + NAME = "BitcoinPlus" + SHORTNAME = "XBC" + NET = "mainnet" + XPUB_VERBYTES = bytes.fromhex("0488B21E") + XPRV_VERBYTES = bytes.fromhex("0488ADE4") + P2PKH_VERBYTE = bytes.fromhex("19") + P2SH_VERBYTES = [bytes.fromhex("55")] + WIF_BYTE = bytes.fromhex("99") + GENESIS_HASH = ('0000005f6a28e686f641c616e56182d1' + 'b43afbe08a223f23bda23cdf9d55b882') + DESERIALIZER = lib_tx.DeserializerTxTime + DAEMON = daemon.LegacyRPCDaemon + TX_COUNT = 1479247 + TX_COUNT_HEIGHT = 749740 + TX_PER_BLOCK = 2 + RPC_PORT = 8885 + REORG_LIMIT = 2000 + + @classmethod + def header_hash(cls, header): + '''Given a header return the hash.''' + import x13_hash + return x13_hash.getPoWHash(header) + + +class Myriadcoin(AuxPowMixin, Coin): + NAME = "Myriadcoin" + SHORTNAME = "XMY" + NET = "mainnet" + XPUB_VERBYTES = bytes.fromhex("0488b21e") + XPRV_VERBYTES = bytes.fromhex("0488ade4") + P2PKH_VERBYTE = bytes.fromhex("32") + P2SH_VERBYTES = [bytes.fromhex("09")] + WIF_BYTE = bytes.fromhex("b2") + GENESIS_HASH = ('00000ffde4c020b5938441a0ea3d314b' + 'f619eff0b38f32f78f7583cffa1ea485') + DESERIALIZER = lib_tx.DeserializerAuxPowSegWit + TX_COUNT = 1976629 + TX_COUNT_HEIGHT = 2580356 + TX_PER_BLOCK = 20 + REORG_LIMIT = 2000 + RPC_PORT = 10889 + + +class MyriadcoinTestnet(Myriadcoin): + NAME = "Myriadcoin" + SHORTNAME = "XMT" + NET = "testnet" + XPUB_VERBYTES = bytes.fromhex("043587cf") + XPRV_VERBYTES = bytes.fromhex("04358394") + P2PKH_VERBYTE = bytes.fromhex("58") + P2SH_VERBYTES = [bytes.fromhex("bc")] + WIF_BYTE = bytes.fromhex("ef") + GENESIS_HASH = ('0000017ce2a79c8bddafbbe47c004aa9' + '2b20678c354b34085f62b762084b9788') diff --git a/electrumx/lib/peer.py b/electrumx/lib/peer.py index e35481e..4427e30 100644 --- a/electrumx/lib/peer.py +++ b/electrumx/lib/peer.py @@ -25,7 +25,8 @@ '''Representation of a peer server.''' -from ipaddress import ip_address +from ipaddress import ip_address, IPv4Address, IPv6Address +from socket import AF_INET, AF_INET6 from electrumx.lib.util import cachedproperty import electrumx.lib.util as util @@ -112,15 +113,24 @@ class Peer(object): for feature in self.FEATURES: setattr(self, feature, getattr(peer, feature)) - def connection_port_pairs(self): - '''Return a list of (kind, port) pairs to try when making a - connection.''' + def connection_tuples(self): + '''Return a list of (kind, port, family) tuples to try when making a + connection. + ''' # Use a list not a set - it's important to try the registered # ports first. pairs = [('SSL', self.ssl_port), ('TCP', self.tcp_port)] while self.other_port_pairs: pairs.append(self.other_port_pairs.pop()) - return [pair for pair in pairs if pair[1]] + if isinstance(self.ip_address, IPv4Address): + families = [AF_INET] + elif isinstance(self.ip_address, IPv6Address): + families = [AF_INET6] + else: + families = [AF_INET, AF_INET6] + return [(kind, port, family) + for kind, port in pairs if port + for family in families] def mark_bad(self): '''Mark as bad to avoid reconnects but also to remember for a diff --git a/electrumx/lib/tx.py b/electrumx/lib/tx.py index bb516fd..b34e17a 100644 --- a/electrumx/lib/tx.py +++ b/electrumx/lib/tx.py @@ -28,6 +28,7 @@ '''Transaction-related classes and functions.''' from collections import namedtuple +from hashlib import blake2s from electrumx.lib.hash import sha256, double_sha256, hash_to_hex_str from electrumx.lib.script import OpCodes @@ -320,26 +321,47 @@ class TxJoinSplit(namedtuple("Tx", "version inputs outputs locktime")): class DeserializerZcash(DeserializerEquihash): def read_tx(self): header = self._read_le_uint32() - overwinterd = ((header >> 31) == 1) - if overwinterd: + overwintered = ((header >> 31) == 1) + if overwintered: version = header & 0x7fffffff - self._read_le_uint32() # versionGroupId + self.cursor += 4 # versionGroupId else: version = header + + is_overwinter_v3 = version == 3 + is_sapling_v4 = version == 4 + base_tx = TxJoinSplit( version, self._read_inputs(), # inputs self._read_outputs(), # outputs self._read_le_uint32() # locktime ) - if base_tx.version >= 3: - self._read_le_uint32() # expiryHeight + + if is_overwinter_v3 or is_sapling_v4: + self.cursor += 4 # expiryHeight + + has_shielded = False + if is_sapling_v4: + self.cursor += 8 # valueBalance + shielded_spend_size = self._read_varint() + self.cursor += shielded_spend_size * 384 # vShieldedSpend + shielded_output_size = self._read_varint() + self.cursor += shielded_output_size * 948 # vShieldedOutput + has_shielded = shielded_spend_size > 0 or shielded_output_size > 0 + if base_tx.version >= 2: joinsplit_size = self._read_varint() if joinsplit_size > 0: - self.cursor += joinsplit_size * 1802 # JSDescription + joinsplit_desc_len = 1506 + (192 if is_sapling_v4 else 296) + # JSDescription + self.cursor += joinsplit_size * joinsplit_desc_len self.cursor += 32 # joinSplitPubKey self.cursor += 64 # joinSplitSig + + if is_sapling_v4 and has_shielded: + self.cursor += 64 # bindingSig + return base_tx @@ -358,6 +380,62 @@ class DeserializerTxTime(Deserializer): ) +class TxTrezarcoin( + namedtuple("Tx", "version time inputs outputs locktime txcomment")): + '''Class representing transaction that has a time and txcomment field.''' + + +class DeserializerTrezarcoin(Deserializer): + + def read_tx(self): + version = self._read_le_int32() + time = self._read_le_uint32() + inputs = self._read_inputs() + outputs = self._read_outputs() + locktime = self._read_le_uint32() + if version >= 2: + txcomment = self._read_varbytes() + else: + txcomment = b'' + return TxTrezarcoin(version, time, inputs, outputs, locktime, + txcomment) + + @staticmethod + def blake2s_gen(data): + version = data[0:1] + keyOne = data[36:46] + keyTwo = data[58:68] + ntime = data[68:72] + _nBits = data[72:76] + _nonce = data[76:80] + _full_merkle = data[36:68] + _input112 = data + _full_merkle + _key = keyTwo + ntime + _nBits + _nonce + keyOne + '''Prepare 112Byte Header ''' + blake2s_hash = blake2s(key=_key, digest_size=32) + blake2s_hash.update(_input112) + '''TrezarFlips - Only for Genesis''' + return ''.join(map(str.__add__, blake2s_hash.hexdigest()[-2::-2], + blake2s_hash.hexdigest()[-1::-2])) + + @staticmethod + def blake2s(data): + version = data[0:1] + keyOne = data[36:46] + keyTwo = data[58:68] + ntime = data[68:72] + _nBits = data[72:76] + _nonce = data[76:80] + _full_merkle = data[36:68] + _input112 = data + _full_merkle + _key = keyTwo + ntime + _nBits + _nonce + keyOne + '''Prepare 112Byte Header ''' + blake2s_hash = blake2s(key=_key, digest_size=32) + blake2s_hash.update(_input112) + '''TrezarFlips''' + return blake2s_hash.digest() + + class DeserializerReddcoin(Deserializer): def read_tx(self): version = self._read_le_int32() @@ -500,6 +578,10 @@ class TxInputDcr(namedtuple("TxInput", "prev_hash prev_idx tree sequence")): return ("Input({}, {:d}, tree={}, sequence={:d})" .format(prev_hash, self.prev_idx, self.tree, self.sequence)) + def is_generation(self): + '''Test if an input is generation/coinbase like''' + return self.prev_idx == MINUS_1 and self.prev_hash == ZERO + class TxOutputDcr(namedtuple("TxOutput", "value version pk_script")): '''Class representing a Decred transaction output.''' @@ -599,6 +681,7 @@ class DeserializerDecred(Deserializer): witness ), tx_hash, self.cursor - start + class TxFlo(namedtuple("Tx", "version inputs outputs locktime txcomment")): '''Class representing a transaction.''' @@ -671,3 +754,18 @@ class DeserializerFlo(DeserializerSegWit): return TxFloSegWit(version, marker, flag, inputs, outputs, witness, locktime, tx_comment), double_sha256(orig_ser), vsize + + +class DeserializerSmartCash(Deserializer): + + @staticmethod + def keccak(data): + from Cryptodome.Hash import keccak + keccak_hash = keccak.new(digest_bits=256) + keccak_hash.update(data) + return keccak_hash.digest() + + def read_tx_and_hash(self): + from electrumx.lib.hash import sha256 + start = self.cursor + return self.read_tx(), sha256(self.binary[start:self.cursor]) diff --git a/electrumx/lib/tx_dash.py b/electrumx/lib/tx_dash.py new file mode 100644 index 0000000..31dee65 --- /dev/null +++ b/electrumx/lib/tx_dash.py @@ -0,0 +1,405 @@ +# Copyright (c) 2016-2018, Neil Booth +# Copyright (c) 2018, the ElectrumX authors +# +# All rights reserved. +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +'''Deserializer for Dash DIP2 special transaction types''' + +from collections import namedtuple + +from electrumx.lib.tx import Deserializer +from electrumx.lib.util import (pack_le_uint16, pack_le_int32, pack_le_uint32, + pack_le_int64, pack_varint, pack_varbytes) + + +# https://github.com/dashpay/dips/blob/master/dip-0002.md +class DashTx(namedtuple("DashTx", + "version inputs outputs locktime " + "tx_type extra_payload")): + '''Class representing a Dash transaction''' + def serialize(self): + nLocktime = pack_le_uint32(self.locktime) + txins = (pack_varint(len(self.inputs)) + + b''.join(tx_in.serialize() for tx_in in self.inputs)) + txouts = (pack_varint(len(self.outputs)) + + b''.join(tx_out.serialize() for tx_out in self.outputs)) + + if self.tx_type: + uVersion = pack_le_uint16(self.version) + uTxType = pack_le_uint16(self.tx_type) + vExtra = self._serialize_extra_payload() + return uVersion + uTxType + txins + txouts + nLocktime + vExtra + else: + nVersion = pack_le_int32(self.version) + return nVersion + txins + txouts + nLocktime + + def _serialize_extra_payload(self): + extra = self.extra_payload + spec_tx_class = DeserializerDash.SPEC_TX_HANDLERS.get(self.tx_type) + if not spec_tx_class: + assert isinstance(extra, (bytes, bytearray)) + return pack_varbytes(extra) + + if not isinstance(extra, spec_tx_class): + raise ValueError('Dash tx_type does not conform with extra' + ' payload class: %s, %s' % (self.tx_type, extra)) + return pack_varbytes(extra.serialize()) + + +# https://github.com/dashpay/dips/blob/master/dip-0002-special-transactions.md +class DashProRegTx(namedtuple("DashProRegTx", + "version type mode collateralOutpoint " + "ipAddress port KeyIdOwner PubKeyOperator " + "KeyIdVoting operatorReward scriptPayout " + "inputsHash payloadSig")): + '''Class representing DIP3 ProRegTx''' + def serialize(self): + assert (len(self.ipAddress) == 16 + and len(self.KeyIdOwner) == 20 + and len(self.PubKeyOperator) == 48 + and len(self.KeyIdVoting) == 20 + and len(self.inputsHash) == 32) + return ( + pack_le_uint16(self.version) + # version + pack_le_uint16(self.type) + # type + pack_le_uint16(self.mode) + # mode + self.collateralOutpoint.serialize() + # collateralOutpoint + self.ipAddress + # ipAddress + pack_le_uint16(self.port) + # port + self.KeyIdOwner + # KeyIdOwner + self.PubKeyOperator + # PubKeyOperator + self.KeyIdVoting + # KeyIdVoting + pack_le_uint16(self.operatorReward) + # operatorReward + pack_varbytes(self.scriptPayout) + # scriptPayout + self.inputsHash + # inputsHash + pack_varbytes(self.payloadSig) # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashProRegTx( + deser._read_le_uint16(), # version + deser._read_le_uint16(), # type + deser._read_le_uint16(), # mode + deser._read_outpoint(), # collateralOutpoint + deser._read_nbytes(16), # ipAddress + deser._read_le_uint16(), # port + deser._read_nbytes(20), # KeyIdOwner + deser._read_nbytes(48), # PubKeyOperator + deser._read_nbytes(20), # KeyIdVoting + deser._read_le_uint16(), # operatorReward + deser._read_varbytes(), # scriptPayout + deser._read_nbytes(32), # inputsHash + deser._read_varbytes() # payloadSig + ) + + +class DashProUpServTx(namedtuple("DashProUpServTx", + "version proTxHash ipAddress port " + "scriptOperatorPayout inputsHash " + "payloadSig")): + '''Class representing DIP3 ProUpServTx''' + def serialize(self): + assert (len(self.proTxHash) == 32 + and len(self.ipAddress) == 16 + and len(self.inputsHash) == 32 + and len(self.payloadSig) == 96) + return ( + pack_le_uint16(self.version) + # version + self.proTxHash + # proTxHash + self.ipAddress + # ipAddress + pack_le_uint16(self.port) + # port + pack_varbytes(self.scriptOperatorPayout) + # scriptOperatorPayout + self.inputsHash + # inputsHash + self.payloadSig # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashProUpServTx( + deser._read_le_uint16(), # version + deser._read_nbytes(32), # proTxHash + deser._read_nbytes(16), # ipAddress + deser._read_le_uint16(), # port + deser._read_varbytes(), # scriptOperatorPayout + deser._read_nbytes(32), # inputsHash + deser._read_nbytes(96) # payloadSig + ) + + +class DashProUpRegTx(namedtuple("DashProUpRegTx", + "version proTxHash mode PubKeyOperator " + "KeyIdVoting scriptPayout inputsHash " + "payloadSig")): + '''Class representing DIP3 ProUpRegTx''' + def serialize(self): + assert (len(self.proTxHash) == 32 + and len(self.PubKeyOperator) == 48 + and len(self.KeyIdVoting) == 20 + and len(self.inputsHash) == 32) + return ( + pack_le_uint16(self.version) + # version + self.proTxHash + # proTxHash + pack_le_uint16(self.mode) + # mode + self.PubKeyOperator + # PubKeyOperator + self.KeyIdVoting + # KeyIdVoting + pack_varbytes(self.scriptPayout) + # scriptPayout + self.inputsHash + # inputsHash + pack_varbytes(self.payloadSig) # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashProUpRegTx( + deser._read_le_uint16(), # version + deser._read_nbytes(32), # proTxHash + deser._read_le_uint16(), # mode + deser._read_nbytes(48), # PubKeyOperator + deser._read_nbytes(20), # KeyIdVoting + deser._read_varbytes(), # scriptPayout + deser._read_nbytes(32), # inputsHash + deser._read_varbytes() # payloadSig + ) + + +class DashProUpRevTx(namedtuple("DashProUpRevTx", + "version proTxHash reason " + "inputsHash payloadSig")): + '''Class representing DIP3 ProUpRevTx''' + def serialize(self): + assert (len(self.proTxHash) == 32 + and len(self.inputsHash) == 32 + and len(self.payloadSig) == 96) + return ( + pack_le_uint16(self.version) + # version + self.proTxHash + # proTxHash + pack_le_uint16(self.reason) + # reason + self.inputsHash + # inputsHash + self.payloadSig # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashProUpRevTx( + deser._read_le_uint16(), # version + deser._read_nbytes(32), # proTxHash + deser._read_le_uint16(), # reason + deser._read_nbytes(32), # inputsHash + deser._read_nbytes(96) # payloadSig + ) + + +class DashCbTx(namedtuple("DashCbTx", "version height merkleRootMNList")): + '''Class representing DIP4 coinbase special tx''' + def serialize(self): + assert len(self.merkleRootMNList) == 32 + return ( + pack_le_uint16(self.version) + # version + pack_le_uint32(self.height) + # height + self.merkleRootMNList # merkleRootMNList + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashCbTx( + deser._read_le_uint16(), # version + deser._read_le_uint32(), # height + deser._read_nbytes(32) # merkleRootMNList + ) + + +class DashSubTxRegister(namedtuple("DashSubTxRegister", + "version userName pubKey payloadSig")): + '''Class representing DIP5 SubTxRegister''' + def serialize(self): + assert (len(self.pubKey) == 48 + and len(self.payloadSig) == 96) + return ( + pack_le_uint16(self.version) + # version + pack_varbytes(self.userName) + # userName + self.pubKey + # pubKey + self.payloadSig # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashSubTxRegister( + deser._read_le_uint16(), # version + deser._read_varbytes(), # userName + deser._read_nbytes(48), # pubKey + deser._read_nbytes(96) # payloadSig + ) + + +class DashSubTxTopup(namedtuple("DashSubTxTopup", + "version regTxHash")): + '''Class representing DIP5 SubTxTopup''' + def serialize(self): + assert len(self.regTxHash) == 32 + return ( + pack_le_uint16(self.version) + # version + self.regTxHash # regTxHash + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashSubTxTopup( + deser._read_le_uint16(), # version + deser._read_nbytes(32) # regTxHash + ) + + +class DashSubTxResetKey(namedtuple("DashSubTxResetKey", + "version regTxHash hashPrevSubTx " + "creditFee newPubKey payloadSig")): + '''Class representing DIP5 SubTxResetKey''' + def serialize(self): + assert (len(self.regTxHash) == 32 + and len(self.hashPrevSubTx) == 32 + and len(self.newPubKey) == 48 + and len(self.payloadSig) == 96) + return ( + pack_le_uint16(self.version) + # version + self.regTxHash + # regTxHash + self.hashPrevSubTx + # hashPrevSubTx + pack_le_int64(self.creditFee) + # creditFee + self.newPubKey + # newPubKey + self.payloadSig # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashSubTxResetKey( + deser._read_le_uint16(), # version + deser._read_nbytes(32), # regTxHash + deser._read_nbytes(32), # hashPrevSubTx + deser._read_le_int64(), # creditFee + deser._read_nbytes(48), # newPubKey + deser._read_nbytes(96) # payloadSig + ) + + +class DashSubTxCloseAccount(namedtuple("DashSubTxCloseAccount", + "version regTxHash hashPrevSubTx " + "creditFee payloadSig")): + '''Class representing DIP5 SubTxCloseAccount''' + def serialize(self): + assert (len(self.regTxHash) == 32 + and len(self.hashPrevSubTx) == 32 + and len(self.payloadSig) == 96) + return ( + pack_le_uint16(self.version) + # version + self.regTxHash + # regTxHash + self.hashPrevSubTx + # hashPrevSubTx + pack_le_int64(self.creditFee) + # creditFee + self.payloadSig # payloadSig + ) + + @classmethod + def read_tx_extra(cls, deser): + return DashSubTxCloseAccount( + deser._read_le_uint16(), # version + deser._read_nbytes(32), # regTxHash + deser._read_nbytes(32), # hashPrevSubTx + deser._read_le_int64(), # creditFee + deser._read_nbytes(96) # payloadSig + ) + + +# https://dash-docs.github.io/en/developer-reference#outpoint +class TxOutPoint(namedtuple("TxOutPoint", "hash index")): + '''Class representing tx output outpoint''' + def serialize(self): + assert len(self.hash) == 32 + return ( + self.hash + # hash + pack_le_uint32(self.index) # index + ) + + @classmethod + def read_outpoint(cls, deser): + return TxOutPoint( + deser._read_nbytes(32), # hash + deser._read_le_uint32() # index + ) + + +class DeserializerDash(Deserializer): + '''Deserializer for Dash DIP2 special tx types''' + # Supported Spec Tx types and corresponding classes mapping + PRO_REG_TX = 1 + PRO_UP_SERV_TX = 2 + PRO_UP_REG_TX = 3 + PRO_UP_REV_TX = 4 + CB_TX = 5 + SUB_TX_REGISTER = 8 + SUB_TX_TOPUP = 9 + SUB_TX_RESET_KEY = 10 + SUB_TX_CLOSE_ACCOUNT = 11 + + SPEC_TX_HANDLERS = { + PRO_REG_TX: DashProRegTx, + PRO_UP_SERV_TX: DashProUpServTx, + PRO_UP_REG_TX: DashProUpRegTx, + PRO_UP_REV_TX: DashProUpRevTx, + CB_TX: DashCbTx, + SUB_TX_REGISTER: DashSubTxRegister, + SUB_TX_TOPUP: DashSubTxTopup, + SUB_TX_RESET_KEY: DashSubTxResetKey, + SUB_TX_CLOSE_ACCOUNT: DashSubTxCloseAccount, + } + + def _read_outpoint(self): + return TxOutPoint.read_outpoint(self) + + def read_tx(self): + header = self._read_le_uint32() + tx_type = header >> 16 # DIP2 tx type + if tx_type: + version = header & 0x0000ffff + else: + version = header + + if tx_type and version < 3: + version = header + tx_type = 0 + + inputs = self._read_inputs() + outputs = self._read_outputs() + locktime = self._read_le_uint32() + if tx_type: + extra_payload_size = self._read_varint() + end = self.cursor + extra_payload_size + spec_tx_class = DeserializerDash.SPEC_TX_HANDLERS.get(tx_type) + if spec_tx_class: + read_method = getattr(spec_tx_class, 'read_tx_extra', None) + extra_payload = read_method(self) + assert isinstance(extra_payload, spec_tx_class) + else: + extra_payload = self._read_nbytes(extra_payload_size) + assert self.cursor == end + else: + extra_payload = b'' + tx = DashTx(version, inputs, outputs, locktime, tx_type, extra_payload) + return tx diff --git a/electrumx/server/block_processor.py b/electrumx/server/block_processor.py index c37eec2..6061a15 100644 --- a/electrumx/server/block_processor.py +++ b/electrumx/server/block_processor.py @@ -44,6 +44,7 @@ class Prefetcher(object): self.min_cache_size = 10 * 1024 * 1024 # This makes the first fetch be 10 blocks self.ave_size = self.min_cache_size // 10 + self.polling_delay = 5 async def main_loop(self, bp_height): '''Loop forever polling for more blocks.''' @@ -53,7 +54,7 @@ class Prefetcher(object): # Sleep a while if there is nothing to prefetch await self.refill_event.wait() if not await self._prefetch_blocks(): - await asyncio.sleep(5) + await asyncio.sleep(self.polling_delay) except DaemonError as e: self.logger.info(f'ignoring daemon error: {e}') @@ -98,11 +99,11 @@ class Prefetcher(object): async with self.semaphore: while self.cache_size < self.min_cache_size: # Try and catch up all blocks but limit to room in cache. - # Constrain fetch count to between 0 and 500 regardless; - # testnet can be lumpy. - cache_room = self.min_cache_size // self.ave_size + # Constrain fetch count to between 0 and 100 regardless; + # some chains can be lumpy. + cache_room = max(self.min_cache_size // self.ave_size, 1) count = min(daemon_height - self.fetched_height, cache_room) - count = min(500, max(count, 0)) + count = min(100, max(count, 0)) if not count: self.caught_up = True return False @@ -626,8 +627,6 @@ class BlockProcessor(object): if first_sync: self.logger.info(f'{electrumx.version} synced to ' f'height {self.height:,d}') - # Initialise the notification framework - await self.notifications.on_block(set(), self.height) # Reopen for serving await self.db.open_for_serving() @@ -682,3 +681,129 @@ class DecredBlockProcessor(BlockProcessor): start -= 1 count += 1 return start, count + + +class NamecoinBlockProcessor(BlockProcessor): + + def advance_txs(self, txs): + result = super().advance_txs(txs) + + tx_num = self.tx_count - len(txs) + script_name_hashX = self.coin.name_hashX_from_script + update_touched = self.touched.update + hashXs_by_tx = [] + append_hashXs = hashXs_by_tx.append + + for tx, tx_hash in txs: + hashXs = [] + append_hashX = hashXs.append + + # Add the new UTXOs and associate them with the name script + for idx, txout in enumerate(tx.outputs): + # Get the hashX of the name script. Ignore non-name scripts. + hashX = script_name_hashX(txout.pk_script) + if hashX: + append_hashX(hashX) + + append_hashXs(hashXs) + update_touched(hashXs) + tx_num += 1 + + self.db.history.add_unflushed(hashXs_by_tx, self.tx_count - len(txs)) + + return result + + +class LTORBlockProcessor(BlockProcessor): + + def advance_txs(self, txs): + self.tx_hashes.append(b''.join(tx_hash for tx, tx_hash in txs)) + + # Use local vars for speed in the loops + undo_info = [] + tx_num = self.tx_count + script_hashX = self.coin.hashX_from_script + s_pack = pack + put_utxo = self.utxo_cache.__setitem__ + spend_utxo = self.spend_utxo + undo_info_append = undo_info.append + update_touched = self.touched.update + + hashXs_by_tx = [set() for _ in txs] + + # Add the new UTXOs + for (tx, tx_hash), hashXs in zip(txs, hashXs_by_tx): + add_hashXs = hashXs.add + tx_numb = s_pack('= 1 required') + if not (0, 10, 1) <= aiorpcx_version < (0, 11): + raise RuntimeError('aiorpcX version 0.10.x, x >= 1, required') env = self.env min_str, max_str = env.coin.SESSIONCLS.protocol_min_max_strings() @@ -99,31 +101,31 @@ class Controller(ServerBase): db = DB(env) bp = BlockProcessor(env, db, daemon, notifications) - # Set ourselves up to implement the MemPoolAPI - self.height = daemon.height - self.cached_height = daemon.cached_height - self.mempool_hashes = daemon.mempool_hashes - self.raw_transactions = daemon.getrawtransactions - self.lookup_utxos = db.lookup_utxos - self.on_mempool = notifications.on_mempool - MemPoolAPI.register(Controller) - mempool = MemPool(env.coin, self) + # Set notifications up to implement the MemPoolAPI + notifications.height = daemon.height + notifications.cached_height = daemon.cached_height + notifications.mempool_hashes = daemon.mempool_hashes + notifications.raw_transactions = daemon.getrawtransactions + notifications.lookup_utxos = db.lookup_utxos + MemPoolAPI.register(Notifications) + mempool = MemPool(env.coin, notifications) session_mgr = SessionManager(env, db, bp, daemon, mempool, - notifications, shutdown_event) + shutdown_event) # Test daemon authentication, and also ensure it has a cached # height. Do this before entering the task group. await daemon.height() caught_up_event = Event() - serve_externally_event = Event() - synchronized_event = Event() - async with TaskGroup() as group: - await group.spawn(session_mgr.serve(serve_externally_event)) - await group.spawn(bp.fetch_and_process_blocks(caught_up_event)) + mempool_event = Event() + + async def wait_for_catchup(): await caught_up_event.wait() await group.spawn(db.populate_header_merkle_cache()) - await group.spawn(mempool.keep_synchronized(synchronized_event)) - await synchronized_event.wait() - serve_externally_event.set() \ No newline at end of file + await group.spawn(mempool.keep_synchronized(mempool_event)) + + async with TaskGroup() as group: + await group.spawn(session_mgr.serve(notifications, mempool_event)) + await group.spawn(bp.fetch_and_process_blocks(caught_up_event)) + await group.spawn(wait_for_catchup()) diff --git a/electrumx/server/daemon.py b/electrumx/server/daemon.py index 506459f..9a87099 100644 --- a/electrumx/server/daemon.py +++ b/electrumx/server/daemon.py @@ -116,7 +116,7 @@ class Daemon(object): nonlocal last_error_log, retry now = time.time() if now - last_error_log > 60: - last_error_time = now + last_error_log = now self.logger.error(f'{error} Retrying occasionally...') if retry == self.max_retry and self.failover(): retry = 0 @@ -445,3 +445,30 @@ class DecredDaemon(Daemon): # FIXME allow self signed certificates connector = aiohttp.TCPConnector(verify_ssl=False) return aiohttp.ClientSession(connector=connector) + + +class PreLegacyRPCDaemon(LegacyRPCDaemon): + '''Handles connections to a daemon at the given URL. + + This class is useful for daemons that don't have the new 'getblock' + RPC call that returns the block in hex, and need the False parameter + for the getblock''' + + async def deserialised_block(self, hex_hash): + '''Return the deserialised block with the given hex hash.''' + return await self._send_single('getblock', (hex_hash, False)) + + +class SmartCashDaemon(Daemon): + + async def masternode_broadcast(self, params): + '''Broadcast a smartnode to the network.''' + return await self._send_single('smartnodebroadcast', params) + + async def masternode_list(self, params): + '''Return the smartnode status.''' + return await self._send_single('smartnodelist', params) + + async def smartrewards(self, params): + '''Return smartrewards data.''' + return await self._send_single('smartrewards', params) diff --git a/electrumx/server/peers.py b/electrumx/server/peers.py index 72b71e4..8e040b4 100644 --- a/electrumx/server/peers.py +++ b/electrumx/server/peers.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017, Neil Booth +# Copyright (c) 2017-2018, Neil Booth # # All rights reserved. # @@ -14,7 +14,7 @@ import ssl import time from collections import defaultdict, Counter -from aiorpcx import (ClientSession, SOCKSProxy, +from aiorpcx import (Connector, RPCSession, SOCKSProxy, Notification, handler_invocation, SOCKSError, RPCError, TaskTimeout, TaskGroup, Event, sleep, run_in_thread, ignore_after, timeout_after) @@ -37,7 +37,7 @@ def assert_good(message, result, instance): f'{type(result).__name__}') -class PeerSession(ClientSession): +class PeerSession(RPCSession): '''An outgoing session to a peer.''' async def handle_request(self, request): @@ -197,14 +197,15 @@ class PeerManager(object): pause = WAKEUP_SECS * 2 ** peer.try_count async with ignore_after(pause): await peer.retry_event.wait() + peer.retry_event.clear() async def _should_drop_peer(self, peer): peer.try_count += 1 is_good = False - for kind, port in peer.connection_port_pairs(): + for kind, port, family in peer.connection_tuples(): peer.last_try = time.time() - kwargs = {} + kwargs = {'family': family} if kind == 'SSL': kwargs['ssl'] = ssl.SSLContext(ssl.PROTOCOL_TLS) @@ -225,8 +226,8 @@ class PeerManager(object): peer_text = f'[{peer}:{port} {kind}]' try: async with timeout_after(120 if peer.is_tor else 30): - async with PeerSession(peer.host, port, - **kwargs) as session: + async with Connector(PeerSession, peer.host, port, + **kwargs) as session: await self._verify_peer(session, peer) is_good = True break @@ -293,7 +294,17 @@ class PeerManager(object): async with TaskGroup() as g: await g.spawn(self._send_headers_subscribe(session, peer, ptuple)) await g.spawn(self._send_server_features(session, peer)) - await g.spawn(self._send_peers_subscribe(session, peer)) + peers_task = await g.spawn(self._send_peers_subscribe + (session, peer)) + + # Process reported peers if remote peer is good + peers = peers_task.result() + await self._note_peers(peers) + features = self._features_to_register(peer, peers) + if features: + self.logger.info(f'registering ourself with {peer}') + # We only care to wait for the response + await session.send_request('server.add_peer', [features]) async def _send_headers_subscribe(self, session, peer, ptuple): message = 'blockchain.headers.subscribe' @@ -356,19 +367,11 @@ class PeerManager(object): # Call add_peer if the remote doesn't appear to know about us. try: real_names = [' '.join([u[1]] + u[2]) for u in raw_peers] - peers = [Peer.from_real_name(real_name, str(peer)) - for real_name in real_names] + return [Peer.from_real_name(real_name, str(peer)) + for real_name in real_names] except Exception: raise BadPeerError('bad server.peers.subscribe response') - await self._note_peers(peers) - features = self._features_to_register(peer, peers) - if not features: - return - self.logger.info(f'registering ourself with {peer}') - # We only care to wait for the response - await session.send_request('server.add_peer', [features]) - # # External interface # diff --git a/electrumx/server/session.py b/electrumx/server/session.py index 0d114ee..7fcb396 100644 --- a/electrumx/server/session.py +++ b/electrumx/server/session.py @@ -20,7 +20,7 @@ from collections import defaultdict from functools import partial from aiorpcx import ( - ServerSession, JSONRPCAutoDetect, JSONRPCConnection, + RPCSession, JSONRPCAutoDetect, JSONRPCConnection, TaskGroup, handler_invocation, RPCError, Request, ignore_after, sleep, Event ) @@ -108,8 +108,7 @@ class SessionGroup(object): class SessionManager(object): '''Holds global state about all sessions.''' - def __init__(self, env, db, bp, daemon, mempool, notifications, - shutdown_event): + def __init__(self, env, db, bp, daemon, mempool, shutdown_event): env.max_send = max(350000, env.max_send) self.env = env self.db = db @@ -136,8 +135,6 @@ class SessionManager(object): # Event triggered when electrumx is listening for incoming requests. self.server_listening = Event() self.session_event = Event() - # Tell sessions about subscription changes - notifications.add_callback(self._notify_sessions) # Set up the RPC request handlers cmds = ('add_peer daemon_url disconnect getinfo groups log peers ' @@ -158,7 +155,7 @@ class SessionManager(object): host, port = args[:2] try: self.servers[kind] = await server - except Exception as e: + except OSError as e: # don't suppress CancelledError self.logger.error(f'{kind} server failed to listen on {host}:' f'{port:d} :{e!r}') else: @@ -205,6 +202,7 @@ class SessionManager(object): # Start listening for incoming connections if paused and # session count has fallen if paused and len(self.sessions) <= low_watermark: + self.logger.info('resuming listening for incoming connections') await self._start_external_servers() paused = False @@ -291,7 +289,7 @@ class SessionManager(object): 'errors': sum(s.errors for s in self.sessions), 'groups': len(group_map), 'logged': len([s for s in self.sessions if s.log_me]), - 'paused': sum(s.paused for s in self.sessions), + 'paused': sum(not s._can_send.is_set() for s in self.sessions), 'pid': os.getpid(), 'peers': self.peer_mgr.info(), 'requests': sum(s.count_pending_items() for s in self.sessions), @@ -346,6 +344,8 @@ class SessionManager(object): '''Refresh the cached header subscription responses to be for height, and record that as notified_height. ''' + # Paranoia: a reorg could race and leave db_height lower + height = min(height, self.db.db_height) electrum, raw = await self._electrum_and_raw_headers(height) self.hsub_results = (electrum, {'hex': raw.hex(), 'height': height}) self.notified_height = height @@ -477,7 +477,7 @@ class SessionManager(object): # --- External Interface - async def serve(self, event): + async def serve(self, notifications, event): '''Start the RPC server if enabled. When the event is triggered, start TCP and SSL servers.''' try: @@ -499,6 +499,8 @@ class SessionManager(object): if self.env.drop_client is not None: self.logger.info('drop clients matching: {}' .format(self.env.drop_client.pattern)) + # Start notifications; initialize hsub_results + await notifications.start(self.db.db_height, self._notify_sessions) await self._start_external_servers() # Peer discovery should start after the external servers # because we connect to ourself @@ -511,7 +513,7 @@ class SessionManager(object): # Close servers and sessions await self._close_servers(list(self.servers.keys())) async with TaskGroup() as group: - for session in list(self.sessions): + for session in self.sessions: await group.spawn(session.close(force_after=1)) def session_count(self): @@ -559,16 +561,14 @@ class SessionManager(object): '''Notify sessions about height changes and touched addresses.''' height_changed = height != self.notified_height if height_changed: - # Paranoia: a reorg could race and leave db_height lower - await self._refresh_hsub_results(min(height, self.db.db_height)) + await self._refresh_hsub_results(height) # Invalidate our history cache for touched hashXs hc = self.history_cache for hashX in set(hc).intersection(touched): del hc[hashX] - async with TaskGroup() as group: - for session in self.sessions: - await group.spawn(session.notify(touched, height_changed)) + for session in self.sessions: + await session.spawn(session.notify, touched, height_changed) def add_session(self, session): self.sessions.add(session) @@ -592,7 +592,7 @@ class SessionManager(object): self.subs_room -= 1 -class SessionBase(ServerSession): +class SessionBase(RPCSession): '''Base class of ElectrumX JSON sessions. Each session runs its tasks in asynchronous parallelism with other @@ -648,7 +648,7 @@ class SessionBase(ServerSession): status += 'C' if self.log_me: status += 'L' - status += str(self.concurrency.max_concurrent) + status += str(self._concurrency.max_concurrent) return status def connection_made(self, transport): @@ -663,12 +663,11 @@ class SessionBase(ServerSession): def connection_lost(self, exc): '''Handle client disconnection.''' - super().connection_lost(exc) self.session_mgr.remove_session(self) msg = '' - if self.paused: - msg += ' whilst paused' - if self.concurrency.max_concurrent != self.max_concurrent: + if not self._can_send.is_set(): + msg += ' with full socket buffer' + if self._concurrency.max_concurrent != self.max_concurrent: msg += ' whilst throttled' if self.send_size >= 1024*1024: msg += ('. Sent {:,d} bytes in {:,d} messages' @@ -676,12 +675,13 @@ class SessionBase(ServerSession): if msg: msg = 'disconnected' + msg self.logger.info(msg) + super().connection_lost(exc) def count_pending_items(self): return len(self.connection.pending_requests()) def semaphore(self): - return Semaphores([self.concurrency.semaphore, self.group.semaphore]) + return Semaphores([self._concurrency.semaphore, self.group.semaphore]) def sub_count(self): return 0 @@ -701,7 +701,7 @@ class SessionBase(ServerSession): class ElectrumX(SessionBase): '''A TCP server that handles incoming Electrum connections.''' - PROTOCOL_MIN = (1, 1) + PROTOCOL_MIN = (1, 2) PROTOCOL_MAX = (1, 4) def __init__(self, *args, **kwargs): @@ -1061,7 +1061,7 @@ class ElectrumX(SessionBase): async def banner(self): '''Return the server banner text.''' - banner = 'Welcome to Electrum!' + banner = f'You are connected to an {electrumx.version} server.' if self.is_tor(): banner_file = self.env.tor_banner_file @@ -1230,6 +1230,7 @@ class ElectrumX(SessionBase): handlers = { 'blockchain.block.get_chunk': self.block_get_chunk, 'blockchain.block.get_header': self.block_get_header, + 'blockchain.block.headers': self.block_headers_12, 'blockchain.estimatefee': self.estimatefee, 'blockchain.relayfee': self.relayfee, 'blockchain.scripthash.get_balance': self.scripthash_get_balance, @@ -1240,23 +1241,16 @@ class ElectrumX(SessionBase): 'blockchain.transaction.broadcast': self.transaction_broadcast, 'blockchain.transaction.get': self.transaction_get, 'blockchain.transaction.get_merkle': self.transaction_merkle, + 'mempool.get_fee_histogram': self.mempool.compact_fee_histogram, 'server.add_peer': self.add_peer, 'server.banner': self.banner, 'server.donation_address': self.donation_address, 'server.features': self.server_features_async, 'server.peers.subscribe': self.peers_subscribe, + 'server.ping': self.ping, 'server.version': self.server_version, } - if ptuple >= (1, 2): - # New handler as of 1.2 - handlers.update({ - 'mempool.get_fee_histogram': - self.mempool.compact_fee_histogram, - 'blockchain.block.headers': self.block_headers_12, - 'server.ping': self.ping, - }) - if ptuple >= (1, 4): handlers.update({ 'blockchain.block.header': self.block_header, @@ -1440,3 +1434,32 @@ class DashElectrumX(ElectrumX): return [mn for mn in cache if mn['payee'] in payees] else: return cache + + +class SmartCashElectrumX(DashElectrumX): + '''A TCP server that handles incoming Electrum-SMART connections.''' + + def set_request_handlers(self, ptuple): + super().set_request_handlers(ptuple) + self.request_handlers.update({ + 'smartrewards.current': self.smartrewards_current, + 'smartrewards.check': self.smartrewards_check + }) + + async def smartrewards_current(self): + '''Returns the current smartrewards info.''' + result = await self.daemon_request('smartrewards', ['current']) + if result is not None: + return result + return None + + async def smartrewards_check(self, addr): + ''' + Returns the status of an address + + addr: a single smartcash address + ''' + result = await self.daemon_request('smartrewards', ['check', addr]) + if result is not None: + return result + return None diff --git a/electrumx_rpc b/electrumx_rpc index b4aec74..69cc70b 100755 --- a/electrumx_rpc +++ b/electrumx_rpc @@ -10,7 +10,7 @@ '''Script to send RPC commands to a running ElectrumX server.''' -from aiorpcx import timeout_after, ClientSession, TaskTimeout +from aiorpcx import timeout_after, Connector, RPCSession, TaskTimeout import argparse import asyncio import json @@ -114,7 +114,7 @@ def main(): async def send_request(): try: async with timeout_after(15): - async with ClientSession('localhost', port) as session: + async with Connector(RPCSession, 'localhost', port) as session: result = await session.send_request(method, args) if method in ('query', ): for line in result: diff --git a/setup.py b/setup.py index 4aafdf7..b6746c5 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ import setuptools -version = '1.8.7' +version = '1.8.12' setuptools.setup( name='electrumX', @@ -8,11 +8,13 @@ setuptools.setup( python_requires='>=3.6', # via environment variables, in which case I've tested with 15.0.4 # "x11_hash" package (1.4) is required to sync DASH network. + # "x13_hash" package is required to sync BitcoinPlus network. # "tribus_hash" package is required to sync Denarius network. # "blake256" package is required to sync Decred network. # "xevan_hash" package is required to sync Xuez network. # "groestlcoin_hash" package is required to sync Groestlcoin network. - install_requires=['aiorpcX>=0.8.1,<0.9', 'attrs', + # "pycryptodomex" package is required to sync SmartCash network. + install_requires=['aiorpcX>=0.10.1,<0.11', 'attrs', 'plyvel', 'pylru', 'aiohttp >= 2'], packages=setuptools.find_packages(include=('electrumx*',)), description='ElectrumX Server', diff --git a/tests/blocks/bitcoinplus_mainnet_749740.json b/tests/blocks/bitcoinplus_mainnet_749740.json new file mode 100644 index 0000000..308e55c --- /dev/null +++ b/tests/blocks/bitcoinplus_mainnet_749740.json @@ -0,0 +1,15 @@ +{ + "hash": "b51b081592349793bbf2d761828aabef40db8c7dd9451f0a0ea279faec1aecaf", + "size": 456, + "height": 749740, + "merkleroot": "cddd323b42891a0787389d40ea0971fbf4b0215ca40fc0229e94edf486eeb1dc", + "tx": [ + "03079ad8d2c3e9db200582e7f3addec3f663c1388ea565482f6140ed58e83f1a", + "6805f87aa7027c84db875d7147696dadd998cf261237bac4a3229e0d7d35c104" + ], + "time": 1544168075, + "nonce": 0, + "bits": "1e0cd5ed", + "previousblockhash": "d86428d967a901e169de1313276f2d463664179e5a7f303923811d1c4a177102", + "block": "030000200271174a1c1d812339307f5a9e176436462d6f271313de69e101a967d92864d8dcb1ee86f4ed949e22c00fa45c21b0f4fb7109ea409d3887071a89423b32ddcd8b220a5cedd50c1e0000000002010000008b220a5c010000000000000000000000000000000000000000000000000000000000000000ffffffff0503ac700b00ffffffff0200000000000000000000000000000000000000000000010000008b220a5c015186024f3de419c8846da76a254930f9b5d68246eb21b1aceca5ba889a190ba30100000049483045022100d81ae320b3f1a296cae778b342937412cc4689f375d5dfc594c1df7fac6aa046022015c71b090e85579f041ae31c6d1881959414231882648b0878a886ba8b8b2a5a01ffffffff03000000000000000000408491a400000000232102eeb314d0ae50152e8f416521b0f3184325f57d8c7932d6a91d186fa2820d3da7ac56aca7a400000000232102eeb314d0ae50152e8f416521b0f3184325f57d8c7932d6a91d186fa2820d3da7ac00000000473045022100c4a62b764a0984e6e2f909ca41b21f61b17f230d60f6c2ba69cb504300931bc202200aa57659cf8c54861002ca924b018385aa3a44c4ff0bc9207ddecc3b8086f76e" +} diff --git a/tests/blocks/bitcoincash_mainnet_100000.json b/tests/blocks/bitcoinsv_mainnet_100000.json similarity index 100% rename from tests/blocks/bitcoincash_mainnet_100000.json rename to tests/blocks/bitcoinsv_mainnet_100000.json diff --git a/tests/blocks/civx_mainnet_50000.json b/tests/blocks/civx_mainnet_50000.json new file mode 100644 index 0000000..aa8cdde --- /dev/null +++ b/tests/blocks/civx_mainnet_50000.json @@ -0,0 +1,16 @@ +{ + "hash": "596b9249ffd6c1dfb3cfa16d3ade2e0cb57342fed66b90e6444dc54cc99d0fc4", + "size": 445, + "height": 50000, + "merkleroot": "8db60d963dad433c8655021d291aafd731a6754aac9b69cf0dece61e5b3c1b75", + "tx": [ + "364c947002496d3115379dd779e2ce54cf114fb6cca42bd3da4de1823e4f08cc", + "a09b658cbe21162bbeb1821e2caf1f0947f8cdd517b87f2232ba1150043790e1" + ], + "time": 1526710352, + "nonce": 0, + "bits": "1a7b61c6", + "previousblockhash": "44530f8cc7040528199dc3a41a8b660bf2feb8e0015d5c787086655ac03cbca3", + "signature": "30440220710162172b283cca7007c72cbb848a52388518b8cfb7a6c906744f473afe312b022056fd92b06351ee7049f0857d688134449566dcb82d0f6a3cb36208832988cba3", + "block": "07000000a3bc3cc05a658670785c5d01e0b8fef20b668b1aa4c39d19280504c78c0f5344751b3c5b1ee6ec0dcf699bac4a75a631d7af1a291d0255863c43ad3d960db68d50c0ff5ac6617b1a00000000020100000050c0ff5a010000000000000000000000000000000000000000000000000000000000000000ffffffff040350c300ffffffff01000000000000000000000000000100000050c0ff5a017879028fc93da2d5ce18feee9f074086790d34c97ccfafe15a42b2423f3e28490200000049483045022100e3a092a079346179213d9b7079c9795e291883cb715e3efee656b9a981632432022002cafb6d6d497705f455b5d6a60bca38c88c26910101faef433ecfe80515e1ef01ffffffff03000000000000000000c07975296d000000232103c0c30d173c8478ceaaba836e8cae3c8c4e43f88f6d555600be124781b533956bacc07975296d000000232103c0c30d173c8478ceaaba836e8cae3c8c4e43f88f6d555600be124781b533956bac000000004630440220710162172b283cca7007c72cbb848a52388518b8cfb7a6c906744f473afe312b022056fd92b06351ee7049f0857d688134449566dcb82d0f6a3cb36208832988cba3" +} diff --git a/tests/blocks/civx_testnet_60000.json b/tests/blocks/civx_testnet_60000.json new file mode 100644 index 0000000..ac7b20c --- /dev/null +++ b/tests/blocks/civx_testnet_60000.json @@ -0,0 +1,16 @@ +{ + "hash": "1e4447195f4259b313b2c56072f7000237828e659254d5bf55f2b91e443f124b", + "size": 401, + "height": 60000, + "merkleroot": "9cf808c8f0e0d62864edee37a27fc44114a8896a6ace0c4ac6434c58e0d450ef", + "tx": [ + "b3e734e183f1b4f10cc3de258d02efbd73fc64577e9c5fc54f7d750b95b29aff", + "859a989109ee967e941808a43224463e181b51af8acc27ad05e2e4f7fdf45f81" + ], + "time": 1537111488, + "nonce": 0, + "bits": "1b00ffff", + "previousblockhash": "4f57fffd01fabbf020ac9e2110b4de9e127c06ba19f83741a5cb26f3b0aa13fe", + "signature" : "304402201d89a82d54b81e3aa0de97875bb15a874fce3319c7baf1751d18620f905909dc02202fc3fe4c17ef43aaa62dab4a6e0c735751d75b8f66e2a81cbead52f744570769", + "block": "07000000fe13aab0f326cba54137f819ba067c129edeb410219eac20f0bbfa01fdff574fef50d4e0584c43c64a0cce6a6a89a81441c47fa237eeed6428d6e0f0c808f89cc0759e5bffff001b000000000201000000c0759e5b010000000000000000000000000000000000000000000000000000000000000000ffffffff040360ea00ffffffff010000000000000000000000000001000000c0759e5b0143723908791e72544c4796be9da581a40eae3ba54b71b596d167f6ab245b37d60100000049483045022100d11ebd7ac7d0dd94f22416a1b223cf91cf1a70de52b2cd502edc1121c4d5409302207e22f22add1dd96bd214ca0f8875e4f06d9688c27053db82ea0ae0e9676d575401ffffffff02000000000000000000c05469f60300000023210288e5256969a3a9fd4735e6b8c8f905b270564f2448658177faf4c990e5745c45ac0000000046304402201d89a82d54b81e3aa0de97875bb15a874fce3319c7baf1751d18620f905909dc02202fc3fe4c17ef43aaa62dab4a6e0c735751d75b8f66e2a81cbead52f744570769" +} diff --git a/tests/blocks/myriadcoin_mainnet_2587044.json b/tests/blocks/myriadcoin_mainnet_2587044.json new file mode 100644 index 0000000..b87182a --- /dev/null +++ b/tests/blocks/myriadcoin_mainnet_2587044.json @@ -0,0 +1,14 @@ +{ + "hash": "09a2344ca39c422a473ab2ac0a93c0de5eef7bbc63c59ea36bf8a126ae2fbc26", + "size": 326, + "height": 2587044, + "merkleroot": "0373487200798a478a9b5330fddcc092cb08f9b517c62eacbfbe733b8e8d3680", + "tx": [ + "0373487200798a478a9b5330fddcc092cb08f9b517c62eacbfbe733b8e8d3680" + ], + "time": 1540383063, + "nonce": 1758391936, + "bits": "1b013fb1", + "previousblockhash": "6bebe78892419acf8f47fa34ac08417036c244a244d209dbb5113edfda7ae480", + "block": "00065a2080e47adadf3e11b5db09d244a244c236704108ac34fa478fcf9a419288e7eb6b80368d8e3b73bebfac2ec617b5f908cb92c0dcfd30539b8a478a7900724873035761d05bb13f011b80eece6801010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4d03a47927045761d05b08fabe6d6db5b8ddd39dc3e80a8930480db7f9dd41acc305fe5f41f5c953ae73e980a534b9020000000000000000005275250000000e2f6d696e696e672d64757463682f00000000020000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf900ba1dd2050000001976a9140c6de8cbb3e5fc90476c696881dc28bb9b4989e088ac0120000000000000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/tests/blocks/nix_mainnet_50000.json b/tests/blocks/nix_mainnet_50000.json new file mode 100644 index 0000000..4dde731 --- /dev/null +++ b/tests/blocks/nix_mainnet_50000.json @@ -0,0 +1,14 @@ +{ + "hash": "b9fa17b5469c68aeddea48666f12c8ae5cdc3e8521b4b5637e10099cda8728fd", + "size": 377, + "height": 50000, + "merkleroot": "2ee565d865d766a9861d77f1d3c34b364261a105fd0b10c15e9cb07dc61b1493", + "tx": [ + "2ee565d865d766a9861d77f1d3c34b364261a105fd0b10c15e9cb07dc61b1493" + ], + "time": 1536401916, + "nonce": 1610805540, + "bits": "1b0551f5", + "previousblockhash": "acec77ce8845f34d2a854dc7da66151338c2f42f1c7f51782bd7732017f13c31", + "block": "00000020313cf1172073d72b78517f1c2ff4c238131566dac74d852a4df34588ce77ecac93141bc67db09c5ec1100bfd05a16142364bc3d3f1771d86a966d765d865e52efca1935bf551051b24f1026001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff200350c30004fca1935b08180006a3510200000d2f6e6f64655374726174756d2f00000000050000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90090f4f70000000017a914e48c970e4a4faa6222688ec6333eb53c578e59f78700d012130000000017a9146a27966d76edfdfb3c53dc37dd5471bdeac7d46c870020a1070000000017a9147150055215791b779dddb1d112541a3fce71061b8700c0cf6a000000001976a91490f50a1fa5b280282de2a3ec15164a766fd48a0288ac0120000000000000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/tests/blocks/nix_testnet_200.json b/tests/blocks/nix_testnet_200.json new file mode 100644 index 0000000..e03db0e --- /dev/null +++ b/tests/blocks/nix_testnet_200.json @@ -0,0 +1,14 @@ +{ + "hash": "9d5d8d308484a654cfc18fc6290734dca584bf0c02409429682a8b46715a0811", + "size": 384, + "height": 200, + "merkleroot": "ee1377591fe82696a15f416476a28cf57a83af77e799bbfdff24909be06cc559", + "tx": [ + "ee1377591fe82696a15f416476a28cf57a83af77e799bbfdff24909be06cc559" + ], + "time": 1542147760, + "nonce": 0, + "bits": "1a2157b9", + "previousblockhash": "1634ccd348860d24b5eabffc8782ae1aa1d6797477f0d4910cb25488a28cb372", + "block": "0000002072b38ca28854b20c91d4f0777479d6a11aae8287fcbfeab5240d8648d3cc341659c56ce09b9024fffdbb99e777af837af58ca27664415fa19626e81f597713eeb04eeb5bb957211a00000000010203000001daf694ffcf73e2710b6148d89fc10b95cb55e255d804014c5141712168b9524c01000000171600147c5aad68a58a92630e3feab030fcaeb2cfff37feffffffff0530ecadf66b01000032b863a914f0c3b8f1fb7c1887a70c0108f729620c4c0901228767a914bdb5bb31196596f760ddaa49f7a82956e30b58de876830ecadf66b01000032b863a914f0c3b8f1fb7c1887a70c0108f729620c4c0901228767a914bdb5bb31196596f760ddaa49f7a82956e30b58de87680090d0030000000017a9147667be5313f1e3fb921a096b4b9b59c82b157ebe870090d0030000000017a914bf41e0caa3649bd8b9f4008103fb2a2757f3b8f3870000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf900000000473045022100b517ff2a36aee842e4ff750723b1cea0e7cc0064677d69735e4775a01245224802206db5bf42c16d76e790e97f741a10f576628c38bcb5a7072d1df4be9c1cd874e4" +} diff --git a/tests/blocks/noir_mainnet_370000.json b/tests/blocks/noir_mainnet_370000.json new file mode 100644 index 0000000..d464e9d --- /dev/null +++ b/tests/blocks/noir_mainnet_370000.json @@ -0,0 +1,14 @@ +{ + "hash": "572d8a5897cad3f3a75811258513d321e8971c27ed210bb24eba4cd59697dc6d", + "size": 230, + "height": 370000, + "merkleroot": "21000ff185207fc1b208ab1c03de33acb678d6ef542731426da5bfb08627d0b0", + "tx": [ + "21000ff185207fc1b208ab1c03de33acb678d6ef542731426da5bfb08627d0b0" + ], + "time": 1542089008, + "nonce": 1713111040, + "bits": "1d05e718", + "previousblockhash": "cb9b3ff2a750f644e9389f50c508e9a4e217df2f07c5bc6a89a2e7fc82e2cdfe", + "block": "00000020fecde282fce7a2896abcc5072fdf17e2a4e908c5509f38e944f650a7f23f9bcbb0d02786b0bfa56d42312754efd678b6ac33de031cab08b2c17f2085f10f00213069ea5b18e7051d00001c660101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1e0350a505043069ea5b083fff6fd4000000000b2f47666c6172652e696f2f000000000260b8131a000000001976a914122466aaa347290e3b3b7858f2ba041af97d1b4388ac20c46d30000000001976a914a26f5f0cf1b72ae0a5ab533f1e5f420876b3bf6988ac00000000" +} \ No newline at end of file diff --git a/tests/blocks/smartcash_mainnet_200000.json b/tests/blocks/smartcash_mainnet_200000.json new file mode 100644 index 0000000..5056cbe --- /dev/null +++ b/tests/blocks/smartcash_mainnet_200000.json @@ -0,0 +1,16 @@ +{ + "hash": "000000000000d1772b7e3ffc661133c252faedcc52b3dd186b83da4b2f2f8cbe", + "size": 692, + "height": 200000, + "merkleroot": "f8f490671e499b66a73e3fe37f3b2288b82e3d359fc3c18938f32e9e830928d2", + "tx": [ + "c19c6e1dd5ca9d06b046a2962782293cdd9be39bb006ce65add0ad945c9eaeec", + "0151e788a439caa317dce1cf5a754f0b5bb8639d4f1073e89d3baa450fda5306", + "a4217a9a787b66a597efae52b24e2c88d1700cf5661bac6ed58c718f90a98b97" + ], + "time": 1511678597, + "nonce": 3716569074, + "bits": "1b01c757", + "previousblockhash": "0000000000016e6bcdbe8af532509cf5aaf99e74b8b0346a59d360beb460e0bf", + "block": "02000000bfe060b4be60d3596a34b0b8749ef9aaf59c5032f58abecd6b6e010000000000d22809839e2ef33889c1c39f353d2eb888223b7fe33f3ea7669b491e6790f4f885621a5a57c7011bf25786dd0301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2703400d03062f503253482f0485621a5a087ffd6961cf0000000d2f6e6f64655374726174756d2f000000000240e6202d040000001976a9145dd99e7cfdee45d47edf9b2d92df27961241145e88ac40412d574f0000001976a9144a7018841fc6003d66b6a1b859e73b4cc3e621b488ac0000000001000000019521d2cde436c42b81158198b2cd8b9d52dc093d4f8465163ecc98a134dd12a6000000006b483045022100ddad79fd8a9fa0ca664ac8e91aa7c8dcc7cad8c4894e1a7d9143de4bdedeef9f022013dfd0605b50d22d2675e21a27255540fa48263ab44801d287a61883ee8074c3012103635fd7668414f4eb1d6088cac789e58709cae9c3c07a00791f415164b67cda4cffffffff0281c03b9e000000001976a9141dc91417504cb86ac5eea49d85a4d3fd51f72db988acbc91e5cb000000001976a914ecdccf8dec8482314050acd84f72d6559a19b30d88ac0000000001000000011a8b6c07eb61bb5e9910de4d31a410a5b69de2bde8a3cb9df599ddaccd373d95000000006c493046022100d1bf91d45a0d53bfad9aa0d226be625f667641fa53661e2cdc21526cf84ede21022100d0cbf38220d789c9b1a5c6288ebfe2e5ddd4ceb5714881d0f43a27d06a6e9649012103133678a3c4d9855f4a25ab318619fe68e0ed67d67c14fa9be678cb561a75f71bffffffff027fd500fc000000001976a914098cd3573bcca56674eb6eeb51fad42ff353945088ac58bda83d000000001976a91456feb1c72217b8f45aa4183da1c81b314a47f5f388ac00000000" +} \ No newline at end of file diff --git a/tests/blocks/trezarcoin_mainnet_612581.json b/tests/blocks/trezarcoin_mainnet_612581.json new file mode 100644 index 0000000..e1f3efa --- /dev/null +++ b/tests/blocks/trezarcoin_mainnet_612581.json @@ -0,0 +1,16 @@ +{ + "hash": "7fccc90aa5997b036d41ec079a2e8e2c52a0d1f64079b59aaa08c25e0e1e1a30", + "size": 682, + "height": 612581, + "merkleroot": "7d9f01b60ab6718e97018b47cd0cf61ca85afe77bcf8d9c90e9709bb2aab9539", + "tx": [ + "758012ea68d57bdc6e413a6d4195638b410df2ed8a3b2387343a854bb3a1c4b6", + "c9f6d252f90f42884774d66d8ca17629333cda2871eeb3612307abeebb7e888d", + "1354ba387c5f42f807889741a63704fc0ea87dc04f29834111c5f8d80ac0a70b" + ], + "time": 1541864019, + "nonce": 0, + "bits": "1c092c62", + "previousblockhash": "ac69b095cc53f7a0e9197a243fab2dfa49e7f0934fa79ec68f47993be813b33e", + "block": "030000003eb313e83b99478fc69ea74f93f0e749fa2dab3f247a19e9a0f753cc95b069ac3995ab2abb09970ec9d9f8bc77fe5aa81cf60ccd478b01978e71b60ab6019f7d53fae65b622c091c00000000030200000053fae65b010000000000000000000000000000000000000000000000000000000000000000ffffffff0d03e558090130062f503253482fffffffff0100000000000000000000000000000200000053fae65b014f5dccf6592b950c707a5ae62c11644bf0cd1bd5777412a26c25e60015ce4f2001000000494830450220360d685960bd8fa30617beac5c952073e2d89be2528eeb11d475e43b894abdfd0221009b7cd6f2b5d8e2f8ad1919ea81b058ba1703e8c07180c09bacc974ec418a612b01ffffffff020000000000000000002059a4cd000000002321026b1af42e2ea1f61ca8bdb563a61787f8d69d7578de77229ef7bb2d2120b7f8f3ac000000000002000000d8f9e65b01b170ad1b81ac0164a637b6bd970c9897cc9be7d4f05b358ccd868a5d2adb2779010000006b483045022100bfffc1364ad5dfc2da6aedc8d8cdb31905d4e8fb7e4c7c5efafada7cbb18559502205a9cd74bba48fc60e142214917a6d66347aa5ca8f0d9664546e37955ca09c401012103765dbe24359bee468d2fde0ad714906bc0c15ce02e7170dbe98d42e663adb3a2feffffff0290aa0830000000001976a9149d864f487a38c872013901e463ea47a56967251888ac404b4c00000000001976a914690acc951705cd7668f6df688ba33c62cf15a3c288ace358090026746578743a536d696c6579476e6f6d6520697320612062616461737320676e6f6d65205e2e5e473045022100ef1ee96a60ce2d0368b371eccf92aea0d532ff5d447ff70b403130f0212b10ba022061c2c9d7b061035fa416303699768c8e99f3f27a470d3b63abc055181ea91350" +} \ No newline at end of file diff --git a/tests/blocks/zcash_testnet_283046.json b/tests/blocks/zcash_testnet_283046.json new file mode 100644 index 0000000..5fb169b --- /dev/null +++ b/tests/blocks/zcash_testnet_283046.json @@ -0,0 +1,16 @@ +{ + "hash": "00036319ae4cfea536d543ea410b89277826340af6134b5ae7972a4f7a3de0a6", + "size": 5276, + "height": 283046, + "merkleroot": "888873d6cc24794d835db193072079d07818dd94dc7401faba955b718965c821", + "tx": [ + "d89a3b4ff8c333875a4a6b6cbe7de9e651f3c6007598c5ef108174ac1b626336", + "ba4d2c82b6700d57c0614fe5bd1fb90fe73da10e61dde2f3b3c87209388c419d", + "5be150e493a89448530a3b0cb43a7bf1c134be937bdc6ea8bb4cbaa5c89c8914" + ], + "time": 1535721514, + "nonce": "00008bfa4bc3c42aaf193cbbb47bca9024391021403e1d45f39a01159c82009a", + "bits": "1f101e83", + "previousblockhash": "00028bdd7797c57413d00165953ff6313e9c5f2d194338312e78b8a55ca6aa24", + "block": "0400000024aaa65ca5b8782e313843192d5f9c3e31f63f956501d01374c59777dd8b020021c86589715b95bafa0174dc94dd1878d079200793b15d834d7924ccd67388888e237da776e7b2209e994340db5cb6124351b503e52943ea095df5f2b93385322a40895b831e101f9a00829c15019af3451d3e402110392490ca7bb4bb3c19af2ac4c34bfa8b0000fd4005001e3c11c2a45123afb3e96715d03aa6e3127b0bb225499523d710dc893d3bf2c1f334794cc3fe8d80fe0881e1d7b9d4a386dd47b0d051d5f8e6158755b52d3af9dad1ae974c2b978156a687bd21c62f6ad49ee9040c295406602a6d1cf482a03e7924f12544134135153c3779202b31cbeacfb2c943b7b98b0d795a622f15b14a82948a2db4f2bb0a3d937427af7c2f5d3ff231bf1da5469c3dafc8c8489be3f5803fb923bf27760e7fe52dddafa581af7494c46d72870ab68ff5e0654d312fc37ce17ded3fd9360dccb3b139a4e09e59990f0cb707640849496eaf856acd424107a6377dfea63967abb4425289139395c54e1330d9625075d96c221911e4b2629f62afad84048d3a55a91deea95322b41b4fb165eee79b75a240522496128d0cd6905e93f42dba2efe3b6cf6276be533b068f7f379533a9d16ce622f048a1b1f1feb8c16b83bd9dd52f76d78fe7f7d016740e2bef9c135fe83e1b889f269fdb77433ab4f15c4a9010517ac156246150c923f641e0b3c9702f10784dde19a43e5211992765c5841ab51adaed4177e0f8291eeba12d600d3d803d7cec09e2947cf5c188805a6147490c19c81368291fcb1d971c66cb8d5a612494b7e9d4895e6f9563b7a52a07a22035a037ba03f186a7cac5ba44b699bbcb1fc067c0841a571bda4b623fb24e4fa2db4737304e4caf17bdf6ec0013af28a03ce1c75b98cc6f5acf242b355a41187218b3d98781026c8be15eb0069a5e642554cea1a590ccdfa425a0c62d9ca05596fbf92c511135f32e4e9b018b3f0f624de86dd5d7bfcbdf053072bddda2e45d498b286780f79fa3890b33a7bb120e77e2feaf376c85a7802642db0a6670dd735dd8f1602f5ad37eaa0cdfa780ef91b26598f122a5f17ca8b763a636e622a24c5bc44b04891cfcd5d9228ab5635266a1a3be239e70a1784d905673bee5555c8bd7e08b452d05792f9b328fce2cd198fce244b89e03987bd12a41bd5ec0aeb3f3bd5342765372b49dbe00fb1e3347fea7abb2dde3691b3a32d4afb4ec9528f94d9628797cc3d0e7dfffb33af2d0d219f3188b713b5e4dad11edd407e28f8b8ec4904281fb40840a22e7b9ec0868ade467cd6890cdef721499a63a4401f6e4be95a251644f31d75a9da11ed954ac2840b0b59792db113e63dd7d09179b5a437dac5097bf7b5418ed871448c51f74c186d662a8e993afb0ba909025cb011698bb831035b3fc66ef86bfa947b09dabeb1a3ac63fdb3891524e86630361bceb58c3a2e725a4ae49d6f4d7c1344993d6644c6970bdca50e099e65ae0e89d3389113528bdb1b42d8bcd2923d803fd9ba493452319761c3f42031ccd7c1655055d90d142061b0758a34d6ebaed959c0fa6dafac86be20ed1fe20f26e3312833af5c75479ebe4a2d556b12b0e709ef7351ebcad944952c760a57d76619d5a72f0af94ccd7ed05d1b5b974067b8409cceb7da871e99a9550d793cabf0e03f0bc54a40e1d45fb71fb40eff2e6d0fa7c994c086a5c1afda32c3fcc62854bff62e19871679922ea6cfa2dfffc9d8764d43e162ce3d7ede0e1c56cd625dc92aab124955bdc4c56d15a26f9da23225f5a2e22f4c5c773afcb2dcf4e0dceee183fdab88291b16bea9a952837df075e439759f55cc05b80d440b637a3bfcccf2194daf02581278594676efdbadac0f098ac53299756b6b89357e6f7d0419ad55f6527b0e1763c0c3e3c2737be3e319dade3525aeedefc806683064bafc69c21b545837472abea915f41ab3d7d826bb22e6eedc128736b6928c7b9ffa3366633fbde03546fa3c36f2e9fdc81e0500f1c8a6cdee3b121d11332769bd7db2dae1b19e24e856cfb8fd99ccbcc6953f9d44e1c1eab607f600c42ce171b92f2cc3799fcb030400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603a651040113ffffffff0220189b3b000000001976a9148a6c756f01e86875e6b6213d536dbd263266062888ac80b2e60e0000000017a9142a71f51b268f74eb3ee5631090589bbf6239bc0c87000000000000000000000000000000000000000400008085202f89000000000000b8510400000000000000000000000100000000000000001027000000000000b68ee5cc6a137376d3c0ee85f6b79a83e432866f99c703db6217064078cc5f4d5ce93244554705daea62988d0f0da3be49ddcc476e471a2bbc2accd465c0baf402e6d35f8b303e3f8b1231fa399781419d28ef75e02391ba22bfee327c51d66e09489e9658689c1d4620010867d5127d04868580c555a91628aecae28061b2c9add8145b186169af5473b7b3bcad895f697b6ddfe8ae866cd6e4de64bd95d20e54f53097353de0fb55e95cd4e711218cb8371b7dce40610318e4f1741369fd390b3028ba8997c9c26de87586cdc9660446e275b936e8338b8151df4bae86fc6e12d382fbb070f93da7e754c06120662c1cae5c220f42c0844fab2aabd7217efb124c049dd377ff53d462133bf83d391566fea5739069d2e1fdf546b915b4f835b51be43a6e82d4ed73490912e3e12a75e7cee1c193f9f8683b7f61ee0813fe949039d4ab7ab220e88b62a5f8fdaf12b588a63c4007410ca49876e5c27a1b2f9c7470509f02a1c50561f39b5bb82e4ab7af2ccfc59254996f107e9f6357b86c49073cc1f772cf33f72deeb09d66d55a97a757b20b3344d3f3b2951c4f3b79db614111f11f6c73fba9d6c0a3fb6740785197d15b900e95795bc48459f3c068022bcb4d15bc4a37f3a92c42c66035cb3fa9fa467c9cafe0efb4fd4d9a9313f0f0889a16c0287e1cd7f0f1952104de00faf616b5981010bfeba2f89fcb2a4e86d496cd579281e6e0bc3fe395fb2a695c38574a0d755c43fe8a5bb802c9d7524c2f353bf4f885d12b986ab608cca547264f9e00d1f611f9d9d0068e7d78e4ce44e6fb83ae7b25448d40c7949bb07331fe030ff81490346d5896b686a760c6139384dfcbdf2dbe43bff776a228c2418178a8f20b9fb483d60788e3b5126f1fca8f311c4af651efa3595957530f8376c60e945e10af3295d3bc6377d93056ba9135dfe43af5b355bbb9c80f10007a5b77ad6d2db49debd7f4f6733d58c79aa0e41d57fe6b37e65a612f5a6087db37c26819691c44f54a208fc210129b51ecb04aec3c6ffd36037efa69986df75d27d0ff01436999f39e4eef379d2b82ca1a8ea5330b383eb6132a23f1a53ff3e02bc2376509a402d5fb4a19fc5685ab5f829a91bef032573e68df896187baae4f24d88db8ea132237fa90b91c1b1cfd42f09952d2f18cfc9c152c532021a06b9dddc1d757a1fe9cf954081a1ef7fd5df0d9a2567a0e6e523f1bc9820dc05c63dd66d2d0dd12d4aaff4ad8a1fd9aca06dc88f5e4820f03078a0aaa1d09c66ff7e57ee4008202175c78905321fcf6beba47d733dc8b527d07bc37bf16ccbe48a79001df1ff104ec90022ed0f6ea7fcd2868a1c5f1f2f3ded4136eeb7db04a59d61e3ec467d8309754b935ab93270222eabce4a66fd656adaa4fb5b461a7a9bc7b3585d36b44d454b64f357043c6f3493eccb06dab906b5cd04bb7e528f72152ef9c5780a78c3a4595a0b075d93c335fc520c53864da9b651109096c121b21b59eceee1c77b64bcccbf257ce119cb087f4aad5ca370550ba2d36810812c40c5c089a84133ae44edb7b42ab45e24cb1fc7b596de06633150e5bf788bed5425846bd5a675b2058235a548483c3b10b0bd695e332aff865596e42ad4ca4a2237ac2bc2373d2d57516b81c81f4349115bcea3d0c72db84a3118ad37836b0ef60a4b3e3cf73348c549678f252531a28fcb90dc6f33b9dac715850cbfca1b16665b13e6212665e72560210dd6e31a92b0186fb698d44a21f496d7b81c9ca9f27ad3d74e7c13169de2e05b69792f18bd19d4dc4eabf75651dddeffe07d924cbcdf284cc586632b6740deec554cb4b46f1ee9a68c8c480e531233b3f2711063353405b4da84c0059b33c1f052a4672ab39cd95902158b5b0401126faa0fc79fd484714569761e8c374ba144480a16abba522acd20b6c629b07c7e8fc70bb5a5e760bf8dc7917a3cec7be5a95a1e28db54032eea849bb018b48bda820848e531131629e59cd1cf4fac78c074be3b22fcc316b0791bcc481841cc1bdcfb489f92eefc24343a34944bf71aaa9a324978a183551b4c179691794cad00cf96181deed56444e307a64f288deb49646c0cc5dddcd691824644c36845f1bb823874393e4e9d6b3fcb35e2f05f45a9ffd60e36d1937751de7eca464613cf3fc7e18a0906f5ca134392125d7001a5d659065893c22d3cd0128b1b971b311df2c6a339fd97fa27ac8fcd5f1852c31c5dd56bf44f736c822bb970820c5770ec86ac879ebc9d8469d4edca1430591c37264a2a5b669c579a73132c7881e98f5f94082b250e7151251728543bd31a54a6cb36c0506c3758d6447c241e22b79519a77aab153c860a2ab4d783f994779930a1f4d111d0473ab5de7fba0de94e0f585f34c55354de5b00408e86c26002887eb94cc653475079e079d1d064f3b359017b346881c16a76150ca763065df511374af9a358dc059ee8dd7a18581f71d12bde6a8c0e7a249c5bec16534b735d23cf49cc0fa020400008085202f89000000000000ba510400000000000000000000000100000000000000001027000000000000b68ee5cc6a137376d3c0ee85f6b79a83e432866f99c703db6217064078cc5f4d3606859d04a0e71b1ee043cd99c1b35967ed9f853e8764dab4de155943f6b6ba79856451b7efa0f4094806394f70edc46d4db04053b48e21ad34f509b0e5386eea55fb6517af0685a00dfcd503bfafd1506001b1b13b8a99674ca16218a3934d6a47ae0bdf70715d4c367df445b48b5cf11ef449cb616e44aeab19cbfdf1b758ae81632f41503cfeaec680e4a2d066b80558f1184c9c8f37f66d5a8a3576226473d4acc5c021853da749f14ad1be45849e012c96c66103e638e06a081287fa8fa3f065e677bd72f767e5cf83fe2d98bfbe2edc21d5f64b1411ba690536722a0fb7cdd8ede09d7b6878bdd9d41c28152d829c3fdeb77be1e2f3d60787023d8f59a0c1742f52c6e894242fa62e0f20806c8b101e281c0a791eb9b0901f3e3d4c6181d0d35e17f5a0a3afa59739e5a872c8afa34af5656459a463bcecb7ab5f6b312e4d8c76491c35c9db5ab020cf038fb6ec721e08e813bc7f3c5d12a11967d91c13a37b8113ad9844ca15375b7cc7227a1a875eb1db927219c0d5748cae57b5769a4306636846b91236ffd02bba6005b28ca2ee3b7e655c157fa67b8667abe2896865ab8ee6dcdb15d146adfe6d731b7822025c8e4b8a526c9a78c97e441c1a055682c142cf070c971008c9f75114fc4c474a2b4ff3b525a8c427ab105acbcede3d23e6338993d4ea21a446e03fc0e2dc37ceefb5859a9044c6e95d3088a897ce615c498a9f4adbae30843338b241f9774349bd52f234332d2b201683a0f132744e1208fc8adb26a3c65a0f13573de20b71d433c960a23840f1edee60a992c4365100534807c8b40e1797464683b25abfcf69322e3ad0eee9d03b8ec33c24f8d8128f5bb93774f54104cc951451d8a7a40306da1e136b8f0521fcc2c4f61bc7bdd9132560b4ecd612752eea3bcf97e7b4f1ac0a55d6c43fc993e7b370a08d2b2b6f64ecb57ce52ef904dec716b28a6c2349c624f53537b8b56b4a86577edb64b3955081de856ba910e2edf5daaff1fd15abd78bf8c527280feca2d2c821ff06c6b2e15799f9c0f2f51c79cd3435d36f9653ab10f184211d986409a79fd6620cdfa5b918c12c0fe841c972924e1699a17eb990909b47793088928880ec30ce5ecfef74462f8c187af913fa3873f1410e16a455d8fb9c64fa671b6c5a0166ec60d752d7f4a42c5b6fefbb530e0eccc7400272687c389d4b543b7681d3c11411515d70407b0261954f401eb73e9567a36c003d257ec5f11c41a87a9510e7d0ca34629153c3b7f286fb06d311df026ccca6bc432879b1cb0ef0bcec1fbfcd68d09347eeeddb49ff37b1d86ceb1e84c2eafea5173a960763ddfeb90c8c1f8155bc74281bc48ca6ea61335df04406851baa3ac473140627773b6c1fc0f5d7cba570b88e74123bd7001e4c12a34c73fefaa48fc852f826bfafd45a036394b200939e849bfc637ec7161e3383694c3cf5ae1d47911899d3e914337de0c979edd5f3cb15e8f34a95ec5bda063555edc061fe1046f9419769bdf54452d50b02e0c911aba993541d33e3e3e71b2387182fe3d8bacd38f0e51c2e38b5367f59475156bd4f4ff62cd4f7e7cae7508d24bb0a9f9f6a8fa7d7349a71ffc37e28322efe7f8637035e24529fadd47d8b9a4354519ed9e936c1c18f24e180735f8da535ce35666651d336b139b0226457e43b6d61991ab9a8db3a72b2889d6d0f58d4b96e29c6b67a410afb384c8b7279697811d8f0d7b555eaee0807b084ab3584164108f435e40c3ca3c7399157a19c6ea7f22031154dc71ee134daf71b8e2911430c01d6d7e92577b5c97cc552e302a429a443d8ff508ed2b77102b9eac113e031816a2f57662a780b79f606727d61ef330e3c872cadbb10987396dd99baa7216e04914520a148d141108bd03e8babec344294ecf9f1068213206bfdb8ec2d31586c13d2b74b7a188e6389fb06ed83f5b9eb72f37d3c1184dad4e2e9c84eba2bcd910ca4a34ec175eb8de2e9fb7eb52a0ccf91248a0ddfcbf266ca8117dd49acf7c24a0d708bce93cfd2ff2da2e3dae465859841a3777c8a26e469a5aadfeef788cd98588e4cf464bae81b80621e5c967e4184a51b7f2c36f6ed519d763e3462823cd67c78c0888912ab49e5c9ea415b57eb7e60355de6847c7efa283c31a68e42d0df833f8299adbba9997de51cfdba9fb9f07c7eeffdbbd29b5dc6ae406eb0540a20bdbafc5ec04a3e373cd72ee7c2625c601375d4b1762127ed53c6d2ceb79663d5a804c1822427fa659f3e1e47ae25c50d12f34626baab6155efd8bcf29ef5f4585b5ea7c3d19c8dda13da4fb573b9f08850a1b1a641b4c0dc91f44ae7923b65fccc8e45c58738c59a5448f6e5a608628595afe1f93c093327979473271adc5d5817ee5ab8853d200e1a7aabf864dc396a2a92a995659d5eb68e155767e81d0f04beecff6e08901a7141e084022517a1d55511f6a2f00606" +} \ No newline at end of file diff --git a/tests/blocks/zcash_testnet_304290.json b/tests/blocks/zcash_testnet_304290.json new file mode 100644 index 0000000..4a84b07 --- /dev/null +++ b/tests/blocks/zcash_testnet_304290.json @@ -0,0 +1,15 @@ +{ + "hash": "001156b74e55b2de497686814210359dccacc4fd062378eb9f2589192331f92b", + "size": 4003, + "height": 304290, + "merkleroot": "a5a00e24671c56e83c4c3ab3dce220190ba050eb337b0e9c65845b84c5809276", + "tx": [ + "0dc31cacd7fa3d79148e7182650efdaefac811f616b2b5ee3b8637d54fac98d5", + "bc3710f869faf00d8453b2960dd73d2c59d4e56def31ef24287af3c2527acba0" + ], + "time": 1539292375, + "nonce": "0000f309899c840746395e25bd7fd6f992ea9bd4de5426e657dcd76552aa0093", + "bits": "1f1ebb93", + "previousblockhash": "001dcc6713694e27d28354a105154156b1fc3e5b82ffe0f49b964828f1b37100", + "block": "040000000071b3f12848969bf4e0ff825b3efcb156411505a15483d2274e691367cc1d00769280c5845b84659c0e7b33eb50a00b1920e2dcb33a4c3ce8561c67240ea0a5b1ecc5e604c6f589b1fc11175cdaa14fd0299b6d13b1c0079e2ffd89b9a39647d7bcbf5b93bb1e1f9300aa5265d7dc57e62654ded49bea92f9d67fbd255e394607849c8909f30000fd4005005cd7cacf4d66f4aa19a4359d2ff896fd383a48152a991db271e3e771eec2d504f369c449bc2a9a0484105b224efa8a4ba12d5dc2ce0da840fa2a96531dbd356f8bdd29a581218f9445917368b0bed3023c23660460d8b6e790e77f220dd06f2666ef5992b332419824f83c60cc666e6b65df7679e43b8185b1080e901f0c1dedfcf55740fee61f147715cef392ed967e3ddd49c00f882062fd616a63a60cad4d0c69aff9766dc303b4a0a7171df1a593dd97b47e43e18ea3551a53ae05d4e1efbf4e8710c122808f970fc56cf28ff4840c18336ccebca601add1320942a2d7c43ac06edb16491fc07f73d54c2992b4a213e815736b0629f299254b166568de3659afb3745ad3b3b8b7e571865631ae5f1db385e5ffac4923bf0f596470cfbf6eb163f906da187215d244d3c8674d1c74267a469cb154eadca5163d0917113df1b7579d7b79141b7c397addedd8a2c2052be6e33e17bb05ab6041710fa90ec0d296af88850c98245b451254cfad9fa187ccdabf4dbbdd4f4b4616fc937f6c1be86d993e117ce0925104e2734a8e3137f45e16efe25907b841b3d57ad7cb78f6829d002307e64f7d50f542cbe38d91e81859233282a37d85e41e51e9dd61666bf1b74a4318bb2426db2fbdbc27dc097ab97d37829d6708f690e9596e1bc473b5d945ad244a7ef1f7122c8ac425b513a73fe5d95f891bbb3209becb92dde3d0ad39f6a8aab3486fcaa7bf199ff90ccaeb6cf40b9dbaae6ca82ef846308290761b1e4f0d8fef88c3d6f25d086a2671afe5ed169f97bf935c2da90ac0ec5f64ade38624899b7dd5d9d67c1d50b7107ddc89eddcd1ede23e9146011158315ed05782691d140dee182c77d381592b98c37fd7df11b03ca0c210814dd869045bb42dbd318629a153b4777e74d5201be544542a5a7aed3b4b436b61dc872142cf6eef25014992f0104f51f1645d008e462319fa440598607c195a315eb7a41e9d86e7a46c4cd6391db4b71b16df04303489024b530b8423e1af015ccb3ae3ff7da9a1243f079e341d0dbee9587395c3fd4a7949ecf83144090b823b28596eaf60ca84df00d5a0da0acd7b8b01613f6415f56eec7dd7258728724487a63f667e41612e008baee19652474a22ade42477255bc9265f05963e9d84f9b09c4266f97685b250e523adafa78efc5f03057282ff257f3d4851b4f5327b0926c3093c0adc0e7ad8bd175567dce4a3a50f11d0e05980c17371730ee27fe6a6d16234d488c52ea4dad729ae85f4d6dd1704fb5b79112520a8dac7c5075531d69205dbfe60193ec3841451c0c8f1f512fdb6fd4609a25d9828871ae58700a360c7c9d64897c20b6bb16210907988b21e2c3cecbe52b30caec0823a3e2d3872503b7d5c1820fb13ff8c963387319bb6689d743cf2c4e1be352f018826ff0d8d1abeb87ae431732c372d74de710df41ec574e363ec4645c4d95384b2fac96779a99c56e90adf412f0204f081cc30f20ad4f5efe338f77d7c7d10fc98f3b5bb678dde567135daa2e03d4bcf0e7a450adc12d4be5c79374e3654104aaac461835aecfdd82bdec4a8ceec593d62f7e6548abf849a55999c7e880db8787b6d7a5a33d849c4580c64a91937dcae6f6c1c373aee3ce2610f6341823e5d19f7a9a2d2ba252f019bbca2e812c0478e5de47b7b4c8f99edffffb1209ef6feba8371522b9c19aa4b5a5f0b1768bd5c611814610aedd3c620035cb505cb9bd07fbf0930bd6d3c37b7339aaa650237906737e348d5d5ce18a7bb8ebb03117b48dff61683f1532081e0a4d8be03f1f1ddc5249eedd3b4551a6d115e62848153020dd7d03a36a60e4b99198966b6ed753476bc2fd54e25e6e0df41472018fe9dc289c0ce689bf5f3614895f1f527b5d9c6020400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603a2a4040103ffffffff0210f19a3b000000001976a914a4f60943699e0939f0d5a6029c4e5d398eb5fdf888ac80b2e60e0000000017a91489169b066f07b60f31ca11628b7964313113687e87000000000000000000000000000000000000000400008085202f89000000000000b6a404001027000000000000012783c73a247606f857b41cc1bdaf4e74669c362b1e7c8fb0068f54ab54bf156cdcc0cb05ce91faf3412053254d13322e3d2065c39ba2ae6eb64896791561035418ba0523eef4bc2c04520f170ae5e6a875ccc389fa471393537f19ed13f531ff4306a367086cd90c67d0640ccaa8b4a32ca7743118105fa03f292d1f01e0ea8882e5cf6d139a6cbcac9ca888ef357bca8503d33199423b6f57a88cbc5dc3a226ba535fde1fa74615dbda11a26b36b724997d6922129926665754b846e187329624138e70d6c9c3a8001430194a6ae895c7443db9c3ab0e122db2c41ef27e1cae1165352f5a665e0e8cd08cd4d4eb18bdd39a848baf6d500eb65d4105cec2ea8e34d16b511d5066daf5d394622644a70a8202a62096f749c8884a7b7ddeda1c1c25b7f49ac187961cb6182f91aaedeab011fcc54e645652c88aa0e11963f2afc823c4851026d5410fa253025f2948e44e439ed4af3c34279b8e0fd1f86913f2d15347ba47d52e279a043f32e188c2242d7779d4ce7d072ef0e5da9a53d9ad44030268bdeb98a85e1a094aded6cfcf4e7d3dc2b9fd5acb278eb5459a506205a831cd5847eaaae3937699a2a9bb76e5abbbde0dbf404ffc1c30023271748b37d91c2d527e00667c591a8e7c362d563f6d3f27681d278b6ceb84eae510ca894daa0517f13638cc0cd1aff20c13ce8ee11b7add11319cccc63791cd9515c6499c32e466db89c7faed6e323688b5eac22d81c6033a4b972428546f6742f45ed5ff8d311c5c6a4c0608394140e048868ef9884f35a8bed165370b52d655340c10742ad00d951532ff8811e45a562cfbd81266322e37c497110ede4ad5716c832970dd2e56c84b2709573b7a8531bdf56b24c3a3be02c92696ae9382a94536c60767bd16574f57a1fb1c5ae7891d951dabab81e49f4b48719d925a4fd9f7c86ea42d02ff8ccbcfa7dadaf0d3973bd3f34aa3c701fd5240970c57a4cdf828d242be24cf2a66e7b1035973b8e960c6f47c1fb12a1c3b6d528791b242762c4490e9c1f10c31c676e4ed90d1c3cf33a0b3f25a62a2be13a80abe6d8e0f3a5461103e6978776d7d762e4e43205a0b10ab50793cbac5773fe95de575ae502d7633c33a424094a281c9b7a5c0362af2fefe61e56246f40270a748755379d7c3aa4de19b298bc58e8e4783ded7e242d78397e65b617e72089a13ca6bd7eb9817760dc6122974f4fe5f4862ced23b63e8d1f928253992f0a8c0ea2763ffd94c072a338af1ac7c4d1871fc01c9c43a6d730c2474525b2bc9ef2c680d6842a13bb13b46c4580a12739ce6fef4a93735efbeb0002cbd5c5bdf4bf0ecb9a5dbe82137a718408769a00c457286f601f6c6391b7e7ec0642fe59617e5ff344d8faf53833c2417beb2dfbdbf7c122ff7148358a060256ba349d2dcb6be6ca62e98d1ceefda45af5afdd8c7adf4e62d94aa1999593accf55374ef4fb0142a29b94fd3303e962466be26b2d6a8502faae9280706f85c07991b71543981c2097f1a3cefaac0fce519d88d8d974be0da1188f41db7d639ce167317cc42db7d031e5bf3211eefb5ef888594d3528676e0a156d61d228ae98dc165a2c15edbbbcde02ccd862eff9c24895a81f31f019f9df9b14a8030d877664f7566f90d96b7daccef283fe66d871ce2c8af9960ae6efbb933c499bcab1fd18b5dd1f0432493bf770459c6b8c7e0e0897ed35085cf438c96afd8b9544f8165f5e2b2f8aa785ba33de6160e4bb2c5b9caf50652147e037db45a8ecd623ab67cfd10c5390e69666747a9b285d8eaa87b3441abcc94fa5c9244389e8b26e20f283b7a9b8e3865704b689443d94eefe522fb6072e6031d8428cb13e11fe7432bc14ba446ba6954ada17a15c9c699a71c8a18c8eb8279601b2910994778de631680c3a883d947f3b0cce68d8e500d7a787b8d04dbcca231069c9db5600adb4b4c3960e2b98aeffbe666b3595038a4585d38701ff9d0737cf1eb91f2e90683de2f41d8235c042fb7b5438b6f6eed1218b8eb57237e10593d330d49d5fe693b17a87d7b01eda59dcdb6dd5a714f56528574405894193f3585690c4ec2124213cfdc37c70d92f3f58a250ae3309f7d3ba137902f6c99ac049b9ee641979656c27f5ce57357a5d30f17963207cda6b83ded6d1d3de4e228a6ac2ed5714900b8c4b797abe72cdf24e35ff85c0aa7b487e12e14850efc401dc5897e2ebe49c898ddd360678ce883ebbb155a7253bd0a7c57f5acce35610d7c929ea1d41ca8958b5e548451ff51468007112b1c65f72bd3933d4e1528090b0e842b677965f665db02511a8c7bf7f93f9853dd456c89661f945bc65b93b8752a546798d3b09040a93555d8a5c5cb7a63dc79e9f4e8479fea07ace9d0dc717874514b14a884906a6440513f7e26fe29f7143f1bfc2637ecde22d9fbc795febdb2a654325f625d595e4e0b629b1b640721181f1bfe1bf19be2513f4f8f29d3e943ff97c6b3c9bcdef16d37dfa188243baddc585d4f7490611b66665ec03f6de2e5e9ea62918722bd20902bd0a6a7da8bbe976be89ec925de50268ca22d9659eb4edb790b1529b90abfe77ff81e601652fa27a3ab6157ed26ec235faa5ad4ef349231af61faaf1fbde3dd19ff219b46f4ebbaa09eaddbe7eef170704a523495d93491f9694f14d50f417c403811a6d8ff8cc3a5716b5c4342c26bae4565de958e8d062dc62a753fe52d4ac3cf7b192b2a10353e04297a3e311b3b7e3e5ce3101481cc656d114c628bbb53f4a665537ba1e81df87845176f63c9726cc6239ce6950875927eb41529fbd9e0426dc702874d41674466e8ca1409df471d6de22553f169f80ad7e86770f86b5ce6a128f133227f58e714eedffcd18c890418539270594da17242d6df728d9759ece3a277e0f674c3299ca1556411e5cf143ce2c2bc2a665c8559db1b2631e0b178b693c777755dc150c09891da7109aa188364295f23f6fcafca60986658e17c675b642b5338851cc5947313c6911e44c5db87c46eb6e520e542b6b1c4d47ed7a41195dacecdaca3f6e0580621dc7874b0309dc70a34db1c61d37d5a0fb5cd68fbb009ed8b1b81f39ba366750a5e2a4438a9008166c541de4f8e27792533aeb2a7a2c4db86216c7d53c4c520eeb18e8673e1b0461bd169355dfef59eb28f883c86f982be501730f732399c4148d2aee30c217a5f75087265f64e8e5d098b64291b4c00395384ca762b1c63e3509b180efc2ae837c83feb213d72103bd80ea928270719f572d75173b18b9810e62ad76585e47181911dcd4f33b2cc37213de985d13401" +} \ No newline at end of file diff --git a/tests/blocks/zelcash_mainnet_100000.json b/tests/blocks/zelcash_mainnet_100000.json new file mode 100644 index 0000000..c2ca509 --- /dev/null +++ b/tests/blocks/zelcash_mainnet_100000.json @@ -0,0 +1,15 @@ +{ + "hash": "00000006521f5900d13e126636749f49c1c8f0b3d6df985ccdfea90f45610a06", + "size": 3598, + "height": 100000, + "merkleroot": "689c4a80dd0a3812e770f5a7bb21adcbb0069c742a480494ce8850eeccfb4986", + "tx": [ + "2a90896956c1a479a8f9eff304e236411fa0b5380469c3907802dbdff44a6272", + "719cc32c99c27e536104169810c2c245334353f98776e9c8c358a783d0b5a73f" + ], + "time": 1529272800, + "nonce": "0000000000000000000000008a36a23b54ffdb9e1482518181d39ca2d08a2da2", + "bits": "1d113a2e", + "previousblockhash": "0000000378c42a7e9adfecc053d34c2591ddd57489fa27712b429ff2a938d419", + "block": "0400000019d438a9f29f422b7127fa8974d5dd91254cd353c0ecdf9a7e2ac478030000008649fbccee5088ce9404482a749c06b0cbad21bba7f570e712380add804a9c680000000000000000000000000000000000000000000000000000000000000000e0d9265b2e3a111da22d8ad0a29cd381815182149edbff543ba2368a000000000000000000000000fd400500a5c56751961c076d71c2d7b5a4c15e3d55b7b45d1316ac0e9d0c8469debd15dc7858037e05ae1926f506c8031fe4919ac7baa25071b31246d43a323652e41cb96172a49ba716fd8d522baf39d5df083fdfe677106099cb21db2e994a2c84cb3c7d4f99c72118bd941b836ca6c98d04d9071fd2e2aad8b442458ebbb8da16346aead2206b1bd849f297906a54421d55f28a123a7d4da58a5f2da725c2140b5a24a6d967fe8f5d6a0799f73e525ee759b2a5a284ec5a9229b29d7bd16418b17c884a98c74f9d3634431d6597b9df351182f316a11bdb3d1eabaf908a4a41b178a0438f7f9f48c71f1efd26860a5d03029d53284dcb4555d077b5d56111c965dd1e186b8760b938d04469849761ec5c21804f16359b0bdc66ed80cfd890127e8d9aaaa0fc786f12ee7d90a797be25e02323e1d2feea72861e7c110d18217bd00df44e51e270122b6250dbd6eaa95db52900ca4588c2069155eaa6031b35530d8d0a035a14370b0575deb950b3f49693c198316eff998f6a4d21c511d3faabc2ecd5137edcaa8cf6e4fa16ae89d6b9d21a1feec7fec9a4d96f0ab3c5f773edeb3130bb12bc07d2407eec6ca783c8b731f6ce66850649323cd47423ef0bd7201d86d0ef15345cc76c34ededb9f696e5088d6c362c96e0df14d090efe37690b2a9fdfc3b9814312370778aa94368cc5209e99e78164e4c34b2b602bacc65a39ac4a1e52103a83fbc90131089d8fc4317913c47d021dd75537d92c2082265ce25a37639e806df12ac00d4d485c1a2e0ad6789cd02bc01367c943e4bbeae0f2268cd360774d2f17c473de7aa9adad0072fb1814647d2a3bfd0455e2a5449d5711dced199584a9aff6719e1b2dd8e0d109d7ae82bcfb8fec8444da6f36def595bc9be25a5d67f74a5fb4a283eac567837b4dac66c7019f18cea6a8ee1cc82d3f67cc02801a496af1343519b4a5ba36ea0ed292a08da37e04627069a4707134713d837736c4fa33bc5b702bb5a8402692106e806cdca84b8463311b75517ac7c5e93211aefa5a33fa2a2698828e94e5079ea66ae01bdab2a049ec9dbfa65194970825225645f3e1cd04b1ca34a215a9ea78511145e928be2e53cf5f7993d061d8b3106f12abd05cb00f3a6b3497f3ddc91f6c3c617df7a0fe8ac3d8ed28a4719998b5770f7332f812b1f17640776319a09dca815c7a3b2f074d50831785c98fe9310e7d92c26092624923a654f48fd4b7faf951dc38d0f2faaaa89afde3fcac9653279f1ef0d68cdf749372bfbc9f0bc100865e31c88813ff9e90a72fb37bbfc0ad94f4a0e7139fb9484f0e440da1ed92bd0d177e1191753dbf270a8c9ef0e04fe72bcaa42d3795f4da9101aa0b8df63494fa68ee19518a0277cdd753e4d7c1fddbe57a3655d372b2774a1d6cef2ce5a093caf6a02342570f9549d96cd78527ad7f90b1a24ced46d271c0a060b7c6404b99dff8314b570c02e7e62b6cf8131e375f897b0981fb8c7834e6651bb0aa367f7d6c146da37115f5c8ad8f80f04bc882dc02e0c91dbb808082b6c81c9ce52030f7fe5c8bf55f4a32d75fc36a00f118a3679e86c17a0c927db2ee71962e5625b4bff0cbc0e753c9e33754a905464afe2f32a665356448814709408ea921a07b28574968e2a4a3acfabdfb83e0507bf67cb0e500f2e1f04291e358b45b9f79602e11c1bbeb21589632c59bab3635dd66bea649b7530700592134b580be816c6e44d3cd6f9520fb3413eba911ba0244d961bd87de55cf237609a3789f35231b2600e92196a7cd22ed3d0737279ce4fb8a54c1157f0e13aaa9726b46897db589f954778c2216dd1ef37efb114e9814e6fed82cdcd8d8686bd4e5ed6e9cfd820574e1e3b8617d5bf932022d51efdf32899852ed7e6ec0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3003a0860100636f696e626c6f636b6572732e636f6d202d2068747470733a2f2f636f696e626c6f636b6572732e636f6dffffffff0280042175030000001976a91494366c530bdec75b6b4a6c647e902069f06cf6c188ac80d1f008000000001976a9142a1efd9d0d4c050df4c88822ed349bfe13fcaace88ac0000000002000000000160b62075030000001976a914c17d10001ecf9fcb20327d96869383217d2f226088ac0000000001000000000000000070dd20750300000078d5e6b10dc8f65fe4627954325df8e2f7af95845e40c4ff34c6d18a20e9db85c33a12a613c78aab75851c0deba2046d3ca0b0980ce4acb546e9c1bbb2c77f3024c853f1689045d3f989f72fda77a91e0c597dc8ad93222a91ffb27e9302b043904b367b917ba27956c819af4d7938e4cc9cdf0949f4705822ff6509ea31a69e676ab31c97c8383f35795a5f40944bc632d8fcb60f0d39f6436cba0463a9824cac60777f94ea3c096411e913c12c576afabd6bf5e9e988808c3347e6def20d1cb6c870ecf0eac01330f5f0430608437ea0b86f3b74d40b7ff8d98ef9ac0ba030dbeebf478de58c2f9805e5643f0fc095fd6578774ea655d1a49bf492aaba7d981441ad1ac73febac08bcab5c3183497afb2d3533c1ea0acde97491d118da0fff021e4a7399f4a95a2b12a3566de942935f6f3979e9dbbe7f6bdfa47aeb3a1db10902198cf90087a388c7757d4d5006040239e1cc3ea90e9d16d15563aef13d60a6700a07e801ca9b20ca83643cd4ec66f150757b76ae22a6016a09298a3d6975655cf9ddcd48650fb9e4d7a49679c57c076af409b5207a34a6f0a60304cd08e7e7eaff031ddb0e357c99439da7915db192bc43207e1dce037c1ed9f0756a0c52de5241060230333e3a4421495fef12a074c02db43393828a25579427dcf307b768faf09733022775b6cc390a84e06bf6a096d2d0055b76264059aca223b84a959da033470ce1030c863b7fca1edcf83d5ac8cf769903027991cd181fdfb2c2649534c37663e9ca030798fc266d3b9099657c49dcfcf7f23ea4661c3d44956a469c78a927a1bbebc24c3adad68d7c11b997acc57ed89eedc2666799282d0e7ac8e97ed1c57f20c28b19c9306ba78e202a860a37ef56ffca54898c73c2cd08ed6f289729a10844f1e250ac7b470cecac85ae778009461fbce9e384fdea5f0518f759947a3f60a24f725039b5bf3335c8bf82a22975e30686cf7a67eacb48957cbeca17883800c597e877f6995a91a944d4578c31813efcdb54c710cc2313717bcde01edd9d671e68591f4d827729ee9f3bc127ed8329a5f71c032b3644d68823078b26c8ecc1c034286dc4278402b45d791685663effa7bd1975d3b4da3c0fd31589c8340c0b7fb1d397cae2c1d33a7c973d2db585aa98b25c6c023a626462a85d5dd0d48f446471a8c3d2d0574c30b31ff38c647b2f34e62476aff26a543cac7ed37e3cc5a9e384a47ca2d75447d0483b91e34cca6d0bc9a8fdcb05b464a4def7069a989b4327b503d26c7c59f83584b726940b4210c5815c85c3de85051905b7c1cfc96e550b5dcaba68e27879b4b2bcef391d8e4decc6dbcf13b8d348c96502cd4d74778f2065b7341ae196d024a2075ea12c18769b0758acb47c87c24c463e27638e0ae146e624ee13eb0a9a292a05742242f3c5eebb4cc62b66aa2773ff1b87e4975052ffa51a6b4090ec71f38df2f0826fe9c303233a51961995ecd7ec45bbc120c65cbe5bb7a5cb6344f7d82d0f3568794b5b263a63b77eacf59bae8335acb3de563c65bed2645b6a0fada48d9aeb2945f25a6f4d757440f09af182dc583e3ef5e7e1048aafb270a776de19398e3ac9e0054965381e1da2b1dccdb53f8d61ac2a99f604a939e5961141d05fd9dfdb16213a2ba6c5b860d7348c67de0fecf842a980de3dbed5efa31146cf038fc7ad274c7093840ce5193eb8865b850caf6d564ffa6160f9e5ce188bb5e957e772da25a278c22b5680c9fb5bc52de0f425e2ea83bd397bf11475464e3acadcbc1b8504a94a4cbc731b6f3d10eaf9568c81c85749ad6fa2dbbd91a6016c52457ea2b8f6e5f7cb661b58e9faf3bd4240a094702db63c4c98e277524869fa31f91147aab17eaef8a16e63f1a78989917903c9cc54419d42f5f111e7abe55a1ea5ab3866216f68de55f4943ad01dd8911edbf1995f82f0b7c068dbc3d48a2bcccf5b19d45e8d7fbfaf4084f638a094bbd97d03a224577eb904396943f6f0e29f2db356de735e06b62e27c121a46c80280eca47d41a89e1aa1043856f99b9c41c7aee4707b12c573d8b690cdb7b3be2f1219fcbfa75f3d458bd51ac3107b681d16b91c08f2a19c917563d708b1c32ba65aa6c66e91fd7d659ba8e62ea877d334d7a4be2c6873c093e53974a05ff3b12608caa570e2c48b7dc97817cfa18492749fc2855c7ba75b20e3e20baef72424b83128c2902633848b5ad076f84aab5b4273844673b6ef48f8e6e340efd549cd46a33b3f2315d9f21fe80100fec6a24c61233692fd053412422e402a4c2254f056f5cb447a558fc06ea64a890df6384dd46723bd91bdd38ef3a3ab1de09e5482ca73020ea075e7bf97e5fe0dda9eb13953dea103289715bfb9d820497838accec2d53c0e225c4fce5f3c987e8e4c7333e4f5c882c5fe6dff3c4d7b7799f50a3da8472d9274e0ecce43049a8d0938e79410d790e84278858271407b3c9556087b3bf131d0cf3c78ab3570dc85e85ddbe7d51e976ffccd7d94928b3252c29b8fc14154b0042ec623861b7e3b373059742540945f74984cc425698e1e1b248080a49a4275816f6c9de5c31f6035135ca86ef69df53cd7b91a843eb891c3a8ae3f5535686e5144499d1b798b847cf14cafcc1fbaaf14951af986eac84f32ca10e" +} diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/lib/test_addresses.py b/tests/lib/test_addresses.py index 173f7f2..b1d6bea 100644 --- a/tests/lib/test_addresses.py +++ b/tests/lib/test_addresses.py @@ -67,6 +67,8 @@ addresses = [ "ab72728952c06dfc0f6cf21449dd645422731ec4", "eb3a3155215538d51de7cc"), (coins.TokenPay, "TDE2X28FGtckatxuP3d8s3V726G4TLNHpT", "23b5dd9b7b402388c7a40bc88c261f3178acf30d", "7c7bdf0e0713f3752f4b88"), + (coins.SmartCash, "SQFDM9NtRRmpHebq3H5RA3qpGJfGqp8Xgw", + "206168f5322583ff37f8e55665a4789ae8963532", "b8cb80b26e8932f5b12a7e"), ] diff --git a/tests/lib/test_tx_dash.py b/tests/lib/test_tx_dash.py new file mode 100644 index 0000000..0cf21dc --- /dev/null +++ b/tests/lib/test_tx_dash.py @@ -0,0 +1,464 @@ +import pytest + +import electrumx.lib.tx_dash as lib_tx_dash + + +bfh = bytes.fromhex + + +V2_TX = ( + '020000000192809f0b234cb850d71d020e678e93f074648ed0df5affd0c46d3bcb177f' + '9ccf020000008b483045022100c5403bcf86c3ae7b8fd4ca0d1e4df6729cc1af05ff95' + 'd9726b43a64b41dd5d9902207fab615f41871885aa3062fc7d8f8d9d3dcbc2e4867c5d' + '96dd7a176b99e927924141040baa4271a82c5f1a09a5ea63d763697ca0545b6049c4dd' + '8e8d099dd91f2da10eb11e829000a82047ac56969fb582433067a21c3171e569d1832c' + '34fdd793cfc8ffffffff030000000000000000226a20195ce612d20e5284eb78bb28c9' + 'c50d6139b10b77b2d5b2f94711b13162700472bfc53000000000001976a9144a519c63' + 'f985ba5ab8b71bb42f1ecb82a0a0d80788acf6984315000000001976a9148b80536aa3' + 'c460258cda834b86a46787c9a2b0bf88ac00000000') + + +CB_TX = ( + '0300050001000000000000000000000000000000000000000000000000000000000000' + '0000ffffffff1303c407040e2f5032506f6f6c2d74444153482fffffffff0448d6a73d' + '000000001976a914293859173a34194d445c2962b97383e2a93d7cb288ac22fc433e00' + '0000001976a914bf09c602c6b8f1db246aba5c37ad1cfdcb16b15e88ace9259c000000' + '00004341047559d13c3f81b1fadbd8dd03e4b5a1c73b05e2b980e00d467aa9440b29c7' + 'de23664dde6428d75cafed22ae4f0d302e26c5c5a5dd4d3e1b796d7281bdc9430f35ac' + '00000000000000002a6a28be61411c3c79b7fd45923118ba74d340afb248ae2edafe78' + 'c15e2d1aa337c942000000000000000000000000260100c407040076629a6e42fb5191' + '88f65889fd3ac0201be87aa227462b5643e8bb2ec1d7a82a') + + +PRO_REG_TX = ( + '030001000335f1c2ca44a1eb72e59f589df2852caacba39b7c0a5e61967f6b71d7a763' + '3153000000006b483045022100b2d457bbe855abc365a7db9c8014ea106fdb6dae6327' + '927fe81dfbdecf032b260220262e7e6c28899cd741db55c2e2ec35ed849cf99e78e36a' + '70c2ec3dac3c2ef60a012102500859b69a4cad6cfe4cf6b606be25b367c562b3be9a24' + 'b06d60c7047ee18fa2feffffff473ac70b52b2260aa0e4bec818c5a8c71d37a1b17430' + '75823c8e572ad71938b0000000006b483045022100fa4d57cdeb61f8ff1298fdc40256' + 'c68dfce320d44f584494c0a53233ddbe30a702206a50aaa245a6097d06c790fb1d7a37' + 'ced1622299c0aa93ebc018f1590d0eb15c012103f273126b24f755ab7e41311d03d545' + '590c162ea179421c5e18271c57de1a1635feffffff4de1afa0a321bc88c34978d4eeba' + '739256b86f8d8cdf47651b6f60e451f0a3de000000006a47304402202c4c5c48ac1d37' + '9f6da8143664072d6545d64691ce4738e026adf80c9afab24f022053804b4166a342da' + '38c538757680bebdc7785ce8c18a817fb3014fdaeec6d3bb0121028e99f6bc86489a43' + 'f953b2f0b046666efd7f7ad44da30f62ed5d32921556f8c5feffffff01c7430f000000' + '00001976a914c1de5f0587dc39112a28644904b0f3ed3298a6ed88ac00000000fd1201' + '0100000000004de1afa0a321bc88c34978d4eeba739256b86f8d8cdf47651b6f60e451' + 'f0a3de0100000000000000000000000000ffff12ca34aa752f2b3edeed6842db1f59cf' + '35de1ab5721094f049d000ab986c589053b3f3bd720724e75e18581afdca54bce80d14' + '750b1bcf9202158fe6c596ce8391815265747bd4a2009e2b3edeed6842db1f59cf35de' + '1ab5721094f049d000001976a9149bf5948b901a1e3e54e42c6e10496a17cd4067e088' + 'ac54d046585434668b4ee664c597864248b8a6aac33a7b2f4fcd1cc1b5da474a8a411f' + 'c1617ae83406c92a9132f14f9fff1487f2890f401e776fdddd639bc5055c456268cf74' + '97400d3196109c8cd31b94732caf6937d63de81d9a5be4db5beb83f9aa') + + +PRO_UP_SERV_TX = ( + '03000200010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000ce01003c6dca244f49f19d3f09889753ffff' + '1fec5bb8f9f5bd5bc09dabd999da21198f00000000000000000000ffff5fb735802711' + '1976a91421851058431a7d722e8e8dd9509e7f2b8e7042ec88acefcfe3d578914bb48c' + '6bd71b3459d384e4237446d521c9e2c6b6fcf019b5aafc99443fe14f644cfa47086e88' + '97cf7b546a67723d4a8ec5353a82f962a96ec3cea328343b647aace2897d6eddd0b8c8' + 'ee0f2e56f6733aed2e9f0006caafa6fc21c18a013c619d6e37af8d2f0985e3b769abc3' + '8ffa60e46c365a38d9fa0d44fd62') + + +PRO_UP_REG_TX = ( + '0300030001f8f9a27ca1c727fb971d45983c9a08a0bbd76753f8eb7913130c72d94218' + '8d32000000006a47304402205d530dc4e9e34b44fdf58f06fff0c225d80490be2861ad' + '7fe5fed7e62b48053b022052a78b5beaccc468b7fdb80e47090cb54c351aa9aa82fa7e' + '9b15b82d53b5f15a0121028106cde1660d2bfcc11231dfb1a05b60ded262d59e5e021a' + 'a3a814234013f4e9feffffff01c60c0000000000001976a91452a23d803da188cca952' + 'f9b7bc94c47c6fd1468a88ac00000000e40100aeb817f94b8e699b58130a53d2fbe98d' + '5519c2abe3b15e6f36c9abeb32e4dcce00001061eb559a64427ad239830742ef59591c' + 'dbbdffda7d3f5e7a2d95b9607ad80e389191e44c59ea5987b85e6d0e3eb527b9e198fa' + '7a745913c9278ec993d4472a95dac4251976a914eebbacffff3a55437803e0efb68a7d' + '591e0409d188ac0eb0067e6ccdd2acb96e7279113702218f3f0ab6f2287e14c11c5be6' + 'f2051d5a4120cb00124d838b02207097048cb668244cd79df825eb2d4d211fd2c4604c' + '18b30e1ae9bb654787144d16856676efff180889f05b5c9121a483b4ae3f0ea0ff3faf') + + +PRO_UP_REV_TX = ( + '030004000100366cd80169116da28e387413e8e3660a7aedd65002b320d0bd165eea8e' + 'ba52000000006a4730440220043a639f4554842f38253c75d066e70098ef02b141d5ff' + 'dea9fc408d307fce1202205d5d779f416fbc431847d19d83ae90c4036cf9925d3c4852' + 'cdd5df25d5843a48012102688d37c6d08a236d7952cdbc310dcb344ddae8b02e028720' + '1e79fd774509e8abfeffffff01570b0000000000001976a91490c5ce9d8bfefe3526d8' + '538cd0ed5e5d472c992a88ac00000000a40100b67ffbbd095de31ea38446754b6bf251' + '287936d2881d58b7c4efae0b54c75e9f0000eb073521b60306717f1d4feb3e9022f886' + 'b97bf981137684716a7d3d7e45b7fe83f4bb5530f7c5954e8b1ad50a74a9e1d65dcdcb' + 'e4acb8cbe3671abc7911e8c3954856c4da7e5fd242f2e4f5546f08d90849245bc593d1' + '605654e1a99cd0a79e9729799742c48d4920044666ad25a85fd093559c43e4900e634c' + '371b9b8d89ba') + + +SUB_TX_REGISTER = ( + '03000800010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000960100036162638e7042ec88acefcfe3d578' + '914bb48c6bd71b3459d384e42374e8abfeffffff01570b0000000000001976a91490c5' + 'ce9d8bc992a88ac00000000a40100b67ffbbd095de31ea38446754e8abfeffffff0157' + '0b0000000000001976a91490c5ce9d8bc992a88ac00000000a40100b67ffbbd095de31' + 'ea38446754e8abfeffffff01570b0000000000001976a91490c5ce9d') + + +SUB_TX_TOPUP = ( + '03000900010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000220100d384e42374e8abfeffffff01570b00' + '0000a40100b67ffbbd095de31ea3844675') + + +SUB_TX_RESET_KEY = ( + '03000a00010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000da0100d384e42374e8abfeffffff01570b00' + '0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b' + 'c6e8e0e358f3fb7bdbe9a667b3d0e803000000000000601210293360bf2a2e81067341' + '2bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e810673' + '412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e8106' + '73412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e81' + '0673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761cabcdefab') + + +SUB_TX_CLOSE_ACCOUNT = ( + '03000b00010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000aa0100d384e42374e8abfeffffff01570b00' + '0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b' + 'c6e8e0e358f3fb7bdbe9a12bc6e8e803000000000000a62bc6e8e0e358f3fb7bdbe9a6' + '67b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9' + 'a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdb' + 'e9a667b3d0103f761cabcdefab') + + +UNKNOWN_SPEC_TX = ( + '0300bb00010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000aa0100d384e42374e8abfeffffff01570b00' + '0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b' + 'c6e8e0e358f3fb7bdbe9a12bc6e8e0e358f3fb7bdbe9a62bc6e8e0e358f3fb7bdbe9a6' + '67b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9' + 'a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdb' + 'e9a667b3d0103f761cabcdefab') + + +WRONG_SPEC_TX = ( # Tx version < 3 + '0200bb00010931c6b0ad7ce07f3c8aefeeb78e246a4fe6872bbf08ab6e4eb6a7b69acd' + '64a6010000006b483045022100a2feb698c43c752738fabea281b7e9e5a3aa648a4c54' + '1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231' + '74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b' + '3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217' + '4d22769c3a4f90b2dcd0de88ac00000000') + + +def test_dash_v2_tx(): + test = bfh(V2_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 2 + assert tx.tx_type == 0 + assert tx.extra_payload == b'' + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_cb_tx(): + test = bfh(CB_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 5 + extra = tx.extra_payload + assert extra.version == 1 + assert extra.height == 264132 + assert len(extra.merkleRootMNList) == 32 + assert extra.merkleRootMNList == bfh( + '76629a6e42fb519188f65889fd3ac0201be87aa227462b5643e8bb2ec1d7a82a') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_pro_reg_tx(): + test = bfh(PRO_REG_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 1 + extra = tx.extra_payload + assert extra.version == 1 + assert extra.type == 0 + assert extra.mode == 0 + assert len(extra.collateralOutpoint.hash) == 32 + assert extra.collateralOutpoint.hash == bfh( + '4de1afa0a321bc88c34978d4eeba739256b86f8d8cdf47651b6f60e451f0a3de') + assert extra.collateralOutpoint.index == 1 + assert len(extra.ipAddress) == 16 + assert extra.ipAddress == bfh('00000000000000000000ffff12ca34aa') + assert extra.port == 12149 + assert len(extra.KeyIdOwner) == 20 + assert extra.KeyIdOwner == bfh( + '2b3edeed6842db1f59cf35de1ab5721094f049d0') + assert len(extra.PubKeyOperator) == 48 + assert extra.PubKeyOperator == bfh( + '00ab986c589053b3f3bd720724e75e18581afdca54bce80d14750b1bcf920215' + '8fe6c596ce8391815265747bd4a2009e') + assert len(extra.KeyIdVoting) == 20 + assert extra.KeyIdVoting == bfh( + '2b3edeed6842db1f59cf35de1ab5721094f049d0') + assert extra.operatorReward == 0 + assert extra.scriptPayout == bfh( + '76a9149bf5948b901a1e3e54e42c6e10496a17cd4067e088ac') + assert len(extra.inputsHash) == 32 + assert extra.inputsHash == bfh( + '54d046585434668b4ee664c597864248b8a6aac33a7b2f4fcd1cc1b5da474a8a') + assert extra.payloadSig == bfh( + '1fc1617ae83406c92a9132f14f9fff1487f2890f401e776fdddd639bc505' + '5c456268cf7497400d3196109c8cd31b94732caf6937d63de81d9a5be4db' + '5beb83f9aa') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_pro_up_serv_tx(): + test = bfh(PRO_UP_SERV_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 2 + extra = tx.extra_payload + assert extra.version == 1 + assert len(extra.proTxHash) == 32 + assert extra.proTxHash == bfh( + '3c6dca244f49f19d3f09889753ffff1fec5bb8f9f5bd5bc09dabd999da21198f') + assert len(extra.ipAddress) == 16 + assert extra.ipAddress == bfh('00000000000000000000ffff5fb73580') + assert extra.port == 4391 + assert extra.scriptOperatorPayout == bfh( + '76a91421851058431a7d722e8e8dd9509e7f2b8e7042ec88ac') + assert len(extra.inputsHash) == 32 + assert extra.inputsHash == bfh( + 'efcfe3d578914bb48c6bd71b3459d384e4237446d521c9e2c6' + 'b6fcf019b5aafc') + assert len(extra.payloadSig) == 96 + assert extra.payloadSig == bfh( + '99443fe14f644cfa47086e8897cf7b546a67723d4a8ec5353a82f962a96e' + 'c3cea328343b647aace2897d6eddd0b8c8ee0f2e56f6733aed2e9f0006ca' + 'afa6fc21c18a013c619d6e37af8d2f0985e3b769abc38ffa60e46c365a38' + 'd9fa0d44fd62') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_pro_up_reg_tx(): + test = bfh(PRO_UP_REG_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 3 + extra = tx.extra_payload + assert extra.version == 1 + assert len(extra.proTxHash) == 32 + assert extra.proTxHash == bfh( + 'aeb817f94b8e699b58130a53d2fbe98d5519c2abe3b15e6f36c9abeb32e4dcce') + assert extra.mode == 0 + assert len(extra.PubKeyOperator) == 48 + assert extra.PubKeyOperator == bfh( + '1061eb559a64427ad239830742ef59591cdbbdffda7d3f5e7a2d95b9607a' + 'd80e389191e44c59ea5987b85e6d0e3eb527') + assert len(extra.KeyIdVoting) == 20 + assert extra.KeyIdVoting == bfh( + 'b9e198fa7a745913c9278ec993d4472a95dac425') + assert extra.scriptPayout == bfh( + '76a914eebbacffff3a55437803e0efb68a7d591e0409d188ac') + assert len(extra.inputsHash) == 32 + assert extra.inputsHash == bfh( + '0eb0067e6ccdd2acb96e7279113702218f3f0ab6f2287e14c11c5be6f2051d5a') + assert extra.payloadSig == bfh( + '20cb00124d838b02207097048cb668244cd79df825eb2d4d211fd2c4604c1' + '8b30e1ae9bb654787144d16856676efff180889f05b5c9121a483b4ae3f0e' + 'a0ff3faf') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_pro_up_rev_tx(): + test = bfh(PRO_UP_REV_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 4 + extra = tx.extra_payload + assert extra.version == 1 + assert len(extra.proTxHash) == 32 + assert extra.proTxHash == bfh( + 'b67ffbbd095de31ea38446754b6bf251287936d2881d58b7c4efae0b54c75e9f') + assert extra.reason == 0 + assert len(extra.inputsHash) == 32 + assert extra.inputsHash == bfh( + 'eb073521b60306717f1d4feb3e9022f886b97bf981137684716a7d3d7e45b7fe') + assert len(extra.payloadSig) == 96 + assert extra.payloadSig == bfh( + '83f4bb5530f7c5954e8b1ad50a74a9e1d65dcdcbe4acb8cbe3671abc7911' + 'e8c3954856c4da7e5fd242f2e4f5546f08d90849245bc593d1605654e1a9' + '9cd0a79e9729799742c48d4920044666ad25a85fd093559c43e4900e634c' + '371b9b8d89ba') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_sub_tx_register_tx(): + test = bfh(SUB_TX_REGISTER) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 8 + extra = tx.extra_payload + assert extra.version == 1 + assert extra.userName == b'abc' + assert len(extra.pubKey) == 48 + assert extra.pubKey == bfh( + '8e7042ec88acefcfe3d578914bb48c6bd71b3459d384e42374e8abfeffff' + 'ff01570b0000000000001976a91490c5ce9d') + assert len(extra.payloadSig) == 96 + assert extra.payloadSig == bfh( + '8bc992a88ac00000000a40100b67ffbbd095de31ea38446754e8abfeffff' + 'ff01570b0000000000001976a91490c5ce9d8bc992a88ac00000000a4010' + '0b67ffbbd095de31ea38446754e8abfeffffff01570b0000000000001976' + 'a91490c5ce9d') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_sub_tx_topup_tx(): + test = bfh(SUB_TX_TOPUP) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 9 + extra = tx.extra_payload + assert extra.version == 1 + assert len(extra.regTxHash) == 32 + assert extra.regTxHash == bfh( + 'd384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31ea3844675') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_sub_tx_reset_key_tx(): + test = bfh(SUB_TX_RESET_KEY) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 10 + extra = tx.extra_payload + assert extra.version == 1 + assert len(extra.regTxHash) == 32 + assert extra.regTxHash == bfh( + 'd384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31ea3844675') + assert len(extra.hashPrevSubTx) == 32 + assert extra.hashPrevSubTx == bfh( + 'af3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0') + assert extra.creditFee == 1000 + assert len(extra.newPubKey) == 48 + assert extra.newPubKey == bfh( + '601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f7' + '61caf3e98e9601210293360bf2a2e810673') + assert len(extra.payloadSig) == 96 + assert extra.payloadSig == bfh( + '412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360b' + 'f2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e960' + '1210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761' + 'cabcdefab') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_sub_tx_close_account_tx(): + test = bfh(SUB_TX_CLOSE_ACCOUNT) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 11 + extra = tx.extra_payload + assert extra.version == 1 + assert len(extra.regTxHash) == 32 + assert extra.regTxHash == bfh( + 'd384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31ea3844675') + assert len(extra.hashPrevSubTx) == 32 + assert extra.hashPrevSubTx == bfh( + 'af3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a12bc6e8') + assert extra.creditFee == 1000 + assert len(extra.payloadSig) == 96 + assert extra.payloadSig == bfh( + 'a62bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360b' + 'f2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e960' + '1210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761' + 'cabcdefab') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_unknown_spec_tx(): + test = bfh(UNKNOWN_SPEC_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 3 + assert tx.tx_type == 187 + extra = tx.extra_payload + assert extra == bfh( + '0100d384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31e' + 'a3844675af3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7b' + 'dbe9a12bc6e8e0e358f3fb7bdbe9a62bc6e8e0e358f3fb7bdbe9a667b3d0' + '103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7b' + 'dbe9a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8' + 'e0e358f3fb7bdbe9a667b3d0103f761cabcdefab') + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_wrong_spec_tx(): + test = bfh(WRONG_SPEC_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.version == 12255234 + assert tx.tx_type == 0 + extra = tx.extra_payload + assert extra == b'' + ser = tx.serialize() + assert ser == test + + +def test_dash_tx_serialize_wrong_tx_type(): + test = bfh(CB_TX) + deser = lib_tx_dash.DeserializerDash(test) + tx = deser.read_tx() + assert tx.tx_type == 5 + tx = tx._replace(tx_type=4) + assert tx.tx_type == 4 + with pytest.raises(ValueError) as excinfo: + ser = tx.serialize() + assert ('Dash tx_type does not conform' + ' with extra payload class' in str(excinfo.value)) diff --git a/tests/server/test_compaction.py b/tests/server/test_compaction.py index 44017f1..a831226 100644 --- a/tests/server/test_compaction.py +++ b/tests/server/test_compaction.py @@ -113,7 +113,7 @@ async def run_test(db_dir): environ.clear() environ['DB_DIRECTORY'] = db_dir environ['DAEMON_URL'] = '' - environ['COIN'] = 'BitcoinCash' + environ['COIN'] = 'BitcoinSV' db = DB(Env()) await db.open_for_serving() history = db.history diff --git a/tests/server/test_daemon.py b/tests/server/test_daemon.py index 712e02a..20b5d89 100644 --- a/tests/server/test_daemon.py +++ b/tests/server/test_daemon.py @@ -487,6 +487,6 @@ async def test_failover(daemon, caplog): with ClientSessionFailover(('getblockcount', [], height)): await daemon.height() == height - assert in_caplog(caplog, "disconnected", 3) + assert in_caplog(caplog, "disconnected", 1) assert in_caplog(caplog, "failing over") assert in_caplog(caplog, "connection restored") diff --git a/tests/server/test_env.py b/tests/server/test_env.py index 3dcec3c..fbc8f45 100644 --- a/tests/server/test_env.py +++ b/tests/server/test_env.py @@ -16,7 +16,7 @@ BASE_DB_DIR = '/some/dir' base_environ = { 'DB_DIRECTORY': BASE_DB_DIR, 'DAEMON_URL': BASE_DAEMON_URL, - 'COIN': 'BitcoinCash', + 'COIN': 'BitcoinSV', } @@ -88,13 +88,13 @@ def test_COIN_NET(): '''Test COIN and NET defaults and redirection.''' setup_base_env() e = Env() - assert e.coin == lib_coins.BitcoinCash + assert e.coin == lib_coins.BitcoinSV os.environ['NET'] = 'testnet' e = Env() - assert e.coin == lib_coins.BitcoinCashTestnet + assert e.coin == lib_coins.BitcoinSVTestnet os.environ['NET'] = ' testnet ' e = Env() - assert e.coin == lib_coins.BitcoinCashTestnet + assert e.coin == lib_coins.BitcoinSVTestnet os.environ.pop('NET') os.environ['COIN'] = ' Litecoin ' e = Env() @@ -169,7 +169,7 @@ def test_RPC_HOST(): def test_REORG_LIMIT(): assert_integer('REORG_LIMIT', 'reorg_limit', - lib_coins.BitcoinCash.REORG_LIMIT) + lib_coins.BitcoinSV.REORG_LIMIT) def test_TCP_PORT(): @@ -416,5 +416,5 @@ def test_ban_versions(): def test_coin_class_provided(): - e = Env(lib_coins.BitcoinCash) - assert e.coin == lib_coins.BitcoinCash + e = Env(lib_coins.BitcoinSV) + assert e.coin == lib_coins.BitcoinSV diff --git a/tests/server/test_notifications.py b/tests/server/test_notifications.py new file mode 100644 index 0000000..af559a4 --- /dev/null +++ b/tests/server/test_notifications.py @@ -0,0 +1,47 @@ +import asyncio + +import pytest + +from electrumx.server.controller import Notifications + + +@pytest.mark.asyncio +async def test_simple_mempool(): + n = Notifications() + notified = [] + async def notify(height, touched): + notified.append((height, touched)) + await n.start(5, notify) + + mtouched = {'a', 'b'} + btouched = {'b', 'c'} + await n.on_mempool(mtouched, 6) + assert notified == [(5, set())] + await n.on_block(btouched, 6) + assert notified == [(5, set()), (6, set.union(mtouched, btouched))] + + +@pytest.mark.asyncio +async def test_enter_mempool_quick_blocks_2(): + n = Notifications() + notified = [] + async def notify(height, touched): + notified.append((height, touched)) + await n.start(5, notify) + + # Suppose a gets in block 6 and blocks 7,8 found right after and + # the block processer processes them together. + await n.on_mempool({'a'}, 5) + assert notified == [(5, set()), (5, {'a'})] + # Mempool refreshes with daemon on block 6 + await n.on_mempool({'a'}, 6) + assert notified == [(5, set()), (5, {'a'})] + # Blocks 6, 7 processed together + await n.on_block({'a', 'b'}, 7) + assert notified == [(5, set()), (5, {'a'})] + # Then block 8 processed + await n.on_block({'c'}, 8) + assert notified == [(5, set()), (5, {'a'})] + # Now mempool refreshes + await n.on_mempool(set(), 8) + assert notified == [(5, set()), (5, {'a'}), (8, {'a', 'b', 'c'})] diff --git a/tests/test_transactions.py b/tests/test_transactions.py index d91a65c..731012d 100644 --- a/tests/test_transactions.py +++ b/tests/test_transactions.py @@ -11,8 +11,9 @@ from binascii import unhexlify import pytest -from electrumx.lib.coins import Coin +from electrumx.lib.coins import Coin, Namecoin from electrumx.lib.hash import hash_to_hex_str +from electrumx.lib.script import OpCodes, Script TRANSACTION_DIR = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'transactions') @@ -57,3 +58,16 @@ def test_transaction(transaction_details): assert spk['hex'] == tx_pks.hex() assert coin.address_to_hashX(spk['address']) == \ coin.hashX_from_script(tx_pks) + if issubclass(coin, Namecoin): + if "nameOp" not in spk or "name" not in spk["nameOp"]: + assert coin.name_hashX_from_script(tx_pks) is None + else: + OP_NAME_UPDATE = OpCodes.OP_3 + normalized_name_op_script = bytearray() + normalized_name_op_script.append(OP_NAME_UPDATE) + normalized_name_op_script.extend(Script.push_data(spk["nameOp"]["name"].encode("ascii"))) + 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) + assert coin.name_hashX_from_script(tx_pks) == Coin.hashX_from_script(normalized_name_op_script) diff --git a/tests/transactions/namecoin_mainnet_037339.json b/tests/transactions/namecoin_mainnet_037339.json new file mode 100644 index 0000000..467039e --- /dev/null +++ b/tests/transactions/namecoin_mainnet_037339.json @@ -0,0 +1,62 @@ +{ + "txid": "037339b97cf38d0fd8d68046c0ce7661a3d0117fac1da802c1d4c13056a74096", + "hash": "037339b97cf38d0fd8d68046c0ce7661a3d0117fac1da802c1d4c13056a74096", + "version": 28928, + "size": 568, + "vsize": 568, + "locktime": 411806, + "vin": [ + { + "txid": "4e6adc779e9d6d359c131a6c162fda9ab6822c829ed85e6461eca09a7f2da860", + "vout": 0, + "scriptSig": { + "asm": "30450221009934d4cef1c24141e5d74d825f1d50cc199bd9daf76e15024ff6119bc86fb8da02200d648a0c0dff5b4d091fdd8562a2f4a4cde243d460708565c1c96b2a3c1db786[ALL] 02beb88ae836bc254ef277e0911c8affe248d1e6a893bba6ce7da6cd9aee6079e4", + "hex": "4830450221009934d4cef1c24141e5d74d825f1d50cc199bd9daf76e15024ff6119bc86fb8da02200d648a0c0dff5b4d091fdd8562a2f4a4cde243d460708565c1c96b2a3c1db786012102beb88ae836bc254ef277e0911c8affe248d1e6a893bba6ce7da6cd9aee6079e4" + }, + "sequence": 4294967294 + }, + { + "txid": "d269af00988e45ed9a5fe085884b8f729afac4a5ccaaf8e1ee601439e7bcc125", + "vout": 1, + "scriptSig": { + "asm": "3045022100d2c96c88ceff7653e741c40e011d0253a7426f29af68097f6c0af45878f83bc8022008908f2a63ab0230caec18443c034478ce32367fcdcf810998293f6bb6808225[ALL] 02d514d8b84fe28a4f5b998fb15d931456dd98365df9576dbcc47f787412eec1a6", + "hex": "483045022100d2c96c88ceff7653e741c40e011d0253a7426f29af68097f6c0af45878f83bc8022008908f2a63ab0230caec18443c034478ce32367fcdcf810998293f6bb6808225012102d514d8b84fe28a4f5b998fb15d931456dd98365df9576dbcc47f787412eec1a6" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 1477675940, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 224538b431f8deb3fddccc433ebc1327017634e7 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914224538b431f8deb3fddccc433ebc1327017634e788ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "Myha6mFMZV7u9Yvj6X43cidZocas5Xhq3E" + } + }, + { + "value": 1000000, + "n": 1, + "scriptPubKey": { + "nameOp": { + "op": "name_update", + "name": "dd/domob", + "value": "{\"ip\":\"176.31.184.255\",\"map\":{\"*\":{\"ip\":\"176.31.184.255\",\"tor\":\"wivfwn64tm3uaeig.onion\"}},\"fingerprint\":[\"6969C8037D2318BEDBC8111474B0A6E66E73BDB9\"],\"tor\":\"wivfwn64tm3uaeig.onion\"}" + }, + "asm": "OP_NAME_UPDATE 64642f646f6d6f62 7b226970223a223137362e33312e3138342e323535222c226d6170223a7b222a223a7b226970223a223137362e33312e3138342e323535222c22746f72223a2277697666776e3634746d3375616569672e6f6e696f6e227d7d2c2266696e6765727072696e74223a5b2236393639433830333744323331384245444243383131313437344230413645363645373342444239225d2c22746f72223a2277697666776e3634746d3375616569672e6f6e696f6e227d OP_2DROP OP_DROP OP_DUP OP_HASH160 57fd3c4a6a417c17f8d902e90e2bfb97b1a12e11 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "530864642f646f6d6f624cb47b226970223a223137362e33312e3138342e323535222c226d6170223a7b222a223a7b226970223a223137362e33312e3138342e323535222c22746f72223a2277697666776e3634746d3375616569672e6f6e696f6e227d7d2c2266696e6765727072696e74223a5b2236393639433830333744323331384245444243383131313437344230413645363645373342444239225d2c22746f72223a2277697666776e3634746d3375616569672e6f6e696f6e227d6d7576a91457fd3c4a6a417c17f8d902e90e2bfb97b1a12e1188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "N4bcMSxUL7jNDAJa34DpkdZPp9faHRJeaP" + } + } + ], + "hex": "007100000260a82d7f9aa0ec61645ed89e822c82b69ada2f166c1a139c356d9d9e77dc6a4e000000006b4830450221009934d4cef1c24141e5d74d825f1d50cc199bd9daf76e15024ff6119bc86fb8da02200d648a0c0dff5b4d091fdd8562a2f4a4cde243d460708565c1c96b2a3c1db786012102beb88ae836bc254ef277e0911c8affe248d1e6a893bba6ce7da6cd9aee6079e4feffffff25c1bce7391460eee1f8aacca5c4fa9a728f4b8885e05f9aed458e9800af69d2010000006b483045022100d2c96c88ceff7653e741c40e011d0253a7426f29af68097f6c0af45878f83bc8022008908f2a63ab0230caec18443c034478ce32367fcdcf810998293f6bb6808225012102d514d8b84fe28a4f5b998fb15d931456dd98365df9576dbcc47f787412eec1a6feffffff02a48b1358000000001976a914224538b431f8deb3fddccc433ebc1327017634e788ac40420f0000000000db530864642f646f6d6f624cb47b226970223a223137362e33312e3138342e323535222c226d6170223a7b222a223a7b226970223a223137362e33312e3138342e323535222c22746f72223a2277697666776e3634746d3375616569672e6f6e696f6e227d7d2c2266696e6765727072696e74223a5b2236393639433830333744323331384245444243383131313437344230413645363645373342444239225d2c22746f72223a2277697666776e3634746d3375616569672e6f6e696f6e227d6d7576a91457fd3c4a6a417c17f8d902e90e2bfb97b1a12e1188ac9e480600", + "blockhash": "1453f1744573abc329a116d071f9041bea5639f51c6e9bb2463fcb21f0638d2c", + "confirmations": 10342, + "time": 1533902501, + "blocktime": 1533902501 +} diff --git a/tests/transactions/namecoin_mainnet_0c6867.json b/tests/transactions/namecoin_mainnet_0c6867.json new file mode 100644 index 0000000..6c7b912 --- /dev/null +++ b/tests/transactions/namecoin_mainnet_0c6867.json @@ -0,0 +1,52 @@ +{ + "txid": "0c686779a1dcc867039a3c71934d6cde487c4eabd9cd2efd0bdcf15262ed9886", + "hash": "0c686779a1dcc867039a3c71934d6cde487c4eabd9cd2efd0bdcf15262ed9886", + "version": 28928, + "size": 280, + "vsize": 280, + "locktime": 421976, + "vin": [ + { + "txid": "0b9468e87947debbf999ac9290fcd25af7eff5f4d6df4773be2a89fd31009078", + "vout": 1, + "scriptSig": { + "asm": "304402203b3d10f8ba91fb477fdcbeb0354016bce97fcdf7d050191c7958a7d174ae4e76022064bd96fb14fcfc535320dd9eafd9a6c6dd9410937afa4fdb1064e2d8cc1110fa[ALL] 0421c34686d12da7331dcf876a61b58cdfa9bb892120fa8e699daac1333ad7325ed09a37432a414ccc2bed6506b3badd0413cd35469dcfda23ebadca86929f59c1", + "hex": "47304402203b3d10f8ba91fb477fdcbeb0354016bce97fcdf7d050191c7958a7d174ae4e76022064bd96fb14fcfc535320dd9eafd9a6c6dd9410937afa4fdb1064e2d8cc1110fa01410421c34686d12da7331dcf876a61b58cdfa9bb892120fa8e699daac1333ad7325ed09a37432a414ccc2bed6506b3badd0413cd35469dcfda23ebadca86929f59c1" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 280480622, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 b7db2908b47c32f4b8864caf2522d2eb1ed3d50b OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914b7db2908b47c32f4b8864caf2522d2eb1ed3d50b88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "NDLWQGyHyhneB7ySsL6na2QBPK1T2i1WSQ" + } + }, + { + "value": 1000000, + "n": 1, + "scriptPubKey": { + "nameOp": { + "op": "name_new", + "hash": "2dbe200657c5c3cce22f0637480865d5db3aaaac" + }, + "asm": "OP_NAME_NEW 2dbe200657c5c3cce22f0637480865d5db3aaaac OP_2DROP OP_DUP OP_HASH160 6985a7f580409d4fdaf223f34848212955d371eb OP_EQUALVERIFY OP_CHECKSIG", + "hex": "51142dbe200657c5c3cce22f0637480865d5db3aaaac6d76a9146985a7f580409d4fdaf223f34848212955d371eb88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "N6CKGNr6iBDriS6iwZBAFswM2auAQnjd5K" + } + } + ], + "hex": "007100000178900031fd892abe7347dfd6f4f5eff75ad2fc9092ac99f9bbde4779e868940b010000008a47304402203b3d10f8ba91fb477fdcbeb0354016bce97fcdf7d050191c7958a7d174ae4e76022064bd96fb14fcfc535320dd9eafd9a6c6dd9410937afa4fdb1064e2d8cc1110fa01410421c34686d12da7331dcf876a61b58cdfa9bb892120fa8e699daac1333ad7325ed09a37432a414ccc2bed6506b3badd0413cd35469dcfda23ebadca86929f59c1feffffff026ecbb710000000001976a914b7db2908b47c32f4b8864caf2522d2eb1ed3d50b88ac40420f00000000003051142dbe200657c5c3cce22f0637480865d5db3aaaac6d76a9146985a7f580409d4fdaf223f34848212955d371eb88ac58700600", + "blockhash": "15b3979258287d26becc021b265bcccc964b9863d44a8a5802b9f6ce53d9509d", + "confirmations": 170, + "time": 1539845549, + "blocktime": 1539845549 +} diff --git a/tests/transactions/namecoin_mainnet_460f2b.json b/tests/transactions/namecoin_mainnet_460f2b.json new file mode 100644 index 0000000..e22d578 --- /dev/null +++ b/tests/transactions/namecoin_mainnet_460f2b.json @@ -0,0 +1,58 @@ +{ + "txid": "460f2b0a6f480b0d16b99fd4ea55afbf7ee628365a2a32d54b56422163e7660b", + "hash": "460f2b0a6f480b0d16b99fd4ea55afbf7ee628365a2a32d54b56422163e7660b", + "version": 28928, + "size": 688, + "vsize": 688, + "locktime": 422150, + "vin": [ + { + "txid": "33991d6cc33c2f9d85484086d0e9dcb93717be11e89bb315c5f0233d0fc0fc01", + "vout": 1, + "scriptSig": { + "asm": "3045022100c26ad0e826c1759a02a4bb3a8f816841b6330b44d3bba5ace371af7aeb736cae02205e6e9927d5e8279d32e741fbcd567c08f6dda8bdd0e3597c85b85831c3a73090[ALL] 03a7c03fa10f4ffa393a2e90ba098bf1f9b5d0cf84f83bc006fc9902884f22a5b5", + "hex": "483045022100c26ad0e826c1759a02a4bb3a8f816841b6330b44d3bba5ace371af7aeb736cae02205e6e9927d5e8279d32e741fbcd567c08f6dda8bdd0e3597c85b85831c3a73090012103a7c03fa10f4ffa393a2e90ba098bf1f9b5d0cf84f83bc006fc9902884f22a5b5" + }, + "sequence": 4294967293 + }, + { + "txid": "4632320203dddc75cac6e0078a040b6601de73b95d0069c8ef37f34e085f883c", + "vout": 0, + "scriptSig": { + "asm": "304402205bf9d8fe538d18d2f589f818acfc66efb3d7c563a6d0ce94379761e3ad5de4bb02204841c4f51cdb4433991f73fcff41fc82afd0a4411a89b09de30e6fb603ddf5a1[ALL] 0284741f8ca6ab581a46ae0ba5edfbfd134378c41e576c9267ca99054ecdf121cb", + "hex": "47304402205bf9d8fe538d18d2f589f818acfc66efb3d7c563a6d0ce94379761e3ad5de4bb02204841c4f51cdb4433991f73fcff41fc82afd0a4411a89b09de30e6fb603ddf5a101210284741f8ca6ab581a46ae0ba5edfbfd134378c41e576c9267ca99054ecdf121cb" + }, + "sequence": 4294967293 + } + ], + "vout": [ + { + "value": 1000000, + "n": 0, + "scriptPubKey": { + "nameOp": { + "op": "name_update", + "name": "test/6", + "value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + "asm": "OP_NAME_UPDATE 746573742f36 787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 OP_2DROP OP_DROP OP_DUP OP_HASH160 734b00d1b31f3c3a89bcd6d302b820d4c0459fc1 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "5306746573742f364d2c017878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878786d7576a914734b00d1b31f3c3a89bcd6d302b820d4c0459fc188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "N75ym2CibThuKTtR4eRRZAMvkcLybL77fS" + } + }, + { + "value": 354398, + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 3b9cde2101e9da0fbf47d98ed859b0ad8fa886b5 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9143b9cde2101e9da0fbf47d98ed859b0ad8fa886b588ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "N21ZzKiuLLQ5pZnoJrqaSNZSbipQUtAaGt" + } + } + ], + "hex": "007100000201fcc00f3d23f0c515b39be811be1737b9dce9d0864048859d2f3cc36c1d9933010000006b483045022100c26ad0e826c1759a02a4bb3a8f816841b6330b44d3bba5ace371af7aeb736cae02205e6e9927d5e8279d32e741fbcd567c08f6dda8bdd0e3597c85b85831c3a73090012103a7c03fa10f4ffa393a2e90ba098bf1f9b5d0cf84f83bc006fc9902884f22a5b5fdffffff3c885f084ef337efc869005db973de01660b048a07e0c6ca75dcdd0302323246000000006a47304402205bf9d8fe538d18d2f589f818acfc66efb3d7c563a6d0ce94379761e3ad5de4bb02204841c4f51cdb4433991f73fcff41fc82afd0a4411a89b09de30e6fb603ddf5a101210284741f8ca6ab581a46ae0ba5edfbfd134378c41e576c9267ca99054ecdf121cbfdffffff0240420f0000000000fd52015306746573742f364d2c017878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878786d7576a914734b00d1b31f3c3a89bcd6d302b820d4c0459fc188ac5e680500000000001976a9143b9cde2101e9da0fbf47d98ed859b0ad8fa886b588ac06710600" +} diff --git a/tests/transactions/namecoin_mainnet_5e3495.json b/tests/transactions/namecoin_mainnet_5e3495.json new file mode 100644 index 0000000..209f857 --- /dev/null +++ b/tests/transactions/namecoin_mainnet_5e3495.json @@ -0,0 +1,63 @@ +{ + "txid": "5e349540789309a088f9ede78c2e42e233e670aabbbd79886adc541389cfa4fa", + "hash": "5e349540789309a088f9ede78c2e42e233e670aabbbd79886adc541389cfa4fa", + "version": 28928, + "size": 478, + "vsize": 478, + "locktime": 421921, + "vin": [ + { + "txid": "4748ec1d3acad8bdb357b5499530ce1c3ada97ae9952475e3901e8f75dd55506", + "vout": 1, + "scriptSig": { + "asm": "30450221008eff8db772c8018181ccb1355d29e32436982f13d032d6ad72191139f7d9790402201a98c67c368b2c389156cb20b88aef251ec4e22535d830cea7986bcf62815059[ALL] 04e1c4b9e1cb0090fb6f55b98da47ed030a9e6383f6dd7d17089237abf10e5d939147dae8da00fc0840cf452c0e1a1001a56691abaa2cf07dc03c5477a586be6e2", + "hex": "4830450221008eff8db772c8018181ccb1355d29e32436982f13d032d6ad72191139f7d9790402201a98c67c368b2c389156cb20b88aef251ec4e22535d830cea7986bcf62815059014104e1c4b9e1cb0090fb6f55b98da47ed030a9e6383f6dd7d17089237abf10e5d939147dae8da00fc0840cf452c0e1a1001a56691abaa2cf07dc03c5477a586be6e2" + }, + "sequence": 4294967294 + }, + { + "txid": "0c686779a1dcc867039a3c71934d6cde487c4eabd9cd2efd0bdcf15262ed9886", + "vout": 1, + "scriptSig": { + "asm": "3045022100d242038864fc1b09ccdf4707b4ba828289c946c1c8681cff6347708332b9f6630220425d2dc3e4bd608efa82c6392e9732502ccffeba8c037ebf22ba035fc959cda6[ALL] 046cd0bf29656995ca841923f30f4b7ac9ae7cb4265da65ca8bd38363387b9317449cb1a0d6a11bc71d70a571ca7ee5b6a5dfe37cac10ccb4ed5cdb82751ceaa4b", + "hex": "483045022100d242038864fc1b09ccdf4707b4ba828289c946c1c8681cff6347708332b9f6630220425d2dc3e4bd608efa82c6392e9732502ccffeba8c037ebf22ba035fc959cda60141046cd0bf29656995ca841923f30f4b7ac9ae7cb4265da65ca8bd38363387b9317449cb1a0d6a11bc71d70a571ca7ee5b6a5dfe37cac10ccb4ed5cdb82751ceaa4b" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 280384718, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 9a52d8b8f425031b6ef40a847e771f6134af9804 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9149a52d8b8f425031b6ef40a847e771f6134af980488ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "NAeMWUDKZAjbDXM7BryV3Wa9Lp3C3aG7oq" + } + }, + { + "value": 1000000, + "n": 1, + "scriptPubKey": { + "nameOp": { + "op": "name_firstupdate", + "name": "d/heretostay", + "value": "{}", + "rand": "ca7d07e0aa9d23c2dc7efe5f2902f0e2ec22fe7c" + }, + "asm": "OP_NAME_FIRSTUPDATE 642f68657265746f73746179 ca7d07e0aa9d23c2dc7efe5f2902f0e2ec22fe7c 32123 OP_2DROP OP_2DROP OP_DUP OP_HASH160 ce26e759dbb966466446aab6e48cf39a23badd75 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "520c642f68657265746f7374617914ca7d07e0aa9d23c2dc7efe5f2902f0e2ec22fe7c027b7d6d6d76a914ce26e759dbb966466446aab6e48cf39a23badd7588ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "NFNQ1Ez6ZYVQpvsWcePBQMSiA3LB4BT9o1" + } + } + ], + "hex": "00710000020655d55df7e801395e475299ae97da3a1cce309549b557b3bdd8ca3a1dec4847010000008b4830450221008eff8db772c8018181ccb1355d29e32436982f13d032d6ad72191139f7d9790402201a98c67c368b2c389156cb20b88aef251ec4e22535d830cea7986bcf62815059014104e1c4b9e1cb0090fb6f55b98da47ed030a9e6383f6dd7d17089237abf10e5d939147dae8da00fc0840cf452c0e1a1001a56691abaa2cf07dc03c5477a586be6e2feffffff8698ed6252f1dc0bfd2ecdd9ab4e7c48de6c4d93713c9a0367c8dca17967680c010000008b483045022100d242038864fc1b09ccdf4707b4ba828289c946c1c8681cff6347708332b9f6630220425d2dc3e4bd608efa82c6392e9732502ccffeba8c037ebf22ba035fc959cda60141046cd0bf29656995ca841923f30f4b7ac9ae7cb4265da65ca8bd38363387b9317449cb1a0d6a11bc71d70a571ca7ee5b6a5dfe37cac10ccb4ed5cdb82751ceaa4bfeffffff02ce54b610000000001976a9149a52d8b8f425031b6ef40a847e771f6134af980488ac40420f000000000041520c642f68657265746f7374617914ca7d07e0aa9d23c2dc7efe5f2902f0e2ec22fe7c027b7d6d6d76a914ce26e759dbb966466446aab6e48cf39a23badd7588ac21700600", + "blockhash": "5b8c0254e59018d9cba170efccec0e1909898b8552ab581ba73a482d5693d25b", + "confirmations": 145, + "time": 1539853690, + "blocktime": 1539853690 +} diff --git a/tests/transactions/namecoin_mainnet_cfc5d7.json b/tests/transactions/namecoin_mainnet_cfc5d7.json new file mode 100644 index 0000000..eca550d --- /dev/null +++ b/tests/transactions/namecoin_mainnet_cfc5d7.json @@ -0,0 +1,62 @@ +{ + "txid": "cfc5d7e6280af21ce96f016826080490106dbf53f12ed1e38737595564b125c1", + "hash": "cfc5d7e6280af21ce96f016826080490106dbf53f12ed1e38737595564b125c1", + "version": 28928, + "size": 513, + "vsize": 513, + "locktime": 422067, + "vin": [ + { + "txid": "29c4c6c3443395a675111f7d809f192874d574425c014bb30ba8b6d4958fce2a", + "vout": 1, + "scriptSig": { + "asm": "30440220545b4eb23ddd3053580b58ef445092135a39a102cd858c3f46a8e3bbd68c0bb302200eb29decfaf4d189ca6dcae6cf4d86ddee5a2e2122fc504179e84c119873b014[ALL] 04d9fb2666d199134a53392189011a1aac0942d21299d338c274ae46f35cbeb631f4a413810d43fc1f968d7abc07b4181e56a5042e9f134538f8208b648d3bc5c7", + "hex": "4730440220545b4eb23ddd3053580b58ef445092135a39a102cd858c3f46a8e3bbd68c0bb302200eb29decfaf4d189ca6dcae6cf4d86ddee5a2e2122fc504179e84c119873b014014104d9fb2666d199134a53392189011a1aac0942d21299d338c274ae46f35cbeb631f4a413810d43fc1f968d7abc07b4181e56a5042e9f134538f8208b648d3bc5c7" + }, + "sequence": 4294967294 + }, + { + "txid": "5e349540789309a088f9ede78c2e42e233e670aabbbd79886adc541389cfa4fa", + "vout": 1, + "scriptSig": { + "asm": "3045022100f446e902ad3218d9d14ea2328f3ee5432b8f3a20224c2fc5fd9919b1c3d4362f022072fa9b4f840f53795f96336fadb79af2fb8c1e750a6cd84a5189fc381b5d8d56[ALL] 040df31f5db8614a8178e6d0785a56118c4f7d8fed10e80156e47934bd486f71ad1e81da5fbca360507eadc12e6c6b082bc6bee9f30fe64e235ea1127e28dfdf9c", + "hex": "483045022100f446e902ad3218d9d14ea2328f3ee5432b8f3a20224c2fc5fd9919b1c3d4362f022072fa9b4f840f53795f96336fadb79af2fb8c1e750a6cd84a5189fc381b5d8d560141040df31f5db8614a8178e6d0785a56118c4f7d8fed10e80156e47934bd486f71ad1e81da5fbca360507eadc12e6c6b082bc6bee9f30fe64e235ea1127e28dfdf9c" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 1000000, + "n": 0, + "scriptPubKey": { + "nameOp": { + "op": "name_update", + "name": "d/heretostay", + "value": "{\"ip\":\"185.234.217.36\",\"map\":{\"*\":{\"ip\":\"185.234.217.36\"}}}" + }, + "asm": "OP_NAME_UPDATE 642f68657265746f73746179 7b226970223a223138352e3233342e3231372e3336222c226d6170223a7b222a223a7b226970223a223138352e3233342e3231372e3336227d7d7d OP_2DROP OP_DROP OP_DUP OP_HASH160 584e13c024ce2eac261902a3c9508731a3dfa143 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "530c642f68657265746f737461793b7b226970223a223138352e3233342e3231372e3336222c226d6170223a7b222a223a7b226970223a223138352e3233342e3231372e3336227d7d7d6d7576a914584e13c024ce2eac261902a3c9508731a3dfa14388ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "N4dHCRYVP8oQa6ZXLC1DPnzbvuvq29hy6v" + } + }, + { + "value": 279093004, + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 09804e98bc777f101343fcd3c67044742e785bf6 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91409804e98bc777f101343fcd3c67044742e785bf688ac", + "reqSigs": 1, + "type": "pubkeyhash", + "address": "MwSbzJTK1Dc2dBcE4u6nLJ95ZmEnzPUtSE" + } + } + ], + "hex": "00710000022ace8f95d4b6a80bb34b015c4274d57428199f807d1f1175a6953344c3c6c429010000008a4730440220545b4eb23ddd3053580b58ef445092135a39a102cd858c3f46a8e3bbd68c0bb302200eb29decfaf4d189ca6dcae6cf4d86ddee5a2e2122fc504179e84c119873b014014104d9fb2666d199134a53392189011a1aac0942d21299d338c274ae46f35cbeb631f4a413810d43fc1f968d7abc07b4181e56a5042e9f134538f8208b648d3bc5c7fefffffffaa4cf891354dc6a8879bdbbaa70e633e2422e8ce7edf988a00993784095345e010000008b483045022100f446e902ad3218d9d14ea2328f3ee5432b8f3a20224c2fc5fd9919b1c3d4362f022072fa9b4f840f53795f96336fadb79af2fb8c1e750a6cd84a5189fc381b5d8d560141040df31f5db8614a8178e6d0785a56118c4f7d8fed10e80156e47934bd486f71ad1e81da5fbca360507eadc12e6c6b082bc6bee9f30fe64e235ea1127e28dfdf9cfeffffff0240420f000000000065530c642f68657265746f737461793b7b226970223a223138352e3233342e3231372e3336222c226d6170223a7b222a223a7b226970223a223138352e3233342e3231372e3336227d7d7d6d7576a914584e13c024ce2eac261902a3c9508731a3dfa14388ac0c9fa210000000001976a91409804e98bc777f101343fcd3c67044742e785bf688acb3700600", + "blockhash": "182f4fbdac2309b8f3333802ff81008178661662bf2d7bd385a2e93d3ac493a4", + "confirmations": 3, + "time": 1539945678, + "blocktime": 1539945678 +}