3
3
# Distributed under the MIT/X11 software license, see the accompanying
4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
6
+ import io
7
+
8
+ from decimal import Decimal
6
9
from test_framework .test_framework import BitcoinTestFramework
7
- from test_framework .util import connect_nodes_bi , assert_equal
8
10
from test_framework .authproxy import JSONRPCException
9
- from decimal import Decimal
11
+ from test_framework .messages import (
12
+ COIN ,
13
+ CTransaction ,
14
+ CTxOut ,
15
+ CTxOutAsset ,
16
+ CTxOutValue ,
17
+ CTxInWitness ,
18
+ CTxOutWitness ,
19
+ )
20
+ from test_framework .util import (
21
+ connect_nodes_bi ,
22
+ assert_equal ,
23
+ hex_str_to_bytes ,
24
+ bytes_to_hex_str ,
25
+ BITCOIN_ASSET_OUT ,
26
+ assert_raises_rpc_error ,
27
+ )
10
28
import os
11
29
import re
12
30
@@ -378,7 +396,8 @@ def run_test(self):
378
396
assert_equal (multi_asset_amount ['bitcoin' ], value1 + value3 )
379
397
assert_equal (multi_asset_amount [test_asset ], Decimal ('0.00000003' ))
380
398
381
- # Check blinded multisig functionality
399
+ # Check blinded multisig functionality and partial blinding functionality
400
+
382
401
# Get two pubkeys
383
402
blinded_addr = self .nodes [0 ].getnewaddress ()
384
403
pubkey = self .nodes [0 ].getaddressinfo (blinded_addr )["pubkey" ]
@@ -396,15 +415,143 @@ def run_test(self):
396
415
# Create blinded address from p2sh address and import corresponding privkey
397
416
blinded_multisig_addr = self .nodes [0 ].createblindedaddress (unconfidential_addr , blinding_pubkey )
398
417
self .nodes [0 ].importblindingkey (blinded_multisig_addr , blinding_key )
399
- self .nodes [1 ].importblindingkey (blinded_multisig_addr , blinding_key )
400
- # Send coins to blinded multisig address and check that they were received
401
- self .nodes [2 ].sendtoaddress (blinded_multisig_addr , 1 )
418
+
419
+ # Issue new asset, to use different assets in one transaction when doing
420
+ # partial blinding. Just to make these tests a bit more elaborate :-)
421
+ issued3 = self .nodes [2 ].issueasset (1 , 0 )
422
+ self .nodes [2 ].generate (1 )
402
423
self .sync_all ()
403
- assert_equal (len (self .nodes [0 ].listunspent (0 , 0 , [unconfidential_addr ])), 1 )
404
- assert_equal (len (self .nodes [1 ].listunspent (0 , 0 , [unconfidential_addr ])), 1 )
424
+ node2_balance = self .nodes [2 ].getbalance ()
425
+ assert (issued3 ['asset' ] in node2_balance )
426
+ assert_equal (node2_balance [issued3 ['asset' ]], Decimal (1 ))
405
427
406
- self .nodes [0 ].generate (1 )
428
+ # Send asset to blinded multisig address and check that it was received
429
+ self .nodes [2 ].sendtoaddress (address = blinded_multisig_addr , amount = 1 , assetlabel = issued3 ['asset' ])
407
430
self .sync_all ()
431
+ # We will use this multisig UTXO in our partially-blinded transaction,
432
+ # and will also check that multisig UTXO can be successfully spent
433
+ # after the transaction is signed by node1 and node0 in succession.
434
+ unspent_asset = self .nodes [0 ].listunspent (0 , 0 , [unconfidential_addr ], True , {"asset" :issued3 ['asset' ]})
435
+ assert_equal (len (unspent_asset ), 1 )
436
+ assert (issued3 ['asset' ] not in self .nodes [2 ].getbalance ())
437
+
438
+ # Create new UTXO on node0 to be used in our partially-blinded transaction
439
+ blinded_addr = self .nodes [0 ].getnewaddress ()
440
+ addr = self .nodes [0 ].validateaddress (blinded_addr )["unconfidential" ]
441
+ self .nodes [0 ].sendtoaddress (blinded_addr , 0.1 )
442
+ unspent = self .nodes [0 ].listunspent (0 , 0 , [addr ])
443
+ assert_equal (len (unspent ), 1 )
444
+
445
+ # Create new UTXO on node1 to be used in our partially-blinded transaction
446
+ blinded_addr2 = self .nodes [1 ].getnewaddress ()
447
+ addr2 = self .nodes [1 ].validateaddress (blinded_addr2 )["unconfidential" ]
448
+ self .nodes [1 ].sendtoaddress (blinded_addr2 , 0.11 )
449
+ unspent2 = self .nodes [1 ].listunspent (0 , 0 , [addr2 ])
450
+ assert_equal (len (unspent2 ), 1 )
451
+
452
+ # The transaction will have three non-fee outputs
453
+ dst_addr = self .nodes [0 ].getnewaddress ()
454
+ dst_addr2 = self .nodes [1 ].getnewaddress ()
455
+ dst_addr3 = self .nodes [2 ].getnewaddress ()
456
+
457
+ # Inputs are selected up front
458
+ inputs = [{"txid" : unspent2 [0 ]["txid" ], "vout" : unspent2 [0 ]["vout" ]}, {"txid" : unspent [0 ]["txid" ], "vout" : unspent [0 ]["vout" ]}, {"txid" : unspent_asset [0 ]["txid" ], "vout" : unspent_asset [0 ]["vout" ]}]
459
+
460
+ # Create one part of the transaction to partially blind
461
+ rawtx = self .nodes [0 ].createrawtransaction (
462
+ inputs , {dst_addr2 : Decimal ("0.01" )})
463
+
464
+ # Create another part of the transaction to partially blind
465
+ rawtx2 = self .nodes [0 ].createrawtransaction (
466
+ inputs ,
467
+ {dst_addr : Decimal ("0.1" ), dst_addr3 : Decimal ("1.0" )},
468
+ 0 ,
469
+ False ,
470
+ {dst_addr : unspent [0 ]['asset' ], dst_addr3 : unspent_asset [0 ]['asset' ]})
471
+
472
+ sum_i = unspent2 [0 ]["amount" ] + unspent [0 ]["amount" ]
473
+ sum_o = 0.01 + 0.10 + 0.1
474
+ assert_equal (int (round (sum_i * COIN )), int (round (sum_o * COIN )))
475
+
476
+ # Blind the first part of the transaction - we need to supply the
477
+ # assetcommmitments for all of the inputs, for the surjectionproof
478
+ # to be valid after we combine the transactions
479
+ blindtx = self .nodes [1 ].blindrawtransaction (
480
+ rawtx , True , [
481
+ unspent2 [0 ]['assetcommitment' ],
482
+ unspent [0 ]['assetcommitment' ],
483
+ unspent_asset [0 ]['assetcommitment' ]
484
+ ])
485
+
486
+ # Combine the transactions
487
+
488
+ # Blinded, but incomplete transaction.
489
+ # 3 inputs and 1 output, but no fee output, and
490
+ # it was blinded with 3 asset commitments, that means
491
+ # the final transaction should have 3 inputs.
492
+ btx = CTransaction ()
493
+ btx .deserialize (io .BytesIO (hex_str_to_bytes (blindtx )))
494
+
495
+ # Unblinded transaction, with 3 inputs and 2 outputs.
496
+ # We will add them to the other transaction to make it complete.
497
+ ubtx = CTransaction ()
498
+ ubtx .deserialize (io .BytesIO (hex_str_to_bytes (rawtx2 )))
499
+
500
+ # We will add outputs of unblinded transaction
501
+ # on top of inputs and outputs of the blinded, but incomplete transaction.
502
+ # We also append empty witness instances to make witness arrays match
503
+ # vin/vout arrays
504
+ btx .wit .vtxinwit .append (CTxInWitness ())
505
+ btx .vout .append (ubtx .vout [0 ])
506
+ btx .wit .vtxoutwit .append (CTxOutWitness ())
507
+ btx .wit .vtxinwit .append (CTxInWitness ())
508
+ btx .vout .append (ubtx .vout [1 ])
509
+ btx .wit .vtxoutwit .append (CTxOutWitness ())
510
+ # Add explicit fee output
511
+ btx .vout .append (CTxOut (nValue = CTxOutValue (10000000 ),
512
+ nAsset = CTxOutAsset (BITCOIN_ASSET_OUT )))
513
+ btx .wit .vtxoutwit .append (CTxOutWitness ())
514
+
515
+ # Input 0 is bitcoin asset (already blinded)
516
+ # Input 1 is also bitcoin asset
517
+ # Input 2 is our new asset
518
+
519
+ # Blind with wrong order of assetcommitments - such transaction should be rejected
520
+ blindtx = self .nodes [0 ].blindrawtransaction (
521
+ bytes_to_hex_str (btx .serialize ()), True , [
522
+ unspent_asset [0 ]['assetcommitment' ],
523
+ unspent [0 ]['assetcommitment' ],
524
+ unspent2 [0 ]['assetcommitment' ]
525
+ ])
526
+
527
+ stx2 = self .nodes [1 ].signrawtransactionwithwallet (blindtx )
528
+ stx = self .nodes [0 ].signrawtransactionwithwallet (stx2 ['hex' ])
529
+ self .sync_all ()
530
+
531
+ assert_raises_rpc_error (- 26 , "bad-txns-in-ne-out" , self .nodes [2 ].sendrawtransaction , stx ['hex' ])
532
+
533
+ # Blind with correct order of assetcommitments
534
+ blindtx = self .nodes [0 ].blindrawtransaction (
535
+ bytes_to_hex_str (btx .serialize ()), True , [
536
+ unspent2 [0 ]['assetcommitment' ],
537
+ unspent [0 ]['assetcommitment' ],
538
+ unspent_asset [0 ]['assetcommitment' ]
539
+ ])
540
+
541
+ stx2 = self .nodes [1 ].signrawtransactionwithwallet (blindtx )
542
+ stx = self .nodes [0 ].signrawtransactionwithwallet (stx2 ['hex' ])
543
+ txid = self .nodes [2 ].sendrawtransaction (stx ['hex' ])
544
+ self .nodes [2 ].generate (1 )
545
+ assert self .nodes [2 ].getrawtransaction (txid , 1 )['confirmations' ] == 1
546
+ self .sync_all ()
547
+
548
+ # Check that the sent asset has reached its destination
549
+ unconfidential_dst_addr3 = self .nodes [2 ].validateaddress (dst_addr3 )["unconfidential" ]
550
+ unspent_asset2 = self .nodes [2 ].listunspent (1 , 1 , [unconfidential_dst_addr3 ], True , {"asset" :issued3 ['asset' ]})
551
+ assert_equal (len (unspent_asset2 ), 1 )
552
+ assert_equal (unspent_asset2 [0 ]['amount' ], Decimal (1 ))
553
+ # And that the balance was correctly updated
554
+ assert_equal (self .nodes [2 ].getbalance ()[issued3 ['asset' ]], Decimal (1 ))
408
555
409
556
# Basic checks of rawblindrawtransaction functionality
410
557
blinded_addr = self .nodes [0 ].getnewaddress ()
0 commit comments