Merge branch 'master' into devel

This commit is contained in:
Neil Booth 2018-08-14 11:34:18 +09:00
commit a108817dd4
8 changed files with 113 additions and 26 deletions

View File

@ -2100,3 +2100,42 @@ class GroestlcoinTestnet(Groestlcoin):
'7frvhgofuf522b5i.onion t', '7frvhgofuf522b5i.onion t',
'aocojvqcybdoxekv.onion t', 'aocojvqcybdoxekv.onion t',
] ]
class Pivx(Coin):
NAME = "Pivx"
SHORTNAME = "PIVX"
NET = "mainnet"
XPUB_VERBYTES = bytes.fromhex("022D2533")
XPRV_VERBYTES = bytes.fromhex("0221312B")
P2PKH_VERBYTE = bytes.fromhex("1e")
P2SH_VERBYTES = [bytes.fromhex("0d")]
WIF_BYTE = bytes.fromhex("d4")
GENESIS_HASH = ('0000041e482b9b9691d98eefb4847340'
'5c0b8ec31b76df3797c74a78680ef818')
BASIC_HEADER_SIZE = 80
HDR_V4_SIZE = 112
HDR_V4_HEIGHT = 863787
HDR_V4_START_OFFSET = HDR_V4_HEIGHT * BASIC_HEADER_SIZE
TX_COUNT = 2930206
TX_COUNT_HEIGHT = 1299212
TX_PER_BLOCK = 2
RPC_PORT = 51473
@classmethod
def static_header_offset(cls, height):
assert cls.STATIC_BLOCK_HEADERS
if height >= cls.HDR_V4_HEIGHT:
relative_v4_offset = (height - cls.HDR_V4_HEIGHT) * cls.HDR_V4_SIZE
return cls.HDR_V4_START_OFFSET + relative_v4_offset
else:
return height * cls.BASIC_HEADER_SIZE
@classmethod
def header_hash(cls, header):
version, = struct.unpack('<I', header[:4])
if version >= 4:
return super().header_hash(header)
else:
import quark_hash
return quark_hash.getPoWHash(header)

View File

