How to redeem atomic Script with P2SH(HTLC)
peter-jim opened this issue · 3 comments
peter-jim commented
recently I got some problem with atomic(HTLC) . When I broad hex,I got error with mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)
. I think my signature and alice.publickey is corretly. Can you tell why ,thank you
here is my code
const bitcoin = require('bitcoinjs-lib');
const ecc = require('tiny-secp256k1');
const ecpair = require('ecpair');
const crypto = require("crypto");
const TESTNET = bitcoin.networks.testnet;
const ECPair = ecpair.ECPairFactory(ecc);
const alice = ECPair.fromWIF(
'xxxx',
);
const address = bitcoin.payments.p2pkh({
pubkey: alice.publicKey,
network: TESTNET,
});
const txId = "c4c76dd3d64a82d591494b01364cc61d160ea41b4283f67f3949992233546440";
const vout = 0;
const value = 600;
const secret = Buffer.from('123', 'utf-8');
const secretHash = bitcoin.crypto.sha256(secret);//
console.log("secretHash",secretHash.toString('hex'))
console.log("alice address",address.address)
const expiry = 1000;
const lockingScript = bitcoin.script.compile([
bitcoin.opcodes.OP_IF,
bitcoin.opcodes.OP_SHA256,
secretHash,
bitcoin.opcodes.OP_EQUALVERIFY,
bitcoin.opcodes.OP_DUP,
bitcoin.opcodes.OP_HASH160,
bitcoin.crypto.hash160(alice.publicKey),
bitcoin.opcodes.OP_ELSE,
bitcoin.script.number.encode(expiry).toString('hex'),
bitcoin.opcodes.OP_CHECKSEQUENCEVERIFY,
bitcoin.opcodes.OP_DROP,
bitcoin.opcodes.OP_DUP,
bitcoin.opcodes.OP_HASH160,
bitcoin.crypto.hash160(alice.publicKey),
bitcoin.opcodes.OP_ENDIF,
bitcoin.opcodes.OP_EQUALVERIFY,
bitcoin.opcodes.OP_CHECKSIG
]);
const p2shAddress = bitcoin.payments.p2sh({
redeem: { output: lockingScript },
network: TESTNET
});
console.log('p2shAddress :', p2shAddress.address);
const redeemTx = new bitcoin.Transaction(TESTNET);
redeemTx.addInput(Buffer.from(txId, 'hex').reverse(), vout);
redeemTx.addOutput(bitcoin.address.toOutputScript(address.address, TESTNET), value);
const hashType = bitcoin.Transaction.SIGHASH_ALL;
const utxoAddress = bitcoin.payments.p2pkh({ pubkey: alice.publicKey, network: TESTNET });
const p2pkhScriptPubKey = bitcoin.address.toOutputScript(utxoAddress.address, TESTNET);
console.log('toOutputScript', p2pkhScriptPubKey.toString('hex'));
console.log('toOutputScript alice', bitcoin.address.toOutputScript(address.address, TESTNET).toString('hex') );
const signatureHash = redeemTx.hashForSignature(0, p2pkhScriptPubKey, hashType);
const signature = bitcoin.script.signature.encode(alice.sign(signatureHash), hashType);
console.log("signature", bitcoin.script.signature.encode(alice.sign(signatureHash), hashType).toString('hex'))
console.log("alice publickey", alice.publicKey)
const pubKeyHash = crypto.createHash('sha256').update(alice.publicKey.toString('hex')).digest();
console.log('SHA256(alice.publicKey) with crypto lib:', pubKeyHash.toString('hex'));
console.log('SHA256(alice.publicKey) with bitcoinjs lib:', bitcoin.crypto.sha256(Buffer.from('032cf9dd2b7cf826a8d0e176ae0127e1e32b7e33dc55d78754c5f60bfd8f1173b8', 'utf-8')).toString('hex'));
console.log(bitcoin.address.fromBase58Check(address.address).hash.toString("hex"));
console.log(bitcoin.crypto.hash160(Buffer.from('032cf9dd2b7cf826a8d0e176ae0127e1e32b7e33dc55d78754c5f60bfd8f1173b8', 'hex')).toString('hex'));
const redeemScriptSig = bitcoin.payments.p2sh({
redeem: {
input: bitcoin.script.compile([
signature,
alice.publicKey,
secret,
bitcoin.opcodes.OP_TRUE,
// Buffer.from([]),
]),
output: lockingScript
},
network: TESTNET,
}).input;
redeemTx.setInputScript(0, redeemScriptSig);
console.log('Redeem Tx Hex:', redeemTx.toHex());
junderw commented
- Don't convert to a hex string here:
bitcoin.script.number.encode(expiry).toString('hex'),
hashForSignature
should not takep2pkhScriptPubKey
it should takelockingScript
.
peter-jim commented
Amazing ,Thank you a lot ,it work! have a nice day!
junderw commented
Also if you will always use the same key twice, you can move the DUP and hash160 stuff outside the ENDIF