Closed pluswave closed 6 years ago
It seems I was wrong. with this patch test also pass now.
--- a/test/integration/transactions.js
+++ b/test/integration/transactions.js
@@ -240,10 +240,19 @@ describe('bitcoinjs-lib (transactions)', function () {
txb.addInput(unspent.txId, unspent.vout, null, p2sh.output)
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 3e4)
txb.sign(0, keyPairs[0], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
+
+ const txhex = txb.buildIncomplete().toHex()
+ const txb1 = bitcoin.TransactionBuilder.fromTransaction(bitcoin.Transaction.fromHex(txhex), regtest)
txb.sign(0, keyPairs[2], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
txb.sign(0, keyPairs[3], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
+ txb1.sign(0, keyPairs[2], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
+ txb1.sign(0, keyPairs[3], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
const tx = txb.build()
+ const tx1 = txb1.build()
+ if (tx.toHex() !== tx1.toHex()) {
+ return done('serialization and deserialization inconsistent for transaction.')
+ }
// build and broadcast to the Bitcoin RegTest network
regtestUtils.broadcast(tx.toHex(), function (err) {
Is this issue resolved? I am confused.
These are the lines you are looking for:
This serializes your partially signed transaction:
const txhex = txb.buildIncomplete().toHex()
This deserializes your partially signed transaction:
const txb1 = bitcoin.TransactionBuilder.fromTransaction(bitcoin.Transaction.fromHex(txhex), regtest)
The p2sh.redeem.output
and p2wsh.redeem.output
~can be regenerated using the public keys stored in txb1.__inputs[0].pubkeys.map(key => key.toString('hex'))
~ fetched via txb1.__inputs[0].pubkeys
.
The problem is the input amounts. They are now not available. We need to use an API to get the listunspent
. Segwit introduces this burden which has broken most tools like coinb.in
.
So our script looks something like:
const txhex = txb.buildIncomplete().toHex()
const txb1 = bitcoin.TransactionBuilder.fromTransaction(bitcoin.Transaction.fromHex(txhex), regtest)
//const pubkeys = txb1.__inputs[0].pubkeys.map(key => key.toString('hex')) not required
const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys: txb1.__inputs[0].pubkeys, network })
const p2wsh = bitcoin.payments.p2wsh({redeem: p2ms, network})
const p2sh = bitcoin.payments.p2sh({ redeem: p2wsh, network })
// get unspent from API `const unspent`
const privateKey = bitcoin.ECPair.fromWIF(privateWIF)
unspent.forEach((utxo, index) => {
txb1.sign(index, privateKey, p2sh.redeem.output, null, utxo.amount, p2wsh.redeem.output)
})
txb1.build().toHex()
I think that's everything you need to sign with the second party's key.
The p2sh.redeem.output and p2wsh.redeem.output can be regenerated using the public keys stored in txb1.__inputs[0].pubkeys.map(key => key.toString('hex')).
:scream: What can we do to help you here
Segwit introduces this burden which has broken most tools like coinb.in.
Alternative wording would be: "Segwit introduces this security feature to protect users from losing funds without explicit knowledge"
Whoops they are buffers already and I was converting them to strings. D'oh!
const pubkeys = txb1.__inputs[0].pubkeys.map(key => key.toString('hex'))
const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys, network })
Becomes:
const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys: txb1.__inputs[0].pubkeys, network })
I don't mind Segwit as it reduces transaction sizes but I wish that they come up with a standard that allows all the information required to be in the TX and then drop the extra info when placed into the block.
Tested this and it works...
const bitcoin = require('bitcoinjs-lib')
const bitcore = require('bitcore-lib')
const txhex = "..."
const privateWIF = "..."
const url = "..."
fetch(`https://chain.so/api/v2/get_tx_unspent/btctest/${address}`)
.then(res => res.json())
.then(json => {
let unspent = json.data.txs.map((val, index) => {
return {index, amount: bitcore.Unit.fromBTC(val.value).toSatoshis()}
})
const txb = bitcoin.TransactionBuilder.fromTransaction(bitcoin.Transaction.fromHex(txhex), bitcoin.networks.testnet)
const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys: txb.__inputs[0].pubkeys, network: bitcoin.networks.testnet })
const p2wsh = bitcoin.payments.p2wsh({redeem: p2ms, network: bitcoin.networks.testnet})
const p2sh = bitcoin.payments.p2sh({ redeem: p2wsh, network: bitcoin.networks.testnet })
const privateKey = bitcoin.ECPair.fromWIF(privateWIF, bitcoin.networks.testnet)
unspent.forEach((utxo, index) => {
txb.sign(index, privateKey, p2sh.redeem.output, null, utxo.amount, p2wsh.redeem.output)
})
txb.build().toHex() // <- broadcast this
})
.catch(reason => console.log(reason))
I don't mind Segwit as it reduces transaction sizes but I wish that they come up with a standard that allows all the information required to be in the TX and then drop the extra info when placed into the block.
Well...
they
There is no "they." Segwit solved a problem and increased security. Consensus devs do not manage wallet software, so if any wallet software devs had a question/concern they wanted addressed, they should have said something during the 1.5 years that Segwit was well defined and in development.
a standard that allows all the information required to be in the TX and then drop the extra info when placed into the block.
There is a standard. It's called BIP174 (https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) We currently do not have this supported in bitcoinjs-lib because it's still in active development (changing rapidly) so we don't want to put it out there until things settle down. Look forward to it, though. Also tell coinbin and other wallets to support it. Interoperability will increase greatly.
Looks like this issue is solved?
Reopen if any new problems arise.
@junderw is bip174 implemented in bitcoinjs?
there is an initial implementation pull request over at our bip174 repo.
It's not ready, but it passes all the tests on the BIP.
I want to use bitcoinjs-lib in this case:
Alice and Bob already made a P2SH(P2WSH(multisig))) address;
co-operation process:
AFAIK, current TransactionBuilder and Transaction are not suitable for this case, especially for (de)serialization.