bitcoinjs-lib icon indicating copy to clipboard operation
bitcoinjs-lib copied to clipboard

I need help asap 2

Open Lutnerd opened this issue 3 years ago • 7 comments
trafficstars

Good day everyone I need help I went to broadcast my transaction it’s giving me error when I’m trying to push transaction 3EC5C8A4-95DE-48D1-82FB-CD18BA737762

On the below when I decode raw transaction it’s giving me this addresses": [ "14XzvjeSSPTNt1in2XZtug8aXxVyVVe8tq", "bc1qdkezmg0ah89l23tfleasngcd4tfnpsgh2lh9jl" ], "block_height": -1, "block_index": -1, "confirmations": 0, "double_spend": false, "fees": 29700000, "hash": "6922dc59f148b4b8268bc914f7fcf016e46c4a8d8a053be45ded09729b933c79", "inputs": [ { "addresses": [ "14XzvjeSSPTNt1in2XZtug8aXxVyVVe8tq" ], "age": 741957, "output_index": 1, "output_value": 149700000, "prev_hash": "f73f407dcb4d4d7f0570a615e2fdde1f6fc5bf75f7183e7dd39b428286d75670", "script": "76a91426c535f6258a5cfcee1ccbb879cd8dc147a0fd7388ac", "script_type": "pay-to-pubkey-hash", "sequence": 4294967293 } ], "opt_in_rbf": true, "outputs": [ { "addresses": [ "bc1qdkezmg0ah89l23tfleasngcd4tfnpsgh2lh9jl" ], "script": "00146db22da1fdb9cbf54569fe7b09a30daad330c117", "script_type": "pay-to-witness-pubkey-hash", "value": 120000000 } ], "preference": "high", "received": "2022-06-23T08:34:47.604665062Z", "relayed_by": "3.236.233.149", "size": 107, "total": 120000000, "ver": 1, "vin_sz": 1, "vout_sz": 1, "vsize": 107

}

Lutnerd avatar Jun 23 '22 08:06 Lutnerd

I Have found this older issue (it might help): https://github.com/bitcoinjs/bitcoinjs-lib/issues/924

Please also describe how the API of this lib is being used.

motorina0 avatar Jun 27 '22 05:06 motorina0

Hello everyone, I have the same problem.

import { ECPairAPI, ECPairFactory } from 'ecpair';
import * as bitcoin from 'bitcoinjs-lib';
import * as ecc from 'tiny-secp256k1';

create keys using the function:

const generateKey = () => {
  const NETWORK = bitcoin.networks.testnet;
  const ECPair: ECPairAPI = ECPairFactory(ecc);
  const keyPair = ECPair.makeRandom({ network: NETWORK });
  const { address } = bitcoin.payments.p2pkh({
    pubkey: keyPair.publicKey,
    network: NETWORK,
  });
  const publicKey = keyPair.publicKey.toString('hex');
  const privateKeyWif = keyPair.toWIF();
  return {
    address,
    publicKey,
    privateKeyWif,
  };
};

output:

{
  address: 'mx8HFEoW6gnZ3993N5p2B2hAgQwW85biLd',
  publicKey: '03a91708dc31db2376e7ee11d9945478dda2dfe5047651acb90948bffa8ab0038e',
  privateKeyWif: 'cRzY6KknsptFznYgGsdQCTghVXB5ZQayde7qthsYXEAVWqiYAcQv'
}

