Add support for stagenet addresses

This commit is contained in:
Michał Sałaban 2018-05-21 17:25:28 +02:00
parent 0bfdb8f7be
commit a037f121b7
2 changed files with 52 additions and 6 deletions

View File

@ -19,8 +19,8 @@ class Address(object):
:param label: a label for the address (defaults to `None`)
"""
label = None
_valid_netbytes = (18, 53)
# NOTE: _valid_netbytes order is (real, testnet)
_valid_netbytes = (18, 53, 24)
# NOTE: _valid_netbytes order is (mainnet, testnet, stagenet)
def __init__(self, addr, label=None):
addr = str(addr)
@ -40,6 +40,13 @@ class Address(object):
nb=self._decoded[0],
allowed=", ".join(map(lambda b: '%02x' % b, self._valid_netbytes))))
def is_mainnet(self):
"""Returns `True` if the address belongs to mainnet.
:rtype: bool
"""
return self._decoded[0] == self._valid_netbytes[0]
def is_testnet(self):
"""Returns `True` if the address belongs to testnet.
@ -47,6 +54,13 @@ class Address(object):
"""
return self._decoded[0] == self._valid_netbytes[1]
def is_stagenet(self):
"""Returns `True` if the address belongs to stagenet.
:rtype: bool
"""
return self._decoded[0] == self._valid_netbytes[2]
def view_key(self):
"""Returns public view key.
@ -73,7 +87,7 @@ class Address(object):
payment_id = numbers.PaymentID(payment_id)
if not payment_id.is_short():
raise TypeError("Payment ID {0} has more than 64 bits and cannot be integrated".format(payment_id))
prefix = 54 if self.is_testnet() else 19
prefix = 54 if self.is_testnet() else 25 if self.is_stagenet() else 19
data = bytearray([prefix]) + self._decoded[1:65] + struct.pack('>Q', int(payment_id))
checksum = bytearray(keccak_256(data).digest()[:4])
return IntegratedAddress(base58.encode(hexlify(data + checksum)))
@ -95,7 +109,8 @@ class SubAddress(Address):
Any type of address which is not the master one for a wallet.
"""
_valid_netbytes = (42, 63)
_valid_netbytes = (42, 63, 36)
# NOTE: _valid_netbytes order is (mainnet, testnet, stagenet)
def with_payment_id(self, _):
raise TypeError("SubAddress cannot be integrated with payment ID")
@ -107,7 +122,8 @@ class IntegratedAddress(Address):
A master address integrated with payment id (short one, max 64 bit).
"""
_valid_netbytes = (19, 54)
_valid_netbytes = (19, 54, 25)
# NOTE: _valid_netbytes order is (mainnet, testnet, stagenet)
def __init__(self, address):
address = str(address)
@ -127,7 +143,7 @@ class IntegratedAddress(Address):
"""Returns the base address without payment id.
:rtype: :class:`Address`
"""
prefix = 53 if self.is_testnet() else 18
prefix = 53 if self.is_testnet() else 24 if self.is_stagenet() else 18
data = bytearray([prefix]) + self._decoded[1:65]
checksum = keccak_256(data).digest()[:4]
return Address(base58.encode(hexlify(data + checksum)))

View File

