3

I have multiple partially signed transactions that I want to combine into one transaction. All those transactions were signed using the same key so it should be possible to combine all those partial signed into one combined transaction that can be signed and broadcasted at once using one key. According with bitcoin's rpc function combinerawtransaction is the proper to be used in my case but that function is not working because instead of combining all partial signed transaction into one is returning only the first partial signed transaction (it does not matter the order of the array, it will return always the first element)

Here you have the way I am trying to combine two partial signed address:

bitcoin-cli combinerawtransaction '["020000000001014a05cf2073d4ee6aa61256159e421d9f12291c44fc9607d99a4045ab192a580a01000000232200209acb3925f27bec7d8ac16b49705f6d47d5b87d48dc8571d3f49b10dcc7d89051ffffffff037cb002000000000016001488427232a9085b4ab6c334c6115725765864a6ad521d000000000000160014c2fe1292769b585b91fb8b045c651d79398589cc540700000000000016001454c64819279b8cc3e78e5f2be7b9121f1caa2386040047304402207abf6df0650b8723677d493b182e742a8dddd89ad1ee8eaa1c65a9b559841ecb022052fe5bcad01702e0e73c3b34cbfef957ba8e4744d614104f5d8fbc3d57cad4ce010069522103f6de61c401c947aad006ba9dbfdaad795e77be06972a3fb7308e70049d4026db2103e33af80b92e4efd64852166d6126e10aafdcc741579c67c6aa9eb89080cebeb221029791c6e3f0dc5bfa63db3f5aa0066badd6c5608d2a75394124d14df78795178153ae00000000", "02000000000101419e71a8980f8b86890a249e69bc9461f677dbefe4c856eb38baa361f0121d070000000023220020a8c4e11c15bcc878d57238016fe896c586508c913e0b300d80fa9409b031efb7ffffffff037cb002000000000016001488427232a9085b4ab6c334c6115725765864a6ad521d000000000000160014c2fe1292769b585b91fb8b045c651d79398589cc540700000000000016001454c64819279b8cc3e78e5f2be7b9121f1caa23860400473044022061b31eb92fb0555d368c2349ef9584df89bfc573a37acfd0bbf2de18d6cb51420220785706c33d3b7b735e434decddf1520ce687b168d17b40527da2712a3634f42f010069522103f6de61c401c947aad006ba9dbfdaad795e77be06972a3fb7308e70049d4026db2103e33af80b92e4efd64852166d6126e10aafdcc741579c67c6aa9eb89080cebeb221027152e86c82d162b47684a52cd9e74ed57b9fc2295531d8da6a560a7a602357fc53ae00000000"]'

The above command is executed without any errors and returns the following transaction:

02000000000101419e71a8980f8b86890a249e69bc9461f677dbefe4c856eb38baa361f0121d070000000023220020a8c4e11c15bcc878d57238016fe896c586508c913e0b300d80fa9409b031efb7ffffffff037cb002000000000016001488427232a9085b4ab6c334c6115725765864a6ad521d000000000000160014c2fe1292769b585b91fb8b045c651d79398589cc540700000000000016001454c64819279b8cc3e78e5f2be7b9121f1caa23860400473044022061b31eb92fb0555d368c2349ef9584df89bfc573a37acfd0bbf2de18d6cb51420220785706c33d3b7b735e434decddf1520ce687b168d17b40527da2712a3634f42f010069522103f6de61c401c947aad006ba9dbfdaad795e77be06972a3fb7308e70049d4026db2103e33af80b92e4efd64852166d6126e10aafdcc741579c67c6aa9eb89080cebeb221027152e86c82d162b47684a52cd9e74ed57b9fc2295531d8da6a560a7a602357fc53ae00000000

And that raw transaction is exactly the first raw transaction passed in the array to combinerawtransaction's function and returned unmodified

I am a bit lost because I do not know what is happening to not having both transactions combined. Also, I am using bitcoin testnet, I can sign and broadcast those transactions individually but I cannot combine them into one, any help will be appreciated

Steps to reproduce how I created those raw transactions:

  1. First of all I create a 2-3 multisig address:
$participants = [];
$participants[] = "03e33af80b92e4efd64852166d6126e10aafdcc741579c67c6aa9eb89080cebeb2";//pubkey1
$participants[] = "03f6de61c401c947aad006ba9dbfdaad795e77be06972a3fb7308e70049d4026db";//pubkey2
$participants[] = "029791c6e3f0dc5bfa63db3f5aa0066badd6c5608d2a75394124d14df787951781";//pubkey3

$res = $this->bitcoin->addmultisigaddress($participants, $pubkey_str);
$multisig_address = $res["address"];
$redeemScript = $res["redeemScript"];
$this->bitcoin->importaddress($multisig_address, "", false); // I import the multisig address so I can check incoming transactions

The above code is to create the multisig address associated to the first raw transaction, to create the multisig address associated to the second transaction repeat same steps but changing the third pubkey for this 027152e86c82d162b47684a52cd9e74ed57b9fc2295531d8da6a560a7a602357fc

  1. Once I created both multisig address I proceed to send some funds to both multisig address. You can check both txids: 0a582a19ab45409ad90796fc441c29129f1d429e155612a66aeed47320cf054aand 071d12f061a3ba38eb56c8e4efdb77f66194bc699e240a89868b0f98a8719e41(respectively). To fund both addresses I just opened a testnet account using electrum and spend some btc testnet.

  2. Now the next step is to create partial signed transactions (using third pubkeys). For that I need to check unspent outputs and create a raw transaction based on that data.

