比特币指令集
本文主要译自比特币 wiki
约定
- 数字是小端编码,也就是遵循英特尔处理器的规则
- 整数的编码规则是最高位表示付好,对于一个字节的整数,0x81表示-1,0x80表示负0,0x03 表示3,0x83表示-3
- 0表示 False, 其他表示 True
常数指令
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_0 | 0 | 0X00 | nothing | nothing | 在站上放置一个空数组 |
N/A | 1-75 | 0x01-0x4b | special | data | 指令支出后面有多少字节数据需要放置到栈上,比如03 01 02 03,03意味着后面有三个字节的数据01 02 03 需要放置到栈上,01 02 03就是执行后的栈顶数据 |
OP_PUSHDATA1 | 76 | 0x4c | special | 数据 | 输入输出长度均不固定,0x4c 后面的第一个字节表示后面数据的长度比如以下指令 0x4c020102,执行完以后,栈顶为01 02 |
OP_PUSHDATA2 | 77 | 0x4d | special | 数据 | 输入输出长度均不固定,0x4d 后面的两个字节表示后面数据的长度比如以下指令 0x4d00010001....ff,执行完以后,栈顶为0001....feff, 栈顶有256字节的数据,这些数据分别是00...ff |
OP_PUSHDATA4 | 78 | 0x4e | special | 数据 | 输入输出长度均不固定,0x4e 后面的四个字节表示后面数据的长度比如以下指令 0x4e000000010001....ff,其中4e 后面的00000001表示长度为2^24字节, 目前应该用不到,因为这远超出了一块的大小,是不允许的 |
OP_1NEGATIVE | 79 | 0X4F | 空 | -1 | 将数值-1放在栈顶,比特币的虚拟机是多少位的? |
OP_1,OP_TRUE | 81 | 0x51 | 空 | 1 | 将数值1放在栈顶 |
OP_2-OP_16 | 82-96 | 0X52-0X60 | 空 | 2-16 | 将数值2-16放置在栈顶 |
流程控制
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_NOP | 97 | 0x61 | 空 | 空 | 就是一般的 nop 指令 |
OP_IF | 99 | 0X63 | True/false | <expression> if [statements] [else [statements1]] endif | 移除栈顶,如果为真, statements 将会被执行 |
OP_NOTIF | 100 | 0X64 | True/false | <expression> notif [statements] [else [statements1]] endif | 移除栈顶,如果为假, statements 将会被执行 |
OP_ELSE | 103 | 0X67 | True/false | <expression> notif [statements] [else [statements1]] endif | 移除栈顶,如果为假, statements1 将会被执行 |
OP_ENDIF | 104 | 0X68 | True/false | <expression> notif [statements] [else [statements1]] endif | 主要用来标记if语句的结束 |
OP_verify | 105 | 0X69 | True/false空 | 移除栈顶,如果为假,交易直接标记为失败,为真,继续执行指令. | |
OP_RETURN | 106 | 0x6a | 空 | 交易失败 | 虚拟机执行到此,标记交易失败.因此如果一个交易的输出有 OP_RETURN, 那么意味着这是一个永远有效的 UTXO,谁也无法花费. 可以将此 UTXO value设置为0,用来记录一些特殊数据 |
OP_IF OP_ELSE示例
假设初始栈,自顶向下
graph TD
A[栈底部<br/>ff<br/>fe<br/>fd<br/>]
指令如下:
OP_1 OP_IF OP_2 OP_3 OP_ELSE OP_4 OP_5 OP_ENDIF
我们一步一步来看一下栈和指令的变化
1. OP_1
栈:
graph TD
A[栈底部<br/>ff<br/>fe<br/>fd<br/>1]
指令:
OP_IF OP_2 OP_3 OP_ELSE OP_4 OP_5 OP_ENDIF
2. OP_IF
栈:
graph TD
A[栈底部<br/>ff<br/>fe<br/>fd]
指令:
OP_2 OP_3 OP_ELSE OP_4 OP_5 OP_ENDIF
因为条件为真,因此执行 OP_2 OP_3这两条语句,不执行 OP_4 OP_5.
3. OP_2 OP_3
栈:
graph TD
A[栈底部<br/>ff<br/>fe<br/>fd<br/>2<br/>3]
指令:
OP_ELSE OP_4 OP_5 OP_ENDIF
4. OP_2 OP_3
栈:
graph TD
A[栈底部<br/>ff<br/>fe<br/>fd<br/>2<br/>3]
指令:
空
因为执行了 OP_IF else 模块不执行.
栈相关指令
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_TOALTSTACK | 107 | 0x6b | x1 | (alt)x1 | 移动主栈栈顶数据到附加栈, 完全不清楚为什么比特币执行会有两个栈,在什么地方用呢 |
OP_FROMALTSTACK | 108 | 0x6c | (alt)x1 | x1 | 移动附加栈栈顶数据到主栈 |
OP_IFDUP | 115 | 0x73 | x | x/xx | 如果 x 非0,栈上会有两份 x, 否则 什么都不做(栈不变化) |
OP_DEPTH | 116 | 0x74 | 空 | 栈高度 | 将栈上有多少数据信息放到栈顶 |
OP_DROP | 117 | 0x75 | x | 空 | 丢弃栈顶数据 |
OP_DUP | 118 | 0x76 | x | x x | 复制栈顶数据 |
OP_NIP | 119 | 0x77 | x1 x2 | x2 移除栈顶上面的一项 | |
OP_OVER | 120 | 0x78 | x1 x2 | x1 x2 x1 | 复制栈第二项到栈顶 |
OP_PICK | 121 | 0x79 | xn...x2 x1 x0 <n> | xn ... x2 x1 x0 xn | 复制栈第 n 项到栈顶,这个 n 最大可以多大呢? |
OP_ROLL | 122 | 0x7a | xn... x2 x1 <n> | ... x2 x1 x0 xn | 移动栈第 n 项到栈顶 |
OP_ROT | 123 | 0x7b | x1 x2 x3 | x2 x3 x1 | 旋转栈前三项相当于把第三项移到栈顶 |
OP_SWAP | 124 | 0x7c | x1 x2 | x2 x1 | 将栈顶两项互相交换 |
OP_TUCK | 125 | 0x7d | x1 x2 | x2 x1 x2 | 将栈顶复制一份到第二项之上 |
OP_2DROP | 109 | 0x6d | x1 x2 | 空 | 移除栈顶两项 |
OP_2DUP | 110 | 0x6e | x1 x2 | x1 x2 x1 x2 | 复制栈顶两项 |
OP_3DUP | 111 | 0x6f | x1 x2 x3 | x1 x2 x3 x1 x2 x3 | 复制栈顶三项 |
OP_2OVER | 112 | 0x70 | x1 x2 x3 x4 | x1 x2 x3 x4 x1 x2 | 复制栈第三第四项到栈顶 |
OP_2ROT | 113 | 0x71 | x1 x2 x3 x4 x5 x6 | x3 x4 x5 x6 x1 x2 | 移动栈第第五第六项到栈顶 |
OP_2SWAP | 114 | 0x72 | x1 x2 x3 x4 | x3 x4 x1 x2 | 交换栈顶一对数据 |
关于栈描述,栈是按照从左至右表示栈底到栈顶. 以OP_2ROT 为例,
输入:
x1 x2 x3 x4 x5 x6
栈顶是 x6,第二项是 x5,以此类推,第六项是 x1
执行完输出为:
x3 x4 x5 x6 x1 x2
栈顶是 x2,第二项是x1,以此类推,第六项是x3
字符串相关指令
名字 | 指令 | 描述 |
---|---|---|
OP_CAT | 126 | 已禁用,碰到此指令,交易直接失败 |
OP_SUBSTR | 127 | 已禁用,碰到此指令,交易直接失败 |
OP_LEFT | 128 | 已禁用,碰到此指令,交易直接失败 |
OP_RIGHT | 129 | 已禁用,碰到此指令,交易直接失败 |
OP_SIZE | 130 | 将栈上字符串的长度放到栈顶(不会弹出字符串) |
位运算
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_INVERT | 131 | 0x83 | 已禁用,碰到此指令,交易直接失败 | ||
OP_AND | 132 | 0x84 | 已禁用,碰到此指令,交易直接失败 | ||
OP_OR | 133 | 0x85 | 已禁用,碰到此指令,交易直接失败 | ||
OP_XOR | 134 | 0x86 | 已禁用,碰到此指令,交易直接失败 | ||
OP_EQUAL | 135 | 0x87 | x1 x2 | TRUE/false | 弹出栈顶两个数据,如果相等,放置1到栈顶,否则放置0到栈顶 |
OP_EQUALVERIFY | 136 | 0x88 | x1 x2 | 弹出栈顶两个数据,如果不等,交易直接失败,否则什么都不做. |
算术运算
比特币不再支持乘除运算,碰到这样的指令,必须失败.这些指令就不列出了.
这些指令包括乘法指令(OP_MUL,OP_2MUL),除法指令(OP_DIV,OP_2DIV,OP_MOD),移位指令( OP_LSHIFT,OP_RSHIFT)
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_1ADD | 139 | 0x8b | x | x+1 | 栈顶数据加1 |
OP_1SUB | 140 | 0x8c | x | x-1 | 栈顶数据减1 |
OP_NEGATE | 143 | 0x8f | x | -x | 符号取反 |
OP_ABS | 144 | 0x90 | x | abs(x) | 求栈顶的绝对值,弹出 x, 压入 x 的绝对值 |
OP_NOT | 145 | 0x91 | x | not(x) | x 转换位逻辑真假,然后取反,比如3,相当于真, not 以后为0 |
OP_0NOTEQUAL | 146 | 0x92 | in | out | 返回0,如果输入为0,否则1. 这条指令看不懂什么意思,怎么用 |
OP_ADD | 147 | 0x93 | a b | a+b | 求和 |
OP_SUB | 148 | 0x94 | a b | a-b | 求差 |
OP_BOOLAND | 154 | 0x9a | a b | a && b | 如果 a b 都不是""(空字符串),输出为1,否则为0 |
OP_BOOLOR | 155 | 0x9b | a b | a or b | 如果 a 或者 b 不是"",输出为1,否则为0 |
OP_NUMEQUAL | 156 | 0x9c | a b | a==b | 弹出a,b 如果相等,放置1到栈顶,否则放置0 |
OP_NUMEQUALVERIFY | 157 | 0x9d | a b | nothing/fail | 如果 a,b 不等,交易失败,否则什么都不做 |
OP_NUMNOTEQUAL | 158 | 0x9e | a b | a!=b | 如果 a,b 不等,栈顶放1,否则放0 |
OP_LESSTHAN | 159 | 0x9f | a b | a<b | a 是否小于 b |
OP_GREATERTHAN | 160 | 0xa0 | a b | a>b | a 是否大于 b |
OP_LESSTHANOREQUAL | 161 | 0xa1 | a b | a<=b | a 是否小于等于 b |
OP_GREATERTHANOREQUAL | 162 | 0xa2 | a b | a>=b | a 是否大于等于 b |
OP_MIN | 163 | 0xa3 | a b | a<b?a:b | 弹出 a,b ,然后在栈顶放较小的 |
OP_MAX | 164 | 0xa4 | a b | a>b?a:b | 弹出 a,b,然后放较大的 |
OP_WITHIN | 165 | 0xa5 | x a b | true/false | 弹出 x,a,b,如果 x 介于 a,b 之间,放1,否则放0 |
密码学指令
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_RIPEMD160 | 166 | 0xa6 | in | hash | hash=RIPEMD160(in), 问题是如何知道 in 的长度是多少呢?怎么界定? |
OP_SHA1 | 167 | 0xa7 | in | hash | 求sha1. |
OP_SHA256 | 168 | 0xa8 | in | hash | 求sha256 |
OP_HASH160 | 169 | 0xa9 | in | hash | ripemd160(sha256(in)) |
OP_HASH256 | 170 | 0xaa | in | hash | sha256(sha256(in)) |
OP_CODESEPARATOR | 171 | 0xab | Nothing | Nothing | 代码数据分隔符. |
OP_CHECKSIG | 172 | 0xac | sig pubkey | True / false | 弹出 signature,pubkey, 验证两者是否匹配. 至于签名内容包含什么,可以参考我另一篇博客比特币 解锁脚本signature script 包含了那些东西 |
OP_CHECKSIGVERIFY | 173 | 0xad | sig pubkey | Nothing / fail | 和前一条指令功能相同,如果验证为假,那么交易直接失败 |
OP_CHECKMULTISIG | 174 | 0xae | x sig1 sig2 ... pub1 pub2 | True / False | 多重签名验证 , 弹出的数据根据 n/m 来确定. |
OP_CHECKMULTISIGVERIFY | 175 | 0xaf | x sig1 sig2 ... pub1 pub2 ... | Nothing / fail | 先做OP_CHECKMULTISIG, 然后执行OP_VERIFY |
LockTime
名字 | 指令 | 十六进制 | 输入 | 输出 | 描述 |
---|---|---|---|---|---|
OP_CHECKLOCKTIMEVERIFY (previously OP_NOP2) | 177 | 0xb1 | x | x / fail | 基本功能就是为了阻止 TxOut 只能在某个绝对块数之后被花出,比如30000 OP_CHECKLOCKTIMEVERIFY DROP ... 表示30000块之后后续脚本才有可能成功,否则必定失败. 详细功能参考 BIP 0065. |
OP_CHECKSEQUENCEVERIFY (previously OP_NOP3) | 178 | 0xb2 | x | x / fail | 使用 TxIn中的 nSequence 中的作为相对块数,表示只能在花费的那个UTXO 被挖矿nSequence块以后才能花费那个 UTXO.详细参考 BIP 0112. |
关于OP_CHECKLOCKTIMEVERIFY的一个示例
IF
<now + 3 months> CHECKLOCKTIMEVERIFY DROP
<Lenny's pubkey> CHECKSIGVERIFY
1
ELSE
2
ENDIF
<Alice's pubkey> <Bob's pubkey> 2 CHECKMULTISIG
上面的脚本中< now+3 months> 就是一个从现在起,推算出来的一个绝对块数,比如现在是5000000块,那么三个月以后就是5012960块
那么解锁脚本是什么呢,有两种情况
一种是三个月以后,使用Alice或者 Bob 的签名,加上 Lenny 的签名
一种是随时用Alice和 Bob 的签名
第一种情况,解锁脚本是
0 <Alice/Bob's signature> <Lenny's signature> 1
解锁脚本从左到右一次压栈,
- 1表示走上面的分支
- 验证是否是三个月以后了
- 第一个 CHECKSIGVERIFY验证Lenny的签名是否正确
- 第二个CHECKMULTISIG输入是
0 <Alice/Bob's signature> 1 <Alice's pubkey> <Bob's pubkey> 2 CHECKMULTISIG
,因此随便 Alice/Bob 的一个有效签名都可以花费该 UTXO
第二种情况解锁脚本
0 <Alice's signature> <Bob's signature> 0
- 0表示走下面的分支
- 也就是一个2-2的多重签名验证,因此需要 Alice/Bob 都签名才可以.