Thursday, December 5, 2024
HomeBitcoinBroadcast Error RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Invalid Schnorr signature)"}

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


Whereas broadcasting uncooked transaction has to chain, acquired the under error
RPC error: {“code”:-26,”message”:”non-mandatory-script-verify-flag (Invalid Schnorr signature)”} however signature verification methodology says its a legitimate signature for the given message.

I am making an attempt to do a easy taproot ship transaction (key path spending). Signature is given by exterior signer

My information factors are as under

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

Transaction hash

020000000001012bd272fa216d2370e265f591907266a8e76a26bc0be4318c9b1b340eaa6134860000000000ffffffff021027000000000000225120ddb666300b8d7ef23e61e2ff3af3c70b59f882d6de1deb601590bb4d15b5d5d3a8c8fa0200000000225120ddb666300b8d7ef23e61e2ff3af3c70b59f882d6de1deb601590bb4d15b5d5d30141ed3061523f39137cdab4c9ca0bf9b62433b9642bb8165d996dcc120662866e8060e6f2314d7b03bab31f0a95b4574ddbed2892a176d2723810bd28fda66d14960100000000

enter image description here

That is my whole code

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

const UNCONFIRMED_HEIGHT = 4194303;

async operate btcSendTransaction() {
  strive {
    const handle = course of.env.BTC_ADDRESS;
    return await createSendTransaction(handle);
  } catch (err) {
    console.error("Error in btcSendTransaction:", err);
    throw err;
  }
}

async operate createSendTransaction(handle) {
  const txObj = await handleTxObj(handle);
  const { preSignTxHashes, psbt } = await generatePreSignTxHash(txObj);
  console.log("preSignTxHashes", preSignTxHashes);
  
  // Generate signatures for every enter
  const generatedSigns = [];
  for (let i = 0; i < preSignTxHashes.size; i++) {
    const generatedSign = await signBTCTransaction(preSignTxHashes[i], "HASH");
    if (generatedSign) {
      generatedSigns.push(generatedSign);
    }
  }

  // Take away the '0x' prefix for verification
  const hashToVerify = preSignTxHashes[0].exchange('0x', '');
  console.log('Hash for verification:', hashToVerify);
  
  strive {
    const isValid = await verifySchnorrSignature(
      hashToVerify,
      generatedSigns[0].signal
    );
    console.log("Signature verification:", isValid);

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

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

const handleTxObj = async (handle) => {
  strive {
    let utxos = await getUtxos(handle);
    utxos = utxos.filter((v) => v.peak !== 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: handle,
      utxos: selectedUtxos,
      outputs,
      feeRate,
      toAddress: handle,
    };
  } catch (error) {
    console.error("handleTxObj error:", error);
    throw error;
  }
}

export operate selectUtxos(utxos, targetAmount) {
  utxos.type((a, b) => b.worth - a.worth);
  const selectedUtxos = [];
  let totalValue = 0;

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

  if (totalValue < targetAmount) {
    throw new Error('Inadequate UTXOs to cowl the goal quantity');
  }

  return { selectedUtxos, totalValue };
}

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

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

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

    // Add outputs
    for (const output of outputs) {
      psbt.addOutput({
        handle: output.handle,
        worth: output.quantity,
      });
    }

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

    if (changeAmount > 546) {
      psbt.addOutput({
        handle: fromAddress,
        worth: changeAmount,
      });
    }

    // Generate signing hashes
    const unsignedTx = Transaction.fromBuffer(psbt.information.globalMap.unsignedTx.toBuffer());
    const preSignTxHashes = psbt.information.inputs.map((enter, index) => {
      const hash = unsignedTx.hashForWitnessV1(
        index,
        [input.witnessUtxo.script],
        [input.witnessUtxo.value],
        Transaction.SIGHASH_ALL
      );
      
      console.log('Enter particulars:', {
        script: enter.witnessUtxo.script.toString('hex'),
        worth: enter.witnessUtxo.worth,
        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.size) {
    throw new Error('No signatures supplied');
  }

  strive {
    signatures.forEach((sig, index) => {
      const sigBuffer = Buffer.from(sig.signal.exchange('0x', ''), 'hex');
      console.log(`Uncooked signature for enter ${index}:`, sigBuffer.toString('hex'));
      console.log('Signature size:', sigBuffer.size);

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

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

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

    psbt.finalizeAllInputs();
    const tx = psbt.extractTransaction(true);
    const rawTx = tx.toHex();
    
    console.log('Last transaction:', rawTx);
    console.log('Transaction particulars:', {
      model: tx.model,
      inputs: tx.ins.map(enter => ({
        txid: enter.hash.reverse().toString('hex'),
        vout: enter.index,
        witness: enter.witness.map(w => w.toString('hex'))
      })),
      outputs: tx.outs.map(output => ({
        worth: output.worth,
        script: output.script.toString('hex')
      }))
    });
    
    return await pushTx(rawTx);
  } catch (error) {
    console.error('Did not broadcast transaction:', error);
    throw error;
  }
};

export const pushTx = async (rawtx) => {
  strive {
    const endpoint="https://esplora.signet.surge.dev/tx";
    const resp = await fetch(endpoint, {
      methodology: "POST",
      headers: { "Content material-Kind": "textual content/plain" },
      physique: rawtx,
    });
    
    if (!resp.okay) {
      const errorText = await resp.textual content();
      throw new Error(`HTTP error! standing: ${resp.standing}, message: ${errorText}`);
    }
    
    const txid = await resp.textual content();
    return { txid };
  } catch (error) {
    console.error('Push transaction error:', error);
    throw error;
  }
};

export const getUtxos = async (handle) => {
  strive {
    const endpoint = `https://esplora.signet.surge.dev/handle/${handle}/utxo`;
    const resp = await fetch(endpoint, {
      methodology: "GET",
      headers: { "Content material-Kind": "software/json" },
    });
    if (!resp.okay) {
      throw new Error(`HTTP error! standing: ${resp.standing}`);
    }
    return await resp.json();
  } catch (error) {
    console.error('Get UTXOs error:', error);
    throw error;
  }
};

export { btcSendTransaction };

Can anybody assist me with this?

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments