Pages:
Author

Topic: Multi-signature address never receives bitcoins (Read 5114 times)

legendary
Activity: 1008
Merit: 1007
November 17, 2013, 06:08:23 AM
#43
Didn't you already found out how to do that earlier?

https://bitcointalksearch.org/topic/m.3435441

In any case, we store unspent outputs for every address in a database, along with information needed to spend it: txid, vout, value. For this we monitor the blockchain continuously add check for transactions involving addresses that we care about.

I just wanted to double check what options I had, but I see that incrementally storing them and then revalidating is pretty much the only choice, bar a blockchain rescan at each withdrawal Smiley
member
Activity: 80
Merit: 10
Lead developer
Didn't you already found out how to do that earlier?

https://bitcointalksearch.org/topic/m.3435441

In any case, we store unspent outputs for every address in a database, along with information needed to spend it: txid, vout, value. For this we monitor the blockchain continuously add check for transactions involving addresses that we care about.
legendary
Activity: 1008
Merit: 1007
I guess that transmitting redeemScript with the transaction doesn't expose any potential vulnerability?

No, it doesn't, because as I said, it gets transmitted in the transaction's hex data anyway.

Congrats on finally succeeding in signing a multisig transaction. I know how happy I was the first time I received "complete: true" Smiley.

Quick follow up question - how do you go about collecting unspent outputs from multi-sig addresses to use in future transactions?
member
Activity: 80
Merit: 10
Lead developer
I guess that transmitting redeemScript with the transaction doesn't expose any potential vulnerability?

No, it doesn't, because as I said, it gets transmitted in the transaction's hex data anyway.

Congrats on finally succeeding in signing a multisig transaction. I know how happy I was the first time I received "complete: true" Smiley.
legendary
Activity: 1008
Merit: 1007
You can recreate the redeemScript using createmultisig command at any time, if you use the same public keys. This will result in same P2SH address & redeemScript pair. Note that the order of keys DOES matter here, if you mix it up, it will result in a different address/redeemScript pair.

You can also extract the redeemScript from the transaction hex data. It's the last parameter of the input you are signing. This could be tricky to implement correctly though, so it's definitely better to store and send the redeemScript along with the transaction.

In the end, did you manage to get "complete": true with your signed transaction? If you get false and the hex data doesn't change, it usually means that the private key was invalid, so bitcoind didn't sign anything.

Hi,

Thanks for the advice - I guess that transmitting redeemScript with the transaction doesn't expose any potential vulnerability?

As to your question, yes I did finally get complete=true Smiley

Cheers, Paul.
member
Activity: 80
Merit: 10
Lead developer
You can recreate the redeemScript using createmultisig command at any time, if you use the same public keys. This will result in same P2SH address & redeemScript pair. Note that the order of keys DOES matter here, if you mix it up, it will result in a different address/redeemScript pair.

You can also extract the redeemScript from the transaction hex data. It's the last parameter of the input you are signing. This could be tricky to implement correctly though, so it's definitely better to store and send the redeemScript along with the transaction.

In the end, did you manage to get "complete": true with your signed transaction? If you get false and the hex data doesn't change, it usually means that the private key was invalid, so bitcoind didn't sign anything.
legendary
Activity: 1008
Merit: 1007
kjj
legendary
Activity: 1302
Merit: 1026
The gist is incredibly useful.  Be sure to copy out the commands and reformat them so you can see what's really going on.  The long lines can be hard to follow.  If you unpack the commands in the gist, you can see that the redemption info is needed both to create and to sign.

The transaction goes through several stages when redeeming multisig.

First, a partial transaction is created that specifies which transaction is to be redeemed, and lists the outputs.

Second, the information needed to actually redeem the P2SH input are added to the transaction.  You can see this as an explicit step if you call signrawtransaction with the redemption info, but without any private keys.

Next, one or more signatures are added.  This can be one step, or many.

Here is example PHP code.  This is not a utility suitable for production usage, it is just a demonstration of how things work, but you can use it for one-off redemption, or modify it to accept the payment info.

Code: (redeemmultisig.php)

// this file sets up the $rpc object used for RPC calls later
require_once("local_connection_info.php");

// which transaction output are you redeeming?
$redeemtxid="";
$redeemvout=0;

// what is the redeemscript that hashes to that address?
$redeemscript="";

// It may be possible to derive this from the txout info, but for now you have to enter it
$redeempubkey="";

// If you provide enough keys to complete the transaction, it will send automatically
// otherwise, it will provide the partially signed transaction
// Note that this script isn't capable of continuing a partially signed transaction
// (it should be easy to add.)
$privkeys=array(
     
"",
     
"",
);

