• About
  • FAQ
  • Earn Bitcoin while Surfing the net
  • Buy & Sell Crypto on Paxful
Newsletter
Approx Foundation
  • Home
    • Home – Layout 1
  • Bitcoin
  • Ethereum
  • Regulation
  • Market
  • Blockchain
  • Business
  • Guide
  • Contact Us
No Result
View All Result
  • Home
    • Home – Layout 1
  • Bitcoin
  • Ethereum
  • Regulation
  • Market
  • Blockchain
  • Business
  • Guide
  • Contact Us
No Result
View All Result
Approx Foundation
No Result
View All Result
Home Bitcoin

Broadcast Error RPC error: {“code”:-26,”message”:”non-mandatory-script-verify-flag (Invalid Schnorr signature)”}

Moussa by Moussa
November 28, 2024
in Bitcoin
0
peer discovery – how to obtain the IP addresses of nodes for mining pools?
189
SHARES
1.5k
VIEWS
Share on FacebookShare on Twitter


While broadcasting raw transaction has to chain, got the below error
RPC error: {“code”:-26,”message”:”non-mandatory-script-verify-flag (Invalid Schnorr signature)”} but signature verification method says its a valid signature for the given message.

I’m trying to do a simple taproot send transaction (key path spending). Signature is given by external signer

My data points are as below

{
  message: '60ccb78b5936d80f63c32eeafe9b746909d7e716f0f96988f437972e633ec7e0',
  signature: 'ed3061523f39137cdab4c9ca0bf9b62433b9642bb8165d996dcc120662866e8060e6f2314d7b03bab31f0a95b4574ddbed2892a176d2723810bd28fda66d1496',
  publicKey: 'ddb666300b8d7ef23e61e2ff3af3c70b59f882d6de1deb601590bb4d15b5d5d3'
}

Transaction hash

020000000001012bd272fa216d2370e265f591907266a8e76a26bc0be4318c9b1b340eaa6134860000000000ffffffff021027000000000000225120ddb666300b8d7ef23e61e2ff3af3c70b59f882d6de1deb601590bb4d15b5d5d3a8c8fa0200000000225120ddb666300b8d7ef23e61e2ff3af3c70b59f882d6de1deb601590bb4d15b5d5d30141ed3061523f39137cdab4c9ca0bf9b62433b9642bb8165d996dcc120662866e8060e6f2314d7b03bab31f0a95b4574ddbed2892a176d2723810bd28fda66d14960100000000

enter image description here

This is my entire code

import sha256 from "sha256";
import { Psbt, networks, payments, Transaction } from "bitcoinjs-lib";
import dotenv from 'dotenv';
import { verifySchnorrSignature } from "./mpc/address.js";
import { signBTCTransaction } from "./systemCallerUtils.js";
dotenv.config();

const UNCONFIRMED_HEIGHT = 4194303;

async function btcSendTransaction() {
  try {
    const address = process.env.BTC_ADDRESS;
    return await createSendTransaction(address);
  } catch (err) {
    console.error("Error in btcSendTransaction:", err);
    throw err;
  }
}

async function createSendTransaction(address) {
  const txObj = await handleTxObj(address);
  const { preSignTxHashes, psbt } = await generatePreSignTxHash(txObj);
  console.log("preSignTxHashes", preSignTxHashes);
  
  // Generate signatures for each input
  const generatedSigns = [];
  for (let i = 0; i < preSignTxHashes.length; i++) {
    const generatedSign = await signBTCTransaction(preSignTxHashes[i], "HASH");
    if (generatedSign) {
      generatedSigns.push(generatedSign);
    }
  }

  // Remove the '0x' prefix for verification
  const hashToVerify = preSignTxHashes[0].replace('0x', '');
  console.log('Hash for verification:', hashToVerify);
  
  try {
    const isValid = await verifySchnorrSignature(
      hashToVerify,
      generatedSigns[0].sign
    );
    console.log("Signature verification:", isValid);

    if (!isValid) {
      console.error('Verification failed:', {
        hash: hashToVerify,
        signature: generatedSigns[0].sign,
        pubkey: process.env.MPC_PUB_KEY
      });
      throw new Error('Invalid signature generated');
    }
  } catch (error) {
    console.error('Verification error:', error);
    throw error;
  }

  try {
    if (generatedSigns.length) {
      const response = await broadCastTx(generatedSigns, psbt);
      return response;
    }
  } catch (e) {
    console.error('Broadcast error:', e);
    throw e;
  }
}

