Post
Topic
Board Bahasa Indonesia (Indonesian)
Merits 4 from 2 users
Re: [Edukasi] Proses Transaksi & Block di Jaringan Blockchain Bitcoin
by
punk.zink
on 09/03/2024, 07:09:39 UTC
⭐ Merited by Husna QA (3) ,fillippone (1)
Taproot yang mengimplementasikan MAST Protocol memberikan keuntungan yang cukup besar pada saat membuat sebuah transaksi, dimana dalam hal ini sebuah transaksi jadi memiliki use case dan opsi yang lebih beragam. Dengan adanya MAST Protocol maka untuk setiap penggunaan UTXO (output dari Transaksi yang belum digunakan) bisa didasarkan pada struktur script dari sebuah Merkle Tree (script Tree), sementara script yang disusun dalam script Tree tersebut disebut dengan istilah Tapscript.

Sebelum Taproot direlease, jika kita ingin membuat sebuah Transaksi Multisig pada format transaksi P2SH maupun P2WSH, maka untuk bisa menggunakan UTXO pada transaksi tersebut diperlukan signature dari masing-masing Key yang terkorelasi. Sementara pada Taproot, memungkinkan bagi suatu transaksi yang dalam penggunaan UTXO-nya diwakili oleh proses MultiSig atau menggunakan metode unlocking lainnya yang didasarkan pada Tapscript yang sudah dituliskan di script Tree.

Untuk detail lebih lanjut, maka akan saya berikan contoh pembuatan sebuah Taproot Address yang menggunakan dasar Script path spends, dimana pada struktur script Tree memiliki 2 Tapscript dengan fungsi yang berbeda. Tascript pertama merupakan unlocking-script berdasarkan proses Multisig 2-of-2, sementara untuk Tapscript kedua merupakan unlocking-script yang didasarkan pada signature dari dari sebuah Private Key.

Contoh kasus penggunaan Script path spends diatas bisa dijadikan opsi bagi seseorang (Owner contohnya) yang memiliki 2 wakil terpecaya, dimana untuk setiap transaksi yang dibuat bisa dilakukan oleh 2 wakil tersebut dengan masing-masing melakukan "sign" secara terpisah atau transaksi bisa dilakukan cukup dengan hanya mendapatkan "sign" dari si Owner sendiri. Sementara untuk pembuatan Taproot address dan transaksi, bisa dilakukan oleh pihak ke-4 (sekretaris misalnya  Grin).



Transaksi Taproot dengan 2 opsi Script path spends

Bahan
  • 3 Extended Private Key untuk masing-masing : Owner, Signer 1 dan Signer 2
  • 1 Extended Public Key sebagai Internal Key (dalam bentuk X-Only PubKey)
  • Node JS dan bitcoinjs-lib (serta beberapa library JavaScript lainnya))

Membuat Address

- Untuk masing-masing node harus selalu menampilkan (provide) library dibawah ini, dalam setiap prosesnya
Code:
import * as bitcoin from "bitcoinjs-lib";
import { BIP32Factory } from 'bip32';
import * as bip39 from 'bip39';
import * as ecc from "tiny-secp256k1";
const testnet = bitcoin.networks.testnet;
import pkg from 'bip174/src/lib/interfaces.js';
const { PsbtInput, TapLeaf, TapLeafScript } = pkg;
import { LEAF_VERSION_TAPSCRIPT } from 'bitcoinjs-lib/src/payments/bip341.js';
import { toXOnly, tapTreeToList, tapTreeFromList } from 'bitcoinjs-lib/src/psbt/bip371.js';
bitcoin.initEccLib(ecc);
const bip32 = BIP32Factory(ecc);


- Mendapatkan X-Only PubKey dari masing-masing: Owner, Signer 1 dan Signer 2

  • Owner
Code:
const xprivOwner = 'tprv8ZgxMBicQKsPduxxxxxxxxxxxxxxxxCueWfakJRjEbiJKTwgx';
const OwnerKey = bip32.fromBase58(xprivOwner, bitcoin.networks.testnet);
const ownerPubkeys = toXOnly(OwnerKey.publicKey).toString('hex');

console.log("PubKey Owner: " + ownerPubkeys)

  • Signer 1
Code:
const xprivleafKey1 = 'tprv8ZgxMBicQKsPe9xxxxxxxxxxxxxxxxxx2nLLNwKkpfbPq91W';
const leafKey1 = bip32.fromBase58(xprivleafKey1, bitcoin.networks.testnet);
const leafPubkeys1 = toXOnly(leafKey1.publicKey).toString('hex');