{
  address: 'mkYC3kNNgVCN5dHS4Ao7ZDYpXcXQM7BwLv',
  publicKey: '028389bfbfb2775ff7b346d772a495983eb50cd49162ae3087aadafb5090a001d1',
  privateKeyWif: 'cSrYNJfE1eCpsJcbyu1GnvRusAwZuuiTTqkWdtRCbbQoGsmjKmA1'
}
const getTxUtho = async (address: string) => {
  try {
    const res = await fetch(`https://api.blockcypher.com/v1/btc/test3/addrs/${address}/full?includeHex=true`, {
        method: 'GET',
        headers: {
        'Content-Type': 'application/json'
        },
    });
    if (!!res.txs.length) {
      return {
        hash: res.txs[0].hash,
        hex: res.txs[0].hex,
      };
    }
  } catch(e) {
      console.error(e);
  }
}
const pushRawTransaction = async ( txHex: string ) => {
  try {
    const res = await fetch(`https://api.blockcypher.com/v1/btc/test3/txs/push`, {
        method: 'POST',
        body: JSON.stringify({ tx: txHex }),
        headers: {
        'Content-Type': 'application/json'
        },
    });
    return res.hash;
  } catch(e) {
      console.error(e);
  }
};
const validator = (
  pubkey: Buffer,
  msghash: Buffer,
  signature: Buffer,
): boolean => {
  const ECPair = ECPairFactory(ecc);
  return ECPair.fromPublicKey(pubkey).verify(msghash, signature);
};
const sendTransactions = async (
  to: string,
  amount: number,
  from: string,
  privateKey: string,
  publicKey: string,
) => {
  const publicKeyBuffer = Buffer.from(publicKey, 'hex');
  const ECPair = ECPairFactory(ecc);
  const NETWORK = bitcoin.networks.testnet;

  const alice = ECPair.fromWIF(privateKey, NETWORK);

  const p2wpkh = bitcoin.payments.p2wpkh({
    pubkey: publicKeyBuffer,
    network: NETWORK,
    m: 1,
  });

  const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network: NETWORK });
  const redeemScript = p2sh.redeem.output;

  const { hash, hex } = await getTxUtho(from);
  const psbt = new bitcoin.Psbt({ network: NETWORK });
  psbt.addInput({
    hash: hash, //txId
    index: 0,
    nonWitnessUtxo: Buffer.from(hex, 'hex'),
    redeemScript,
  });

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

  psbt.signInput(0, alice);
  psbt.validateSignaturesOfInput(0, validator);
  psbt.finalizeAllInputs();
  const txRaw = psbt.extractTransaction(true); // max fee
  const txHash = await pushRawTransaction(txRaw.toHex());
  return txHash;
}
sendTransactions(
  'mx8HFEoW6gnZ3993N5p2B2hAgQwW85biLd',    // to
  10000,    // amount
  'mkYC3kNNgVCN5dHS4Ao7ZDYpXcXQM7BwLv',    // from
  'cSrYNJfE1eCpsJcbyu1GnvRusAwZuuiTTqkWdtRCbbQoGsmjKmA1',    //private
  '028389bfbfb2775ff7b346d772a495983eb50cd49162ae3087aadafb5090a001d1',    //public
);

Can you please point out what is my mistake?

mb38 avatar Jun 27 '22 13:06 mb38

@mb38 You are mixing up p2pkh and p2wpkh. Pick one.

(Your generate keys is generating p2pkh address, but your send function treats it like p2sh-p2wpkh...)

junderw avatar Jun 28 '22 03:06 junderw

@junderw Thanks, I fixed it to p2pkh.

const p2pkh = bitcoin.payments.p2pkh({
      pubkey: publicKeyBuffer,
      network: NETWORK,
      m: 1,
    });

const p2sh = bitcoin.payments.p2sh({ redeem: p2pkh, network: NETWORK });

But now I'm getting a new error when sending a POST request to: https://api.blockcypher.com/v1/btc/test3/txs/push

{
	"error": "Error validating transaction: Error running script for input 0 referencing 867e6297d599e36220c3542095123f3de120d45fd57e014be634db0cb603efe6 at 0: Script was NOT verified successfully.."
}

HEX that I send:

{
"tx":"0200000001e6ef03b60cdb34e64b017ed55fd420e13d3f12952054c32062e399d597627e860000000085483045022100dfbcbc3d66bacbd4c2b31372d5caa4c65709f7a8749d38ee37d5393512b5d97b022017d9543d892f9280b916081fa7c4a4ef1a0a9486f212b4b6a8fd59a315aa6c4f0121028389bfbfb2775ff7b346d772a495983eb50cd49162ae3087aadafb5090a001d11976a9143714868de0b58bd838ac2e7e40033ee1970204fc88acffffffff0101000000000000001976a914b630641e3b490b573cf53e34b1bc20a10a54042b88ac00000000"
}

psbt.validateSignaturesOfInput(0, validator) // true Do I need to do any additional checks before sending a transaction?

mb38 avatar Jun 28 '22 05:06 mb38

you don't need p2sh.

p2sh-p2pkh is not the same as p2pkh.

junderw avatar Jun 28 '22 06:06 junderw

@junderw Thank you very much this fixed the problem and redeemScript should not be used in this case. Just in case, here is a working code for sending a transaction for those who will face the same problem

const sendTransactions = async (
  to: string,
  amount: number,
  from: string,
  privateKey: string,
) => {
  const network = bitcoin.networks.testnet;
  const ECPair: ECPairAPI = ECPairFactory(ecc);
  const alice = ECPair.fromWIF(privateKey, network);

  const { hash, hex } = await getTxUtho(from);
  const psbt = new bitcoin.Psbt({ network });
  psbt.addInput({
    hash: hash, //txId
    index: 0,
    nonWitnessUtxo: Buffer.from(hex, 'hex'),
  });

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

  psbt.signInput(0, alice);
  psbt.validateSignaturesOfInput(0, validator);
  psbt.finalizeAllInputs();
  const txRaw = psbt.extractTransaction(true); // max fee
  const txHash = await pushRawTransaction(txRaw.toHex());
  return txHash;
};

mb38 avatar Jun 28 '22 08:06 mb38

I've seen psbt.validateSignaturesOfInput(0, validator); without further checks in many code examples. I believe it would be a good idea to throw if psbt.validateSignaturesOfInput(0, validator) !== true.

landabaso avatar Jun 28 '22 16:06 landabaso