@ -42,8 +42,8 @@ class Tx(namedtuple("Tx", "version inputs outputs locktime")):
'''Class representing a transaction.''' '''Class representing a transaction.'''
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return self.inputs[0].is_coinbase return self.inputs[0].is_generation
def serialize(self): def serialize(self):
return b''.join(( return b''.join((
@ -63,9 +63,9 @@ class TxInput(namedtuple("TxInput", "prev_hash prev_idx script sequence")):
MINUS_1 = 4294967295 MINUS_1 = 4294967295
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return (self.prev_hash == TxInput.ZERO and return (self.prev_idx == TxInput.MINUS_1 and
self.prev_idx == TxInput.MINUS_1) self.prev_hash == TxInput.ZERO)
def __str__(self): def __str__(self):
script = self.script.hex() script = self.script.hex()
@ -215,8 +215,8 @@ class TxSegWit(namedtuple("Tx", "version marker flag inputs outputs "
'''Class representing a SegWit transaction.''' '''Class representing a SegWit transaction.'''
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return self.inputs[0].is_coinbase return self.inputs[0].is_generation
class DeserializerSegWit(Deserializer): class DeserializerSegWit(Deserializer):
@ -327,8 +327,8 @@ class TxJoinSplit(namedtuple("Tx", "version inputs outputs locktime")):
'''Class representing a JoinSplit transaction.''' '''Class representing a JoinSplit transaction.'''
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return self.inputs[0].is_coinbase if len(self.inputs) > 0 else False return self.inputs[0].is_generation if len(self.inputs) > 0 else False
class DeserializerZcash(DeserializerEquihash): class DeserializerZcash(DeserializerEquihash):
@ -361,8 +361,8 @@ class TxTime(namedtuple("Tx", "version time inputs outputs locktime")):
'''Class representing transaction that has a time field.''' '''Class representing transaction that has a time field.'''
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return self.inputs[0].is_coinbase return self.inputs[0].is_generation
class DeserializerTxTime(Deserializer): class DeserializerTxTime(Deserializer):
@ -445,13 +445,10 @@ class DeserializerGroestlcoin(DeserializerSegWit):
class TxInputDcr(namedtuple("TxInput", "prev_hash prev_idx tree sequence")): class TxInputDcr(namedtuple("TxInput", "prev_hash prev_idx tree sequence")):
'''Class representing a Decred transaction input.''' '''Class representing a Decred transaction input.'''
ZERO = bytes(32)
MINUS_1 = 4294967295
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return (self.prev_hash == TxInputDcr.ZERO and return (self.prev_idx == TxInput.MINUS_1 and
self.prev_idx == TxInputDcr.MINUS_1) self.prev_hash == TxInput.ZERO)
def __str__(self): def __str__(self):
prev_hash = hash_to_hex_str(self.prev_hash) prev_hash = hash_to_hex_str(self.prev_hash)
@ -469,8 +466,8 @@ class TxDcr(namedtuple("Tx", "version inputs outputs locktime expiry "
'''Class representing a Decred transaction.''' '''Class representing a Decred transaction.'''
@cachedproperty @cachedproperty
def is_coinbase(self): def is_generation(self):
return self.inputs[0].is_coinbase return self.inputs[0].is_generation
class DeserializerDecred(Deserializer): class DeserializerDecred(Deserializer):
@ -546,7 +543,7 @@ class DeserializerDecred(Deserializer):
# Drop the coinbase-like input from a vote tx as it creates problems # Drop the coinbase-like input from a vote tx as it creates problems
# with UTXOs lookups and mempool management # with UTXOs lookups and mempool management
if inputs[0].is_coinbase and len(inputs) > 1: if inputs[0].is_generation and len(inputs) > 1:
inputs = inputs[1:] inputs = inputs[1:]
if produce_hash: if produce_hash:

View File

@ -411,7 +411,7 @@ class BlockProcessor(object):
tx_numb = s_pack('<I', tx_num) tx_numb = s_pack('<I', tx_num)
# Spend the inputs # Spend the inputs
if not tx.is_coinbase: if not tx.is_generation:
for txin in tx.inputs: for txin in tx.inputs:
cache_value = spend_utxo(txin.prev_hash, txin.prev_idx) cache_value = spend_utxo(txin.prev_hash, txin.prev_idx)
undo_info_append(cache_value) undo_info_append(cache_value)
@ -490,7 +490,7 @@ class BlockProcessor(object):
touched.add(cache_value[:-12]) touched.add(cache_value[:-12])
# Restore the inputs # Restore the inputs
if not tx.is_coinbase: if not tx.is_generation:
for txin in reversed(tx.inputs): for txin in reversed(tx.inputs):
n -= undo_entry_len n -= undo_entry_len
undo_item = undo_info[n:n + undo_entry_len] undo_item = undo_info[n:n + undo_entry_len]

View File

@ -586,9 +586,7 @@ class DB(object):
self.write_utxo_state(batch) self.write_utxo_state(batch)
async def all_utxos(self, hashX): async def all_utxos(self, hashX):
'''Return all UTXOs for an address sorted in no particular order. By '''Return all UTXOs for an address sorted in no particular order.'''
default yields at most 1000 entries.
'''
def read_utxos(): def read_utxos():
utxos = [] utxos = []
utxos_append = utxos.append utxos_append = utxos.append

View File

@ -985,7 +985,7 @@ class ElectrumX(SessionBase):
'''Return a raw block header as a hexadecimal string. '''Return a raw block header as a hexadecimal string.
height: the header's height''' height: the header's height'''
return self.block_header(height) return await self.block_header(height)
async def block_headers(self, start_height, count, cp_height=0): async def block_headers(self, start_height, count, cp_height=0):
'''Return count concatenated block headers as hex for the main chain; '''Return count concatenated block headers as hex for the main chain;

View File

@ -0,0 +1,14 @@
{
"hash": "00000000003ce77135d15257a57f7508b8c5021372de2eae554f3142b60944cc",
"size": 231,
"height": 10000,
"merkleroot": "bd27e18a8abbd501b775d32fc6402a1a474a0517c1c8b04b9d487b0203f6b0f0",
"tx": [
"bd27e18a8abbd501b775d32fc6402a1a474a0517c1c8b04b9d487b0203f6b0f0"
],
"time": 1454814715,
"nonce": 14876727,
"bits": "1c06b486",
"previousblockhash": "00000000023fecac81bc148c7ab26a0190dbabeac2e8e260f62dff5205596f02",
"block": "03000000026f590552ff2df660e2e8c2eaabdb90016ab27a8c14bc81acec3f0200000000f0b0f603027b489d4bb0c8c117054a471a2a40c62fd375b701d5bb8a8ae127bdfbb5b65686b4061c3700e3000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1f02102704fbb5b65608380001169c6108000d2f6e6f64655374726174756d2f000000000200c817a8040000001976a91493d5f8ec14e203ef275ebfe942bc6a1e2784f95088ac00f2052a010000001976a914d6716d39693e034596a1e8546b4d65e4a06159cc88ac00000000"
}

View File

@ -0,0 +1,15 @@
{
"hash": "bb6127b99bf96b150c86ac38fde17c47d6c95b460c462ef45fd5043a44479068",
"size": 461,
"height": 1000000,
"merkleroot": "ecafe8267cbc5e4b6f4aec0978b02f0ba47a19828b0f8780e25685184d61c9e2",
"tx": [
"290871d1dc1673069a4c3efef424278b377becbff0c776e20972d212daa4a3d4",
"e217611a8db9ec5994632e1f66727c53e0ba09c406f6c993c8d52f5474efe620"
],
"time": 1516510311,
"nonce": 0,
"bits": "1a7128a9",
"previousblockhash": "795ab132be197a0a173cbe3590660235d906e0011052a10206244e0eae4b5152",
"block": "0400000052514bae0e4e240602a1521001e006d93502669035be3c170a7a19be32b15a79e2c9614d188556e280870f8b82197aa40b2fb07809ec4a6f4b5ebc7c26e8afec671c645aa928711a000000004ff5c33f2832ca5fa5ecbefb33c068e32ad0ae6e47c71be916fc34615c299b8c0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff060340420f0101ffffffff01000000000000000000000000000100000001eb79b426b80013c330e13e49764deeba311f8be69d0ec117d5b4f11d72215f3e0100000049483045022100f495580e30a64b4945582fe3e9a9118a60b53ca22c44232c170ff99a9fa7e8210220712921e4ddda1afe47b2481f2d1512759aaa0ab584f16ffe4b28771437c716be01ffffffff03000000000000000000500ae8470c0000002321037e0b96219461080ce2f837825fd3c52b08199c404a0d6d59f026a6a890dc4b15ac808ef20d000000001976a914f0364dfac5fca72abd79085c6b00f9e8f35bbff688ac0000000046304402203b270304b2fa14362d9718c16bf20e5c6ede49abfa7fe5fc5326b9f598d592d402203b32fda981ead1df35aebc1eca9b4766555dd2f200538f6b3d62d6ccc5180aa7"
}

24
tests/lib/test_coins.py Normal file
View File

@ -0,0 +1,24 @@
import electrumx.lib.coins as coins
def test_bitcoin_cash():
raw_header = bytes.fromhex(
"00000020df975c121dcbc18bbb7ddfd0419fc368b45db86b48c87e0"
"1000000000000000036ae3dd40a10a40d3050de13ca546a2f81589d"
"e2d2f317925a43a115437e2381f5bf535b94da0118ac8df8c5"
)
height = 540000
electrum_header = {
'block_height': 540000,
'version': 536870912,
'prev_block_hash':
'0000000000000000017ec8486bb85db468c39f41d0df7dbb8bc1cb1d125c97df',
'merkle_root':
'81237e4315a1435a9217f3d2e29d58812f6a54ca13de50300da4100ad43dae36',
'timestamp': 1532215285,
'bits': 402774676,
'nonce': 3321400748
}
assert coins.BitcoinCash.electrum_header(
raw_header, height) == electrum_header