const handleTxObj = async (address) => {
  try {
    let utxos = await getUtxos(address);
    utxos = utxos.filter((v) => v.height !== UNCONFIRMED_HEIGHT);
    
    const outputAmount = 10000;
    const feeRate = 200;
    const outputs = [{
      address: address,
      amount: outputAmount,
    }];

    const { selectedUtxos, totalValue } = selectUtxos(utxos, outputAmount + feeRate);

    console.log("selectedUtxos", selectedUtxos);

    return {
      fromAddress: address,
      utxos: selectedUtxos,
      outputs,
      feeRate,
      toAddress: address,
    };
  } catch (error) {
    console.error("handleTxObj error:", error);
    throw error;
  }
}

export function selectUtxos(utxos, targetAmount) {
  utxos.sort((a, b) => b.value - a.value);
  const selectedUtxos = [];
  let totalValue = 0;

  for (const utxo of utxos) {
    selectedUtxos.push(utxo);
    totalValue += utxo.value;
    if (totalValue >= targetAmount) break;
  }

  if (totalValue < targetAmount) {
    throw new Error('Insufficient UTXOs to cover the target amount');
  }

  return { selectedUtxos, totalValue };
}

export const generatePreSignTxHash = async (txObject) => {
  const network = networks.testnet;
  const psbt = new Psbt({ network });
  
  try {
    const { utxos, fromAddress, outputs, feeRate } = txObject;
    let inputSum = 0;
    const pubKey = process.env.MPC_PUB_KEY;
    const xOnlyPubKey = Buffer.from(pubKey, 'hex');

    // Add inputs using the actual UTXO script
    for (const utxo of utxos) {
      inputSum += utxo.value;
      
      // Get the actual UTXO details
      const txDetails = await fetch(`https://esplora.signet.surge.dev/tx/${utxo.txid}/hex`).then(r => r.text());
      const tx = Transaction.fromHex(txDetails);
      const outputScript = tx.outs[utxo.vout].script;
      
      console.log('UTXO details:', {
        script: outputScript.toString('hex'),
        value: utxo.value
      });

      psbt.addInput({
        hash: utxo.txid,
        index: utxo.vout,
        witnessUtxo: {
          script: outputScript,
          value: utxo.value,
        },
        tapInternalKey: xOnlyPubKey,
      });
    }

    // Add outputs
    for (const output of outputs) {
      psbt.addOutput({
        address: output.address,
        value: output.amount,
      });
    }

    // Add change output
    const totalOutputAmount = outputs.reduce((sum, output) => sum + output.amount, 0);
    const changeAmount = inputSum - totalOutputAmount - feeRate;

    if (changeAmount > 546) {
      psbt.addOutput({
        address: fromAddress,
        value: changeAmount,
      });
    }

    // Generate signing hashes
    const unsignedTx = Transaction.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
    const preSignTxHashes = psbt.data.inputs.map((input, index) => {
      const hash = unsignedTx.hashForWitnessV1(
        index,
        [input.witnessUtxo.script],
        [input.witnessUtxo.value],
        Transaction.SIGHASH_ALL
      );
      
      console.log('Input details:', {
        script: input.witnessUtxo.script.toString('hex'),
        value: input.witnessUtxo.value,
        hash: hash.toString('hex')
      });
      
      return `0x${hash.toString('hex')}`;
    });

    return { preSignTxHashes, psbt };
  } catch (error) {
    console.error('Error in generatePreSignTxHash:', error);
    throw error;
  }
};

