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
183 public static string GetTxnOutputType(txnouttype t)
187 case txnouttype.TX_NONSTANDARD: return "nonstandard";
188 case txnouttype.TX_PUBKEY: return "pubkey";
189 case txnouttype.TX_PUBKEYHASH: return "pubkeyhash";
190 case txnouttype.TX_SCRIPTHASH: return "scripthash";
191 case txnouttype.TX_MULTISIG: return "multisig";
192 case txnouttype.TX_NULL_DATA: return "nulldata";
198 /// Get the name of supplied opcode
200 /// <param name="opcode">Opcode</param>
201 /// <returns>Opcode name</returns>
202 public static string GetOpName(opcodetype opcode)
207 case opcodetype.OP_0:
209 case opcodetype.OP_PUSHDATA1:
210 return "OP_PUSHDATA1";
211 case opcodetype.OP_PUSHDATA2:
212 return "OP_PUSHDATA2";
213 case opcodetype.OP_PUSHDATA4:
214 return "OP_PUSHDATA4";
215 case opcodetype.OP_1NEGATE:
217 case opcodetype.OP_RESERVED:
218 return "OP_RESERVED";
219 case opcodetype.OP_1:
221 case opcodetype.OP_2:
223 case opcodetype.OP_3:
225 case opcodetype.OP_4:
227 case opcodetype.OP_5:
229 case opcodetype.OP_6:
231 case opcodetype.OP_7:
233 case opcodetype.OP_8:
235 case opcodetype.OP_9:
237 case opcodetype.OP_10:
239 case opcodetype.OP_11:
241 case opcodetype.OP_12:
243 case opcodetype.OP_13:
245 case opcodetype.OP_14:
247 case opcodetype.OP_15:
249 case opcodetype.OP_16:
253 case opcodetype.OP_NOP:
255 case opcodetype.OP_VER:
257 case opcodetype.OP_IF:
259 case opcodetype.OP_NOTIF:
261 case opcodetype.OP_VERIF:
263 case opcodetype.OP_VERNOTIF:
264 return "OP_VERNOTIF";
265 case opcodetype.OP_ELSE:
267 case opcodetype.OP_ENDIF:
269 case opcodetype.OP_VERIFY:
271 case opcodetype.OP_RETURN:
275 case opcodetype.OP_TOALTSTACK:
276 return "OP_TOALTSTACK";
277 case opcodetype.OP_FROMALTSTACK:
278 return "OP_FROMALTSTACK";
279 case opcodetype.OP_2DROP:
281 case opcodetype.OP_2DUP:
283 case opcodetype.OP_3DUP:
285 case opcodetype.OP_2OVER:
287 case opcodetype.OP_2ROT:
289 case opcodetype.OP_2SWAP:
291 case opcodetype.OP_IFDUP:
293 case opcodetype.OP_DEPTH:
295 case opcodetype.OP_DROP:
297 case opcodetype.OP_DUP:
299 case opcodetype.OP_NIP:
301 case opcodetype.OP_OVER:
303 case opcodetype.OP_PICK:
305 case opcodetype.OP_ROLL:
307 case opcodetype.OP_ROT:
309 case opcodetype.OP_SWAP:
311 case opcodetype.OP_TUCK:
315 case opcodetype.OP_CAT:
317 case opcodetype.OP_SUBSTR:
319 case opcodetype.OP_LEFT:
321 case opcodetype.OP_RIGHT:
323 case opcodetype.OP_SIZE:
327 case opcodetype.OP_INVERT:
329 case opcodetype.OP_AND:
331 case opcodetype.OP_OR:
333 case opcodetype.OP_XOR:
335 case opcodetype.OP_EQUAL:
337 case opcodetype.OP_EQUALVERIFY:
338 return "OP_EQUALVERIFY";
339 case opcodetype.OP_RESERVED1:
340 return "OP_RESERVED1";
341 case opcodetype.OP_RESERVED2:
342 return "OP_RESERVED2";
345 case opcodetype.OP_1ADD:
347 case opcodetype.OP_1SUB:
349 case opcodetype.OP_2MUL:
351 case opcodetype.OP_2DIV:
353 case opcodetype.OP_NEGATE:
355 case opcodetype.OP_ABS:
357 case opcodetype.OP_NOT:
359 case opcodetype.OP_0NOTEQUAL:
360 return "OP_0NOTEQUAL";
361 case opcodetype.OP_ADD:
363 case opcodetype.OP_SUB:
365 case opcodetype.OP_MUL:
367 case opcodetype.OP_DIV:
369 case opcodetype.OP_MOD:
371 case opcodetype.OP_LSHIFT:
373 case opcodetype.OP_RSHIFT:
375 case opcodetype.OP_BOOLAND:
377 case opcodetype.OP_BOOLOR:
379 case opcodetype.OP_NUMEQUAL:
380 return "OP_NUMEQUAL";
381 case opcodetype.OP_NUMEQUALVERIFY:
382 return "OP_NUMEQUALVERIFY";
383 case opcodetype.OP_NUMNOTEQUAL:
384 return "OP_NUMNOTEQUAL";
385 case opcodetype.OP_LESSTHAN:
386 return "OP_LESSTHAN";
387 case opcodetype.OP_GREATERTHAN:
388 return "OP_GREATERTHAN";
389 case opcodetype.OP_LESSTHANOREQUAL:
390 return "OP_LESSTHANOREQUAL";
391 case opcodetype.OP_GREATERTHANOREQUAL:
392 return "OP_GREATERTHANOREQUAL";
393 case opcodetype.OP_MIN:
395 case opcodetype.OP_MAX:
397 case opcodetype.OP_WITHIN:
401 case opcodetype.OP_RIPEMD160:
402 return "OP_RIPEMD160";
403 case opcodetype.OP_SHA1:
405 case opcodetype.OP_SHA256:
407 case opcodetype.OP_HASH160:
409 case opcodetype.OP_HASH256:
411 case opcodetype.OP_CODESEPARATOR:
412 return "OP_CODESEPARATOR";
413 case opcodetype.OP_CHECKSIG:
414 return "OP_CHECKSIG";
415 case opcodetype.OP_CHECKSIGVERIFY:
416 return "OP_CHECKSIGVERIFY";
417 case opcodetype.OP_CHECKMULTISIG:
418 return "OP_CHECKMULTISIG";
419 case opcodetype.OP_CHECKMULTISIGVERIFY:
420 return "OP_CHECKMULTISIGVERIFY";
423 case opcodetype.OP_NOP1:
425 case opcodetype.OP_NOP2:
427 case opcodetype.OP_NOP3:
429 case opcodetype.OP_NOP4:
431 case opcodetype.OP_NOP5:
433 case opcodetype.OP_NOP6:
435 case opcodetype.OP_NOP7:
437 case opcodetype.OP_NOP8:
439 case opcodetype.OP_NOP9:
441 case opcodetype.OP_NOP10:
444 // template matching params
445 case opcodetype.OP_PUBKEYHASH:
446 return "OP_PUBKEYHASH";
447 case opcodetype.OP_PUBKEY:
449 case opcodetype.OP_SMALLDATA:
450 return "OP_SMALLDATA";
452 case opcodetype.OP_INVALIDOPCODE:
453 return "OP_INVALIDOPCODE";
460 /// Get next opcode from passed list of bytes and extract push arguments if there are some.
462 /// <param name="codeBytes">WrappedList reference.</param>
463 /// <param name="opcodeRet">Found opcode.</param>
464 /// <param name="bytesRet">IEnumerable out param which is used to get the push arguments.</param>
465 /// <returns>Result of operation</returns>
466 public static bool GetOp(ref WrappedList<byte> codeBytes, out opcodetype opcodeRet, out IEnumerable<byte> bytesRet)
468 bytesRet = new List<byte>();
469 opcodeRet = opcodetype.OP_INVALIDOPCODE;
476 opcode = (opcodetype)codeBytes.GetItem();
478 catch (WrappedListException)
480 // No instruction found there
485 if (opcode <= opcodetype.OP_PUSHDATA4)
487 byte[] szBytes = new byte[4] { 0, 0, 0, 0 }; // Zero length
491 if (opcode < opcodetype.OP_PUSHDATA1)
493 // Zero value opcodes (OP_0, OP_FALSE)
494 szBytes[3] = (byte)opcode;
496 else if (opcode == opcodetype.OP_PUSHDATA1)
498 // The next byte contains the number of bytes to be pushed onto the stack,
499 // i.e. you have something like OP_PUSHDATA1 0x01 [0x5a]
500 szBytes[3] = (byte)codeBytes.GetItem();
502 else if (opcode == opcodetype.OP_PUSHDATA2)
504 // The next two bytes contain the number of bytes to be pushed onto the stack,
505 // i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a]
506 codeBytes.GetItems(2).CopyTo(szBytes, 2);
508 else if (opcode == opcodetype.OP_PUSHDATA4)
510 // The next four bytes contain the number of bytes to be pushed onto the stack,
511 // OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a]
512 szBytes = codeBytes.GetItems(4);
515 catch (WrappedListException)
517 // Unable to read operand length
521 int nSize = (int)Interop.BEBytesToUInt32(szBytes);
525 // If nSize is greater than zero then there is some data available
528 // Read found number of bytes into list of OP_PUSHDATAn arguments.
529 bytesRet = codeBytes.GetEnumerableItems(nSize);
531 catch (WrappedListException)
533 // Unable to read data
545 /// Convert value bytes into readable representation.
547 /// 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.
549 /// <param name="bytes">Collection of value bytes.</param>
550 /// <returns>Formatted value.</returns>
551 public static string ValueString(IEnumerable<byte> bytes)
553 StringBuilder sb = new StringBuilder();
555 if (bytes.Count() <= 4)
557 byte[] valueBytes = new byte[4] { 0, 0, 0, 0 };
558 bytes.ToArray().CopyTo(valueBytes, valueBytes.Length - bytes.Count());
560 sb.Append(Interop.BEBytesToUInt32(valueBytes));
564 return Interop.ToHex(bytes);
567 return sb.ToString();
571 /// Convert list of stack items into human readable representation.
573 /// <param name="stackList">List of stack items.</param>
574 /// <returns>Formatted value.</returns>
575 public static string StackString(IList<IList<byte>> stackList)
577 StringBuilder sb = new StringBuilder();
578 foreach (IList<byte> bytesList in stackList)
580 sb.Append(ValueString(bytesList));
583 return sb.ToString();
587 /// Decode small integer
589 /// <param name="opcode">Small integer opcode (OP_0 - OP_16)</param>
590 /// <returns>Small integer</returns>
591 public static int DecodeOP_N(opcodetype opcode)
593 if (opcode == opcodetype.OP_0)
596 // Only OP_n opcodes are supported, throw exception otherwise.
597 if (opcode < opcodetype.OP_1 || opcode > opcodetype.OP_16)
598 throw new Exception("Invalid small integer opcode.");
599 return (int)opcode - (int)(opcodetype.OP_1 - 1);
603 /// Converts small integer into opcode
605 /// <param name="n">Small integer from the range of 0 up to 16.</param>
606 /// <returns>Corresponding opcode.</returns>
607 public static opcodetype EncodeOP_N(int n)
609 // The n value must be in the range of 0 to 16.
611 throw new Exception("Invalid small integer value.");
613 return opcodetype.OP_0;
614 return (opcodetype)(opcodetype.OP_1 + n - 1);
617 public static int ScriptSigArgsExpected(txnouttype t, IList<IEnumerable<byte>> solutions)
621 case txnouttype.TX_NONSTANDARD:
623 case txnouttype.TX_NULL_DATA:
625 case txnouttype.TX_PUBKEY:
627 case txnouttype.TX_PUBKEYHASH:
629 case txnouttype.TX_MULTISIG:
630 if (solutions.Count() < 1 || solutions.First().Count() < 1)
632 return solutions.First().First() + 1;
633 case txnouttype.TX_SCRIPTHASH:
634 return 1; // doesn't include args needed by the script
640 /// Is it a standart type of scriptPubKey?
642 /// <param name="scriptPubKey">CScript instance</param>
643 /// <param name="whichType">utut type</param>
644 /// <returns>Checking result</returns>
645 public static bool IsStandard(CScript scriptPubKey, out txnouttype whichType)
647 IList<IEnumerable<byte>> solutions = new List<IEnumerable<byte>>();
649 if (!Solver(scriptPubKey, out whichType, out solutions))
651 // No solutions found
655 if (whichType == txnouttype.TX_MULTISIG)
657 // Additional verification of OP_CHECKMULTISIG arguments
658 byte m = solutions.First().First();
659 byte n = solutions.Last().First();
661 // Support up to x-of-3 multisig txns as standard
672 return whichType != txnouttype.TX_NONSTANDARD;
676 /// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
678 /// <param name="scriptPubKey">CScript instance</param>
679 /// <param name="typeRet">Output type</param>
680 /// <param name="solutions">Set of solutions</param>
681 /// <returns>Result</returns>
682 public static bool Solver(CScript scriptPubKey, out txnouttype typeRet, out IList<IEnumerable<byte>> solutions)
684 solutions = new List<IEnumerable<byte>>();
686 // There are shortcuts for pay-to-script-hash and pay-to-pubkey-hash, which are more constrained than the other types:
688 // It is always OP_HASH160 20 [20 byte hash] OP_EQUAL
689 if (scriptPubKey.IsPayToScriptHash)
691 typeRet = txnouttype.TX_SCRIPTHASH;
693 // Take 20 bytes with offset of 2 bytes
694 IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(2).Take(20);
695 solutions.Add(hashBytes);
700 // It is always OP_DUP OP_HASH160 20 [20 byte hash] OP_EQUALVERIFY OP_CHECKSIG
701 if (scriptPubKey.IsPayToPubKeyHash)
703 typeRet = txnouttype.TX_PUBKEYHASH;
705 // Take 20 bytes with offset of 3 bytes
706 IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(3).Take(20);
707 solutions.Add(hashBytes);
712 List<Tuple<txnouttype, IEnumerable<byte>>> templateTuples = new List<Tuple<txnouttype, IEnumerable<byte>>>();
714 // Sender provides pubkey, receiver adds signature
715 // [ECDSA public key] OP_CHECKSIG
717 new Tuple<txnouttype, IEnumerable<byte>>(
718 txnouttype.TX_PUBKEY,
719 new byte[] { (byte)opcodetype.OP_PUBKEY, (byte)opcodetype.OP_CHECKSIG })
722 // Sender provides N pubkeys, receivers provides M signatures
723 // N [pubkey1] [pubkey2] ... [pubkeyN] M OP_CHECKMULTISIG
724 // Where N and M are small integer opcodes (OP1 ... OP_16)
726 new Tuple<txnouttype, IEnumerable<byte>>(
727 txnouttype.TX_MULTISIG,
728 new byte[] { (byte)opcodetype.OP_SMALLINTEGER, (byte)opcodetype.OP_PUBKEYS, (byte)opcodetype.OP_SMALLINTEGER, (byte)opcodetype.OP_CHECKMULTISIG })
731 // Data-carrying output
732 // OP_RETURN [up to 80 bytes of data]
734 new Tuple<txnouttype, IEnumerable<byte>>(
735 txnouttype.TX_NULL_DATA,
736 new byte[] { (byte)opcodetype.OP_RETURN, (byte)opcodetype.OP_SMALLDATA })
739 // Nonstandard tx output
740 typeRet = txnouttype.TX_NONSTANDARD;
742 foreach (Tuple<txnouttype, IEnumerable<byte>> templateTuple in templateTuples)
744 CScript script1 = scriptPubKey;
745 CScript script2 = new CScript(templateTuple.Item2);
747 opcodetype opcode1, opcode2;
750 WrappedList<byte> wl1 = script1.GetWrappedList();
751 WrappedList<byte> wl2 = script2.GetWrappedList();
753 IEnumerable<byte> args1, args2;
755 byte last1 = script1.Bytes.Last();
756 byte last2 = script2.Bytes.Last();
760 if (wl1.GetCurrentItem() == last1 && wl2.GetCurrentItem() == last2)
763 typeRet = templateTuple.Item1;
764 if (typeRet == txnouttype.TX_MULTISIG)
766 // Additional checks for TX_MULTISIG:
767 byte m = solutions.First().First();
768 byte n = solutions.Last().First();
770 if (m < 1 || n < 1 || m > n || solutions.Count - 2 != n)
778 if (!GetOp(ref wl1, out opcode1, out args1))
782 if (!GetOp(ref wl2, out opcode2, out args2))
787 // Template matching opcodes:
788 if (opcode2 == opcodetype.OP_PUBKEYS)
790 while (args1.Count() >= 33 && args1.Count() <= 120)
792 solutions.Add(args1);
793 if (!GetOp(ref wl1, out opcode1, out args1))
798 if (!GetOp(ref wl2, out opcode2, out args2))
800 // Normal situation is to fall through
801 // to other if/else statements
803 if (opcode2 == opcodetype.OP_PUBKEY)
805 if (args1.Count() < 33 || args1.Count() > 120)
809 solutions.Add(args1);
811 else if (opcode2 == opcodetype.OP_PUBKEYHASH)
813 if (args1.Count() != 20) // hash160 size
817 solutions.Add(args1);
819 else if (opcode2 == opcodetype.OP_SMALLINTEGER)
821 // Single-byte small integer pushed onto solutions
822 if (opcode1 == opcodetype.OP_0 || (opcode1 >= opcodetype.OP_1 && opcode1 <= opcodetype.OP_16))
824 byte n = (byte)DecodeOP_N(opcode1);
825 solutions.Add(new byte[] { n });
832 else if (opcode2 == opcodetype.OP_SMALLDATA)
834 // small pushdata, <= 80 bytes
835 if (args1.Count() > 80)
840 else if (opcode1 != opcode2 || !args1.SequenceEqual(args2))
842 // Others must match exactly
849 typeRet = txnouttype.TX_NONSTANDARD;
854 public static Hash256 SignatureHash(CScript scriptCode, CTransaction txTo, int nIn, int nHashType)
856 if (nIn >= txTo.vin.Length)
858 StringBuilder sb = new StringBuilder();
859 sb.AppendFormat("ERROR: SignatureHash() : nIn={0} out of range\n", nIn);
860 throw new ArgumentOutOfRangeException("nIn", sb.ToString());
863 CTransaction txTmp = new CTransaction(txTo);
865 // In case concatenating two scripts ends up with two codeseparators,
866 // or an extra one at the end, this prevents all those possible incompatibilities.
867 scriptCode.RemovePattern(new byte[] { (byte)opcodetype.OP_CODESEPARATOR });
869 // Blank out other inputs' signatures
870 for (int i = 0; i < txTmp.vin.Length; i++)
872 txTmp.vin[i].scriptSig = new CScript();
874 txTmp.vin[nIn].scriptSig = scriptCode;
876 // Blank out some of the outputs
877 if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_NONE)
880 txTmp.vout = new CTxOut[0];
882 // Let the others update at will
883 for (int i = 0; i < txTmp.vin.Length; i++)
887 txTmp.vin[i].nSequence = 0;
891 else if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_SINGLE)
893 // Only lock-in the txout payee at same index as txin
895 if (nOut >= txTmp.vout.Length)
897 StringBuilder sb = new StringBuilder();
898 sb.AppendFormat("ERROR: SignatureHash() : nOut={0} out of range\n", nOut);
899 throw new ArgumentOutOfRangeException("nOut", sb.ToString());
901 Array.Resize(ref txTmp.vout, nOut + 1);
903 for (int i = 0; i < nOut; i++)
905 txTmp.vout[i] = new CTxOut();
908 // Let the others update at will
909 for (int i = 0; i < txTmp.vin.Length; i++)
913 txTmp.vin[i].nSequence = 0;
918 // Blank out other inputs completely, not recommended for open transactions
919 if ((nHashType & (int)sigflag.SIGHASH_ANYONECANPAY) != 0)
921 txTmp.vin[0] = txTmp.vin[nIn];
922 Array.Resize(ref txTmp.vin, 1);
925 // Serialize and hash
926 List<byte> b = new List<byte>();
927 b.AddRange(txTmp.Bytes);
928 b.AddRange(BitConverter.GetBytes(nHashType));
930 return Hash256.Compute256(b);