Bitcoinjs-lib: Error: Input #0 has witnessUtxo but non-segwit script:

Created on 21 Nov 2019  路  19Comments  路  Source: bitcoinjs/bitcoinjs-lib

I'm trying to sign a transaction but I'm getting below error:

Error: Input #0 has witnessUtxo but non-segwit script: a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed87

Below is my code:

const bitcoin = require('bitcoinjs-lib');
const request = require('request-promise-native');
// const net = bitcoin.networks.bitcoin;
const net = bitcoin.networks.testnet;

const API = net === bitcoin.networks.testnet
    ? 'https://test-insight.swap.online/insight-api'
    : 'https://insight.bitpay.com/api'

const fetchUnspents = (address) =>
    request(`${API}/addr/${address}/utxo/`).then(JSON.parse)


(async () => {
    const psbt = new bitcoin.Psbt({ network: net });
    const alice_pair = bitcoin.ECPair.fromWIF('cR6RdGAojE4TuzRSY16a92vPfKgdjUj3tjHmoaPRcHvxRpTMr8gy', net);
    const pubkeys = [alice_pair.publicKey].map(hex => Buffer.from(hex, 'hex'));
    const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});

    const unspents = await fetchUnspents(address);
    const totalAmount = unspents.reduce((summ, { satoshis }) => summ + satoshis, 0);
    const withdrawAmount = 0.001 * 100000000;
    const fee = 0.00001 * 100000000;
    const change = totalAmount - (withdrawAmount + fee);

    unspents.forEach(element => {
        psbt.addInput({
            hash: element.txid,
            index: element.vout,
            witnessUtxo: {
                script: Buffer.from(element.scriptPubKey, 'hex'),
                value: element.amount * 100000000
            },
            // redeemScript:Buffer.from(element.scriptPubKey)
        })
    });

    psbt.addOutput({
        address: '2NBJtjiL8kHb3vGW4b945rgSbh9zasAq7qB',
        value: withdrawAmount
    });

    psbt.addOutput({
        address: address,
        value: change
    });

    psbt.signInput(0, alice_pair);

    console.log('valid signature: ', psbt.validateSignaturesOfAllInputs());
    psbt.finalizeAllInputs();
    const rawHex = psbt.extractTransaction().toHex();
    console.log(rawHex);
})()

All 19 comments

You missed redeemScript into txInput for P2SH

Instead of just grabbing the address, try this:

const p2shObj = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});
const { address } = p2shObj;
const redeemScript = p2shObj.redeem.output;

Then use redeemScript with addInput.

Let me know if this works.

@rohitsahu21

const pubkeys = [alice_pair.publicKey].map(hex => Buffer.from(hex, 'hex'));

.publicKey already Buffer so above code will raise error. You can write like this

const pubkeys = [alice_pair.publicKey]

Above utxos is not witnessUtxo so you should use nonWitnessUtxo instead. Value of nonWitnessUtxo is Buffer of hex of previous raw tx

A sample inputData is

const p2shObj = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});
const redeemScript = p2shObj.redeem.output;
psbt.addInput({
  hash: 'db87829c15a5e3100c41563bad05d65c129f637f91705628afb16a2b33c50d27',
  index: 1,
  nonWitnessUtxo: Buffer.from('02000000000101eb64c7ac988c0e3564c35c618127d398835f7176cd6089ef445b14bddf88321c04000000171600144e386df71c94aca6f4304e427e5f326685371ae1feffffff02ba4c2f000000000017a91437bf7c47aa84767161d4f70ed07e4b2d7ddb4ad08740420f000000000017a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed870247304402200a30031e9b85e56a79ec995b31fe83cfcad3aba9188dfc87d5d3f84c252b1c28022045925955d54cdc23866bd16ba0e565a6203406367b1a118667d2327fe210096401210265eb47ee4d7c71385abb4343a150c1d8713303c18bfb9a3b7be3f0ea2c760b323b8e1800', 'hex'),
  redeemScript: redeemScript,
});

psbt.signInput(0, alice_pair);
console.log('valid signature: ', psbt.validateSignaturesOfAllInputs()) // return true

@rohitsahu21

const pubkeys = [alice_pair.publicKey].map(hex => Buffer.from(hex, 'hex'));

.publicKey already Buffer so above code will raise error. You can write like this

const pubkeys = [alice_pair.publicKey]

Above utxos is not witnessUtxo so you should use nonWitnessUtxo instead. Value of nonWitnessUtxo is Buffer of hex of previous raw tx

A sample inputData is

