2 using System.Collections.Generic;
5 using System.Threading.Tasks;
12 public enum opcodetype
54 OP_FROMALTSTACK = 0x6c,
86 OP_EQUALVERIFY = 0x88,
111 OP_NUMEQUALVERIFY = 0x9d,
112 OP_NUMNOTEQUAL = 0x9e,
114 OP_GREATERTHAN = 0xa0,
115 OP_LESSTHANOREQUAL = 0xa1,
116 OP_GREATERTHANOREQUAL = 0xa2,
128 OP_CODESEPARATOR = 0xab,
130 OP_CHECKSIGVERIFY = 0xad,
131 OP_CHECKMULTISIG = 0xae,
132 OP_CHECKMULTISIGVERIFY = 0xaf,
146 // template matching params
148 OP_SMALLINTEGER = 0xfa,
150 OP_PUBKEYHASH = 0xfd,
153 OP_INVALIDOPCODE = 0xff,
156 public static class ScriptOpcode
160 /// Get the name of supplied opcode
162 /// <param name="opcode">Opcode</param>
163 /// <returns>Opcode name</returns>
164 public static string GetOpName(opcodetype opcode)
169 case opcodetype.OP_0:
171 case opcodetype.OP_PUSHDATA1:
172 return "OP_PUSHDATA1";
173 case opcodetype.OP_PUSHDATA2:
174 return "OP_PUSHDATA2";
175 case opcodetype.OP_PUSHDATA4:
176 return "OP_PUSHDATA4";
177 case opcodetype.OP_1NEGATE:
179 case opcodetype.OP_RESERVED:
180 return "OP_RESERVED";
181 case opcodetype.OP_1:
183 case opcodetype.OP_2:
185 case opcodetype.OP_3:
187 case opcodetype.OP_4:
189 case opcodetype.OP_5:
191 case opcodetype.OP_6:
193 case opcodetype.OP_7:
195 case opcodetype.OP_8:
197 case opcodetype.OP_9:
199 case opcodetype.OP_10:
201 case opcodetype.OP_11:
203 case opcodetype.OP_12:
205 case opcodetype.OP_13:
207 case opcodetype.OP_14:
209 case opcodetype.OP_15:
211 case opcodetype.OP_16:
215 case opcodetype.OP_NOP:
217 case opcodetype.OP_VER:
219 case opcodetype.OP_IF:
221 case opcodetype.OP_NOTIF:
223 case opcodetype.OP_VERIF:
225 case opcodetype.OP_VERNOTIF:
226 return "OP_VERNOTIF";
227 case opcodetype.OP_ELSE:
229 case opcodetype.OP_ENDIF:
231 case opcodetype.OP_VERIFY:
233 case opcodetype.OP_RETURN:
237 case opcodetype.OP_TOALTSTACK:
238 return "OP_TOALTSTACK";
239 case opcodetype.OP_FROMALTSTACK:
240 return "OP_FROMALTSTACK";
241 case opcodetype.OP_2DROP:
243 case opcodetype.OP_2DUP:
245 case opcodetype.OP_3DUP:
247 case opcodetype.OP_2OVER:
249 case opcodetype.OP_2ROT:
251 case opcodetype.OP_2SWAP:
253 case opcodetype.OP_IFDUP:
255 case opcodetype.OP_DEPTH:
257 case opcodetype.OP_DROP:
259 case opcodetype.OP_DUP:
261 case opcodetype.OP_NIP:
263 case opcodetype.OP_OVER:
265 case opcodetype.OP_PICK:
267 case opcodetype.OP_ROLL:
269 case opcodetype.OP_ROT:
271 case opcodetype.OP_SWAP:
273 case opcodetype.OP_TUCK:
277 case opcodetype.OP_CAT:
279 case opcodetype.OP_SUBSTR:
281 case opcodetype.OP_LEFT:
283 case opcodetype.OP_RIGHT:
285 case opcodetype.OP_SIZE:
289 case opcodetype.OP_INVERT:
291 case opcodetype.OP_AND:
293 case opcodetype.OP_OR:
295 case opcodetype.OP_XOR:
297 case opcodetype.OP_EQUAL:
299 case opcodetype.OP_EQUALVERIFY:
300 return "OP_EQUALVERIFY";
301 case opcodetype.OP_RESERVED1:
302 return "OP_RESERVED1";
303 case opcodetype.OP_RESERVED2:
304 return "OP_RESERVED2";
307 case opcodetype.OP_1ADD:
309 case opcodetype.OP_1SUB:
311 case opcodetype.OP_2MUL:
313 case opcodetype.OP_2DIV:
315 case opcodetype.OP_NEGATE:
317 case opcodetype.OP_ABS:
319 case opcodetype.OP_NOT:
321 case opcodetype.OP_0NOTEQUAL:
322 return "OP_0NOTEQUAL";
323 case opcodetype.OP_ADD:
325 case opcodetype.OP_SUB:
327 case opcodetype.OP_MUL:
329 case opcodetype.OP_DIV:
331 case opcodetype.OP_MOD:
333 case opcodetype.OP_LSHIFT:
335 case opcodetype.OP_RSHIFT:
337 case opcodetype.OP_BOOLAND:
339 case opcodetype.OP_BOOLOR:
341 case opcodetype.OP_NUMEQUAL:
342 return "OP_NUMEQUAL";
343 case opcodetype.OP_NUMEQUALVERIFY:
344 return "OP_NUMEQUALVERIFY";
345 case opcodetype.OP_NUMNOTEQUAL:
346 return "OP_NUMNOTEQUAL";
347 case opcodetype.OP_LESSTHAN:
348 return "OP_LESSTHAN";
349 case opcodetype.OP_GREATERTHAN:
350 return "OP_GREATERTHAN";
351 case opcodetype.OP_LESSTHANOREQUAL:
352 return "OP_LESSTHANOREQUAL";
353 case opcodetype.OP_GREATERTHANOREQUAL:
354 return "OP_GREATERTHANOREQUAL";
355 case opcodetype.OP_MIN:
357 case opcodetype.OP_MAX:
359 case opcodetype.OP_WITHIN:
363 case opcodetype.OP_RIPEMD160:
364 return "OP_RIPEMD160";
365 case opcodetype.OP_SHA1:
367 case opcodetype.OP_SHA256:
369 case opcodetype.OP_HASH160:
371 case opcodetype.OP_HASH256:
373 case opcodetype.OP_CODESEPARATOR:
374 return "OP_CODESEPARATOR";
375 case opcodetype.OP_CHECKSIG:
376 return "OP_CHECKSIG";
377 case opcodetype.OP_CHECKSIGVERIFY:
378 return "OP_CHECKSIGVERIFY";
379 case opcodetype.OP_CHECKMULTISIG:
380 return "OP_CHECKMULTISIG";
381 case opcodetype.OP_CHECKMULTISIGVERIFY:
382 return "OP_CHECKMULTISIGVERIFY";
385 case opcodetype.OP_NOP1:
387 case opcodetype.OP_NOP2:
389 case opcodetype.OP_NOP3:
391 case opcodetype.OP_NOP4:
393 case opcodetype.OP_NOP5:
395 case opcodetype.OP_NOP6:
397 case opcodetype.OP_NOP7:
399 case opcodetype.OP_NOP8:
401 case opcodetype.OP_NOP9:
403 case opcodetype.OP_NOP10:
406 // template matching params
407 case opcodetype.OP_PUBKEYHASH:
408 return "OP_PUBKEYHASH";
409 case opcodetype.OP_PUBKEY:
411 case opcodetype.OP_SMALLDATA:
412 return "OP_SMALLDATA";
414 case opcodetype.OP_INVALIDOPCODE:
415 return "OP_INVALIDOPCODE";
422 /// Get next opcode from passed list of bytes and extract push arguments if there are some.
424 /// <param name="codeBytes">WrappedList reference.</param>
425 /// <param name="opcodeRet">Found opcode.</param>
426 /// <param name="bytesRet">IEnumerable out param which is used to get the push arguments.</param>
427 /// <returns>Result of operation</returns>
428 public static bool GetOp(ref WrappedList<byte> codeBytes, out opcodetype opcodeRet, out IEnumerable<byte> bytesRet)
430 bytesRet = new List<byte>();
431 opcodeRet = opcodetype.OP_INVALIDOPCODE;
438 opcode = (opcodetype)codeBytes.GetItem();
440 catch (WrappedListException)
442 // No instruction found there
447 if (opcode <= opcodetype.OP_PUSHDATA4)
449 byte[] szBytes = new byte[4] {0, 0, 0, 0}; // Zero length
453 if (opcode < opcodetype.OP_PUSHDATA1)
455 // Zero value opcodes (OP_0, OP_FALSE)
456 szBytes[3] = (byte)opcode;
458 else if (opcode == opcodetype.OP_PUSHDATA1)
460 // The next byte contains the number of bytes to be pushed onto the stack,
461 // i.e. you have something like OP_PUSHDATA1 0x01 [0x5a]
462 szBytes[3] = (byte) codeBytes.GetItem();
464 else if (opcode == opcodetype.OP_PUSHDATA2)
466 // The next two bytes contain the number of bytes to be pushed onto the stack,
467 // i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a]
468 codeBytes.GetItems(2).CopyTo(szBytes, 2);
470 else if (opcode == opcodetype.OP_PUSHDATA4)
472 // The next four bytes contain the number of bytes to be pushed onto the stack,
473 // OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a]
474 szBytes = codeBytes.GetItems(4);
477 catch (WrappedListException)
479 // Unable to read operand length
483 // Reverse array if we are on little-endian machine
484 if (BitConverter.IsLittleEndian)
486 Array.Reverse(szBytes);
489 int nSize = BitConverter.ToInt32(szBytes, 0);
493 // If nSize is greater than zero then there is some data available
496 // Read found number of bytes into list of OP_PUSHDATAn arguments.
497 bytesRet = codeBytes.GetEnumerableItems(nSize);
499 catch (WrappedListException)
501 // Unable to read data
513 /// Convert value bytes into readable representation.
515 /// 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.
517 /// <param name="bytes">Collection of value bytes.</param>
518 /// <returns>Formatted value.</returns>
519 public static string ValueString(IEnumerable<byte> bytes)
521 StringBuilder sb = new StringBuilder();
523 if (bytes.Count() <= 4)
525 byte[] valueBytes = new byte[4] {0, 0, 0, 0};
526 bytes.ToArray().CopyTo(valueBytes, valueBytes.Length - bytes.Count());
528 // Reverse array if we are on little-endian machine
529 if (BitConverter.IsLittleEndian)
531 Array.Reverse(valueBytes);
534 sb.Append(BitConverter.ToInt32(valueBytes, 0));
538 foreach (byte b in bytes)
540 sb.AppendFormat("{0:x2}", b);
544 return sb.ToString();
548 /// Convert list of stack items into human readable representation.
550 /// <param name="stackList">List of stack items.</param>
551 /// <returns>Formatted value.</returns>
552 public static string StackString(IList<IList<byte>> stackList)
554 StringBuilder sb = new StringBuilder();
555 foreach(IList<byte> bytesList in stackList)
557 sb.Append(ValueString(bytesList));
560 return sb.ToString();
564 /// Decode small integer
566 /// <param name="opcode">Small integer opcode (OP_0 - OP_16)</param>
567 /// <returns>Small integer</returns>
568 static int DecodeOP_N(opcodetype opcode)
570 if (opcode == opcodetype.OP_0)
573 // Only OP_n opcodes are supported, throw exception otherwise.
574 if (opcode < opcodetype.OP_1 || opcode > opcodetype.OP_16)
575 throw new Exception("Invalid small integer opcode.");
576 return (int)opcode - (int)(opcodetype.OP_1 - 1);
580 /// Converts small integer into opcode
582 /// <param name="n">Small integer from the range of 0 up to 16.</param>
583 /// <returns>Corresponding opcode.</returns>
584 static opcodetype EncodeOP_N(int n)
586 // The n value must be in the range of 0 to 16.
588 throw new Exception("Invalid small integer value.");
590 return opcodetype.OP_0;
591 return (opcodetype)(opcodetype.OP_1 + n - 1);