tcommands: add convert_xkey for converting between {x,y,z}|{pub,prv} - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 5fc715cdee8c54ecb260ac256a5baccecc358e4b DIR parent 9cff42328d5b6c92c87a2b41bb1f4e463c39aab7 HTML Author: SomberNight <somber.night@protonmail.com> Date: Sun, 20 Jan 2019 15:49:42 +0100 commands: add convert_xkey for converting between {x,y,z}|{pub,prv} Diffstat: M electrum/commands.py | 11 +++++++++++ M electrum/tests/test_commands.py | 45 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 0 deletions(-) --- DIR diff --git a/electrum/commands.py b/electrum/commands.py t@@ -38,6 +38,7 @@ from .import util, ecc from .util import bfh, bh2u, format_satoshis, json_decode, print_error, json_encode from . import bitcoin from .bitcoin import is_address, hash_160, COIN, TYPE_ADDRESS +from . import bip32 from .i18n import _ from .transaction import Transaction, multisig_script, TxOutput from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED t@@ -429,6 +430,16 @@ class Commands: """Get master private key. Return your wallet\'s master private key""" return str(self.wallet.keystore.get_master_private_key(password)) + @command('') + def convert_xkey(self, xkey, xtype): + """Convert xtype of a master key. e.g. xpub -> ypub""" + is_xprv = bip32.is_xprv(xkey) + if not bip32.is_xpub(xkey) and not is_xprv: + raise Exception('xkey should be a master public/private key') + _, depth, fingerprint, child_number, c, cK = bip32.deserialize_xkey(xkey, is_xprv) + serialize = bip32.serialize_xprv if is_xprv else bip32.serialize_xpub + return serialize(xtype, c, cK, depth, fingerprint, child_number) + @command('wp') def getseed(self, password=None): """Get seed phrase. Print the generation seed of your wallet.""" DIR diff --git a/electrum/tests/test_commands.py b/electrum/tests/test_commands.py t@@ -3,6 +3,8 @@ from decimal import Decimal from electrum.commands import Commands, eval_bool +from . import TestCaseForTestnet + class TestCommands(unittest.TestCase): t@@ -39,3 +41,46 @@ class TestCommands(unittest.TestCase): self.assertTrue(eval_bool("True")) self.assertTrue(eval_bool("true")) self.assertTrue(eval_bool("1")) + + def test_convert_xkey(self): + cmds = Commands(config=None, wallet=None, network=None) + xpubs = { + ("xpub6CCWFbvCbqF92kGwm9nV7t7RvVoQUKaq5USMdyVP6jvv1NgN52KAX6NNYCeE8Ca7JQC4K5tZcnQrubQcjJ6iixfPs4pwAQJAQgTt6hBjg11", "standard"), + ("ypub6X2mZGb7kWnct3U4bWa7KyCw6TwrQwaKzaxaRNPGUkJo4UVbKgUj9A2WZQbp87E2i3Js4ZV85SmQnt2BSzWjXCLzjQXMkK7egQXXVHT4eKn", "p2wpkh-p2sh"), + ("zpub6qs2rwG2uCL6jLfBRsMjY4JSGS6JMZZpuhUoCmH9rkgg7aJpaLeHmDgeacZQ81sx7gRfp35gY77xgAdkAgvkKS2bbkDnLDw8x8bAsuKBrvP", "p2wpkh"), + } + for xkey1, xtype1 in xpubs: + for xkey2, xtype2 in xpubs: + self.assertEqual(xkey2, cmds.convert_xkey(xkey1, xtype2)) + + xprvs = { + ("xprv9yD9r6PJmTgqpGCUf8FUkkAhNTxv4rryiFWkqb5mYQPw8aMDXUzuyJ3tgv5vUqYkdK1E6Q5jKxPss4HkMBYV4q8AfG8t7rxgyS4xQX4ndAm", "standard"), + ("yprvAJ3R9m4Dv9EKfZPbVV36xqGCYS7N1UrUdN2ycyyevQmpBgASn9AUbMi2i83WUkCg2x82qsgHnckRkLuK4sxVs4omXbqJhmnBFA8bo8ssinK", "p2wpkh-p2sh"), + ("zprvAcsgTRj94pmoWraiKqpjAvMhiQFox6qyYUZCQNsYJR9hEmyg2oL3DRNAjL16UerbSbEqbMGrFH6yddWsnaNWfJVNPwXjHgbfWtCFBgDxFkX", "p2wpkh"), + } + for xkey1, xtype1 in xprvs: + for xkey2, xtype2 in xprvs: + self.assertEqual(xkey2, cmds.convert_xkey(xkey1, xtype2)) + + +class TestCommandsTestnet(TestCaseForTestnet): + + def test_convert_xkey(self): + cmds = Commands(config=None, wallet=None, network=None) + xpubs = { + ("tpubD8p5qNfjczgTGbh9qgNxsbFgyhv8GgfVkmp3L88qtRm5ibUYiDVCrn6WYfnGey5XVVw6Bc5QNQUZW5B4jFQsHjmaenvkFUgWtKtgj5AdPm9", "standard"), + ("upub59wfQ8qJTg6ZSuvwtR313Qdp8gP8TSBwTof5dPQ3QVsYp1N9t29Rr9TGF1pj8kAXUg3mKbmrTKasA2qmBJKb1bGUzB6ApDZpVC7LoHhyvBo", "p2wpkh-p2sh"), + ("vpub5UmvhoWDcMe3JD84impdFVjKJeXaQ4BSNvBJQnHvnWFRs7BP8gJzUD7QGDnK8epStKAa55NQuywR3KTKtzjbopx5rWnbQ8PJkvAzBtgaGBc", "p2wpkh"), + } + for xkey1, xtype1 in xpubs: + for xkey2, xtype2 in xpubs: + self.assertEqual(xkey2, cmds.convert_xkey(xkey1, xtype2)) + + xprvs = { + ("tprv8c83gxdVUcznP8fMx2iNUBbaQgQC7MUbBUDG3c6YU9xgt7Dn5pfcgHUeNZTAvuYmNgVHjyTzYzGWwJr7GvKCm2FkPaaJipyipbfJeB3tdPW", "standard"), + ("uprv8vxJzdJQdJYGERrUnPVzgGh5aeYe3yU66ajUpzzRrALZwD31LUqBJM8nPmQkvpCgnKc6VT4Z1ed4pbTfzcjDZFwMFvGjJjoD6Kix2pCwVe7", "p2wpkh-p2sh"), + ("vprv9FnaJHyKmz5k5j3bckHctMnakch5zbTb1hFhcPtKEAiSzJrEb8zjvQnvQyNLvircBxiuEvf7UJycht5EiK9EMVcx8Fy9techN3nbRQRFhEv", "p2wpkh"), + } + for xkey1, xtype1 in xprvs: + for xkey2, xtype2 in xprvs: + self.assertEqual(xkey2, cmds.convert_xkey(xkey1, xtype2))