btcs

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

main.c (5948B)


      1 
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <errno.h>
      6 
      7 #include "stack.h"
      8 #include "script.h"
      9 #include "alloc.h"
     10 #include "util.h"
     11 
     12 extern int yyparse();
     13 extern FILE* yyin;
     14 
     15 char * g_reader_buf;
     16 char * g_reader_buf_top;
     17 struct stack g_reader_stack;
     18 u32 g_reader_buf_cap;
     19 int yy_scan_string(const char *);
     20 
     21 
     22 void yyerror(const char* s);
     23 
     24 #define streq(a,b) strcmp(a,b) == 0
     25 
     26 
     27 void parse_error(char* err) {
     28   fprintf(stderr, "[btcs] parse error: %s\n", err);
     29   exit(1);
     30 }
     31 
     32 #define COMPILE_SHOW_SCRIPT      (1 << 0)
     33 #define COMPILE_SHOW_SCRIPT_HEX  (1 << 1)
     34 #define COMPILE_SHOW_STACK       (1 << 2)
     35 #define COMPILE_SHOW_STACK_HEX   (1 << 3)
     36 #define COMPILE_SHOW_RESULTS     (1 << 4)
     37 #define COMPILE_SHOW_LABELS      (1 << 5)
     38 #define COMPILE_SHOW_ALL         0x3F
     39 
     40 static int compile(int compile_options, int argc, const char *argv[])
     41 {
     42   yyin = stdin;
     43 
     44   struct result result;
     45   /* size_t size; */
     46   size_t bufsize = MAX_STACK_SIZE * MAX_STACK_SIZE;
     47   int i;
     48   int compiled_len;
     49   u8 *buf = (u8*)malloc(bufsize);
     50   struct stack tmp_stack;
     51   alloc_arenas();
     52   stack_init(&tmp_stack);
     53   stack_init(&g_reader_stack);
     54 
     55   if (argc > 1) {
     56     for (i = 1; i < argc; ++i) {
     57       yy_scan_string(argv[i]);
     58       yyparse();
     59     }
     60   }
     61   else {
     62     do {
     63       yyparse();
     64     } while(!feof(yyin));
     65   }
     66 
     67   bool nol = (compile_options & COMPILE_SHOW_LABELS) == 0;
     68 
     69   /* size = g_reader_buf_top - g_reader_buf; */
     70   if (compile_options & COMPILE_SHOW_SCRIPT) {
     71 	  if (compile_options & COMPILE_SHOW_LABELS)
     72 		printf("script      ");
     73 	  script_print_vals(&g_reader_stack);
     74   }
     75 
     76   script_serialize(&g_reader_stack, buf, bufsize, &compiled_len);
     77   script_eval(buf, compiled_len, &tmp_stack, &result);
     78 
     79   if (compile_options & COMPILE_SHOW_SCRIPT_HEX) {
     80 	  if (compile_options & COMPILE_SHOW_LABELS)
     81 		printf("script_hex  ");
     82 	  for(i = 0; i < compiled_len; ++i)
     83 		  printf("%02x", buf[i]);
     84 	  printf("\n");
     85   }
     86 
     87   if (compile_options & COMPILE_SHOW_STACK) {
     88 	  if (compile_options & COMPILE_SHOW_LABELS)
     89 		printf("stack       ");
     90 	  script_print_vals(&tmp_stack);
     91   }
     92 
     93   stack_serialize(&tmp_stack, buf, bufsize, &compiled_len);
     94 
     95   if (compile_options & COMPILE_SHOW_STACK_HEX) {
     96 	  if (compile_options & COMPILE_SHOW_LABELS)
     97 		printf("stack_hex   ");
     98 	  for(i = 0; i < compiled_len; ++i)
     99 		  printf("%02x", buf[i]);
    100 	  printf("\n");
    101   }
    102 
    103   if (compile_options & COMPILE_SHOW_RESULTS) {
    104 	  if (compile_options & COMPILE_SHOW_LABELS)
    105 		printf("results     ");
    106 	  if (result.error)
    107 		  printf("error:%d:%s:%s", result.op_count, result.error,
    108 			 op_name(result.last_op));
    109 	  else
    110 		  printf("success");
    111 	  printf("\n");
    112   }
    113 
    114   stack_free(&g_reader_stack);
    115   stack_free(&tmp_stack);
    116   free_arenas(0);
    117 
    118   return !!result.error;
    119 }
    120 
    121 static void fail(int err, const char *msg)
    122 {
    123 	fprintf(stderr, "error: %s\n", msg);
    124 	exit(err);
    125 }
    126 
    127 
    128 static int decompile(const char *str, size_t *strlen, bool abbrev_data)
    129 {
    130 	static u8 buf[10000];
    131 
    132 	hex_decode(str, strlen, buf, sizeof(buf));
    133 
    134 	if (*strlen % 2 != 0)
    135 		return 0;
    136 
    137 	size_t nbytes = *strlen / 2;
    138 
    139 	script_print(buf, nbytes, abbrev_data);
    140 
    141 	return 1;
    142 }
    143 
    144 
    145 static void usage()
    146 {
    147 	fprintf(stderr, "usage: btcs [OPTIONS] <script>\n\n");
    148 	fprintf(stderr, "   OPTIONS\n\n");
    149 	fprintf(stderr, "      -d,--decompile    decompile a base16 string to bitcoin script\n");
    150 	exit(1);
    151 }
    152 
    153 static u32 count_bits(u32 n)
    154 {
    155 	u32 count = 0;
    156 	while (n) {
    157 		n &= (n-1) ;
    158 		count++;
    159 	}
    160 	return count;
    161 }
    162 
    163 int main(int argc, const char *argv[])
    164 {
    165 	static u8 buf[20000];
    166 
    167 	bool is_decompile = false;
    168 	const char *input = NULL;
    169 	size_t written;
    170 	bool abbrev_data = false;
    171 	int compile_options = 0;
    172 	int last_opt = 0;
    173 	int hide_labels = -1;
    174 
    175 	if (argc == 2 && (streq(argv[1], "-h") || streq(argv[1], "--help")))
    176 		usage();
    177 
    178 	for (int i = 1; i < argc; i++) {
    179 		if (streq(argv[i], "-d") || streq(argv[i], "--decompile"))
    180 			is_decompile = true;
    181 		else if (streq(argv[i], "-sh") || streq(argv[i], "--script-hex"))
    182 			compile_options |= COMPILE_SHOW_SCRIPT_HEX;
    183 		else if (streq(argv[i], "-s") || streq(argv[i], "--script"))
    184 			compile_options |= COMPILE_SHOW_SCRIPT;
    185 		else if (streq(argv[i], "-t") || streq(argv[i], "--stack"))
    186 			compile_options |= COMPILE_SHOW_STACK;
    187 		else if (streq(argv[i], "-th") || streq(argv[i], "--stack-hex"))
    188 			compile_options |= COMPILE_SHOW_STACK_HEX;
    189 		else if (streq(argv[i], "-r") || streq(argv[i], "--results"))
    190 			compile_options |= COMPILE_SHOW_RESULTS;
    191 		else if (streq(argv[i], "-l") || streq(argv[i], "--hide-labels"))
    192 			hide_labels = 1;
    193 		else if (streq(argv[i], "+l") || streq(argv[i], "--show-labels"))
    194 			hide_labels = 0;
    195 		else if (streq(argv[i], "-a") || streq(argv[i], "--abbreviate-data"))
    196 			abbrev_data = true;
    197 		else {
    198 			last_opt = i-1;
    199 			input = argv[i];
    200 			break;
    201 		}
    202 	}
    203 
    204 	if (is_decompile) {
    205 		// we have stdin
    206 		char *line = NULL;
    207 		ssize_t len = 0, prevlen;
    208 		size_t n;
    209 		int ok;
    210 		bool failed = false;
    211 
    212 		if (input == NULL) {
    213 			while ((len = getline(&line, &n, stdin)) != -1) {
    214 				len--;
    215 				prevlen = len;
    216 				ok = decompile(line, (size_t*)&len, abbrev_data);
    217 
    218 				printf("%.*s\n", (int)(prevlen - len), line+len);
    219 
    220 				if (!ok) {
    221 					failed = true;
    222 					fprintf(stderr, "failed to decompile\n");
    223 				}
    224 			}
    225 		}
    226 		else {
    227 			ok = read_arg_or_stdin(input, buf, sizeof(buf), &written);
    228 
    229 			if (!ok)
    230 				fail(4, "failed to read input arg (too big?)");
    231 
    232 			ok = decompile((const char *)buf, &written, abbrev_data);
    233 			printf("\n");
    234 
    235 			if (!ok) {
    236 				fprintf(stderr, "failed to decompile\n");
    237 				failed = true;
    238 			}
    239 		}
    240 
    241 		if (failed)
    242 			exit(5);
    243 
    244 
    245 	}
    246 	else {
    247 		if (!compile_options)
    248 			compile_options = COMPILE_SHOW_ALL;
    249 
    250 		if (hide_labels == -1)
    251 			hide_labels = count_bits(compile_options) == 1;
    252 
    253 		if (hide_labels)
    254 			compile_options &= ~COMPILE_SHOW_LABELS;
    255 		else
    256 			compile_options |= COMPILE_SHOW_LABELS;
    257 
    258 		exit( compile(compile_options, argc - last_opt, argv + last_opt) );
    259 	}
    260 }
    261 
    262 void yyerror(const char* s) {
    263   fprintf(stderr, "Parse error: %s\n", s);
    264   exit(1);
    265 }