用JavaScript开发比特币应用BitcoinJS-lib的过程是怎样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
在这个教程中,我们将学习如何使用Bitconjs-lib开发库来开发一个简单的JavaScript版本的比特币应用。我们要实现的特性包括:离线创建比特币私钥和地址、进行账户充值、离线构造转账裸交易并广播到比特币网络中等。
BitcoinJS-lib是一个npm包,可以用于node.js或浏览器javascript环境中。可以使用npm或yarn安装BitcoinJS-lib开发包:
npm install bitcoinjs-lib
首先引入bitcoinjs-lib开发库:
const Btc = require('bitcoinjs-lib')
比特币的主链和测试链有不同的网络参数,出于简化和安全性考虑,我们使用测试链来开发这个教程中的应用,因此引入测试链网络参数:
const TestNet = Btc.networks.testnet
每个比特币地址都对应一对密钥(私钥和公钥),因此我们首先用BitcoinJS创建密钥对并从密钥对推导出地址:
let keyPair = Btc.ECPair.makeRandom({ network: TestNet }) let address = keyPair.getAddress() let wifKey = keyPair.toWIF() console.log(`Address: ${address} \n WifKey: ${wifKey}`)
在上边的代码中,我们首先使用BitcoinJS的ECPair
类的静态方法makeRandom()
生成一个随机密钥对,然后使用密钥对的getAddress()
方法推导出对应的比特币地址,并使用toWif()
获取WIF格式的私钥,最后显示出得到的地址和WIF格式的私钥。
代码运行结果如下(你的结果应该与此不同):
Address: mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1 WifKey: cTEAh3DsC7KE4mzY5YFTYommzr7czbdiBfLPsXZrF6o3zSQLLw9Q
如果你有其他钱包到处的WIF格式的私钥,也可以导入BitcoinJS并推导出对应的地址,例如:
let wifKey = 'cTEAh3DsC7KE4mzY5YFTYommzr7czbdiBfLPsXZrF6o3zSQLLw9Q' let keyPair = new Btc.ECPair.fromWIF(privKey, TestNet) console.log("Address:", keyPair.getAddress())
结果类似如下:
Address: mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1
要记住私钥有点麻烦,我们可以用密码来辅助推导私钥,这样就可以进一步推导出公钥和地址。下面的代码使用BitcoinJS和nodejs大数计算库bigi实现:
const BigInteger = require('bigi') let passphrase = 'J@vaScr1pt' let keyPair = generateAddressFromSHA256Hash(passphrase); console.log('Address: ', keyPair.getAddress()) function generateAddressFromSHA256Hash(passphrase) { let hash = Btc.crypto.sha256(passphrase); let d = BigInteger.fromBuffer(hash); let keyPair = new Btc.ECPair(d, null, { network: TestNet }); return keyPair; }
结果如下:
Address: mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1
现在使用generateAddressFromSHA256Hash()
函数,我们就可以在任何时候用J@VaSc1pt
这个密码来会付出地址mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1
以及其对应的密钥对了。
在继续之前,我们需要为创建的比特币地址充点比特币。在网上有一些比特币测试链的Faucet,可以用来为任意指定的比特币地址充入一些比特币以便进行开发和测试。我使用的是这个,当然你可以搜索出更多的这种Faucet。
让Faucet给我们的测试地址充值结果如下:
cool,现在我们有了1.3个比特币可以继续测试了!
有两种办法查询一个比特币地址的余额、UTXO等信息:使用自己的节点,或者使用第三方API。出于简化考虑,在本教程中我们使用第三方API来查询指定比特币地址的余额与UTXO:
onst request = require('request'); let addr = 'mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1' let apiUrl = 'https://testnet.blockexplorer.com/api/addr/' // log unspent transactions request.get(apiUrl + addr + '/utxo', (err, req, body) => { console.log('utxo => ', JSON.parse(body)) } ); // log balance request.get(apiUrl + addr + '/balance', (err, req, body) => { console.log('balance => ', JSON.parse(body)) } );
结果如下:
utxo => [{ address: 'mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1', txid: '2d742aa8409ee4cd8afcb2f59aac6ede47b478fafbca2335c9c04c6aedf94c9b', vout: 0, scriptPubKey: '76a9146d622b371423d2e450c19d98059867d71e6aa87c88ac', amount: 1.3, satoshis: 130000000, height: 1180957, confirmations: 14 }] balance => 130000000 // 1.3 BTC = 130000000 satoshis
构造比特币裸交易要复杂一点,我们需要自己组织交易的输入和输出。
首先用BitcoinJS的交易构造器TransactionBuider
创建一个交易对象:
let tx = new Btc.TransactionBuilder(TestNet)
然后我们声明转出账号和转入账号:
let keyPair1 = generateAddressFromSHA256Hash('J@vaScr1pt') let keyPair2 = generateAddressFromSHA256Hash('B*tc0in')
然后声明转账金额、手续费等参数,并计算找零金额:
let amountWeHave = 130000000 // 1.3 BTC let amountToKeep = 100000000 // 1 BTC let transactionFee = 1000 // .00001 BTC let amountToSend = amountWeHave - amountToKeep - transactionFee
好了,现在可以为交易添加输入了。还记得前面我们查询出来的交易输出吗?这个交易输出我们将用作新交易的输入:
[{ txid: '2d742aa8409ee4cd8afcb2f59aac6ede47b478fafbca2335c9c04c6aedf94c9b', vout: 0, satoshis: 130000000, }]
使用BitcoinJS交易对象的addInput()
方法添加交易输入:
tx.addInput('2d742aa8409...', 0)
接下来添加交易输出,我们需要声明交易输出目标地址和金额:
tx.addOutput(keyPair2.getAddress(), amountToSend)
由于交易输入金额大于上述交易输出金额,因此我们还需要添加找零输出:
tx.addOutput(keyPair1.getAddress(), amountToKeep)
现在我们进行签名,由于用的是keyPair1的比特币,因此需要使用keyPair1的私钥进行签名:
tx.sign(0, keyPair1)
接下来把签名交易序列化为16进制码流,以便广播到比特币网络中:
let tx_hex = tx.build().toHex()
完整的代码如下:
let tx = new Btc.TransactionBuilder(TestNet) let keyPair1 = generateAddressFromSHA256Hash('J@vaScr1pt') let keyPair2 = generateAddressFromSHA256Hash('B*tc0in') let amountWeHave = 130000000 // 1.3 BTC let amountToKeep = 100000000 // 1 BTC let transactionFee = 1000 // .00001 BTC let amountToSend = amountWeHave - amountToKeep - transactionFee tx.addInput('2d742aa8409ee4cd8afcb2f59aac6ede47b478fafbca2335c9c04c6aedf94c9b', 0) tx.addOutput(keyPair2.getAddress(), amountToSend) tx.addOutput(keyPair1.getAddress(), amountToKeep) tx.sign(0, keyPair1) let tx_hex = tx.build().toHex()console.log('our beautiful transaction: ', tx_hex)
输出结果如下:
01000000019b4cf9ed6a4cc0c93523cafbfa78b447de6eac9af5b2fc8acde49e40 a82a742d000000006b483045022100b8e1bc891bbd910960cf00b52b87493ddf80 8c0b6816b05724b62c507c2ea552022071d775d9b89e0bbc1c2d1b907b700dbda5 8d880508ba7f6e11a3acc659d3ebe20121034ec9060d1935b235794e22f5335b4e 5c55e764ba9bddab2cf7f199dac7309ce1ffffffff0298bfc901000000001976a9 1423e6e135110f5fcacbd77323382bb70e4f76105f88ac00e1f505000000001976 a9146d622b371423d2e450c19d98059867d71e6aa87c88ac00000000
在广播裸交易之前,检查一下裸交易的内容是一种有效的调试方法。我们可以使用BlockCypher提供的解码工具来查看裸交易的内容,结果如下
{ "addresses": [ "mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1", "minnXa8Qarg5WbxPQg3vjLZdpbZGHavCzC" ], "block_height": -1, "block_index": -1, "confirmations": 0, "double_spend": false, "fees": 1000, "hash": "64697ab2a3c76b8c5930ca128316238bba5b172b2f8f61a0046b6630b1f80f08", "inputs": [ { "addresses": [ "mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1" ], "age": 1180957, "output_index": 0, "output_value": 130000000, "prev_hash": "2d742aa8409ee4cd8afcb2f59aac6ede47b478fafbca2335c9c04c6aedf94c9b", "script": "483045022100b8e1bc891bbd910960cf00b52b87493ddf808c0b6816b05724b62c507c2ea552022071d775d9b89e0bbc1c2d1b907b700dbda58d880508ba7f6e11a3acc659d3ebe20121034ec9060d1935b235794e22f5335b4e5c55e764ba9bddab2cf7f199dac7309ce1", "script_type": "pay-to-pubkey-hash", "sequence": 4294967295 } ], "outputs": [ { "addresses": [ "minnXa8Qarg5WbxPQg3vjLZdpbZGHavCzC" ], "script": "76a91423e6e135110f5fcacbd77323382bb70e4f76105f88ac", "script_type": "pay-to-pubkey-hash", "value": 29999000 }, { "addresses": [ "mqVKYrNJcMkdK2QHFNEd1P6Qfc1Sqs3hu1" ], "script": "76a9146d622b371423d2e450c19d98059867d71e6aa87c88ac", "script_type": "pay-to-pubkey-hash", "value": 100000000 } ], "preference": "low", "received": "2017-09-04T05:24:14.417939071Z", "relayed_by": "54.158.194.253", "size": 226, "total": 129999000, "ver": 1, "vin_sz": 1, "vout_sz": 2 }
一旦生成比特币裸交易,可以在网上找到很多提供广播比特币裸交易的服务。如果你希望在代码中进行广播,也可以使用这个API。
广播完成后,你可以在区块浏览器中查看交易确认情况:
看完上述内容,你们掌握用JavaScript开发比特币应用BitcoinJS-lib的过程是怎样的的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。