btcs

bitcoin script parser/evaluator/compiler/decompiler
git clone git://jb55.com/btcs
Log | Files | Refs | README | LICENSE

commit 0e514a791b2070a79f073c765b0a1eff14f8c17c
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 21 Oct 2017 22:43:48 -0700

Initial commit

Diffstat:
A.gitignore | 6++++++
AMakefile | 27+++++++++++++++++++++++++++
Alexer.l | 24++++++++++++++++++++++++
Amph-opcodes | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aopcodes | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aoplookup.h | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparser.y | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascript.c | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascript.h | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 928 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,6 @@ +*.o +/parser.tab.h +/parser.tab.c +/oplookup.c +/lex.yy.c +/bcs diff --git a/Makefile b/Makefile @@ -0,0 +1,27 @@ + + +GEN=parser.tab.c parser.tab.h lex.yy.c oplookup.c +DEPS=script.c parser.tab.c lex.yy.c oplookup.c +PREFIX ?= /usr/local +BIN=bcs + +all: $(BIN) + +oplookup.c: opcodes + @./mph-opcodes opcodes > $@ + +parser.tab.c parser.tab.h: parser.y + bison -d parser.y + +lex.yy.c: lexer.l parser.tab.h + flex lexer.l + +install: $(BIN) + mkdir -p $(PREFIX)/bin + cp $(BIN) $(PREFIX)/bin + +$(BIN): $(GEN) $(DEPS) + $(CC) -O0 -g -o $@ $(DEPS) + +clean: + rm -f $(GEN) diff --git a/lexer.l b/lexer.l @@ -0,0 +1,24 @@ +%option noyywrap + +%{ +#include <stdio.h> +#include "script.h" + +#define YY_DECL int yylex() + + +#include "parser.tab.h" + +%} + +%% + +[ \t] ; // ignore all whitespace +\n {return T_NEWLINE;} + +(op_)?[a-zA-Z0-9]+ { + yylval = op_tokenize(yytext); + return T_OP; +} + +%% diff --git a/mph-opcodes b/mph-opcodes @@ -0,0 +1,101 @@ +#!/usr/bin/env python +# Easy Perfect Minimal Hashing +# By Steve Hanov. Released to the public domain. +# +# Based on: +# Edward A. Fox, Lenwood S. Heath, Qi Fan Chen and Amjad M. Daoud, +# "Practical minimal perfect hash functions for large databases", CACM, 35(1):105-121 +# also a good reference: +# Compress, Hash, and Displace algorithm by Djamal Belazzougui, +# Fabiano C. Botelho, and Martin Dietzfelbinger +import sys + +DICTIONARY = sys.argv[1] + +# Calculates a distinct hash function for a given string. Each value of the +# integer d results in a different hash value. +def hash( d, str ): + if d == 0: d = 0x01000193 + + # Use the FNV algorithm from http://isthe.com/chongo/tech/comp/fnv/ + for c in str: + d = ( (d * 0x01000193) ^ ord(c) ) & 0xffffffff; + + return d + +# Computes a minimal perfect hash table using the given python dictionary. It +# returns a tuple (G, V). G and V are both arrays. G contains the intermediate +# table of values needed to compute the index of the value in V. V contains the +# values of the dictionary. +def CreateMinimalPerfectHash( dict ): + size = len(dict) + + # Step 1: Place all of the keys into buckets + buckets = [ [] for i in range(size) ] + G = [0] * size + values = [None] * size + + for key in dict.keys(): + buckets[hash(0, key) % size].append( key ) + + # Step 2: Sort the buckets and process the ones with the most items first. + buckets.sort( key=len, reverse=True ) + for b in xrange( size ): + bucket = buckets[b] + if len(bucket) <= 1: break + + d = 1 + item = 0 + slots = [] + + # Repeatedly try different values of d until we find a hash function + # that places all items in the bucket into free slots + while item < len(bucket): + slot = hash( d, bucket[item] ) % size + if values[slot] != None or slot in slots: + d += 1 + item = 0 + slots = [] + else: + slots.append( slot ) + item += 1 + + G[hash(0, bucket[0]) % size] = d + for i in range(len(bucket)): + values[slots[i]] = dict[bucket[i]] + + # Only buckets with 1 item remain. Process them more quickly by directly + # placing them into a free slot. Use a negative value of d to indicate + # this. + freelist = [] + for i in xrange(size): + if values[i] == None: freelist.append( i ) + + for b in xrange( b, size ): + bucket = buckets[b] + if len(bucket) == 0: break + slot = freelist.pop() + # We subtract one to ensure it's negative even if the zeroeth slot was + # used. + G[hash(0, bucket[0]) % size] = -slot-1 + values[slot] = dict[bucket[0]] + + return (G, values) + +# Look up a value in the hash table, defined by G and V. +def PerfectHashLookup( G, V, key ): + d = G[hash(0,key) % len(G)] + if d < 0: return V[-d-1] + return V[hash(d, key) % len(V)] + +dict = {} +line = 1 +keys = map(lambda x: x.strip(), open(DICTIONARY, "rt").readlines()) +for key in keys: + dict[key] = line + line += 1 + +(G, V) = CreateMinimalPerfectHash( dict ) + +print G +print V diff --git a/opcodes b/opcodes @@ -0,0 +1,121 @@ +0 +FALSE +PUSHDATA1 +PUSHDATA2 +PUSHDATA4 +1NEGATE +RESERVED +1 +TRUE +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +NOP +VER +IF +NOTIF +VERIF +VERNOTIF +ELSE +ENDIF +VERIFY +RETURN +TOALTSTACK +FROMALTSTACK +2DROP +2DUP +3DUP +2OVER +2ROT +2SWAP +IFDUP +DEPTH +DROP +DUP +NIP +OVER +PICK +ROLL +ROT +SWAP +TUCK +CAT +SUBSTR +LEFT +RIGHT +SIZE +INVERT +AND +OR +XOR +EQUAL +EQUALVERIFY +RESERVED1 +RESERVED2 +numeric +1ADD +1SUB +2MUL +2DIV +NEGATE +ABS +NOT +0NOTEQUAL +ADD +SUB +MUL +DIV +MOD +LSHIFT +RSHIFT +BOOLAND +BOOLOR +NUMEQUAL +NUMEQUALVERIFY +NUMNOTEQUAL +LESSTHAN +GREATERTHAN +LESSTHANOREQUAL +GREATERTHANOREQUAL +MIN +MAX +WITHIN +RIPEMD160 +SHA1 +SHA256 +HASH160 +HASH256 +CODESEPARATOR +CHECKSIG +CHECKSIGVERIFY +CHECKMULTISIG +CHECKMULTISIGVERIFY +NOP1 +CHECKLOCKTIMEVERIFY +NOP2 +CHECKSEQUENCEVERIFY +NOP3 +NOP4 +NOP5 +NOP6 +NOP7 +NOP8 +NOP9 +NOP10 +SMALLINTEGER +PUBKEYS +PUBKEYHASH +PUBKEY +INVALIDOPCODE+ \ No newline at end of file diff --git a/oplookup.h b/oplookup.h @@ -0,0 +1,156 @@ + +#ifndef BCS_OPLOOKUP_H +#define BCS_OPLOOKUP_H + +enum opcode_token +{ + // push value + _OP_0, + _OP_FALSE, + _OP_PUSHDATA1, + _OP_PUSHDATA2, + _OP_PUSHDATA4, + _OP_1NEGATE, + _OP_RESERVED, + _OP_1, + _OP_TRUE, + _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_CHECKLOCKTIMEVERIFY, + _OP_NOP2, + _OP_CHECKSEQUENCEVERIFY, + _OP_NOP3, + _OP_NOP4, + _OP_NOP5, + _OP_NOP6, + _OP_NOP7, + _OP_NOP8, + _OP_NOP9, + _OP_NOP10, + + + // template matching params + _OP_SMALLINTEGER, + _OP_PUBKEYS, + _OP_PUBKEYHASH, + _OP_PUBKEY, + + _OP_INVALIDOPCODE, +}; + + +enum opcode_token op_mph(const char *); + + +#endif /* BCS_OPLOOKUP_H */ + diff --git a/parser.y b/parser.y @@ -0,0 +1,57 @@ + +%{ + +#include <stdio.h> +#include <stdlib.h> +#include "script.h" + +extern int yylex(); +extern int yyparse(); +extern FILE* yyin; + +char buffer[255]; + +void yyerror(const char* s); +%} + +%union { + enum opcode opcode; +} + +%token T_OP +%token T_NEWLINE T_QUIT + +%type<opcode> T_OP + +%start script + +%% + +script: + | script line +; + +line: T_NEWLINE + | T_OP line { printf("%s\n", op_str($1)); } + +/* opcode: */ +/* | T_OP { op_add($$); } */ +/* ; */ + + +%% + +int main() { + yyin = stdin; + + do { + yyparse(); + } while(!feof(yyin)); + + return 0; +} + +void yyerror(const char* s) { + fprintf(stderr, "Parse error: %s\n", s); + exit(1); +} diff --git a/script.c b/script.c @@ -0,0 +1,280 @@ + +#include "script.h" +#include <stdio.h> +#include <string.h> +#include <ctype.h> + + + +enum opcode +op_tokenize(char *str) { + int len,i; + char *p; + + p = str; + len = strlen(str); + + for (i = 0; i < len; ++i) + str[i] = toupper(str[i]); + + // upper all all + if (len >= 3) + if (str[0] == 'O') + if (str[1] == 'P') + if (str[2] == '_') { + p = &str[3]; + len -= 3; + } + + return op_mph(str); +} + + +enum opcode op_from_token(enum opcode_token opcode) { + switch (opcode) { + case _OP_0: return OP_0; + case _OP_FALSE: return OP_FALSE; + case _OP_PUSHDATA1: return OP_PUSHDATA1; + case _OP_PUSHDATA2: return OP_PUSHDATA2; + case _OP_PUSHDATA4: return OP_PUSHDATA4; + case _OP_1NEGATE: return OP_1NEGATE; + case _OP_RESERVED: return OP_RESERVED; + case _OP_1: return OP_1; + case _OP_TRUE: return OP_TRUE; + case _OP_2: return OP_2; + case _OP_3: return OP_3; + case _OP_4: return OP_4; + case _OP_5: return OP_5; + case _OP_6: return OP_6; + case _OP_7: return OP_7; + case _OP_8: return OP_8; + case _OP_9: return OP_9; + case _OP_10: return OP_10; + case _OP_11: return OP_11; + case _OP_12: return OP_12; + case _OP_13: return OP_13; + case _OP_14: return OP_14; + case _OP_15: return OP_15; + case _OP_16: return OP_16; + case _OP_NOP: return OP_NOP; + case _OP_VER: return OP_VER; + case _OP_IF: return OP_IF; + case _OP_NOTIF: return OP_NOTIF; + case _OP_VERIF: return OP_VERIF; + case _OP_VERNOTIF: return OP_VERNOTIF; + case _OP_ELSE: return OP_ELSE; + case _OP_ENDIF: return OP_ENDIF; + case _OP_VERIFY: return OP_VERIFY; + case _OP_RETURN: return OP_RETURN; + case _OP_TOALTSTACK: return OP_TOALTSTACK; + case _OP_FROMALTSTACK: return OP_FROMALTSTACK; + case _OP_2DROP: return OP_2DROP; + case _OP_2DUP: return OP_2DUP; + case _OP_3DUP: return OP_3DUP; + case _OP_2OVER: return OP_2OVER; + case _OP_2ROT: return OP_2ROT; + case _OP_2SWAP: return OP_2SWAP; + case _OP_IFDUP: return OP_IFDUP; + case _OP_DEPTH: return OP_DEPTH; + case _OP_DROP: return OP_DROP; + case _OP_DUP: return OP_DUP; + case _OP_NIP: return OP_NIP; + case _OP_OVER: return OP_OVER; + case _OP_PICK: return OP_PICK; + case _OP_ROLL: return OP_ROLL; + case _OP_ROT: return OP_ROT; + case _OP_SWAP: return OP_SWAP; + case _OP_TUCK: return OP_TUCK; + case _OP_CAT: return OP_CAT; + case _OP_SUBSTR: return OP_SUBSTR; + case _OP_LEFT: return OP_LEFT; + case _OP_RIGHT: return OP_RIGHT; + case _OP_SIZE: return OP_SIZE; + case _OP_INVERT: return OP_INVERT; + case _OP_AND: return OP_AND; + case _OP_OR: return OP_OR; + case _OP_XOR: return OP_XOR; + case _OP_EQUAL: return OP_EQUAL; + case _OP_EQUALVERIFY: return OP_EQUALVERIFY; + case _OP_RESERVED1: return OP_RESERVED1; + case _OP_RESERVED2: return OP_RESERVED2; + case _OP_1ADD: return OP_1ADD; + case _OP_1SUB: return OP_1SUB; + case _OP_2MUL: return OP_2MUL; + case _OP_2DIV: return OP_2DIV; + case _OP_NEGATE: return OP_NEGATE; + case _OP_ABS: return OP_ABS; + case _OP_NOT: return OP_NOT; + case _OP_0NOTEQUAL: return OP_0NOTEQUAL; + case _OP_ADD: return OP_ADD; + case _OP_SUB: return OP_SUB; + case _OP_MUL: return OP_MUL; + case _OP_DIV: return OP_DIV; + case _OP_MOD: return OP_MOD; + case _OP_LSHIFT: return OP_LSHIFT; + case _OP_RSHIFT: return OP_RSHIFT; + case _OP_BOOLAND: return OP_BOOLAND; + case _OP_BOOLOR: return OP_BOOLOR; + case _OP_NUMEQUAL: return OP_NUMEQUAL; + case _OP_NUMEQUALVERIFY: return OP_NUMEQUALVERIFY; + case _OP_NUMNOTEQUAL: return OP_NUMNOTEQUAL; + case _OP_LESSTHAN: return OP_LESSTHAN; + case _OP_GREATERTHAN: return OP_GREATERTHAN; + case _OP_LESSTHANOREQUAL: return OP_LESSTHANOREQUAL; + case _OP_GREATERTHANOREQUAL: return OP_GREATERTHANOREQUAL; + case _OP_MIN: return OP_MIN; + case _OP_MAX: return OP_MAX; + case _OP_WITHIN: return OP_WITHIN; + case _OP_RIPEMD160: return OP_RIPEMD160; + case _OP_SHA1: return OP_SHA1; + case _OP_SHA256: return OP_SHA256; + case _OP_HASH160: return OP_HASH160; + case _OP_HASH256: return OP_HASH256; + case _OP_CODESEPARATOR: return OP_CODESEPARATOR; + case _OP_CHECKSIG: return OP_CHECKSIG; + case _OP_CHECKSIGVERIFY: return OP_CHECKSIGVERIFY; + case _OP_CHECKMULTISIG: return OP_CHECKMULTISIG; + case _OP_CHECKMULTISIGVERIFY: return OP_CHECKMULTISIGVERIFY; + case _OP_NOP1: return OP_NOP1; + case _OP_CHECKLOCKTIMEVERIFY: return OP_CHECKLOCKTIMEVERIFY; + case _OP_NOP2: return OP_NOP2; + case _OP_CHECKSEQUENCEVERIFY: return OP_CHECKSEQUENCEVERIFY; + case _OP_NOP3: return OP_NOP3; + case _OP_NOP4: return OP_NOP4; + case _OP_NOP5: return OP_NOP5; + case _OP_NOP6: return OP_NOP6; + case _OP_NOP7: return OP_NOP7; + case _OP_NOP8: return OP_NOP8; + case _OP_NOP9: return OP_NOP9; + case _OP_NOP10: return OP_NOP10; + case _OP_SMALLINTEGER: return OP_SMALLINTEGER; + case _OP_PUBKEYS: return OP_PUBKEYS; + case _OP_PUBKEYHASH: return OP_PUBKEYHASH; + case _OP_PUBKEY: return OP_PUBKEY; + case _OP_INVALIDOPCODE: return OP_INVALIDOPCODE; + } +} + + +const char* op_str(enum opcode opcode) +{ + switch (opcode) + { + // push value + case OP_0 : return "0"; + case OP_PUSHDATA1 : return "OP_PUSHDATA1"; + case OP_PUSHDATA2 : return "OP_PUSHDATA2"; + case OP_PUSHDATA4 : return "OP_PUSHDATA4"; + case OP_1NEGATE : return "-1"; + case OP_RESERVED : return "OP_RESERVED"; + case OP_1 : return "1"; + case OP_2 : return "2"; + case OP_3 : return "3"; + case OP_4 : return "4"; + case OP_5 : return "5"; + case OP_6 : return "6"; + case OP_7 : return "7"; + case OP_8 : return "8"; + case OP_9 : return "9"; + case OP_10 : return "10"; + case OP_11 : return "11"; + case OP_12 : return "12"; + case OP_13 : return "13"; + case OP_14 : return "14"; + case OP_15 : return "15"; + case OP_16 : return "16"; + + // control + case OP_NOP : return "OP_NOP"; + case OP_VER : return "OP_VER"; + case OP_IF : return "OP_IF"; + case OP_NOTIF : return "OP_NOTIF"; + case OP_VERIF : return "OP_VERIF"; + case OP_VERNOTIF : return "OP_VERNOTIF"; + case OP_ELSE : return "OP_ELSE"; + case OP_ENDIF : return "OP_ENDIF"; + case OP_VERIFY : return "OP_VERIFY"; + case OP_RETURN : return "OP_RETURN"; + + // stack ops + case OP_TOALTSTACK : return "OP_TOALTSTACK"; + case OP_FROMALTSTACK : return "OP_FROMALTSTACK"; + case OP_2DROP : return "OP_2DROP"; + case OP_2DUP : return "OP_2DUP"; + case OP_3DUP : return "OP_3DUP"; + case OP_2OVER : return "OP_2OVER"; + case OP_2ROT : return "OP_2ROT"; + case OP_2SWAP : return "OP_2SWAP"; + case OP_IFDUP : return "OP_IFDUP"; + case OP_DEPTH : return "OP_DEPTH"; + case OP_DROP : return "OP_DROP"; + case OP_DUP : return "OP_DUP"; + case OP_NIP : return "OP_NIP"; + case OP_OVER : return "OP_OVER"; + case OP_PICK : return "OP_PICK"; + case OP_ROLL : return "OP_ROLL"; + case OP_ROT : return "OP_ROT"; + case OP_SWAP : return "OP_SWAP"; + case OP_TUCK : return "OP_TUCK"; + + // splice ops + case OP_CAT : return "OP_CAT"; + case OP_NOT : return "OP_NOT"; + case OP_0NOTEQUAL : return "OP_0NOTEQUAL"; + case OP_ADD : return "OP_ADD"; + case OP_SUB : return "OP_SUB"; + case OP_MUL : return "OP_MUL"; + case OP_DIV : return "OP_DIV"; + case OP_MOD : return "OP_MOD"; + case OP_LSHIFT : return "OP_LSHIFT"; + case OP_RSHIFT : return "OP_RSHIFT"; + case OP_BOOLAND : return "OP_BOOLAND"; + case OP_BOOLOR : return "OP_BOOLOR"; + case OP_NUMEQUAL : return "OP_NUMEQUAL"; + case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY"; + case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL"; + case OP_LESSTHAN : return "OP_LESSTHAN"; + case OP_GREATERTHAN : return "OP_GREATERTHAN"; + case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL"; + case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL"; + case OP_MIN : return "OP_MIN"; + case OP_MAX : return "OP_MAX"; + case OP_WITHIN : return "OP_WITHIN"; + + // crypto + case OP_RIPEMD160 : return "OP_RIPEMD160"; + case OP_SHA1 : return "OP_SHA1"; + case OP_SHA256 : return "OP_SHA256"; + case OP_HASH160 : return "OP_HASH160"; + case OP_HASH256 : return "OP_HASH256"; + case OP_CODESEPARATOR : return "OP_CODESEPARATOR"; + case OP_CHECKSIG : return "OP_CHECKSIG"; + case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; + case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; + case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; + + // expansion + case OP_NOP1 : return "OP_NOP1"; + case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY"; + case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY"; + case OP_NOP4 : return "OP_NOP4"; + case OP_NOP5 : return "OP_NOP5"; + case OP_NOP6 : return "OP_NOP6"; + case OP_NOP7 : return "OP_NOP7"; + case OP_NOP8 : return "OP_NOP8"; + case OP_NOP9 : return "OP_NOP9"; + case OP_NOP10 : return "OP_NOP10"; + + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + + // Note: + // The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum + // as kind of implementation hack, they are *NOT* real opcodes. If found in real + // Script, just let the default: case deal with them. + + default: + return "OP_UNKNOWN"; + } +} + + diff --git a/script.h b/script.h @@ -0,0 +1,155 @@ + +#ifndef BCS_SCRIPT_H +#define BCS_SCRIPT_H + +enum opcode +{ + // push value + OP_0 = 0x00, + OP_FALSE = OP_0, + OP_PUSHDATA1 = 0x4c, + OP_PUSHDATA2 = 0x4d, + OP_PUSHDATA4 = 0x4e, + OP_1NEGATE = 0x4f, + OP_RESERVED = 0x50, + OP_1 = 0x51, + OP_TRUE=OP_1, + OP_2 = 0x52, + OP_3 = 0x53, + OP_4 = 0x54, + OP_5 = 0x55, + OP_6 = 0x56, + OP_7 = 0x57, + OP_8 = 0x58, + OP_9 = 0x59, + OP_10 = 0x5a, + OP_11 = 0x5b, + OP_12 = 0x5c, + OP_13 = 0x5d, + OP_14 = 0x5e, + OP_15 = 0x5f, + OP_16 = 0x60, + + // control + OP_NOP = 0x61, + OP_VER = 0x62, + OP_IF = 0x63, + OP_NOTIF = 0x64, + OP_VERIF = 0x65, + OP_VERNOTIF = 0x66, + OP_ELSE = 0x67, + OP_ENDIF = 0x68, + OP_VERIFY = 0x69, + OP_RETURN = 0x6a, + + // stack ops + OP_TOALTSTACK = 0x6b, + OP_FROMALTSTACK = 0x6c, + OP_2DROP = 0x6d, + OP_2DUP = 0x6e, + OP_3DUP = 0x6f, + OP_2OVER = 0x70, + OP_2ROT = 0x71, + OP_2SWAP = 0x72, + OP_IFDUP = 0x73, + OP_DEPTH = 0x74, + OP_DROP = 0x75, + OP_DUP = 0x76, + OP_NIP = 0x77, + OP_OVER = 0x78, + OP_PICK = 0x79, + OP_ROLL = 0x7a, + OP_ROT = 0x7b, + OP_SWAP = 0x7c, + OP_TUCK = 0x7d, + + // splice ops + OP_CAT = 0x7e, + OP_SUBSTR = 0x7f, + OP_LEFT = 0x80, + OP_RIGHT = 0x81, + OP_SIZE = 0x82, + + // bit logic + OP_INVERT = 0x83, + OP_AND = 0x84, + OP_OR = 0x85, + OP_XOR = 0x86, + OP_EQUAL = 0x87, + OP_EQUALVERIFY = 0x88, + OP_RESERVED1 = 0x89, + OP_RESERVED2 = 0x8a, + + // numeric + OP_1ADD = 0x8b, + OP_1SUB = 0x8c, + OP_2MUL = 0x8d, + OP_2DIV = 0x8e, + OP_NEGATE = 0x8f, + OP_ABS = 0x90, + OP_NOT = 0x91, + OP_0NOTEQUAL = 0x92, + + OP_ADD = 0x93, + OP_SUB = 0x94, + OP_MUL = 0x95, + OP_DIV = 0x96, + OP_MOD = 0x97, + OP_LSHIFT = 0x98, + OP_RSHIFT = 0x99, + + OP_BOOLAND = 0x9a, + OP_BOOLOR = 0x9b, + OP_NUMEQUAL = 0x9c, + OP_NUMEQUALVERIFY = 0x9d, + OP_NUMNOTEQUAL = 0x9e, + OP_LESSTHAN = 0x9f, + OP_GREATERTHAN = 0xa0, + OP_LESSTHANOREQUAL = 0xa1, + OP_GREATERTHANOREQUAL = 0xa2, + OP_MIN = 0xa3, + OP_MAX = 0xa4, + + OP_WITHIN = 0xa5, + + // crypto + OP_RIPEMD160 = 0xa6, + OP_SHA1 = 0xa7, + OP_SHA256 = 0xa8, + OP_HASH160 = 0xa9, + OP_HASH256 = 0xaa, + OP_CODESEPARATOR = 0xab, + OP_CHECKSIG = 0xac, + OP_CHECKSIGVERIFY = 0xad, + OP_CHECKMULTISIG = 0xae, + OP_CHECKMULTISIGVERIFY = 0xaf, + + // expansion + OP_NOP1 = 0xb0, + OP_CHECKLOCKTIMEVERIFY = 0xb1, + OP_NOP2 = OP_CHECKLOCKTIMEVERIFY, + OP_CHECKSEQUENCEVERIFY = 0xb2, + OP_NOP3 = OP_CHECKSEQUENCEVERIFY, + OP_NOP4 = 0xb3, + OP_NOP5 = 0xb4, + OP_NOP6 = 0xb5, + OP_NOP7 = 0xb6, + OP_NOP8 = 0xb7, + OP_NOP9 = 0xb8, + OP_NOP10 = 0xb9, + + + // template matching params + OP_SMALLINTEGER = 0xfa, + OP_PUBKEYS = 0xfb, + OP_PUBKEYHASH = 0xfd, + OP_PUBKEY = 0xfe, + + OP_INVALIDOPCODE = 0xff, +}; + +void op_add(enum opcode); +const char * op_str(enum opcode); +enum opcode op_tokenize(char *); + +#endif /* BCS_SCRIPT_H */