轉載:http://www.showmuch.com/article/article_120.html
前面講了交易單,接下來講講交易單的類型和交易驗證的實現細節。
交易的類型與驗證
交易單(Transaction)目前被bitcoin分爲3種:
- 按IP地址轉賬(Transfer)
- 按接收地址轉賬(Transfer)
- 造幣(Generation)
通過前面對交易單的描述,我想大家應該已經知道,交易的驗證是通過不斷的追溯交易單來完成的。那麼交易驗證的細節是如何實現的,bitcoin的交易驗證的實現細節是很意思的,它是通過腳本來實現驗證的,這樣bitcoin就實現了一個可被腳本擴展的行爲,更加廣義的”交易”,這可以保證足夠的靈活性和可擴展,可以想象也許以後會有真正的分佈式計算任務跑在上面作爲一筆交易。因此要想講清楚驗證的細節,就不得不從腳本系統講起了。
腳本系統
Bitcoin的腳本系統是使用類FORTH語言(FORTH在嵌入式設備中是我最喜歡的一種語言)實現的,FORTH系統是面向棧的“高級機器”語言,它兼具了高級語言的特性(面向WORD)和機器語言的高性能與小尺寸,唯一的缺點就是可讀性不高,基本上可以把FORTH當一種高級的機器語言吧。Bitcoin在實現上做了許多簡化和特殊實現,所以只能算是類FORTH的系統。
在FORTH系統中所有的命令(函數)都被稱爲單詞(WORD),所有數據的處理都要壓入數據棧上進行,所以FORTH被稱爲面向棧的語言。
比如 1和2相加,在FORTH系統中則是 1 2 +,數字 1,2 表示將它們壓入到數據棧中(在FORTH解釋器執行後實際指令會有OP_PUSH),+的操作則是將棧頂和次棧頂的數字取出並相加,並將結果壓回數據棧。
Bitcoin的腳本系統的所有的操作指令(單詞)見後面的附錄,不是所有的操作指令都能被執行支持,因爲安全上的考慮有的操作指令被禁止掉了,比如大多數的字符串操作和乘除運算。
在FORTH系統中一般會定義該系統是8位FORTH, 16位FORTH還是32/64位FORTH,這和數據棧的值長有關。在Bitcoin中的腳本系統使用的堆棧是用(vector<vector<unsigned char> >)來模擬的,它在數據棧的每一項都是以字符串的形式存放,它的數值是統一用CBigNum來運算的(讀到這裏應該明白爲啥bitcoin會限制乘除運算了),每一次從數據棧中壓入(CBigNum.getvch())或者取出數值(CastToBigNum(stacktop[-1]))都要進行一次轉換。看着這樣的實現,讓我有點發怵,本能的不喜歡,怎麼能把高效的FORTH搞成這個樣子。Bitcoin的腳本系統與FORTH一樣,有兩個堆棧,一個數據棧,在Bitcoin中被稱爲main stack,一個返回棧,在Bitcoin中被稱爲alt stack(事實上在Bitcoin中將alt stack作爲數據棧的中轉而還沒有作爲FORTH意義上的返回棧). Bitcoin的腳本系統沒有實現單詞定義,流程跳轉,循環控制(FOR, WHILE),對IF的實現非常醜陋。事實上我對Bitcoin的腳本實現不是十分認可,堆棧採用變長的數據值,直接將big number 作爲opcode,導致每一次opcode執行開銷無法控制,由於沒有完整實現FORTH的控制指令,導致用trick的方式來實現IF指令,在bitcoin中也因此無法定義新的WORD。總之我很不喜歡bitcoin的這個腳本引擎實現(參見script.cpp)。
下一篇將接着介紹下和交易驗證相關的幾個操作符:OP_DUP, OP_HASH160, OP_EQUALVERIFY , OP_CHECKSIG 的功能,現在有點倦了。
enum opcodetype
{
// push value
OP_0=0,
OP_FALSE=OP_0,
OP_PUSHDATA1=76,
OP_PUSHDATA2,
OP_PUSHDATA4,
OP_1NEGATE,
OP_RESERVED,
OP_1,
OP_TRUE=OP_1,
OP_2,
OP_3,
OP_4,
OP_5,
OP_6,
OP_7,
OP_8,
OP_9,
OP_10,
OP_11,
OP_12,
OP_13,
OP_14,
OP_15,
OP_16,
// control
OP_NOP,
OP_VER,
OP_IF,
OP_NOTIF,
OP_VERIF,
OP_VERNOTIF,
OP_ELSE,
OP_ENDIF,
OP_VERIFY,
OP_RETURN,
// stack ops
OP_TOALTSTACK,
OP_FROMALTSTACK,
OP_2DROP,
OP_2DUP,
OP_3DUP,
OP_2OVER,
OP_2ROT,
OP_2SWAP,
OP_IFDUP,
OP_DEPTH,
OP_DROP,
OP_DUP,
OP_NIP,
OP_OVER,
OP_PICK,
OP_ROLL,
OP_ROT,
OP_SWAP,
OP_TUCK,
// splice ops
OP_CAT,
OP_SUBSTR,
OP_LEFT,
OP_RIGHT,
OP_SIZE,
// bit logic
OP_INVERT,
OP_AND,
OP_OR,
OP_XOR,
OP_EQUAL,
OP_EQUALVERIFY,
OP_RESERVED1,
OP_RESERVED2,
// numeric
OP_1ADD,
OP_1SUB,
OP_2MUL,
OP_2DIV,
OP_NEGATE,
OP_ABS,
OP_NOT,
OP_0NOTEQUAL,
OP_ADD,
OP_SUB,
OP_MUL,
OP_DIV,
OP_MOD,
OP_LSHIFT,
OP_RSHIFT,
OP_BOOLAND,
OP_BOOLOR,
OP_NUMEQUAL,
OP_NUMEQUALVERIFY,
OP_NUMNOTEQUAL,
OP_LESSTHAN,
OP_GREATERTHAN,
OP_LESSTHANOREQUAL,
OP_GREATERTHANOREQUAL,
OP_MIN,
OP_MAX,
OP_WITHIN,
// crypto
OP_RIPEMD160,
OP_SHA1,
OP_SHA256,
OP_HASH160,
OP_HASH256,
OP_CODESEPARATOR,
OP_CHECKSIG,
OP_CHECKSIGVERIFY,
OP_CHECKMULTISIG,
OP_CHECKMULTISIGVERIFY,
// expansion
OP_NOP1,
OP_NOP2,
OP_NOP3,
OP_NOP4,
OP_NOP5,
OP_NOP6,
OP_NOP7,
OP_NOP8,
OP_NOP9,
OP_NOP10,
// template matching params
OP_PUBKEYHASH = 0xfd,
OP_PUBKEY = 0xfe,
OP_INVALIDOPCODE = 0xff,
};
附錄Bitcoin腳本系統單詞列表
參見:https://en.bitcoin.it/wiki/Script:
常量
常量就是用來把數據壓入棧中的單詞:
單詞 | 虛擬指令(opcode) | 輸入 | 輸出 | Description |
---|---|---|---|---|
OP_0, OP_FALSE | 0 | Nothing. | 0 | 壓入數字0到棧中 |
N/A | 1-75 | (special) | data | 將緊隨 opcode 的data數據 opcode個字節壓入到堆棧。opcode兼作數據長度指示。 |
OP_PUSHDATA1 | 76 | (special) | data | 緊隨該指令的下一個字節是被壓入數據大小,然後是被壓入數據 |
OP_PUSHDATA2 | 77 | (special) | data | 緊隨該指令的兩個字節是被壓入數據大小,然後是被壓入數據. |
OP_PUSHDATA4 | 78 | (special) | data | 緊隨該指令的4個字節是被壓入數據大小,然後是被壓入數據. |
OP_1NEGATE | 79 | 無. | -1 | 壓入-1 |
OP_1, OP_TRUE | 81 | 無. | 1 | 壓入1. |
OP_2-OP_16 | 82-96 | 無. | 2-16 | 2-16被壓入. |
控制流
單詞 | Opcode | 輸入 | 輸出 | 描述 |
---|---|---|---|---|
OP_NOP | 97 | 無 | 無 | 空指令. |
OP_IF | 99 | <expression> if [statements] [else [statements]] endif | If 判斷指令,取出棧頂值,如果棧頂值爲1, 則if後面的語句被執行,否則else中的語句被執行。 | |
OP_NOTIF | 100 | <expression> ifnot [statements] [else [statements]] endif | Ifnot 判斷指令,取出棧頂值,如果棧頂值爲0, 則if後面的語句被執行,否則else中的語句被執行。 | |
OP_ELSE | 103 | <expression> if [statements] [else [statements]] endif | 放置在 OP_IF 或OP_NOTIF 後的指令,當前面的條件不滿足的時候執行 | |
OP_ENDIF | 104 | <expression> if [statements] [else [statements]] endif | 結束 if/else 執行塊. | |
OP_VERIFY | 105 | True / false | Nothing / False |
標記交易單無效 如果棧頂值不爲真。當棧頂值爲真,移除該棧頂值,否則保留該值。 |
OP_RETURN | 106 | Nothing | Nothing | 標記交易單無效. |
堆棧操作
Word | Opcode | Input | Output | Description |
---|---|---|---|---|
OP_TOALTSTACK | 107 | x1 | (alt)x1 | 從數據棧中彈出棧頂 數據,壓入輔助棧。 |
OP_FROMALTSTACK | 108 | (alt)x1 | x1 | 從輔助棧彈出棧頂數據壓入到數據棧 |
OP_IFDUP | 115 | x | x / x x | 如果棧頂非0則複製棧頂 |
OP_DEPTH | 116 | Nothing | <Stack size> | 獲取堆棧數據個數 |
OP_DROP | 117 | x | Nothing | 丟棄棧頂數據. |
OP_DUP | 118 | x | x x | 複製棧頂數據. |
OP_NIP | 119 | x1 x2 | x2 | 丟棄次棧頂數據 |
OP_OVER | 120 | x1 x2 | x1 x2 x1 | 複製次棧頂數據到棧頂. |
OP_PICK | 121 | xn … x2 x1 x0 <n> | xn … x2 x1 x0 xn | 複製第n項數據到棧頂. |
OP_ROLL | 122 | xn … x2 x1 x0 <n> | … x2 x1 x0 xn | 將第n項數據移到棧頂. |
OP_ROT | 123 | x1 x2 x3 | x2 x3 x1 | 棧頂3項數據向左旋轉. |
OP_SWAP | 124 | x1 x2 | x2 x1 | 棧頂2項數據交換. |
OP_TUCK | 125 | x1 x2 | x2 x1 x2 | 棧頂數據複製並插入到次棧頂數據前 |
OP_2DROP | 109 | x1 x2 | Nothing | 同 DROP,只是數據項是2項. |
OP_2DUP | 110 | x1 x2 | x1 x2 x1 x2 | 同 DUP,只是數據項是2項. |
OP_3DUP | 111 | x1 x2 x3 | x1 x2 x3 x1 x2 x3 | 同 DUP,只是數據項是3項. |
OP_2OVER | 112 | x1 x2 x3 x4 | x1 x2 x3 x4 x1 x2 | 同 OVER,只是數據項是2項. |
OP_2ROT | 113 | x1 x2 x3 x4 x5 x6 | x3 x4 x5 x6 x1 x2 | 同 ROT,只是數據項是2項. |
OP_2SWAP | 114 | x1 x2 x3 x4 | x3 x4 x1 x2 | 同 SWAP,只是數據項是2項. |
字符串處理
字符串處理的大多數指令都被禁止了。
Word | Opcode | Input | Output | Description |
---|---|---|---|---|
OP_CAT | 126 | x1 x2 | out | Concatenates two strings. [禁止] |
OP_SUBSTR | 127 | in begin size | out | Returns a section of a string. [禁止] |
OP_LEFT | 128 | in size | out | Keeps only characters left of the specified point in a string. [禁止] |
OP_RIGHT | 129 | in size | out | Keeps only characters right of the specified point in a string. [禁止] |
OP_SIZE | 130 | in | in size | 返回字符串長度 |
位運算
Word | Opcode | Input | Output | Description |
---|---|---|---|---|
OP_INVERT | 131 | in | out | Flips all of the bits in the input. [禁止] |
OP_AND | 132 | x1 x2 | out | Boolean and between each bit in the inputs. [禁止] |
OP_OR | 133 | x1 x2 | out | Boolean or between each bit in the inputs. [禁止] |
OP_XOR | 134 | x1 x2 | out | Boolean exclusive or between each bit in the inputs. [禁止] |
OP_EQUAL | 135 | x1 x2 | True / false | Returns 1 if the inputs are exactly equal, 0 otherwise. |
OP_EQUALVERIFY | 136 | x1 x2 | True / false | Same as OP_EQUAL, but runs OP_VERIFY afterward. |
數學運算
Word | Opcode | Input | Output | Description |
---|---|---|---|---|
OP_1ADD | 139 | in | out | 1 is added to the input. |
OP_1SUB | 140 | in | out | 1 is subtracted from the input. |
OP_2MUL | 141 | in | out | The input is multiplied by 2. [禁止] |
OP_2DIV | 142 | in | out | The input is divided by 2. [禁止] |
OP_NEGATE | 143 | in | out | The sign of the input is flipped. |
OP_ABS | 144 | in | out | The input is made positive. |
OP_NOT | 145 | in | out | If the input is 0 or 1, it is flipped. Otherwise the output will be 0. |
OP_0NOTEQUAL | 146 | in | out | Returns 1 if the input is 0. 0 otherwise. |
OP_ADD | 147 | a b | out | a is added to b. |
OP_SUB | 148 | a b | out | b is subtracted from a. |
OP_MUL | 149 | a b | out | a is multiplied by b. [禁止] |
OP_DIV | 150 | a b | out | a is divided by b. [禁止] |
OP_MOD | 151 | a b | out | Returns the remainder after dividing a by b. [禁止] |
OP_LSHIFT | 152 | a b | out | Shifts a left b bits, preserving sign. [禁止] |
OP_RSHIFT | 153 | a b | out | Shifts a right b bits, preserving sign. [禁止] |
OP_BOOLAND | 154 | a b | out | If both a and b are not 0, the output is 1. Otherwise 0. |
OP_BOOLOR | 155 | a b | out | If a or b is not 0, the output is 1. Otherwise 0. |
OP_NUMEQUAL | 156 | a b | out | Returns 1 if the numbers are equal, 0 otherwise. |
OP_NUMEQUALVERIFY | 157 | a b | out | Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. |
OP_NUMNOTEQUAL | 158 | a b | out | Returns 1 if the numbers are not equal, 0 otherwise. |
OP_LESSTHAN | 159 | a b | out | Returns 1 if a is less than b, 0 otherwise. |
OP_GREATERTHAN | 160 | a b | out | Returns 1 if a is greater than b, 0 otherwise. |
OP_LESSTHANOREQUAL | 161 | a b | out | Returns 1 if a is less than or equal to b, 0 otherwise. |
OP_GREATERTHANOREQUAL | 162 | a b | out | Returns 1 if a is greater than or equal to b, 0 otherwise. |
OP_MIN | 163 | a b | out | Returns the smaller of a and b. |
OP_MAX | 164 | a b | out | Returns the larger of a and b. |
OP_WITHIN | 165 | x min max | out | Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. |
加密相關
Word | Opcode | Input | Output | Description |
---|---|---|---|---|
OP_RIPEMD160 | 166 | in | hash | The input is hashed using RIPEMD-160. |
OP_SHA1 | 167 | in | hash | The input is hashed using SHA-1. |
OP_SHA256 | 168 | in | hash | The input is hashed using SHA-256. |
OP_HASH160 | 169 | in | hash | The input is hashed twice: first with SHA-256 and then with RIPEMD-160. |
OP_HASH256 | 170 | in | hash | The input is hashed two times with SHA-256. |
OP_CODESEPARATOR | 171 | Nothing | Nothing | All of the signature checking words will only match signatures to the data after the most recently-executed OP_CODESEPARATOR. |
OP_CHECKSIG | 172 | sig pubkey | True / false | The entire transaction’s outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. |
OP_CHECKSIGVERIFY | 173 | sig pubkey | True / false | Same as OP_CHECKSIG, but OP_VERIFY is executed afterward. |
OP_CHECKMULTISIG | 174 | sig1 sig2 … <number of signatures> pub1 pub2 <number of public keys> | True / False | For each signature and public key pair, OP_CHECKSIG is executed. If more public keys than signatures are listed, some key/sig pairs can fail. All signatures need to match a public key. If all signatures are valid, 1 is returned, 0 otherwise. |
OP_CHECKMULTISIGVERIFY | 175 | sig1 sig2 … <number of signatures> pub1 pub2 … <number of public keys> | True / False | Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward. |
僞詞(Pseudo-words)
下列詞彙用於在內部使用,在腳本系統中實際上不存在的詞。
Word | Opcode | Description |
---|---|---|
OP_PUBKEYHASH | 253 | 表示OP_HASH160 後的公開密鑰散列 |
OP_PUBKEY | 254 | 表示一個公開密鑰(可以被 OP_CHECKSIG). |
OP_INVALIDOPCODE | 255 |
保留詞(Reserved words)
沒有被定義的opcode被保留以後使用,如果在腳本中使用這些保留詞,要麼被忽略,要麼使得交易無效。
Word | Opcode | When used… |
---|---|---|
OP_RESERVED | 80 | Transaction is invalid |
OP_VER | 98 | Transaction is invalid |
OP_VERIF | 101 | Transaction is invalid |
OP_VERNOTIF | 102 | Transaction is invalid |
OP_RESERVED1 | 137 | Transaction is invalid |
OP_RESERVED2 | 138 | Transaction is invalid |
OP_NOP1-OP_NOP10 | 176-185 | The word is ignored. |