比特币指令集

比特币指令集

本文主要译自比特币 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. 1表示走上面的分支
  2. 验证是否是三个月以后了
  3. 第一个 CHECKSIGVERIFY验证Lenny的签名是否正确
  4. 第二个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
  1. 0表示走下面的分支
  2. 也就是一个2-2的多重签名验证,因此需要 Alice/Bob 都签名才可以.
posted on 2018-08-14 17:29  baizx  阅读(1891)  评论(0编辑  收藏  举报