专栏首页申龙斌的程序人生用NBitcoin进行区块链开发(6):交易签名

用NBitcoin进行区块链开发(6):交易签名

比特币交易的签名过程是所有环节中最复杂的步骤之一,下面两篇文章对这个过程有详细的描述。

https://klmoney.wordpress.com/bitcoin-dissecting-transactions-part-2-building-a-transaction-by-hand/

http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html

为了试验整个签名过程,我从一堆钱包地址中翻出了一笔816聪的零钱,地址为:15Qzd7JUnNSEtDR8nPhHtGBaBHHz8rrfeQ。

签名过程需要动用私钥,提前在Bitcoin Core中找到它,建立一个BitcoinSecret。

BitcoinSecret secret = new BitcoinSecret("L5ktQM***QtNECt");

创建一个交易:

Transaction tx = Transaction.Create(Network.Main);

构建一个输入项,来自于以前一笔交易(txid: ab04***a949)的第1项输出(起始编号是0)。这里需要注意,签名之前把ScriptSig信息填好。

TxIn vin = new TxIn(); uint256 prevTX = new uint256("ab047463b7ee9140012b5cdc6d2d2d92ef08c8a96320e19265415fbf3964a949"); vin.PrevOut = new OutPoint(prevTX, 1); vin.ScriptSig = secret.ScriptPubKey; tx.Inputs.Add(vin);

再构建一个输出项,把600聪发到一个地址中,剩下的216聪自动作为矿工的手续费奖励。

TxOut vout = new TxOut(); var destination = BitcoinAddress.Create("18Cf4LhiW3RwYbUH4xaQS9hmNH6TcM25Aw", Network.Main); vout.Value = Money.Satoshis(600); vout.ScriptPubKey = destination.ScriptPubKey; tx.Outputs.Add(vout);

最为关键的一步,用私钥完成签名操作。

tx.Sign(secret.PrivateKey, assumeP2SH: false);

用NBitcoin编程,内部复杂的签名细节已经被开发者全部封装好了,我们只需调用Sign()函数即可。我们可以看一下交易在签名之后的二进制数据,来准确地理解签名的过程。

整个交易数据占用191个字节:

010000000149a96439bf5f416592e12063a9c808ef922d2d6ddc5c2b014091eeb7637404ab010000006a47304402206a9f99a4a1647d3453d49939e29d5e06c48fb04d8894e3c49cdf8894e3d14ead0220435c88822e9ff9fa5fd62c374738d0b820de136b062252dfc0e2d0632aee233f012102b6ab8cb7e8bf8affa75b4138715aeb16c8867fa93bb67fd729597a25e788586affffffff0158020000000000001976a9144efd399552efc20e0a84526e7afb6d58bcf6fe8b88ac00000000

把这笔交易广播到比特币网络:

QBitNinjaClient client = new QBitNinjaClient(Network.Main); client.Broadcast(tx);

没过多久就有了5个确认。

把这191个字节掰碎了再看看。

version: 01 00 00 00 input count: 01 PrevOut TXID: 49 a9 64 39 bf 5f 41 65 92 e1 20 63 a9 c8 08 ef 92 2d 2d 6d d c 5c 2b 01 40 91 ee b7 63 74 04 ab PrevOut index: 01 00 00 00 script length: 6a (十进制:106) ScriptSig: 47 30 44 02 20 6a 9f 99 a4 a1 64 7d 34 53 d4 99 39 e2 9d 5e 06 c4 8f b0 4d 88 94 e3 c4 9c df 88 94 e3 d1 4e ad 02 20 43 5c 88 82 2e 9f f9 fa 5f d6 2c 37 47 38 d0 b8 20 de 13 6b 06 22 52 df c0 e2 d0 63 2a ee 23 3f 01 21 02 b6 ab 8c b7 e8 bf 8a ff a7 5b 41 38 71 5a eb 16 c8 86 7f a9 3b b6 7f d7 29 59 7a 25 e7 88 58 6a Sequence: ff ff ff ff Output count: 01 Value: 58 02 00 00 00 00 00 00 Script Length: 19 (十进制:25) ScriptPubKey: 76 a9 14 4e fd 39 95 52 ef c2 0e 0a 84 52 6e 7a fb 6d 58 bc f6 fe 8b 88 ac Lock Time: 00 00 00 00

其它内容在这篇文章中都已经介绍过了,现在多出了ScriptSig这些内容。

ScriptSig主要由签名和公钥两部分构成。

签名部分用DER编码(Distinguished Encoding Rules,可辨别编码规则),实际上就是记录了椭圆曲线签名的2个整数(R, S)。

今天比特币价格25135元,试验这篇文章只花了216聪的交易手续费,算下来还不到6分钱。在2017年底牛市的时候,手续费曾高达210000聪(以当前的价格换算为200多元)。

看来熊市也是有好处的:可以直接在主网上练技术。

本文分享自微信公众号 - 申龙斌的程序人生(slbGTD)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OP_RETURN誓言墙

    我们可以在比特币交易中附加上一个OP_RETURN输出,OP_RETURN可以填入任意字符,可以是誓言,可以是证据,也可以是情人节表白,一经写入,就会永久保存在...

    申龙斌
  • 零基础学编程020:强大的列表推导

    问题描述:找出50之内的所有勾股数。 所谓勾股数,就是三个正整数,满足x*x + y*y = z*z。例如:3,4,5或5,12,13。 电脑解题只会用笨办法,...

    申龙斌
  • 零基础学编程041:欧拉公式的几何意义

    欧拉公式号称是最美的出自上帝之手的数学公式,即 ? ,这个公式里 e 和 π 都是无理数,i 是 -1 的平方根,是一个虚数,0和1是最简单的整数,欧拉公式把...

    申龙斌
  • 利用HTC One漏洞破解手机PIN密码

    HTC One手机运行的是Android 4.2.2、HBOOT 1.54.0000,它存在一个名为Bootloader的漏洞。这个漏洞早在2014年2月份就报...

    FB客服
  • 10张图22段代码,万字长文带你搞懂虚拟内存模型和malloc内部原理

    摊牌了,不装了,其实我是程序喵辛苦工作一天还要回家编辑公众号到大半夜的老婆,希望各位大哥能踊跃转发,完成我一千阅读量的KPI(梦想),谢谢!

    公众号C语言与CPP编程
  • Linux如何调试内存泄漏

    内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前...

    公众号C语言与CPP编程
  • AkShare-股票数据-科创板报告

    科创板(The Science and Technology Innovation Board; STAR Market) [1] ,是由国家主席习近平于20...

    AkShare
  • 安全分析 | 两个VMware Workstation中的TOCTOU漏洞

    前两天,VMware发布了一份安全公告,并修复了VMware ESXi、Workstation、Fusion和NSX-T中的六个安全漏洞。其中有两个漏洞属于TO...

    FB客服
  • 高效的选择:将键盘上的大小写锁定键 CapsLock 与退出键 Esc 交换位置

    如果你习惯使用 Shift 切换大小写,那么在你左手小指处的 caps lock 大小写锁定键几乎没有用武之地。

    Piper蛋窝
  • 私人订制属于自己的Linux系统

    init通过调用/etc/inittab这个配置文件,然后再去执行/etc/rc.d/rc.sysinit的系统初始化脚本

    常见_youmen

扫码关注云+社区

领取腾讯云代金券