2 using System.Collections.Generic;
11 public enum opcodetype
53 OP_FROMALTSTACK = 0x6c,
85 OP_EQUALVERIFY = 0x88,
110 OP_NUMEQUALVERIFY = 0x9d,
111 OP_NUMNOTEQUAL = 0x9e,
113 OP_GREATERTHAN = 0xa0,
114 OP_LESSTHANOREQUAL = 0xa1,
115 OP_GREATERTHANOREQUAL = 0xa2,
127 OP_CODESEPARATOR = 0xab,
129 OP_CHECKSIGVERIFY = 0xad,
130 OP_CHECKMULTISIG = 0xae,
131 OP_CHECKMULTISIGVERIFY = 0xaf,
145 // template matching params
147 OP_SMALLINTEGER = 0xfa,
149 OP_PUBKEYHASH = 0xfd,
152 OP_INVALIDOPCODE = 0xff,
155 public static class ScriptOpcode
159 /// Get the name of supplied opcode
161 /// <param name="opcode">Opcode</param>
162 /// <returns>Opcode name</returns>
163 public static string GetOpName(opcodetype opcode)
168 case opcodetype.OP_0:
170 case opcodetype.OP_PUSHDATA1:
171 return "OP_PUSHDATA1";
172 case opcodetype.OP_PUSHDATA2:
173 return "OP_PUSHDATA2";
174 case opcodetype.OP_PUSHDATA4:
175 return "OP_PUSHDATA4";
176 case opcodetype.OP_1NEGATE:
178 case opcodetype.OP_RESERVED:
179 return "OP_RESERVED";
180 case opcodetype.OP_1:
182 case opcodetype.OP_2:
184 case opcodetype.OP_3:
186 case opcodetype.OP_4:
188 case opcodetype.OP_5:
190 case opcodetype.OP_6:
192 case opcodetype.OP_7:
194 case opcodetype.OP_8:
196 case opcodetype.OP_9:
198 case opcodetype.OP_10:
200 case opcodetype.OP_11:
202 case opcodetype.OP_12:
204 case opcodetype.OP_13:
206 case opcodetype.OP_14:
208 case opcodetype.OP_15:
210 case opcodetype.OP_16:
214 case opcodetype.OP_NOP:
216 case opcodetype.OP_VER:
218 case opcodetype.OP_IF:
220 case opcodetype.OP_NOTIF:
222 case opcodetype.OP_VERIF:
224 case opcodetype.OP_VERNOTIF:
225 return "OP_VERNOTIF";
226 case opcodetype.OP_ELSE:
228 case opcodetype.OP_ENDIF:
230 case opcodetype.OP_VERIFY:
232 case opcodetype.OP_RETURN:
236 case opcodetype.OP_TOALTSTACK:
237 return "OP_TOALTSTACK";
238 case opcodetype.OP_FROMALTSTACK:
239 return "OP_FROMALTSTACK";
240 case opcodetype.OP_2DROP:
242 case opcodetype.OP_2DUP:
244 case opcodetype.OP_3DUP:
246 case opcodetype.OP_2OVER:
248 case opcodetype.OP_2ROT:
250 case opcodetype.OP_2SWAP:
252 case opcodetype.OP_IFDUP:
254 case opcodetype.OP_DEPTH:
256 case opcodetype.OP_DROP:
258 case opcodetype.OP_DUP:
260 case opcodetype.OP_NIP:
262 case opcodetype.OP_OVER:
264 case opcodetype.OP_PICK:
266 case opcodetype.OP_ROLL:
268 case opcodetype.OP_ROT:
270 case opcodetype.OP_SWAP:
272 case opcodetype.OP_TUCK:
276 case opcodetype.OP_CAT:
278 case opcodetype.OP_SUBSTR:
280 case opcodetype.OP_LEFT:
282 case opcodetype.OP_RIGHT:
284 case opcodetype.OP_SIZE:
288 case opcodetype.OP_INVERT:
290 case opcodetype.OP_AND:
292 case opcodetype.OP_OR:
294 case opcodetype.OP_XOR:
296 case opcodetype.OP_EQUAL:
298 case opcodetype.OP_EQUALVERIFY:
299 return "OP_EQUALVERIFY";
300 case opcodetype.OP_RESERVED1:
301 return "OP_RESERVED1";
302 case opcodetype.OP_RESERVED2:
303 return "OP_RESERVED2";
306 case opcodetype.OP_1ADD:
308 case opcodetype.OP_1SUB:
310 case opcodetype.OP_2MUL:
312 case opcodetype.OP_2DIV:
314 case opcodetype.OP_NEGATE:
316 case opcodetype.OP_ABS:
318 case opcodetype.OP_NOT:
320 case opcodetype.OP_0NOTEQUAL:
321 return "OP_0NOTEQUAL";
322 case opcodetype.OP_ADD:
324 case opcodetype.OP_SUB:
326 case opcodetype.OP_MUL:
328 case opcodetype.OP_DIV:
330 case opcodetype.OP_MOD:
332 case opcodetype.OP_LSHIFT:
334 case opcodetype.OP_RSHIFT:
336 case opcodetype.OP_BOOLAND:
338 case opcodetype.OP_BOOLOR:
340 case opcodetype.OP_NUMEQUAL:
341 return "OP_NUMEQUAL";
342 case opcodetype.OP_NUMEQUALVERIFY:
343 return "OP_NUMEQUALVERIFY";
344 case opcodetype.OP_NUMNOTEQUAL:
345 return "OP_NUMNOTEQUAL";
346 case opcodetype.OP_LESSTHAN:
347 return "OP_LESSTHAN";
348 case opcodetype.OP_GREATERTHAN:
349 return "OP_GREATERTHAN";
350 case opcodetype.OP_LESSTHANOREQUAL:
351 return "OP_LESSTHANOREQUAL";
352 case opcodetype.OP_GREATERTHANOREQUAL:
353 return "OP_GREATERTHANOREQUAL";
354 case opcodetype.OP_MIN:
356 case opcodetype.OP_MAX:
358 case opcodetype.OP_WITHIN:
362 case opcodetype.OP_RIPEMD160:
363 return "OP_RIPEMD160";
364 case opcodetype.OP_SHA1:
366 case opcodetype.OP_SHA256:
368 case opcodetype.OP_HASH160:
370 case opcodetype.OP_HASH256:
372 case opcodetype.OP_CODESEPARATOR:
373 return "OP_CODESEPARATOR";
374 case opcodetype.OP_CHECKSIG:
375 return "OP_CHECKSIG";
376 case opcodetype.OP_CHECKSIGVERIFY:
377 return "OP_CHECKSIGVERIFY";
378 case opcodetype.OP_CHECKMULTISIG:
379 return "OP_CHECKMULTISIG";
380 case opcodetype.OP_CHECKMULTISIGVERIFY:
381 return "OP_CHECKMULTISIGVERIFY";
384 case opcodetype.OP_NOP1:
386 case opcodetype.OP_NOP2:
388 case opcodetype.OP_NOP3:
390 case opcodetype.OP_NOP4:
392 case opcodetype.OP_NOP5:
394 case opcodetype.OP_NOP6:
396 case opcodetype.OP_NOP7:
398 case opcodetype.OP_NOP8:
400 case opcodetype.OP_NOP9:
402 case opcodetype.OP_NOP10:
405 // template matching params
406 case opcodetype.OP_PUBKEYHASH:
407 return "OP_PUBKEYHASH";
408 case opcodetype.OP_PUBKEY:
410 case opcodetype.OP_SMALLDATA:
411 return "OP_SMALLDATA";
413 case opcodetype.OP_INVALIDOPCODE:
414 return "OP_INVALIDOPCODE";
421 /// Get next opcode from passed list of bytes and extract push arguments if there are some.
423 /// <param name="codeBytes">WrappedList reference.</param>
424 /// <param name="opcodeRet">Found opcode.</param>
425 /// <param name="bytesRet">IEnumerable out param which is used to get the push arguments.</param>
426 /// <returns>Result of operation</returns>
427 public static bool GetOp(ref WrappedList<byte> codeBytes, out opcodetype opcodeRet, out IEnumerable<byte> bytesRet)
429 bytesRet = new List<byte>();
430 opcodeRet = opcodetype.OP_INVALIDOPCODE;
437 opcode = (opcodetype)codeBytes.GetItem();
439 catch (WrappedListException)
441 // No instruction found there
446 if (opcode <= opcodetype.OP_PUSHDATA4)
448 byte[] szBytes = new byte[4] {0, 0, 0, 0}; // Zero length
452 if (opcode < opcodetype.OP_PUSHDATA1)
454 // Zero value opcodes (OP_0, OP_FALSE)
455 szBytes[3] = (byte)opcode;
457 else if (opcode == opcodetype.OP_PUSHDATA1)
459 // The next byte contains the number of bytes to be pushed onto the stack,
460 // i.e. you have something like OP_PUSHDATA1 0x01 [0x5a]
461 szBytes[3] = (byte) codeBytes.GetItem();
463 else if (opcode == opcodetype.OP_PUSHDATA2)
465 // The next two bytes contain the number of bytes to be pushed onto the stack,
466 // i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a]
467 codeBytes.GetItems(2).CopyTo(szBytes, 2);
469 else if (opcode == opcodetype.OP_PUSHDATA4)
471 // The next four bytes contain the number of bytes to be pushed onto the stack,
472 // OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a]
473 szBytes = codeBytes.GetItems(4);
476 catch (WrappedListException)
478 // Unable to read operand length
482 int nSize = (int)Interop.BEBytesToUInt32(szBytes);
486 // If nSize is greater than zero then there is some data available
489 // Read found number of bytes into list of OP_PUSHDATAn arguments.
490 bytesRet = codeBytes.GetEnumerableItems(nSize);
492 catch (WrappedListException)
494 // Unable to read data
506 /// Convert value bytes into readable representation.
508 /// If list lengh is equal or lesser than 4 bytes then bytes are interpreted as integer value. Otherwise you will get hex representation of supplied data.
510 /// <param name="bytes">Collection of value bytes.</param>
511 /// <returns>Formatted value.</returns>
512 public static string ValueString(IEnumerable<byte> bytes)
514 StringBuilder sb = new StringBuilder();
516 if (bytes.Count() <= 4)
518 byte[] valueBytes = new byte[4] {0, 0, 0, 0};
519 bytes.ToArray().CopyTo(valueBytes, valueBytes.Length - bytes.Count());
521 sb.Append(Interop.BEBytesToUInt32(valueBytes));
525 return Interop.ToHex(bytes);
528 return sb.ToString();
532 /// Convert list of stack items into human readable representation.
534 /// <param name="stackList">List of stack items.</param>
535 /// <returns>Formatted value.</returns>
536 public static string StackString(IList<IList<byte>> stackList)
538 StringBuilder sb = new StringBuilder();
539 foreach(IList<byte> bytesList in stackList)
541 sb.Append(ValueString(bytesList));
544 return sb.ToString();
548 /// Decode small integer
550 /// <param name="opcode">Small integer opcode (OP_0 - OP_16)</param>
551 /// <returns>Small integer</returns>
552 public static int DecodeOP_N(opcodetype opcode)
554 if (opcode == opcodetype.OP_0)
557 // Only OP_n opcodes are supported, throw exception otherwise.
558 if (opcode < opcodetype.OP_1 || opcode > opcodetype.OP_16)
559 throw new Exception("Invalid small integer opcode.");
560 return (int)opcode - (int)(opcodetype.OP_1 - 1);
564 /// Converts small integer into opcode
566 /// <param name="n">Small integer from the range of 0 up to 16.</param>
567 /// <returns>Corresponding opcode.</returns>
568 public static opcodetype EncodeOP_N(int n)
570 // The n value must be in the range of 0 to 16.
572 throw new Exception("Invalid small integer value.");
574 return opcodetype.OP_0;
575 return (opcodetype)(opcodetype.OP_1 + n - 1);