0
Help us understand the problem. What are the problem?

posted at

updated at

bitcoinjs-libでSegwitシングルシグのトランザクションを作る

はじめに

上記記事で作成したP2WPKHアドレスにSignetで入金し、トランザクションを作成してブロードキャストするところまでをやってみます。

準備

フルノード

Dockerのある環境で、Signetフルノードを立ち上げます。

$ ID=$(docker ps -q)
$ alias bcli="docker exec $ID bitcoin-cli"
$ bcli getblockchaininfo
{
  "chain": "signet",
  "blocks": 52781,
  "headers": 52781,
  "bestblockhash": "0000011901fe5f02923fd64aa9d1ae97d4defa9e0ee130cd360986f7e896cd57",
  "difficulty": 0.002919030932507782,
  "mediantime": 1629981736,
  "verificationprogress": 0.9999984371265536,
  "initialblockdownload": false,
  "chainwork": "00000000000000000000000000000000000000000000000000000094db3d1966",
  "size_on_disk": 154655081,
  "pruned": false,
  "softforks": {
    "bip34": {
      "type": "buried",
      "active": true,
      "height": 1
    },
    "bip66": {
      "type": "buried",
      "active": true,
      "height": 1
    },
    "bip65": {
      "type": "buried",
      "active": true,
      "height": 1
    },
    "csv": {
      "type": "buried",
      "active": true,
      "height": 1
    },
    "segwit": {
      "type": "buried",
      "active": true,
      "height": 1
    },
    "taproot": {
      "type": "bip9",
      "bip9": {
        "status": "active",
        "start_time": -1,
        "timeout": 9223372036854775807,
        "since": 0,
        "min_activation_height": 0
      },
      "height": 0,
      "active": true
    }
  },
  "warnings": ""
}

"blocks"と"headers"が同じブロック高になれば同期OKです。
同期している間に先に進みます。

アドレス準備

アドレス作成編で作成したP2WPKHを使います。

P2WPKH:
tb1qzwwvqxr2m8l0kt8trnnhaa48awtq45zauflz5y

Signet BTC調達

Signet Faucetを使ってP2WPKHに入金します。

ときどき、不調な時がありますので、そういう場合は時間をおいてお試しください。

Exploreで確認します。

鍵の準備

ここで、シングルシグのアドレスを作成しましたが、そのときの拡張秘密鍵、拡張公開鍵を使用します。

$ node getKeys.js 
mnemonic:
task foster wet panther noble tissue hockey ancient faint mandate suit thank mad wrist where category lecture margin wrap evoke desert topic empty include
xpriv:
tprv8gPHaXkdRLgnE1NgPqZPkH1ffYBiQkuAVowFDi5rGDuxj19vuBsD53cmXHxq8u4gmDv9t8a2YaY56roA8KNZRNTNSe6Yv6jVdDhUvxYbcRj
xpub:
tpubDD5KiwnsZiNT7UQUHVDz9gfnEZhea66557Y2WE89gViMZVQhXagoFYEdhSnsRKtJJrv9yAmEkdCUA68GPmPk9W8tdfq5iWU7JpcXpEUfhyL

拡張秘密鍵と拡張公開鍵は別々のファイルで作成します。

ディレクトリはこれから作成するプログラムと同じです。

xpriv.json
{
    "xpriv": "tprv8gPHaXkdRLgnE1NgPqZPkH1ffYBiQkuAVowFDi5rGDuxj19vuBsD53cmXHxq8u4gmDv9t8a2YaY56roA8KNZRNTNSe6Yv6jVdDhUvxYbcRj"
}
xpub.json
{
    "xpub": "tpubDD5KiwnsZiNT7UQUHVDz9gfnEZhea66557Y2WE89gViMZVQhXagoFYEdhSnsRKtJJrv9yAmEkdCUA68GPmPk9W8tdfq5iWU7JpcXpEUfhyL"
}

トランザクション作成

前回のアドレス作成で得たxprivとxprivをセット、
入金時のTXIDとIndexをセットします。

psbt.addOutputの宛先、送金額を適当にセットします。

singleSigTx.js
const bitcoin = require('bitcoinjs-lib');
const bip32 = require('bip32');
const bip39 = require('bip39');
const wif = require('wif');
const { xpub } = require('./xpub.json');
const MAINNET = bitcoin.networks.bitcoin;
const TESTNET = bitcoin.networks.testnet;
// let bitcoinNetwork = MAINNET;
let bitcoinNetwork = TESTNET;

const { xpriv } = require('./xpriv.json');

const privkeyNode = bitcoin.bip32.fromBase58(xpriv, bitcoinNetwork);
const privateKey_wif = privkeyNode.derive(1).derive(0).derive(0).derive(0).toWIF();
console.log("privateKey_wif:");
console.log(privateKey_wif);

function getPubkeyFromXpub(xpub) {
    const pubkeyNode = bitcoin.bip32.fromBase58(xpub, bitcoinNetwork);
    const pubkey = pubkeyNode.derive(1).derive(0).derive(0).derive(0).publicKey;
    return pubkey;
}

const pubkey = getPubkeyFromXpub(xpub);

const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: pubkey, network: bitcoinNetwork, });

console.log('Witness script:')
console.log(p2wpkh.output.toString('hex'))

console.log('P2WPKH address')
console.log(p2wpkh.address) 

const psbt = new bitcoin.Psbt({ network: bitcoinNetwork });