$res = $this->bitcoin->listunspent(2, 9999999, json_decode('["'.$multisig_address.'"]'));
$fee = 0.00002;
$total_amount = 0.00;
$total_amount = 0.00;
$txids = [];
$vouts = [];
$amounts = [];
$scriptPubs = [];
for($i=0; $i<count($transactions); $i++){
    $txids[] = $transactions[$i]["txid"];
    $total_amount+=$transactions[$i]["amount"];
    $vouts[] = $transactions[$i]["vout"];
    $amounts[] = $transactions[$i]["amount"];
    $scriptPubs[] = $transactions[$i]["scriptPubKey"];
}

$amount1 = 0.00176252;
$amount2 = 0.00007506;
$amount3 = 0.00001876;

$address1 = "tb1q3pp8yv4fppd54dkrxnrpz4e9wevxff4d2v3r6e";
$address2 = "tb1qctlp9ynkndv9hy0m3vz9cega0yuctzwv6z273w";
$address3 = "tb1q2nrysxf8nwxv8euwtu470wgjruw25guxkal3wd";

$inputs = '[';
for($j=0; $j<count($vouts); $j++){
    $inputs.='{
                        "txid": "'.$txids[$j].'",
                        "vout": '.$vouts[$j].'
                      }';
    if($j+1!=count($vouts)){
        $inputs.=',';
    }
}
$inputs.=']';

$outputs = '{"'.$address1.'": '.$amount1.', "'.$address2.'": '.$amount2.', "'.$address3.'": '.$amount3.'}';

$rawtransaction = $this->bitcoin->createrawtransaction(json_decode($inputs), json_decode($outputs));

$prevtxs = '[';
for($j=0; $j<count($txids); $j++){
    $prevtxs .= '{
                    "txid": "'.$txids[$j].'",
                    "vout": '.$vouts[$j].',
                    "scriptPubKey": "'.$scriptPubs[$j].'", 
                    "redeemScript": "'.$redeemScript.'",
                    "amount": '.$amounts[$j].'
                  }';
    if($j+1!=count($txids)){
        $prevtxs.=',';
    }
}
$prevtxs.=']';

$private_key = $this->dumpKey($pubkey3_privkey); // replace this value with cTe9h3HqgqC7wzUsVVw7hgoPkBNLUuChZNB7aKFsSYeTi5MYcABX or cQon9MgHPoAj3wBU8ne2BVaThTuRkXvb9FUFyQdjePUrYWTjdCaE
        $partially_signed = $this->signrawtransactionwithkey($rawtransaction, json_decode('["'.$private_key.'"]'), json_decode($prevtxs))["hex"]; // and in this step I get the transaction hex string

In case you have a bitcoin node with testnet blockchain you can verify that pubkey1 (cPkPnf3qhf1AALzroHixPTYBq2cLQ9HLs9fvkTsS82ccBGZDHFaV) or pubkey2 (cQmzvzai8ft574ErkUH7nPVcP2SbR7xaPurKigWGPYVbhfMop9ia) can sign partial signed raw transactions

3
  • How did you create those transactions? Will help in trying to reproduce the issue. – Prayank Apr 12 at 21:02
  • @Prayank Allow me some minutes and I will upload all detailed steps – Kevin Gravell Apr 12 at 21:18
  • @Prayank Done! I was testing it using a small php script but still I think that the code is enough clear, also I tried to keep it as simple as possible without removing any information. If you see that I am missing something to combine those transactions let me know :) Thanks! – Kevin Gravell Apr 12 at 22:05
6

The issue here is that the two transactions are different, and combinerawtransaction does not operate on different transactions (it apparently just silently does nothing). It sounds like you expect combinerawtransaction to take two separate transactions and create a new one which has the inputs and outputs of both transactions. (or perhaps take two transaction with the same outputs but different inputs and produce a transaction with the combined inputs and same outputs). However that is not what it does. Instead it actually takes the same transaction (i.e. same inputs and outputs) and merges the signatures for the same inputs together.

It is not possible to do what you want because the signatures commit to the particular inputs and outputs of that transaction. Once you try to join a transaction with another one, those signatures become invalid and the whole transaction would need to be re-signed.

4
  • Thanks for your reply! Sorry if I am asking stupid obvious questions but I am learning how to create and handle raw transactions. Now thanks your explanation I understand that function is merging signatures becoming them invalid. My intention is to make an easier multisig process between different parties, if you need to sign several multisig transactions I would like to make that you can sign several transactions at once (so you do not need to sign one transaction and broadcast it, repeating the process for all your transactions). Is that possible? Maybe using createpsbt and combinepsbt? – Kevin Gravell Apr 13 at 0:22
  • Or should I repeat the whole above process but including all inputs and outputs in the same transaction? – Kevin Gravell Apr 13 at 0:23
  • 1
    You have to include all inputs and outputs in the same transaction when you create it. – Andrew Chow Apr 13 at 0:26
  • Ok thanks! It worked combining all inputs and outputs into one transaction! – Kevin Gravell Apr 14 at 17:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.