refactor(core/cardano): decouple address parameters validation

pull/1666/head
gabrielkerekes 3 years ago committed by matejcik
parent d6776d988e
commit 597402eab8

@ -8,7 +8,6 @@
"parameters": {
"path": "m/1852'/1815'/0'/0/0",
"address_type": "enterprise",
"staking_key_hash": "1bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff",
"network_id": 1,
"protocol_magic": 764824073
},
@ -20,7 +19,6 @@
"parameters": {
"path": "m/1852'/1815'/0'/0/0",
"address_type": "enterprise",
"staking_key_hash": "1bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff",
"network_id": 0,
"protocol_magic": 42
},

@ -230,7 +230,7 @@
]
},
"result": {
"error_message": "Output address network mismatch!"
"error_message": "Output address network mismatch"
}
},
{
@ -258,7 +258,7 @@
]
},
"result": {
"error_message": "Output address network mismatch!"
"error_message": "Output address network mismatch"
}
},
{

@ -1,9 +1,15 @@
from trezor import wire
from trezor.crypto import base58, hashlib
from trezor.enums import CardanoAddressType
from .byron_address import derive_byron_address, validate_byron_address
from .helpers import INVALID_ADDRESS, NETWORK_MISMATCH, bech32, network_ids
from .helpers import (
ADDRESS_KEY_HASH_SIZE,
INVALID_ADDRESS,
INVALID_ADDRESS_PARAMETERS,
NETWORK_MISMATCH,
bech32,
network_ids,
)
from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT
from .helpers.utils import derive_public_key, variable_length_encode
from .seed import is_byron_path, is_shelley_path
@ -31,6 +37,70 @@ MIN_ADDRESS_BYTES_LENGTH = 29
MAX_ADDRESS_BYTES_LENGTH = 65
def validate_address_parameters(parameters: CardanoAddressParametersType) -> None:
_validate_address_parameters_structure(parameters)
if parameters.address_type == CardanoAddressType.BYRON:
if not is_byron_path(parameters.address_n):
raise INVALID_ADDRESS_PARAMETERS
elif parameters.address_type in ADDRESS_TYPES_SHELLEY:
if not is_shelley_path(parameters.address_n):
raise INVALID_ADDRESS_PARAMETERS
if parameters.address_type == CardanoAddressType.BASE:
_validate_base_address_staking_info(
parameters.address_n_staking, parameters.staking_key_hash
)
elif parameters.address_type == CardanoAddressType.POINTER:
if parameters.certificate_pointer is None:
raise INVALID_ADDRESS_PARAMETERS
elif parameters.address_type == CardanoAddressType.REWARD:
if not SCHEMA_STAKING_ANY_ACCOUNT.match(parameters.address_n):
raise INVALID_ADDRESS_PARAMETERS
else:
raise INVALID_ADDRESS_PARAMETERS
def _validate_address_parameters_structure(
parameters: CardanoAddressParametersType,
) -> None:
address_n_staking = parameters.address_n_staking
staking_key_hash = parameters.staking_key_hash
certificate_pointer = parameters.certificate_pointer
fields_to_be_empty: tuple = ()
if parameters.address_type in (
CardanoAddressType.BYRON,
CardanoAddressType.REWARD,
CardanoAddressType.ENTERPRISE,
):
fields_to_be_empty = (address_n_staking, staking_key_hash, certificate_pointer)
elif parameters.address_type == CardanoAddressType.BASE:
fields_to_be_empty = (certificate_pointer,)
elif parameters.address_type == CardanoAddressType.POINTER:
fields_to_be_empty = (address_n_staking, staking_key_hash)
if any(fields_to_be_empty):
raise INVALID_ADDRESS_PARAMETERS
def _validate_base_address_staking_info(
staking_path: list[int],
staking_key_hash: bytes | None,
) -> None:
if staking_key_hash and staking_path:
raise INVALID_ADDRESS_PARAMETERS
if staking_key_hash:
if len(staking_key_hash) != ADDRESS_KEY_HASH_SIZE:
raise INVALID_ADDRESS_PARAMETERS
elif staking_path:
if not SCHEMA_STAKING_ANY_ACCOUNT.match(staking_path):
raise INVALID_ADDRESS_PARAMETERS
else:
raise INVALID_ADDRESS_PARAMETERS
def _validate_address_and_get_type(
address: str, protocol_magic: int, network_id: int
) -> int:
@ -142,7 +212,7 @@ def _get_address_network_id(address: bytes) -> int:
def get_public_key_hash(keychain: seed.Keychain, path: list[int]) -> bytes:
public_key = derive_public_key(keychain, path)
return hashlib.blake2b(data=public_key, outlen=28).digest()
return hashlib.blake2b(data=public_key, outlen=ADDRESS_KEY_HASH_SIZE).digest()
def derive_human_readable_address(
@ -180,31 +250,18 @@ def derive_address_bytes(
is_byron_address = parameters.address_type == CardanoAddressType.BYRON
if is_byron_address:
address = _derive_byron_address(keychain, parameters.address_n, protocol_magic)
address = derive_byron_address(keychain, parameters.address_n, protocol_magic)
else:
address = _derive_shelley_address(keychain, parameters, network_id)
return address
def _derive_byron_address(
keychain: seed.Keychain, path: list[int], protocol_magic: int
) -> bytes:
if not is_byron_path(path):
raise wire.DataError("Invalid path for byron address!")
address = derive_byron_address(keychain, path, protocol_magic)
return address
def _derive_shelley_address(
keychain: seed.Keychain,
parameters: CardanoAddressParametersType,
network_id: int,
) -> bytes:
if not is_shelley_path(parameters.address_n):
raise wire.DataError("Invalid path for shelley address!")
if parameters.address_type == CardanoAddressType.BASE:
address = _derive_base_address(
keychain,
@ -213,21 +270,22 @@ def _derive_shelley_address(
parameters.staking_key_hash,
network_id,
)
elif parameters.address_type == CardanoAddressType.ENTERPRISE:
address = _derive_enterprise_address(keychain, parameters.address_n, network_id)
elif parameters.address_type == CardanoAddressType.POINTER:
if parameters.certificate_pointer is None:
raise wire.DataError("Certificate pointer data missing!")
# ensured by validate_address_parameters
assert parameters.certificate_pointer is not None
address = _derive_pointer_address(
keychain,
parameters.address_n,
parameters.certificate_pointer,
network_id,
)
elif parameters.address_type == CardanoAddressType.ENTERPRISE:
address = _derive_enterprise_address(keychain, parameters.address_n, network_id)
elif parameters.address_type == CardanoAddressType.REWARD:
address = _derive_reward_address(keychain, parameters.address_n, network_id)
else:
raise wire.DataError("Invalid address type!")
raise INVALID_ADDRESS_PARAMETERS
return address
@ -247,27 +305,12 @@ def _derive_base_address(
header = _create_address_header(CardanoAddressType.BASE, network_id)
spending_key_hash = get_public_key_hash(keychain, path)
_validate_base_address_staking_info(staking_path, staking_key_hash)
if staking_key_hash is None:
staking_key_hash = get_public_key_hash(keychain, staking_path)
return header + spending_key_hash + staking_key_hash
def _validate_base_address_staking_info(
staking_path: list[int],
staking_key_hash: bytes | None,
) -> None:
if (staking_key_hash is None) == (not staking_path):
raise wire.DataError(
"Base address needs either a staking path or a staking key hash!"
)
if staking_key_hash is None and not SCHEMA_STAKING_ANY_ACCOUNT.match(staking_path):
raise wire.DataError("Invalid staking path!")
def _derive_pointer_address(
keychain: seed.Keychain,
path: list[int],
@ -305,9 +348,6 @@ def _derive_reward_address(
path: list[int],
network_id: int,
) -> bytes:
if not SCHEMA_STAKING_ANY_ACCOUNT.match(path):
raise wire.DataError("Invalid path for reward address!")
staking_key_hash = get_public_key_hash(keychain, path)
return pack_reward_address_bytes(staking_key_hash, network_id)

@ -4,7 +4,11 @@ from trezor.enums import CardanoAddressType
from apps.common import cbor
from .address import derive_address_bytes, derive_human_readable_address
from .address import (
derive_address_bytes,
derive_human_readable_address,
validate_address_parameters,
)
from .helpers import INVALID_AUXILIARY_DATA, bech32
from .helpers.bech32 import HRP_JORMUN_PUBLIC_KEY
from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT
@ -36,12 +40,7 @@ METADATA_KEY_CATALYST_REGISTRATION = 61284
METADATA_KEY_CATALYST_REGISTRATION_SIGNATURE = 61285
def validate_auxiliary_data(
keychain: seed.Keychain,
auxiliary_data: CardanoTxAuxiliaryDataType | None,
protocol_magic: int,
network_id: int,
) -> None:
def validate_auxiliary_data(auxiliary_data: CardanoTxAuxiliaryDataType | None) -> None:
if not auxiliary_data:
return
@ -52,10 +51,7 @@ def validate_auxiliary_data(
if auxiliary_data.catalyst_registration_parameters:
fields_provided += 1
_validate_catalyst_registration_parameters(
keychain,
auxiliary_data.catalyst_registration_parameters,
protocol_magic,
network_id,
auxiliary_data.catalyst_registration_parameters
)
if fields_provided != 1:
@ -72,10 +68,7 @@ def _validate_auxiliary_data_blob(auxiliary_data_blob: bytes) -> None:
def _validate_catalyst_registration_parameters(
keychain: seed.Keychain,
catalyst_registration_parameters: CardanoCatalystRegistrationParametersType,
protocol_magic: int,
network_id: int,
) -> None:
if (
len(catalyst_registration_parameters.voting_public_key)
@ -92,8 +85,7 @@ def _validate_catalyst_registration_parameters(
if address_parameters.address_type == CardanoAddressType.BYRON:
raise INVALID_AUXILIARY_DATA
# try to derive the address to validate it
derive_address_bytes(keychain, address_parameters, protocol_magic, network_id)
validate_address_parameters(address_parameters)
async def show_auxiliary_data(

@ -7,7 +7,7 @@ from .address import (
get_public_key_hash,
validate_reward_address,
)
from .helpers import INVALID_CERTIFICATE, LOVELACE_MAX_SUPPLY
from .helpers import ADDRESS_KEY_HASH_SIZE, INVALID_CERTIFICATE, LOVELACE_MAX_SUPPLY
from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT
if False:
@ -26,7 +26,6 @@ if False:
POOL_HASH_SIZE = 28
VRF_KEY_HASH_SIZE = 32
POOL_METADATA_HASH_SIZE = 32
PUBLIC_KEY_HASH_SIZE = 28
IPV4_ADDRESS_SIZE = 4
IPV6_ADDRESS_SIZE = 16
@ -140,7 +139,9 @@ def _validate_pool_owners(owners: list[CardanoPoolOwnerType]) -> None:
owner.staking_key_hash is not None or owner.staking_key_path is not None
)
if owner.staking_key_hash is not None:
assert_certificate_cond(len(owner.staking_key_hash) == PUBLIC_KEY_HASH_SIZE)
assert_certificate_cond(
len(owner.staking_key_hash) == ADDRESS_KEY_HASH_SIZE
)
if owner.staking_key_path:
assert_certificate_cond(
SCHEMA_STAKING_ANY_ACCOUNT.match(owner.staking_key_path)

@ -5,7 +5,7 @@ from apps.common import paths
from apps.common.layout import address_n_to_str, show_qr
from . import seed
from .address import derive_human_readable_address
from .address import derive_human_readable_address, validate_address_parameters
from .helpers import protocol_magics, staking_use_cases
from .helpers.paths import SCHEMA_ADDRESS
from .helpers.utils import to_account_path
@ -38,6 +38,7 @@ async def get_address(
)
validate_network_info(msg.network_id, msg.protocol_magic)
validate_address_parameters(address_parameters)
try:
address = derive_human_readable_address(

@ -1,7 +1,8 @@
from trezor import wire
INVALID_ADDRESS = wire.ProcessError("Invalid address")
NETWORK_MISMATCH = wire.ProcessError("Output address network mismatch!")
INVALID_ADDRESS_PARAMETERS = wire.ProcessError("Invalid address parameters")
NETWORK_MISMATCH = wire.ProcessError("Output address network mismatch")
INVALID_CERTIFICATE = wire.ProcessError("Invalid certificate")
INVALID_WITHDRAWAL = wire.ProcessError("Invalid withdrawal")
INVALID_TOKEN_BUNDLE_OUTPUT = wire.ProcessError("Invalid token bundle in output")
@ -14,3 +15,4 @@ INVALID_STAKEPOOL_REGISTRATION_TX_INPUTS = wire.ProcessError(
)
LOVELACE_MAX_SUPPLY = 45_000_000_000 * 1_000_000
ADDRESS_KEY_HASH_SIZE = 28

@ -17,6 +17,7 @@ from .address import (
derive_address_bytes,
derive_human_readable_address,
get_address_bytes_unsafe,
validate_address_parameters,
validate_output_address,
)
from .auxiliary_data import (
@ -135,12 +136,10 @@ async def _sign_ordinary_tx(
ctx, keychain, i.address_n, SCHEMA_ADDRESS.match(i.address_n)
)
_validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id)
_validate_outputs(msg.outputs, msg.protocol_magic, msg.network_id)
_validate_certificates(msg.certificates, msg.protocol_magic, msg.network_id)
_validate_withdrawals(msg.withdrawals)
validate_auxiliary_data(
keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id
)
validate_auxiliary_data(msg.auxiliary_data)
# display the transaction in UI
await _show_standard_tx(ctx, keychain, msg)
@ -166,11 +165,9 @@ async def _sign_stake_pool_registration_tx(
_validate_stake_pool_registration_tx_structure(msg)
_ensure_no_signing_inputs(msg.inputs)
_validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id)
_validate_outputs(msg.outputs, msg.protocol_magic, msg.network_id)
_validate_certificates(msg.certificates, msg.protocol_magic, msg.network_id)
validate_auxiliary_data(
keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id
)
validate_auxiliary_data(msg.auxiliary_data)
await _show_stake_pool_registration_tx(ctx, keychain, msg)
@ -209,7 +206,6 @@ def _validate_stake_pool_registration_tx_structure(msg: CardanoSignTx) -> None:
def _validate_outputs(
keychain: seed.Keychain,
outputs: list[CardanoTxOutputType],
protocol_magic: int,
network_id: int,
@ -218,10 +214,7 @@ def _validate_outputs(
for output in outputs:
total_amount += output.amount
if output.address_parameters:
# try to derive the address to validate it
derive_address_bytes(
keychain, output.address_parameters, protocol_magic, network_id
)
validate_address_parameters(output.address_parameters)
elif output.address is not None:
validate_output_address(output.address, protocol_magic, network_id)
else:

@ -8,7 +8,7 @@ from trezor.messages import CardanoBlockchainPointerType
from apps.common import HARDENED, seed
if not utils.BITCOIN_ONLY:
from apps.cardano.address import derive_human_readable_address
from apps.cardano.address import derive_human_readable_address, validate_address_parameters
from apps.cardano.byron_address import _address_hash
from apps.cardano.helpers import network_ids, protocol_magics
from apps.cardano.seed import Keychain
@ -335,32 +335,6 @@ class TestCardanoAddress(unittest.TestCase):
self.assertEqual(actual_address, expected_address)
def test_base_address_with_invalid_parameters(self):
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
passphrase = ""
node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
keychain = Keychain(node)
# both address_n_staking and staking_key_hash are None
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
address_n_staking=None,
staking_key_hash=None,
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
# address_n_staking is not a staking path
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
address_n_staking=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
staking_key_hash=None,
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
def test_enterprise_address(self):
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
passphrase = ""
@ -404,21 +378,6 @@ class TestCardanoAddress(unittest.TestCase):
self.assertEqual(actual_address, expected_address)
def test_pointer_address_invalid_pointers(self):
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
passphrase = ""
node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
keychain = Keychain(node)
# pointer is None
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.POINTER,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
certificate_pointer=None,
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
def test_reward_address(self):
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
passphrase = ""
@ -440,95 +399,99 @@ class TestCardanoAddress(unittest.TestCase):
self.assertEqual(actual_address, expected_address)
def test_reward_address_with_non_staking_path(self):
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
def test_testnet_byron_address(self):
mnemonic = "all all all all all all all all all all all all"
passphrase = ""
node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
keychain = Keychain(node)
with self.assertRaises(wire.DataError):
addresses = [
"2657WMsDfac5F3zbgs9BwNWx3dhGAJERkAL93gPa68NJ2i8mbCHm2pLUHWSj8Mfea",
"2657WMsDfac6ezKWszxLFqJjSUgpg9NgxKc1koqi24sVpRaPhiwMaExk4useKn5HA",
"2657WMsDfac7hr1ioJGr6g7r6JRx4r1My8Rj91tcPTeVjJDpfBYKURrPG2zVLx2Sq",
]
for i, expected in enumerate(addresses):
# 44'/1815'/0'/0/i'
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.REWARD,
address_n=[44 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0]
address_type=CardanoAddressType.BYRON,
address_n=[0x80000000 | 44, 0x80000000 | 1815, 0x80000000, 0, i],
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
address = derive_human_readable_address(keychain, address_parameters, protocol_magics.TESTNET, 0)
self.assertEqual(expected, address)
def test_shelley_address_with_byron_namespace(self):
"""
It shouldn't be possible to derive Shelley addresses
(Base, Pointer, Enterprise, Reward) with a Byron namespace (44')
"""
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
passphrase = ""
node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
keychain = Keychain(node)
def test_validate_address_parameters(self):
test_vectors = [
# base address - both address_n_staking and staking_key_hash are None
CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
address_n_staking=None,
staking_key_hash=None,
),
# base address - both address_n_staking and staking_key_hash are set
CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
address_n_staking=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 2, 0],
staking_key_hash=unhexlify("1bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff"),
),
# base address - staking_key_hash is too short
CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
address_n_staking=None,
staking_key_hash=unhexlify("1bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8d"),
),
# base address - address_n_staking is not a staking path
CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
address_n_staking=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
staking_key_hash=None,
),
# pointer address - pointer is None
CardanoAddressParametersType(
address_type=CardanoAddressType.POINTER,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
certificate_pointer=None,
),
# reward address - non staking path
CardanoAddressParametersType(
address_type=CardanoAddressType.REWARD,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0]
),
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
# Shelley addresses with Byron namespace
CardanoAddressParametersType(
address_type=CardanoAddressType.BASE,
address_n=[44 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0]
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
),
CardanoAddressParametersType(
address_type=CardanoAddressType.POINTER,
address_n=[44 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
certificate_pointer=CardanoBlockchainPointerType(block_index=0, tx_index=0, certificate_index=0)
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
),
CardanoAddressParametersType(
address_type=CardanoAddressType.ENTERPRISE,
address_n=[44 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
),
CardanoAddressParametersType(
address_type=CardanoAddressType.REWARD,
address_n=[44 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
def test_byron_address_with_shelley_namespace(self):
"""
It shouldn't be possible to derive Byron addresses
with a Shelley namespace (1852')
"""
mnemonic = "all all all all all all all all all all all all"
passphrase = ""
node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
keychain = Keychain(node)
),
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
# Byron address with Shelley namespace
CardanoAddressParametersType(
address_type=CardanoAddressType.BYRON,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
def test_testnet_byron_address(self):
mnemonic = "all all all all all all all all all all all all"
passphrase = ""
node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
keychain = Keychain(node)
addresses = [
"2657WMsDfac5F3zbgs9BwNWx3dhGAJERkAL93gPa68NJ2i8mbCHm2pLUHWSj8Mfea",
"2657WMsDfac6ezKWszxLFqJjSUgpg9NgxKc1koqi24sVpRaPhiwMaExk4useKn5HA",
"2657WMsDfac7hr1ioJGr6g7r6JRx4r1My8Rj91tcPTeVjJDpfBYKURrPG2zVLx2Sq",
]
for i, expected in enumerate(addresses):
# 44'/1815'/0'/0/i'
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.BYRON,
address_n=[0x80000000 | 44, 0x80000000 | 1815, 0x80000000, 0, i],
)
address = derive_human_readable_address(keychain, address_parameters, protocol_magics.TESTNET, 0)
self.assertEqual(expected, address)
for address_parameters in test_vectors:
with self.assertRaises(wire.ProcessError):
validate_address_parameters(address_parameters)
if __name__ == '__main__':
unittest.main()

Loading…
Cancel
Save