编写第一笔比特币交易 #2

如何编程构建 bitcoin 交易

在 GitHub 上查看代码

第一部分介绍了交易构建的基础知识,如从目标地址创建输出和收集所需的输入价值。最复杂的部分是构建输入签名的消息。现在我们已经有了一个,我们将生成一个签名,最终生成交易输入的脚本。最后一步是将所有内容打包在一起。

输入脚本

作为 ex-tx-build.c 的结果,为我们的输入构建了可签名的消息。在 ex-tx-sign.c 中,我们将重复使用该消息作为起点。

生成签名

与其签署消息本身,我们将签署其 hash256 摘要:

62 44 98 0f a0 75 2e 5b
46 43 ed b3 53 fd a5 23
8a 9a 3d 44 49 16 76 78
8e fd d2 5d d6 48 55 ba

使用我们的 ECDSA 私钥

16 26 07 83 e4 0b 16 73
16 73 62 2a c8 a5 b0 45
fc 3e a4 af 70 f7 27 f3
f9 e9 2b dd 3a 1d dc 42

这是我得到的一个 DER 签名(你的将会有所不同):

30 44 02 20 11 1a 48 2a
ba 6a fb a1 2a 6f 27 de
76 7d d4 d0 64 17 de f6
65 bd 10 0b c6 8c 42 84
5c 75 2a 8f 02 20 5e 86
f5 e0 54 b2 c6 ca c5 d6
63 66 4e 35 77 9f b0 34
38 7c 07 84 8b c7 72 44
42 ca cf 65 93 24 

标志和汇编

SIGHASH标志(现在是 8 位)再次附加到签名上,与压缩的 ECDSA 公钥一起:

02
82 00 6e 93 98 a6 98 6e
da 61 fe 91 67 4c 3a 10
8c 39 94 75 bf 1e 73 8f
19 df c2 db 11 db 1d 28

最终,我们能够构建我们的 P2PKH 输入脚本:

47 30 44 02 20 11 1a 48
2a ba 6a fb a1 2a 6f 27
de 76 7d d4 d0 64 17 de
f6 65 bd 10 0b c6 8c 42
84 5c 75 2a 8f 02 20 5e
86 f5 e0 54 b2 c6 ca c5
d6 63 66 4e 35 77 9f b0
34 38 7c 07 84 8b c7 72
44 42 ca cf 65 93 24 01

21 02 82 00 6e 93 98 a6
98 6e da 61 fe 91 67 4c
3a 10 8c 39 94 75 bf 1e
73 8f 19 df c2 db 11 db
1d 28

是的,签名过程可能是我们工作中最令人讨厌和容易出错的部分。

打包交易

我们已经准备好从我们的输入和输出中打包交易。让我们看看 ex-tx-pack.c

输入和输出

就像我为输出所做的那样,我还在 tx.h 中编写了一个用于创建 P2PKH 输入的 C 宏。该宏接受 UTXO 输出点、签名、公钥和SIGHASH标志:

void bbp_txin_create_p2pkh(bbp_txin_t *txin, const bbp_outpoint_t *outpoint,
        const char *sig, const char *pub, bbp_sighash_t flag);

我们使用该宏来创建我们的输入,而输出代码则直接从 ex-tx-build.c 中取出:

bbp_outpoint_fill(&outpoint,
        "f34e1c37e736727770fed85d1b129713ef7f300304498c31c833985f487fa2f3", 0);
bbp_txin_create_p2pkh(&ins[0], &outpoint,
        "30440220111a482aba6afba12a6f27de767dd4d06...",
        "0282006e9398a6986eda61fe91674c3a108c39947...",
        BBP_SIGHASH_ALL);

bbp_txout_create_p2pkh(&outs[0], 25100000,
        "18ba14b3682295cb05230e31fecb000892406608");
bbp_txout_create_p2pkh(&outs[1], 61900000,
        "6bf19e55f94d986b4640c154d864699341919511");

最终结构