export const broadCastTx = async (signatures, psbt) => {
  if (!signatures.length) {
    throw new Error('No signatures provided');
  }

  try {
    signatures.forEach((sig, index) => {
      const sigBuffer = Buffer.from(sig.sign.replace('0x', ''), 'hex');
      console.log(`Raw signature for input ${index}:`, sigBuffer.toString('hex'));
      console.log('Signature length:', sigBuffer.length);

      // For Taproot with SIGHASH_ALL
      const sigWithHashtype = Buffer.concat([
        sigBuffer,
        Buffer.from([Transaction.SIGHASH_ALL])
      ]);

      console.log(`Signature with hashtype for input ${index}:`, sigWithHashtype.toString('hex'));

      psbt.updateInput(index, {
        tapKeySig: sigWithHashtype
      });
    });

    psbt.finalizeAllInputs();
    const tx = psbt.extractTransaction(true);
    const rawTx = tx.toHex();
    
    console.log('Final transaction:', rawTx);
    console.log('Transaction details:', {
      version: tx.version,
      inputs: tx.ins.map(input => ({
        txid: input.hash.reverse().toString('hex'),
        vout: input.index,
        witness: input.witness.map(w => w.toString('hex'))
      })),
      outputs: tx.outs.map(output => ({
        value: output.value,
        script: output.script.toString('hex')
      }))
    });
    
    return await pushTx(rawTx);
  } catch (error) {
    console.error('Failed to broadcast transaction:', error);
    throw error;
  }
};

export const pushTx = async (rawtx) => {
  try {
    const endpoint="https://esplora.signet.surge.dev/tx";
    const resp = await fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "text/plain" },
      body: rawtx,
    });
    
    if (!resp.ok) {
      const errorText = await resp.text();
      throw new Error(`HTTP error! status: ${resp.status}, message: ${errorText}`);
    }
    
    const txid = await resp.text();
    return { txid };
  } catch (error) {
    console.error('Push transaction error:', error);
    throw error;
  }
};

export const getUtxos = async (address) => {
  try {
    const endpoint = `https://esplora.signet.surge.dev/address/${address}/utxo`;
    const resp = await fetch(endpoint, {
      method: "GET",
      headers: { "Content-Type": "application/json" },
    });
    if (!resp.ok) {
      throw new Error(`HTTP error! status: ${resp.status}`);
    }
    return await resp.json();
  } catch (error) {
    console.error('Get UTXOs error:', error);
    throw error;
  }
};

export { btcSendTransaction };

Can anyone help me with this?



Source link

Related articles

Oil Sinks to $88, Then Spikes as Iran Claims Control of Hormuz

Oil Sinks to $88, Then Spikes as Iran Claims Control of Hormuz

May 6, 2026
How do Bitcoin mining pools typically handle payout frequency versus thresholds?

Keeping wallet addresses outside bitcoin core

May 6, 2026
Share76Tweet47

Related Posts

Oil Sinks to $88, Then Spikes as Iran Claims Control of Hormuz

Oil Sinks to $88, Then Spikes as Iran Claims Control of Hormuz

by Moussa
May 6, 2026
0

Key TakeawaysTrump’s hopes to end Epic Fury dropped WTI to $88.66, but future deals face hurdles from Iran’s new demands.Iran’s...

How do Bitcoin mining pools typically handle payout frequency versus thresholds?

Keeping wallet addresses outside bitcoin core

by Moussa
May 6, 2026
0

Yes you can use this architecture, provided that the bitcoin node you don't control doesn't know your private keys for...

Bitcoin ETF News: Hong Kong’s Spot ETFs Changing the ‘Weekend Gap’

Bitcoin ETF News: Hong Kong’s Spot ETFs Changing the ‘Weekend Gap’

by Moussa
May 6, 2026
0

In Bitcoin ETF news today, Hong Kong’s spot BTC ETFs are measurably compressing Bitcoin’s notorious ‘weekend gap,’ with Asian-session trading...

Ripple CEO Garlinghouse Says XRP Army Is Stronger Than Ever

Ripple CEO Garlinghouse Says XRP Army Is Stronger Than Ever

by Moussa
May 6, 2026
0

Trusted Editorial content, reviewed by leading industry experts and seasoned editors. Ad Disclosure Ripple CEO Brad Garlinghouse used a Consensus...

Zcash Hits New YTD High As Multicoin Discloses ZEC Bet

Zcash Hits New YTD High As Multicoin Discloses ZEC Bet

by Moussa
May 6, 2026
0

Zcash extended one of the strongest recent moves in the large-cap segment, setting a new year-to-date high of $590 after...

Load More

youssufi.com

sephina.com

[vc_row full_width="stretch_row" parallax="content-moving" vc_row_background="" background_repeat="no-repeat" background_position="center center" footer_scheme="dark" css=".vc_custom_1517813231908{padding-top: 60px !important;padding-bottom: 30px !important;background-color: #191818 !important;background-position: center;background-repeat: no-repeat !important;background-size: cover !important;}" footer_widget_title_color="#fcbf46" footer_button_bg="#fcb11e"][vc_column width="1/4"]

