@@ -281,69 +281,121 @@ def test_short_4_letter_mnemonic_qr():
281
281
assert d .get_seed_phrase () == ["height" , "demise" , "useless" , "trap" , "grow" , "lion" , "found" , "off" , "key" , "clown" , "transfer" , "enroll" ]
282
282
283
283
284
- def test_bitcoin_address ():
285
- bad1 = "loremipsum"
286
- bad2 = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae"
287
- bad3 = "121802020768124106400009195602431595117715840445"
288
-
289
- legacy_address1 = "1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY"
290
- legacy_address2 = "16ftSEQ4ctQFDtVZiUBusQUjRrGhM3JYwe"
291
-
292
- main_bech32_address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
293
- test_bech32_address = "tb1qkurj377gtlmu0j5flcykcsh2xagexh9h3jk06a"
294
-
295
- main_nested_segwit_address = "3Nu78Cqcf6hsD4sUBAN9nP13tYiHU9QPFX"
296
- test_nested_segwit_address = "2N6JbrvPMMwbBhu2KxqXyyHUQz3XKspvyfm"
297
-
298
- main_bech32_address2 = "bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?amount=12000"
299
- main_bech32_address3 = "BITCOIN:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?junk"
300
-
301
- d = DecodeQR ()
302
- d .add_data (bad1 )
303
-
304
- assert d .qr_type == QRType .INVALID
305
-
306
- d = DecodeQR ()
307
- d .add_data (legacy_address1 )
308
-
309
- assert d .get_address () == legacy_address1
310
- assert d .get_address_type () == (SettingsConstants .LEGACY_P2PKH , SettingsConstants .MAINNET )
311
-
312
- d = DecodeQR ()
313
- d .add_data (legacy_address2 )
314
-
315
- assert d .get_address () == legacy_address2
316
- assert d .get_address_type () == (SettingsConstants .LEGACY_P2PKH , SettingsConstants .MAINNET )
317
-
318
- d = DecodeQR ()
319
- d .add_data (main_bech32_address )
320
-
321
- assert d .get_address () == main_bech32_address
322
- assert d .get_address_type () == (SettingsConstants .NATIVE_SEGWIT , SettingsConstants .MAINNET )
323
-
324
- d = DecodeQR ()
325
- d .add_data (test_bech32_address )
326
-
327
- assert d .get_address () == test_bech32_address
328
- assert d .get_address_type () == (SettingsConstants .NATIVE_SEGWIT , SettingsConstants .TESTNET )
329
-
330
- d = DecodeQR ()
331
- d .add_data (main_nested_segwit_address )
332
-
333
- assert d .get_address () == main_nested_segwit_address
334
- assert d .get_address_type () == (SettingsConstants .NESTED_SEGWIT , SettingsConstants .MAINNET )
335
-
336
- d = DecodeQR ()
337
- d .add_data (test_nested_segwit_address )
338
-
339
- assert d .get_address () == test_nested_segwit_address
340
- assert d .get_address_type () == (SettingsConstants .NESTED_SEGWIT , SettingsConstants .TESTNET )
284
+ # Test data for bitcoin address decoding. All generated from test key: ["abandon"] * 11 + ["about"]
285
+ legacy_address_mainnet = "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"
286
+ legacy_address_testnet = "mkpZhYtJu2r87Js3pDiWJDmPte2NRZ8bJV"
287
+
288
+ nested_segwit_address_mainnet = "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"
289
+ nested_segwit_address_testnet = "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2"
290
+
291
+ native_segwit_address_mainnet = "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"
292
+ native_segwit_address_testnet = "tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl"
293
+ native_segwit_address_regtest = "bcrt1q6rz28mcfaxtmd6v789l9rrlrusdprr9pz3cppk"
294
+
295
+ taproot_address_mainnet = "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr"
296
+ taproot_address_testnet = "tb1p8wpt9v4frpf3tkn0srd97pksgsxc5hs52lafxwru9kgeephvs7rqlqt9zj"
297
+ taproot_address_regtest = "bcrt1p8wpt9v4frpf3tkn0srd97pksgsxc5hs52lafxwru9kgeephvs7rqjeprhg"
298
+
299
+
300
+
301
+ def test_bitcoin_address ():
302
+ """
303
+ Decoder should parse various types of valid bitcoin addresses with or without the
304
+ "bitcoin:" prefix and optional query params.
305
+ """
306
+ def decode (address , expected_script_type , expected_network = SettingsConstants .MAINNET ):
307
+ for data in [address , "bitcoin:" + address , "bitcoin:" + address + "?amount=12000" ]:
308
+ d = DecodeQR ()
309
+ d .add_data (data )
310
+ assert d .get_address () == address
311
+ assert d .get_address_type () == (expected_script_type , expected_network )
312
+
313
+ decode (legacy_address_mainnet , SettingsConstants .LEGACY_P2PKH )
314
+ decode (legacy_address_testnet , SettingsConstants .LEGACY_P2PKH , SettingsConstants .TESTNET )
315
+ decode (nested_segwit_address_mainnet , SettingsConstants .NESTED_SEGWIT )
316
+ decode (nested_segwit_address_testnet , SettingsConstants .NESTED_SEGWIT , SettingsConstants .TESTNET )
317
+ decode (native_segwit_address_mainnet , SettingsConstants .NATIVE_SEGWIT )
318
+ decode (native_segwit_address_testnet , SettingsConstants .NATIVE_SEGWIT , SettingsConstants .TESTNET )
319
+ decode (native_segwit_address_regtest , SettingsConstants .NATIVE_SEGWIT , SettingsConstants .REGTEST )
320
+ decode (taproot_address_mainnet , SettingsConstants .TAPROOT )
321
+ decode (taproot_address_testnet , SettingsConstants .TAPROOT , SettingsConstants .TESTNET )
322
+ decode (taproot_address_regtest , SettingsConstants .TAPROOT , SettingsConstants .REGTEST )
323
+
324
+
325
+
326
+ def test_invalid_bitcoin_address ():
327
+ """
328
+ Decoder should fail to parse invalid address data.
329
+ * Test incorrect "bitcoin:" prefix.
330
+ * Test invalid addresses.
331
+ * Test valid addresses w/additional prefixes (to ensure regexp is not finding
332
+ mid-string matches) which make the data invalid.
333
+ """
334
+ bad_inputs = [
335
+ # wrong separator char
336
+ "bitcoin=bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" ,
337
+
338
+ # Unrecognized addr prefix
339
+ "bitcoin:bcfakehrp1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" ,
340
+
341
+ # valid addr w/garbage addr prefix
342
+ "abcbc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" ,
343
+
344
+ # valid "bitcoin:" prefix w/garbage addr prefix
345
+ "bitcoin:abcbc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" ,
346
+
347
+ # typo in "bitcoin:" prefix
348
+ "bitcon:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" ,
349
+ ]
341
350
342
- d = DecodeQR ()
343
- d .add_data (main_bech32_address2 )
344
-
345
- assert d .get_address () == "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
346
- assert d .get_address_type () == (SettingsConstants .NATIVE_SEGWIT , SettingsConstants .MAINNET )
351
+ for bad_input in bad_inputs :
352
+ d = DecodeQR ()
353
+ status = d .add_data (bad_input )
354
+ assert status == DecodeQRStatus .INVALID
355
+
356
+
357
+
358
+ def test_bitcoin_address_ignores_case_where_allowed ():
359
+ """
360
+ Decoder should ignore case in QR data prefix and in the address itself (for the
361
+ address types where case is ignored).
362
+ """
363
+ def decode (address , expected_script_type , is_case_sensitive , expected_network = SettingsConstants .MAINNET ):
364
+ addr_variations = [address ]
365
+ if not is_case_sensitive :
366
+ # Test as-is and all uppercase
367
+ addr_variations .append (address .upper ())
368
+
369
+ for addr_variation in addr_variations :
370
+ # First add prefix capitalizations
371
+ variations_1 = ["bitcoin:" + addr_variation , "BITCOIN:" + addr_variation ]
372
+
373
+ # Now add query params
374
+ variations_2 = [v + "?amount=12000" for v in variations_1 ]
375
+ variations_3 = [v + "?AMOUNT=12000" for v in variations_1 ]
376
+ for data in [addr_variation ] + variations_1 + variations_2 + variations_3 :
377
+ d = DecodeQR ()
378
+ d .add_data (data )
379
+ assert d .get_address_type () == (expected_script_type , expected_network )
380
+
381
+ if not is_case_sensitive :
382
+ assert d .get_address () == addr_variation .lower ()
383
+ else :
384
+ assert d .get_address () == addr_variation
385
+
386
+ # Case sensitive address types
387
+ decode (legacy_address_mainnet , SettingsConstants .LEGACY_P2PKH , is_case_sensitive = True )
388
+ decode (legacy_address_testnet , SettingsConstants .LEGACY_P2PKH , is_case_sensitive = True , expected_network = SettingsConstants .TESTNET )
389
+ decode (nested_segwit_address_mainnet , SettingsConstants .NESTED_SEGWIT , is_case_sensitive = True )
390
+ decode (nested_segwit_address_testnet , SettingsConstants .NESTED_SEGWIT , is_case_sensitive = True , expected_network = SettingsConstants .TESTNET )
391
+
392
+ # Case insensitive address types
393
+ decode (native_segwit_address_mainnet , SettingsConstants .NATIVE_SEGWIT , is_case_sensitive = False )
394
+ decode (native_segwit_address_testnet , SettingsConstants .NATIVE_SEGWIT , is_case_sensitive = False , expected_network = SettingsConstants .TESTNET )
395
+ decode (native_segwit_address_regtest , SettingsConstants .NATIVE_SEGWIT , is_case_sensitive = False , expected_network = SettingsConstants .REGTEST )
396
+ decode (taproot_address_mainnet , SettingsConstants .TAPROOT , is_case_sensitive = False )
397
+ decode (taproot_address_testnet , SettingsConstants .TAPROOT , is_case_sensitive = False , expected_network = SettingsConstants .TESTNET )
398
+ decode (taproot_address_regtest , SettingsConstants .TAPROOT , is_case_sensitive = False , expected_network = SettingsConstants .REGTEST )
347
399
348
400
349
401
0 commit comments