bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

p2wpkh/native segwit psbt transaction script was not verified successfully

mohammadameer opened this issue · comments

i've been trying to create and broadcast a tx on btc testnet but always receiving this error

Error validating transaction: Error running script for input 0 referencing 89896a313da14f615b1ffb6713a537c908d562ca154eaea7d5464cc653d858ac at 1: Script was NOT verified successfully..

i've gone through the integration tests and searched online, looks like its an issue with the script but i'm not sure what i'm doing wrong, still learning how things work in btc

how i create and broadcast the tx

// my address tb1qesvpu44j6qaf62ae9rt755xedxwapm2ywkpefs
// address i'm try to send to tb1qf92zdta53f8ns833c4d8f2jjv0uz5nhyf8etl7
// amount is 0.00001 btc
// inputs from blockcypher /txs/new endpoint
// broadcast using blockcypher /txs/push

const network = bitcoin.networks.testnet;

/** validate inputs */
const validator = (
  pubkey: Buffer,
  msghash: Buffer,
  signature: Buffer,
): boolean => {
  // @ts-ignore
  return ECPair.fromPublicKey(pubkey).verify(msghash, signature);
};

const privateKeyWIF = (privateKey: string) => {
  const // @ts-ignore
    prvFormat = Buffer.concat([
      Buffer.from([network.wif]), // network byte
      Buffer.from(privateKey, 'hex'), // private key
      Buffer.from([0x01]), // Compressed public key flag
    ]),
    firstHash = crypto.createHash('sha256').update(prvFormat).digest(),
    doubleHash = crypto.createHash('sha256').update(firstHash).digest(),
    joinHashes = Buffer.concat([
      prvFormat,
      doubleHash.slice(0, 4), // checksum
    ]);
  return bs58.encode(joinHashes); // WIF hash
};

const privateKey = ``

/** signing key pair */
const keyPair = ECPair.fromWIF(privateKeyWIF(privateKey), network);

/** transaction object */
const psbt = new bitcoin.Psbt({network});

const pubkey = keyPair.publicKey;
const p2wpkh = bitcoin.payments.p2wpkh({pubkey, network});

// add inputs
for (let i = 0; i < inputs.length; i++) {
  const input = inputs[i];

  input.witnessUtxo.script = p2wpkh.output;

  psbt.addInput({
    hash: input.hash, // prev_hash
    index: input.index, // output_index
    witnessUtxo: input.witnessUtxo, // {script: Buffer, value}
  });
}
// add outputs
for (let i = 0; i < outputs.length; i++)
  psbt.addOutput({...outputs[i], address: outputs[i].addresses[0]});

psbt.signAllInputs(keyPair);

// validate signing
if (!psbt.validateSignaturesOfInput(0, validator)) return;

// output string
psbt.finalizeAllInputs();
return psbt.extractTransaction()?.toHex();

thanks in advance

The content of inputs and outputs is incorrect.

Can you please give more details For the inputs I confirmed I'm using the correct values, the script match the input script and tx id and the index are from the prev

the error is on inputs scripts will output affect it

I can’t give you more details.

all the code you have given is correct.

If it’s not working, then that is due to whatever is not written here.

what is not written here? inputs and outputs.

these are the inputs with script and outputs that i'm using to send the tx

// 1 input
input {"hash": "89896a313da14f615b1ffb6713a537c908d562ca154eaea7d5464cc653d858ac", "index": 1, "witnessUtxo": {"script": [Object], "value": 33143}}
input script {"data": [0, 20, 204, 24, 30, 86, 178, 208, 58, 157, 43, 185, 40, 215, 234, 80, 217, 105, 157, 208, 237, 68], "type": "Buffer"}
input script hex 0014cc181e56b2d03a9d2bb928d7ea50d9699dd0ed44

// 2 outputs
output {"address": "tb1qf92zdta53f8ns833c4d8f2jjv0uz5nhyf8etl7", "value": 1000}
output {"address": "tb1qesvpu44j6qaf62ae9rt755xedxwapm2ywkpefs", "value": 31929}

the signed hash that i'm broadcasting

