主页 > imtoken钱包分享链接在哪里 > 比特币源码分析三:交易脚本

比特币源码分析三:交易脚本

比特币源码分析三:交易脚本

本文假设读者理解两个基本概念

1、哈希算法,比特币使用的是sha-256,不明白的google一下

2、非对称加密算法比特币怎么算出来的,比特币使用椭圆曲线加密算法,后面会被ecc代替

这两个概念不需要了解详细的数学实现,只要了解大致的工作原理,相信码农应该具备这个基本功

地址

如果你用过比特币,你可能有一个类似以下格式的地址

1QAc9S5EmycqjzzWDc1yiWzr9jJLC8sLiY

如果有人要转账给你,你必须提供这样的地址,那么这个地址是什么?

如果想看看这个地址是怎么生成的,可以尝试自己调试

1、gdb 比特币

比特币怎么算出来的

set arg -regtest(注意这里不需要-daemon,因为添加这个参数会fork一个不受gdb控制的新进程)

b 获取新地址

r

2、 启动一个新的shell并输入bitcoin-cli -regtest getnewaddress

此时断点到达getnewaddress函数,栈如下

3、继续跟进就是具体的地址生成过程

关键流程(功能)如下

1、CKey::MakeNewKey (key.cpp),其中CKey代表ecc算法的私钥

这个功能非常简单。调用GetStrongRandBytes会生成一个大小为32字节的随机数(校验功能是验证随机数是否符合私钥的格式)。fCompressedIn 表示是否压缩。这涉及到一个 ecc 的公钥地址的梗。不注意

2、CKey::GetPubKey (key.cpp) 生成公钥并返回CPubKey(表示ecc公钥的类)

比特币怎么算出来的

这个功能也比较简单。它使用生成的私钥(32 字节的密钥数据)来生成相应的公钥。公钥长度为65字节(如果不压缩,fCompressedIn为假)

总结一下:

使用随机数生成私钥,然后使用私钥生成公钥。好奇的读者可能会问,私钥是随机数吗?对应的公钥不怕跟别人重复吗?完全不用担心这个。首先,这个随机数是指机器上的硬件信息。其次,据说生成的数字是32字节大小的随机数。如果和别人重复,你相当于一年365天。彩票。

生成公钥后,会将公钥处理成大家都能看到的字符串地址。它可能会经过以下步骤

1、先对公钥做一个hash160(内部实现是为公钥sha256构造一个CKeyID对象,然后是ripemd160)

这个keyid比较重要,后面介绍脚本的时候会介绍。

2、keyid 数据前加一个字节的前缀。此前缀因网络而异。

a) 主网是 0x00

b) 测试网是 0x6f

c) Regnet 也是 0x6f

比特币怎么算出来的

3、 对ver+keyid执行两次sha256,取散列结果的前四个字节作为校验和(checksum)

4、 最后对ver+keyid+校验和进行base58(base64算法的修改版,去掉了一些不常见的字符)

3、4 两步代码如下(base58.cpp)

交易脚本

正如关于交易的文章中提到的,交易脚本实际上由两部分组成

1、输入脚本(锁定)

2、输出脚本(键)

不清楚这个概念的可以参考《比特币源码分析交易》

为了便于理解,笔者先从最简单的脚本开始讲解

输入脚本:

比特币怎么算出来的

输出脚本:OP_DUP OP_HASH160

OP_EQUALVERIFY OP_CHECKSIG

先解释一下上面的脚本指令

OP_DUP复制指令,将虚拟机栈顶的数据复制到栈顶

OP_HASH160 hash160指令,计算keyid的hash160是一种算法

OP_EQUALVERIFY比较指令,比较栈顶的两个数据是否相等,如果不相等,则执行失败

OP_CHECKSIG 是一个签名验证指令。堆栈顶部的前两个元素是 pubkey,第二个是签名。这个指令比较复杂。简而言之,它通过公钥和签名来验证交易数据,后面会详细介绍。

除了指令之外,还有一些关键数据的内部表示

sig,对于交易数据,由私钥计算得到的签名,签名验证是用公钥对交易数据进行运算,然后与签名核对,如果一致,说明验证通过通过

Pubkey,上面提到的私钥生成的65字节数据(压缩后为33字节)

比特币怎么算出来的

PubKeyHash,对应上面的keyid比特币怎么算出来的,是对pubkey进行hash160计算的结果

虚拟机是通过栈来执行的,有数据结构基础的人可以理解,栈是一种先进先出的数据结构。虚拟机执行时,会先执行输入脚本,再执行输出脚本。如果有错误,验证将失败。

1、先推送sig

2、再次推送 pubkey

3、复制栈顶的公钥

4、做hash160操作

5、推送 PubKeyHash

6、 比较栈顶两个数据是否相等,不等校验失败

7、 取栈顶的pubkey和sig,验证签名,如果签名验证失败,脚本验证失败

这里我们需要结合上一篇文章来看看。虽然先执行输入脚本,但输出脚本按出现的顺序先出现,即先出钱的交易(先出锁),再出出钱的交易(即键)刚出来。这里很容易混淆

虚拟机执行interpreter.cpp的EvalScript函数中的主要逻辑,调用是通过VerifyScript