一个新的bug解决途径——Bitcoin交易签名错误

1.问题描述

在开发比特币钱包的时候,发送原始交易数据(Raw transaction)遇到一个报错:
创建交易失败:16: mandatory-script-verify-flag-failed (Script failed an OP_EQUALVERIFY operation). Code:-26, sendTransaction fail
看问题的描述应该是签名有问题。查看了下官方的错误信息。如下:
https://github.com/bitcoin/bitcoin/blob/master/src/script/script_error.cpp
一个新的bug解决途径——Bitcoin交易签名错误_第1张图片

2.问题分析

尽管基本确定是签名出了问题,还是对问题进行完整的分析,可能的原因如下:

  • 节点出错,误报错
  • 原始交易数据组织结构不对或不完整
  • 使用了错误的私钥 :搜索了下网络上前人是否遇到同样的问题:找到了一条相关的。

“I figure out that the issue behind is that I am signing with an erroneous key which wasn’t related to the UTXO. I had to backup the key tied to the UTXO address using dumpprivkey and sign with it.”

前人表示:UTXO没有用正确的私钥签名。如果是这个原因,私钥和公钥不对应。这个问题最严重。
  • 错误的公钥。用公钥无法验证签名信息
  • 私钥正确但是加密过程出错。

3.原因排除及查找

对以上的原因进行逐一排除。流程如下:

3.1. 交易数据解码

采用第三方网页小工具进行对交易数据进行解码。可以进行解码。结果如下: 排除是交易数据组织结构的不对或不完整的原因。
一个新的bug解决途径——Bitcoin交易签名错误_第2张图片

3.2. 节点排除

将可以解码的交易数据,通过第三方的节点进行广播。
第三方节点报错和我们节点保持一样。
基本排除是节点的问题

3.3. 解码数据分析

对解码的交易数据进行分析。对比知道各项数据的含义。 同时对hash之后的原始交易数据进行分析。明白各个字段的数据结构和含义,并找到示例。
一个新的bug解决途径——Bitcoin交易签名错误_第3张图片
一个新的bug解决途径——Bitcoin交易签名错误_第4张图片

3.4. 正确的数据对比

在网上找了下正确的原始交易数据以及解码后的数据。和我们的进行对比分析。查找不同之处。

  • 错误的:

0100000001fe91dac523e181e83def2294fd15da3ba14377d23c618895b8a6604bd43117cb000000006b483045022100f9d4e16bce4a4d2899fa56f2e73ade8643facf9ba2d27fd8537788daafd0f654022022b63b31c294595c8215c95eb4400e4f21d95a75e57b2b473c0b99b040cf8594812102766226f3e6ed5efac9d397826e5bcc12089e75f2ce1a6941e2e0bf0d823f920cffffffff0210270000000000001976a914f7fc369a3964e26862443458b6696e8db4fdc3f588ac99070f00000000001976a914d68f2225a78e0639116a457dbafd230f2220920888ac00000000

  • 正确的:

01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000008a47304402204d78d2e6c0f801573e4960fb8e51ad939380d119d25f97d15efdedf815b05f02022066bd2ab0b401e32e7ce67ea45f8224097eeafbef2335d563776e5efe6632732d01410479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1ffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac00000000

对比之后发现在公钥部分采用的02开头的短公钥模式,而不是04开头的完整公钥模式。很有可能就是这个地方有问题。

3.5. 手动修改数据

发现可能的问题之后,对原始的交易数据进行手动修改。

  • 完整的公钥:将02改成04,补充上公钥y部分
  • 修改标示字符长度的数据。将21改成41,将整个签名部分的字段长度6b改成8b。

修改后如下:

0100000001db08cf5cf79beb81d763d428cda858f749df73fee98f0122770decc47743b1ed010000008a473044022005d283ef645139495d331a29cfc601939e8356d0cdb9a836f8af994e2436dd6802200a8b94e7147a9b72ea94e0a48254363eb4b53530ab185b4a9f1d1537927242d2814104766226f3e6ed5efac9d397826e5bcc12089e75f2ce1a6941e2e0bf0d823f920c91403a11553b15e4f911cc1aad8dfd3ec18c8bb52acf9703d9f3148017a71facffffffff0210270000000000001976a91469b4211f4a1fd4c51034dd79efe441f24637b61988acf2cc0e00000000001976a914d68f2225a78e0639116a457dbafd230f2220920888ac00000000

3.6. 解码及广播数据

将手动修改的交易数据进行解码,可以进行正确解码。

然后将交易数据进行广播。可以进行广播。说明问题就出在采用的公钥模式或编码在交易中的公钥不完整。在交易数据生成过程中采用私钥是正确的,签名过程也没有问题。

下一步就是对代码进行定位修改。

4.代码定位

  • 首先定位生成原始交易数据的代码。查找是否有问题。
  • 然后定位公钥拼接函数是否有问题。
  • 再查看拼接函数输入的公钥参数是否正确。
  • 最后发现代码中传参采用了压缩的公钥模式,而注释写的以及实际生成的是未压缩的公钥模式。

5.代码修改及解决验证

定位到了相应的函数代码之后,将采用压缩公钥的函数,修改成采用未压缩公钥,不修改公钥类型,正确编码完整的公钥。

修改后,生成一笔交易,并进行广播。

发现没有问题,多次验证后,没有问题。说明问题得到解决。

6.总结

解决途径还是着重于:问题分析——>可能原因——>原因排除——>原因确定——>定位代码——>修改验证

花费时间最多还是在原因排除和原因确定上。

如果对代码熟悉的话,可以很快的定位并修改。

在解决过程中还是需要一些小工具进行辅助。这样会事半功倍。


参考资料:
http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
https://blog.csdn.net/q4878802/article/details/49638457
https://blog.csdn.net/g2com/article/details/71513630
https://blog.csdn.net/taifei/article/details/73321293
https://blog.csdn.net/AMDS123/article/details/73478738
http://blog.sina.com.cn/s/blog_a93b83380102z732.html
https://www.8btc.com/article/54601
https://en.bitcoin.it/wiki/Script
https://curiosity-driven.org/bitcoin-contracts
https://blog.csdn.net/tuxedolinux/article/details/85218824
https://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
https://bitcoin.stackexchange.com/questions/36440/signing-a-raw-transaction-with-python-ecdsa-or-openssl?noredirect=1&lq=1

你可能感兴趣的:(Bitcoin)