bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.6k stars 2.08k forks source link

'PrevOutScript is scripthash, requires redeemScript' is emitted even when redeem script exists #1180

Closed omrip30 closed 5 years ago

omrip30 commented 5 years ago

When creating a 'TransactionBuilder' object from an existing transaction and then signing an input, an error is thrown ('PrevOutScript is scripthash, requires redeemScript') even when the redeem script exists inside the input. The only way to avoid this is to add the redeem script again as the third parameter of the 'sign' method. Expected behaviour: the 'sign' function should check if the redeem script exists inside the input and if it does, it should use it (if no extra redeem script was provided as a parameter)

dcousens commented 5 years ago

Can you please provide reproduction code?

omrip30 commented 5 years ago

Hi, Basically I receive a multisig(2-3) transaction without signatures and I sign it with one private key. Also, each input contains the redeem script:

const bitcoin = require('bitcoinjs-lib')
const wif = require('wif')

const privateHex = 'b820275a9d01127063bf0d134cccfa2250437590d51068e85fb058af1a0c18e5'
const txHex = '0100000001b033b2214568b49fda417371aba0634b0303a2b6a19884c25d03d0b91bdbe231000000006f000000004c6952210258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c08c1a399a9121038e803e3d84cfc821cc8bf46233a9c2bb359d529db0bcdd3f1a4f38678dd02d7f2103b83e59d848407d7f62a82c99905f5ca3e8e8f5d6400eb78a0b4b067aea0720d953aeffffffff0200e1f5050000000017a914a9974100aeee974a20cda9a2f545704a0ab54fdc87c72831010000000017a9149f57a6712ef023f85ffac631ed4263b977b2d0678700000000'
const tx = bitcoin.Transaction.fromHex(txHex) // missing, added by @dcousens

const txb = bitcoin.TransactionBuilder.fromTransaction(tx, bitcoin.networks.testnet)
const privateKey = Buffer.from(privateHex, 'hex')
const wifKey = wif.encode(239, privateKey, true)

const keyPair = bitcoin.ECPair.fromWIF(wifKey, bitcoin.networks.testnet)

for (let i = 0; i < txb.__inputs.length; i++) {
  txb.sign(i, keyPair)
}
dcousens commented 5 years ago
const privateKey = Buffer.from(privateHex, 'hex')
const wifKey = wif.encode(239, privateKey, true)
const keyPair = bitcoin.ECPair.fromWIF(wifKey, bitcoin.networks.testnet)

Could be

const privateKey = Buffer.from(privateHex, 'hex')
const keyPair = bitcoin.ECPair.fromPrivateKey(privateKey, { network: bitcoin.networks.testnet })
omrip30 commented 5 years ago

That's great, but the interesting part is: for (let i = 0; i < txb.__inputs.length; i++) { txb.sign(i, keyPair) }

That's the one that throws the error.

dcousens commented 5 years ago

Fixed in https://github.com/bitcoinjs/bitcoinjs-lib/pull/1181

dcousens commented 5 years ago

Don't use txb.__inputs.length, you have the transaction, use tx.ins.length.

const privateKey = Buffer.from('b820275a9d01127063bf0d134cccfa2250437590d51068e85fb058af1a0c18e5', 'hex')
const txHex = '0100000001b033b2214568b49fda417371aba0634b0303a2b6a19884c25d03d0b91bdbe231000000006f000000004c6952210258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c'
const keyPair = bitcoin.ECPair.fromPrivateKey(privateKey, { network: bitcoin.networks.testnet })

const tx = bitcoin.Transaction.fromHex(txHex)
const txb = bitcoin.TransactionBuilder.fromTransaction(tx, bitcoin.networks.testnet)

for (let i = 0; i < tx.ins.length; i++) {
  txb.sign(i, keyPair)
}
dcousens commented 5 years ago

That said, it might be useful to have some way of accessing that information via the TransactionBuilder API...

omrip30 commented 5 years ago

Thanks:) I tried the accessing the 'tx.ins' property but it was undefined for some reason. Anyway, I think that a getter for the inputs should be added to the TransactionBuilder API

omrip30 commented 5 years ago

You're awesome, thanks!

dcousens commented 5 years ago

@omrip30 I've used your test fixture directly in https://github.com/bitcoinjs/bitcoinjs-lib/pull/1181#discussion_r211510641, thanks for the bug report :+1: