Repository: ofek/bit

Issue:
Multisig error
What's wrong with that? The code below gives out an error `Traceback (most recent call last):
  File "/home/tony/Documents/DLF/Dev/1.py", line 15, in <module>
    NetworkAPI.broadcast_tx_testnet(tx_2)
  File "/home/tony/.local/lib/python3.7/site-packages/bit/network/services.py", line 533, in broadcast_tx_testnet
    raise ConnectionError('Transaction broadcast failed, or '
ConnectionError: Transaction broadcast failed, or Unspents were already used`

Balance = 0.04 BTC 

```
from bit import MultiSigTestnet, PrivateKeyTestnet, wif_to_key
from bit.network import NetworkAPI

key1 = wif_to_key(WIF1)
key2 = wif_to_key(WIF2)

multisig1 = MultiSigTestnet(key1, {key1.public_key, key2.public_key}, 2)
multisig2 = MultiSigTestnet(key2, {key1.public_key, key2.public_key}, 2)
tx_1 = multisig1.create_transaction([('2Mxpa7jzh37ZuXKVxqnS5RLD7XCdGFrDFy1', 100000, 'satoshi')], fee=30)
tx_2 = multisig2.sign_transaction(tx_1) 
print(tx_1, tx_2)
NetworkAPI.broadcast_tx_testnet(tx_2)





Comments:

Patch:
diff --git a/bit/transaction.py b/bit/transaction.py
index 6d7c00b..95d0f71 100644
--- a/bit/transaction.py
+++ b/bit/transaction.py
@@ -621,13 +621,19 @@ def sign_tx(private_key, tx, *, unspents):
 
     # Make input parameters for preimage calculation
     inputs_parameters = []
+
+    # The TxObj in `tx` will below be modified to contain the scriptCodes used
+    # for the transaction structure to be signed
+
+    # `input_script_field` copies the scriptSigs for partially signed
+    # transactions to later extract signatures from it:
+    input_script_field = [tx.TxIn[i].script_sig for i in range(len(tx.TxIn))]
+
     for i in sign_inputs:
         # Create transaction object for preimage calculation
         tx_input = tx.TxIn[i].txid + tx.TxIn[i].txindex
         segwit_input = input_dict[tx_input]['segwit']
         tx.TxIn[i].segwit_input = segwit_input
-        # For partially signed transaction we must extract the signatures:
-        input_script_field = tx.TxIn[i].script_sig
 
         script_code = private_key.scriptcode
         script_code_len = int_to_varint(len(script_code))
@@ -640,9 +646,10 @@ def sign_tx(private_key, tx, *, unspents):
             try:
                 tx.TxIn[i].script_sig += input_dict[tx_input]['amount']\
                                          .to_bytes(8, byteorder='little')
-                # For partially signed transaction we must extract the
-                # signatures:
-                input_script_field = tx.TxIn[i].witness
+
+                # For partially signed Segwit transactions the signatures must
+                # be extracted from the witnessScript field:
+                input_script_field[i] = tx.TxIn[i].witness
             except AttributeError:
                 raise ValueError(
                     'Cannot sign a segwit input when the input\'s amount is '
@@ -666,8 +673,8 @@ def sign_tx(private_key, tx, *, unspents):
             sigs = {}
             # Initial number of witness items (OP_0 + one signature + redeemscript).
             witness_count = 3
-            if input_script_field:
-                sig_list = get_signatures_from_script(input_script_field)
+            if input_script_field[i]:
+                sig_list = get_signatures_from_script(input_script_field[i])
                 # Bitcoin Core convention: Every missing signature is denoted
                 # by 0x00. Only used for already partially-signed scriptSigs:
                 script_blob += b'\x00' * (private_key.m - len(sig_list)-1)


Test patch:
diff --git a/tests/test_transaction.py b/tests/test_transaction.py
index 3548271..1410abf 100644
--- a/tests/test_transaction.py
+++ b/tests/test_transaction.py
@@ -99,6 +99,42 @@ FINAL_TX_BATCH = ('010000000001024623e78d68e72b428eb4f53f73086ad824a2c2b6be90'
                   '2cba96d3499410bbd90121021816325d19fd34fd87a039e83e35fc9de3'
                   'c9de64a501a6684b9bf9946364fbb700000000')
 
+FINAL_TX_MULTISIG_MANY = (
+    '010000000001040100000000000000000000000000000000000000000000000000000000'
+    '0000000000000023220020d3a4db6921782f78eb4f158f73adde471629dd5aca41c14a5b'
+    'fc2ec2a8f39202ffffffff02000000000000000000000000000000000000000000000000'
+    '0000000000000001000000db00483045022100a9efd4418fc75749407ab9369c21a52f9e'
+    '105f0dac25e8e7020f16fd0738185f0220421930e517fe2cd015a9f1e0c884f07ca0b80f'
+    '0153cf413dfd926abfeb5bf81201483045022100afc30dd8dc8fc7d006458034bbd3f425'
+    '4cd5783d56ef6568fb21d074f44fa3ad02200e7b1207113c59525eb7376a7bc5fea42405'
+    '1152687e406fd90a435467f8b8db01475221021816325d19fd34fd87a039e83e35fc9de3'
+    'c9de64a501a6684b9bf9946364fbb721037d696886864509ed63044d8f1bcd53b8def124'
+    '7bd2bbe056ff81b23e8c09280f52aeffffffff0300000000000000000000000000000000'
+    '0000000000000000000000000000000200000023220020d3a4db6921782f78eb4f158f73'
+    'adde471629dd5aca41c14a5bfc2ec2a8f39202ffffffff04000000000000000000000000'
+    '0000000000000000000000000000000000000003000000db00483045022100a324e5256d'
+    'c2621e4b185112ea80d95d170b6cd13dcf7a096e5a82cd85e94bad02200e9859d4b7af52'
+    '0eaab1bbcee6d25ad1e2dee1c9f428794a40fa8bcff82395c601483045022100ea77d456'
+    '5fd49b113df45507ebb2f1ee101d65798ecbf9a98f99212cb05d776a02207bc44b0e1f62'
+    '6c9072a6524f1459f9bc9965f75b863c705c8f6a07646ae4e9d901475221021816325d19'
+    'fd34fd87a039e83e35fc9de3c9de64a501a6684b9bf9946364fbb721037d696886864509'
+    'ed63044d8f1bcd53b8def1247bd2bbe056ff81b23e8c09280f52aeffffffff0200286bee'
+    '000000001600140ee268c86d05f290add1bfc9bdfc3992d785bce2505c9a3b0000000017'
+    'a914d35515db546bb040e61651150343a218c87b471e8704004730440220279267d5c34f'
+    'f4acb9b99cf5d28b1498be2c72dee87c0f331078ef906b9163bd02203b10bda36d7182a4'
+    '0c3d42df74484d5e1c32fa24b0ed708f8951e82a642c569d01483045022100c452fc9665'
+    '9792ac1f36846657b54c1b1dc319ef0018db53d4b9d96e2c7dbdd602203740cc070738d6'
+    '1e458be5cb330c0d221478b3564dfa3f5a7ecb82e384a2fa0601475221021816325d19fd'
+    '34fd87a039e83e35fc9de3c9de64a501a6684b9bf9946364fbb721037d696886864509ed'
+    '63044d8f1bcd53b8def1247bd2bbe056ff81b23e8c09280f52ae000400473044022015f6'
+    '687440590aec9e5f7bf2d2f69701474dd8d3df22cc314b8b557e4cd457fb02200e0f6ec2'
+    '4a125fa70fac34feb5244add0cb89b317b8da807b68cec62003d02ab0148304502210090'
+    '28061143f911ab7dbcfcd8851e253a14a58dd6320296be5cafcbd5f1f8af44022043b1f9'
+    '1ec311f2e351ad783a2bf9591754576a3a733917e0ce2b2a6c1e0f94c001475221021816'
+    '325d19fd34fd87a039e83e35fc9de3c9de64a501a6684b9bf9946364fbb721037d696886'
+    '864509ed63044d8f1bcd53b8def1247bd2bbe056ff81b23e8c09280f52ae0000000000'
+)
+
 INPUTS = [
     TxIn(
         (b"G0D\x02 E\xb7C\xdb\xaa\xaa,\xd1\xef\x0b\x914oVD\xe3-\xc7\x0c\xde\x05\t"
@@ -153,6 +189,32 @@ UNSPENTS_BATCH = [
             1,
             'np2wkh')
 ]
+UNSPENTS_MULTISIG_MANY = [
+    Unspent(2000000000,
+            1,
+            'a914d35515db546bb040e61651150343a218c87b471e87',
+            '0000000000000000000000000000000000000000000000000000000000000001',
+            0,
+            'np2wsh'),
+    Unspent(2000000000,
+            1,
+            'a914f132346e75e3a317f3090a07560fe75d74e1f51087',
+            '0000000000000000000000000000000000000000000000000000000000000002',
+            1,
+            'p2sh'),
+    Unspent(2000000000,
+            1,
+            'a914d35515db546bb040e61651150343a218c87b471e87',
+            '0000000000000000000000000000000000000000000000000000000000000003',
+            2,
+            'np2wsh'),
+    Unspent(2000000000,
+            1,
+            'a914f132346e75e3a317f3090a07560fe75d74e1f51087',
+            '0000000000000000000000000000000000000000000000000000000000000004',
+            3,
+            'p2sh'),
+]
 OUTPUTS = [
     ('n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi', 50000),
     ('mtrNwJxS1VyHYn3qBY1Qfsm3K3kh1mGRMS', 83658760)
@@ -499,6 +561,21 @@ class TestCreateSignedTransaction:
         tx2 = multi1.sign_transaction(tx1, unspents=UNSPENTS_BATCH[::-1])
         assert tx2 == FINAL_TX_BATCH
 
+    def test_multisig_tx_many_inputs(self):
+        key1 = PrivateKeyTestnet(WALLET_FORMAT_TEST_1)
+        key2 = PrivateKeyTestnet(WALLET_FORMAT_TEST_2)
+        p = [key1.public_key.hex(), key2.public_key.hex()]
+        multi1 = MultiSigTestnet(key1, p, 2)
+        multi2 = MultiSigTestnet(key2, p, 2)
+        tx0 = create_new_transaction(
+            multi1,
+            UNSPENTS_MULTISIG_MANY,
+            [("bcrt1qpm3x3jrdqhefptw3hlymmlpejttct08zgzzd2t", 4000000000),
+            ("2NCWeVbWmaUp92dSFP3RddPk6r3GTd6cDd6", 999971920)]
+        )
+        tx1 = multi2.sign_transaction(tx0, unspents=UNSPENTS_MULTISIG_MANY)
+        assert tx1 == FINAL_TX_MULTISIG_MANY
+
 
 class TestDeserializeTransaction:
     def test_legacy_deserialize(self):