psbt.addInput({
    hash: '364c422186a0e07e7de4ab71cd29e065920b6c46efce16fb49636cd95dee7e38',
    index: 0,
    sequence: 0xffffffff,

    witnessUtxo: {
    script: Buffer.from(p2wpkh.output.toString('hex'),'hex',),
    value: 100000,
    },
});
psbt.addOutput({
    address: "tb1q2adzgyzuy3msvjjfn3pkghf5fnwtwmxcglw3cuk5gvvv3ahmt63qqqa3n6",
    value: 70000,
});
psbt.addOutput({
    address: "tb1qzwwvqxr2m8l0kt8trnnhaa48awtq45zauflz5y",
    value: 29890,
});

const obj = wif.decode(privateKey_wif);

const privKey = bitcoin.ECPair.fromPrivateKey(obj.privateKey);

psbt.signInput(0, privKey);

psbt.validateSignaturesOfInput(0);
psbt.finalizeAllInputs();
const txHex = psbt.extractTransaction().toHex();

console.log(txHex);
$ node singleSigTx.js 
privateKey_wif:
cVa9bD3JAoc6hJHfU68PkLWrYmn6AN81PJs7kG6BHR1TeA4nKJtF
02000000000101387eee5dd96c6349fb16ceef466c0b9265e029cd71abe47d7ee0a08621424c360000000000ffffffff027011010000000000220020575a24105c2477064a499c43645d344cdcb76cd847dd1c72d44318c8f6fb5ea2c274000000000000160014139cc0186ad9fefb2ceb1ce77ef6a7eb960ad05d024830450221008b022898583d8dd4eb8136982b3ed7bdd0f632a6613def653d171c1536ef954702206e7d958b881a6e66c42d9ba8c3fd88a9724fc10d9c12a5e15340c564e8a0d3ae0121034c30836747cd7d7a50db1de9ceb1c953a4c308bbf2669c620d62a4370f63b47200000000

なお、WIF形式の秘密鍵(privateKey_wif)はBitcoin Coreのウォレットに取り込めます。

$ bcli importprivkey cVa9bD3JAoc6hJHfU68PkLWrYmn6AN81PJs7kG6BHR1TeA4nKJtF

得られた生トランザクションをデコードして確認します。

$ bcli decoderawtransaction 02000000000101387eee5dd96c6349fb16ceef466c0b9265e029cd71abe47d7ee0a08621424c360000000000ffffffff027011010000000000220020575a24105c2477064a499c43645d344cdcb76cd847dd1c72d44318c8f6fb5ea2c274000000000000160014139cc0186ad9fefb2ceb1ce77ef6a7eb960ad05d024830450221008b022898583d8dd4eb8136982b3ed7bdd0f632a6613def653d171c1536ef954702206e7d958b881a6e66c42d9ba8c3fd88a9724fc10d9c12a5e15340c564e8a0d3ae0121034c30836747cd7d7a50db1de9ceb1c953a4c308bbf2669c620d62a4370f63b47200000000

フルノードが同期完了した後、ブロードキャストします。

$ bcli sendrawtransaction 02000000000101387eee5dd96c6349fb16ceef466c0b9265e029cd71abe47d7ee0a08621424c360000000000ffffffff027011010000000000220020575a24105c2477064a499c43645d344cdcb76cd847dd1c72d44318c8f6fb5ea2c274000000000000160014139cc0186ad9fefb2ceb1ce77ef6a7eb960ad05d024830450221008b022898583d8dd4eb8136982b3ed7bdd0f632a6613def653d171c1536ef954702206e7d958b881a6e66c42d9ba8c3fd88a9724fc10d9c12a5e15340c564e8a0d3ae0121034c30836747cd7d7a50db1de9ceb1c953a4c308bbf2669c620d62a4370f63b47200000000
error code: -26
error message:
min relay fee not met, 110 < 153

このエラーは手数料不足で送金できませんでした。

Input - OutPut >= 153 になるように調整します。

psbt.addOutput({
    address: "tb1qzwwvqxr2m8l0kt8trnnhaa48awtq45zauflz5y",
    value: 29847,
});
$ node singleSigTx.js 
privateKey_wif:
cVa9bD3JAoc6hJHfU68PkLWrYmn6AN81PJs7kG6BHR1TeA4nKJtF
02000000000101387eee5dd96c6349fb16ceef466c0b9265e029cd71abe47d7ee0a08621424c360000000000ffffffff027011010000000000220020575a24105c2477064a499c43645d344cdcb76cd847dd1c72d44318c8f6fb5ea29774000000000000160014139cc0186ad9fefb2ceb1ce77ef6a7eb960ad05d0248304502210090508855aaca0dc1a5387d136ca4373791855792c3467a39991aca10d4814639022057312bedf9d922999ccba8dab4b8f3d5a32548c4c380e9f316a93e347e36e88d0121034c30836747cd7d7a50db1de9ceb1c953a4c308bbf2669c620d62a4370f63b47200000000

再度送金

$ bcli sendrawtransaction 02000000000101387eee5dd96c6349fb16ceef466c0b9265e029cd71abe47d7ee0a08621424c360000000000ffffffff027011010000000000220020575a24105c2477064a499c43645d344cdcb76cd847dd1c72d44318c8f6fb5ea29774000000000000160014139cc0186ad9fefb2ceb1ce77ef6a7eb960ad05d0248304502210090508855aaca0dc1a5387d136ca4373791855792c3467a39991aca10d4814639022057312bedf9d922999ccba8dab4b8f3d5a32548c4c380e9f316a93e347e36e88d0121034c30836747cd7d7a50db1de9ceb1c953a4c308bbf2669c620d62a4370f63b47200000000
19fdd3ba91d7b7e2a05a49cdf20998334d5e5a774025e8cb51bfc2c4d06c364b

得られたトランザクションをExplorerで確認してみましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
0
Help us understand the problem. What are the problem?