02000000000101ac58d853c64c46d5a7ae4e15ca62d508c937a51367fb1f5b614fa13d316a89890100000000ffffffff02e803000000000000160014495426afb48a4f381e31c55a74aa5263f82a4ee40e7b000000000000160014cc181e56b2d03a9d2bb928d7ea50d9699dd0ed4402473044022100b221378fcf806f185d52da910dcde1391e5dcd03eb476c9f4a33b36044d86a53021f01fcb511bbe3da0de7472ca691fdca92d42cb8cae0ee02ed7cbc3cf2b458ba012103574c43180a7f73383fbf2a516af17947a7aafc569002a2174d0f68a34d1ab04c00000000

You are signing with the wrong key.

You don't realize it because you are overwriting the script with p2wpkh.output.

The signed transaction you posted contains 03574c43180a7f73383fbf2a516af17947a7aafc569002a2174d0f68a34d1ab04c as its public key, but this public key does not equal cc181e56b2d03a9d2bb928d7ea50d9699dd0ed44 when hashed with HASH160 (the hash used to make the p2wpkh.)

The solution: you should use the correct key for privateKey

i use walletcore and i can derrive the private key from the mnemonic using different chains, i get the correct pubkey and hash160 from the private key when i derrive it from btc but still get same error

public key 02554afb7fa245ce52d323b9254f91185b3b3738d08837fc786cabcd0fc6dee056
public key hashed with hash160 cc181e56b2d03a9d2bb928d7ea50d9699dd0ed44

txs hash

02000000000101ac58d853c64c46d5a7ae4e15ca62d508c937a51367fb1f5b614fa13d316a89890100000000ffffffff02e803000000000000160014495426afb48a4f381e31c55a74aa5263f82a4ee4597c000000000000160014cc181e56b2d03a9d2bb928d7ea50d9699dd0ed4402473044022053e98a808c65daff4fb1604449eb94ad8828fc9211e217156824706c639b5abf02206b2ff3cde3e2b09dd1e2a50af186211feb3d26ad823c8cd6ae37fdbf749169ce012102554afb7fa245ce52d323b9254f91185b3b3738d08837fc786cabcd0fc6dee05600000000

02000000000101ac58d853c64c46d5a7ae4e15ca62d508c937a51367fb1f5b614fa13d316a89890100000000ffffffff02e803000000000000160014495426afb48a4f381e31c55a74aa5263f82a4ee4417c000000000000160014cc181e56b2d03a9d2bb928d7ea50d9699dd0ed4402483045022100cbf4fa81c40190fccccd13659f1f5b1d23a4bc4c1f4a9f2618c892b0a97e6e00022021655b3204569a59a097cd724534176e5755acc0bfb995975f2b012a94b0fc4a012102554afb7fa245ce52d323b9254f91185b3b3738d08837fc786cabcd0fc6dee05600000000

> bitcoin.crypto.hash160(
      Buffer.from('02554afb7fa245ce52d323b9254f91185b3b3738d08837fc786cabcd0fc6dee056','hex')
  ).toString('hex')
'f9f5fdf91be4a57f52a39543201d16d174c29eb0'

You have the wrong key.

cc181e56b2d03a9d2bb928d7ea50d9699dd0ed44 does not equal f9f5fdf91be4a57f52a39543201d16d174c29eb0

And just to make sure the p2wpkh internals aren't incorrect. Here's the same exact hash.

> b.payments.p2wpkh(
        { pubkey: Buffer.from('02554afb7fa245ce52d323b9254f91185b3b3738d08837fc786cabcd0fc6dee056','hex') }
    ).hash.toString('hex')
'f9f5fdf91be4a57f52a39543201d16d174c29eb0'
> b.payments.p2wpkh(
        { pubkey: Buffer.from('02554afb7fa245ce52d323b9254f91185b3b3738d08837fc786cabcd0fc6dee056','hex') }
    ).output.toString('hex')
'0014f9f5fdf91be4a57f52a39543201d16d174c29eb0'

using bip32 and bip39 i'm able to get the correct seed, publicKey and WIF for path m/84'/0'/0'/0/0

but when trying to create the hash using same above code i get cc181e56b2d03a9d2bb928d7ea50d9699dd0ed44 0014cc181e56b2d03a9d2bb928d7ea50d9699dd0ed44 also a different address

my environment is a RN app with version 0.68.7

"@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3",
"bitcoinjs-lib": "6.1.5",

@junderw i was able to fix the issue by upgrading RN to a version +0.70.0, from different discussions in this repo and the noble repos i saw that the JS Native BigInt is used, and RN only support it after version 0.70.0

thanks for your help 🙏