本来打算接着写交易签名的,研究半天发现不搞清楚脚本,就没办法讲签名。那还是先讲脚本吧。
比特币脚本的详细介绍和运作原理,建议去读廖雪峰大神的深入理解比特币交易的脚本文章 。本文的重点还是从源码中挖金子。
先贴一张最典型的支付脚本执行过程示意图,镇个场子:上图中那些以OP打头的,都是比特币脚本中的操作码。它们定义在src/script/script.h文件中,其类型是unsigned char,也就是说,操作码最多不会超过256个。从enum opcodetype定义看,包括压栈数据22个、流程控制10个、堆栈处理20个、字符串处理5个、位操作8个、算术逻辑操作27个、加密操作10个、扩展备用10个,一共是112个。具体清单这里不列了,后面在源码中会逐一解析。
与脚本相关的数据类型主要有4个,按照定义顺序分别是:CScriptNum、CScriptBase、CScript、CScriptWitness。
CScriptNum主要用于处理脚本中的数字,并且可以对运算结果提供溢出保护,只要不再参与后续运算操作就行。
CScriptBase是这样定义的:
typedef prevector<28, unsigned char> CScriptBase;
这里使用了一个prevector类,它定义于src/prevector.h,是C++标准库vector的变种,允许预分配向量空间。CScriptBase就是预分配了28个unsigned char,用来存储脚本。据比特币研发团队2015年10月所做的测试,它可以把dbcache内存使用减少23%、初始同步速度提高13%。个人猜测这个28应该是测试中发现的最优配置。
CScript类继承于CScriptBase,它用来存储脚本,并提供了脚本内容的常用操作,比如添加、序列化、数字加/解码等等操作函数。
CScriptWitness主要用于隔离见证,用来存储被隔离的见证脚本。它内部使用的数据结构是:
std::vector > stack;
OK,下面我们来逐一看看脚本操作码。先看GetScriptOp函数,它用于取出下一个操作码,包括相关的操作数据。函数定义于src/script.cpp中:
bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end,
opcodetype& opcodeRet, std::vector* pvchRet)
{
opcodeRet = OP_INVALIDOPCODE;
if (pvchRet)
pvchRet->clear();
if (pc >= end)
return false;
if (end - pc < 1)
return false;
unsigned int opcode = *pc++; //取出操作码
//操作码定义中,0是OP_0/OP_FALSE,1-75都没有定义,
//76、77、78分别是OP_PUSHDATA1、OP_PUSHDATA2、OP_PUSHDATA4
if (opcode <= OP_PUSHDATA4)
{
unsigned int nSize = 0;
if (opcode < OP_PUSHDATA1)
{ //直接将操作数压栈
nSize = opcode;
}
else if (opcode == OP_PUSHDATA1)
{ //下一个字节代表要被压入堆栈的数据长度
if (end - pc < 1)
return false;
nSize = *pc++;
}
else if (opcode == OP_PUSHDATA2)
{ //下两个字节代表要被压入堆栈的数据长度
if (end - pc < 2)
return false;
nSize = ReadLE16(&pc[0]);
pc += 2;
}
else if (opcode == OP_PUSHDATA4)
{ //下四个字节代表要被压入堆栈的数据长度
if (end - pc < 4)
return false;
nSize = ReadLE32(&pc[0]);
pc += 4;
}
if (end - pc < 0 || (unsigned int)(end - pc) < nSize)
return false;
if (pvchRet) //取出需要被压栈的数据内容
pvchRet->assign(pc, pc + nSize);
pc += nSize;
}
//返回操作码
opcodeRet = static_cast(opcode);
return true;
}
对脚本的详细处理是在EvalScript函数中,它定义于src/script/interpreter.cpp中,函数非常长,但是逻辑并不复杂,就是针对不同的操作码进行不同的处理操作(为了简化,去掉了部分数据检查):
bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags,
const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
static const valtype vchFalse(0);
static const valtype vchTrue(1, 1);
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
CScript::const_iterator pbegincodehash = script.begin();
opcodetype opcode;
valtype vchPushValue;
std::vector vfExec;
std::vector altstack;
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
int nOpCount = 0;
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
try
{
while (pc < pend) //只要脚本没处理完,继续循环
{
bool fExec = !count(vfExec.begin(), vfExec.end(), false);
//读取操作码
if (!script.GetOp(pc, opcode, vchPushValue))
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
//单个脚本里操作码总数不超过201个。注意OP_RESERVED不计算
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
//这里是已经禁用的操作码,主要是字符串、位、算术逻辑运算符
if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT ||
opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_AND ||
opcode == OP_OR || opcode == OP_XOR || opcode == OP_2MUL ||
opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV ||
opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT)
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
//不是隔离见证的脚本不允许出现OP_CODESEPARATOR
if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR);
//检查压栈操作码与操作数是否对应
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
return set_error(serror, SCRIPT_ERR_MINIMALDATA);
}
stack.push_back(vchPushValue);
} else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode)
{
//1到16,或者-1,直接将数字压栈
case OP_1NEGATE:
case OP_1: case OP_2: case OP_3: case OP_4:
case OP_5: case OP_6: case OP_7: case OP_8:
case OP_9: case OP_10: case OP_11: case OP_12:
case OP_13: case OP_14: case OP_15: case OP_16:
{
CScriptNum bn((int)opcode - (int)(OP_1 - 1));
stack.push_back(bn.getvch());
break;
}
//流程控制码开始,首先是无操作
case OP_NOP:
break;
case OP_CHECKLOCKTIMEVERIFY: //锁定点检查
{
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
break; //不需要检查,直接跳过(NOP2)
}
//允许5个字节。正常操作数是4个,但运算之后可能溢出
//而且nLockTime也会超出4字节。5字节就肯定够用了
const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);
//返回检查结果
if (!checker.CheckLockTime(nLockTime))
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
break;
}
case OP_CHECKSEQUENCEVERIFY: //序列号检查
{
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
break; //不检查,直接跳过(NOP3)
}
const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5);
//允许Disable,便于未来软分叉延展性
if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)
break;
//返回检查结果
if (!checker.CheckSequence(nSequence))
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
break;
}
//无操作,注意 NOP2、NOP3就是上面的两个检查(数值相等)
case OP_NOP1: case OP_NOP4: case OP_NOP5: case OP_NOP6:
case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
{ //软分叉安全设置
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
break;
}
case OP_IF: //栈顶元素不为0则语句执行
case OP_NOTIF: //栈顶元素为0则语句执行
{
bool fValue = false;
if (fExec)
{
valtype& vch = stacktop(-1);
fValue = CastToBool(vch);
if (opcode == OP_NOTIF)
fValue = !fValue;
popstack(stack); //删除栈顶元素
}
vfExec.push_back(fValue);
break;
}
case OP_ELSE: //上面IF、NOTIF的另一分支
vfExec.back() = !vfExec.back();
break;
case OP_ENDIF: //结束IF、NOTIF语句
vfExec.pop_back();
break;
case OP_VERIFY: //验证栈顶元素
{
bool fValue = CastToBool(stacktop(-1));
if (fValue) //为真,OK
popstack(stack);
else
return set_error(serror, SCRIPT_ERR_VERIFY);
break;
}
case OP_RETURN: //直接无效
return set_error(serror, SCRIPT_ERR_OP_RETURN);
break;
//下面是堆栈处理
case OP_TOALTSTACK: //栈顶元素压入辅栈,并从主栈删除
altstack.push_back(stacktop(-1));
popstack(stack);
break;
case OP_FROMALTSTACK: //辅栈顶元素压入主栈,并从辅栈删除
stack.push_back(altstacktop(-1));
popstack(altstack);
break;
case OP_2DROP: //删除栈顶两个元素
popstack(stack);
popstack(stack);
break;
case OP_2DUP: //复制栈顶两个元素
{
valtype vch1 = stacktop(-2);
valtype vch2 = stacktop(-1);
stack.push_back(vch1);
stack.push_back(vch2);
break;
}
case OP_3DUP: //复制栈顶三个元素
{
valtype vch1 = stacktop(-3);
valtype vch2 = stacktop(-2);
valtype vch3 = stacktop(-1);
stack.push_back(vch1);
stack.push_back(vch2);
stack.push_back(vch3);
break;
}
case OP_2OVER: //栈底两个元素复制到栈顶 (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
{
valtype vch1 = stacktop(-4);
valtype vch2 = stacktop(-3);
stack.push_back(vch1);
stack.push_back(vch2);
break;
}
case OP_2ROT: //第5、6个元素移动到栈顶 (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
{
valtype vch1 = stacktop(-6);
valtype vch2 = stacktop(-5);
stack.erase(stack.end()-6, stack.end()-4);
stack.push_back(vch1);
stack.push_back(vch2);
break;
}
case OP_2SWAP: //交换栈顶两对元素 (x1 x2 x3 x4 -- x3 x4 x1 x2)
swap(stacktop(-4), stacktop(-2));
swap(stacktop(-3), stacktop(-1));
break;
case OP_IFDUP: //如果栈顶元素非0,复制之
{
valtype vch = stacktop(-1);
if (CastToBool(vch))
stack.push_back(vch);
break;
}
case OP_DEPTH: //堆栈元素个数压栈
{
CScriptNum bn(stack.size());
stack.push_back(bn.getvch());
break;
}
case OP_DROP: //删除栈顶元素
popstack(stack);
break;
case OP_DUP: //复制栈顶元素
{
valtype vch = stacktop(-1);
stack.push_back(vch);
break;
}
case OP_NIP: //删除栈顶下一个元素
stack.erase(stack.end() - 2);
break;
case OP_OVER: //复制栈顶下一个元素到栈顶 (x1 x2 -- x1 x2 x1)
{
valtype vch = stacktop(-2);
stack.push_back(vch);
break;
}
case OP_PICK: //第n个元素复制到栈顶 (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
case OP_ROLL: //第n个元素移动到栈顶 (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
{
int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); //先取n值
popstack(stack);
valtype vch = stacktop(-n-1);
if (opcode == OP_ROLL)
stack.erase(stack.end()-n-1);
stack.push_back(vch);
break;
}
case OP_ROT: //栈顶3个元素向左翻转 (x1 x2 x3 -- x2 x3 x1)
swap(stacktop(-3), stacktop(-2));
swap(stacktop(-2), stacktop(-1));
break;
case OP_SWAP: //交换栈顶两个元素
swap(stacktop(-2), stacktop(-1));
case OP_TUCK: //栈顶元素复制并插入到下个元素之前 (x1 x2 -- x2 x1 x2)
{
valtype vch = stacktop(-1);
stack.insert(stack.end()-2, vch);
break;
}
case OP_SIZE: //栈顶元素的大小压栈
{
CScriptNum bn(stacktop(-1).size());
stack.push_back(bn.getvch());
break;
}
//下面是位操作
case OP_EQUAL: //栈顶两个数相等,结果压栈
case OP_EQUALVERIFY: //栈顶两个数相等,对结果再做验证
{
valtype& vch1 = stacktop(-2);
valtype& vch2 = stacktop(-1);
bool fEqual = (vch1 == vch2);
popstack(stack);
popstack(stack);
stack.push_back(fEqual ? vchTrue : vchFalse);
if (opcode == OP_EQUALVERIFY)
{
if (fEqual)
popstack(stack);
else
return set_error(serror, SCRIPT_ERR_EQUALVERIFY);
}
break;
}
//下面是算术操作
case OP_1ADD: case OP_1SUB: //栈顶元素+1、-1
case OP_NEGATE: case OP_ABS: //栈顶元素取反、取正
case OP_NOT: case OP_0NOTEQUAL: //栈顶元素为零、不为零
{
CScriptNum bn(stacktop(-1), fRequireMinimal);
switch (opcode)
{
case OP_1ADD: bn += bnOne; break;
case OP_1SUB: bn -= bnOne; break;
case OP_NEGATE: bn = -bn; break;
case OP_ABS: if (bn < bnZero) bn = -bn; break;
case OP_NOT: bn = (bn == bnZero); break;
case OP_0NOTEQUAL: bn = (bn != bnZero); break;
default: assert(!"invalid opcode"); break;
}
popstack(stack);
stack.push_back(bn.getvch());
}
break;
case OP_ADD: case OP_SUB: case OP_BOOLAND: case OP_BOOLOR:
case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL:
case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL:
case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX:
{ //程序猿都懂,不注释了
CScriptNum bn1(stacktop(-2), fRequireMinimal);
CScriptNum bn2(stacktop(-1), fRequireMinimal);
CScriptNum bn(0);
switch (opcode)
{
case OP_ADD: bn = bn1 + bn2; break;
case OP_SUB: bn = bn1 - bn2; break;
case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;
case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break;
case OP_NUMEQUAL: bn = (bn1 == bn2); break;
case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break;
case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break;
case OP_LESSTHAN: bn = (bn1 < bn2); break;
case OP_GREATERTHAN: bn = (bn1 > bn2); break;
case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;
case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
default: assert(!"invalid opcode"); break;
}
popstack(stack);
popstack(stack);
stack.push_back(bn.getvch());
if (opcode == OP_NUMEQUALVERIFY)
{
if (CastToBool(stacktop(-1)))
popstack(stack);
else
return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY);
}
break;
}
case OP_WITHIN: //栈顶最大,其次最小,再次介于两者之间
{
CScriptNum bn1(stacktop(-3), fRequireMinimal);
CScriptNum bn2(stacktop(-2), fRequireMinimal);
CScriptNum bn3(stacktop(-1), fRequireMinimal);
bool fValue = (bn2 <= bn1 && bn1 < bn3);
popstack(stack);
popstack(stack);
popstack(stack);
stack.push_back(fValue ? vchTrue : vchFalse);
break;
}
//下面是加密操作
case OP_RIPEMD160: case OP_SHA1: case OP_SHA256:
case OP_HASH160: case OP_HASH256:
{
valtype& vch = stacktop(-1);
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
if (opcode == OP_RIPEMD160)
CRIPEMD160().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_SHA1)
CSHA1().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_SHA256)
CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_HASH160)
CHash160().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_HASH256)
CHash256().Write(vch.data(), vch.size()).Finalize(vchHash.data());
popstack(stack);
stack.push_back(vchHash);
break;
}
case OP_CODESEPARATOR:
pbegincodehash = pc; //哈希值只从这里开始计算
break;
case OP_CHECKSIG: //检查签名
case OP_CHECKSIGVERIFY: //检查签名并验证
{
//省略,后续文章再详细解析
break;
}
case OP_CHECKMULTISIG: //检查多重签名
case OP_CHECKMULTISIGVERIFY: //检查并验证
{
//省略,后续文章再详细解析
break;
}
default:
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
}
}
catch (...)
{
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
}
return set_success(serror);
}
最后的签名验证部分的代码,暂时省略了,留到后面专题再详细解析。
欢迎转载,请注明出处。