non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)
Arunpandiaraja opened this issue · 2 comments
Hi, i'm trying to broadcast a transaction using external signature which is ECDSA
, transaction is getting signed, but getting this error while broadcasting non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)
, Have checked similar issues but not able to find any solution, Not sure what i'm missing here and raw transaction is huge as well, any help would be much appreciated, My code shown below.
Signature:
cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c4cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc14
Signed Raw transaction hex:
02000000000118032d6e5ca1d7f0dd36426890d6f622d0455389584a3e64f891e862b0eabb81210000000000ffffffffb420c0c66431056ba49e75464410fecf6ab0b17b0a330aea42f9fa51198036fe0000000000ffffffffdf80bbb8a789dce8639492f3527172deac03896316edd89eb975d4d04458bf6b0100000000ffffffff8ba794099d320876c30ef491a10e41ebb7e26af4828c80e393f4e34b705759310000000000ffffffffeaf07eebbd7f19e18cdda014a174257e3144ca28fb97e8b5b488f2bf512dcdce0000000000ffffffffb3d3f3fb32e19f730141d3b7df85fd024baea6defb0305fe7fc498db9fffd2440100000000ffffffffe239b7ce80c1d08420e0936a0197a514bd440b60dfea5b14c6ea8153479878a10100000000ffffffff35f5d629f28973310a63cb1494ecff3d810b6d5f6fc8545deb293dd31b095b820000000000ffffffff94886826bb7dc5ea51ce074960f0e79824ae2d86f1da21be0cc5b57550751e960000000000ffffffffe435299e1220cd011b07a4e977cfb766d3d9c67e78d37f946e3dee0bcc98aea30000000000ffffffff6d93c92e95d9eb6053c81e13423102bc70ff597eb94f9b0b97809ad502aa41980100000000ffffffffb3d3f3fb32e19f730141d3b7df85fd024baea6defb0305fe7fc498db9fffd2440000000000fffffffff203c2769df469b5bd13b1b47b10aa4d532f157a2c743abbc2ab92b8b46c4ce50000000000ffffffff6d93c92e95d9eb6053c81e13423102bc70ff597eb94f9b0b97809ad502aa41980000000000ffffffffef51fa9034fd727ed27b1e36bbe9c4000a30b595c3e397091d83f3dd2090bcbc0000000000ffffffff01d25d0458d650f7e83213e3b22dead18780833139f687d2312d28b155085c0a0000000000ffffffff0058484f81c363f763c52f4b2afbe23118b3ae6136d45410b5dafaec23654e6a0000000000ffffffff605dd6ead625ea7e203ecb8cdbe77f1ad8583c15756d4e27e64e6a5de8d952e50000000000ffffffffec58484d921f058eabc627cfc7a3dded0757531f1abc92adb38dbf7783a4ab660000000000ffffffffb2ffe6af7b8d2ff91e22845dbc668c754ca4fee10a8e3f689139120672a308690000000000ffffffff4b2b01504980090436e5de9b7f4d27cb7b6ceb3e3f912f24cd62249be0bf4cbd0100000000ffffffff7fd78caa8d14416a6c223848b8f430b1f7710cc41abd74b6c5026fa95d12e1050000000000ffffffffae4ece7add902892e8bdb0c17eedd2e8db3f0146c5b91a07e1282e90c89124000000000000ffffffff505d218f34e06e7e1e225511c278190a518f28d201dc02800726a4bc210e61b00100000000ffffffff0100e1f50500000000160014b206974d3306ff4fc78acb60b7c0cbfb9c38da5e02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca02483045022100cafcd323d98b66c85002c197bc2fcc6856b5b6887ec8a63da87b3a92cd33a68c02204cb3e368d7695ef815324e0a0066e05256e846c3f08d414d449c54776270bc140121025a3946bdee01e3070fa9de8e706f6b8bb5b724066eae8c2a4d942d7253c67aca00000000
export const getSignedTxHashBtc = async (signature: string, txObject: any) => {
const { fromAddress, utxos, outputs, feeRate, outputAmount } = txObject
try {
if (signature === '') {
return ''
}
const pubKey = localStorageService.generatedPublicKey.get()
const network = networks.testnet
const psbt = new Psbt({ network })
psbt.setVersion(2)
psbt.setLocktime(0)
const _signature = signature.slice(0, -2)
const rawSignature = _signature
const pubkeyBuffer = Buffer.from(pubKey ?? '', 'hex')
const signatureBuffer = Buffer.from(rawSignature ?? '', 'hex')
console.log(_signature, '_signature')
const txHexes = await Promise.all(
utxos.map(async (utxo: any) => {
const txResponse = await getPrevTxHex({ txID: utxo.txid })
return txResponse
})
)
let inputSum = 0
utxos.forEach((utxo: any, index: number) => {
inputSum += utxo.value
psbt.addInput({
hash: utxo.txid,
index: utxo.vout,
nonWitnessUtxo: Buffer.from(txHexes[index], 'hex'),
sequence: 4294967295,
})
})
outputs.forEach((output: any) => {
psbt.addOutput({
address: output.address,
value: output.amount,
})
})
const changeAmount = inputSum - outputAmount - feeRate
if (changeAmount > 0) {
psbt.addOutput({
address: fromAddress,
value: changeAmount,
})
}
const externalSigner: Signer = {
publicKey: pubkeyBuffer,
sign: () => signatureBuffer,
}
psbt.signAllInputs(externalSigner)
psbt.finalizeAllInputs()
const signedTxHex = psbt.extractTransaction(true).toHex()
console.log('Signed transaction:', signedTxHex)
const txId = await pushTx(signedTxHex)
if (txId) {
return txId
} else {
return null
}
} catch (error) {
console.error('Error in getSignedTxHashBtc:', error)
return null
}
}
Hi @junderw can u help me with this?
The error you're encountering, "non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)," typically arises from issues related to the format or structure of the transaction or the signatures themselves. Below, I will outline potential causes and solutions to address this error.
Potential Causes and Solutions
-
Incorrect Signature Format:
- Ensure the signatures are in DER format and correctly encoded.
-
Incorrect Script:
- Verify that the script and the script types match the inputs and outputs. Ensure that the signatures and public keys are correctly included in the scriptSig.
-
Mismatched or Incomplete Inputs:
- Ensure all inputs are correctly referenced and match the UTXOs.
-
Sequence and Locktime:
- The sequence numbers and locktime should be correctly set. You have set the sequence to
4294967295
, which is generally acceptable, but ensure this is correct for your transaction type.
- The sequence numbers and locktime should be correctly set. You have set the sequence to
-
Correct Handling of Non-Witness UTXOs:
- Verify that the
nonWitnessUtxo
buffers are correctly formatted and correspond to the previous transactions.
- Verify that the
-
Signature Placeholder:
- Ensure the signatures are correctly placed, and that no placeholder (like
0
) is incorrectly interpreted as an invalid signature.
- Ensure the signatures are correctly placed, and that no placeholder (like
Revised Code
Here is a more detailed and slightly revised version of your code to address these potential issues:
import { Psbt, networks } from 'bitcoinjs-lib'
import { getPrevTxHex, pushTx } from './apiService'
import { localStorageService } from './localStorageService'
export const getSignedTxHashBtc = async (signature, txObject) => {
const { fromAddress, utxos, outputs, feeRate, outputAmount } = txObject
try {
if (!signature) {
throw new Error('Signature is empty')
}
const pubKey = localStorageService.generatedPublicKey.get()
const network = networks.testnet
const psbt = new Psbt({ network })
psbt.setVersion(2)
psbt.setLocktime(0)
const rawSignature = signature.slice(0, -2)
const pubkeyBuffer = Buffer.from(pubKey, 'hex')
const signatureBuffer = Buffer.from(rawSignature, 'hex')
// Fetch previous transaction hexes
const txHexes = await Promise.all(
utxos.map(async (utxo) => {
const txResponse = await getPrevTxHex({ txID: utxo.txid })
return txResponse
})
)
// Add inputs
let inputSum = 0
utxos.forEach((utxo, index) => {
inputSum += utxo.value
psbt.addInput({
hash: utxo.txid,
index: utxo.vout,
nonWitnessUtxo: Buffer.from(txHexes[index], 'hex'),
sequence: 4294967295,
})
})
// Add outputs
outputs.forEach((output) => {
psbt.addOutput({
address: output.address,
value: output.amount,
})
})
// Add change output
const changeAmount = inputSum - outputAmount - feeRate
if (changeAmount > 0) {
psbt.addOutput({
address: fromAddress,
value: changeAmount,
})
}
// Define the external signer
const externalSigner = {
publicKey: pubkeyBuffer,
sign: () => signatureBuffer,
}
// Sign all inputs
psbt.signAllInputs(externalSigner)
// Finalize all inputs
psbt.finalizeAllInputs()
// Extract the signed transaction
const signedTxHex = psbt.extractTransaction(true).toHex()
console.log('Signed transaction:', signedTxHex)
// Broadcast the transaction
const txId = await pushTx(signedTxHex)
if (txId) {
return txId
} else {
throw new Error('Transaction broadcast failed')
}
} catch (error) {
console.error('Error in getSignedTxHashBtc:', error)
return null
}
}
Notes:
-
Error Handling:
- Improved error handling to provide more informative error messages.
-
Ensure Signature Buffer:
- Check the conversion of
signatureBuffer
to ensure it matches the expected DER format.
- Check the conversion of
-
Transaction Fees:
- Ensure the
feeRate
andoutputAmount
calculations are correct to avoid any discrepancies.
- Ensure the
-
Public Key and Signature Extraction:
- Verify the
pubKey
andsignature
extracted from local storage or other sources are correctly formatted and valid.
- Verify the
If the error persists, you may need to delve deeper into the specifics of the transaction and the signature to ensure everything aligns correctly with Bitcoin's transaction rules and the script validation logic.