3

I'm learning about Bitcoin transaction. I tested Pay to Multisig (Multisig pubkey scripts, p2ms) by using bitcore-lib. It worked. The bellow tx is mine. That is 2-of-3 multi-sig and I have all of the three private keys.

http://tbtc.blockr.io/tx/info/c85ab15eddd1faabc86b36b5fb0a963ba4ebb3fd5839404708c5e0eb2dcaa545

How can I pay from this p2ms to regular tx (P2PKH)?

I think OP_0 SignatureA SignatureB is the unlocking script. But I have no idea what should I do..

I'm using bitcore-lib but another way is also OK.

https://github.com/bitpay/bitcore-lib/blob/master/docs/script.md

I noticed that p2ms does not have their address. Thus I cannot find utxos unlike normal way. e.g. https://api.blockcypher.com/v1/btc/test3/addrs/mqDJGWqwWghJvjqmp4sGRbhL6E1UtC7niY


Update 1

I found this following description on https://bitcore.io/api/lib/transaction However, how can I set up the utxo. As I mentioned, I cannot find the utxo.

var utxo = new UnspentOutput({
  "txId" : "a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9",
  "outputIndex" : 0,
  "address" : "mgJT8iegL4f9NCgQFeFyfvnSw1Yj4M5Woi",
  "script" : "76a914089acaba6af8b2b4fb4bed3b747ab1e4e60b496588ac",
  "satoshis" : 70000
});

var multiSigTx = new Transaction()
    .from(utxo, publicKeys, threshold)
    .change(address)
    .sign(myKeys);

var serialized = multiSigTx.toObject();

Update 2

I found that Multisig pubkey scripts refers to Bare multisig. And Bare multisig may have something problem to spend...

"Bare multisig" refers to putting the multisig script directly in the output pubkey - so all nodes must store the entire script until it is spent. This also means the sender needs to know the full multisig script, and must pay a fee sufficient to cover its (large) size.

https://bitcoin.org/en/glossary/multisig

https://www.reddit.com/r/Bitcoin/comments/32zcpl/difference_between_p2sh_multisig_and_bare/


Update 3

sign.js

var bitcore = require('bitcore-lib');
var network = 'testnet';

var key1 = new bitcore.PrivateKey("3a49e7f41ff22b017d59b3ea686e8627dc6e46b618b00b1c9da3184437cf3a79", network);
var key2 = new bitcore.PrivateKey("5cc229f92f31d87db8cba3d6891b484a96201eda76e1032f81cf205020fc2aa0", network);
var keys = [key1, key2];

var pub1 = new bitcore.PublicKey("022bda026d6aee8133f0290449a282f8cfbccafdc064b0b47068854457f38af3bc", network);
var pub2 = new bitcore.PublicKey("030a230982d9706247d5997df1aea7144266c33a2e6c64c6a3a44c5cdf9c0ff58a", network);
var pub3 = new bitcore.PublicKey("0218597441c292cb6d73174c1662ac9d60b76688fd359f90e2d653d1a089c9aba9", network);
var pubkeys = [pub1, pub2, pub3];

var utxo = new bitcore.Transaction.UnspentOutput({
  "txId" : "c85ab15eddd1faabc86b36b5fb0a963ba4ebb3fd5839404708c5e0eb2dcaa545",
  "outputIndex" : 0,
  "address" : "mfYRZHwMfvFti3gErrKeBmMmMraFJVRMyJ",
  "script" : "76a91400472c7ada0f94b832befcdd883501124305fe7b88ac", // OP_DUP OP_HASH160 20 0x00472c7ada0f94b832befcdd883501124305fe7b OP_EQUALVERIFY OP_CHECKSIG
  "satoshis" : 159800000
});

var multiSigTx = new bitcore.Transaction()
    .from(utxo, pubkeys, 2)
    .change(address)
    .sign(keys);

var serialized = multiSigTx.toString();
console.log(serialized);

node sign.js

$ node sign.js 
/private/tmp/txeditor/node_modules/bitcore-lib/lib/transaction/transaction.js:590
    throw new Error("@TODO");
    ^

Error: @TODO
    at Transaction._fromMultisigUtxo (/private/tmp/txeditor/node_modules/bitcore-lib/lib/transaction/transaction.js:590:11)
    at Transaction.from (/private/tmp/txeditor/node_modules/bitcore-lib/lib/transaction/transaction.js:552:10)
    at Object.<anonymous> (/private/tmp/txeditor/sign.js:22:6)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)
    at startup (node.js:139:18)
    at node.js:974:3

I'm looking into this error.


Update4

  utxo = new UnspentOutput(utxo);
  if (utxo.script.isMultisigOut()) {
    clazz = MultiSigInput;
  } else if (utxo.script.isScriptHashOut()) {
    clazz = MultiSigScriptHashInput;
  } else {
    throw new Error("@TODO"); // Error
  }

It seems it is not considered as multisigOut or multiSigScriptHashInput.


Update5

var bitcore = require('bitcore-lib');
var network = 'testnet';

var key1 = new bitcore.PrivateKey("3a49e7f41ff22b017d59b3ea686e8627dc6e46b618b00b1c9da3184437cf3a79", network);
var key2 = new bitcore.PrivateKey("5cc229f92f31d87db8cba3d6891b484a96201eda76e1032f81cf205020fc2aa0", network);
var keys = [key1, key2];

var pub1 = new bitcore.PublicKey("022bda026d6aee8133f0290449a282f8cfbccafdc064b0b47068854457f38af3bc", network);
var pub2 = new bitcore.PublicKey("030a230982d9706247d5997df1aea7144266c33a2e6c64c6a3a44c5cdf9c0ff58a", network);
var pub3 = new bitcore.PublicKey("0218597441c292cb6d73174c1662ac9d60b76688fd359f90e2d653d1a089c9aba9", network);
var pubkeys = [pub1, pub2, pub3];

var utxo = new bitcore.Transaction.UnspentOutput({
  "txId" : "c85ab15eddd1faabc86b36b5fb0a963ba4ebb3fd5839404708c5e0eb2dcaa545",
  "outputIndex" : 0,
  "script" : "52210218597441c292cb6d73174c1662ac9d60b76688fd359f90e2d653d1a089c9aba921022bda026d6aee8133f0290449a282f8cfbccafdc064b0b47068854457f38af3bc21030a230982d9706247d5997df1aea7144266c33a2e6c64c6a3a44c5cdf9c0ff58a53ae",
  "satoshis" : 159900000
});

var multiSigTx = new bitcore.Transaction()
    .from(utxo, pubkeys, 2)
    .to("mfYRZHwMfvFti3gErrKeBmMmMraFJVRMyJ", 159800000)
    .sign(keys);

var serialized = multiSigTx.toString();
console.log(serialized);

It worked.

$ node sign.js 
010000000145a5ca2debe0c50847403958fdb3eba43b960afbb5366bc8abfad1dd5eb15ac800000000920047304402203fa6520a6a8345603a03990ae99e7dd83a482f868f902d8f40298c44e8ea808902205e025a57c47af57892c2b616d3f92c679aefd8ac9cfd3e72f35fce6df96a0ffb01483045022100cebdb64fdc383bdbf88fe2820fe49e2e61642e9e94a3b58baa6efdde42fcf745022024a2a7a54a6c0e25b4e1580be62d336716c771dabd837430c58c392dc4c5afc501ffffffff01c05a8609000000001976a91400472c7ada0f94b832befcdd883501124305fe7b88ac00000000

Txid

http://tbtc.blockr.io/tx/info/219a49b6a376e8f4ef86866e93483552679b5157318f0e4085430a3cee24e3d8

2
  • Oh, it seems that the script it was expecting was the previous one instead of the new one, and that the new one is encoded in the .to("mfYRZHwMfvFti3gErrKeBmMmMraFJVRMyJ", 159800000). My bad.
    – sr_gi
    Feb 14, 2017 at 15:26
  • No. it was because I was not familiar with the API. You saved me.
    – zono
    Feb 14, 2017 at 15:29

1 Answer 1

2

Yo are right with how the unlocking script should be. I've never used bitcoire.io API, but for what I can see, it seems you can build the utxo by referring to the information you already have.

(Take the answer with a grain of salt, since I've never used the API, the information I'm giving you is more from a transaction structure / scripting point of view than from the API itself).

It seems that the UTXO structure of the API is a little messed up, since it mixes data that is actually referring to an UTXO (txId and index) with data that actually refers new transaction output (address, script and satoshis)

txId can be found in the previous tx c85ab15eddd1faabc86b36b5fb0a963ba4ebb3fd5839404708c5e0eb2dcaa545.

The index you should spend is 0, since is the only output generated by the previous tx.

I guess that the address field is referring to the output address (the address where you want to send bitcoins to), since you have enough information with the txId and the index to build the input of your new transaction.

I guess that script is referring to scriptPubKey, since the code is signing the transaction afterwards, what should fill the scriptSig field. According to that, the provided script should be the one that requires the public key associated with the Bitcoin address to which you what to transfer the funds (P2PKH), in that case, it should be something like:

76a9<HASH160 of the public key>88ac that is

<OP_DUP><OP_HASH160><HASH160 of the public key><OP_EQUAL><OP_CHECKSIG>

satoshis is the amount of them that you want to spend from the previous output. Take into account that, since there is just one output in the previous tx, if you don't spend all the funds from it, the rest will be considered as fees.

Finally, you should perform 2 out of 3 signatures with the private keys you have, it seems that .sign(myKeys); does the trick.

You can fiend the deserialized tx data used to answer the question in http://tbtc.blockr.io/api/v1/tx/raw/c85ab15eddd1faabc86b36b5fb0a963ba4ebb3fd5839404708c5e0eb2dcaa545

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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