Improve CryptoUtils with wrappers for managed implementations of standard hashing...
[NovacoinLibrary.git] / Novacoin / ScriptCode.cs
index 8f53feb..14bc2e5 100644 (file)
@@ -1,16 +1,32 @@
+/**
+ *  Novacoin classes library
+ *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
+
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 using System;
 using System.Collections.Generic;
+using System.Diagnostics.Contracts;
 using System.Linq;
-using System.Text;
-
 using System.Numerics;
-
-// using Org.BouncyCastle.Math;
+using System.Text;
 
 namespace Novacoin
 {
     /// <summary>
-    /// Script opcodes
+    /// Script instructions
     /// </summary>
     public enum instruction
     {
@@ -210,344 +226,82 @@ namespace Novacoin
         }
 
         /// <summary>
-        /// Get the name of supplied opcode
+        /// Get the name of instruction
         /// </summary>
-        /// <param name="opcode">Opcode</param>
-        /// <returns>Opcode name</returns>
+        /// <param name="opcode">Instruction</param>
+        /// <returns>Instruction name</returns>
         public static string GetOpName(instruction opcode)
         {
-            switch (opcode)
-            {
-                // push value
-                case instruction.OP_0:
-                    return "OP_0";
-                case instruction.OP_PUSHDATA1:
-                    return "OP_PUSHDATA1";
-                case instruction.OP_PUSHDATA2:
-                    return "OP_PUSHDATA2";
-                case instruction.OP_PUSHDATA4:
-                    return "OP_PUSHDATA4";
-                case instruction.OP_1NEGATE:
-                    return "OP_1NEGATE";
-                case instruction.OP_RESERVED:
-                    return "OP_RESERVED";
-                case instruction.OP_1:
-                    return "OP_1";
-                case instruction.OP_2:
-                    return "OP_2";
-                case instruction.OP_3:
-                    return "OP_3";
-                case instruction.OP_4:
-                    return "OP_4";
-                case instruction.OP_5:
-                    return "OP_5";
-                case instruction.OP_6:
-                    return "OP_6";
-                case instruction.OP_7:
-                    return "OP_7";
-                case instruction.OP_8:
-                    return "OP_8";
-                case instruction.OP_9:
-                    return "OP_9";
-                case instruction.OP_10:
-                    return "OP_10";
-                case instruction.OP_11:
-                    return "OP_11";
-                case instruction.OP_12:
-                    return "OP_12";
-                case instruction.OP_13:
-                    return "OP_13";
-                case instruction.OP_14:
-                    return "OP_14";
-                case instruction.OP_15:
-                    return "OP_15";
-                case instruction.OP_16:
-                    return "OP_16";
-
-                // control
-                case instruction.OP_NOP:
-                    return "OP_NOP";
-                case instruction.OP_VER:
-                    return "OP_VER";
-                case instruction.OP_IF:
-                    return "OP_IF";
-                case instruction.OP_NOTIF:
-                    return "OP_NOTIF";
-                case instruction.OP_VERIF:
-                    return "OP_VERIF";
-                case instruction.OP_VERNOTIF:
-                    return "OP_VERNOTIF";
-                case instruction.OP_ELSE:
-                    return "OP_ELSE";
-                case instruction.OP_ENDIF:
-                    return "OP_ENDIF";
-                case instruction.OP_VERIFY:
-                    return "OP_VERIFY";
-                case instruction.OP_RETURN:
-                    return "OP_RETURN";
-
-                // stack ops
-                case instruction.OP_TOALTSTACK:
-                    return "OP_TOALTSTACK";
-                case instruction.OP_FROMALTSTACK:
-                    return "OP_FROMALTSTACK";
-                case instruction.OP_2DROP:
-                    return "OP_2DROP";
-                case instruction.OP_2DUP:
-                    return "OP_2DUP";
-                case instruction.OP_3DUP:
-                    return "OP_3DUP";
-                case instruction.OP_2OVER:
-                    return "OP_2OVER";
-                case instruction.OP_2ROT:
-                    return "OP_2ROT";
-                case instruction.OP_2SWAP:
-                    return "OP_2SWAP";
-                case instruction.OP_IFDUP:
-                    return "OP_IFDUP";
-                case instruction.OP_DEPTH:
-                    return "OP_DEPTH";
-                case instruction.OP_DROP:
-                    return "OP_DROP";
-                case instruction.OP_DUP:
-                    return "OP_DUP";
-                case instruction.OP_NIP:
-                    return "OP_NIP";
-                case instruction.OP_OVER:
-                    return "OP_OVER";
-                case instruction.OP_PICK:
-                    return "OP_PICK";
-                case instruction.OP_ROLL:
-                    return "OP_ROLL";
-                case instruction.OP_ROT:
-                    return "OP_ROT";
-                case instruction.OP_SWAP:
-                    return "OP_SWAP";
-                case instruction.OP_TUCK:
-                    return "OP_TUCK";
-
-                // splice ops
-                case instruction.OP_CAT:
-                    return "OP_CAT";
-                case instruction.OP_SUBSTR:
-                    return "OP_SUBSTR";
-                case instruction.OP_LEFT:
-                    return "OP_LEFT";
-                case instruction.OP_RIGHT:
-                    return "OP_RIGHT";
-                case instruction.OP_SIZE:
-                    return "OP_SIZE";
-
-                // bit logic
-                case instruction.OP_INVERT:
-                    return "OP_INVERT";
-                case instruction.OP_AND:
-                    return "OP_AND";
-                case instruction.OP_OR:
-                    return "OP_OR";
-                case instruction.OP_XOR:
-                    return "OP_XOR";
-                case instruction.OP_EQUAL:
-                    return "OP_EQUAL";
-                case instruction.OP_EQUALVERIFY:
-                    return "OP_EQUALVERIFY";
-                case instruction.OP_RESERVED1:
-                    return "OP_RESERVED1";
-                case instruction.OP_RESERVED2:
-                    return "OP_RESERVED2";
-
-                // numeric
-                case instruction.OP_1ADD:
-                    return "OP_1ADD";
-                case instruction.OP_1SUB:
-                    return "OP_1SUB";
-                case instruction.OP_2MUL:
-                    return "OP_2MUL";
-                case instruction.OP_2DIV:
-                    return "OP_2DIV";
-                case instruction.OP_NEGATE:
-                    return "OP_NEGATE";
-                case instruction.OP_ABS:
-                    return "OP_ABS";
-                case instruction.OP_NOT:
-                    return "OP_NOT";
-                case instruction.OP_0NOTEQUAL:
-                    return "OP_0NOTEQUAL";
-                case instruction.OP_ADD:
-                    return "OP_ADD";
-                case instruction.OP_SUB:
-                    return "OP_SUB";
-                case instruction.OP_MUL:
-                    return "OP_MUL";
-                case instruction.OP_DIV:
-                    return "OP_DIV";
-                case instruction.OP_MOD:
-                    return "OP_MOD";
-                case instruction.OP_LSHIFT:
-                    return "OP_LSHIFT";
-                case instruction.OP_RSHIFT:
-                    return "OP_RSHIFT";
-                case instruction.OP_BOOLAND:
-                    return "OP_BOOLAND";
-                case instruction.OP_BOOLOR:
-                    return "OP_BOOLOR";
-                case instruction.OP_NUMEQUAL:
-                    return "OP_NUMEQUAL";
-                case instruction.OP_NUMEQUALVERIFY:
-                    return "OP_NUMEQUALVERIFY";
-                case instruction.OP_NUMNOTEQUAL:
-                    return "OP_NUMNOTEQUAL";
-                case instruction.OP_LESSTHAN:
-                    return "OP_LESSTHAN";
-                case instruction.OP_GREATERTHAN:
-                    return "OP_GREATERTHAN";
-                case instruction.OP_LESSTHANOREQUAL:
-                    return "OP_LESSTHANOREQUAL";
-                case instruction.OP_GREATERTHANOREQUAL:
-                    return "OP_GREATERTHANOREQUAL";
-                case instruction.OP_MIN:
-                    return "OP_MIN";
-                case instruction.OP_MAX:
-                    return "OP_MAX";
-                case instruction.OP_WITHIN:
-                    return "OP_WITHIN";
-
-                // crypto
-                case instruction.OP_RIPEMD160:
-                    return "OP_RIPEMD160";
-                case instruction.OP_SHA1:
-                    return "OP_SHA1";
-                case instruction.OP_SHA256:
-                    return "OP_SHA256";
-                case instruction.OP_HASH160:
-                    return "OP_HASH160";
-                case instruction.OP_HASH256:
-                    return "OP_HASH256";
-                case instruction.OP_CODESEPARATOR:
-                    return "OP_CODESEPARATOR";
-                case instruction.OP_CHECKSIG:
-                    return "OP_CHECKSIG";
-                case instruction.OP_CHECKSIGVERIFY:
-                    return "OP_CHECKSIGVERIFY";
-                case instruction.OP_CHECKMULTISIG:
-                    return "OP_CHECKMULTISIG";
-                case instruction.OP_CHECKMULTISIGVERIFY:
-                    return "OP_CHECKMULTISIGVERIFY";
-
-                // expansion
-                case instruction.OP_NOP1:
-                    return "OP_NOP1";
-                case instruction.OP_NOP2:
-                    return "OP_NOP2";
-                case instruction.OP_NOP3:
-                    return "OP_NOP3";
-                case instruction.OP_NOP4:
-                    return "OP_NOP4";
-                case instruction.OP_NOP5:
-                    return "OP_NOP5";
-                case instruction.OP_NOP6:
-                    return "OP_NOP6";
-                case instruction.OP_NOP7:
-                    return "OP_NOP7";
-                case instruction.OP_NOP8:
-                    return "OP_NOP8";
-                case instruction.OP_NOP9:
-                    return "OP_NOP9";
-                case instruction.OP_NOP10:
-                    return "OP_NOP10";
-
-                // template matching params
-                case instruction.OP_SMALLINTEGER:
-                    return "OP_SMALLINTEGER";
-                case instruction.OP_PUBKEYHASH:
-                    return "OP_PUBKEYHASH";
-                case instruction.OP_PUBKEY:
-                    return "OP_PUBKEY";
-                case instruction.OP_PUBKEYS:
-                    return "OP_PUBKEYS";
-                case instruction.OP_SMALLDATA:
-                    return "OP_SMALLDATA";
-
-                case instruction.OP_INVALIDOPCODE:
-                    return "OP_INVALIDOPCODE";
-                default:
-                    return "OP_UNKNOWN";
-            }
+            if (opcode == instruction.OP_0) // OP_0 and OP_FALSE are synonyms
+                return "OP_0";
+            if (opcode == instruction.OP_1) // OP_1 and OP_TRUE are synonyms
+                return "OP_1";
+
+            return Enum.GetName(typeof(instruction), opcode);
         }
 
         /// <summary>
-        /// Get next opcode from passed list of bytes and extract push arguments if there are some.
+        /// Get next instruction from list of bytes and extract push arguments if there are some.
         /// </summary>
         /// <param name="codeBytes">ByteQueue reference.</param>
-        /// <param name="opcodeRet">Found opcode.</param>
+        /// <param name="opcodeRet">Found instruction.</param>
         /// <param name="bytesRet">IEnumerable out param which is used to get the push arguments.</param>
         /// <returns>Result of operation</returns>
-        public static bool GetOp(ref ByteQueue codeBytes, out instruction opcodeRet, out IEnumerable<byte> bytesRet)
+        public static bool GetOp(ref InstructionQueue codeBytes, out instruction opcodeRet, out byte[] bytesRet)
         {
-            bytesRet = new List<byte>();
-            opcodeRet = instruction.OP_INVALIDOPCODE;
-
-            instruction opcode;
+            bytesRet = new byte[0];
+            instruction opcode = opcodeRet = instruction.OP_INVALIDOPCODE;
 
-            try
-            {
-                // Read instruction
-                opcode = (instruction)codeBytes.Get();
-            }
-            catch (ByteQueueException)
+            // Read instruction
+            byte opVal = 0xff;
+            if (!codeBytes.TryGet(ref opVal))
             {
-                // No instruction found there
                 return false;
             }
+            opcode = (instruction)opVal;
 
             // Immediate operand
             if (opcode <= instruction.OP_PUSHDATA4)
             {
-                byte[] szBytes = new byte[4] { 0, 0, 0, 0 }; // Zero length
+                var szBytes = new byte[4] { 0, 0, 0, 0 }; // Zero length
+                int nSize = 0;
 
                 try
                 {
                     if (opcode < instruction.OP_PUSHDATA1)
                     {
-                        // Zero value opcodes (OP_0, OP_FALSE)
-                        szBytes[3] = (byte)opcode;
+                        // Zero value instructions (OP_0, OP_FALSE)
+                        nSize = (int) opcode;
                     }
                     else if (opcode == instruction.OP_PUSHDATA1)
                     {
                         // The next byte contains the number of bytes to be pushed onto the stack, 
                         //    i.e. you have something like OP_PUSHDATA1 0x01 [0x5a]
-                        szBytes[3] = (byte)codeBytes.Get();
+                        nSize = codeBytes.Get();
                     }
                     else if (opcode == instruction.OP_PUSHDATA2)
                     {
                         // The next two bytes contain the number of bytes to be pushed onto the stack,
-                        //    i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a]
-                        codeBytes.Get(2).CopyTo(szBytes, 2);
+                        //    i.e. now your operation will seem like this: OP_PUSHDATA2 0x01 0x00 [0x5a]
+                        nSize = BitConverter.ToInt16(codeBytes.Get(2), 0);
                     }
                     else if (opcode == instruction.OP_PUSHDATA4)
                     {
                         // The next four bytes contain the number of bytes to be pushed onto the stack,
-                        //   OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a]
-                        szBytes = codeBytes.Get(4);
+                        //   OP_PUSHDATA4 0x01 0x00 0x00 0x00 [0x5a]
+                        nSize = BitConverter.ToInt32(codeBytes.Get(4), 0);
                     }
                 }
-                catch (ByteQueueException)
+                catch (InstructionQueueException)
                 {
                     // Unable to read operand length
                     return false;
                 }
 
-                int nSize = (int)Interop.BEBytesToUInt32(szBytes);
-
                 if (nSize > 0)
                 {
-                    // If nSize is greater than zero then there is some data available
-                    try
-                    {
-                        // Read found number of bytes into list of OP_PUSHDATAn arguments.
-                        bytesRet = codeBytes.GetEnumerable(nSize);
-                    }
-                    catch (ByteQueueException)
+                    // Trying to read found number of bytes into list of OP_PUSHDATAn arguments.
+                    if (!codeBytes.TryGet(nSize, ref bytesRet))
                     {
                         // Unable to read data
                         return false;
@@ -567,16 +321,13 @@ namespace Novacoin
         /// </summary>
         /// <param name="bytes">Collection of value bytes.</param>
         /// <returns>Formatted value.</returns>
-        public static string ValueString(IEnumerable<byte> bytes)
+        public static string ValueString(byte[] bytes)
         {
-            StringBuilder sb = new StringBuilder();
+            var sb = new StringBuilder();
 
-            if (bytes.Count() <= 4)
+            if (bytes.Length <= 4)
             {
-                byte[] valueBytes = new byte[4] { 0, 0, 0, 0 };
-                bytes.ToArray().CopyTo(valueBytes, valueBytes.Length - bytes.Count());
-
-                sb.Append(Interop.BEBytesToUInt32(valueBytes));
+                sb.Append(new BigInteger(bytes));
             }
             else
             {
@@ -591,12 +342,12 @@ namespace Novacoin
         /// </summary>
         /// <param name="stackList">List of stack items.</param>
         /// <returns>Formatted value.</returns>
-        public static string StackString(IList<IList<byte>> stackList)
+        public static string StackString(IList<byte[]> stackList)
         {
-            StringBuilder sb = new StringBuilder();
-            foreach (IList<byte> bytesList in stackList)
+            var sb = new StringBuilder();
+            foreach (var bytes in stackList)
             {
-                sb.Append(ValueString(bytesList));
+                sb.Append(ValueString(bytes));
             }
 
             return sb.ToString();
@@ -605,53 +356,46 @@ namespace Novacoin
         /// <summary>
         /// Decode instruction to integer value
         /// </summary>
-        /// <param name="opcode">Small integer opcode (OP_1_NEGATE and OP_0 - OP_16)</param>
+        /// <param name="opcode">Small integer instruction (OP_1_NEGATE and OP_0 - OP_16)</param>
         /// <returns>Small integer</returns>
         public static int DecodeOP_N(instruction opcode, bool AllowNegate = false)
         {
-            if (AllowNegate && opcode == instruction.OP_1NEGATE)
-            {
-                return -1;
-            }
-
-            if (opcode == instruction.OP_0)
-            {
-                return 0;
-            }
+            // Only OP_n instructions are supported, throw exception otherwise.
+            Contract.Requires<ArgumentException>((opcode == instruction.OP_1NEGATE && AllowNegate) || (opcode >= instruction.OP_0 && opcode <= instruction.OP_16), "Invalid integer instruction.");
 
-            // Only OP_n opcodes are supported, throw exception otherwise.
-            if (opcode < instruction.OP_1 || opcode > instruction.OP_16)
+            switch (opcode)
             {
-                throw new ArgumentException("Invalid integer instruction.");
+                case instruction.OP_1NEGATE:
+                    return -1;
+                case instruction.OP_0:
+                    return 0;
+                default:
+                    return (int)opcode - (int)(instruction.OP_1 - 1);
             }
-
-            return (int)opcode - (int)(instruction.OP_1 - 1);
         }
 
         /// <summary>
         /// Converts integer into instruction
         /// </summary>
         /// <param name="n">Small integer from the range of -1 up to 16.</param>
-        /// <returns>Corresponding opcode.</returns>
+        /// <returns>Corresponding instruction.</returns>
         public static instruction EncodeOP_N(int n, bool allowNegate = false)
         {
-            if (allowNegate && n == -1)
-            {
-                return instruction.OP_1NEGATE;
-            }
+            // The n value must be in the range of 1 to 16.
+            Contract.Requires<ArgumentException>((n == -1 && allowNegate) || (n >= 0 && n <= 16), "Invalid integer value.");
 
-            if (n == 0)
+            switch (n)
             {
-                return instruction.OP_0;
+                case -1:
+                    return instruction.OP_1NEGATE;
+                case 0:
+                    return instruction.OP_0;
+                default:
+                    return (instruction.OP_1 + n - 1);
             }
-
-            // The n value must be in the range of 0 to 16.
-            if (n < 0 || n > 16)
-                throw new ArgumentException("Invalid integer value.");
-            return (instruction.OP_1 + n - 1);
         }
 
-        public static int ScriptSigArgsExpected(txnouttype t, IList<IEnumerable<byte>> solutions)
+        public static int ScriptSigArgsExpected(txnouttype t, IList<byte[]> solutions)
         {
             switch (t)
             {
@@ -664,9 +408,9 @@ namespace Novacoin
                 case txnouttype.TX_PUBKEYHASH:
                     return 2;
                 case txnouttype.TX_MULTISIG:
-                    if (solutions.Count() < 1 || solutions.First().Count() < 1)
+                    if (solutions.Count < 1 || solutions.First().Length < 1)
                         return -1;
-                    return solutions.First().First() + 1;
+                    return solutions.First()[0] + 1;
                 case txnouttype.TX_SCRIPTHASH:
                     return 1; // doesn't include args needed by the script
             }
@@ -681,7 +425,7 @@ namespace Novacoin
         /// <returns>Checking result</returns>
         public static bool IsStandard(CScript scriptPubKey, out txnouttype whichType)
         {
-            IList<IEnumerable<byte>> solutions = new List<IEnumerable<byte>>();
+            IList<byte[]> solutions;
 
             if (!Solver(scriptPubKey, out whichType, out solutions))
             {
@@ -692,8 +436,8 @@ namespace Novacoin
             if (whichType == txnouttype.TX_MULTISIG)
             {
                 // Additional verification of OP_CHECKMULTISIG arguments
-                byte m = solutions.First().First();
-                byte n = solutions.Last().First();
+                var m = solutions.First()[0];
+                var n = solutions.Last()[0];
 
                 // Support up to x-of-3 multisig txns as standard
                 if (n < 1 || n > 3)
@@ -716,9 +460,11 @@ namespace Novacoin
         /// <param name="typeRet">Output type</param>
         /// <param name="solutions">Set of solutions</param>
         /// <returns>Result</returns>
-        public static bool Solver(CScript scriptPubKey, out txnouttype typeRet, out IList<IEnumerable<byte>> solutions)
+        public static bool Solver(CScript scriptPubKey, out txnouttype typeRet, out IList<byte[]> solutions)
         {
-            solutions = new List<IEnumerable<byte>>();
+            byte[] scriptBytes = scriptPubKey;
+
+            solutions = new List<byte[]>();
 
             // There are shortcuts for pay-to-script-hash and pay-to-pubkey-hash, which are more constrained than the other types.
 
@@ -728,8 +474,8 @@ namespace Novacoin
                 typeRet = txnouttype.TX_SCRIPTHASH;
 
                 // Take 20 bytes with offset of 2 bytes
-                IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(2).Take(20);
-                solutions.Add(hashBytes);
+                var hashBytes = scriptBytes.Skip(2).Take(20);
+                solutions.Add(hashBytes.ToArray());
 
                 return true;
             }
@@ -740,18 +486,18 @@ namespace Novacoin
                 typeRet = txnouttype.TX_PUBKEYHASH;
 
                 // Take 20 bytes with offset of 3 bytes
-                IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(3).Take(20);
-                solutions.Add(hashBytes);
+                var hashBytes = scriptBytes.Skip(3).Take(20);
+                solutions.Add(hashBytes.ToArray());
 
                 return true;
             }
 
-            List<Tuple<txnouttype, IEnumerable<byte>>> templateTuples = new List<Tuple<txnouttype, IEnumerable<byte>>>();
+            var templateTuples = new List<Tuple<txnouttype, byte[]>>();
 
             // Sender provides pubkey, receiver adds signature
             // [ECDSA public key] OP_CHECKSIG
             templateTuples.Add(
-                new Tuple<txnouttype, IEnumerable<byte>>(
+                new Tuple<txnouttype, byte[]>(
                     txnouttype.TX_PUBKEY,
                     new byte[] {
                         (byte)instruction.OP_PUBKEY,
@@ -761,9 +507,9 @@ namespace Novacoin
 
             // Sender provides N pubkeys, receivers provides M signatures
             // N [pubkey1] [pubkey2] ... [pubkeyN] M OP_CHECKMULTISIG
-            // Where N and M are small integer opcodes (OP1 ... OP_16)
+            // Where N and M are small integer instructions (OP1 ... OP_16)
             templateTuples.Add(
-                new Tuple<txnouttype, IEnumerable<byte>>(
+                new Tuple<txnouttype, byte[]>(
                     txnouttype.TX_MULTISIG,
                     new byte[] {
                         (byte)instruction.OP_SMALLINTEGER,
@@ -776,7 +522,7 @@ namespace Novacoin
             // Data-carrying output
             // OP_RETURN [up to 80 bytes of data]
             templateTuples.Add(
-                new Tuple<txnouttype, IEnumerable<byte>>(
+                new Tuple<txnouttype, byte[]>(
                     txnouttype.TX_NULL_DATA,
                     new byte[] {
                         (byte)instruction.OP_RETURN,
@@ -787,33 +533,33 @@ namespace Novacoin
             // Nonstandard tx output
             typeRet = txnouttype.TX_NONSTANDARD;
 
-            foreach (Tuple<txnouttype, IEnumerable<byte>> templateTuple in templateTuples)
+            foreach (var templateTuple in templateTuples)
             {
-                CScript script1 = scriptPubKey;
-                CScript script2 = new CScript(templateTuple.Item2);
+                var script1 = scriptPubKey;
+                var script2 = new CScript(templateTuple.Item2);
 
                 instruction opcode1, opcode2;
 
                 // Compare
-                ByteQueue bq1 = script1.GetByteQUeue();
-                ByteQueue bq2 = script2.GetByteQUeue();
+                var bq1 = script1.GetInstructionQueue();
+                var bq2 = script2.GetInstructionQueue();
 
-                IEnumerable<byte> args1, args2;
+                byte[] args1, args2;
 
-                int last1 = script1.Bytes.Count() -1;
-                int last2 = script2.Bytes.Count() - 1;
+                int last1 = ((byte[])script1).Length - 1;
+                int last2 = ((byte[])script2).Length - 1;
 
                 while (true)
                 {
-                    if (bq1.CurrentIndex == last1 && bq2.CurrentIndex == last2)
+                    if (bq1.Index == last1 && bq2.Index == last2)
                     {
                         // Found a match
                         typeRet = templateTuple.Item1;
                         if (typeRet == txnouttype.TX_MULTISIG)
                         {
                             // Additional checks for TX_MULTISIG:
-                            byte m = solutions.First().First();
-                            byte n = solutions.Last().First();
+                            var m = solutions.First().First();
+                            var n = solutions.Last().First();
 
                             if (m < 1 || n < 1 || m > n || solutions.Count - 2 != n)
                             {
@@ -832,7 +578,7 @@ namespace Novacoin
                         break;
                     }
 
-                    // Template matching opcodes:
+                    // Template matching instructions:
                     if (opcode2 == instruction.OP_PUBKEYS)
                     {
                         while (args1.Count() >= 33 && args1.Count() <= 120)
@@ -872,7 +618,7 @@ namespace Novacoin
                         // Single-byte small integer pushed onto solutions
                         try
                         {
-                            byte n = (byte)DecodeOP_N(opcode1);
+                            var n = (byte)DecodeOP_N(opcode1);
                             solutions.Add(new byte[] { n });
                         }
                         catch (Exception)
@@ -883,7 +629,7 @@ namespace Novacoin
                     else if (opcode2 == instruction.OP_SMALLDATA)
                     {
                         // small pushdata, <= 80 bytes
-                        if (args1.Count() > 80)
+                        if (args1.Length > 80)
                         {
                             break;
                         }
@@ -902,27 +648,31 @@ namespace Novacoin
             return false;
         }
 
-        public static Hash256 SignatureHash(CScript scriptCode, CTransaction txTo, int nIn, int nHashType)
+        /// <summary>
+        /// Generation of SignatureHash. This method is responsible for removal of transaction metadata. It's necessary signature can't sign itself. 
+        /// </summary>
+        /// <param name="script">Spending instructions</param>
+        /// <param name="txTo">Instance of transaction</param>
+        /// <param name="nIn">Input number</param>
+        /// <param name="nHashType">Hash type flag</param>
+        /// <returns></returns>
+        public static Hash256 SignatureHash(CScript script, CTransaction txTo, int nIn, int nHashType)
         {
-            if (nIn >= txTo.vin.Length)
-            {
-                StringBuilder sb = new StringBuilder();
-                sb.AppendFormat("ERROR: SignatureHash() : nIn={0} out of range\n", nIn);
-                throw new ArgumentOutOfRangeException("nIn", sb.ToString());
-            }
+            Contract.Requires<ArgumentOutOfRangeException>(nIn < txTo.vin.Length, "nIn out of range.");
 
-            CTransaction txTmp = new CTransaction(txTo);
+            // Init a copy of transaction
+            var txTmp = new CTransaction(txTo);
 
             // In case concatenating two scripts ends up with two codeseparators,
             // or an extra one at the end, this prevents all those possible incompatibilities.
-            scriptCode.RemovePattern(new byte[] { (byte)instruction.OP_CODESEPARATOR });
+            script.RemoveInstruction(instruction.OP_CODESEPARATOR);
 
             // Blank out other inputs' signatures
             for (int i = 0; i < txTmp.vin.Length; i++)
             {
                 txTmp.vin[i].scriptSig = new CScript();
             }
-            txTmp.vin[nIn].scriptSig = scriptCode;
+            txTmp.vin[nIn].scriptSig = script;
 
             // Blank out some of the outputs
             if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_NONE)
@@ -973,14 +723,22 @@ namespace Novacoin
                 Array.Resize(ref txTmp.vin, 1);
             }
 
-            // Serialize and hash
-            List<byte> b = new List<byte>();
-            b.AddRange(txTmp.Bytes);
-            b.AddRange(BitConverter.GetBytes(nHashType));
+            // Concatenate and hash
+            var txBytes = (byte[])txTmp;
+            var nHashTypeBytes = BitConverter.GetBytes(nHashType);
 
-            return Hash256.Compute256(b);
+            return Hash256.Compute256(ref txBytes, ref nHashTypeBytes);
         }
 
+        //
+        // Script is a stack machine (like Forth) that evaluates a predicate
+        // returning a bool indicating valid or not.  There are no loops.
+        //
+
+        /// <summary>
+        /// Script machine exception
+        /// </summary>
+        [Serializable]
         public class StackMachineException : Exception
         {
             public StackMachineException()
@@ -998,22 +756,15 @@ namespace Novacoin
             }
         }
 
-
-        //
-        // Script is a stack machine (like Forth) that evaluates a predicate
-        // returning a bool indicating valid or not.  There are no loops.
-        //
-
         /// <summary>
         /// Remove last element from stack
         /// </summary>
         /// <param name="stack">Stack reference</param>
-        static void popstack(ref List<IEnumerable<byte>> stack)
+        private static void popstack(ref List<byte[]> stack)
         {
-            int nCount = stack.Count;
-            if (nCount == 0)
-                throw new StackMachineException("popstack() : stack empty");
-            stack.RemoveAt(nCount - 1);
+            Contract.Requires<StackMachineException>(stack.Count > 0, "Stack is empty.");
+
+            stack.RemoveAt(stack.Count - 1);
         }
 
         /// <summary>
@@ -1022,27 +773,12 @@ namespace Novacoin
         /// <param name="stack">Stack reference</param>
         /// <param name="nDepth">Depth</param>
         /// <returns>Byte sequence</returns>
-        static IEnumerable<byte> stacktop(ref List<IEnumerable<byte>> stack, int nDepth)
+        private static byte[] stacktop(ref List<byte[]> stack, int nDepth)
         {
-            int nStackElement = stack.Count + nDepth;
+            Contract.Requires<StackMachineException>(nDepth < 0, "Positive or zero stack depth makes no sense.");
+            Contract.Requires<StackMachineException>(stack.Count + nDepth >= 0, "Value exceeds real stack depth.");
 
-            if (nDepth >= 0)
-            {
-                StringBuilder sb = new StringBuilder();
-                sb.AppendFormat("stacktop() : positive depth ({0}) has no sense.", nDepth);
-
-                throw new StackMachineException(sb.ToString());
-            }
-
-            if (nStackElement < 0)
-            {
-                StringBuilder sb = new StringBuilder();
-                sb.AppendFormat("stacktop() : nDepth={0} exceeds real stack depth ({1})", nDepth, stack.Count);
-
-                throw new StackMachineException(sb.ToString());
-            }
-
-            return stack[nStackElement];
+            return stack[stack.Count + nDepth];
         }
 
         /// <summary>
@@ -1050,16 +786,14 @@ namespace Novacoin
         /// </summary>
         /// <param name="value">Some byte sequence</param>
         /// <returns></returns>
-        private static bool CastToBool(IEnumerable<byte> arg)
+        private static bool CastToBool(byte[] arg)
         {
-            byte[] value = arg.ToArray();
-
-            for (var i = 0; i < value.Length; i++)
+            for (var i = 0; i < arg.Length; i++)
             {
-                if (value[i] != 0)
+                if (arg[i] != 0)
                 {
                     // Can be negative zero
-                    if (i == value.Length - 1 && value[i] == 0x80)
+                    if (i == arg.Length - 1 && arg[i] == 0x80)
                     {
                         return false;
                     }
@@ -1076,877 +810,894 @@ namespace Novacoin
         /// </summary>
         /// <param name="value"></param>
         /// <returns></returns>
-        private static BigInteger CastToBigInteger(IEnumerable<byte> value)
+        private static BigInteger CastToBigInteger(byte[] value)
         {
-            if (value.Count() > 4)
-            {
-                throw new StackMachineException("CastToBigInteger() : overflow");
-            }
+            Contract.Requires<StackMachineException>(value.Length <= 4, "Size limit failed.");
 
-            return new BigInteger(value.ToArray());
+            return new BigInteger(value);
         }
 
-        static bool EvalScript(ref List<IEnumerable<byte>> stack, CScript script, CTransaction txTo, int nIn, int flags, int nHashType)
+        /// <summary>
+        /// Execution of script
+        /// </summary>
+        /// <param name="stack"></param>
+        /// <param name="script">Script to execute</param>
+        /// <param name="txTo">Transaction instance</param>
+        /// <param name="nIn">Input number</param>
+        /// <param name="flags">Signature checking flags</param>
+        /// <param name="nHashType">Hash type flag</param>
+        /// <returns></returns>
+        public static bool EvalScript(ref List<byte[]> stack, CScript script, CTransaction txTo, int nIn, int flags, int nHashType)
         {
-            instruction opcode;
-
-            ByteQueue CodeQueue = script.GetByteQUeue();
-
-            List<bool> vfExec = new List<bool>();
-            List<IEnumerable<byte>> altStack = new List<IEnumerable<byte>>();
+            var scriptBytes = ((byte[])script);
 
-            byte[] falseBytes = new byte[0];
-            byte[] trueBytes = new byte[] { 0x01 };
-
-            if (script.Bytes.Count() > 10000)
+            if (scriptBytes.Length > 10000)
             {
                 return false; // Size limit failed
             }
 
+            var vfExec = new List<bool>();
+
             int nOpCount = 0;
             int nCodeHashBegin = 0;
 
-            IEnumerable<byte> pushArg;
+            var falseBytes = new byte[0];
+            var trueBytes = new byte[] { 0x01 };
 
-            while (GetOp(ref CodeQueue, out opcode, out pushArg)) // Read instructions
+            var CodeQueue = script.GetInstructionQueue();
+            var altStack = new List<byte[]>();
+
+#if !DEBUG
+            try
             {
-                bool fExec = vfExec.IndexOf(false) != -1;
+#endif
+                instruction opcode;
+                byte[] pushArg;
 
-                if (pushArg.Count() > 520)
+                while (GetOp(ref CodeQueue, out opcode, out pushArg)) // Read instructions
                 {
-                    return false; // Script element size limit failed
-                }
+                    bool fExec = vfExec.IndexOf(false) == -1;
 
-                if (opcode > instruction.OP_16 && ++nOpCount > 201)
-                {
-                    return false;
-                }
+                    if (pushArg.Length > 520)
+                    {
+                        return false; // Script element size limit failed
+                    }
 
-                if (fExec && 0 <= opcode && opcode <= instruction.OP_PUSHDATA4)
-                {
-                    stack.Add(pushArg); // Push argument to stack
-                }
-                else if (fExec || (instruction.OP_IF <= opcode && opcode <= instruction.OP_ENDIF))
-                    switch (opcode)
+                    if (opcode > instruction.OP_16 && ++nOpCount > 201)
                     {
-                        //
-                        // Disabled opcodes
-                        //
-                        case instruction.OP_CAT:
-                        case instruction.OP_SUBSTR:
-                        case instruction.OP_LEFT:
-                        case instruction.OP_RIGHT:
-                        case instruction.OP_INVERT:
-                        case instruction.OP_AND:
-                        case instruction.OP_OR:
-                        case instruction.OP_XOR:
-                        case instruction.OP_2MUL:
-                        case instruction.OP_2DIV:
-                        case instruction.OP_MUL:
-                        case instruction.OP_DIV:
-                        case instruction.OP_MOD:
-                        case instruction.OP_LSHIFT:
-                        case instruction.OP_RSHIFT:
-                            return false;
-
-                        //
-                        // Push integer instructions
-                        //
-                        case instruction.OP_1NEGATE:
-                        case instruction.OP_1:
-                        case instruction.OP_2:
-                        case instruction.OP_3:
-                        case instruction.OP_4:
-                        case instruction.OP_5:
-                        case instruction.OP_6:
-                        case instruction.OP_7:
-                        case instruction.OP_8:
-                        case instruction.OP_9:
-                        case instruction.OP_10:
-                        case instruction.OP_11:
-                        case instruction.OP_12:
-                        case instruction.OP_13:
-                        case instruction.OP_14:
-                        case instruction.OP_15:
-                        case instruction.OP_16:
-                            {
-                                // ( -- value)
-                                BigInteger bn = DecodeOP_N(opcode);
-                                stack.Add(bn.ToByteArray());
-                            }
-                            break;
+                        return false;
+                    }
 
-                        //
-                        // Extension
-                        //
-                        case instruction.OP_NOP:
-                        case instruction.OP_NOP1:
-                        case instruction.OP_NOP2:
-                        case instruction.OP_NOP3:
-                        case instruction.OP_NOP4:
-                        case instruction.OP_NOP5:
-                        case instruction.OP_NOP6:
-                        case instruction.OP_NOP7:
-                        case instruction.OP_NOP8:
-                        case instruction.OP_NOP9:
-                        case instruction.OP_NOP10:
-                            {
-                                // Just do nothing
-                                break;
-                            }
+                    if (fExec && 0 <= opcode && opcode <= instruction.OP_PUSHDATA4)
+                    {
+                        stack.Add(pushArg); // Push argument to stack
+                    }
+                    else if (fExec || (instruction.OP_IF <= opcode && opcode <= instruction.OP_ENDIF))
+                        switch (opcode)
+                        {
+                            //
+                            // Disabled instructions
+                            //
+                            case instruction.OP_CAT:
+                            case instruction.OP_SUBSTR:
+                            case instruction.OP_LEFT:
+                            case instruction.OP_RIGHT:
+                            case instruction.OP_INVERT:
+                            case instruction.OP_AND:
+                            case instruction.OP_OR:
+                            case instruction.OP_XOR:
+                            case instruction.OP_2MUL:
+                            case instruction.OP_2DIV:
+                            case instruction.OP_MUL:
+                            case instruction.OP_DIV:
+                            case instruction.OP_MOD:
+                            case instruction.OP_LSHIFT:
+                            case instruction.OP_RSHIFT:
+                                return false;
 
-                        //
-                        // Control
-                        //
-                        case instruction.OP_IF:
-                        case instruction.OP_NOTIF:
-                            {
-                                // <expression> if [statements] [else [statements]] endif
-                                bool fValue = false;
-                                if (fExec)
+                            //
+                            // Push integer instructions
+                            //
+                            case instruction.OP_1NEGATE:
+                            case instruction.OP_1:
+                            case instruction.OP_2:
+                            case instruction.OP_3:
+                            case instruction.OP_4:
+                            case instruction.OP_5:
+                            case instruction.OP_6:
+                            case instruction.OP_7:
+                            case instruction.OP_8:
+                            case instruction.OP_9:
+                            case instruction.OP_10:
+                            case instruction.OP_11:
+                            case instruction.OP_12:
+                            case instruction.OP_13:
+                            case instruction.OP_14:
+                            case instruction.OP_15:
+                            case instruction.OP_16:
                                 {
-                                    if (stack.Count() < 1)
-                                    {
-                                        return false;
-                                    }
-                                    IEnumerable<byte> vch = stacktop(ref stack, -1);
-                                    fValue = CastToBool(vch);
-                                    if (opcode == instruction.OP_NOTIF)
-                                    {
-                                        fValue = !fValue;
-                                    }
-                                    popstack(ref stack);
+                                    // ( -- value)
+                                    BigInteger bn = DecodeOP_N(opcode, true);
+                                    stack.Add(bn.ToByteArray());
                                 }
-                                vfExec.Add(fValue);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_ELSE:
-                            {
-                                int nExecCount = vfExec.Count();
-                                if (nExecCount == 0)
+                            //
+                            // Extension
+                            //
+                            case instruction.OP_NOP:
+                            case instruction.OP_NOP1:
+                            case instruction.OP_NOP2:
+                            case instruction.OP_NOP3:
+                            case instruction.OP_NOP4:
+                            case instruction.OP_NOP5:
+                            case instruction.OP_NOP6:
+                            case instruction.OP_NOP7:
+                            case instruction.OP_NOP8:
+                            case instruction.OP_NOP9:
+                            case instruction.OP_NOP10:
                                 {
-                                    return false;
+                                    // Just do nothing
                                 }
-                                vfExec[nExecCount - 1] = !vfExec[nExecCount - 1];
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_ENDIF:
-                            {
-                                int nExecCount = vfExec.Count();
-                                if (nExecCount == 0)
+                            //
+                            // Control
+                            //
+                            case instruction.OP_IF:
+                            case instruction.OP_NOTIF:
                                 {
-                                    return false;
+                                    // <expression> if [statements] [else [statements]] endif
+                                    var fValue = false;
+                                    if (fExec)
+                                    {
+                                        if (stack.Count() < 1)
+                                        {
+                                            return false;
+                                        }
+                                        var vch = stacktop(ref stack, -1);
+                                        fValue = CastToBool(vch);
+                                        if (opcode == instruction.OP_NOTIF)
+                                        {
+                                            fValue = !fValue;
+                                        }
+                                        popstack(ref stack);
+                                    }
+                                    vfExec.Add(fValue);
                                 }
-                                vfExec.RemoveAt(nExecCount - 1);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_VERIFY:
-                            {
-                                // (true -- ) or
-                                // (false -- false) and return
-                                if (stack.Count() < 1)
+                            case instruction.OP_ELSE:
                                 {
-                                    return false;
+                                    int nExecCount = vfExec.Count();
+                                    if (nExecCount == 0)
+                                    {
+                                        return false;
+                                    }
+                                    vfExec[nExecCount - 1] = !vfExec[nExecCount - 1];
                                 }
+                                break;
 
-                                bool fValue = CastToBool(stacktop(ref stack, -1));
-                                if (fValue)
+                            case instruction.OP_ENDIF:
                                 {
-                                    popstack(ref stack);
-                                }
-                                else
-                                {
-                                    return false;
+                                    int nExecCount = vfExec.Count();
+                                    if (nExecCount == 0)
+                                    {
+                                        return false;
+                                    }
+                                    vfExec.RemoveAt(nExecCount - 1);
                                 }
-                            }
-                            break;
-
-                        case instruction.OP_RETURN:
-                            {
-                                return false;
-                            }
+                                break;
 
-                        //
-                        // Stack ops
-                        //
-                        case instruction.OP_TOALTSTACK:
-                            {
-                                if (stack.Count() < 1)
+                            case instruction.OP_VERIFY:
                                 {
-                                    return false;
-                                }
-                                altStack.Add(stacktop(ref stack, -1));
-                                popstack(ref stack);
-                            }
-                            break;
+                                    // (true -- ) or
+                                    // (false -- false) and return
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
 
-                        case instruction.OP_FROMALTSTACK:
-                            {
-                                if (altStack.Count() < 1)
-                                {
-                                    return false;
+                                    bool fValue = CastToBool(stacktop(ref stack, -1));
+                                    if (fValue)
+                                    {
+                                        popstack(ref stack);
+                                    }
+                                    else
+                                    {
+                                        return false;
+                                    }
                                 }
-                                stack.Add(stacktop(ref stack, -1));
-                                popstack(ref altStack);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_2DROP:
-                            {
-                                // (x1 x2 -- )
-                                if (stack.Count() < 2)
+                            case instruction.OP_RETURN:
                                 {
                                     return false;
                                 }
-                                popstack(ref stack);
-                                popstack(ref stack);
-                            }
-                            break;
 
-                        case instruction.OP_2DUP:
-                            {
-                                // (x1 x2 -- x1 x2 x1 x2)
-                                if (stack.Count() < 2)
+                            //
+                            // Stack ops
+                            //
+                            case instruction.OP_TOALTSTACK:
                                 {
-                                    return false;
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
+                                    altStack.Add(stacktop(ref stack, -1));
+                                    popstack(ref stack);
                                 }
-                                IEnumerable<byte> vch1 = stacktop(ref stack, -2);
-                                IEnumerable<byte> vch2 = stacktop(ref stack, -1);
-                                stack.Add(vch1);
-                                stack.Add(vch2);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_3DUP:
-                            {
-                                // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
-                                if (stack.Count() < 3)
+                            case instruction.OP_FROMALTSTACK:
                                 {
-                                    return false;
+                                    if (altStack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
+                                    stack.Add(stacktop(ref stack, -1));
+                                    popstack(ref altStack);
                                 }
-                                IEnumerable<byte> vch1 = stacktop(ref stack, -3);
-                                IEnumerable<byte> vch2 = stacktop(ref stack, -2);
-                                IEnumerable<byte> vch3 = stacktop(ref stack, -1);
-                                stack.Add(vch1);
-                                stack.Add(vch2);
-                                stack.Add(vch3);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_2OVER:
-                            {
-                                // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
-                                if (stack.Count() < 4)
+                            case instruction.OP_2DROP:
                                 {
-                                    return false;
+                                    // (x1 x2 -- )
+                                    if (stack.Count() < 2)
+                                    {
+                                        return false;
+                                    }
+                                    popstack(ref stack);
+                                    popstack(ref stack);
                                 }
-                                IEnumerable<byte> vch1 = stacktop(ref stack, -4);
-                                IEnumerable<byte> vch2 = stacktop(ref stack, -3);
-                                stack.Add(vch1);
-                                stack.Add(vch2);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_2ROT:
-                            {
-                                int nStackDepth = stack.Count();
-                                // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
-                                if (nStackDepth < 6)
+                            case instruction.OP_2DUP:
                                 {
-                                    return false;
+                                    // (x1 x2 -- x1 x2 x1 x2)
+                                    if (stack.Count() < 2)
+                                    {
+                                        return false;
+                                    }
+                                    var vch1 = stacktop(ref stack, -2);
+                                    var vch2 = stacktop(ref stack, -1);
+                                    stack.Add(vch1);
+                                    stack.Add(vch2);
                                 }
-                                IEnumerable<byte> vch1 = stacktop(ref stack, -6);
-                                IEnumerable<byte> vch2 = stacktop(ref stack, -5);
-                                stack.RemoveRange(nStackDepth - 6, 2);
-                                stack.Add(vch1);
-                                stack.Add(vch2);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_2SWAP:
-                            {
-                                // (x1 x2 x3 x4 -- x3 x4 x1 x2)
-                                int nStackDepth = stack.Count();
-                                if (nStackDepth < 4)
+                            case instruction.OP_3DUP:
                                 {
-                                    return false;
+                                    // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
+                                    if (stack.Count() < 3)
+                                    {
+                                        return false;
+                                    }
+                                    var vch1 = stacktop(ref stack, -3);
+                                    var vch2 = stacktop(ref stack, -2);
+                                    var vch3 = stacktop(ref stack, -1);
+                                    stack.Add(vch1);
+                                    stack.Add(vch2);
+                                    stack.Add(vch3);
                                 }
-                                stack.Swap(nStackDepth - 4, nStackDepth - 2);
-                                stack.Swap(nStackDepth - 3, nStackDepth - 1);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_IFDUP:
-                            {
-                                // (x - 0 | x x)
-                                if (stack.Count() < 1)
+                            case instruction.OP_2OVER:
                                 {
-                                    return false;
+                                    // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
+                                    if (stack.Count() < 4)
+                                    {
+                                        return false;
+                                    }
+                                    var vch1 = stacktop(ref stack, -4);
+                                    var vch2 = stacktop(ref stack, -3);
+                                    stack.Add(vch1);
+                                    stack.Add(vch2);
                                 }
+                                break;
 
-                                IEnumerable<byte> vch = stacktop(ref stack, -1);
-
-                                if (CastToBool(vch))
+                            case instruction.OP_2ROT:
                                 {
-                                    stack.Add(vch);
+                                    int nStackDepth = stack.Count();
+                                    // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
+                                    if (nStackDepth < 6)
+                                    {
+                                        return false;
+                                    }
+                                    var vch1 = stacktop(ref stack, -6);
+                                    var vch2 = stacktop(ref stack, -5);
+                                    stack.RemoveRange(nStackDepth - 6, 2);
+                                    stack.Add(vch1);
+                                    stack.Add(vch2);
                                 }
-                            }
-                            break;
-
-                        case instruction.OP_DEPTH:
-                            {
-                                // -- stacksize
-                                BigInteger bn = new BigInteger((ushort)stack.Count());
-                                stack.Add(bn.ToByteArray());
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_DROP:
-                            {
-                                // (x -- )
-                                if (stack.Count() < 1)
+                            case instruction.OP_2SWAP:
                                 {
-                                    return false;
+                                    // (x1 x2 x3 x4 -- x3 x4 x1 x2)
+                                    int nStackDepth = stack.Count;
+                                    if (nStackDepth < 4)
+                                    {
+                                        return false;
+                                    }
+                                    stack.Swap(nStackDepth - 4, nStackDepth - 2);
+                                    stack.Swap(nStackDepth - 3, nStackDepth - 1);
                                 }
+                                break;
 
-                                popstack(ref stack);
-                            }
-                            break;
-
-                        case instruction.OP_DUP:
-                            {
-                                // (x -- x x)
-                                if (stack.Count() < 1)
+                            case instruction.OP_IFDUP:
                                 {
-                                    return false;
-                                }
+                                    // (x - 0 | x x)
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
 
-                                IEnumerable<byte> vch = stacktop(ref stack, -1);
-                                stack.Add(vch);
-                            }
-                            break;
+                                    var vch = stacktop(ref stack, -1);
 
-                        case instruction.OP_NIP:
-                            {
-                                // (x1 x2 -- x2)
-                                int nStackDepth = stack.Count();
-                                if (nStackDepth < 2)
-                                {
-                                    return false;
+                                    if (CastToBool(vch))
+                                    {
+                                        stack.Add(vch);
+                                    }
                                 }
+                                break;
 
-                                stack.RemoveAt(nStackDepth - 2);
-                            }
-                            break;
-
-                        case instruction.OP_OVER:
-                            {
-                                // (x1 x2 -- x1 x2 x1)
-                                if (stack.Count() < 2)
+                            case instruction.OP_DEPTH:
                                 {
-                                    return false;
+                                    // -- stacksize
+                                    BigInteger bn = new BigInteger((ushort)stack.Count());
+                                    stack.Add(bn.ToByteArray());
                                 }
+                                break;
 
-                                IEnumerable<byte> vch = stacktop(ref stack, -2);
-                                stack.Add(vch);
-                            }
-                            break;
-
-                        case instruction.OP_PICK:
-                        case instruction.OP_ROLL:
-                            {
-                                // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
-                                // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
-
-                                int nStackDepth = stack.Count();
-                                if (nStackDepth < 2)
+                            case instruction.OP_DROP:
                                 {
-                                    return false;
-                                }
-
-                                int n = (int)CastToBigInteger(stacktop(ref stack, -1));
-                                popstack(ref stack);
+                                    // (x -- )
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
 
-                                if (n < 0 || n >= stack.Count())
-                                {
-                                    return false;
+                                    popstack(ref stack);
                                 }
+                                break;
 
-                                IEnumerable<byte> vch = stacktop(ref stack, -n - 1);
-                                if (opcode == instruction.OP_ROLL)
+                            case instruction.OP_DUP:
                                 {
-                                    stack.RemoveAt(nStackDepth - n - 1);
-                                }
+                                    // (x -- x x)
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
 
-                                stack.Add(vch);
-                            }
-                            break;
+                                    var vch = stacktop(ref stack, -1);
+                                    stack.Add(vch);
+                                }
+                                break;
 
-                        case instruction.OP_ROT:
-                            {
-                                // (x1 x2 x3 -- x2 x3 x1)
-                                //  x2 x1 x3  after first swap
-                                //  x2 x3 x1  after second swap
-                                int nStackDepth = stack.Count();
-                                if (nStackDepth < 3)
+                            case instruction.OP_NIP:
                                 {
-                                    return false;
-                                }
-                                stack.Swap(nStackDepth - 3, nStackDepth - 2);
-                                stack.Swap(nStackDepth - 2, nStackDepth - 1);
+                                    // (x1 x2 -- x2)
+                                    int nStackDepth = stack.Count();
+                                    if (nStackDepth < 2)
+                                    {
+                                        return false;
+                                    }
 
-                            }
-                            break;
+                                    stack.RemoveAt(nStackDepth - 2);
+                                }
+                                break;
 
-                        case instruction.OP_SWAP:
-                            {
-                                // (x1 x2 -- x2 x1)
-                                int nStackDepth = stack.Count();
-                                if (nStackDepth < 2)
+                            case instruction.OP_OVER:
                                 {
-                                    return false;
+                                    // (x1 x2 -- x1 x2 x1)
+                                    if (stack.Count() < 2)
+                                    {
+                                        return false;
+                                    }
+
+                                    var vch = stacktop(ref stack, -2);
+                                    stack.Add(vch);
                                 }
-                                stack.Swap(nStackDepth - 2, nStackDepth - 1);
-                            }
-                            break;
+                                break;
 
-                        case instruction.OP_TUCK:
-                            {
-                                // (x1 x2 -- x2 x1 x2)
-                                int nStackDepth = stack.Count();
-                                if (nStackDepth < 2)
+                            case instruction.OP_PICK:
+                            case instruction.OP_ROLL:
                                 {
-                                    return false;
-                                }
-                                IEnumerable<byte> vch = stacktop(ref stack, -1);
-                                stack.Insert(nStackDepth - 2, vch);
-                            }
-                            break;
+                                    // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
+                                    // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
 
+                                    int nStackDepth = stack.Count();
+                                    if (nStackDepth < 2)
+                                    {
+                                        return false;
+                                    }
 
-                        case instruction.OP_SIZE:
-                            {
-                                // (in -- in size)
-                                if (stack.Count() < 1)
-                                {
-                                    return false;
-                                }
+                                    int n = (int)CastToBigInteger(stacktop(ref stack, -1));
+                                    popstack(ref stack);
 
-                                BigInteger bnSize = new BigInteger((ushort)stacktop(ref stack, -1).Count());
-                                stack.Add(bnSize.ToByteArray());
-                            }
-                            break;
+                                    if (n < 0 || n >= stack.Count())
+                                    {
+                                        return false;
+                                    }
 
+                                    var vch = stacktop(ref stack, -n - 1);
+                                    if (opcode == instruction.OP_ROLL)
+                                    {
+                                        stack.RemoveAt(nStackDepth - n - 1);
+                                    }
 
-                        //
-                        // Bitwise logic
-                        //
-                        case instruction.OP_EQUAL:
-                        case instruction.OP_EQUALVERIFY:
-                            //case instruction.OP_NOTEQUAL: // use OP_NUMNOTEQUAL
-                            {
-                                // (x1 x2 - bool)
-                                if (stack.Count() < 2)
-                                {
-                                    return false;
+                                    stack.Add(vch);
                                 }
+                                break;
 
-                                IEnumerable<byte> vch1 = stacktop(ref stack, -2);
-                                IEnumerable<byte> vch2 = stacktop(ref stack, -1);
-                                bool fEqual = (vch1 == vch2);
-                                // OP_NOTEQUAL is disabled because it would be too easy to say
-                                // something like n != 1 and have some wiseguy pass in 1 with extra
-                                // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
-                                //if (opcode == instruction.OP_NOTEQUAL)
-                                //    fEqual = !fEqual;
-                                popstack(ref stack);
-                                popstack(ref stack);
-                                stack.Add(fEqual ? trueBytes : falseBytes);
-
-                                if (opcode == instruction.OP_EQUALVERIFY)
+                            case instruction.OP_ROT:
                                 {
-                                    if (fEqual)
-                                    {
-                                        popstack(ref stack);
-                                    }
-                                    else
+                                    // (x1 x2 x3 -- x2 x3 x1)
+                                    //  x2 x1 x3  after first swap
+                                    //  x2 x3 x1  after second swap
+                                    int nStackDepth = stack.Count();
+                                    if (nStackDepth < 3)
                                     {
                                         return false;
                                     }
-                                }
-                            }
-                            break;
+                                    stack.Swap(nStackDepth - 3, nStackDepth - 2);
+                                    stack.Swap(nStackDepth - 2, nStackDepth - 1);
 
-
-                        //
-                        // Numeric
-                        //
-                        case instruction.OP_1ADD:
-                        case instruction.OP_1SUB:
-                        case instruction.OP_NEGATE:
-                        case instruction.OP_ABS:
-                        case instruction.OP_NOT:
-                        case instruction.OP_0NOTEQUAL:
-                            {
-                                // (in -- out)
-                                if (stack.Count() < 1)
-                                {
-                                    return false;
                                 }
+                                break;
 
-                                BigInteger bn = CastToBigInteger(stacktop(ref stack, -1));
-                                switch (opcode)
+                            case instruction.OP_SWAP:
                                 {
-                                    case instruction.OP_1ADD:
-                                        bn = bn + 1;
-                                        break;
-                                    case instruction.OP_1SUB:
-                                        bn = bn - 1;
-                                        break;
-                                    case instruction.OP_NEGATE:
-                                        bn = -bn;
-                                        break;
-                                    case instruction.OP_ABS:
-                                        bn = BigInteger.Abs(bn);
-                                        break;
-                                    case instruction.OP_NOT:
-                                        bn = bn == 0 ? 1 : 0;
-                                        break;
-                                    case instruction.OP_0NOTEQUAL:
-                                        bn = bn != 0 ? 1 : 0;
-                                        break;
-
-                                    default:
-                                        throw new StackMachineException("invalid instruction");
+                                    // (x1 x2 -- x2 x1)
+                                    int nStackDepth = stack.Count();
+                                    if (nStackDepth < 2)
+                                    {
+                                        return false;
+                                    }
+                                    stack.Swap(nStackDepth - 2, nStackDepth - 1);
                                 }
+                                break;
 
-                                popstack(ref stack);
-                                stack.Add(bn.ToByteArray());
-                            }
-                            break;
-
-                        case instruction.OP_ADD:
-                        case instruction.OP_SUB:
-                        case instruction.OP_BOOLAND:
-                        case instruction.OP_BOOLOR:
-                        case instruction.OP_NUMEQUAL:
-                        case instruction.OP_NUMEQUALVERIFY:
-                        case instruction.OP_NUMNOTEQUAL:
-                        case instruction.OP_LESSTHAN:
-                        case instruction.OP_GREATERTHAN:
-                        case instruction.OP_LESSTHANOREQUAL:
-                        case instruction.OP_GREATERTHANOREQUAL:
-                        case instruction.OP_MIN:
-                        case instruction.OP_MAX:
-                            {
-                                // (x1 x2 -- out)
-                                if (stack.Count() < 2)
+                            case instruction.OP_TUCK:
                                 {
-                                    return false;
+                                    // (x1 x2 -- x2 x1 x2)
+                                    int nStackDepth = stack.Count();
+                                    if (nStackDepth < 2)
+                                    {
+                                        return false;
+                                    }
+                                    var vch = stacktop(ref stack, -1);
+                                    stack.Insert(nStackDepth - 2, vch);
                                 }
+                                break;
 
-                                BigInteger bn1 = CastToBigInteger(stacktop(ref stack, -2));
-                                BigInteger bn2 = CastToBigInteger(stacktop(ref stack, -1));
-                                BigInteger bn = 0;
 
-                                switch (opcode)
+                            case instruction.OP_SIZE:
                                 {
-                                    case instruction.OP_ADD:
-                                        bn = bn1 + bn2;
-                                        break;
-                                    case instruction.OP_SUB:
-                                        bn = bn1 - bn2;
-                                        break;
-                                    case instruction.OP_BOOLAND:
-                                        bn = (bn1 != 0 && bn2 != 0) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_BOOLOR:
-                                        bn = (bn1 != 0 || bn2 != 0) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_NUMEQUAL:
-                                        bn = (bn1 == bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_NUMEQUALVERIFY:
-                                        bn = (bn1 == bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_NUMNOTEQUAL:
-                                        bn = (bn1 != bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_LESSTHAN:
-                                        bn = (bn1 < bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_GREATERTHAN:
-                                        bn = (bn1 > bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_LESSTHANOREQUAL:
-                                        bn = (bn1 <= bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_GREATERTHANOREQUAL:
-                                        bn = (bn1 >= bn2) ? 1 : 0;
-                                        break;
-                                    case instruction.OP_MIN:
-                                        bn = (bn1 < bn2 ? bn1 : bn2);
-                                        break;
-                                    case instruction.OP_MAX:
-                                        bn = (bn1 > bn2 ? bn1 : bn2);
-                                        break;
-
-                                    default:
-                                        throw new StackMachineException("invalid instruction");
+                                    // (in -- in size)
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
+
+                                    var bnSize = new BigInteger((ushort)stacktop(ref stack, -1).Count());
+                                    stack.Add(bnSize.ToByteArray());
                                 }
+                                break;
 
-                                popstack(ref stack);
-                                popstack(ref stack);
-                                stack.Add(bn.ToByteArray());
 
-                                if (opcode == instruction.OP_NUMEQUALVERIFY)
+                            //
+                            // Bitwise logic
+                            //
+                            case instruction.OP_EQUAL:
+                            case instruction.OP_EQUALVERIFY:
+                                //case instruction.OP_NOTEQUAL: // use OP_NUMNOTEQUAL
                                 {
-                                    if (CastToBool(stacktop(ref stack, -1)))
+                                    // (x1 x2 - bool)
+                                    if (stack.Count() < 2)
                                     {
-                                        popstack(ref stack);
+                                        return false;
                                     }
-                                    else
+
+                                    var vch1 = stacktop(ref stack, -2);
+                                    var vch2 = stacktop(ref stack, -1);
+                                    bool fEqual = (vch1.SequenceEqual(vch2));
+                                    // OP_NOTEQUAL is disabled because it would be too easy to say
+                                    // something like n != 1 and have some wiseguy pass in 1 with extra
+                                    // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
+                                    //if (opcode == instruction.OP_NOTEQUAL)
+                                    //    fEqual = !fEqual;
+                                    popstack(ref stack);
+                                    popstack(ref stack);
+                                    stack.Add(fEqual ? trueBytes : falseBytes);
+
+                                    if (opcode == instruction.OP_EQUALVERIFY)
                                     {
-                                        return false;
+                                        if (fEqual)
+                                        {
+                                            popstack(ref stack);
+                                        }
+                                        else
+                                        {
+                                            return false;
+                                        }
                                     }
                                 }
-                            }
-                            break;
-
-                        case instruction.OP_WITHIN:
-                            {
-                                // (x min max -- out)
-                                if (stack.Count() < 3)
-                                    return false;
-                                BigInteger bn1 = CastToBigInteger(stacktop(ref stack, -3));
-                                BigInteger bn2 = CastToBigInteger(stacktop(ref stack, -2));
-                                BigInteger bn3 = CastToBigInteger(stacktop(ref stack, -1));
-                                bool fValue = (bn2 <= bn1 && bn1 < bn3);
-                                popstack(ref stack);
-                                popstack(ref stack);
-                                popstack(ref stack);
-                                stack.Add(fValue ? trueBytes : falseBytes);
-                            }
-                            break;
+                                break;
 
 
-                        //
-                        // Crypto
-                        //
-                        case instruction.OP_RIPEMD160:
-                        case instruction.OP_SHA1:
-                        case instruction.OP_SHA256:
-                        case instruction.OP_HASH160:
-                        case instruction.OP_HASH256:
-                            {
-                                // (in -- hash)
-                                if (stack.Count() < 1)
-                                    return false;
-                                IEnumerable<byte> vch = stacktop(ref stack, -1);
-                                IEnumerable<byte> vchHash = null;
-                                if (opcode == instruction.OP_RIPEMD160)
-                                {
-                                    RIPEMD160 hash = RIPEMD160.Compute160(vch);
-                                    vchHash = hash.hashBytes;
-                                }
-                                else if (opcode == instruction.OP_SHA1)
-                                {
-                                    SHA1 hash = SHA1.Compute1(vch);
-                                    vchHash = hash.hashBytes;
-                                }
-                                else if (opcode == instruction.OP_SHA256)
-                                {
-                                    SHA256 hash = SHA256.Compute256(vch);
-                                    vchHash = hash.hashBytes;
-                                }
-                                else if (opcode == instruction.OP_HASH160)
-                                {
-                                    Hash160 hash = Hash160.Compute160(vch);
-                                    vchHash = hash.hashBytes;
-                                }
-                                else if (opcode == instruction.OP_HASH256)
+                            //
+                            // Numeric
+                            //
+                            case instruction.OP_1ADD:
+                            case instruction.OP_1SUB:
+                            case instruction.OP_NEGATE:
+                            case instruction.OP_ABS:
+                            case instruction.OP_NOT:
+                            case instruction.OP_0NOTEQUAL:
                                 {
-                                    Hash256 hash = Hash256.Compute256(vch);
-                                    vchHash = hash.hashBytes;
-                                }
-                                popstack(ref stack);
-                                stack.Add(vchHash);
-                            }
-                            break;
+                                    // (in -- out)
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
 
-                        case instruction.OP_CODESEPARATOR:
-                            {
-                                // Hash starts after the code separator
-                                nCodeHashBegin = CodeQueue.CurrentIndex;
-                            }
-                            break;
+                                    var bn = CastToBigInteger(stacktop(ref stack, -1));
+                                    switch (opcode)
+                                    {
+                                        case instruction.OP_1ADD:
+                                            bn = bn + 1;
+                                            break;
+                                        case instruction.OP_1SUB:
+                                            bn = bn - 1;
+                                            break;
+                                        case instruction.OP_NEGATE:
+                                            bn = -bn;
+                                            break;
+                                        case instruction.OP_ABS:
+                                            bn = BigInteger.Abs(bn);
+                                            break;
+                                        case instruction.OP_NOT:
+                                            bn = bn == 0 ? 1 : 0;
+                                            break;
+                                        case instruction.OP_0NOTEQUAL:
+                                            bn = bn != 0 ? 1 : 0;
+                                            break;
+                                    }
 
-                        case instruction.OP_CHECKSIG:
-                        case instruction.OP_CHECKSIGVERIFY:
-                            {
-                                // (sig pubkey -- bool)
-                                if (stack.Count() < 2)
-                                {
-                                    return false;
+                                    popstack(ref stack);
+                                    stack.Add(bn.ToByteArray());
                                 }
+                                break;
 
-                                IList<byte> sigBytes = stacktop(ref stack, -2).ToList();
-                                IList<byte> pubkeyBytes = stacktop(ref stack, -1).ToList();
+                            case instruction.OP_ADD:
+                            case instruction.OP_SUB:
+                            case instruction.OP_BOOLAND:
+                            case instruction.OP_BOOLOR:
+                            case instruction.OP_NUMEQUAL:
+                            case instruction.OP_NUMEQUALVERIFY:
+                            case instruction.OP_NUMNOTEQUAL:
+                            case instruction.OP_LESSTHAN:
+                            case instruction.OP_GREATERTHAN:
+                            case instruction.OP_LESSTHANOREQUAL:
+                            case instruction.OP_GREATERTHANOREQUAL:
+                            case instruction.OP_MIN:
+                            case instruction.OP_MAX:
+                                {
+                                    // (x1 x2 -- out)
+                                    if (stack.Count() < 2)
+                                    {
+                                        return false;
+                                    }
 
-                                // Subset of script starting at the most recent codeseparator
-                                CScript scriptCode = new CScript(script.Bytes.Skip(nCodeHashBegin));
+                                    var bn1 = CastToBigInteger(stacktop(ref stack, -2));
+                                    var bn2 = CastToBigInteger(stacktop(ref stack, -1));
+                                    BigInteger bn = 0;
 
-                                // There's no way for a signature to sign itself
-                                scriptCode.RemovePattern(sigBytes);
+                                    switch (opcode)
+                                    {
+                                        case instruction.OP_ADD:
+                                            bn = bn1 + bn2;
+                                            break;
+                                        case instruction.OP_SUB:
+                                            bn = bn1 - bn2;
+                                            break;
+                                        case instruction.OP_BOOLAND:
+                                            bn = (bn1 != 0 && bn2 != 0) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_BOOLOR:
+                                            bn = (bn1 != 0 || bn2 != 0) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_NUMEQUAL:
+                                            bn = (bn1 == bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_NUMEQUALVERIFY:
+                                            bn = (bn1 == bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_NUMNOTEQUAL:
+                                            bn = (bn1 != bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_LESSTHAN:
+                                            bn = (bn1 < bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_GREATERTHAN:
+                                            bn = (bn1 > bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_LESSTHANOREQUAL:
+                                            bn = (bn1 <= bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_GREATERTHANOREQUAL:
+                                            bn = (bn1 >= bn2) ? 1 : 0;
+                                            break;
+                                        case instruction.OP_MIN:
+                                            bn = (bn1 < bn2 ? bn1 : bn2);
+                                            break;
+                                        case instruction.OP_MAX:
+                                            bn = (bn1 > bn2 ? bn1 : bn2);
+                                            break;
+                                    }
 
-                                bool fSuccess = IsCanonicalSignature(sigBytes, flags) && IsCanonicalPubKey(pubkeyBytes.ToList(), flags) && CheckSig(sigBytes, pubkeyBytes, scriptCode, txTo, nIn, nHashType, flags);
+                                    popstack(ref stack);
+                                    popstack(ref stack);
+                                    stack.Add(bn.ToByteArray());
 
-                                popstack(ref stack);
-                                popstack(ref stack);
-                                stack.Add(fSuccess ? trueBytes : falseBytes);
-                                if (opcode == instruction.OP_CHECKSIGVERIFY)
-                                {
-                                    if (fSuccess)
+                                    if (opcode == instruction.OP_NUMEQUALVERIFY)
                                     {
-                                        popstack(ref stack);
+                                        if (CastToBool(stacktop(ref stack, -1)))
+                                        {
+                                            popstack(ref stack);
+                                        }
+                                        else
+                                        {
+                                            return false;
+                                        }
                                     }
-                                    else
+                                }
+                                break;
+
+                            case instruction.OP_WITHIN:
+                                {
+                                    // (x min max -- out)
+                                    if (stack.Count() < 3)
                                     {
                                         return false;
                                     }
-                                }
-                            }
-                            break;
 
-                        case instruction.OP_CHECKMULTISIG:
-                        case instruction.OP_CHECKMULTISIGVERIFY:
-                            {
-                                // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
+                                    var bn1 = CastToBigInteger(stacktop(ref stack, -3));
+                                    var bn2 = CastToBigInteger(stacktop(ref stack, -2));
+                                    var bn3 = CastToBigInteger(stacktop(ref stack, -1));
 
-                                int i = 1;
-                                if (stack.Count() < i)
-                                {
-                                    return false;
-                                }
+                                    bool fValue = (bn2 <= bn1 && bn1 < bn3);
 
-                                int nKeysCount = (int)CastToBigInteger(stacktop(ref stack, -i));
-                                if (nKeysCount < 0 || nKeysCount > 20)
-                                {
-                                    return false;
-                                }
-                                nOpCount += nKeysCount;
-                                if (nOpCount > 201)
-                                {
-                                    return false;
+                                    popstack(ref stack);
+                                    popstack(ref stack);
+                                    popstack(ref stack);
+
+                                    stack.Add(fValue ? trueBytes : falseBytes);
                                 }
-                                int ikey = ++i;
-                                i += nKeysCount;
-                                if (stack.Count() < i)
+                                break;
+
+                            //
+                            // Crypto
+                            //
+                            case instruction.OP_RIPEMD160:
+                            case instruction.OP_SHA1:
+                            case instruction.OP_SHA256:
+                            case instruction.OP_HASH160:
+                            case instruction.OP_HASH256:
                                 {
-                                    return false;
+                                    // (in -- hash)
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
+                                    byte[] hash = null;
+                                    var data = stacktop(ref stack, -1);
+
+                                    switch (opcode)
+                                    {
+                                        case instruction.OP_HASH160:
+                                            hash = CryptoUtils.ComputeHash160(data);
+                                            break;
+                                        case instruction.OP_HASH256:
+                                            hash = CryptoUtils.ComputeHash256(data);
+                                            break;
+                                        case instruction.OP_SHA1:
+                                            hash = CryptoUtils.ComputeSha1(data);
+                                            break;
+                                        case instruction.OP_SHA256:
+                                            hash = CryptoUtils.ComputeSha256(data);
+                                            break;
+                                        case instruction.OP_RIPEMD160:
+                                            hash = CryptoUtils.ComputeRipeMD160(data);
+                                            break;
+                                    }
+                                    popstack(ref stack);
+                                    stack.Add(hash);
                                 }
+                                break;
 
-                                int nSigsCount = (int)CastToBigInteger(stacktop(ref stack, -i));
-                                if (nSigsCount < 0 || nSigsCount > nKeysCount)
+                            case instruction.OP_CODESEPARATOR:
                                 {
-                                    return false;
+                                    // Hash starts after the code separator
+                                    nCodeHashBegin = CodeQueue.Index;
                                 }
-                                int isig = ++i;
-                                i += nSigsCount;
-                                if (stack.Count() < i)
+                                break;
+
+                            case instruction.OP_CHECKSIG:
+                            case instruction.OP_CHECKSIGVERIFY:
                                 {
-                                    return false;
-                                }
+                                    // (sig pubkey -- bool)
+                                    if (stack.Count() < 2)
+                                    {
+                                        return false;
+                                    }
 
-                                // Subset of script starting at the most recent codeseparator
-                                CScript scriptCode = new CScript(script.Bytes.Skip(nCodeHashBegin));
+                                    var sigBytes = stacktop(ref stack, -2);
+                                    var pubkeyBytes = stacktop(ref stack, -1);
 
-                                // There is no way for a signature to sign itself, so we need to drop the signatures
-                                for (int k = 0; k < nSigsCount; k++)
-                                {
-                                    IEnumerable<byte> vchSig = stacktop(ref stack, -isig - k);
-                                    scriptCode.RemovePattern(vchSig.ToList());
+                                    // Subset of script starting at the most recent codeseparator
+                                    var scriptCode = new CScript(scriptBytes.Skip(nCodeHashBegin).ToArray());
+
+                                    // There's no way for a signature to sign itself
+                                    scriptCode.RemovePattern(sigBytes);
+
+                                    bool fSuccess = IsCanonicalSignature(sigBytes, flags) && IsCanonicalPubKey(pubkeyBytes, flags) && CheckSig(sigBytes, pubkeyBytes, scriptCode, txTo, nIn, nHashType, flags);
+
+                                    popstack(ref stack);
+                                    popstack(ref stack);
+
+                                    stack.Add(fSuccess ? trueBytes : falseBytes);
+
+                                    if (opcode == instruction.OP_CHECKSIGVERIFY)
+                                    {
+                                        if (fSuccess)
+                                        {
+                                            popstack(ref stack);
+                                        }
+                                        else
+                                        {
+                                            return false;
+                                        }
+                                    }
                                 }
+                                break;
 
-                                bool fSuccess = true;
-                                while (fSuccess && nSigsCount > 0)
+                            case instruction.OP_CHECKMULTISIG:
+                            case instruction.OP_CHECKMULTISIGVERIFY:
                                 {
-                                    IList<byte> sigBytes = stacktop(ref stack, -isig).ToList();
-                                    IList<byte> pubKeyBytes = stacktop(ref stack, -ikey).ToList();
+                                    // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
 
-                                    // Check signature
-                                    bool fOk = IsCanonicalSignature(sigBytes, flags) && IsCanonicalPubKey(pubKeyBytes.ToList(), flags) && CheckSig(sigBytes, pubKeyBytes, scriptCode, txTo, nIn, nHashType, flags);
+                                    int i = 1;
+                                    if (stack.Count() < i)
+                                    {
+                                        return false;
+                                    }
 
-                                    if (fOk)
+                                    int nKeysCount = (int)CastToBigInteger(stacktop(ref stack, -i));
+                                    if (nKeysCount < 0 || nKeysCount > 20)
                                     {
-                                        isig++;
-                                        nSigsCount--;
+                                        return false;
+                                    }
+                                    nOpCount += nKeysCount;
+                                    if (nOpCount > 201)
+                                    {
+                                        return false;
+                                    }
+                                    int ikey = ++i;
+                                    i += nKeysCount;
+                                    if (stack.Count() < i)
+                                    {
+                                        return false;
                                     }
-                                    ikey++;
-                                    nKeysCount--;
 
-                                    // If there are more signatures left than keys left,
-                                    // then too many signatures have failed
-                                    if (nSigsCount > nKeysCount)
+                                    int nSigsCount = (int)CastToBigInteger(stacktop(ref stack, -i));
+                                    if (nSigsCount < 0 || nSigsCount > nKeysCount)
                                     {
-                                        fSuccess = false;
+                                        return false;
+                                    }
+                                    int isig = ++i;
+                                    i += nSigsCount;
+                                    if (stack.Count() < i)
+                                    {
+                                        return false;
                                     }
-                                }
 
-                                while (i-- > 1)
-                                {
-                                    popstack(ref stack);
-                                }
+                                    // Subset of script starting at the most recent codeseparator
+                                    var scriptCode = new CScript(scriptBytes.Skip(nCodeHashBegin).ToArray());
 
-                                // A bug causes CHECKMULTISIG to consume one extra argument
-                                // whose contents were not checked in any way.
-                                //
-                                // Unfortunately this is a potential source of mutability,
-                                // so optionally verify it is exactly equal to zero prior
-                                // to removing it from the stack.
-                                if (stack.Count() < 1)
-                                {
-                                    return false;
-                                }
-                                if ((flags & (int)scriptflag.SCRIPT_VERIFY_NULLDUMMY) != 0 && stacktop(ref stack, -1).Count() != 0)
-                                {
-                                    return false; // CHECKMULTISIG dummy argument not null
-                                }
-                                popstack(ref stack);
+                                    // There is no way for a signature to sign itself, so we need to drop the signatures
+                                    for (int k = 0; k < nSigsCount; k++)
+                                    {
+                                        var vchSig = stacktop(ref stack, -isig - k);
+                                        scriptCode.RemovePattern(vchSig);
+                                    }
 
-                                stack.Add(fSuccess ? trueBytes : falseBytes);
+                                    bool fSuccess = true;
+                                    while (fSuccess && nSigsCount > 0)
+                                    {
+                                        var sigBytes = stacktop(ref stack, -isig);
+                                        var pubKeyBytes = stacktop(ref stack, -ikey);
+
+                                        // Check signature
+                                        bool fOk = IsCanonicalSignature(sigBytes, flags) && IsCanonicalPubKey(pubKeyBytes, flags) && CheckSig(sigBytes, pubKeyBytes, scriptCode, txTo, nIn, nHashType, flags);
+
+                                        if (fOk)
+                                        {
+                                            isig++;
+                                            nSigsCount--;
+                                        }
+                                        ikey++;
+                                        nKeysCount--;
+
+                                        // If there are more signatures left than keys left,
+                                        // then too many signatures have failed
+                                        if (nSigsCount > nKeysCount)
+                                        {
+                                            fSuccess = false;
+                                        }
+                                    }
 
-                                if (opcode == instruction.OP_CHECKMULTISIGVERIFY)
-                                {
-                                    if (fSuccess)
+                                    while (i-- > 1)
                                     {
                                         popstack(ref stack);
                                     }
-                                    else
+
+                                    // A bug causes CHECKMULTISIG to consume one extra argument
+                                    // whose contents were not checked in any way.
+                                    //
+                                    // Unfortunately this is a potential source of mutability,
+                                    // so optionally verify it is exactly equal to zero prior
+                                    // to removing it from the stack.
+                                    if (stack.Count() < 1)
                                     {
                                         return false;
                                     }
+                                    if ((flags & (int)scriptflag.SCRIPT_VERIFY_NULLDUMMY) != 0 && stacktop(ref stack, -1).Count() != 0)
+                                    {
+                                        return false; // CHECKMULTISIG dummy argument not null
+                                    }
+                                    popstack(ref stack);
+
+                                    stack.Add(fSuccess ? trueBytes : falseBytes);
+
+                                    if (opcode == instruction.OP_CHECKMULTISIGVERIFY)
+                                    {
+                                        if (fSuccess)
+                                        {
+                                            popstack(ref stack);
+                                        }
+                                        else
+                                        {
+                                            return false;
+                                        }
+                                    }
                                 }
-                            }
-                            break;
+                                break;
 
-                        default:
-                            return false;
-                    }
+                            default:
+                                return false;
+                        }
 
-                // Size limits
-                if (stack.Count() + altStack.Count() > 1000)
-                {
-                    return false;
+                    // Size limits
+                    if (stack.Count() + altStack.Count() > 1000)
+                    {
+                        return false;
+                    }
                 }
+#if !DEBUG
             }
+            catch (Exception)
+            {
+                // If there are any exceptions then just return false.
+                return false;
+            }
+#endif
 
-
-            if (vfExec.Count() == 0)
+            if (vfExec.Count() != 0)
             {
+                // Something went wrong with conditional instructions.
                 return false;
             }
 
@@ -1954,21 +1705,21 @@ namespace Novacoin
         }
 
 
-        static bool IsCanonicalPubKey(IList<byte> pubKeyBytes, int flags)
+        public static bool IsCanonicalPubKey(byte[] pubKeyBytes, int flags)
         {
             if ((flags & (int)scriptflag.SCRIPT_VERIFY_STRICTENC) == 0)
                 return true;
 
-            if (pubKeyBytes.Count < 33)
+            if (pubKeyBytes.Length < 33)
                 return false;  // Non-canonical public key: too short
             if (pubKeyBytes[0] == 0x04)
             {
-                if (pubKeyBytes.Count != 65)
+                if (pubKeyBytes.Length != 65)
                     return false; // Non-canonical public key: invalid length for uncompressed key
             }
             else if (pubKeyBytes[0] == 0x02 || pubKeyBytes[0] == 0x03)
             {
-                if (pubKeyBytes.Count != 33)
+                if (pubKeyBytes.Length != 33)
                     return false; // Non-canonical public key: invalid length for compressed key
             }
             else
@@ -1978,14 +1729,25 @@ namespace Novacoin
             return true;
         }
 
-        static bool IsCanonicalSignature(IList<byte> sigBytes, int flags)
+        public static bool IsCanonicalSignature(byte[] sigBytes, int flags)
         {
             // STUB
 
             return true;
         }
 
-        static bool CheckSig(IList<byte> vchSig, IList<byte> vchPubKey, CScript scriptCode, CTransaction txTo, int nIn, int nHashType, int flags)
+        /// <summary>
+        /// Check signature.
+        /// </summary>
+        /// <param name="sigBytes">Signature</param>
+        /// <param name="pubkeyBytes">Public key</param>
+        /// <param name="script">Spending script</param>
+        /// <param name="txTo">CTransaction instance</param>
+        /// <param name="nIn">Input number</param>
+        /// <param name="nHashType">Hashing type flag</param>
+        /// <param name="flags">Signature checking flags</param>
+        /// <returns>Checking result</returns>
+        public static bool CheckSig(byte[] sigBytes, byte[] pubkeyBytes, CScript script, CTransaction txTo, int nIn, int nHashType, int flags)
         {
             CPubKey pubkey;
 
@@ -1993,7 +1755,7 @@ namespace Novacoin
             {
                 // Trying to initialize the public key instance
 
-                pubkey = new CPubKey(vchPubKey);
+                pubkey = new CPubKey(pubkeyBytes);
             }
             catch (Exception)
             {
@@ -2007,7 +1769,7 @@ namespace Novacoin
                 return false;
             }
 
-            if (vchSig.Count == 0)
+            if (sigBytes.Length == 0)
             {
                 return false;
             }
@@ -2015,23 +1777,89 @@ namespace Novacoin
             // Hash type is one byte tacked on to the end of the signature
             if (nHashType == 0)
             {
-                nHashType = vchSig.Last();
+                nHashType = sigBytes.Last();
             }
-            else if (nHashType != vchSig.Last())
+            else if (nHashType != sigBytes.Last())
             {
                 return false;
             }
 
             // Remove hash type
-            vchSig.RemoveAt(vchSig.Count - 1);
+            Array.Resize(ref sigBytes, sigBytes.Length - 1);
+
+            var sighash = SignatureHash(script, txTo, nIn, nHashType);
+
+            if (!pubkey.VerifySignature(sighash, sigBytes))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Evaluates the both scriptSig and scriptPubKey.
+        /// </summary>
+        /// <param name="scriptSig"></param>
+        /// <param name="scriptPubKey"></param>
+        /// <param name="txTo">Transaction</param>
+        /// <param name="nIn">Input number</param>
+        /// <param name="flags">Script validation flags</param>
+        /// <param name="nHashType">Hash type flag</param>
+        /// <returns></returns>
+        public static bool VerifyScript(CScript scriptSig, CScript scriptPubKey, CTransaction txTo, int nIn, int flags, int nHashType)
+        {
+            var stack = new List<byte[]>();
+            List<byte[]> stackCopy = null;
 
-            Hash256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
+            if (!EvalScript(ref stack, scriptSig, txTo, nIn, flags, nHashType))
+            {
+                return false;
+            }
 
-            if (!pubkey.VerifySignature(sighash, vchSig))
+            if ((flags & (int)scriptflag.SCRIPT_VERIFY_P2SH) != 0)
+            {
+                stackCopy = new List<byte[]>(stack);
+            }
+
+            if (!EvalScript(ref stack, scriptPubKey, txTo, nIn, flags, nHashType))
             {
                 return false;
             }
 
+            if (stack.Count == 0 || CastToBool(stack.Last()) == false)
+            {
+                return false;
+            }
+
+            // Additional validation for spend-to-script-hash transactions:
+            if ((flags & (int)scriptflag.SCRIPT_VERIFY_P2SH) != 0 && scriptPubKey.IsPayToScriptHash)
+            {
+                if (!scriptSig.IsPushOnly) // scriptSig must be literals-only
+                {
+                    return false;
+                }
+
+                // stackCopy cannot be empty here, because if it was the
+                // P2SH  HASH <> EQUAL  scriptPubKey would be evaluated with
+                // an empty stack and the EvalScript above would return false.
+
+                if (stackCopy.Count == 0)
+                {
+                    throw new StackMachineException("Fatal script validation error.");
+                }
+
+                var pubKey2 = new CScript(stackCopy.Last());
+                popstack(ref stackCopy);
+
+                if (!EvalScript(ref stackCopy, pubKey2, txTo, nIn, flags, nHashType))
+                    return false;
+                if (stackCopy.Count == 0)
+                    return false;
+
+                return CastToBool(stackCopy.Last());
+            }
+
             return true;
         }
     };