Raw-Transaction

使用 bitcoinjs-lib 簽署本機 P2WPKH(簽署 sighash)(非強制腳本驗證標誌)

  • January 24, 2022

我對 p2wsh 多重簽名配置進行了很多實驗bitcoinjs-lib。但是當我嘗試簽署一個標準的本地 segwit p2wpkh 到 p2wpkh 交易時,一切正常,除了bitcoin-cli sendrawtransaction. 它說

non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)

js程式碼(./btc這裡,其餘的可以npm install編輯):

const { btc, send, listunspent, getnewaddress, bech32toScriptPubKey } = require('./btc')();
const bitcoin = require('bitcoinjs-lib');
const network = bitcoin.networks.testnet;
const hashtype = bitcoin.Transaction.SIGHASH_ALL;
const ECPair = require('ecpair').ECPairFactory(require('tiny-secp256k1'));
const readline = require('readline');

const rl = readline.createInterface({
   input: process.stdin,
   output: process.stdout
});

rl.on('close', () => process.exit(0));

const input = q => new Promise(r => rl.question(q, r));

main();

async function main() {
   const u = (await listunspent(0, 0, true)).filter(x => x.solvable && x.spendable && x.desc.startsWith('wpkh'));

   console.log(u);

   const v = await input('Which input to use? ');

   const utxo = u[parseInt(v)];

   if (!utxo) {
       console.log('error');
       process.exit(1);
   }

   var out = await input('Output address (leave empty to generate a new one) ');

   if (out.length == 0) {
       out = await getnewaddress();
   }

   if (out.length != 42) {
       console.log('p2wpkh addresses are 42 chars long');
       process.exit(1);
   }

   const ecpair = ECPair.fromWIF(await btc('dumpprivkey', utxo.address), network);

   const tx = new bitcoin.Transaction(network);

   tx.addInput(Buffer.from(utxo.txid, 'hex').reverse(), utxo.vout);

   const fee = 110;

   tx.addOutput(bech32toScriptPubKey(out), utxo.amount - fee);

   const sighash = tx.hashForWitnessV0(
       0, Buffer.from(utxo.scriptPubKey, 'hex'), utxo.amount, hashtype
   );

   tx.setWitness(0, [
       bitcoin.script.signature.encode(ecpair.sign(sighash), hashtype),
       ecpair.publicKey
   ]);

   console.log(tx.toHex());
   console.log(await send(tx.toHex()));
}

TX 十六進制

01000000000101c690a8157bb45506b15173a3175bd3504182cf8c91f916235522522a3d1a28280100000000ffffffff01d2410f00000000001600149b959b78f09b7f7976391fd20aad3835b738e0c3024730440220120a950d96210c48a6831e7ee7f746e6119183d8512b10a6b14c60509556bba3022042359f1699e9cfb90637647ecb085e262736dc5ad9c076666cb44c29c20baafc0121027b612527ff9e157b80dd2ddac0e11555afcd517a7a425c27e5c7afbad889528e00000000

我認為我在必須包含在 sighash 中的內容上犯了一個錯誤。scriptPubKeyp2wpkh 的 sighash 中使用了什麼?

我已經通過對 sighash 使用 P2PKH 輸出腳本解決了這個問題

const sighash = tx.hashForWitnessV0(
   0, Buffer.from(utxo.scriptPubKey, 'hex'), utxo.amount, hashtype
);

已更改為

const pkh = bitcoin.script.decompile(Buffer.from(utxo.scriptPubKey, 'hex'))[1];

const sighash = tx.hashForWitnessV0(
   0, bitcoin.script.compile([
       bitcoin.opcodes.OP_DUP,
       bitcoin.opcodes.OP_HASH160,
       pkh,
       bitcoin.opcodes.OP_EQUALVERIFY,
       bitcoin.opcodes.OP_CHECKSIG
   ]), utxo.amount, hashtype
);

我的腳本現在可以工作並將其添加到我的比特幣東西回購

<https://github.com/antonilol/btc_stuff>

<https://github.com/antonilol/btc_stuff/blob/master/p2wpkh.js>

引用自:https://bitcoin.stackexchange.com/questions/111686