Browse Source

Add Decred(DCR) (#402)

patch-2
cipherzzz 7 years ago
committed by Neil
parent
commit
c26227413e
  1. 1
      .travis.yml
  2. 52
      lib/coins.py
  3. 103
      lib/tx.py
  4. 1
      setup.py
  5. 30
      tests/blocks/decred_mainnet_200000.json
  6. 17
      tests/blocks/decred_testnet_200000.json

1
.travis.yml

@ -20,6 +20,7 @@ install:
- pip install tribus-hash
- pip install pytest-cov
- pip install pylru
- pip install blake256
# command to run tests
script: pytest --cov=server --cov=lib --cov=wallet
# Dont report coverage from nightly

52
lib/coins.py

@ -35,6 +35,7 @@ import re
import struct
from decimal import Decimal
from hashlib import sha256
from functools import partial
import lib.util as util
from lib.hash import Base58, hash160, double_sha256, hash_to_str
@ -1420,3 +1421,54 @@ class BitcoinAtom(Coin):
'''Return the block header bytes'''
deserializer = cls.DESERIALIZER(block)
return deserializer.read_header(height, cls.BASIC_HEADER_SIZE)
class Decred(Coin):
NAME = "Decred"
SHORTNAME = "DCR"
NET = "mainnet"
XPUB_VERBYTES = bytes('dpub', 'utf-8')
XPRV_VERBYTES = bytes('dprv', 'utf-8')
P2PKH_VERBYTE = bytes('Ds', 'utf-8')
P2SH_VERBYTES = [bytes('Dc', 'utf-8')]
WIF_BYTE = bytes('Pm', 'utf-8')
GENESIS_HASH = ('298e5cc3d985bfe7f81dc135f360abe089edd4396b86d2de66b0cef42b21d980')
DESERIALIZER = lib_tx.DeserializerDecred
ENCODE_CHECK = partial(Base58.encode_check, hash_fn=lib_tx.DeserializerDecred.blake256)
DECODE_CHECK = partial(Base58.decode_check, hash_fn=lib_tx.DeserializerDecred.blake256)
HEADER_HASH = lib_tx.DeserializerDecred.blake256
BASIC_HEADER_SIZE = 180
ALLOW_ADVANCING_ERRORS = True
TX_COUNT = 217380620
TX_COUNT_HEIGHT = 218875
TX_PER_BLOCK = 1000
RPC_PORT = 9109
@classmethod
def header_hash(cls, header):
'''Given a header return the hash.'''
return cls.HEADER_HASH(header)
@classmethod
def block(cls, raw_block, height):
'''Return a Block namedtuple given a raw block and its height.'''
if height > 0:
return super().block(raw_block, height)
else:
return Block(raw_block, cls.block_header(raw_block, height), [])
class DecredTestnet(Decred):
NAME = "Decred"
NET = "testnet"
XPUB_VERBYTES = bytes('tpub', 'utf-8')
XPRV_VERBYTES = bytes('tprv', 'utf-8')
P2PKH_VERBYTE = bytes('Ts', 'utf-8')
P2SH_VERBYTES = [bytes('Tc', 'utf-8')]
WIF_BYTE = bytes('Pt', 'utf-8')
GENESIS_HASH = ('4261602a9d07d80ad47621a64ba6a07754902e496777edc4ff581946bd7bc29c')
TX_COUNT = 3176305
TX_COUNT_HEIGHT = 254198
TX_PER_BLOCK = 1000
RPC_PORT = 19119

103
lib/tx.py

@ -401,3 +401,106 @@ class DeserializerBitcoinAtom(DeserializerSegWit):
if height >= self.FORK_BLOCK_HEIGHT:
header_len += 4 # flags
return self._read_nbytes(header_len)
# Decred
class TxInputDcr(namedtuple("TxInput", "prev_hash prev_idx tree sequence")):
'''Class representing a Decred transaction input.'''
ZERO = bytes(32)
MINUS_1 = 4294967295
@cachedproperty
def is_coinbase(self):
# The previous output of a coin base must have a max value index and a
# zero hash.
return (self.prev_hash == TxInputDcr.ZERO and
self.prev_idx == TxInputDcr.MINUS_1)
def __str__(self):
prev_hash = hash_to_str(self.prev_hash)
return ("Input({}, {:d}, tree={}, sequence={:d})"
.format(prev_hash, self.prev_idx, self.tree, self.sequence))
class TxOutputDcr(namedtuple("TxOutput", "value version pk_script")):
'''Class representing a transaction output.'''
pass
class TxDcr(namedtuple("Tx", "version inputs outputs locktime expiry "
"witness")):
'''Class representing transaction that has a time field.'''
@cachedproperty
def is_coinbase(self):
return self.inputs[0].is_coinbase
class DeserializerDecred(Deserializer):
@staticmethod
def blake256(data):
from blake256.blake256 import blake_hash
return blake_hash(data)
def read_tx_block(self):
'''Returns a list of (deserialized_tx, tx_hash) pairs.'''
read_tx = self.read_tx
txs = [read_tx() for _ in range(self._read_varint())]
stxs = [read_tx() for _ in range(self._read_varint())]
return txs + stxs
def _read_inputs(self):
read_input = self._read_input
return [read_input() for i in range(self._read_varint())]
def _read_input(self):
return TxInputDcr(
self._read_nbytes(32), # prev_hash
self._read_le_uint32(), # prev_idx
self._read_byte(), # tree
self._read_le_uint32(), # sequence
)
def _read_outputs(self):
read_output = self._read_output
return [read_output() for _ in range(self._read_varint())]
def _read_output(self):
return TxOutputDcr(
self._read_le_int64(), # value
self._read_le_uint16(), # version
self._read_varbytes(), # pk_script
)
def _read_witness(self, fields):
read_witness_field = self._read_witness_field
assert fields == self._read_varint()
return [read_witness_field() for _ in range(fields)]
def _read_witness_field(self):
value_in = self._read_le_int64()
block_height = self._read_le_uint32()
block_index = self._read_le_uint32()
script = self._read_varbytes()
return value_in, block_height, block_index, script
def read_tx(self):
start = self.cursor
version = self._read_le_int32()
assert version == 1 # TODO check other versions for segwit
inputs = self._read_inputs()
outputs = self._read_outputs()
locktime = self._read_le_uint32()
expiry = self._read_le_uint32()
no_witness_tx = b'\x01\x00\x01\x00' + self.binary[start+4:self.cursor]
witness = self._read_witness(len(inputs))
return TxDcr(
version,
inputs,
outputs,
locktime,
expiry,
witness
), DeserializerDecred.blake256(no_witness_tx)

1
setup.py

@ -10,6 +10,7 @@ setuptools.setup(
# via environment variables, in which case I've tested with 15.0.4
# "x11_hash" package (1.4) is required to sync DASH network.
# "tribus_hash" package is required to sync Denarius network.
# "blake256" package is required to sync Decred network.
install_requires=['plyvel', 'pylru', 'aiohttp >= 1'],
packages=setuptools.find_packages(exclude=['tests']),
description='ElectrumX Server',

30
tests/blocks/decred_mainnet_200000.json

File diff suppressed because one or more lines are too long

17
tests/blocks/decred_testnet_200000.json

@ -0,0 +1,17 @@
{
"hash": "0000000003416ee936e24e3d8ebb0ae12cc9cd397df61346f2805642676291ae",
"size": 1637,
"height": 200000,
"merkleroot": "560d636172de028d728723b41428eb51acb4e969caf54f50f0de19f14a66fb1e",
"tx": [
"42fb258edd91d3b4aeea43f2451311b1045e3d0f935491301e03377eb86b1c46",
"9b1e326156e1426d1b2c32d711e660c936f53fcdf90de3ea4f8ae18c695751e0",
"017ac016d59cbc1b381ae71f61173bf9b5eaf85e338f2b81df73f88574bc7fa6",
"a15ddc52b33346ddb22005eaf622336d0f56856f598e1068d1fba280d9cf0408"
],
"time": 1513807068,
"nonce": 4094753344,
"bits": "1c038167",
"previousblockhash": "0000000001c195bb55127867a4dbeb9385fc14113db92a787ccd8c64d4bab58f",
"block": "060000008fb5bad4648ccd7c782ab93d1114fc8593ebdba467781255bb95c101000000001efb664af119def0504ff5ca69e9b4ac51eb2814b42387728d02de7261630d56778f843a51d3aa5d44dd17c5f35a0b163d925b9ce2dc7dfb25cb1534184cce4e01005768179ecf0803000000e41200006781031cbcf9645901000000400d030065060000dcdc3a5a40fa10f43ffde600cc7b6b00000000000000000000000000000000000000000000000000060000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff03b0d76703000000000000144fa6cbd0dbe5ec407fe4c8ad374e667771fa0d4400000000000000000000266a24400d03000000000000000000000000000000000000000000000000008ca3582a0607db7b260e6f140000000000001976a9149d8e8bdc618035be32a14ab752af2e331f9abf3688ac000000000000000001d5e5d6170000000000000000ffffffff0800002f646372642f0301000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffffab941af0b55cb4fd9a936b4b02cd052e9821b307c11389d3a3e68b40911b9c360000000001ffffffff0400000000000000000000266a248fb5bad4648ccd7c782ab93d1114fc8593ebdba467781255bb95c101000000003f0d030000000000000000000000086a060500060000003dc040000000000000001abb76a9147f686bc0e548bbb92f487db6da070e43a341172888ac3cdc96d60000000000001abb76a9149d8e8bdc618035be32a14ab752af2e331f9abf3688ac000000000000000002b0d767030000000000000000ffffffff020000cac46fd300000000260b03000d0000009047304402203a4a29b406b8eac0ac9adbbe818a28795cada504e83a46aa3e9c41cbfa014f700220310017fb5c5b5cc27d4b22f0867c324badf7a0b3953a274d95d1295e447f136d0147512102fe82f22f2e5bc1be0b67d85afef87329fc1c4512f30a47ce459c78bd7502ba9821022cf2f038dbb85f0a35fed9ac147e58d9ee85a80f8827085f51ef4129a02d458652ae01000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff171c0027204501f9572b19306e8fe6813b00391aaec26d295fabbb449fa245e00000000001ffffffff0400000000000000000000266a248fb5bad4648ccd7c782ab93d1114fc8593ebdba467781255bb95c101000000003f0d030000000000000000000000086a060500060000005f6341000000000000001abb76a9147f686bc0e548bbb92f487db6da070e43a341172888ac38a085010100000000001abb76a9149d8e8bdc618035be32a14ab752af2e331f9abf3688ac000000000000000002b0d767030000000000000000ffffffff020000e82b5ffe00000000e40603000500000090473044022060f6d935b0385d55a12899c48fa18e7e938d819874c3fe72924d665122fa95c30220566fcc424cf25f772007cff3b0a0f6f99dbf5b197ac26c1b67347a2dccb152bb0147512102fe82f22f2e5bc1be0b67d85afef87329fc1c4512f30a47ce459c78bd7502ba9821022cf2f038dbb85f0a35fed9ac147e58d9ee85a80f8827085f51ef4129a02d458652ae01000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff21cd5bfc8082569d5b317be8cf67d6b36dbb4711a5f69dc25aea0d6c7e319e4b0000000001ffffffff0400000000000000000000266a248fb5bad4648ccd7c782ab93d1114fc8593ebdba467781255bb95c101000000003f0d030000000000000000000000086a060500060000005f6341000000000000001abb76a9147f686bc0e548bbb92f487db6da070e43a341172888ac711c961c0100000000001abb76a9149d8e8bdc618035be32a14ab752af2e331f9abf3688ac000000000000000002b0d767030000000000000000ffffffff02000021a86f190100000029040300060000009148304502210098a4987ba360e1aea04de1ff77c1f5dd646b7dd1b00136ca58db005248e4451b022001b87cf0bb13bef9e09a48cfa88d5b9f6fc07af95cdc75b4e9f67c040541737a0147512102fe82f22f2e5bc1be0b67d85afef87329fc1c4512f30a47ce459c78bd7502ba9821022cf2f038dbb85f0a35fed9ac147e58d9ee85a80f8827085f51ef4129a02d458652ae"
}
Loading…
Cancel
Save