Bitcoin Core脚本验证引擎:区块链虚拟机执行环境的实现
概述
Bitcoin Core的脚本验证引擎是区块链网络的核心组件,负责执行区块链脚本(Blockchain Script)并验证交易的有效性。这个基于堆栈的虚拟机(Stack-based Virtual Machine)实现了区块链的智能合约系统,确保所有网络参与者对交易有效性达成共识。
脚本验证引擎架构
核心组件
执行环境关键参数
| 参数 | 限制值 | 描述 |
|---|---|---|
| MAX_SCRIPT_SIZE | 10,000 字节 | 单个脚本最大长度 |
| MAX_SCRIPT_ELEMENT_SIZE | 520 字节 | 栈元素最大大小 |
| MAX_OPS_PER_SCRIPT | 201 次 | 非push操作最大次数 |
| MAX_STACK_SIZE | 1000 个 | 执行栈最大深度 |
| MAX_PUBKEYS_PER_MULTISIG | 20 个 | 多签公钥最大数量 |
脚本执行流程
执行状态机
核心执行函数
bool EvalScript(std::vector<std::vector<unsigned char>>& stack,
const CScript& script,
unsigned int flags,
const BaseSignatureChecker& checker,
SigVersion sigversion,
ScriptExecutionData& execdata,
ScriptError* serror)
{
// 初始化执行环境
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
ConditionStack vfExec;
std::vector<valtype> altstack;
// 主执行循环
while (pc < pend) {
opcodetype opcode;
valtype vchPushValue;
// 读取指令
if (!script.GetOp(pc, opcode, vchPushValue))
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
// 执行操作码
switch (opcode) {
// 各种操作码处理逻辑
case OP_CHECKSIG:
// 签名验证逻辑
break;
case OP_CHECKMULTISIG:
// 多签验证逻辑
break;
// ... 其他操作码
}
}
// 最终状态验证
if (stack.size() != 1) return false;
return CastToBool(stacktop(-1));
}
签名验证机制
签名版本支持
Bitcoin Core支持多种签名版本,适应不同的交易类型:
| 签名版本 | 描述 | 对应BIP |
|---|---|---|
| SigVersion::BASE | 基础脚本和P2SH | BIP16 |
| SigVersion::WITNESS_V0 | 隔离见证v0 | BIP141 |
| SigVersion::TAPROOT | Taproot密钥路径 | BIP341 |
| SigVersion::TAPSCRIPT | Taproot脚本路径 | BIP342 |
签名检查流程
脚本操作码分类
堆栈操作指令
// 堆栈操作示例
OP_DUP, // 复制栈顶元素
OP_DROP, // 删除栈顶元素
OP_SWAP, // 交换栈顶两个元素
OP_2DUP, // 复制栈顶两个元素
OP_2DROP, // 删除栈顶两个元素
OP_2OVER, // 复制栈顶第二对元素
OP_2ROT, // 旋转栈顶六个元素
算术运算指令
// 算术运算(部分已禁用)
OP_ADD, // 加法
OP_SUB, // 减法
OP_1ADD, // 加1
OP_1SUB, // 减1
OP_NEGATE, // 取反
OP_ABS, // 取绝对值
密码学指令
// 哈希函数
OP_RIPEMD160, // RIPEMD-160哈希
OP_SHA1, // SHA-1哈希
OP_SHA256, // SHA-256哈希
OP_HASH160, // RIPEMD160(SHA256(x))
OP_HASH256, // SHA256(SHA256(x))
// 签名验证
OP_CHECKSIG, // 单签名验证
OP_CHECKSIGVERIFY, // 验证并终止
OP_CHECKMULTISIG, // 多签名验证
OP_CHECKMULTISIGVERIFY,// 多签验证并终止
OP_CHECKSIGADD // Tapscript签名添加
验证标志系统
主要验证标志
Bitcoin Core使用32位标志系统来控制脚本验证行为:
| 标志 | 值 | 描述 |
|---|---|---|
| SCRIPT_VERIFY_P2SH | 1<<0 | 启用P2SH脚本验证 |
| SCRIPT_VERIFY_STRICTENC | 1<<1 | 严格编码验证 |
| SCRIPT_VERIFY_DERSIG | 1<<2 | 严格DER签名验证 |
| SCRIPT_VERIFY_LOW_S | 1<<3 | 低S值签名验证 |
| SCRIPT_VERIFY_NULLDUMMY | 1<<4 | 空哑元验证 |
| SCRIPT_VERIFY_SIGPUSHONLY | 1<<5 | 仅push操作验证 |
| SCRIPT_VERIFY_MINIMALDATA | 1<<6 | 最小数据编码验证 |
| SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | 1<<7 | 阻止可升级NOP |
| SCRIPT_VERIFY_CLEANSTACK | 1<<8 | 清洁堆栈验证 |
| SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | 1<<9 | 时间锁验证 |
| SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | 1<<10 | 序列锁验证 |
| SCRIPT_VERIFY_WITNESS | 1<<11 | 隔离见证支持 |
| SCRIPT_VERIFY_TAPROOT | 1<<17 | Taproot支持 |
高级特性实现
Tapscript执行环境
Tapscript引入了新的执行规则和限制:
// Tapscript特定验证规则
static bool EvalChecksigTapscript(const valtype& sig,
const valtype& pubkey,
ScriptExecutionData& execdata,
unsigned int flags,
const BaseSignatureChecker& checker,
SigVersion sigversion,
ScriptError* serror,
bool& success)
{
// 验证权重限制
execdata.m_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED;
if (execdata.m_validation_weight_left < 0) {
return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT);
}
// Schnorr签名验证
if (pubkey.size() == 32) {
if (success && !checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror)) {
return false;
}
}
return true;
}
条件执行系统
Bitcoin Script使用条件栈来实现复杂的条件逻辑:
class ConditionStack {
private:
uint32_t m_stack_size = 0;
uint32_t m_first_false_pos = NO_FALSE;
public:
void push_back(bool f) {
if (m_first_false_pos == NO_FALSE && !f) {
m_first_false_pos = m_stack_size;
}
++m_stack_size;
}
void pop_back() {
--m_stack_size;
if (m_first_false_pos == m_stack_size) {
m_first_false_pos = NO_FALSE;
}
}
void toggle_top() {
if (m_first_false_pos == NO_FALSE) {
m_first_false_pos = m_stack_size - 1;
} else if (m_first_false_pos == m_stack_size - 1) {
m_first_false_pos = NO_FALSE;
}
}
};
性能优化与安全考虑
预计算数据缓存
struct PrecomputedTransactionData {
// BIP341 Taproot预计算数据
uint256 m_prevouts_single_hash;
uint256 m_sequences_single_hash;
uint256 m_outputs_single_hash;
// BIP143 SegWit预计算数据
uint256 hashPrevouts, hashSequence, hashOutputs;
// 花费输出数据
std::vector<CTxOut> m_spent_outputs;
};
安全限制机制
| 安全机制 | 实现方式 | 防护目标 |
|---|---|---|
| 操作次数限制 | MAX_OPS_PER_SCRIPT | 防止无限循环 |
| 堆栈深度限制 | MAX_STACK_SIZE | 防止堆栈溢出 |
| 脚本大小限制 | MAX_SCRIPT_SIZE | 防止资源耗尽 |
| 禁用危险操作码 | OP_CAT, OP_SUBSTR等 | 防止脚本漏洞 |
实际应用示例
标准P2PKH脚本验证
// P2PKH脚本执行示例
CScript scriptSig = CScript() << sig << pubkey;
CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160
<< ToByteVector(pubkeyHash)
<< OP_EQUALVERIFY << OP_CHECKSIG;
// 执行验证
std::vector<std::vector<unsigned char>> stack;
bool success = EvalScript(stack, scriptSig + scriptPubKey,
flags, checker, SigVersion::BASE, execdata, &error);
多签脚本执行
// 2-of-3多签示例
CScript scriptPubKey = CScript() << OP_2
<< pubkey1 << pubkey2 << pubkey3
<< OP_3 << OP_CHECKMULTISIG;
// 相应的scriptSig需要提供签名和哑元
CScript scriptSig = CScript() << OP_0 << sig1 << sig2;
总结
Bitcoin Core的脚本验证引擎是一个高度优化、安全可靠的区块链虚拟机实现。它通过:
- 严格的执行限制:防止资源耗尽和恶意脚本
- 多版本签名支持:兼容传统脚本和现代Taproot
- 模块化设计:清晰的接口分离和职责划分
- 共识安全性:确保所有节点执行结果一致
这个引擎不仅是区块链网络共识的基础,也为开发者提供了构建复杂智能合约的能力,同时保持了系统的安全性和稳定性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