console.log("signerPubkeys1: " + leafPubkeys1);

  • Signer 2
Code:
const xprivleafKey2 = 'tprv8ZgxMBicQKsPeMxxxxxxxxxxxxxABFVfaGRRwz9vqDnwSK2';
const leafKey2 = bip32.fromBase58(xprivleafKey2, bitcoin.networks.testnet);
const leafPubkeys2 = toXOnly(leafKey2.publicKey).toString('hex');

console.log("signerPubkeys2: " + leafPubkeys2);


- Membuat Address di Node Operator
Code:
const xpubKey = 'tpubDDSaWvfLpFMfH119pbvNV9z5mXob2pJ4XiTLeXv3nSsBi2JSCrhc1hy7EoFFwGu4LYHSsgRzqZ5ho4MbtL53qQyKvw7ioVFKkYRVRXcE8L9';
const internalKey = bip32.fromBase58(xpubKey, bitcoin.networks.testnet);

const ownerPubkeys = '6d966f42e1672c8ebd5224f48bb67ae698ee2a11aa84bd8eeebae06457822bb8';
const ownerAsm = `${ownerPubkeys} OP_CHECKSIG`;
const ownerScript = bitcoin.script.fromASM(ownerAsm);

const signerPubkeys1 = '8a30b94ede9dcb8831339b8cd68856b52f745164c944f1b46cb2832b6c3d9468';
const signerPubkeys2 = '5b7955d831a41e5c4d4cf7dc07f4d8463c96f2492e0d2633df2d01d3074de2d2';
const leafScriptAsm = `${signerPubkeys2} OP_CHECKSIG ${signerPubkeys1} OP_CHECKSIGADD OP_2 OP_NUMEQUAL`;
const leafScript = bitcoin.script.fromASM(leafScriptAsm);

const scriptTree = [{ output: leafScript },{ output: ownerScript }];

const { output, address, witness } = bitcoin.payments.p2tr({
  internalPubkey: toXOnly(internalKey.publicKey),
          scriptTree,
          network: testnet,
    });

console.log(address);
Code:
tb1p2dk7yuq5rqt5jt2dr2njjrsdv2g5d6lxszc8c8herd6k2gd00w5ql574z6


MembuatTransaksi dengan opsi spending MultiSig (Signer 1 dan Signer 2)

- Operator
Code:
const xpubKey = 'tpubDDSaWvfLpFMfH119pbvNV9z5mXob2pJ4XiTLeXv3nSsBi2JSCrhc1hy7EoFFwGu4LYHSsgRzqZ5ho4MbtL53qQyKvw7ioVFKkYRVRXcE8L9';
const internalKey = bip32.fromBase58(xpubKey, bitcoin.networks.testnet);

const ownerPubkeys = '6d966f42e1672c8ebd5224f48bb67ae698ee2a11aa84bd8eeebae06457822bb8';
const ownerAsm = `${ownerPubkeys} OP_CHECKSIG`;
const ownerScript = bitcoin.script.fromASM(ownerAsm);

const signerPubkeys1 = '8a30b94ede9dcb8831339b8cd68856b52f745164c944f1b46cb2832b6c3d9468';
const signerPubkeys2 = '5b7955d831a41e5c4d4cf7dc07f4d8463c96f2492e0d2633df2d01d3074de2d2';
const leafScriptAsm = `${signerPubkeys2} OP_CHECKSIG ${signerPubkeys1} OP_CHECKSIGADD OP_2 OP_NUMEQUAL`;
const leafScript = bitcoin.script.fromASM(leafScriptAsm);

const scriptTree = [{ output: leafScript },{ output: ownerScript }];

const redeem = {output: leafScript, redeemVersion: LEAF_VERSION_TAPSCRIPT};
const { output, address, witness } = bitcoin.payments.p2tr({
  internalPubkey: toXOnly(internalKey.publicKey),
          scriptTree,
  redeem,
          network: testnet,
    });

    const psbt = new bitcoin.Psbt({ network: testnet });
      psbt.addInput({
      hash: '503eec63c75856eb07afe77d70d3e2dafbbbf4b79620aecad77bdbcbfe7c64f1',
      index: 0,
      sequence: 0xfffffffd,
      witnessUtxo: { value: 6000, script: output },
    });
    psbt.updateInput(0, {
      tapLeafScript: [
        {
          leafVersion: redeem.redeemVersion,
          script: redeem.output,
          controlBlock: witness[witness.length - 1],
        },
      ],
    });

    psbt.addOutput({ value: 5000, address: 'tb1p40hzwygkq4mmm6ma6e60003wj8ajx5rf2zqgj266zrcz4q573a2qj4uxa2' });

