diff --git a/lib/coins.py b/lib/coins.py index 701625c..8df7a20 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -39,7 +39,7 @@ from hashlib import sha256 import lib.util as util from lib.hash import Base58, hash160, double_sha256, hash_to_str from lib.script import ScriptPubKey -from lib.tx import Deserializer, DeserializerSegWit +from lib.tx import Deserializer, DeserializerSegWit, DeserializerAuxPow, DeserializerZcash Block = namedtuple("Block", "header transactions") @@ -293,6 +293,23 @@ class Coin(object): def deserializer(cls): return Deserializer +class CoinAuxPow(Coin): + # Set NAME and NET to avoid exception in Coin::lookup_coin_class + NAME = "" + NET = "" + STATIC_BLOCK_HEADERS = False + + @classmethod + def header_hash(cls, header): + '''Given a header return hash''' + return double_sha256(header[:cls.BASIC_HEADER_SIZE]) + + @classmethod + def block_header(cls, block, height): + '''Return the AuxPow block header bytes''' + block = DeserializerAuxPow(block) + return block.read_header(height, cls.BASIC_HEADER_SIZE) + class Bitcoin(Coin): NAME = "Bitcoin" @@ -451,7 +468,7 @@ class LitecoinTestnetSegWit(LitecoinTestnet): # Source: namecoin.org -class Namecoin(Coin): +class Namecoin(CoinAuxPow): NAME = "Namecoin" SHORTNAME = "NMC" NET = "mainnet" @@ -484,7 +501,7 @@ class NamecoinTestnet(Namecoin): # For DOGE there is disagreement across sites like bip32.org and # pycoin. Taken from bip32.org and bitmerchant on github -class Dogecoin(Coin): +class Dogecoin(CoinAuxPow): NAME = "Dogecoin" SHORTNAME = "DOGE" NET = "mainnet" @@ -682,3 +699,50 @@ class FairCoin(Coin): 'timestamp': timestamp, 'creatorId': creatorId, } + + +class Zcash(Coin): + NAME = "Zcash" + SHORTNAME = "ZEC" + NET = "mainnet" + XPUB_VERBYTES = bytes.fromhex("0488b21e") + XPRV_VERBYTES = bytes.fromhex("0488ade4") + P2PKH_VERBYTE = bytes.fromhex("1CB8") + P2SH_VERBYTE = bytes.fromhex("1CBD") + WIF_BYTE = bytes.fromhex("80") + GENESIS_HASH = ('00040fe8ec8471911baa1db1266ea15d' + 'd06b4a8a5c453883c000b031973dce08') + STATIC_BLOCK_HEADERS = False + BASIC_HEADER_SIZE = 140 # Excluding Equihash solution + TX_COUNT = 329196 + TX_COUNT_HEIGHT = 68379 + TX_PER_BLOCK = 5 + IRC_PREFIX = "E_" + IRC_CHANNEL = "#electrum-zcash" + RPC_PORT = 8232 + REORG_LIMIT = 800 + + @classmethod + def electrum_header(cls, header, height): + version, = struct.unpack(' 0 else False + + +class DeserializerZcash(Deserializer): + def read_header(self, height, static_header_size): + '''Return the block header bytes''' + start = self.cursor + # We are going to calculate the block size then read it as bytes + self.cursor += static_header_size + solution_size = self._read_varint() + self.cursor += solution_size + header_end = self.cursor + self.cursor = start + return self._read_nbytes(header_end) + + def read_tx(self): + start = self.cursor + base_tx = TxJoinSplit( + self._read_le_int32(), # version + self._read_inputs(), # inputs + self._read_outputs(), # outputs + self._read_le_uint32() # locktime + ) + if base_tx.version >= 2: + joinsplit_size = self._read_varint() + if joinsplit_size > 0: + self.cursor += joinsplit_size * 1802 # JSDescription + self.cursor += 32 # joinSplitPubKey + self.cursor += 64 # joinSplitSig + return base_tx, double_sha256(self.binary[start:self.cursor]) diff --git a/tests/test_addresses.py b/tests/test_addresses.py index 9ee81fd..be560d0 100644 --- a/tests/test_addresses.py +++ b/tests/test_addresses.py @@ -26,7 +26,7 @@ import pytest -from lib.coins import Litecoin, Bitcoin +from lib.coins import Litecoin, Bitcoin, Zcash from lib.hash import Base58 addresses = [ @@ -38,6 +38,10 @@ addresses = [ "206168f5322583ff37f8e55665a4789ae8963532", "b8cb80b26e8932f5b12a7e"), (Litecoin, "3GxRZWkJufR5XA8hnNJgQ2gkASSheoBcmW", "a773db925b09add367dcc253c1f9bbc1d11ec6fd", "062d8515e50cb92b8a3a73"), + (Zcash, "t1LppKe1sfPNDMysGSGuTjxoAsBcvvSYv5j", + "206168f5322583ff37f8e55665a4789ae8963532", "b8cb80b26e8932f5b12a7e"), + (Zcash, "t3Zq2ZrASszCg7oBbio7oXqnfR6dnSWqo76", + "a773db925b09add367dcc253c1f9bbc1d11ec6fd", "062d8515e50cb92b8a3a73"), ]