Merge branch 'sync-upstream'

This commit is contained in:
Vivek Teega 2018-12-17 15:41:33 +05:30
commit 03d219db10
43 changed files with 2349 additions and 240 deletions

View File

@ -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

View File

@ -22,3 +22,73 @@ See `readthedocs <https://electrumx.readthedocs.io/>`_.
**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

View File

@ -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 <https://github.com/kyuupichan/aiorpcX>`_ for all
networking, ``JSON RPC`` and proxy handling
* proxy detection improvements
* `documentation <https://electrumx.readthedocs.io/>`_ 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
<https://electrumx.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) <magnet:?xt=urn:btih:caa804f48a319b061be3884ac011656c27121a6f&dn=electrumx_1.2_btc_leveldb_490153>`_.
**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

View File

@ -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 -----------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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('<H', script[n: n + 2])
n += 2
else:
dlen, = struct.unpack('<I', script[n: n + 4])
n += 4
if n + dlen > 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')

View File

@ -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

View File

@ -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])

405
electrumx/lib/tx_dash.py Normal file
View File

@ -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

View File

@ -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('<I', tx_num)
for idx, txout in enumerate(tx.outputs):
# Get the hashX. Ignore unspendable outputs.
hashX = script_hashX(txout.pk_script)
if hashX:
add_hashXs(hashX)
put_utxo(tx_hash + s_pack('<H', idx),
hashX + tx_numb + s_pack('<Q', txout.value))
tx_num += 1
# Spend the inputs
# A separate for-loop here allows any tx ordering in block.
for (tx, tx_hash), hashXs in zip(txs, hashXs_by_tx):
add_hashXs = hashXs.add
for txin in tx.inputs:
if txin.is_generation():
continue
cache_value = spend_utxo(txin.prev_hash, txin.prev_idx)
undo_info_append(cache_value)
add_hashXs(cache_value[:-12])
# Update touched set for notifications
for hashXs in hashXs_by_tx:
update_touched(hashXs)
self.db.history.add_unflushed(hashXs_by_tx, self.tx_count)
self.tx_count = tx_num
self.db.tx_counts.append(tx_num)
return undo_info
def backup_txs(self, txs):
undo_info = self.db.read_undo_info(self.height)
if undo_info is None:
raise ChainError('no undo information found for height {:,d}'
.format(self.height))
# Use local vars for speed in the loops
s_pack = pack
put_utxo = self.utxo_cache.__setitem__
spend_utxo = self.spend_utxo
script_hashX = self.coin.hashX_from_script
add_touched = self.touched.add
undo_entry_len = 12 + HASHX_LEN
# Restore coins that had been spent
# (may include coins made then spent in this block)
n = 0
for tx, tx_hash in txs:
for txin in tx.inputs:
if txin.is_generation():
continue
undo_item = undo_info[n:n + undo_entry_len]
put_utxo(txin.prev_hash + s_pack('<H', txin.prev_idx),
undo_item)
add_touched(undo_item[:-12])
n += undo_entry_len
assert n == len(undo_info)
# Remove tx outputs made in this block, by spending them.
for tx, tx_hash in txs:
for idx, txout in enumerate(tx.outputs):
hashX = script_hashX(txout.pk_script)
if hashX:
# Be careful with unspendable outputs- we didn't save those
# in the first place.
cache_value = spend_utxo(tx_hash, idx)
add_touched(cache_value[:-12])
self.tx_count -= len(txs)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2016-2017, Neil Booth
# Copyright (c) 2016-2018, Neil Booth
#
# All rights reserved.
#
@ -33,8 +33,7 @@ class Notifications(object):
def __init__(self):
self._touched_mp = {}
self._touched_bp = {}
self._highest_block = 0
self._notify_funcs = []
self._highest_block = -1
async def _maybe_notify(self):
tmp, tbp = self._touched_mp, self._touched_bp
@ -49,16 +48,19 @@ class Notifications(object):
# new block height
return
touched = tmp.pop(height)
touched.update(tbp.pop(height, set()))
for old in [h for h in tmp if h <= height]:
del tmp[old]
for old in [h for h in tbp if h <= height]:
del tbp[old]
for notify_func in self._notify_funcs:
await notify_func(height, touched)
touched.update(tbp.pop(old))
await self.notify(height, touched)
def add_callback(self, notify_func):
self._notify_funcs.append(notify_func)
async def notify(self, height, touched):
pass
async def start(self, height, notify_func):
self._highest_block = height
self.notify = notify_func
await self.notify(height, set())
async def on_mempool(self, touched, height):
self._touched_mp[height] = touched
@ -80,8 +82,8 @@ class Controller(ServerBase):
'''Start the RPC server and wait for the mempool to synchronize. Then
start serving external clients.
'''
if not (0, 8, 1) <= aiorpcx_version < (0, 9):
raise RuntimeError('aiorpcX version 0.8.x with x >= 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()
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())