const psbtBaseText = psbt.toBase64();
console.log(psbtBaseText);
Code:
cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hCFcAzSQvwke9DYlTYXfRMck3bo29xvGYMdkl1qrANcfi2Cwy+HkXt24UDL8NETuPjZsq8jWkEXsRTYJIKq88z6B+QRyBbeVXYMaQeXE1M99wH9NhGPJbySS4NJjPfLQHTB03i0qwgijC5Tt6dy4gxM5uM1ohWtS90UWTJRPG0bLKDK2w9lGi6UpzAAAA=

- Signer 1
Code:
const xprivleafKey1 = 'tprv8ZgxMBicQKsPe9xxxxxxxxxxxxxxxxxx2nLLNwKkpfbPq91W';
const leafKey1 = bip32.fromBase58(xprivleafKey1, bitcoin.networks.testnet);
const leafPubkeys1 = toXOnly(leafKey1.publicKey).toString('hex');

const psbtBaseText = 'cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hCFcAzSQvwke9DYlTYXfRMck3bo29xvGYMdkl1qrANcfi2Cwy+HkXt24UDL8NETuPjZsq8jWkEXsRTYJIKq88z6B+QRyBbeVXYMaQeXE1M99wH9NhGPJbySS4NJjPfLQHTB03i0qwgijC5Tt6dy4gxM5uM1ohWtS90UWTJRPG0bLKDK2w9lGi6UpzAAAA=';
const signer1 = bitcoin.Psbt.fromBase64(psbtBaseText);
signer1.signInput(0, leafKey1);
const s1text = signer1.toBase64();
console.log(s1text);
Code:
cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hBFIowuU7encuIMTObjNaIVrUvdFFkyUTxtGyygytsPZRok7gNaaaDtCpJyM5GhvRzAcyKePQaVyILPVPtpGk/yh1AAAkxDsWe8OnaFRJij+PQE8kIgzulwzZp+YawGXz/N2zvWetSDHJNS2SDi/r3y7lGlShsyuA4j//6fjx3fi39mkIVwDNJC/CR70NiVNhd9ExyTdujb3G8Zgx2SXWqsA1x+LYLDL4eRe3bhQMvw0RO4+NmyryNaQRexFNgkgqrzzPoH5BHIFt5VdgxpB5cTUz33Af02EY8lvJJLg0mM98tAdMHTeLSrCCKMLlO3p3LiDEzm4zWiFa1L3RRZMlE8bRssoMrbD2UaLpSnMAAAA==

- Signer 2
Code:
const xprivleafKey2 = 'tprv8ZgxMBicQKsPeMxxxxxxxxxxxxxABFVfaGRRwz9vqDnwSK2';
const leafKey2 = bip32.fromBase58(xprivleafKey2, bitcoin.networks.testnet);
const leafPubkeys2 = toXOnly(leafKey2.publicKey).toString('hex');

const psbtBaseText = 'cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hCFcAzSQvwke9DYlTYXfRMck3bo29xvGYMdkl1qrANcfi2Cwy+HkXt24UDL8NETuPjZsq8jWkEXsRTYJIKq88z6B+QRyBbeVXYMaQeXE1M99wH9NhGPJbySS4NJjPfLQHTB03i0qwgijC5Tt6dy4gxM5uM1ohWtS90UWTJRPG0bLKDK2w9lGi6UpzAAAA=';
const signer2 = bitcoin.Psbt.fromBase64(psbtBaseText);
signer2.signInput(0, leafKey2);
const s2text = signer2.toBase64();
console.log(s2text);
Code:
cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hBFFt5VdgxpB5cTUz33Af02EY8lvJJLg0mM98tAdMHTeLSk7gNaaaDtCpJyM5GhvRzAcyKePQaVyILPVPtpGk/yh1AS3lC0idY+mWKk5QqyvpyLlNZDCFtAFzVGuzvA8VLsfvQO28bRiw+hjJa6m05sJH4KwQX8GiAX17sfiMjnvNJUEIVwDNJC/CR70NiVNhd9ExyTdujb3G8Zgx2SXWqsA1x+LYLDL4eRe3bhQMvw0RO4+NmyryNaQRexFNgkgqrzzPoH5BHIFt5VdgxpB5cTUz33Af02EY8lvJJLg0mM98tAdMHTeLSrCCKMLlO3p3LiDEzm4zWiFa1L3RRZMlE8bRssoMrbD2UaLpSnMAAAA==

