taccept base43-encoded tx in Qt "Load transaction" - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit eb04551f9ad11d367310592ab260895eb48bcb90 DIR parent 8f5ca40d10e921f87f1faf6162d81a62d114f1d7 HTML Author: SomberNight <somber.night@protonmail.com> Date: Tue, 5 Mar 2019 17:27:53 +0100 accept base43-encoded tx in Qt "Load transaction" When encoding transactions as QR codes, we encode the tx bytes as base43 first. This makes it easier to load a transaction if the user manually decodes the QR code. Diffstat: M electrum/tests/test_transaction.py | 19 ++++++++++++++++++- M electrum/transaction.py | 23 +++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) --- DIR diff --git a/electrum/tests/test_transaction.py b/electrum/tests/test_transaction.py t@@ -1,5 +1,5 @@ from electrum import transaction -from electrum.transaction import TxOutputForUI +from electrum.transaction import TxOutputForUI, tx_from_str from electrum.bitcoin import TYPE_ADDRESS from electrum.keystore import xpubkey_to_address from electrum.util import bh2u, bfh t@@ -171,6 +171,23 @@ class TestTransaction(SequentialTestCase): tx = transaction.Transaction(v2_blob) self.assertEqual(tx.txid(), "b97f9180173ab141b61b9f944d841e60feec691d6daab4d4d932b24dd36606fe") + def test_tx_from_str(self): + # json dict + self.assertEqual('020000000001012005273af813ba23b0c205e4b145e525c280dd876e061f35bff7db9b2e0043640100000000fdffffff02d885010000000000160014e73f444b8767c84afb46ef4125d8b81d2542a53d00e1f5050000000017a914052ed032f5c74a636ed5059611bb90012d40316c870247304402200c628917673d75f05db893cc377b0a69127f75e10949b35da52aa1b77a14c350022055187adf9a668fdf45fc09002726ba7160e713ed79dddcd20171308273f1a2f1012103cb3e00561c3439ccbacc033a72e0513bcfabff8826de0bc651d661991ade6171049e1600', + tx_from_str("""{ + "complete": true, + "final": false, + "hex": "020000000001012005273af813ba23b0c205e4b145e525c280dd876e061f35bff7db9b2e0043640100000000fdffffff02d885010000000000160014e73f444b8767c84afb46ef4125d8b81d2542a53d00e1f5050000000017a914052ed032f5c74a636ed5059611bb90012d40316c870247304402200c628917673d75f05db893cc377b0a69127f75e10949b35da52aa1b77a14c350022055187adf9a668fdf45fc09002726ba7160e713ed79dddcd20171308273f1a2f1012103cb3e00561c3439ccbacc033a72e0513bcfabff8826de0bc651d661991ade6171049e1600" + } + """) + ) + # raw hex + self.assertEqual('020000000001012005273af813ba23b0c205e4b145e525c280dd876e061f35bff7db9b2e0043640100000000fdffffff02d885010000000000160014e73f444b8767c84afb46ef4125d8b81d2542a53d00e1f5050000000017a914052ed032f5c74a636ed5059611bb90012d40316c870247304402200c628917673d75f05db893cc377b0a69127f75e10949b35da52aa1b77a14c350022055187adf9a668fdf45fc09002726ba7160e713ed79dddcd20171308273f1a2f1012103cb3e00561c3439ccbacc033a72e0513bcfabff8826de0bc651d661991ade6171049e1600', + tx_from_str('020000000001012005273af813ba23b0c205e4b145e525c280dd876e061f35bff7db9b2e0043640100000000fdffffff02d885010000000000160014e73f444b8767c84afb46ef4125d8b81d2542a53d00e1f5050000000017a914052ed032f5c74a636ed5059611bb90012d40316c870247304402200c628917673d75f05db893cc377b0a69127f75e10949b35da52aa1b77a14c350022055187adf9a668fdf45fc09002726ba7160e713ed79dddcd20171308273f1a2f1012103cb3e00561c3439ccbacc033a72e0513bcfabff8826de0bc651d661991ade6171049e1600')) + # base43 + self.assertEqual('020000000001012005273af813ba23b0c205e4b145e525c280dd876e061f35bff7db9b2e0043640100000000fdffffff02d885010000000000160014e73f444b8767c84afb46ef4125d8b81d2542a53d00e1f5050000000017a914052ed032f5c74a636ed5059611bb90012d40316c870247304402200c628917673d75f05db893cc377b0a69127f75e10949b35da52aa1b77a14c350022055187adf9a668fdf45fc09002726ba7160e713ed79dddcd20171308273f1a2f1012103cb3e00561c3439ccbacc033a72e0513bcfabff8826de0bc651d661991ade6171049e1600', + tx_from_str('64XF-8+PM6*4IYN-QWW$B2QLNW+:C8-$I$-+T:L.6DKXTSWSFFONDP1J/MOS3SPK0-SYVW38U9.3+A1/*2HTHQTJGP79LVEK-IITQJ1H.C/X$NSOV$8DWR6JAFWXD*LX4-EN0.BDOF+PPYPH16$NM1H.-MAA$V1SCP0Q.6Y5FR822S6K-.5K5F.Z4Q:0SDRG-4GEBLAO4W9Z*H-$1-KDYAFOGF675W0:CK5M1LT92IG:3X60P3GKPM:X2$SP5A7*LT9$-TTEG0/DRZYV$7B4ADL9CVS5O7YG.J64HLZ24MVKO/-GV:V.T/L$D3VQ:MR8--44HK8W')) + def test_get_address_from_output_script(self): # the inverse of this test is in test_bitcoin: test_address_to_script addr_from_script = lambda script: transaction.get_address_from_output_script(bfh(script)) DIR diff --git a/electrum/transaction.py b/electrum/transaction.py t@@ -39,7 +39,7 @@ from .bitcoin import (TYPE_ADDRESS, TYPE_PUBKEY, TYPE_SCRIPT, hash_160, hash160_to_p2sh, hash160_to_p2pkh, hash_to_segwit_addr, hash_encode, var_int, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC, COIN, push_script, int_to_hex, push_script, b58_address_to_hash160, - opcodes, add_number_to_script) + opcodes, add_number_to_script, base_decode) from .crypto import sha256d from .keystore import xpubkey_to_address, xpubkey_to_pubkey t@@ -1185,19 +1185,26 @@ class Transaction: return out -def tx_from_str(txt): - "json or raw hexadecimal" - import json +def tx_from_str(txt: str) -> str: + """Sanitizes tx-describing input (json or raw hex or base43) into + raw hex transaction.""" + assert isinstance(txt, str), f"txt must be str, not {type(txt)}" txt = txt.strip() if not txt: raise ValueError("empty string") + # try hex try: bfh(txt) - is_hex = True - except: - is_hex = False - if is_hex: return txt + except: + pass + # try base43 + try: + return base_decode(txt, length=None, base=43).hex() + except: + pass + # try json + import json tx_dict = json.loads(str(txt)) assert "hex" in tx_dict.keys() return tx_dict["hex"]