// 3 modes
// Pay to self - ask bitcoind for a new address, send everything to it (minus the fee)
// Pay someone else, change back to me - ask bitcoind for a new address, use it for change (put "SELF" in as $changeaddr, address in as $payaddr)
// Pay someone else, change to someone else - specify addresses for both $payaddr and $changeaddr
$payaddr="SELF";
$fee=0.00;
$payamount=0;   // ignored if paying to self
$changeaddr=""// ignored if paying to self

// Thus ends the configuration section.  All below is work


// Fetch the info we need from the old transaction
$txhex=$rpc->getrawtransaction($redeemtxid);
$txbody=$rpc->decoderawtransaction($txhex);

// configure the outputs
// change amount is always calculated automatically
if("SELF"==$payaddr){
 
$paddr=$rpc->getnewaddress();
 
$pays=array($paddr=>$txbody['vout'][$redeemvout]['value']-$fee);
}elseif(
"SELF"==$changeaddr){
 
$caddr=$rpc->getnewaddress();
 
$camt=$txbody['vout'][$redeemvout]['value']-$payamount-$fee;;
 
$pays=array($payaddr=>$payamount,$caddr=>$camt);
}else{
 
$camt=$txbody['vout'][$redeemvout]['value']-$payamount-$fee;
 
$pays=array($payaddr=>$payamount,$changeaddr=>$camt);
}

// this array holds the info needed to redeem the transaction
$redeemblock=array(array("txid"=>$redeemtxid,"vout"=>$redeemvout,"scriptPubKey"=>$redeempubkey,"redeemScript"=>$redeemscript));

// now we create the transaction, complete it, and sign it
$raw=$rpc->createrawtransaction($redeemblock,$pays);
$signed=$rpc->signrawtransaction($raw,$redeemblock,$privkeys);

// This would be a good place to inspect the output.  Uncomment these to verify function.
//$decoded=$rpc->decoderawtransaction($signed['hex']);
//print_r($decoded)
//die();

if(1==$signed['complete']){
 
$outtxid=$rpc->sendrawtransaction($signed['hex']);
 echo 
$outtxid."\n";
}else{
 echo 
$signed['hex']."\n";
}

?>

legendary
Activity: 1008
Merit: 1007
You may find this gist by Gavin useful.

I did, but it also threw me off, because its out of date.

In that example, gavin passes scriptPubKey and redeemScript to createrawtransaction. This is no longer correct. You must pass these to signrawtransaction now.
legendary
Activity: 1974
Merit: 1030
You may find this gist by Gavin useful.
legendary
Activity: 1008
Merit: 1007
Ok, managed to get something working but only in the case of using two separate wallets with one private key located in each. In addition both wallets need to have the multi-sig address you're using added to them, despite them already containing one private key each.

Is there a way to have a wallet correctly sign a multi-sig transaction without explicitly adding the multi-sig address to it?

Ok, to answer my own question, *yes* there is a way, and here is how:

* use createmultisig 2 [pubKeyA, pubKeyB] to generate a redeemScript and an address
* createrawtransaction as usual
* signrawtransaction using private key A, and also you must pass, for each transaction output:
{
   txid - this is the txid of the transaction you just created, NOT the funding transaction
   vout - index of transaction output
   scriptPubKey - this is from the output (indexed vout) for the transaction you just created
   redeemScript - this is from createmultisig
}
* transmit the hex transaction to the other party along with the redeemScript
* have the other party perform the same process for signing on their end
* transaction is signed correctly.

I was unable to determine if the other party could extract the redeemScript from the transaction alone which would save some messing around.

note: something which threw me was the offical documentation for signrawtransaction, which omits to mention redeemScript. This could do with fixing

Cheers, Paul.
legendary
Activity: 1008
Merit: 1007
Ok, managed to get something working but only in the case of using two separate wallets with one private key located in each. In addition both wallets need to have the multi-sig address you're using added to them, despite them already containing one private key each.

Is there a way to have a wallet correctly sign a multi-sig transaction without explicitly adding the multi-sig address to it?
legendary
Activity: 1008
Merit: 1007
I'm quite familiar with how this all works so if you have any more technical questions, feel free to ask, I'm glad to help Smiley.

Thanks for the offer, I'll take you up on how to create and sign a multi-sig transaction.

I currently have:

* sent funds to a 2/2 multi-sig address
* created a raw transaction spending the output of the above
* signed with one private key (which is in wallet, but I passed it to the function anyway)
* signed with the other private key (not in wallet)

