栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

比特币源码分析 脚本(二)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

比特币源码分析 脚本(二)

代码分析

在script.h中,存放着类Cscript的成员函数,其中最关键的是函数GetOp

bool GetOp(const_iterator& pc, opcodetype& opcodeRet, vector& vchRet) const

GetOp的参数包括程序计数器PC、操作码OPCode及立即数返回值。该函数的作用是从脚本PC处读出操作码,调整PC指向下一个操作码;若当前读取的操作码为立即数操作码,则也一并读出立即数。

在script.cpp中,存放着与脚本密切相关的函数,其中最基础、最关键的是函数evalscript

bool evalscript(const Cscript& script, const CTransaction& txTo, unsigned int nIn, int nHashType,
                vector >* pvStackRet)

evalscript的参数包括待执行的程序(待执行的脚本),运行的环境(待填充的交易,交易输入的索引等)以及运行的结果

evalscript主要局部变量及解析如下:

Cscript::const_iterator pc = script.begin();				//程序计数器,用于指向下一个执行的指令
Cscript::const_iterator pend = script.end();				//用于判断程序结束
Cscript::const_iterator pbegincodehash = script.begin();	//与操作码OP_CODESEPARATOR一起用于辅助定位待签名脚本
vector vfExec;										//条件判断结果
vector stack;										//主运行栈,用于运行时存放中间数值
vector altstack;									//次栈,未找到具体用法

evalscript主要逻辑是从待执行脚本中取出操作码并执行,直至取完、执行过程中遇到OP_RETURN、执行过程中VERIFY类验证失败、执行过程中遇到错误(例如操作数不足等)才会结束执行。
各类操作码大致行为如下表:

类型操作
立即数往主栈压入立即数
流程控制对操作数进行条件判断;根据条件判断结果控制指令解析执行;对条件判断结果进行操作
栈操作对栈顶某些元素进行复制、反转、交换等操作
切片运算对栈顶某些元素进行拼接、位移等操作
位运算对栈顶某些元素进行位运算
数值运算对栈顶某些元素进行数值运算
加密运算对栈顶某些元素进行计算哈希值、验签等密码学运算
边界符
模板
非法字节码

其中,边界符、模板、非法字节码三类操作码并无实际的执行代码(即这三类操作码在输入到脚本执行前已被预处理)。

所有指令中,较难理解的是OP_CHECKSIGVERIFY(OP_CHECKMULTISIGVERIFY可看作升级版OP_CHECKSIGVERIFY)

case OP_CHECKSIGVERIFY:
{
    // (sig pubkey -- bool)
    // OP_CHECKSIGVERIFY输入参数为sig及pubkey,输出结果bool
    if (stack.size() < 2)
        return false;

    valtype& vchSig    = stacktop(-2);
    valtype& vchPubKey = stacktop(-1);

    // debug print
    //PrintHex(vchSig.begin(), vchSig.end(), "sig: %sn");
    //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %sn");

    // Subset of script starting at the most recent codeseparator
    // 从最近的分隔符OP_CODESEPARATOR一直到结束的脚本需要进行验签
    Cscript scriptCode(pbegincodehash, pend);

    // Drop the signature, since there's no way for a signature to sign itself
    // 去掉签名
    scriptCode.FindAndDelete(Cscript(vchSig));

	// 跟进 CheckSig -> SignatureHash,最终在SignatureHash中,将scriptCode填充到txTo的vin[nIn]中的scriptSig,
	// 序列化后在进行计算哈希值,并对该哈希值进行验签
    bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);

    stack.pop_back();
    stack.pop_back();
    stack.push_back(fSuccess ? vchTrue : vchFalse);
    if (opcode == OP_CHECKSIGVERIFY)
    {
        if (fSuccess)
            stack.pop_back();
        else
        	// 验签失败直接返回
            pc = pend;
    }
}
break;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/304325.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号