We bring you the latest in Crypto News

[/vc_column][vc_column width="1/4"][vc_wp_categories]
[/vc_column][vc_column width="1/4"][vc_wp_tagcloud taxonomy="post_tag"][/vc_column][vc_column width="1/4"]

Newsletter

[vc_raw_html]JTNDcCUzRSUzQ2RpdiUyMGNsYXNzJTNEJTIydG5wJTIwdG5wLXN1YnNjcmlwdGlvbiUyMiUzRSUwQSUzQ2Zvcm0lMjBtZXRob2QlM0QlMjJwb3N0JTIyJTIwYWN0aW9uJTNEJTIyaHR0cHMlM0ElMkYlMkZhcHByb3gub3JnJTJGJTNGbmElM0RzJTIyJTNFJTBBJTBBJTNDaW5wdXQlMjB0eXBlJTNEJTIyaGlkZGVuJTIyJTIwbmFtZSUzRCUyMm5sYW5nJTIyJTIwdmFsdWUlM0QlMjIlMjIlM0UlM0NkaXYlMjBjbGFzcyUzRCUyMnRucC1maWVsZCUyMHRucC1maWVsZC1maXJzdG5hbWUlMjIlM0UlM0NsYWJlbCUyMGZvciUzRCUyMnRucC0xJTIyJTNFRmlyc3QlMjBuYW1lJTIwb3IlMjBmdWxsJTIwbmFtZSUzQyUyRmxhYmVsJTNFJTBBJTNDaW5wdXQlMjBjbGFzcyUzRCUyMnRucC1uYW1lJTIyJTIwdHlwZSUzRCUyMnRleHQlMjIlMjBuYW1lJTNEJTIybm4lMjIlMjBpZCUzRCUyMnRucC0xJTIyJTIwdmFsdWUlM0QlMjIlMjIlM0UlM0MlMkZkaXYlM0UlMEElM0NkaXYlMjBjbGFzcyUzRCUyMnRucC1maWVsZCUyMHRucC1maWVsZC1lbWFpbCUyMiUzRSUzQ2xhYmVsJTIwZm9yJTNEJTIydG5wLTIlMjIlM0VFbWFpbCUzQyUyRmxhYmVsJTNFJTBBJTNDaW5wdXQlMjBjbGFzcyUzRCUyMnRucC1lbWFpbCUyMiUyMHR5cGUlM0QlMjJlbWFpbCUyMiUyMG5hbWUlM0QlMjJuZSUyMiUyMGlkJTNEJTIydG5wLTIlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHJlcXVpcmVkJTNFJTNDJTJGZGl2JTNFJTBBJTNDZGl2JTIwY2xhc3MlM0QlMjJ0bnAtZmllbGQlMjB0bnAtcHJpdmFjeS1maWVsZCUyMiUzRSUzQ2xhYmVsJTNFJTNDaW5wdXQlMjB0eXBlJTNEJTIyY2hlY2tib3glMjIlMjBuYW1lJTNEJTIybnklMjIlMjByZXF1aXJlZCUyMGNsYXNzJTNEJTIydG5wLXByaXZhY3klMjIlM0UlQzIlQTBCeSUyMGNvbnRpbnVpbmclMkMlMjB5b3UlMjBhY2NlcHQlMjB0aGUlMjBwcml2YWN5JTIwcG9saWN5JTNDJTJGbGFiZWwlM0UlM0MlMkZkaXYlM0UlM0NkaXYlMjBjbGFzcyUzRCUyMnRucC1maWVsZCUyMHRucC1maWVsZC1idXR0b24lMjIlM0UlM0NpbnB1dCUyMGNsYXNzJTNEJTIydG5wLXN1Ym1pdCUyMiUyMHR5cGUlM0QlMjJzdWJtaXQlMjIlMjB2YWx1ZSUzRCUyMlN1YnNjcmliZSUyMiUyMCUzRSUwQSUzQyUyRmRpdiUzRSUwQSUzQyUyRmZvcm0lM0UlMEElM0MlMkZkaXYlM0UlM0NiciUyRiUzRSUzQyUyRnAlM0U=[/vc_raw_html][/vc_column][/vc_row]
No Result
View All Result
  • Contact Us
  • Homepages
  • Business
  • Guide

© 2024 APPROX FOUNDATION - The Crypto Currency News