@ -33,8 +33,12 @@ class Tests(object):
self.assertEqual(a, a2)
self.assertEqual(a, self.addr)
self.assertEqual(self.addr, a)
self.assertEqual(a.is_mainnet(), self.mainnet)
self.assertEqual(a.is_testnet(), self.testnet)
self.assertEqual(a.is_stagenet(), self.stagenet)
self.assertEqual(a2.is_mainnet(), self.mainnet)
self.assertEqual(a2.is_testnet(), self.testnet)
self.assertEqual(a2.is_stagenet(), self.stagenet)
ia = IntegratedAddress(self.iaddr)
ia2 = address(self.iaddr)
@ -42,8 +46,12 @@ class Tests(object):
self.assertEqual(ia, ia2)
self.assertEqual(ia, self.iaddr)
self.assertEqual(self.iaddr, ia)
self.assertEqual(ia.is_mainnet(), self.mainnet)
self.assertEqual(ia.is_testnet(), self.testnet)
self.assertEqual(ia.is_stagenet(), self.stagenet)
self.assertEqual(ia2.is_mainnet(), self.mainnet)
self.assertEqual(ia2.is_testnet(), self.testnet)
self.assertEqual(ia2.is_stagenet(), self.stagenet)
self.assertEqual(ia2.base_address(), a)
self.assertEqual(ia.view_key(), a.view_key())
@ -55,8 +63,12 @@ class Tests(object):
self.assertEqual(sa, sa2)
self.assertEqual(sa, self.subaddr)
self.assertEqual(self.subaddr, sa)
self.assertEqual(sa.is_mainnet(), self.mainnet)
self.assertEqual(sa.is_testnet(), self.testnet)
self.assertEqual(sa.is_stagenet(), self.stagenet)
self.assertEqual(sa2.is_mainnet(), self.mainnet)
self.assertEqual(sa2.is_testnet(), self.testnet)
self.assertEqual(sa2.is_stagenet(), self.stagenet)
self.assertNotEqual(a, 0)
@ -120,7 +132,9 @@ class AddressTestCase(unittest.TestCase, Tests):
pid = '4a6f686e47616c74'
subaddr = '83bK2pMxCQXdRyd6W1haNWYRsF6Qb3iGa8gxKEynm9U7cYoXrMHFwRrFFuxRSgnLtGe7LM8SmrPY6L3TVBa3UV3YLuVJ7Rw'
iaddr = '4DHKLPmWW8aBoEbSyzKVbbDRmc8nsnpZLUpQBYvhUxs3KVrodnaFaBEQMDp69u4VaiEG3LSQXA6M61mXPrztCLuhAR6GpL18QNwE8h3TuF'
mainnet = True
testnet = False
stagenet = False
addr_invalid = '43aeKax1ts4boEbSyzKVbbDRmc8nsnpZLUpQBYvhUxs3KVrodnaFaBEQMDp69u4VaiEG3LSQXA6M61mXPrztCLuh7PFUAmd'
iaddr_invalid = '4DHKLpmWW8aBoEbSyzKVbbDRmc8nsnpZLUpQBYvhUxs3KVrodnaFaBEQMDp69u4VaiEG3LSQXA6M61mXPrztCLuhAR6GpL18QNwE8h3TuF'
@ -132,6 +146,22 @@ class TestnetAddressTestCase(AddressTestCase, Tests):
pid = '4a6f686e47616c74'
iaddr = 'A6PA4wkzmeyWik5QSUSoGYicdvvsbSNHrT9Arsx1XBTz6VrWPSgfmnUKSPZDMyX4Ms8R9TkhB4uFqK9s5LUBbV6YbfyqvDecDn3E7cvp9b'
subaddr = 'BbBjyYoYNNwFfL8RRVRTMiZUofBLpjRxdNnd5E4LyGcAK5CEsnL3gmE5QkrDRta7RPficGHcFdR6rUwWcjnwZVvCE3tLxhJ'
mainnet = False
testnet = True
stagenet = False
addr_invalid = '9vgV48wWAPTWik5QSUSoGYicdvvsbSNHrT9Arsx1XBTz6VrWPSgfmnUKSPZDMyX4Ms8R9TkhB4uFqK9s5LUbbV6YQN2Q9ag'
iaddr_invalid = 'A6PA4wkzmeyWik5qSUSoGYicdvvsbSNHrT9Arsx1XBTz6VrWPSgfmnUKSPZDMyX4Ms8R9TkhB4uFqK9s5LUBbV6YbfyqvDecDn3E7cvp9b'
class StagenetAddressTestCase(AddressTestCase, Tests):
addr = '56cXYWG13YKaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkeUVogGN3'
psk = '7e33891fe6ea30c7fd79d48e250906329104dc77407cf732699f41564df8ca8e'
pvk = '77a3720428f91f0f58a196bb374f703b3ca45fa55f0764adc81ff241c4c797f3'
pid = '4a6f686e47616c74'
iaddr = '5GKCZK5VeoqaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkehhE4RH8N7QfEAC8jMy'
subaddr = '7417qYoKBoYXCugU2KvJBZExmyjav4n1MVME74AeWNwxQ39wKtbWdyP6YGuMK6C7HkAjBuVcbUYmCWbxDLwk9GAX4qyb48U'
mainnet = False
testnet = False
stagenet = True
addr_invalid ='7417qYoKBoYXCugU2KvJBZExmyjav4n1MVME74AeWNwxQ39wKtbWdyP6YGuMK6C7HkAjBuVcbUYmCWbyDLwk9GAX4qyb48U'
iaddr_invalid = '5GKCZK5VeuqaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkehhE4RH8N7QfEAC8jMy'