View File

@ -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)

View File

@ -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
#

View File

@ -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

View File

@ -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:

View File

@ -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',

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -0,0 +1,14 @@
{
"hash": "09a2344ca39c422a473ab2ac0a93c0de5eef7bbc63c59ea36bf8a126ae2fbc26",
"size": 326,
"height": 2587044,
"merkleroot": "0373487200798a478a9b5330fddcc092cb08f9b517c62eacbfbe733b8e8d3680",
"tx": [
"0373487200798a478a9b5330fddcc092cb08f9b517c62eacbfbe733b8e8d3680"
],
"time": 1540383063,
"nonce": 1758391936,
"bits": "1b013fb1",
"previousblockhash": "6bebe78892419acf8f47fa34ac08417036c244a244d209dbb5113edfda7ae480",
"block": "00065a2080e47adadf3e11b5db09d244a244c236704108ac34fa478fcf9a419288e7eb6b80368d8e3b73bebfac2ec617b5f908cb92c0dcfd30539b8a478a7900724873035761d05bb13f011b80eece6801010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4d03a47927045761d05b08fabe6d6db5b8ddd39dc3e80a8930480db7f9dd41acc305fe5f41f5c953ae73e980a534b9020000000000000000005275250000000e2f6d696e696e672d64757463682f00000000020000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf900ba1dd2050000001976a9140c6de8cbb3e5fc90476c696881dc28bb9b4989e088ac0120000000000000000000000000000000000000000000000000000000000000000000000000"
}

View File

@ -0,0 +1,14 @@
{
"hash": "b9fa17b5469c68aeddea48666f12c8ae5cdc3e8521b4b5637e10099cda8728fd",
"size": 377,
"height": 50000,
"merkleroot": "2ee565d865d766a9861d77f1d3c34b364261a105fd0b10c15e9cb07dc61b1493",
"tx": [
"2ee565d865d766a9861d77f1d3c34b364261a105fd0b10c15e9cb07dc61b1493"
],
"time": 1536401916,
"nonce": 1610805540,
"bits": "1b0551f5",
"previousblockhash": "acec77ce8845f34d2a854dc7da66151338c2f42f1c7f51782bd7732017f13c31",
"block": "00000020313cf1172073d72b78517f1c2ff4c238131566dac74d852a4df34588ce77ecac93141bc67db09c5ec1100bfd05a16142364bc3d3f1771d86a966d765d865e52efca1935bf551051b24f1026001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff200350c30004fca1935b08180006a3510200000d2f6e6f64655374726174756d2f00000000050000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90090f4f70000000017a914e48c970e4a4faa6222688ec6333eb53c578e59f78700d012130000000017a9146a27966d76edfdfb3c53dc37dd5471bdeac7d46c870020a1070000000017a9147150055215791b779dddb1d112541a3fce71061b8700c0cf6a000000001976a91490f50a1fa5b280282de2a3ec15164a766fd48a0288ac0120000000000000000000000000000000000000000000000000000000000000000000000000"
}

View File

