bitcoinjs / bitcoinjs-lib

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

Problem when sending p2wpkh address #1541

Closed khiemkino closed 3 years ago

khiemkino commented 4 years ago

Here is my hex transaction 010000000122946aa47a58b28b13dde495ab816abad94bae9929c9fdc072b3b9af0052e978000000006b483045022100d2ec7850d53c9f37ccf71716c890f2988dd23e1f36739749736e17946838776a02207116c1a0290963192371064a887aef3f48dbceb58e1c3cf084e2360b54305202012103e2f4a2dfcf5c8f0ec4641aeac1ab0a19864166e9789ccbf52c33812d66d2dbadffffffff0110270000000000001600140167a00be5f8973ce8d1c3593a6097ac5030b91e00000000 When i broad cast this txs using https://live.blockcypher.com/btc/pushtx/ it get the error Error validating transaction: witness script detected in tx without witness data. Can some one help me. I'm newbie on bitcoin

longhoangwkm commented 4 years ago

sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Witness requires empty scriptSig) (code 64)"}.

First at all, you are use bitcoin main net to develop. We don't recommend it. Let move over to testnet to make it easier to share information like private keys for easier debugging.

Could you share your code how you to create an above tx hex ?!

Btw, here are an example how to create Create a Transaction with a SegWit P2WPKH input

HamzaYasin1 commented 4 years ago

There you go the full code to send bech32 address transactions.

const bitcoin = require("bitcoinjs-lib");

let utxo = [{
        txId: '37e14bbaab07f7dbe7ef391e80071b9fc0dfc9289886ac5d80e0c2394363b324',
        outputIndex: 1,
        address: 'ltc1q9umns6nuxv3xrhzdwlmhkzujewu6hulyuwgx30',
        script: '00142f37386a7c332261dc4d77f77b0b92cbb9abf3e4',
        satoshis: 3000
    },
    {
        txId: '37e14bbaab07f7dbe7ef391e80071b9fc0dfc9289886ac5d80e0c2394363b324',
        outputIndex: 0,
        address: 'ltc1q9umns6nuxv3xrhzdwlmhkzujewu6hulyuwgx30',
        script: '00142f37386a7c332261dc4d77f77b0b92cbb9abf3e4',
        satoshis: 5000
    }
]

let NETWORK = bitcoin.networks.bitcoin;
let txb = new bitcoin.TransactionBuilder(NETWORK);

//need scriptPubKey for adding input
let WIF = ""; //private key of bech32 output
let keypair = bitcoin.ECPair.fromWIF(WIF, NETWORK);
let scriptPubkey = bitcoin.script.witnessPubKeyHash.output.encode(
    bitcoin.crypto.hash160(
        keypair.getPublicKeyBuffer()
    )
);

//add input
for (let item = 0; item < utxo.length; item++) {

    txb.addInput(utxo[item].txId, utxo[item].outputIndex, null, scriptPubkey);
balance = balance + utxo[item].satoshis
}

        let changeAmount = balance - (value + fee)

   txb.addOutput(inputReceiverAddress, value);
        txb.addOutput(inputChangeAddress, changeAmount);
// //signing
for (let item = 0; item < utxo.length; item++) {

    txb.sign(item, keypair, null, null, utxo[item].satoshis);
}
let tx = txb.build();
let txhex = tx.toHex();

console.log(txhex);
junderw commented 4 years ago

@HamzaYasin1 that code is for v3.x.x, and we are currently on v5.x.x.

max-lt commented 4 years ago

I reproduced the same issue.

the returned transaction is valid but I got the following error from blockstream info :

sendrawtransaction RPC error: {
  "code": -26,
  "message": "non-mandatory-script-verify-flag (Extra items left on stack after execution) (code 64)"
}
import { PsbtInputUpdate, TransactionInput } from 'bip174/src/lib/interfaces';
const toASM = bitcoin.script.toASM;

const network = bitcoin.networks.testnet;
const psbt = new bitcoin.Psbt({ network });