- Kembali ke Operator (tuliskan perintah ini dibawah perintah-perintah lain yang sebelumnya sudah dituliskan di atas)
Code:
// const psbtBaseText = psbt.toBase64(); (tanda // bisa ditambahkan agar perintah tidak dieksekusi oleh Node JS)
// console.log(psbtBaseText);

const s1text = 'cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hBFIowuU7encuIMTObjNaIVrUvdFFkyUTxtGyygytsPZRok7gNaaaDtCpJyM5GhvRzAcyKePQaVyILPVPtpGk/yh1AAAkxDsWe8OnaFRJij+PQE8kIgzulwzZp+YawGXz/N2zvWetSDHJNS2SDi/r3y7lGlShsyuA4j//6fjx3fi39mkIVwDNJC/CR70NiVNhd9ExyTdujb3G8Zgx2SXWqsA1x+LYLDL4eRe3bhQMvw0RO4+NmyryNaQRexFNgkgqrzzPoH5BHIFt5VdgxpB5cTUz33Af02EY8lvJJLg0mM98tAdMHTeLSrCCKMLlO3p3LiDEzm4zWiFa1L3RRZMlE8bRssoMrbD2UaLpSnMAAAA==';
const s2text = 'cHNidP8BAF4CAAAAAfFkfP7L23vXyq4glrf0u/va4tNwfeevB+tWWMdj7D5QAAAAAAD/////AYgTAAAAAAAAIlEgq+4nERYFd73rfdZ0974ukfsjUGlQgIkrWhDwKoKej1QAAAAAAAEBK3AXAAAAAAAAIlEgU23icBQYF0ktTRqnKQ4NYpFG6+aAsHwe+Rt1ZSGve6hBFFt5VdgxpB5cTUz33Af02EY8lvJJLg0mM98tAdMHTeLSk7gNaaaDtCpJyM5GhvRzAcyKePQaVyILPVPtpGk/yh1AS3lC0idY+mWKk5QqyvpyLlNZDCFtAFzVGuzvA8VLsfvQO28bRiw+hjJa6m05sJH4KwQX8GiAX17sfiMjnvNJUEIVwDNJC/CR70NiVNhd9ExyTdujb3G8Zgx2SXWqsA1x+LYLDL4eRe3bhQMvw0RO4+NmyryNaQRexFNgkgqrzzPoH5BHIFt5VdgxpB5cTUz33Af02EY8lvJJLg0mM98tAdMHTeLSrCCKMLlO3p3LiDEzm4zWiFa1L3RRZMlE8bRssoMrbD2UaLpSnMAAAA==';

const sign1 = bitcoin.Psbt.fromBase64(s1text);
const sign2 = bitcoin.Psbt.fromBase64(s2text);
psbt.combine(sign1, sign2);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction();
const rawTx = tx.toBuffer();
const hex = rawTx.toString('hex');
console.log(hex);
Code:
02000000000101f1647cfecbdb7bd7caae2096b7f4bbfbdae2d3707de7af07eb5658c763ec3e500000000000ffffffff018813000000000000225120abee2711160577bdeb7dd674f7be2e91fb2350695080892b5a10f02a829e8f5404400009310ec59ef0e9da1512628fe3d013c908833ba5c33669f986b0197cff376cef59eb520c724d4b64838bfaf7cbb94695286ccae0388ffffa7e3c777e2dfd9a404b7942d22758fa658a93942acafa722e53590c216d005cd51aecef03c54bb1fbd03b6f1b462c3e86325aea6d39b091f82b0417f068805f5eec7e23239ef3495046205b7955d831a41e5c4d4cf7dc07f4d8463c96f2492e0d2633df2d01d3074de2d2ac208a30b94ede9dcb8831339b8cd68856b52f745164c944f1b46cb2832b6c3d9468ba529c41c033490bf091ef436254d85df44c724ddba36f71bc660c764975aab00d71f8b60b0cbe1e45eddb85032fc3444ee3e366cabc8d69045ec45360920aabcf33e81f9000000000

- Selanjutnya tinggal mengirimkan RAW Transaction diatas ke jaringan Bitcoin Testnet

- TXID b402e905a9c323868f8d69fbd3be9061e2fca6a7f0e5ed628cf1bbf8ed8dd1a7