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,
156 /// Transaction output types.
158 public enum txnouttype
162 // 'standard' transaction types:
171 /// Signature hash types/flags
178 SIGHASH_ANYONECANPAY = 0x80,
181 public static class ScriptCode
185 /// Get the name of supplied opcode
187 /// <param name="opcode">Opcode</param>
188 /// <returns>Opcode name</returns>
189 public static string GetOpName(opcodetype opcode)
194 case opcodetype.OP_0:
196 case opcodetype.OP_PUSHDATA1:
197 return "OP_PUSHDATA1";
198 case opcodetype.OP_PUSHDATA2:
199 return "OP_PUSHDATA2";
200 case opcodetype.OP_PUSHDATA4:
201 return "OP_PUSHDATA4";
202 case opcodetype.OP_1NEGATE:
204 case opcodetype.OP_RESERVED:
205 return "OP_RESERVED";
206 case opcodetype.OP_1:
208 case opcodetype.OP_2:
210 case opcodetype.OP_3:
212 case opcodetype.OP_4:
214 case opcodetype.OP_5:
216 case opcodetype.OP_6:
218 case opcodetype.OP_7:
220 case opcodetype.OP_8:
222 case opcodetype.OP_9:
224 case opcodetype.OP_10:
226 case opcodetype.OP_11:
228 case opcodetype.OP_12:
230 case opcodetype.OP_13:
232 case opcodetype.OP_14:
234 case opcodetype.OP_15:
236 case opcodetype.OP_16:
240 case opcodetype.OP_NOP:
242 case opcodetype.OP_VER:
244 case opcodetype.OP_IF:
246 case opcodetype.OP_NOTIF:
248 case opcodetype.OP_VERIF:
250 case opcodetype.OP_VERNOTIF:
251 return "OP_VERNOTIF";
252 case opcodetype.OP_ELSE:
254 case opcodetype.OP_ENDIF:
256 case opcodetype.OP_VERIFY:
258 case opcodetype.OP_RETURN:
262 case opcodetype.OP_TOALTSTACK:
263 return "OP_TOALTSTACK";
264 case opcodetype.OP_FROMALTSTACK:
265 return "OP_FROMALTSTACK";
266 case opcodetype.OP_2DROP:
268 case opcodetype.OP_2DUP:
270 case opcodetype.OP_3DUP:
272 case opcodetype.OP_2OVER:
274 case opcodetype.OP_2ROT:
276 case opcodetype.OP_2SWAP:
278 case opcodetype.OP_IFDUP:
280 case opcodetype.OP_DEPTH:
282 case opcodetype.OP_DROP:
284 case opcodetype.OP_DUP:
286 case opcodetype.OP_NIP:
288 case opcodetype.OP_OVER:
290 case opcodetype.OP_PICK:
292 case opcodetype.OP_ROLL:
294 case opcodetype.OP_ROT:
296 case opcodetype.OP_SWAP:
298 case opcodetype.OP_TUCK:
302 case opcodetype.OP_CAT:
304 case opcodetype.OP_SUBSTR:
306 case opcodetype.OP_LEFT:
308 case opcodetype.OP_RIGHT:
310 case opcodetype.OP_SIZE:
314 case opcodetype.OP_INVERT:
316 case opcodetype.OP_AND:
318 case opcodetype.OP_OR:
320 case opcodetype.OP_XOR:
322 case opcodetype.OP_EQUAL:
324 case opcodetype.OP_EQUALVERIFY:
325 return "OP_EQUALVERIFY";
326 case opcodetype.OP_RESERVED1:
327 return "OP_RESERVED1";
328 case opcodetype.OP_RESERVED2:
329 return "OP_RESERVED2";
332 case opcodetype.OP_1ADD:
334 case opcodetype.OP_1SUB:
336 case opcodetype.OP_2MUL:
338 case opcodetype.OP_2DIV:
340 case opcodetype.OP_NEGATE:
342 case opcodetype.OP_ABS:
344 case opcodetype.OP_NOT:
346 case opcodetype.OP_0NOTEQUAL:
347 return "OP_0NOTEQUAL";
348 case opcodetype.OP_ADD:
350 case opcodetype.OP_SUB:
352 case opcodetype.OP_MUL:
354 case opcodetype.OP_DIV:
356 case opcodetype.OP_MOD:
358 case opcodetype.OP_LSHIFT:
360 case opcodetype.OP_RSHIFT:
362 case opcodetype.OP_BOOLAND:
364 case opcodetype.OP_BOOLOR:
366 case opcodetype.OP_NUMEQUAL:
367 return "OP_NUMEQUAL";
368 case opcodetype.OP_NUMEQUALVERIFY:
369 return "OP_NUMEQUALVERIFY";
370 case opcodetype.OP_NUMNOTEQUAL:
371 return "OP_NUMNOTEQUAL";
372 case opcodetype.OP_LESSTHAN:
373 return "OP_LESSTHAN";
374 case opcodetype.OP_GREATERTHAN:
375 return "OP_GREATERTHAN";
376 case opcodetype.OP_LESSTHANOREQUAL:
377 return "OP_LESSTHANOREQUAL";
378 case opcodetype.OP_GREATERTHANOREQUAL:
379 return "OP_GREATERTHANOREQUAL";
380 case opcodetype.OP_MIN:
382 case opcodetype.OP_MAX:
384 case opcodetype.OP_WITHIN:
388 case opcodetype.OP_RIPEMD160:
389 return "OP_RIPEMD160";
390 case opcodetype.OP_SHA1:
392 case opcodetype.OP_SHA256:
394 case opcodetype.OP_HASH160:
396 case opcodetype.OP_HASH256:
398 case opcodetype.OP_CODESEPARATOR:
399 return "OP_CODESEPARATOR";
400 case opcodetype.OP_CHECKSIG:
401 return "OP_CHECKSIG";
402 case opcodetype.OP_CHECKSIGVERIFY:
403 return "OP_CHECKSIGVERIFY";
404 case opcodetype.OP_CHECKMULTISIG:
405 return "OP_CHECKMULTISIG";
406 case opcodetype.OP_CHECKMULTISIGVERIFY:
407 return "OP_CHECKMULTISIGVERIFY";
410 case opcodetype.OP_NOP1:
412 case opcodetype.OP_NOP2:
414 case opcodetype.OP_NOP3:
416 case opcodetype.OP_NOP4:
418 case opcodetype.OP_NOP5:
420 case opcodetype.OP_NOP6:
422 case opcodetype.OP_NOP7:
424 case opcodetype.OP_NOP8:
426 case opcodetype.OP_NOP9:
428 case opcodetype.OP_NOP10:
431 // template matching params
432 case opcodetype.OP_PUBKEYHASH:
433 return "OP_PUBKEYHASH";
434 case opcodetype.OP_PUBKEY:
436 case opcodetype.OP_SMALLDATA:
437 return "OP_SMALLDATA";
439 case opcodetype.OP_INVALIDOPCODE:
440 return "OP_INVALIDOPCODE";
447 /// Get next opcode from passed list of bytes and extract push arguments if there are some.
449 /// <param name="codeBytes">WrappedList reference.</param>
450 /// <param name="opcodeRet">Found opcode.</param>
451 /// <param name="bytesRet">IEnumerable out param which is used to get the push arguments.</param>
452 /// <returns>Result of operation</returns>
453 public static bool GetOp(ref WrappedList<byte> codeBytes, out opcodetype opcodeRet, out IEnumerable<byte> bytesRet)
455 bytesRet = new List<byte>();
456 opcodeRet = opcodetype.OP_INVALIDOPCODE;
463 opcode = (opcodetype)codeBytes.GetItem();
465 catch (WrappedListException)
467 // No instruction found there
472 if (opcode <= opcodetype.OP_PUSHDATA4)
474 byte[] szBytes = new byte[4] { 0, 0, 0, 0 }; // Zero length
478 if (opcode < opcodetype.OP_PUSHDATA1)
480 // Zero value opcodes (OP_0, OP_FALSE)
481 szBytes[3] = (byte)opcode;
483 else if (opcode == opcodetype.OP_PUSHDATA1)
485 // The next byte contains the number of bytes to be pushed onto the stack,
486 // i.e. you have something like OP_PUSHDATA1 0x01 [0x5a]
487 szBytes[3] = (byte)codeBytes.GetItem();
489 else if (opcode == opcodetype.OP_PUSHDATA2)
491 // The next two bytes contain the number of bytes to be pushed onto the stack,
492 // i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a]
493 codeBytes.GetItems(2).CopyTo(szBytes, 2);
495 else if (opcode == opcodetype.OP_PUSHDATA4)
497 // The next four bytes contain the number of bytes to be pushed onto the stack,
498 // OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a]
499 szBytes = codeBytes.GetItems(4);
502 catch (WrappedListException)
504 // Unable to read operand length
508 int nSize = (int)Interop.BEBytesToUInt32(szBytes);
512 // If nSize is greater than zero then there is some data available
515 // Read found number of bytes into list of OP_PUSHDATAn arguments.
516 bytesRet = codeBytes.GetEnumerableItems(nSize);
518 catch (WrappedListException)
520 // Unable to read data
532 /// Convert value bytes into readable representation.
534 /// 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.
536 /// <param name="bytes">Collection of value bytes.</param>
537 /// <returns>Formatted value.</returns>
538 public static string ValueString(IEnumerable<byte> bytes)
540 StringBuilder sb = new StringBuilder();
542 if (bytes.Count() <= 4)
544 byte[] valueBytes = new byte[4] { 0, 0, 0, 0 };
545 bytes.ToArray().CopyTo(valueBytes, valueBytes.Length - bytes.Count());
547 sb.Append(Interop.BEBytesToUInt32(valueBytes));
551 return Interop.ToHex(bytes);
554 return sb.ToString();
558 /// Convert list of stack items into human readable representation.
560 /// <param name="stackList">List of stack items.</param>
561 /// <returns>Formatted value.</returns>
562 public static string StackString(IList<IList<byte>> stackList)
564 StringBuilder sb = new StringBuilder();
565 foreach (IList<byte> bytesList in stackList)
567 sb.Append(ValueString(bytesList));
570 return sb.ToString();
574 /// Decode small integer
576 /// <param name="opcode">Small integer opcode (OP_0 - OP_16)</param>
577 /// <returns>Small integer</returns>
578 public static int DecodeOP_N(opcodetype opcode)
580 if (opcode == opcodetype.OP_0)
583 // Only OP_n opcodes are supported, throw exception otherwise.
584 if (opcode < opcodetype.OP_1 || opcode > opcodetype.OP_16)
585 throw new Exception("Invalid small integer opcode.");
586 return (int)opcode - (int)(opcodetype.OP_1 - 1);
590 /// Converts small integer into opcode
592 /// <param name="n">Small integer from the range of 0 up to 16.</param>
593 /// <returns>Corresponding opcode.</returns>
594 public static opcodetype EncodeOP_N(int n)
596 // The n value must be in the range of 0 to 16.
598 throw new Exception("Invalid small integer value.");
600 return opcodetype.OP_0;
601 return (opcodetype)(opcodetype.OP_1 + n - 1);
604 public static int ScriptSigArgsExpected(txnouttype t, IList<IEnumerable<byte>> solutions)
608 case txnouttype.TX_NONSTANDARD:
610 case txnouttype.TX_NULL_DATA:
612 case txnouttype.TX_PUBKEY:
614 case txnouttype.TX_PUBKEYHASH:
616 case txnouttype.TX_MULTISIG:
617 if (solutions.Count() < 1 || solutions.First().Count() < 1)
619 return solutions.First().First() + 1;
620 case txnouttype.TX_SCRIPTHASH:
621 return 1; // doesn't include args needed by the script
627 public static bool IsStandard(CScript scriptPubKey, out txnouttype whichType)
629 IList<IEnumerable<byte>> solutions = new List<IEnumerable<byte>>();
631 if (!Solver(scriptPubKey, out whichType, out solutions))
633 // No solutions found
637 if (whichType == txnouttype.TX_MULTISIG)
639 byte m = solutions.First().First();
640 byte n = solutions.Last().First();
642 // Support up to x-of-3 multisig txns as standard
653 return whichType != txnouttype.TX_NONSTANDARD;
657 /// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
659 /// <param name="scriptPubKey">CScript instance</param>
660 /// <param name="typeRet">Output type</param>
661 /// <param name="solutions">Set of solutions</param>
662 /// <returns>Result</returns>
663 public static bool Solver(CScript scriptPubKey, out txnouttype typeRet, out IList<IEnumerable<byte>> solutions)
665 solutions = new List<IEnumerable<byte>>();
667 // There are shortcuts for pay-to-script-hash and pay-to-pubkey-hash, which are more constrained than the other types:
669 // It is always OP_HASH160 20 [20 byte hash] OP_EQUAL
670 if (scriptPubKey.IsPayToScriptHash)
672 typeRet = txnouttype.TX_SCRIPTHASH;
674 // Take 20 bytes with offset of 2 bytes
675 IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(2).Take(20);
676 solutions.Add(hashBytes);
681 // It is always OP_DUP OP_HASH160 20 [20 byte hash] OP_EQUALVERIFY OP_CHECKSIG
682 if (scriptPubKey.IsPayToPubKeyHash)
684 typeRet = txnouttype.TX_PUBKEYHASH;
686 // Take 20 bytes with offset of 3 bytes
687 IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(3).Take(20);
688 solutions.Add(hashBytes);
693 List<Tuple<txnouttype, IEnumerable<byte>>> templateTuples = new List<Tuple<txnouttype, IEnumerable<byte>>>();
695 // Sender provides pubkey, receiver adds signature
696 // [ECDSA public key] OP_CHECKSIG
698 new Tuple<txnouttype, IEnumerable<byte>>(
699 txnouttype.TX_PUBKEY,
700 new byte[] { (byte)opcodetype.OP_PUBKEY, (byte)opcodetype.OP_CHECKSIG })
703 // Sender provides N pubkeys, receivers provides M signatures
704 // N [pubkey1] [pubkey2] ... [pubkeyN] M OP_CHECKMULTISIG
705 // Where N and M are small integer opcodes (OP1 ... OP_16)
707 new Tuple<txnouttype, IEnumerable<byte>>(
708 txnouttype.TX_MULTISIG,
709 new byte[] { (byte)opcodetype.OP_SMALLINTEGER, (byte)opcodetype.OP_PUBKEYS, (byte)opcodetype.OP_SMALLINTEGER, (byte)opcodetype.OP_CHECKMULTISIG })
712 // Data-carrying output
713 // OP_RETURN [up to 80 bytes of data]
715 new Tuple<txnouttype, IEnumerable<byte>>(
716 txnouttype.TX_NULL_DATA,
717 new byte[] { (byte)opcodetype.OP_RETURN, (byte)opcodetype.OP_SMALLDATA })
720 // Nonstandard tx output
721 typeRet = txnouttype.TX_NONSTANDARD;
723 foreach (Tuple<txnouttype, IEnumerable<byte>> templateTuple in templateTuples)
725 CScript script1 = scriptPubKey;
726 CScript script2 = new CScript(templateTuple.Item2);
728 opcodetype opcode1, opcode2;
731 WrappedList<byte> wl1 = script1.GetWrappedList();
732 WrappedList<byte> wl2 = script2.GetWrappedList();
734 IEnumerable<byte> args1, args2;
736 byte last1 = script1.Bytes.Last();
737 byte last2 = script2.Bytes.Last();
741 if (wl1.GetCurrentItem() == last1 && wl2.GetCurrentItem() == last2)
744 typeRet = templateTuple.Item1;
745 if (typeRet == txnouttype.TX_MULTISIG)
747 // Additional checks for TX_MULTISIG:
748 byte m = solutions.First().First();
749 byte n = solutions.Last().First();
751 if (m < 1 || n < 1 || m > n || solutions.Count - 2 != n)
759 if (!GetOp(ref wl1, out opcode1, out args1))
763 if (!GetOp(ref wl2, out opcode2, out args2))
768 // Template matching opcodes:
769 if (opcode2 == opcodetype.OP_PUBKEYS)
771 while (args1.Count() >= 33 && args1.Count() <= 120)
773 solutions.Add(args1);
774 if (!GetOp(ref wl1, out opcode1, out args1))
779 if (!GetOp(ref wl2, out opcode2, out args2))
781 // Normal situation is to fall through
782 // to other if/else statements
784 if (opcode2 == opcodetype.OP_PUBKEY)
786 if (args1.Count() < 33 || args1.Count() > 120)
790 solutions.Add(args1);
792 else if (opcode2 == opcodetype.OP_PUBKEYHASH)
794 if (args1.Count() != 20) // hash160 size
798 solutions.Add(args1);
800 else if (opcode2 == opcodetype.OP_SMALLINTEGER)
802 // Single-byte small integer pushed onto solutions
803 if (opcode1 == opcodetype.OP_0 || (opcode1 >= opcodetype.OP_1 && opcode1 <= opcodetype.OP_16))
805 byte n = (byte)DecodeOP_N(opcode1);
806 solutions.Add(new byte[] { n });
813 else if (opcode2 == opcodetype.OP_SMALLDATA)
815 // small pushdata, <= 80 bytes
816 if (args1.Count() > 80)
821 else if (opcode1 != opcode2 || !args1.SequenceEqual(args2))
823 // Others must match exactly
830 typeRet = txnouttype.TX_NONSTANDARD;
835 public static Hash256 SignatureHash(CScript scriptCode, CTransaction txTo, int nIn, int nHashType)
837 if (nIn >= txTo.vin.Length)
839 StringBuilder sb = new StringBuilder();
840 sb.AppendFormat("ERROR: SignatureHash() : nIn={0} out of range\n", nIn);
841 throw new ArgumentOutOfRangeException("nIn", sb.ToString());
844 CTransaction txTmp = new CTransaction(txTo);
846 // In case concatenating two scripts ends up with two codeseparators,
847 // or an extra one at the end, this prevents all those possible incompatibilities.
848 scriptCode.RemovePattern(new byte[] { (byte)opcodetype.OP_CODESEPARATOR });
850 // Blank out other inputs' signatures
851 for (int i = 0; i < txTmp.vin.Length; i++)
853 txTmp.vin[i].scriptSig = new CScript();
855 txTmp.vin[nIn].scriptSig = scriptCode;
857 // Blank out some of the outputs
858 if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_NONE)
863 // Let the others update at will
864 for (int i = 0; i < txTmp.vin.Length; i++)
868 txTmp.vin[i].nSequence = 0;
872 else if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_SINGLE)
874 // Only lock-in the txout payee at same index as txin
876 if (nOut >= txTmp.vout.Length)
878 StringBuilder sb = new StringBuilder();
879 sb.AppendFormat("ERROR: SignatureHash() : nOut={0} out of range\n", nOut);
880 throw new ArgumentOutOfRangeException("nOut", sb.ToString());
882 Array.Resize(ref txTmp.vout, nOut + 1);
884 for (int i = 0; i < nOut; i++)
886 txTmp.vout[i] = new CTxOut();
889 // Let the others update at will
890 for (int i = 0; i < txTmp.vin.Length; i++)
894 txTmp.vin[i].nSequence = 0;
899 // Blank out other inputs completely, not recommended for open transactions
900 if ((nHashType & (int)sigflag.SIGHASH_ANYONECANPAY) != 0)
902 txTmp.vin[0] = txTmp.vin[nIn];
903 Array.Resize(ref txTmp.vin, 1);
906 // Serialize and hash
907 List<byte> b = new List<byte>();
908 b.AddRange(txTmp.Bytes);
909 b.AddRange(BitConverter.GetBytes(nHashType));
911 return Hash256.Compute256(b);