psbt.addOutput({
  address: 'tb1q2u8t0wjcvmnvhdjw7v0gp44jutwewz4t2ptuxtj96x9chfwpl5qscjsx50',
  value: 700
});

// const tx = await this.txService.getTransaction('ec0da321b85f95349f174a62cbda11d936e6b2edaac2bf411efd4d7bfa663b23');
const tx = bitcoin.Transaction.fromHex(
  '0200000000010134a63889952bcd31ec9d90ef5b936a3fc599aca1854a61adb5' +
  '0f998840ed1e8a0100000000ffffffff0184030000000000002200206a097c57' +
  '4946f5d0d05a44d3d0a01c891ebe6c6e1235ae709be4583f9d9b5a9702483045' +
  '022100a0316d35e3aa3be6d6abbf529f7b9589a1722e19c39cd184d5936042a0' +
  '53d8bb0220467b437f29af8e5274f0b4684450f5adb33cd53c417c8caf2690e7' +
  'b6b86da43c0121022f440c477fd0683841d4e76bcfe4371539c9006be4ac139d' +
  'c66a87545c8eef4200000000'
);

const index = 0;
const input: PsbtInputUpdate & TransactionInput = {
  hash: tx.getId(),
  index
};

input.nonWitnessUtxo = tx.toBuffer();

// const ecpair = this.walletService.derive(1);
const ecpair = bitcoin.ECPair.fromWIF('cNgEuSCjocr1i1n2W2hwjkBgnPBsmcSZmjSP1is8nJScqymQxKsa', network);

const p2wsh = bitcoin.payments.p2wsh({
  redeem: bitcoin.payments.p2wpkh({
    pubkey: ecpair.publicKey,
    network
  })
});

input.witnessScript = p2wsh.redeem.output; // P2WSH only
console.log('SEQ', toASM(p2wsh.output) === toASM(tx.outs[index].script)); // true

psbt.addInput(input);

psbt.signInput(index, ecpair);

console.log('SIGS', psbt.validateSignaturesOfAllInputs()); // true

psbt.finalizeAllInputs();

const ftx = psbt.extractTransaction();

// 57ff26ffd282f8f17845ac319df4bd8b8df8e093252571f3fe61021db8aedd98
console.log(ftx.getId());

// 02000000000101233b66fa7b4dfd1e41bfc2aaedb2e636d911dacb624a179f34955fb821a30dec0000000000ffffffff01bc02000000000000220020570eb7ba5866e6cbb64ef31e80d6b2e2dd970aab5057c32e45d18b8ba5c1fd010347304402206563c23bf00191dcb890ad7f9b280f1a5cdb30ee09da742cc543c39fe3e03e6c022005b96307f6d5a047960750c4a36a20064d0e45bc3a281f8eccc4fe82e5cf6289012102f64eac4e8bb6096f9e3ce644921db2754ec7709402e6fccc6fc452d6b2678c75160014264b274c380e35ac52fe0dac57d01395c0cbf5b400000000
console.log(ftx.toHex());
junderw commented 4 years ago

P2WSH-P2WPKH is not a valid script.

junderw commented 4 years ago

try using p2sh instead of p2wsh, and you will need to create a new address and send some coins to it and try again...

Also, you don't need nonWitnessUtxo for segwit.

Something like the below should work.

const p2sh = bitcoin.payments.p2sh({
  redeem: bitcoin.payments.p2wpkh({
    pubkey: ecpair.publicKey,
    network
  }),
  network
});

input.witnessUtxo = {
  script: p2sh.output!,
  value: 10000,
}
max-lt commented 4 years ago

I had to make some changes to your answer to make it work

// input.witnessUtxo = {
// script: p2sh.redeem.output,
//   value: prev.vout.value
// };

input.redeemScript = p2sh.redeem.output;
input.nonWitnessUtxo = prev.tx.toBuffer();

Doesn't p2sh lack of witness data ?

junderw commented 4 years ago

p2wpkh is segwit, regardless of whether it is inside P2SH or not.

junderw commented 4 years ago

nonWitnessUtxo is therefore not needed.

witnessUtxo is all you need.