The process does not fail, but the resulting signed transaction has complete set to 'false', which isn't right.

edit: looking at the raw transaction after creating it, signing it once, signing it twice, the hex doesn't change at all, which must mean something very wrong is happening?

Hope you can help!

Cheers, Paul.
member
Activity: 80
Merit: 10
Lead developer
Just visit any block explorer, to see the balance at a particular address.


Fantastic advice, thanks for taking the time.

@monsterer: Message me if you'd like to receive an invite code for Bitalo, which implements multi-signature addresses for its wallets and creates/signs transactions on client-side, in Javascript. On the server side it does exactly the process that you described above - iterating over transactions in blocks and crediting users wallet balances.
It works quite well at the moment, though we're still testing it to find out any outstanding bugs in the implementation.

I'm quite familiar with how this all works so if you have any more technical questions, feel free to ask, I'm glad to help Smiley.

Edit: Blockexplorers are tricky, because they don't handle P2SH addresses well yet. For example:

http://blockexplorer.com/testnet/tx/67a05915c2a90e9743f04fb5e76f954204002401150ab34ebaed6f721056ae23
http://testnet.btclook.com/txn/67a05915c2a90e9743f04fb5e76f954204002401150ab34ebaed6f721056ae23

This is a valid transaction from P2SH address to another. Blockexplorer lists the inputs and outputs as "Strange", and BTCLook shows "Huh", even though they are perfectly legal.
legendary
Activity: 1008
Merit: 1007
Just visit any block explorer, to see the balance at a particular address.


Fantastic advice, thanks for taking the time.
legendary
Activity: 1596
Merit: 1100
Just visit any block explorer, to see the balance at a particular address.
legendary
Activity: 1008
Merit: 1007
That's standard fare, with pay-to-script-hash (P2SH).  Multisig P2SH addresses are easy.

"addmultisig" RPC call handles this, for bitcoind / Bitcoin-QT.

No its not standard fare. As the title of this thread indicates, the standard mechanisms in bitcoind (listsinceblock, listtransactions, getbalance etc etc) do not report any information about coins at multi-sig addresses unless the wallet contains all the private keys.

This method I've just described is AFAIK, the *only* way to tell that coins have arrived on an address, making it very far from standard fair, given the amount of work it is.
legendary
Activity: 1596
Merit: 1100
This is huge, because it means you can give out multi-sig addresses to your users and actually be able to credit them when the coins arrive!

That's standard fare, with pay-to-script-hash (P2SH).  Multisig P2SH addresses are easy.

"addmultisig" RPC call handles this, for bitcoind / Bitcoin-QT.

legendary
Activity: 1008
Merit: 1007
If you don't know the txid you could scan the blockchain for new txIDs and use getrawtransaction on each of them to figure out if any outputs were sent to the multi-sig address.

Haven't implemented it yet so I'm not sure if it will work like this but so far it looks like it could imho.

Ok, so it turns out that you are right - it *is* possible to tell if someone has sent coins to a multi-sig address. This is the process:

Code:
* Start from last processed block hash
* Call getblock
* Iterate through all transaction ids (which really are *all* txids, and not just those in your wallet - this is the first part of the key to the process)
{
   * call getrawtransaction on each txid (which also lets you inspect non-wallet transactions, 2nd part of the key to the process)
   * Iterate through all vouts
   {
      * check each address in the scriptPubKey list to see if it matches your multi-sig address
      * if it does, you've found a deposit! You can determine the number of confirmations from the call you made to getrawtransaction
   }
}
* Goto next block hash

This is huge, because it means you can give out multi-sig addresses to your users and actually be able to credit them when the coins arrive!

Cheers, Paul.
newbie
Activity: 27
Merit: 0
I just ran into the same problem while working on the Moneychanger project for open-transactions.

A solution is to use getrawtransaction to check if requested money was sent to the p2sh address in the first place,
then getrawmempool to see if it has any confirmations yet,
then getblockcount --> getblockhash(count) --> getblock(hash) --> getblock(block->previous) -->... to iterate through the blockchain to figure out how many confirmations it has.

If you don't know the txid you could scan the blockchain for new txIDs and use getrawtransaction on each of them to figure out if any outputs were sent to the multi-sig address.

Haven't implemented it yet so I'm not sure if it will work like this but so far it looks like it could imho.

This all seems very hackish and error-prone to me so I hope we'll soon get proper bitcoin API support for that kind of transactions.
Pages:
Jump to: