parent
a820829e0e
commit
bc31df8ee0
70
lib/coins.py
70
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('<I', header[:4])
|
||||
timestamp, bits = struct.unpack('<II', header[100:108])
|
||||
|
||||
return {
|
||||
'block_height': height,
|
||||
'version': version,
|
||||
'prev_block_hash': hash_to_str(header[4:36]),
|
||||
'merkle_root': hash_to_str(header[36:68]),
|
||||
'timestamp': timestamp,
|
||||
'bits': bits,
|
||||
'nonce': hash_to_str(header[108:140]),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def block_header(cls, block, height):
|
||||
'''Return the block header bytes'''
|
||||
block = DeserializerZcash(block)
|
||||
return block.read_header(height, cls.BASIC_HEADER_SIZE)
|
||||
|
||||
@classmethod
|
||||
def deserializer(cls):
|
||||
return DeserializerZcash
|
||||
|
||||
64
lib/tx.py
64
lib/tx.py
@ -238,3 +238,67 @@ class DeserializerSegWit(Deserializer):
|
||||
|
||||
return TxSegWit(version, marker, flag, inputs,
|
||||
outputs, witness, locktime), double_sha256(orig_ser)
|
||||
|
||||
|
||||
class DeserializerAuxPow(Deserializer):
|
||||
VERSION_AUXPOW = (1 << 8)
|
||||
|
||||
def read_header(self, height, static_header_size):
|
||||
'''Return the AuxPow block header bytes'''
|
||||
start = self.cursor
|
||||
version = self._read_le_uint32()
|
||||
if version & self.VERSION_AUXPOW:
|
||||
# We are going to calculate the block size then read it as bytes
|
||||
self.cursor = start
|
||||
self.cursor += static_header_size # Block normal header
|
||||
self.read_tx() # AuxPow transaction
|
||||
self.cursor += 32 # Parent block hash
|
||||
merkle_size = self._read_varint()
|
||||
self.cursor += 32 * merkle_size # Merkle branch
|
||||
self.cursor += 4 # Index
|
||||
merkle_size = self._read_varint()
|
||||
self.cursor += 32 * merkle_size # Chain merkle branch
|
||||
self.cursor += 4 # Chain index
|
||||
self.cursor += 80 # Parent block header
|
||||
header_end = self.cursor
|
||||
else:
|
||||
header_end = static_header_size
|
||||
self.cursor = start
|
||||
return self._read_nbytes(header_end)
|
||||
|
||||
|
||||
class TxJoinSplit(namedtuple("Tx", "version inputs outputs locktime")):
|
||||
'''Class representing a JoinSplit transaction.'''
|
||||
|
||||
@cachedproperty
|
||||
def is_coinbase(self):
|
||||
return self.inputs[0].is_coinbase if len(self.inputs) > 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])
|
||||
|
||||
@ -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"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user