专栏名称: 申龙斌的程序人生
分享可繁殖的知识与技能:GTD时间管理、读书心得、个人成长、财富自由之路
目录
相关文章推荐
OSC开源社区  ·  深度实测Manus,我依然认为这就是AI ... ·  2 天前  
程序员的那些事  ·  被骂了!腾讯道歉 + 立刻改正 ·  4 天前  
OSC开源社区  ·  Linux内核往事 ·  3 天前  
程序猿  ·  雷军提出建议!他本人也曾是“受害者” ·  6 天前  
51好读  ›  专栏  ›  申龙斌的程序人生

准确理解以3开头的比特币地址的含义

申龙斌的程序人生  · 公众号  · 程序员  · 2019-03-03 17:10

正文

比特币以前都是1开头的地址,后来出现了3开头的地址,最新的地址格式是bc1开头的。

17mKugcBDEJbu391Fq41AdwLeGHwJLPRDf

35DHm5kjYbvkUwGNc9KR1HywTn4caeWFwL

bc1qfgedw3874f3wkqtkwjm2fawuuwtldvdefh3prc


以1开头的地址是公钥经过Hash160之后的结果,接到BTC的一方使用私钥来解锁。


由于比特币里都是用脚本(Script)来实现锁定和解锁的逻辑,地址可以表示公钥的哈希,也可以表示为脚本的哈希,这就产生了以3开头的地址,准确的名字是 P2SH(Pay to Script Hash)地址


回顾一下以前介绍过的两种交易类型:

  • P2PK : Pay to Public Key 直接用公钥,不安全,占用空间大,早已弃用

  • P2PKH : Pay to Public Key Hash 用公钥的哈希,更安全,也节省空间,普遍采用



认真研究一笔交易的执行过程,可以更加准确地理解P2SH的概念,以这笔从3地址转账到1地址的交易为例:

https://nioctib.tech/#/transaction/7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45




下图中的解锁脚本用来使用3地址中的0.0099 BTC。

总共三个参数,第一个参数为0,一个令人费解的参数,也写作OP_0或OP_FALSE,后面再解释。

0   3045...9001   5141...51ae

追查0.0099BTC的来源,可以看到锁定脚本:

HASH160   e9c3...160a   EQUAL



debug脚本的验证过程:

前三步把几个操作数压栈,很简单。


取出栈顶端的 0x5141...51ae, 执行HASH160。


再压入一个数 0xe9c3...160a。


执行OP_EQUAL操作。顶端返回一个参数1,说明验证成功。



下面要解开一段脚本,继续验证的过程。

先把这串十六进制数

5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae

到这个网址解码:

http://chainquery.com/bitcoin-api/decodescript


解码得到的脚本是:

OP_1 042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf OP_1 OP_CHECKMULTISIG

0x51对应OP_1,也写作OP_TRUE,中间一串数字042f...6bdf。

最后的0xae是 OP_CHECKMULTISIG,表示多重签名检查。


这段脚本经过哈希之后,加上前缀05和校验码,生成的地址就是:

3P14159f73E4gFr7JterCCQh9QjiTjiZrG

可以用C#源代码验证上面的结论。

string scriptText = "5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae";
Script script = new Script(Encoders.Hex.DecodeData(scriptText));

Console.WriteLine(script.GetScriptAddress(Network.Main));

// 输出结果:3P14159f73E4gFr7JterCCQh9QjiTjiZrG


堆栈里还有两个数字,再追加上这组代码,准备继续执行。


压入OP_1, 0x042f...6bdf, OP_1,准备执行OP_CHECKMULTISIG。


这里变得非常难于理解,需要提前补一下多重签名的概念,对于一个M-N多重签名(M<=N),表示N个公钥中,只需要提供M个签名就可以花费这笔资金。以2-3多重签名为例(即M=2,N=3),3个公钥要提供2组签名,堆栈里应该有这样一些数。

    3
(公钥3)
(公钥2)
(公钥1)
2
(签名2)
(签名1)
0

堆栈最底部的0是一个Bitcoin Core早期实现时的一个BUG,程序员经常会犯的一个"差一BUG",英文为off-by-one。程序在解析script时要多取出一个数,所以就充填了一个OP_FALSE(0)。


比特币最多允许提供16个签名,因为内部只有OP_1, OP_2 ... OP_16,操作数对应着0x51, 0x52 ...  0x60。


现在就可以理解堆栈里的这一串数字的含义,这里利用多重签名的语法来表示一个单一签名,即 1-1 多重签名。

OP_1

0x042f...6bdf 公钥1

OP_1

0x3045...9001 签名1

OP_0


当签名和公钥匹配时,脚本执行结果返回1,表示整个交易通过了有效性验证。


要想了解脚本和签名的生成过程,需要继续学习构建P2SH交易的过程。


参考阅读:







请到「今天看啥」查看全文