From d4dcd7bff9aaa87d2ba3f02b3ec4aa39dfc30eaa Mon Sep 17 00:00:00 2001 From: gabrielkerekes Date: Thu, 21 Jan 2021 10:32:23 +0100 Subject: [PATCH] fix(core/cardano): allow staking accounts beyond 100' --- .../fixtures/cardano/sign_tx.failed.json | 104 +++++++++++++++++ common/tests/fixtures/cardano/sign_tx.json | 110 ++++++++++++++++++ ...ign_tx_stake_pool_registration.failed.json | 83 +++++++++++++ .../sign_tx_stake_pool_registration.json | 85 ++++++++++++++ core/src/apps/cardano/address.py | 6 +- core/src/apps/cardano/certificates.py | 8 +- core/src/apps/cardano/helpers/paths.py | 7 ++ .../apps/cardano/helpers/staking_use_cases.py | 3 - core/src/apps/cardano/layout.py | 9 ++ core/src/apps/cardano/sign_tx.py | 63 +++++++++- tests/device_tests/cardano/test_sign_tx.py | 48 ++++---- tests/ui_tests/fixtures.json | 56 +++++---- 12 files changed, 522 insertions(+), 60 deletions(-) diff --git a/common/tests/fixtures/cardano/sign_tx.failed.json b/common/tests/fixtures/cardano/sign_tx.failed.json index 943d46b0fd..7bd8ac1c0d 100644 --- a/common/tests/fixtures/cardano/sign_tx.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.failed.json @@ -636,6 +636,110 @@ "error_message": "Invalid metadata" } }, + { + "description": "Change output path larger than 100", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + }, + { + "addressType": 0, + "path": "m/1852'/1815'/190'/0/0", + "stakingPath": "m/1852'/1815'/0'/2/0", + "amount": "7120787" + } + ] + }, + "result": { + "error_message": "Invalid change output path" + } + }, + { + "description": "Change output staking path larger than 100", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + }, + { + "addressType": 0, + "path": "m/1852'/1815'/0'/0/0", + "stakingPath": "m/1852'/1815'/190'/2/0", + "amount": "7120787" + } + ] + }, + "result": { + "error_message": "Invalid change output staking path" + } + }, + { + "description": "Stake deregistration account larger than 100", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 1, + "path": "m/1852'/1815'/190'/2/0" + } + ], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ] + }, + "result": { + "error_message": "Invalid certificate path" + } + }, { "description": "Too many tokens in output", "parameters": { diff --git a/common/tests/fixtures/cardano/sign_tx.json b/common/tests/fixtures/cardano/sign_tx.json index 8a937eb93d..88528f5f6d 100644 --- a/common/tests/fixtures/cardano/sign_tx.json +++ b/common/tests/fixtures/cardano/sign_tx.json @@ -186,6 +186,80 @@ "serialized_tx": "83a400818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7000182825839115e2f080eb93bad86d401545e0ce5f2221096d6477e11e6643922fa8d4dc0d667c1316ff84e572310e265edb31330448b36b7179e28dd419e1a006ca7938258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a006ca79302182a030aa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840e0bdaa59016f2a521d31179b60364eacdcb53c34ae01c56b339afa62d312f5f89783579691cac777e3d5f2e7810aa8fe554ba545a8d1578c55405af5ae51b30ff6" } }, + { + "description": "transaction with base address change output path larger than 100", + "parameters": { + "security_checks": "prompt", + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "YES"], ["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + }, + { + "addressType": 0, + "path": "m/1852'/1815'/190'/0/0", + "stakingPath": "m/1852'/1815'/0'/2/0", + "amount": "7120787" + } + ] + }, + "result": { + "tx_hash": "1fc82ce2420c173a0947eaf49af76fcd6f4e400e2bfb5fa152a482ea12dde24b", + "serialized_tx": "83a400818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018282583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0182583901606898e71f1e144b3a13b7dd355aa64472837b40eb5d11ed1e732112122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a006ca79302182a030aa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158404d8f0fd9798b62937b1739dcb893dfc6a0abd9eb2ad98244ced00d78949a2fd2751fac4bb2ebe5577688e5d9f47da79a52b5c571c3082996514ab5995dc2580df6" + } + }, + { + "description": "transaction with base address change output staking path account larger than 100", + "parameters": { + "security_checks": "prompt", + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + }, + { + "addressType": 0, + "path": "m/1852'/1815'/0'/0/0", + "stakingPath": "m/1852'/1815'/190'/2/0", + "amount": "7120787" + } + ] + }, + "result": { + "tx_hash": "abd1b24ac0638251398444ee136110f952738df32a512ce35894f8453d0e8edf", + "serialized_tx": "83a400818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018282583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff018258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa58e438148441c6409537ebd82bb04924362cce2912f3494693fcb0001a006ca79302182a030aa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158402de6b2f4651ad503abfb171a7ced0d88505b57a336dd3a8d2428f6584337e318f9bae2e7a0b2f76f96f5667b6c181a0e5e3e7a0592d541883893c6d43232d50ff6" + } + }, { "description": "simple transaction with base address change output with staking key hash", "parameters": { @@ -473,6 +547,42 @@ "serialized_tx": "83a600818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a048182018200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427705a1581de1122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771903e8a10082825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e58400202826a8b9688cf978000e7d1591582c65b149bb9f55dc883ae1acf85432618ca32be8a06fef37e69df503a294e7093006f63ababf9fcea639390226934020a8258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158407efa634e42fa844cad5f60bf005d645817cc674f30eaab0da398b99034850780b40ab5a1028da033330a0f82b01648ec92cff8ca85a072594efb298016f38d0df6" } }, + { + "description": "transaction with stake deregistration with account larger than 100", + "parameters": { + "security_checks": "prompt", + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 1, + "path": "m/1852'/1815'/190'/2/0" + } + ], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "YES"], ["YES"], ["YES"], ["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ] + }, + "result": { + "tx_hash": "cc068a25994ef6a90cdab8adfbe302d6f742de9901ba2495dd64a09f2ef951f5", + "serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a048182018200581c58e438148441c6409537ebd82bb04924362cce2912f3494693fcb000a10082825820d1a07f06b872c68120def0203d0fc3d582ac4ce3897d5eaf448026960875f76d5840b67d2af9de2bdfcf552f92ae12a16ed9f9cce9e34adbfe492ff75917a8a0277e125bac8f0dbdd0c4f11fd95ab6d94cb937a5b708f47ec338a00cab2931ba14038258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1584019b71c5b97a188cf9ff479b6ef7a45a0df94a917845d15c03a5fa508042724dcee1e8f944b91141ed91e6faa228806b3644e2560cb231470d09788ac5065ff00f6" + } + }, { "description": "transaction with metadata", "parameters": { diff --git a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json index 51a4ef279e..b0d4c19cb5 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json @@ -454,6 +454,89 @@ "result": { "error_message": "ProcessError: Invalid address" } + }, + { + "description": "Sample stake pool registration certificate with owner staking path account larger than 100", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 3, + "pool_parameters": { + "pool_id": "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973", + "vrf_key_hash": "198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d0640", + "pledge": 500000000, + "cost": 340000000, + "margin": { + "numerator": 1, + "denominator": 2 + }, + "reward_account": "stake1uya87zwnmax0v6nnn8ptqkl6ydx4522kpsc3l3wmf3yswygwx45el", + "owners": [ + { + "staking_key_path": "m/1852'/1815'/190'/2/0" + }, + { + "staking_key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "relays": [ + { + "type": 0, + "ipv4_address": "192.168.0.1", + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv4_address": "192.168.0.1", + "port": 1234 + }, + { + "type": 1, + "host_name": "www.test.test", + "port": 1234 + }, + { + "type": 2, + "host_name": "www.test2.test" + } + ], + "metadata": { + "url": "https://www.test.test", + "hash": "914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6" + } + } + } + ], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "SWIPE", "YES"]], + "inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ] + }, + "result": { + "error_message": "Invalid pool owner staking path" + } } ] } diff --git a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json index b0b3cf9e6c..71f319cd12 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json @@ -88,6 +88,91 @@ "serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a04818a03581cf61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb49735820198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d06401a1dcd65001a1443fd00d81e820102581de13a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c49071182581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c4907118584001904d244c0a8000150b80d01200000a3852e8a00003473700384001904d2f650b80d01200000a3852e8a00003473700384001904d244c0a80001f683011904d26d7777772e746573742e7465737482026e7777772e74657374322e74657374827568747470733a2f2f7777772e746573742e746573745820914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6a10081825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e584006305b52f76d2d2da6925c02036a9a28456976009f8c6432513f273110d09ea26db79c696cec322b010e5cbb7d90a6b473b157e65df846a1487062569a5f5a04f6" } }, + { + "description": "Sample stake pool registration certificate with owner staking path account larger than 100", + "parameters": { + "security_checks": "prompt", + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 3, + "pool_parameters": { + "pool_id": "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973", + "vrf_key_hash": "198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d0640", + "pledge": 500000000, + "cost": 340000000, + "margin": { + "numerator": 1, + "denominator": 2 + }, + "reward_account": "stake1uya87zwnmax0v6nnn8ptqkl6ydx4522kpsc3l3wmf3yswygwx45el", + "owners": [ + { + "staking_key_path": "m/1852'/1815'/190'/2/0" + }, + { + "staking_key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "relays": [ + { + "type": 0, + "ipv4_address": "192.168.0.1", + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv4_address": "192.168.0.1", + "port": 1234 + }, + { + "type": 1, + "host_name": "www.test.test", + "port": 1234 + }, + { + "type": 2, + "host_name": "www.test2.test" + } + ], + "metadata": { + "url": "https://www.test.test", + "hash": "914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6" + } + } + } + ], + "withdrawals": [], + "metadata": "", + "input_flow": [["SWIPE", "SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["YES"], ["YES"]], + "inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ] + }, + "result": { + "tx_hash": "f3d62758ff2f520e7256e65be9d8165da60c7979a97202c19d625709412411fd", + "serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a04818a03581cf61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb49735820198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d06401a1dcd65001a1443fd00d81e820102581de13a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c49071182581c58e438148441c6409537ebd82bb04924362cce2912f3494693fcb000581c3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c4907118584001904d244c0a8000150b80d01200000a3852e8a00003473700384001904d2f650b80d01200000a3852e8a00003473700384001904d244c0a80001f683011904d26d7777772e746573742e7465737482026e7777772e74657374322e74657374827568747470733a2f2f7777772e746573742e746573745820914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6a10081825820d1a07f06b872c68120def0203d0fc3d582ac4ce3897d5eaf448026960875f76d5840c61890be9a2c964f2b64cbd6a91ac6a56332d28ea773855c86e3cd0d1693ae61e9bc053143d2aba14a721fae77edde70ee736b17a761e7b823d87071a4852205f6" + } + }, { "description": "Stake pool registration certificate with no pool metadata", "parameters": { diff --git a/core/src/apps/cardano/address.py b/core/src/apps/cardano/address.py index 3067b52882..5cfc9cd904 100644 --- a/core/src/apps/cardano/address.py +++ b/core/src/apps/cardano/address.py @@ -6,7 +6,7 @@ from apps.common.seed import remove_ed25519_prefix from .byron_address import derive_byron_address, validate_byron_address from .helpers import INVALID_ADDRESS, NETWORK_MISMATCH, bech32, network_ids -from .helpers.paths import SCHEMA_STAKING +from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT from .helpers.utils import variable_length_encode from .seed import is_byron_path, is_shelley_path @@ -273,7 +273,7 @@ def _validate_base_address_staking_info( "Base address needs either a staking path or a staking key hash!" ) - if staking_key_hash is None and not SCHEMA_STAKING.match(staking_path): + if staking_key_hash is None and not SCHEMA_STAKING_ANY_ACCOUNT.match(staking_path): raise wire.DataError("Invalid staking path!") @@ -314,7 +314,7 @@ def _derive_reward_address( path: List[int], network_id: int, ) -> bytes: - if not SCHEMA_STAKING.match(path): + 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) diff --git a/core/src/apps/cardano/certificates.py b/core/src/apps/cardano/certificates.py index 7b64b41cd4..bd34a058f9 100644 --- a/core/src/apps/cardano/certificates.py +++ b/core/src/apps/cardano/certificates.py @@ -8,7 +8,7 @@ from .address import ( validate_reward_address, ) from .helpers import INVALID_CERTIFICATE, LOVELACE_MAX_SUPPLY -from .helpers.paths import SCHEMA_STAKING +from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT if False: from typing import List, Optional @@ -44,7 +44,7 @@ def validate_certificate( CardanoCertificateType.STAKE_REGISTRATION, CardanoCertificateType.STAKE_DEREGISTRATION, ): - if not SCHEMA_STAKING.match(certificate.path): + if not SCHEMA_STAKING_ANY_ACCOUNT.match(certificate.path): raise INVALID_CERTIFICATE if certificate.type == CardanoCertificateType.STAKE_DELEGATION: @@ -144,7 +144,9 @@ def _validate_pool_owners(owners: List[CardanoPoolOwnerType]) -> None: if owner.staking_key_hash is not None: assert_certificate_cond(len(owner.staking_key_hash) == PUBLIC_KEY_HASH_SIZE) if owner.staking_key_path: - assert_certificate_cond(SCHEMA_STAKING.match(owner.staking_key_path)) + assert_certificate_cond( + SCHEMA_STAKING_ANY_ACCOUNT.match(owner.staking_key_path) + ) if owner.staking_key_path: owners_as_path_count += 1 diff --git a/core/src/apps/cardano/helpers/paths.py b/core/src/apps/cardano/helpers/paths.py index 6eb645acc8..1a23472d35 100644 --- a/core/src/apps/cardano/helpers/paths.py +++ b/core/src/apps/cardano/helpers/paths.py @@ -13,14 +13,21 @@ SCHEMA_PUBKEY = PathSchema("m/[44,1852]'/coin_type'/account'/*", SLIP44_ID) SCHEMA_ADDRESS = PathSchema("m/[44,1852]'/coin_type'/account'/[0,1,2]/address_index", SLIP44_ID) # staking is only allowed on Shelley paths with suffix /2/0 SCHEMA_STAKING = PathSchema("m/1852'/coin_type'/account'/2/0", SLIP44_ID) +SCHEMA_STAKING_ANY_ACCOUNT = PathSchema("m/1852'/coin_type'/[0-%s]'/2/0" % (HARDENED - 1), SLIP44_ID) # fmt: on # the maximum allowed change address. this should be large enough for normal # use and still allow to quickly brute-force the correct bip32 path MAX_CHANGE_ADDRESS_INDEX = const(1_000_000) +MAX_ACCOUNT_INDEX = const(100) ACCOUNT_PATH_INDEX = const(2) BIP_PATH_LENGTH = const(5) +CHANGE_OUTPUT_PATH_NAME = "Change output path" +CHANGE_OUTPUT_STAKING_PATH_NAME = "Change output staking path" +CERTIFICATE_PATH_NAME = "Certificate path" +POOL_OWNER_STAKING_PATH_NAME = "Pool owner staking path" + def unharden(item: int) -> int: return item ^ (item & HARDENED) diff --git a/core/src/apps/cardano/helpers/staking_use_cases.py b/core/src/apps/cardano/helpers/staking_use_cases.py index 5c776e77d2..e4f8ec2bc2 100644 --- a/core/src/apps/cardano/helpers/staking_use_cases.py +++ b/core/src/apps/cardano/helpers/staking_use_cases.py @@ -2,7 +2,6 @@ from trezor.messages import CardanoAddressType from ..address import get_public_key_hash from ..seed import is_shelley_path -from .paths import SCHEMA_ADDRESS from .utils import to_account_path if False: @@ -29,8 +28,6 @@ POINTER_ADDRESS = 3 def get(keychain: Keychain, address_parameters: CardanoAddressParametersType) -> int: address_type = address_parameters.address_type if address_type == CardanoAddressType.BASE: - if not SCHEMA_ADDRESS.match(address_parameters.address_n): - return MISMATCH if not is_shelley_path(address_parameters.address_n): return MISMATCH diff --git a/core/src/apps/cardano/layout.py b/core/src/apps/cardano/layout.py index aacfc45521..02d4bb85ce 100644 --- a/core/src/apps/cardano/layout.py +++ b/core/src/apps/cardano/layout.py @@ -140,6 +140,15 @@ async def show_warning_tx_output_contains_tokens(ctx: wire.Context) -> None: await require_confirm(ctx, page1) +async def show_warning_path(ctx: wire.Context, path: List[int], title: str) -> None: + page1 = Text("Confirm path", ui.ICON_WRONG, ui.RED) + page1.normal(title) + page1.bold(address_n_to_str(path)) + page1.normal("is unknown.") + page1.normal("Are you sure?") + await require_confirm(ctx, page1) + + async def show_warning_tx_no_staking_info( ctx: wire.Context, address_type: EnumTypeCardanoAddressType, amount: int ) -> None: diff --git a/core/src/apps/cardano/sign_tx.py b/core/src/apps/cardano/sign_tx.py index f34a5e6eb0..339cad22f8 100644 --- a/core/src/apps/cardano/sign_tx.py +++ b/core/src/apps/cardano/sign_tx.py @@ -5,7 +5,7 @@ from trezor.messages import CardanoAddressType, CardanoCertificateType from trezor.messages.CardanoAddressParametersType import CardanoAddressParametersType from trezor.messages.CardanoSignedTx import CardanoSignedTx -from apps.common import cbor +from apps.common import cbor, safety_checks from apps.common.paths import validate_path from apps.common.seed import remove_ed25519_prefix @@ -32,9 +32,15 @@ from .helpers import ( from .helpers.paths import ( ACCOUNT_PATH_INDEX, BIP_PATH_LENGTH, + CERTIFICATE_PATH_NAME, + CHANGE_OUTPUT_PATH_NAME, + CHANGE_OUTPUT_STAKING_PATH_NAME, + MAX_ACCOUNT_INDEX, MAX_CHANGE_ADDRESS_INDEX, + POOL_OWNER_STAKING_PATH_NAME, SCHEMA_ADDRESS, SCHEMA_STAKING, + SCHEMA_STAKING_ANY_ACCOUNT, ) from .helpers.utils import to_account_path from .layout import ( @@ -47,6 +53,7 @@ from .layout import ( confirm_transaction, confirm_transaction_network_ttl, confirm_withdrawal, + show_warning_path, show_warning_tx_different_staking_account, show_warning_tx_network_unverifiable, show_warning_tx_no_staking_info, @@ -67,10 +74,12 @@ if False: from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType from apps.common.cbor import CborSequence + from apps.common.paths import PathSchema CborizedTokenBundle = Dict[bytes, Dict[bytes, int]] CborizedTxOutput = Tuple[bytes, Union[int, Tuple[int, CborizedTokenBundle]]] + METADATA_HASH_SIZE = 32 MINTING_POLICY_ID_LENGTH = 28 MAX_METADATA_LENGTH = 500 @@ -283,7 +292,7 @@ def _validate_certificates( def _validate_withdrawals(withdrawals: List[CardanoTxWithdrawalType]) -> None: for withdrawal in withdrawals: - if not SCHEMA_STAKING.match(withdrawal.path): + if not SCHEMA_STAKING_ANY_ACCOUNT.match(withdrawal.path): raise INVALID_WITHDRAWAL if not 0 <= withdrawal.amount < LOVELACE_MAX_SUPPLY: @@ -568,9 +577,13 @@ async def _show_standard_tx( if not is_network_id_verifiable: await show_warning_tx_network_unverifiable(ctx) + total_amount = await _show_outputs(ctx, keychain, msg) for certificate in msg.certificates: + await _fail_or_warn_if_invalid_path( + ctx, SCHEMA_STAKING, certificate.path, CERTIFICATE_PATH_NAME + ) await confirm_certificate(ctx, certificate) for withdrawal in msg.withdrawals: @@ -602,6 +615,16 @@ async def _show_stake_pool_registration_tx( await confirm_stake_pool_parameters( ctx, pool_parameters, msg.network_id, msg.protocol_magic ) + + for owner in pool_parameters.owners: + if owner.staking_key_path: + await _fail_or_warn_if_invalid_path( + ctx, + SCHEMA_STAKING, + owner.staking_key_path, + POOL_OWNER_STAKING_PATH_NAME, + ) + await confirm_stake_pool_owners( ctx, keychain, pool_parameters.owners, msg.network_id ) @@ -618,16 +641,23 @@ async def _show_outputs( total_amount = 0 for output in msg.outputs: if output.address_parameters: - address = derive_human_readable_address( - keychain, output.address_parameters, msg.protocol_magic, msg.network_id + await _fail_or_warn_if_invalid_path( + ctx, + SCHEMA_ADDRESS, + output.address_parameters.address_n, + CHANGE_OUTPUT_PATH_NAME, ) await _show_change_output_staking_warnings( - ctx, keychain, output.address_parameters, address, output.amount + ctx, keychain, output.address_parameters, output.amount ) if _should_hide_output(output.address_parameters.address_n, msg.inputs): continue + + address = derive_human_readable_address( + keychain, output.address_parameters, msg.protocol_magic, msg.network_id + ) else: assert output.address is not None # _validate_outputs address = output.address @@ -646,11 +676,21 @@ async def _show_change_output_staking_warnings( ctx: wire.Context, keychain: seed.Keychain, address_parameters: CardanoAddressParametersType, - address: str, amount: int, ) -> None: address_type = address_parameters.address_type + if ( + address_type == CardanoAddressType.BASE + and not address_parameters.staking_key_hash + ): + await _fail_or_warn_if_invalid_path( + ctx, + SCHEMA_STAKING, + address_parameters.address_n_staking, + CHANGE_OUTPUT_STAKING_PATH_NAME, + ) + staking_use_case = staking_use_cases.get(keychain, address_parameters) if staking_use_case == staking_use_cases.NO_STAKING: await show_warning_tx_no_staking_info(ctx, address_type, amount) @@ -686,6 +726,7 @@ def _should_hide_output(output: List[int], inputs: List[CardanoTxInputType]) -> if ( len(output) != BIP_PATH_LENGTH or output[: (ACCOUNT_PATH_INDEX + 1)] != inp[: (ACCOUNT_PATH_INDEX + 1)] + or output[(ACCOUNT_PATH_INDEX + 1)] > MAX_ACCOUNT_INDEX or output[-2] >= 2 or output[-1] >= MAX_CHANGE_ADDRESS_INDEX ): @@ -704,3 +745,13 @@ def _is_network_id_verifiable(msg: CardanoSignTx) -> bool: or len(msg.withdrawals) != 0 or _has_stake_pool_registration(msg) ) + + +async def _fail_or_warn_if_invalid_path( + ctx: wire.Context, schema: PathSchema, path: List[int], path_name: str +) -> None: + if not schema.match(path): + if safety_checks.is_strict(): + raise wire.DataError("Invalid %s" % path_name.lower()) + else: + await show_warning_path(ctx, path, path_name) diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index 2ff9656eb0..6d18b07b5a 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -16,7 +16,7 @@ import pytest -from trezorlib import cardano, messages +from trezorlib import cardano, device, messages from trezorlib.exceptions import TrezorFailure from ...common import parametrize_using_common_fixtures @@ -39,27 +39,18 @@ def test_cardano_sign_tx(client, parameters, result): certificates = [cardano.create_certificate(c) for c in parameters["certificates"]] withdrawals = [cardano.create_withdrawal(w) for w in parameters["withdrawals"]] - expected_responses = [messages.PassphraseRequest()] - expected_responses += [ - messages.ButtonRequest(code=messages.ButtonRequestType.Other) - for i in range(len(parameters["input_flow"])) - ] - expected_responses.append(messages.CardanoSignedTx()) + input_flow = parameters.get("input_flow", ()) - def input_flow(): - for sequence in parameters["input_flow"]: - yield - for action in sequence: - if action == "SWIPE": - client.debug.swipe_up() - elif action == "YES": - client.debug.press_yes() - else: - raise ValueError("Invalid input action") + if parameters.get("security_checks") == "prompt": + device.apply_settings( + client, safety_checks=messages.SafetyCheckLevel.PromptTemporarily + ) + else: + device.apply_settings(client, safety_checks=messages.SafetyCheckLevel.Strict) with client: - client.set_expected_responses(expected_responses) - client.set_input_flow(input_flow) + client.set_input_flow(_to_device_actions(client, input_flow)) + response = cardano.sign_tx( client=client, inputs=inputs, @@ -86,10 +77,10 @@ def test_cardano_sign_tx_failed(client, parameters, result): certificates = [cardano.create_certificate(c) for c in parameters["certificates"]] withdrawals = [cardano.create_withdrawal(w) for w in parameters["withdrawals"]] - expected_responses = [messages.PassphraseRequest(), messages.Failure()] + input_flow = parameters.get("input_flow", ()) with client: - client.set_expected_responses(expected_responses) + client.set_input_flow(_to_device_actions(client, input_flow)) with pytest.raises(TrezorFailure, match=result["error_message"]): cardano.sign_tx( @@ -105,3 +96,18 @@ def test_cardano_sign_tx_failed(client, parameters, result): protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], ) + + +def _to_device_actions(client, input_flow): + if not input_flow: + yield + + for sequence in input_flow: + yield + for action in sequence: + if action == "SWIPE": + client.debug.swipe_up() + elif action == "YES": + client.debug.press_yes() + else: + raise ValueError("Invalid input action") diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index a9fd98585b..06f5f20e88 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -1,31 +1,37 @@ { -"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "5e2334cff9d0946ec722d69d7065023d707d8208a0ceee928824fd006edb93ad", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "1ac78675dd64f4acbf7cf8f24bc1492bec5f0bce32a3f860742d5fa1922afb24", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "8151b1b3cfa5ef79a256409d78b0219eb43b8fb498776b16e2f43bb5c9a38c55", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "8151b1b3cfa5ef79a256409d78b0219eb43b8fb498776b16e2f43bb5c9a38c55", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "66a8f9e4a2590c304046c8802673fb373d3fa9f3baa03dbc361818dd56fb1eab", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "accbbaba30610e45d9cbd74a3a6693cff7b65811dbd7ec0c8db8a6adc014d9d5", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "cf3dd28eb435afc09eace0f2b02e7bae18978d0f47a6a43f27040cb6b6f5460e", -"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "3954d5a5374321ba8328a86e5302878d231c9ec8f1bb70de257a5f24ffdc2dd6", -"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "8e8b165ad23d69e4d5f52c5a6cb1f11b27829d54d5e44dd401b13875667e6287", -"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "10cb4b3cbb74b3d44e430f3be1affd489ca6dfde179f1916d0abb82fbfff8764", -"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_output]": "ce02b6982e756401f8dd006e64c86825a4254dc57e6c2077f7c62848c9a3d178", -"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_script_address_c-466ef44c": "4a46dd8ac42295d853646a55ca1b85023b2235af6155be663b1de10a6c98def2", -"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_enterprise_address_ch-15518a4c": "079c395ab5dfa10d9bc6364e4201c128cd02ade9fad730390720784360b17d79", -"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_pointer_address_change_output]": "d5d251a3a597abc1df5480651dfbf15d59f7b207bf351131906862b0aaa07a51", -"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_certificate_with_no_p-0bbad967": "28a4cc241374f3125d60d33a87c0456ffe9509817d1849d8bfc0e378d6c48a07", -"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "d8303a92b2d5a67d81543eea2fb822ac2ab994ffa07c7d6d23db24a38f626dab", -"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "0f2330f22f60905681622bec047bfd67d1aeb3a30c7523d20dee62b59dd86dec", -"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "af40cd3886590c39a36c503c1dddfff60ea3ec8a0948e45c109b45c83056d72a", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_metadata]": "d364e0bc601fc16088bd7717822b554f3d4bd234e1ed779cc5bf9acdb316bf26", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "a22ad00e9e58a64eca1f295191fa36937beb09b41620e64942498788e448e3a3", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "b89e4b24a93197752607d62fa88f918590ff94a2c40007ead6773a3d1bda7285", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "a7a3f01b6972aeab505e9df70c83111ef03102b62d5260164ed36a0140d7d9dc", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "9912dd5d7fe33c3f4c48e813c39d717947d9c96a15f4349ed153548314c4cf80", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "45c35b504a486f709af64c5827231446269b3396335fd014da8c3015a1d799cc", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "e962a871d51f5fb0775f291f6e266445bc947600d60558a17ae47efb494b2e56", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "0514ba487672b2bd902ca39ab0665917f0eb0b804a0f857564a0f7183d2f6483", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "5ba2589aeda7cb2b707b5dd0d40ac26a5abe6eb0c3ec3d47d834701ef07a42bc", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "5ba2589aeda7cb2b707b5dd0d40ac26a5abe6eb0c3ec3d47d834701ef07a42bc", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "c57c4097446de48b1f79850854a83410816ac05c8a7476452771cdc71e0aeefa", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "0f14d371c83adf4ceaa05530581df86eb653b9e8226be61fcd2bc1cc97e3581a", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "a24edeaaefca10b45235836264b8385148048a23bd34c56570c3de69de4f3d06", +"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "db76676358164a3b3dab5148f09ba5515d079212366b79c44f95e2ba613abc71", +"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "c5a5ef80ccefc8df0c2df100678e686458ef92d00738f038fe069e5fb169a8b1", +"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "2bb355fab3aa8cf7b6705e36045287525e5442e8236033e4efefd79d5b913d7d", +"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "a9bbc7137d32d71acc1b4d4b7c19aacf7ec8b63c06fe53c16759bf81f5d0ad96", +"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_output]": "3e55bbf1c01e9a889f2be7e3ae07db4348c13f6bdb6d746e7cb812a18329c9bb", +"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_script_address_c-466ef44c": "cdc9707b2c4ad61bb2037b93b68fac3aef071f1b1458a948a53a3997f3ffc131", +"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_enterprise_address_ch-15518a4c": "4db403239beeaa24f8b1b9d98dedf49a68f6e57b52526822e49d7851f407555e", +"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_pointer_address_change_output]": "8d24fb46f5aa9232873c3d1216e643365cb8f8dbc66f9f81f5cb64943b2476cc", +"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_certificate_with_no_p-0bbad967": "7169657ca34ba6a228b89ef1c44ef1e6f9f740a348d778d0bb60deaac2819381", +"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "83f78636b8ccbd850bd4f7b36d0ea84a69b96db56b572707ab5aaf5f10ae7397", +"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "7178cb7c264c15ab13152a87fe14c39fbdfa8571c166ddcda6e7c65680bbc784", +"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "fcd2bfb85ff1b0ec7a204b2d525c8adf4204afbdcc726d4485820ff36ded4b2c", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_p-3c7243e1": "32458c03d03f4cfc2d83369a7b4a766a7b410452cb27682d5959a09a78d19b90", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_s-20438873": "e1dba216b8ff68de35ff87c1c430bc5170d4a9a3c09047d8f9f7e12982f93139", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_metadata]": "466a7245ae2d643bc35061321e28ff6d80cbe42faabb10ea613cfc92fee31c06", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "555219b1572cd91037379ebd95e2a979c5e0486148cb0c00f837277820cb4cbe", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "7d7915b4300974d5f45a8308da218b7e4bac938a2d033a6db2b6dccdbec5e4d8", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_with_ac-9ca046f0": "e5b8662ef9abe58a835d6d5765e413ee1dc63cc870e2c6627f9da6a93c5ead9f", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "043a0d9689c74a63a4da5067b0b69ced14d3ca1717490e11de52f1bb31610659", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "5a983375390be55cb4fca80a58546cc333148101a02ccfc8c80e1a64b9f47b57", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "367088bed7ede0e6f317d3662f990b4300f93fcff2ccd6309c6c4f50fd8da6f9", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[all_tx_inputs_must_be_external_(without_path)]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_invalid_pool_size]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_non_staking_path]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_path_larger_than_100]": "ffae5d78193ba3e989f025b67c544ce77ac4fde9d547e4588a9fe6f90354a4c2", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_staking_path_larger_than_100]": "ffae5d78193ba3e989f025b67c544ce77ac4fde9d547e4588a9fe6f90354a4c2", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[contains_other_certificates]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[contains_withdrawal]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[fee_is_too_high]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", @@ -48,8 +54,10 @@ "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_is_a_base_address]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_asset_name_in_multiasset_token_group]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_policyid_in_multiasset_output]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-883e81d5": "2468c4f540e8532d28300a7c4209d893536fb099d8036252277634198e9b1c66", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_mainnet_transaction_with_testn-af110e3e": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_testnet_transaction_with_mainn-ba78ab8f": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[stake_deregistration_account_larger_than_100]": "ffae5d78193ba3e989f025b67c544ce77ac4fde9d547e4588a9fe6f90354a4c2", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_protocol_magic_with_mainnet_network_id]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_transaction_with_mainnet_output]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[too_many_tokens_in_output]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",