const p2shObj = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});
const redeemScript = p2shObj.redeem.output;
psbt.addInput({
  hash: 'db87829c15a5e3100c41563bad05d65c129f637f91705628afb16a2b33c50d27',
  index: 1,
  nonWitnessUtxo: Buffer.from('02000000000101eb64c7ac988c0e3564c35c618127d398835f7176cd6089ef445b14bddf88321c04000000171600144e386df71c94aca6f4304e427e5f326685371ae1feffffff02ba4c2f000000000017a91437bf7c47aa84767161d4f70ed07e4b2d7ddb4ad08740420f000000000017a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed870247304402200a30031e9b85e56a79ec995b31fe83cfcad3aba9188dfc87d5d3f84c252b1c28022045925955d54cdc23866bd16ba0e565a6203406367b1a118667d2327fe210096401210265eb47ee4d7c71385abb4343a150c1d8713303c18bfb9a3b7be3f0ea2c760b323b8e1800', 'hex'),
  redeemScript: redeemScript,
});
psbt.signInput(0, alice_pair);
console.log('valid signature: ', psbt.validateSignaturesOfAllInputs()) // return true

Getting Error: Error: Can not add duplicate data to input

code is here:

unspents.forEach(element => {
    psbt.addInput({
        hash: element.txid,
        index: element.vout,
        witnessUtxo: {
            script: Buffer.from(element.scriptPubKey, 'hex'),
            value: element.amount * 100000000
        },
        nonWitnessUtxo: Buffer.from('02000000000101eb64c7ac988c0e3564c35c618127d398835f7176cd6089ef445b14bddf88321c04000000171600144e386df71c94aca6f4304e427e5f326685371ae1feffffff02ba4c2f000000000017a91437bf7c47aa84767161d4f70ed07e4b2d7ddb4ad08740420f000000000017a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed870247304402200a30031e9b85e56a79ec995b31fe83cfcad3aba9188dfc87d5d3f84c252b1c28022045925955d54cdc23866bd16ba0e565a6203406367b1a118667d2327fe210096401210265eb47ee4d7c71385abb4343a150c1d8713303c18bfb9a3b7be3f0ea2c760b323b8e1800', 'hex'),
        redeemScript: redeemScript
    });
});

remove witnessUtxo you don't need it. nonWitnessUtxo has all the info you need.

Give Error:

Error: No signatures to validate

and How to get nonWitnessUtxo String?

Each utxos has a separate raw hex, you are using raw hex from my example for all outputs, which is a duplicate error. So how can get raw hex from txId quickly, You can fetch from this public API then take value of key hex:

https://api.blockcypher.com/v1/btc/test3/txs/<txID here>?includeHex=true

Or using your bitcoind node with getrawtransaction API. https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/getrawtransaction/

give same error:

Error: No signatures to validate

Code is here:

const hashHex = await fetchHash(unspents[0].txid);
// console.log(hashHex);

unspents.forEach(element => {
    psbt.addInput({
        hash: element.txid,
        index: element.vout,
        nonWitnessUtxo: Buffer.from(hashHex.hex, 'hex'),
        redeemScript: redeemScript
    });
});

Error: No signatures to validate

Could you give me the output of console.log(psbt.toBase64()) just before you run validateSignaturesOfAllInputs

signInput should throw an Error if it doesn't sign. So "No signatures" is weird.

Here is the value of psbt.toBase64() :

cHNidP8BAJwCAAAAAicNxTMrarGvKFZwkX9jnxJc1gWtO1ZBDBDjpRWcgofbAQAAAAD/////rBBngcr/W5WpxRx7TuHnC5HNqla2Q4BZmkRB7L5pT3oAAAAAAP////8CoIYBAAAAAAAXqRTGI9ub/bynsfQzafnFhnBhEQdZ5IfI3g0AAAAAABepFFXp/OuRatbMX8I7OovSzIlVpDbthwAAAAAAAQD3AgAAAAABAetkx6yYjA41ZMNcYYEn05iDX3F2zWCJ70RbFL3fiDIcBAAAABcWABROOG33HJSspvQwTkJ+XzJmhTca4f7///8CukwvAAAAAAAXqRQ3v3xHqoR2cWHU9w7QfkstfdtK0IdAQg8AAAAAABepFFXp/OuRatbMX8I7OovSzIlVpDbthwJHMEQCIAowAx6bheVqeeyZWzH+g8/K06upGI38h9XT+EwlKxwoAiBFkllV1UzcI4Zr0Wug5WWmIDQGNnsaEYZn0jJ/4hAJZAEhAmXrR+5NfHE4WrtDQ6FQwdhxMwPBi/uaO3vj8OosdgsyO44YACICAyngcfcbBtO+P6ZFAOrfW4hiCWUSiAwX/4VqO6A6kTeARzBEAiBGuYf9skqvlCK+ZLBw5LHv7uhGlRJDN9WefBkbgEhxywIgL7M51cEM8rtIrdH8XJJ/bbUb0Gw0mFLlh9Lzyd85wAEBAQQlUSEDKeBx9xsG074/pkUA6t9biGIJZRKIDBf/hWo7oDqRN4BRrgABAPcCAAAAAAEB62THrJiMDjVkw1xhgSfTmINfcXbNYInvRFsUvd+IMhwEAAAAFxYAFE44bfcclKym9DBOQn5fMmaFNxrh/v///wK6TC8AAAAAABepFDe/fEeqhHZxYdT3DtB+Sy1920rQh0BCDwAAAAAAF6kUVen865Fq1sxfwjs6i9LMiVWkNu2HAkcwRAIgCjADHpuF5Wp57JlbMf6Dz8rTq6kYjfyH1dP4TCUrHCgCIEWSWVXVTNwjhmvRa6DlZaYgNAY2exoRhmfSMn/iEAlkASECZetH7k18cThau0NDoVDB2HEzA8GL+5o7e+Pw6ix2CzI7jhgAAQQlUSEDKeBx9xsG074/pkUA6t9biGIJZRKIDBf/hWo7oDqRN4BRrgAAAA==

