nodejs與btc網(wǎng)絡(luò)交互使用
bitcoinjs-lib模組
使用BTC測(cè)試網(wǎng)進(jìn)行測(cè)試
安裝模組
npm i bitcoinjs-lib
根據(jù)隨機(jī)字符構(gòu)造兩個(gè)函數(shù)
function rng () { return Buffer.from('tmd123zzzzzzzzzzzzzzzzzzzzzzzzzz') }
function rng2 () { return Buffer.from('tmd321333zzzzzzzzzzzzzzzzzzzzzzz') }
生成錢(qián)包1, 指定測(cè)試鏈
const alice = bitcoin.ECPair.makeRandom({network: testnet, rng});
const { address } = bitcoin.payments.p2pkh({ pubkey: alice.publicKey, network: testnet });
// console.log(address);
// console.log(alice.toWIF())
// 地址: mmH6e8tfLyvrrnFF3o1scaNsPXShGY89rb
// 私鑰: L182iNrxy9rSPQfEg5X1P1sR9qAbS1pbxPosguD8Sx5tYauV3bYm
生成錢(qián)包2
const bob = bitcoin.ECPair.makeRandom({network: testnet, rng: rng2 });
const { address:address2 } = bitcoin.payments.p2pkh({ pubkey: bob.publicKey, network: testnet });
// console.log(address2);
// console.log(bob.toWIF())
// 地址: miAMpCdoM3SuRMRoEVHp8smFdDAz29WA9g
// 私鑰: L182iNub4Z8Ly6H13jcx7i82jKq3czc7WzFso3z249LuMcMjzQXo
- 比特幣轉(zhuǎn)賬需要提取或合并所有未花費(fèi)的交易中的比特幣,才能實(shí)現(xiàn)交易。
- 描述起來(lái)比較復(fù)雜,下圖是個(gè)例子,我們從區(qū)塊瀏覽器查到我最近一筆未花費(fèi)支出,某個(gè)地址轉(zhuǎn)了0.03個(gè)BTC給我,在這一筆交易中,我有0.03個(gè)BTC。
-
如果我要轉(zhuǎn)出0.5個(gè)BTC給他人,我需要合并其他的交易,否則將會(huì)余額不足,雖然在我這個(gè)地址中有足夠的BTC。
1.png
2.png
單個(gè)哈希交易。
const transfer1 = async () => {
// 注意要指定交易對(duì)象是測(cè)試鏈的
const txb = new bitcoin.TransactionBuilder(testnet);
txb.setVersion(1);
// 在這個(gè)交易中, bob在第0個(gè)位置,上圖所示
txb.addInput('5799a647d6b89a9f73122d75faee6f5a0210bd3cb22c48a70d35eac33ce5d426', 0);
// 這里把btc轉(zhuǎn)給 alice 的地址,金額是0.02 但是要*100000000, 也就是2000000,
// 剩余的金額沒(méi)有設(shè)置招零地址接收,則被視為手續(xù)費(fèi),被區(qū)塊網(wǎng)絡(luò)收取
// 每一筆交易只有已花費(fèi)和未花費(fèi)兩種狀態(tài),不存在消費(fèi)一部分的狀態(tài),
// 所以合并多筆交易的話,只要未花費(fèi),都可以合并。
txb.addOutput('mmH6e8tfLyvrrnFF3o1scaNsPXShGY89rb', 2000000);
// 簽名交易,0代表索引,輸入排序,這里只有一個(gè)輸入,所以是第0位。
txb.sign(0, bob);
// 序列化成一串字符
const tx = txb.build().toHex();
console.log(tx);
// 在一個(gè)測(cè)試鏈的節(jié)點(diǎn)把交易廣布出去
const result = await fetch('https://api.blockcypher.com/v1/btc/test3/txs/push',{
method:'post',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({tx})
});
// 打印結(jié)果
console.log(result);
};
transfer1();
- 轉(zhuǎn)賬的時(shí)候需要手動(dòng)尋找每一筆未花費(fèi)記錄實(shí)在太費(fèi)時(shí)。
- 所以需要一個(gè)輔助節(jié)點(diǎn)來(lái)提取未來(lái)花費(fèi)的記錄
- 以下是一個(gè)區(qū)塊瀏覽器的鏈接,可以查詢(xún)到索要的記錄
https://api.blockcypher.com/v1/btc/test3/addrs/miAMpCdoM3SuRMRoEVHp8smFdDAz29WA9g
多筆交易,自動(dòng)合并。
const transfer2 = async () => {
const url = 'https://api.blockcypher.com/v1/btc/test3/addrs/';
const res = await fetch(url+address2);
const json = await res.json();
const balance = json.balance;
// console.log(balance/100000000);
const txrefs = json.txrefs;
// 過(guò)濾掉已經(jīng)被花費(fèi)了的交易,以及自己不在接收列表的交易
const unspentList = txrefs.filter(item=> !item.spent_by && item.tx_output_n !== -1);
// 這個(gè)地址還可以查詢(xún)余額
// console.log(unspentList);
// 構(gòu)建交易對(duì)象
const txb = new bitcoin.TransactionBuilder(testnet);
txb.setVersion(1);
// 批量插入未花費(fèi)交易
unspentList.forEach(item=>txb.addInput(item.tx_hash, item.tx_output_n));
// 轉(zhuǎn)出賬戶
txb.addOutput('mmH6e8tfLyvrrnFF3o1scaNsPXShGY89rb', 2000000);
// 設(shè)置找零地址,如果忘記了,就會(huì)丟失所有BTC !?。。。。。?!
// 如果不預(yù)留手續(xù)費(fèi),交易可能會(huì)一直不被打包!
// 3000 為手續(xù)費(fèi)
txb.addOutput('miAMpCdoM3SuRMRoEVHp8smFdDAz29WA9g',balance - 2000000 - 3000);
// 批量簽名,根據(jù)索引即可
unspentList.forEach((item,index)=>{txb.sign(index, bob)});
// 序列化交易
const tx = txb.build().toHex();
// console.log(tx);
// 在一個(gè)測(cè)試鏈的節(jié)點(diǎn)把交易廣布出去
const result = await fetch('https://api.blockcypher.com/v1/btc/test3/txs/push',{
method:'post',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({tx})
});
// 打印結(jié)果
console.log(result);
};
transfer2();