@ -0,0 +1,14 @@
{
"hash": "9d5d8d308484a654cfc18fc6290734dca584bf0c02409429682a8b46715a0811",
"size": 384,
"height": 200,
"merkleroot": "ee1377591fe82696a15f416476a28cf57a83af77e799bbfdff24909be06cc559",
"tx": [
"ee1377591fe82696a15f416476a28cf57a83af77e799bbfdff24909be06cc559"
],
"time": 1542147760,
"nonce": 0,
"bits": "1a2157b9",
"previousblockhash": "1634ccd348860d24b5eabffc8782ae1aa1d6797477f0d4910cb25488a28cb372",
"block": "0000002072b38ca28854b20c91d4f0777479d6a11aae8287fcbfeab5240d8648d3cc341659c56ce09b9024fffdbb99e777af837af58ca27664415fa19626e81f597713eeb04eeb5bb957211a00000000010203000001daf694ffcf73e2710b6148d89fc10b95cb55e255d804014c5141712168b9524c01000000171600147c5aad68a58a92630e3feab030fcaeb2cfff37feffffffff0530ecadf66b01000032b863a914f0c3b8f1fb7c1887a70c0108f729620c4c0901228767a914bdb5bb31196596f760ddaa49f7a82956e30b58de876830ecadf66b01000032b863a914f0c3b8f1fb7c1887a70c0108f729620c4c0901228767a914bdb5bb31196596f760ddaa49f7a82956e30b58de87680090d0030000000017a9147667be5313f1e3fb921a096b4b9b59c82b157ebe870090d0030000000017a914bf41e0caa3649bd8b9f4008103fb2a2757f3b8f3870000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf900000000473045022100b517ff2a36aee842e4ff750723b1cea0e7cc0064677d69735e4775a01245224802206db5bf42c16d76e790e97f741a10f576628c38bcb5a7072d1df4be9c1cd874e4"
}

View File

@ -0,0 +1,14 @@
{
"hash": "572d8a5897cad3f3a75811258513d321e8971c27ed210bb24eba4cd59697dc6d",
"size": 230,
"height": 370000,
"merkleroot": "21000ff185207fc1b208ab1c03de33acb678d6ef542731426da5bfb08627d0b0",
"tx": [
"21000ff185207fc1b208ab1c03de33acb678d6ef542731426da5bfb08627d0b0"
],
"time": 1542089008,
"nonce": 1713111040,
"bits": "1d05e718",
"previousblockhash": "cb9b3ff2a750f644e9389f50c508e9a4e217df2f07c5bc6a89a2e7fc82e2cdfe",
"block": "00000020fecde282fce7a2896abcc5072fdf17e2a4e908c5509f38e944f650a7f23f9bcbb0d02786b0bfa56d42312754efd678b6ac33de031cab08b2c17f2085f10f00213069ea5b18e7051d00001c660101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1e0350a505043069ea5b083fff6fd4000000000b2f47666c6172652e696f2f000000000260b8131a000000001976a914122466aaa347290e3b3b7858f2ba041af97d1b4388ac20c46d30000000001976a914a26f5f0cf1b72ae0a5ab533f1e5f420876b3bf6988ac00000000"
}

View File

@ -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"
}

View File

@ -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"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
tests/lib/__init__.py Normal file
View File

View File

@ -67,6 +67,8 @@ addresses = [
"ab72728952c06dfc0f6cf21449dd645422731ec4", "eb3a3155215538d51de7cc"),
(coins.TokenPay, "TDE2X28FGtckatxuP3d8s3V726G4TLNHpT",
"23b5dd9b7b402388c7a40bc88c261f3178acf30d", "7c7bdf0e0713f3752f4b88"),
(coins.SmartCash, "SQFDM9NtRRmpHebq3H5RA3qpGJfGqp8Xgw",
"206168f5322583ff37f8e55665a4789ae8963532", "b8cb80b26e8932f5b12a7e"),
]

464
tests/lib/test_tx_dash.py Normal file
View File

@ -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))

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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'})]

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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"
}

View File

@ -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
}

View File

@ -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
}