美文网首页
使用golang一步步教你在比特币上刻字

使用golang一步步教你在比特币上刻字

作者: hellomi001 | 来源:发表于2018-06-23 14:15 被阅读0次

    from:https://blog.csdn.net/u010662978/article/details/79195284

    大家先看一个区域链浏览器的交易链接:

    https://www.blocktrail.com/tBCC/tx/a63edbbfa17e45b0890520ca30fce6d8eacd41635d1c447418fcfedffa14d914打开这个链接, 滑到最后, 会看如图所示的文字

    这是怎么做到的? 这是一个比特币的交易, 怎么能附上中文呢? 本文就一步步教 你怎么在比特币交易上添加文字. 因为比特币的交易具有不可篡改性, 且永久存在区域链上, 那么其附带的文字就有这个属性, 这就好像是一个誓言! 誓言记存, 多有意义!!

    第一步: 买一定的比特币

    比特币交易是需要手续费的, 而当前的手续费并不便宜, 动则至少上百元, 这太贵了. 所以我推荐大家先去比特币测试网络先弄一些币来测试. 怎么在获取比特币测试网络的免费比特币, 大家可以Google下, 有一些网站会免费送. 比如大家可以去https://testnet.coinfaucet.eu/en/这个站点去获取, 当前获取的前提是你有一个测试网络的比特币地址, 不然不知道给谁发币啊. 下面教你怎么用Golang 生成比特币测试地址:

    https://github.com/btcsuite/btcd是bitcoin的golang版实现, 先按照它的文档安装, 这里假设你已经成功安装在本地了.

    下面这段代码包含生成测试和正式地址, 你可以运行得到测试地址.

    [plain] view plain copy

    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

    [javascript] view plain copy

    {  

    "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

    [plain] view plain copy

    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))  

    第三步: 构造输入

    [plain] view plain copy

    // 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,  

    }  

    第四步: 签名交易(签名输入)

    [plain] view plain copy

    // 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  

       }  

    }  

    第五步: 输出交易原始信息, 广播到网络上

    [plain] view plain copy

    // 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

    下面给出完整源码:

    [plain] view plain copy

    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  

        }  

    }  

    通过以上的方法, 比特币刻字我已在 www.ibitlin.com 上实现, 欢迎使用!!

    相关文章

      网友评论

          本文标题:使用golang一步步教你在比特币上刻字

          本文链接:https://www.haomeiwen.com/subject/acgryftx.html