// You need to get the tx for EVERY INPUT INDIVIDUALLY
// const hashHex = await fetchHash(unspents[0].txid);
// console.log(hashHex);

unspents.forEach(element => {
    const hashHex = await fetchHash(element.txid);
    psbt.addInput({
        hash: element.txid,
        index: element.vout,
        nonWitnessUtxo: Buffer.from(hashHex.hex, 'hex'),
        redeemScript: redeemScript
    });
});

Run fetchHash on EVERY unspent, then try it.

Hello,

I'm trying to do the same thing, but I have a mistake, if you have an idea :
"Redeem script for input #0 doesn't match the scriptPubKey in the prevout"

function scriptCheckerFactory(payment, paymentScriptName) {
   ...
    if (!scriptPubKey.equals(redeemScriptOutput)) {
      throw new Error(
        `${paymentScriptName} for input #${inputIndex} doesn't match the scriptPubKey in the prevout`,
      );
    }
}
scriptPubKey.toString("hex") -> "a914e1767896d84c2489a26666873fc29c864a03b82c87"
redeemScriptOutput.toString("hex") -> "a914f451b792d3f8cd8ba83ef6bed905a3c228dc2dd287"

My code:

    const idx = addrs.indexOf(input.address)
    //QhA84yRpiKszJSvKaDxa9GHwBRTsKHnQ7C
    const ecpair = Bitcoin.ECPair.fromWIF(addrsWallet[idx].private_key, this.network) 
    const pubkeys = [ecpair.publicKey]
    const p2shObj = Bitcoin.payments.p2sh({ redeem: Bitcoin.payments.p2ms(
        { m: 1, pubkeys, network: this.network })
    })
    const redeemScript = p2shObj.redeem.output      
    let rawTx="01000000000101282a14a07aa0ca74aa9db4918bb5dc75576795e985d44cea8c94e00189f8d67401000000171600148031e4abb080a77925c3e7818d7dc5787ffda60dffffffff0280841e000000000017a914b232f46999952516ef3c11c070d9a2af8cba1256874a324e3b0000000017a914e1767896d84c2489a26666873fc29c864a03b82c870247304402200f5c5943918ddbd8ffbf112008527c6dd92d0d65beac6556a7c1b4037dc9155702206362d1adf42c750c486970845a85b7cc6e3d3a10453e8bb001960397365fbc81012103dc63d1938cfa6574239042136990c5dfb2987a465fca2b567ac0fdee2bc60efd00000000"
    psbt.addInput({
        hash: input.txid,
        index: input.vout,                 
        witnessUtxo: {
            script: Buffer.from(input.scriptPubKey, 'hex'),
            value: input.value
        },
        //nonWitnessUtxo:  Buffer.from(rawTx, 'hex'),
        redeemScript: redeemScript,                   
    })
    psbt.signInput(0, ecpair)

if you have any suggestions....
thanks

You are spending the wrong coins.

scriptPubKey is for address A, and redeemScript is for address B.

The error is very easy to understand.

check to make sure everything is correct.

pubkeys are correctly compressed/uncompressed

No, I'm using the good address.
I found this solution:

I replace this (P2MS: "Pay To Multi-Sig")

const p2shObj = Bitcoin.payments.p2sh({ 
    redeem: Bitcoin.payments.p2ms({ m: 1, pubkeys, network: this.network })
})

by this (P2WPKH: "Pay To Witness Public Key Hash")

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

And now I can sign / validateSignaturesOfInput / extractTransaction

No, I'm using the good address

If you were using p2ms instead of p2wpkh then your redeemScript's address was incorrect compared to the address you used to fetch your scriptPubKey.

You fixed it by using the correct payment type.

Thanks for keeping us updated on your status.

For information, the scriptPubKey come from utxo (insight api)

address:"QhA84yRpiKszJSvKaDxa9GHwBRTsKHnQ7C"
amount:0.6
confirmations:50535
height:1232842
satoshis:60000000
scriptPubKey:"a914e1767896d84c2489a26666873fc29c864a03b82c87"
txid:"287f329bfd0c7989c77c341c68a701e1c98d400cd26ce075d97d6851d7bb7043"
vout:0

I will soon do a payment test...and update status

Okay, sending the transaction is working fine!
Thanks for your support.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zhaozhiming picture zhaozhiming  路  3Comments

itsMikeLowrey picture itsMikeLowrey  路  3Comments

coingeek picture coingeek  路  4Comments

ghost picture ghost  路  3Comments

thrastarson picture thrastarson  路  3Comments