比特币交易的签名过程是所有环节中最复杂的步骤之一,下面两篇文章对这个过程有详细的描述。
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多元)。
看来熊市也是有好处的:可以直接在主网上练技术。