共计 9665 个字符,预计需要花费 25 分钟才能阅读完成。
这篇文章将为大家详细讲解有关如何使用 Golang 将誓言存在比特币的区块链上,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
大家先看一个区域链浏览器的交易链接:
https://www.blocktrail.com/tBCC/tx/a63edbbfa17e45b0890520ca30fce6d8eacd41635d1c447418fcfedffa14d914 打开这个链接, 滑到最后, 会看如图所示的文字
这是怎么做到的? 这是一个比特币的交易, 怎么能附上中文呢? 本文就一步步教 你怎么在比特币交易上添加文字. 因为比特币的交易具有不可篡改性, 且永久存在区域链上, 那么其附带的文字就有这个属性, 这就好像是一个誓言! 誓言记存, 多有意义!!
第一步: 买一定的比特币
比特币交易是需要手续费的, 而当前的手续费并不便宜, 动则至少上百元, 这太贵了. 所以我推荐大家先去比特币测试网络先弄一些币来测试. 怎么在获取比特币测试网络的免费比特币, 大家可以 Google 下, 有一些网站会免费送. 比如大家可以去 https://testnet.coinfaucet.eu/en/ 这个站点去获取, 当前获取的前提是你有一个测试网络的比特币地址, 不然不知道给谁发币啊. 下面教你怎么用 Golang 生成比特币测试地址:
https://github.com/btcsuite/btcd 是 bitcoin 的 golang 版实现, 先按照它的文档安装, 这里假设你已经成功安装在本地了.
下面这段代码包含生成测试和正式地址, 你可以运行得到测试地址.
package main
import (
github.com/btcsuite/btcd/btcec
github.com/btcsuite/btcutil
github.com/btcsuite/btcd/chaincfg
fmt
func GenerateBTC() (string, string, error) { privKey, err := btcec.NewPrivateKey(btcec.S256())
if err != nil {
return , , err
}
privKeyWif, err := btcutil.NewWIF(privKey, chaincfg.MainNetParams, false)
if err != nil {
return , , err
}
pubKeySerial := privKey.PubKey().SerializeUncompressed()
pubKeyAddress, err := btcutil.NewAddressPubKey(pubKeySerial, chaincfg.MainNetParams)
if err != nil {
return , , err
}
return privKeyWif.String(), pubKeyAddress.EncodeAddress(), nil
func GenerateBTCTest() (string, string, error) { privKey, err := btcec.NewPrivateKey(btcec.S256())
if err != nil {
return , , err
}
privKeyWif, err := btcutil.NewWIF(privKey, chaincfg.TestNet3Params, false)
if err != nil {
return , , err
}
pubKeySerial := privKey.PubKey().SerializeUncompressed()
pubKeyAddress, err := btcutil.NewAddressPubKey(pubKeySerial, chaincfg.TestNet3Params)
if err != nil {
return , , err
}
return privKeyWif.String(), pubKeyAddress.EncodeAddress(), nil
func main() { wifKey, address, _ := GenerateBTCTest() // 测试地址
// wifKey, address, _ := GenerateBTC() // 正式地址
fmt.Println(address, wifKey)
}
假设你得到了一个测试地址:
地址: mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
私钥: cV4HmdzGF3gG7NdEtVV7sjq22yoBmZBe5MEGKUqvQTXXXXX(注意, 该密钥不是正确的, 请不要使用)
然后, 你去 https://testnet.coinfaucet.eu/en/ 领免费的测试比特币, 可以通过接口查看该地址的未花费交易信息:
https://api.blockcypher.com/v1/btc/test3/addrs/mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd/full
总共发了两笔, 第一笔 0.65 第二笔 1.3 总共这个地址的余额是 1.95
{
address : mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd ,
total_received : 195000000,
total_sent : 0,
balance : 195000000,
unconfirmed_balance : 0,
final_balance : 195000000,
n_tx : 2,
unconfirmed_n_tx : 0,
final_n_tx : 2,
txs : [
// 第二笔
{
block_hash : 00000000000004149feebc41cfeb5a66df052f989aec60faec711caee4f93b3c ,
block_height : 1255326,
block_index : 53,
hash : 2c56134c99b24e17f5c3852d910e2e090848652c4e7b08ee8aa7450b2e14d7c4 ,
addresses : [
2N48GnaEkd8eZgQ5MLTb6EGBvqfuQ94sVTv ,
2NAwfhDByKfV5ZPr4cnLVg9hMHcx31CZbEp ,
mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
],
total : 197064067190,
fees : 100000,
size : 140,
preference : high ,
relayed_by : 94.130.106.254:18333 ,
confirmed : 2017-12-19T02:32:36Z ,
received : 2017-12-19T02:17:26.601Z ,
ver : 1,
double_spend : false,
vin_sz : 1,
vout_sz : 2,
confirmations : 5672,
confidence : 1,
inputs : [
{
prev_hash : 7265ffdf8310fc2ecd6277759f39de9c801149ca602c6b2236667d2af2d5dd29 ,
output_index : 1,
script : 1600149eb46621cceac0e393b5cd5ffb481fafa48a16fc ,
output_value : 197064167190,
sequence : 4294967295,
addresses : [
2NAwfhDByKfV5ZPr4cnLVg9hMHcx31CZbEp
],
script_type : pay-to-script-hash ,
age : 1255313,
witness : [
3044022034bb850d1efab224a14b7cd7565a9fce58fb89794f50471419115f1b893f626d022027a849a46f3a902944e3f01a66eb0fc489bfe8e5a7815b8644128b7e6f89ace101 ,
030916ad60b499268f909e20867b49d22e55b3864aafc896120c6daec1011ceecb
]
}
],
outputs : [
{
value : 130000000,
script : 76a91489a7f0117eaf47d8b4af740c66116e35ffe1bea988ac ,
addresses : [
mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
],
script_type : pay-to-pubkey-hash
},
{
value : 196934067190,
script : a9147758cec0a445f9908186f5cfeeb52bc0077c7e1487 ,
spent_by : 5c3c00896db0ba1a7526c6e8c3495c29264df99d4a494afbd909af4f0d4df605 ,
addresses : [
2N48GnaEkd8eZgQ5MLTb6EGBvqfuQ94sVTv
],
script_type : pay-to-script-hash
}
]
},
// 第一笔
{
block_hash : 00000000000004149feebc41cfeb5a66df052f989aec60faec711caee4f93b3c ,
block_height : 1255326,
block_index : 40,
hash : 48eea09764713f3dadcfed29490ab5e288299e01e571e1f7a1396a75ce38e067 ,
addresses : [
2N4Mrw2XRMEfAuf51JiZsaQCSxr9UowxSbJ ,
2N5CNRLZXXZt2JFxPLX9z6HF9gdgLqG3ycH ,
mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
],
total : 196092936523,
fees : 100000,
size : 140,
preference : high ,
relayed_by : 88.196.208.18:18333 ,
confirmed : 2017-12-19T02:32:36Z ,
received : 2017-12-19T02:17:33.267Z ,
ver : 1,
double_spend : false,
vin_sz : 1,
vout_sz : 2,
confirmations : 5672,
confidence : 1,
inputs : [
{
prev_hash : 2880f6c768afa728fa9374af0617d535a960243f2820de53992279a59b84d8a3 ,
output_index : 1,
script : 1600147ce118c5a9faa2fdf5bc1c7feb41ddac7084a481 ,
output_value : 196093036523,
sequence : 4294967295,
addresses : [
2N5CNRLZXXZt2JFxPLX9z6HF9gdgLqG3ycH
],
script_type : pay-to-script-hash ,
age : 1255313,
witness : [
30440220741aa14828e97e0fd9668b9070e2ab886f3646456c33b143c291f6c47e1ec985022005f624843908a745dbc5d703361065a5fbca9aa0b1fb4aca105cd09d8e6fd09e01 ,
02fe3a6a5cfb075b84d5a0e6daa2220dc49c8a36b61f49f86111dd08141166b7fc
]
}
],
// 以下几个值比较重要
outputs : [
{
value : 65000000,
script : 76a91489a7f0117eaf47d8b4af740c66116e35ffe1bea988ac ,
addresses : [
mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
],
script_type : pay-to-pubkey-hash
},
{
value : 196027936523,
script : a91479eab7f3bf5054cc47da2761f0b61d6cb622622a87 ,
spent_by : dc32b80ba7f863572c8dd97508d8c7a04af35d10671c9ca3c60f0d28c552c8d1 ,
addresses : [
2N4Mrw2XRMEfAuf51JiZsaQCSxr9UowxSbJ
],
script_type : pay-to-script-hash
}
]
}
]
}
记住第一笔的这几个值:
tx_hash 48eea09764713f3dadcfed29490ab5e288299e01e571e1f7a1396a75ce38e067
tx_output_n 0
script: 76a91489a7f0117eaf47d8b4af740c66116e35ffe1bea988ac
value 65000000
我们接下来会用到这个未花费交易
第二步: 构造交易, 附上文字
下面构造一个交易, 这个交易给自己发一笔钱, 交易费是 0.001
address := mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
var balance int64 = 65000000 // 余额
var fee int64 = 0.001 * 1e8 // 交易费
var leftToMe = balance - fee // 余额 - 交易费就是剩下再给我的
// 1. 构造输出
outputs := []*wire.TxOut{}
// 1.1 输出 1, 给自己转剩下的钱
addr, _ := btcutil.DecodeAddress(address, chaincfg.SimNetParams)
pkScript, _ := txscript.PayToAddrScript(addr)
outputs = append(outputs, wire.NewTxOut(leftToMe, pkScript))
// 1.2 输出 2, 添加文字
comment := 这是一个留言, 哈哈
pkScript, _ = txscript.NullDataScript([]byte(comment))
outputs = append(outputs, wire.NewTxOut(int64(0), pkScript))
第三步: 构造输入
// 2. 构造输入
prevTxHash := 48eea09764713f3dadcfed29490ab5e288299e01e571e1f7a1396a75ce38e067
prevPkScriptHex := 76a91489a7f0117eaf47d8b4af740c66116e35ffe1bea988ac
prevTxOutputN := uint32(0)
hash, _ := chainhash.NewHashFromStr(prevTxHash) // tx hash
outPoint := wire.NewOutPoint(hash, prevTxOutputN) // 第几个输出
txIn := wire.NewTxIn(outPoint, nil, nil)
inputs := []*wire.TxIn{txIn}
prevPkScript, _ := hex.DecodeString(prevPkScriptHex)
prevPkScripts := make([][]byte, 1)
prevPkScripts[0] = prevPkScript
tx := wire.MsgTx{
Version: wire.TxVersion,
TxIn: inputs,
TxOut: outputs,
LockTime: 0,
}
第四步: 签名交易 (签名输入)
// 3. 签名
privKey := cV4HmdzGF3gG7NdEtVV7sjq22yoBmZBe5MEGKUqvQTXXXXX // 私钥
sign(tx, privKey, prevPkScripts)
// 签名方法
func sign(tx *wire.MsgTx, privKeyStr string, prevPkScripts [][]byte) {
inputs := tx.TxIn
wif, err := btcutil.DecodeWIF(privKeyStr)
fmt.Println(wif err , err)
privKey := wif.PrivKey
for i := range inputs { pkScript := prevPkScripts[i]
var script []byte
script, err = txscript.SignatureScript(tx, i, pkScript, txscript.SigHashAll,
privKey, false)
inputs[i].SignatureScript = script
}
}
第五步: 输出交易原始信息, 广播到网络上
// 4. 输出 Hex
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
if err := tx.Serialize(buf); err != nil {txHex := hex.EncodeToString(buf.Bytes())
fmt.Println(hex , txHex)
将输出的 hex 广播到网络上, https://tbtc.blockdozer.com/insight/tx/send
下面给出完整源码:
package tx
import (
github.com/btcsuite/btcd/wire
github.com/btcsuite/btcutil
github.com/btcsuite/btcd/chaincfg
github.com/btcsuite/btcd/txscript
github.com/btcsuite/btcd/chaincfg/chainhash
encoding/hex
fmt
bytes
func main() {
address := mt4p3rZpJE5fXEqvGzNBk9HxYXcWKpPJSd
var balance int64 = 65000000 // 余额
var fee int64 = 0.001 * 1e8 // 交易费
var leftToMe = balance - fee // 余额 - 交易费就是剩下再给我的
// 1. 构造输出
outputs := []*wire.TxOut{}
// 1.1 输出 1, 给自己转剩下的钱
addr, _ := btcutil.DecodeAddress(address, chaincfg.SimNetParams)
pkScript, _ := txscript.PayToAddrScript(addr)
outputs = append(outputs, wire.NewTxOut(leftToMe, pkScript))
// 1.2 输出 2, 添加文字
comment := 这是一个留言, 哈哈
pkScript, _ = txscript.NullDataScript([]byte(comment))
outputs = append(outputs, wire.NewTxOut(int64(0), pkScript))
// 2. 构造输入
prevTxHash := 48eea09764713f3dadcfed29490ab5e288299e01e571e1f7a1396a75ce38e067
prevPkScriptHex := 76a91489a7f0117eaf47d8b4af740c66116e35ffe1bea988ac
prevTxOutputN := uint32(0)
hash, _ := chainhash.NewHashFromStr(prevTxHash) // tx hash
outPoint := wire.NewOutPoint(hash, prevTxOutputN) // 第几个输出
txIn := wire.NewTxIn(outPoint, nil, nil)
inputs := []*wire.TxIn{txIn}
prevPkScript, _ := hex.DecodeString(prevPkScriptHex)
prevPkScripts := make([][]byte, 1)
prevPkScripts[0] = prevPkScript
tx := wire.MsgTx{
Version: wire.TxVersion,
TxIn: inputs,
TxOut: outputs,
LockTime: 0,
// 3. 签名
privKey := cV4HmdzGF3gG7NdEtVV7sjq22yoBmZBe5MEGKUqvQTXXXXX // 私钥
sign(tx, privKey, prevPkScripts)
// 4. 输出 Hex
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
if err := tx.Serialize(buf); err != nil {txHex := hex.EncodeToString(buf.Bytes())
fmt.Println(hex , txHex)
// 签名
func sign(tx *wire.MsgTx, privKeyStr string, prevPkScripts [][]byte) {
inputs := tx.TxIn
wif, err := btcutil.DecodeWIF(privKeyStr)
fmt.Println(wif err , err)
privKey := wif.PrivKey
for i := range inputs {pkScript := prevPkScripts[i]
var script []byte
script, err = txscript.SignatureScript(tx, i, pkScript, txscript.SigHashAll,
privKey, false)
inputs[i].SignatureScript = script
}
关于“如何使用 Golang 将誓言存在比特币的区块链上”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。