主页 > 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