最简单的步骤是组装交易结构并将其传递给bbp_tx_serialize

tx.version = bbp_eint32(BBP_LITTLE, 1);
tx.outputs_len = 2;
tx.outputs = outs;
tx.inputs_len = 1;
tx.inputs = ins;
tx.locktime = 0;
rawtx_len = bbp_tx_size(&tx, 0);
rawtx = malloc(rawtx_len);
bbp_tx_serialize(&tx, rawtx, 0);

flag参数设置为0以打包已签名的交易而不是可签名消息。序列化的交易为:

/* 版本(32 位) */
01 00 00 00

/* 输入数量(varint) */
01

/* UTXO txid(hash256,小端) */
f3 a2 7f 48 5f 98 33 c8
31 8c 49 04 03 30 7f ef
13 97 12 1b 5d d8 fe 70
77 72 36 e7 37 1c 4e f3

/* UTXO 索引(32 位) */
00 00 00 00

/* 输入脚本(varint + 数据) */
6a 47 30 44 02 20 11 1a
48 2a ba 6a fb a1 2a 6f
27 de 76 7d d4 d0 64 17
de f6 65 bd 10 0b c6 8c
42 84 5c 75 2a 8f 02 20
5e 86 f5 e0 54 b2 c6 ca
c5 d6 63 66 4e 35 77 9f
b0 34 38 7c 07 84 8b c7
72 44 42 ca cf 65 93 24
01 21 02 82 00 6e 93 98
a6 98 6e da 61 fe 91 67
4c 3a 10 8c 39 94 75 bf
1e 73 8f 19 df c2 db 11
db 1d 28 

/* UTXO 序列 */
ff ff ff ff

/* 输出数量(varint) */
02

/* 输出价值(64 位) */
e0 fe 7e 01 00 00 00 00

/* 输出脚本(varint + 数据) */
19 76 a9 14 18 ba 14 b3
68 22 95 cb 05 23 0e 31
fe cb 00 08 92 40 66 08
88 ac

/* 找零输出价值(64 位) */
e0 84 b0 03 00 00 00 00

/* 找零输出脚本(varint + 数据) */
19 76 a9 14 6b f1 9e 55
f9 4d 98 6b 46 40 c1 54
d8 64 69 93 41 91 95 11
88 ac

/* 锁定时间(32 位) */
00 00 00 00

总共 225 字节。通过对交易进行 hash256(大端)可获得 txid:

99 96 e2 f6 4b 6a f0 23
2d d9 c8 97 39 5c e5 1f
dd 35 e6 35 9e dd 28 55
c6 0f f8 23 d8 d6 57 d1 

发布到网络

我们成功了,我们刚刚构建了我们的第一笔比特币交易!接下来呢?当然,我们希望将我们的交易提交到区块链。为此,存在网络服务可以帮助我们避免与 P2P 网络通信的负担。

例如,Blockr 推送服务 (在我们的场景中为测试网)非常方便,可以将原始交易发布到区块链。插入一个原始交易,就像从 ex-tx-pack.c 输出的rawtx一样,然后你就完成了,甚至可以在确认之前再次检查。如果你之前没有双花你的 UTXO,并且你已经做了一切正确,几分钟后你应该能看到交易实时显示。也就是说,一旦它在一个区块中被挖出。

然而,如果你尝试发布我们的示例交易,你将收到以下错误:

比特币交易推送错误

别担心,那是因为我已经自己发布了它。看看它在区块浏览器上的样子

获取代码!

GitHub 上的完整源代码

下一篇?

你学会了如何签署交易输入并打包原始区块链交易。交易标识符(txid)是交易字节的 hash256 摘要。

下一篇文章中,我们将看一看钱包软件。如果你喜欢这篇文章,请分享。

我是 AI 翻译官,为大家转译优秀英文文章,如有翻译不通的地方,在这里修改,还请包涵~

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Davide De Rosa
Davide De Rosa
江湖只有他的大名,没有他的介绍。