Ejemplo n.º 1
0
        public bool Evaluate(Transaction tx = null, UInt32 txInIndex = 0)
        {
            Stack<IfElseExec> ifExec = new Stack<IfElseExec>();
            int lastCodeSeperator = 0;

            stack.Clear();
            altstack.Clear();

            for (int index = 0; index < elements.Count; index++)
            {
                ScriptElement se = elements[index];
                if (ifExec.Count > 0)
                    if ((ifExec.First() == IfElseExec.SKIP_IF && !(se.opCode == OpCode.OP_ELSE || se.opCode == OpCode.OP_ENDIF)) ||
                        (ifExec.First() == IfElseExec.SKIP_ELSE && !(se.opCode == OpCode.OP_ENDIF)))
                        continue;

                if (se.isData)
                {
                    stack.Push(se.data);
                    continue;
                }

                switch (se.opCode)
                {
                    case OpCode.OP_RESERVED:
                        {
                            return false;
                        }
                    case OpCode.OP_NOP:
                        {
                            // NOP, Dump stack for debug
                            /*
                            stack.ToList().ForEach(x => Console.WriteLine(HexString.FromByteArray(x)));
                            Console.WriteLine("---------------------------");
                            */
                            break;
                        }
                    case OpCode.OP_VER:
                        {
                            return false;
                        }
                    case OpCode.OP_IF:
                    case OpCode.OP_NOTIF:
                        {
                            if (stack.Count < 1)
                                return false;
                            Boolean stackIsZero = new ScriptVarInt(stack.Pop()).value.IsZero;
                            if ((se.opCode == OpCode.OP_IF && !stackIsZero) || (se.opCode == OpCode.OP_NOTIF && stackIsZero))
                            {
                                // Run to else or endif
                                ifExec.Push(IfElseExec.RUN_IF);
                            }
                            else
                            {
                                // Skip to else or endif
                                ifExec.Push(IfElseExec.SKIP_IF);
                            }
                            break;
                        }
                    case OpCode.OP_VERIF:
                    case OpCode.OP_VERNOTIF:
                        {
                            return false;
                        }
                    case OpCode.OP_ELSE:
                        {
                            if (ifExec.Count == 0)
                                // No preceding if statement!
                                return false;
                            if (ifExec.First() == IfElseExec.RUN_IF)
                            {
                                // If ran, skip else
                                ifExec.Push(IfElseExec.SKIP_ELSE);
                            }
                            else if (ifExec.First() == IfElseExec.SKIP_IF)
                            {
                                // If did not run, run else
                                ifExec.Push(IfElseExec.RUN_ELSE);
                            }
                            break;
                        }
                    case OpCode.OP_ENDIF:
                        {
                            if (ifExec.Count == 0)
                                // No preceding if statement!
                                return false;
                            if (ifExec.First() == IfElseExec.RUN_IF ||
                                ifExec.First() == IfElseExec.SKIP_IF)
                            {
                                ifExec.Pop();
                            }
                            else if (ifExec.First() == IfElseExec.RUN_ELSE ||
                               ifExec.First() == IfElseExec.SKIP_ELSE)
                            {
                                ifExec.Pop();
                                ifExec.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_VERIFY:
                        {
                            if (stack.Count < 1 || new ScriptVarInt(stack.First()).value.IsZero)
                                return false;
                            stack.Pop();
                            break;
                        }
                    case OpCode.OP_RETURN:
                        {
                            return false;
                        }
                    case OpCode.OP_TOALTSTACK:
                        {
                            if (stack.Count < 1)
                                return false;
                            altstack.Push(stack.Pop());
                            break;
                        }
                    case OpCode.OP_FROMALTSTACK:
                        {
                            if (altstack.Count < 1)
                                return false;
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_2DROP:
                        {
                            if (stack.Count < 2)
                                return false;
                            stack.Pop();
                            stack.Pop();
                            break;
                        }
                    case OpCode.OP_2DUP:
                        {
                            if (stack.Count < 2)
                                return false;
                            stack.Push(stack.Skip(1).First());
                            stack.Push(stack.Skip(1).First());
                            break;
                        }
                    case OpCode.OP_3DUP:
                        {
                            if (stack.Count < 3)
                                return false;
                            stack.Push(stack.Skip(2).First());
                            stack.Push(stack.Skip(2).First());
                            stack.Push(stack.Skip(2).First());
                            break;
                        }
                    case OpCode.OP_2OVER:
                        {
                            if (stack.Count < 4)
                                return false;
                            stack.Push(stack.Skip(3).First());
                            stack.Push(stack.Skip(3).First());
                            break;
                        }
                    case OpCode.OP_2ROT:
                        {
                            if (stack.Count < 6)
                                return false;
                            altstack.Push(stack.Skip(4).First());
                            altstack.Push(stack.Skip(5).First());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_2SWAP:
                        {
                            if (stack.Count < 4)
                                return false;
                            altstack.Push(stack.Skip(2).First());
                            altstack.Push(stack.Skip(3).First());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_IFDUP:
                        {
                            if (stack.Count < 1)
                                return false;
                            if (!new ScriptVarInt(stack.First()).value.IsZero)
                                stack.Push(stack.First());
                            break;
                        }
                    case OpCode.OP_DEPTH:
                        {
                            stack.Push(new ScriptVarInt((UInt64)stack.Count).ToBytes());
                            break;
                        }
                    case OpCode.OP_DROP:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Pop();
                            break;
                        }
                    case OpCode.OP_DUP:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(stack.First());
                            break;
                        }
                    case OpCode.OP_NIP:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_OVER:
                        {
                            if (stack.Count < 2)
                                return false;
                            stack.Push(stack.Skip(1).First());
                            break;
                        }
                    case OpCode.OP_PICK:
                        {
                            if (stack.Count < 2)
                                return false;
                            int pick = new ScriptVarInt(stack.Pop()).intValue;
                            if (pick < 0 || stack.Count <= pick)
                                return false;
                            stack.Push(stack.Skip(pick).First());
                            break;
                        }
                    case OpCode.OP_ROLL:
                        {
                            if (stack.Count < 2)
                                return false;
                            int roll = new ScriptVarInt(stack.Pop()).intValue;
                            if (roll < 0 || stack.Count <= roll)
                                return false;
                            altstack.Push(stack.Skip(roll).First());
                            for (int i = 0; i < roll; i++)
                                altstack.Push(stack.Pop());
                            stack.Pop();
                            for (int i = 0; i < roll + 1; i++)
                                stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_ROT:
                        {
                            if (stack.Count < 3)
                                return false;
                            altstack.Push(stack.Skip(2).First());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_SWAP:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Skip(1).First());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_TUCK:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Push(altstack.Skip(1).First());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_CAT:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Skip(1).First().Concat(stack.First()).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_SUBSTR:
                        {
                            if (stack.Count < 3)
                                return false;
                            altstack.Push(stack.Skip(2).First()
                                .Skip(new ScriptVarInt(stack.Skip(1).First()).intValue)
                                .Take(new ScriptVarInt(stack.First()).intValue).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_LEFT:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Skip(1).First()
                                .Take(new ScriptVarInt(stack.First()).intValue).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_RIGHT:
                        {
                            if (stack.Count < 2)
                                return false;
                            int count = new ScriptVarInt(stack.First()).intValue;
                            altstack.Push(stack.Skip(1).First()
                                .Skip(stack.Skip(1).First().Length - count).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_SIZE:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(new ScriptVarInt((UInt64)stack.First().Length).ToBytes());
                            break;
                        }
                    case OpCode.OP_INVERT:
                        {
                            if (stack.Count < 1)
                                return false;
                            Byte[] data = stack.Pop();
                            for (int i = 0; i < data.Length; i++)
                                data[i] ^= 0xFF;
                            stack.Push(data);
                            break;
                        }
                    case OpCode.OP_AND:
                    case OpCode.OP_OR:
                    case OpCode.OP_XOR:
                        {
                            if (stack.Count < 2)
                                return false;
                            Byte[] data = stack.Pop();
                            Byte[] data2 = stack.Pop();
                            int length = new int[] { data.Length, data2.Length }.Max();
                            data = data.Concat(new Byte[length - data.Length]).ToArray();
                            data2 = data2.Concat(new Byte[length - data2.Length]).ToArray();
                            switch (se.opCode)
                            {
                                case OpCode.OP_AND:
                                    {
                                        for (int i = 0; i < length; i++)
                                            data[i] &= data2[i];
                                        break;
                                    }
                                case OpCode.OP_OR:
                                    {
                                        for (int i = 0; i < length; i++)
                                            data[i] |= data2[i];
                                        break;
                                    }
                                case OpCode.OP_XOR:
                                    {
                                        for (int i = 0; i < length; i++)
                                            data[i] ^= data2[i];
                                        break;
                                    }
                            }
                            stack.Push(data);
                            break;
                        }
                    case OpCode.OP_EQUAL:
                    case OpCode.OP_EQUALVERIFY:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (stack.Pop().SequenceEqual(stack.Pop()))
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });

                            if (se.opCode == OpCode.OP_EQUALVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_RESERVED1:
                    case OpCode.OP_RESERVED2:
                        {
                            return false;
                        }
                    case OpCode.OP_1ADD:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Add(new ScriptVarInt(stack.Pop()), 1)).ToBytes());
                            break;
                        }
                    case OpCode.OP_1SUB:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Subtract(new ScriptVarInt(stack.Pop()), 1)).ToBytes());
                            break;
                        }
                    case OpCode.OP_2MUL:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Multiply(new ScriptVarInt(stack.Pop()), 2)).ToBytes());
                            break;
                        }
                    case OpCode.OP_2DIV:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Divide(new ScriptVarInt(stack.Pop()), 2)).ToBytes());
                            break;
                        }
                    case OpCode.OP_NEGATE:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Negate(new ScriptVarInt(stack.Pop()))).ToBytes());
                            break;
                        }
                    case OpCode.OP_ABS:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Abs(new ScriptVarInt(stack.Pop()))).ToBytes());
                            break;
                        }
                    case OpCode.OP_NOT:
                        {
                            if (stack.Count < 1)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_0NOTEQUAL:
                        {
                            if (stack.Count < 1)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x00 });
                            else
                                stack.Push(new Byte[] { 0x01 });
                            break;
                        }
                    case OpCode.OP_ADD:
                    case OpCode.OP_SUB:
                    case OpCode.OP_MUL:
                    case OpCode.OP_DIV:
                    case OpCode.OP_MOD:
                    case OpCode.OP_LSHIFT:
                    case OpCode.OP_RSHIFT:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            switch (se.opCode)
                            {
                                case OpCode.OP_ADD:
                                    a = (BigInteger)a + b;
                                    break;
                                case OpCode.OP_SUB:
                                    a = (BigInteger)a - b;
                                    break;
                                case OpCode.OP_MUL:
                                    a = (BigInteger)a * b;
                                    break;
                                case OpCode.OP_DIV:
                                    a = (BigInteger)a / b;
                                    break;
                                case OpCode.OP_MOD:
                                    a = (BigInteger)a % b;
                                    break;
                                case OpCode.OP_LSHIFT:
                                    a = (BigInteger)a << b.intValue;
                                    break;
                                case OpCode.OP_RSHIFT:
                                    a = (BigInteger)a >> b.intValue;
                                    break;
                            }
                            stack.Push(a.ToBytes());
                            break;
                        }
                    case OpCode.OP_BOOLAND:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (!new ScriptVarInt(stack.Pop()).value.IsZero && !new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_BOOLOR:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (!new ScriptVarInt(stack.Pop()).value.IsZero || !new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_NUMEQUAL:
                    case OpCode.OP_NUMEQUALVERIFY:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value == new ScriptVarInt(stack.Pop()).value)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            if (se.opCode == OpCode.OP_NUMEQUALVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_NUMNOTEQUAL:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value != new ScriptVarInt(stack.Pop()).value)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_LESSTHAN:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a < b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_GREATERTHAN:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a > b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_LESSTHANOREQUAL:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a <= b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_GREATERTHANOREQUAL:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a >= b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_MIN:
                        {
                            if (stack.Count < 2)
                                return false;
                            Byte[] b = stack.Pop();
                            Byte[] a = stack.Pop();
                            if (new ScriptVarInt(a).value < new ScriptVarInt(b).value)
                                stack.Push(a);
                            else
                                stack.Push(b);
                            break;
                        }
                    case OpCode.OP_MAX:
                        {
                            if (stack.Count < 2)
                                return false;
                            Byte[] b = stack.Pop();
                            Byte[] a = stack.Pop();
                            if (new ScriptVarInt(a).value > new ScriptVarInt(b).value)
                                stack.Push(a);
                            else
                                stack.Push(b);
                            break;
                        }
                    case OpCode.OP_WITHIN:
                        {
                            if (stack.Count < 3)
                                return false;
                            ScriptVarInt max = new ScriptVarInt(stack.Pop());
                            ScriptVarInt min = new ScriptVarInt(stack.Pop());
                            ScriptVarInt x = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)min <= x && (BigInteger)x <= max)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_RIPEMD160:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(ripemd160.ComputeHash(stack.Pop()));
                            break;
                        }
                    case OpCode.OP_SHA1:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(sha1.ComputeHash(stack.Pop()));
                            break;
                        }
                    case OpCode.OP_SHA256:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(sha256.ComputeHash(stack.Pop()));
                            break;
                        }
                    case OpCode.OP_HASH160:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(ripemd160.ComputeHash(sha256.ComputeHash(stack.Pop())));
                            break;
                        }
                    case OpCode.OP_HASH256:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(sha256.ComputeHash(sha256.ComputeHash(stack.Pop())));
                            break;
                        }
                    case OpCode.OP_CODESEPARATOR:
                        {
                            lastCodeSeperator = index;
                            break;
                        }
                    case OpCode.OP_CHECKSIG:
                    case OpCode.OP_CHECKSIGVERIFY:
                        {
                            if (tx == null)
                                throw new ArgumentNullException("Transaction is required if script contains OP_CHECKSIG[VERIFY]");
                            if (stack.Count < 2)
                                return false;

                            PublicKey pubKey = new PublicKey(stack.Pop());
                            Byte[] sig = stack.Pop();

                            Script subScript = new Script(elements.Skip(lastCodeSeperator)
                                .Where(x => x.opCode != OpCode.OP_CODESEPARATOR).ToArray());

                            stack.Push(new ScriptVarInt(CheckSig(sig, pubKey, txInIndex, subScript, tx) ? 1 : 0).ToBytes());

                            if (se.opCode == OpCode.OP_CHECKSIGVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_CHECKMULTISIG:
                    case OpCode.OP_CHECKMULTISIGVERIFY:
                        {
                            if (tx == null)
                                throw new ArgumentNullException("Transaction is required if script contains OP_CHECKMULTISIG[VERIFY]");
                            if (stack.Count < 2)
                                return false;

                            PublicKey[] pubKeys = new PublicKey[new ScriptVarInt(stack.Pop()).intValue];

                            if (stack.Count < pubKeys.Length + 1)
                                return false;

                            for (int i = 0; i < pubKeys.Length; i++)
                            {
                                pubKeys[i] = new PublicKey(stack.Pop());
                            }

                            Byte[][] sigs = new Byte[new ScriptVarInt(stack.Pop()).intValue][];

                            if (stack.Count < sigs.Length)
                                return false;

                            for (int i = 0; i < sigs.Length; i++)
                            {
                                sigs[i] = stack.Pop();
                            }

                            // Remove extra unused value from stack
                            stack.Pop();

                            Script subScript = new Script(elements.Skip(lastCodeSeperator)
                                .Where(x => x.opCode != OpCode.OP_CODESEPARATOR).ToArray());

                            int validSigs = 0;
                            foreach (Byte[] sig in sigs)
                            {
                                foreach (PublicKey pubKey in pubKeys)
                                {
                                    if (CheckSig(sig, pubKey, txInIndex, subScript, tx))
                                    {
                                        pubKeys = pubKeys.Where(x => x != pubKey).ToArray();
                                        validSigs++;
                                        break;
                                    }
                                }
                            }

                            stack.Push(new ScriptVarInt((validSigs >= sigs.Length) ? 1 : 0).ToBytes());

                            if (se.opCode == OpCode.OP_CHECKMULTISIGVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_NOP1:
                    case OpCode.OP_NOP2:
                    case OpCode.OP_NOP3:
                    case OpCode.OP_NOP4:
                    case OpCode.OP_NOP5:
                    case OpCode.OP_NOP6:
                    case OpCode.OP_NOP7:
                    case OpCode.OP_NOP8:
                    case OpCode.OP_NOP9:
                    case OpCode.OP_NOP10:
                        {
                            break;
                        }
                    case OpCode.OP_SMALLINTEGER:
                    case OpCode.OP_PUBKEYS:
                    case OpCode.OP_PUBKEYHASH:
                    case OpCode.OP_PUBKEY:
                    case OpCode.OP_INVALIDOPCODE:
                    default:
                        {
                            return false;
                        }

                }
            }
            if (ifExec.Count > 0)
                // Missing endif
                return false;
            if (stack.Count > 0 && new ScriptVarInt(stack.First()).value.IsZero)
                return false;
            return true;
        }
Ejemplo n.º 2
0
        public bool Evaluate(Transaction tx = null, UInt32 txInIndex = 0)
        {
            Stack <IfElseExec> ifExec = new Stack <IfElseExec>();
            int lastCodeSeperator     = 0;

            stack.Clear();
            altstack.Clear();

            for (int index = 0; index < elements.Count; index++)
            {
                ScriptElement se = elements[index];
                if (ifExec.Count > 0)
                {
                    if ((ifExec.First() == IfElseExec.SKIP_IF && !(se.opCode == OpCode.OP_ELSE || se.opCode == OpCode.OP_ENDIF)) ||
                        (ifExec.First() == IfElseExec.SKIP_ELSE && !(se.opCode == OpCode.OP_ENDIF)))
                    {
                        continue;
                    }
                }

                if (se.isData)
                {
                    stack.Push(se.data);
                    continue;
                }

                switch (se.opCode)
                {
                case OpCode.OP_RESERVED:
                {
                    return(false);
                }

                case OpCode.OP_NOP:
                {
                    // NOP, Dump stack for debug

                    /*
                     * stack.ToList().ForEach(x => Console.WriteLine(HexString.FromByteArray(x)));
                     * Console.WriteLine("---------------------------");
                     */
                    break;
                }

                case OpCode.OP_VER:
                {
                    return(false);
                }

                case OpCode.OP_IF:
                case OpCode.OP_NOTIF:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    Boolean stackIsZero = new ScriptVarInt(stack.Pop()).value.IsZero;
                    if ((se.opCode == OpCode.OP_IF && !stackIsZero) || (se.opCode == OpCode.OP_NOTIF && stackIsZero))
                    {
                        // Run to else or endif
                        ifExec.Push(IfElseExec.RUN_IF);
                    }
                    else
                    {
                        // Skip to else or endif
                        ifExec.Push(IfElseExec.SKIP_IF);
                    }
                    break;
                }

                case OpCode.OP_VERIF:
                case OpCode.OP_VERNOTIF:
                {
                    return(false);
                }

                case OpCode.OP_ELSE:
                {
                    if (ifExec.Count == 0)
                    {
                        // No preceding if statement!
                        return(false);
                    }
                    if (ifExec.First() == IfElseExec.RUN_IF)
                    {
                        // If ran, skip else
                        ifExec.Push(IfElseExec.SKIP_ELSE);
                    }
                    else if (ifExec.First() == IfElseExec.SKIP_IF)
                    {
                        // If did not run, run else
                        ifExec.Push(IfElseExec.RUN_ELSE);
                    }
                    break;
                }

                case OpCode.OP_ENDIF:
                {
                    if (ifExec.Count == 0)
                    {
                        // No preceding if statement!
                        return(false);
                    }
                    if (ifExec.First() == IfElseExec.RUN_IF ||
                        ifExec.First() == IfElseExec.SKIP_IF)
                    {
                        ifExec.Pop();
                    }
                    else if (ifExec.First() == IfElseExec.RUN_ELSE ||
                             ifExec.First() == IfElseExec.SKIP_ELSE)
                    {
                        ifExec.Pop();
                        ifExec.Pop();
                    }
                    break;
                }

                case OpCode.OP_VERIFY:
                {
                    if (stack.Count < 1 || new ScriptVarInt(stack.First()).value.IsZero)
                    {
                        return(false);
                    }
                    stack.Pop();
                    break;
                }

                case OpCode.OP_RETURN:
                {
                    return(false);
                }

                case OpCode.OP_TOALTSTACK:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Pop());
                    break;
                }

                case OpCode.OP_FROMALTSTACK:
                {
                    if (altstack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_2DROP:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    stack.Pop();
                    stack.Pop();
                    break;
                }

                case OpCode.OP_2DUP:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    stack.Push(stack.Skip(1).First());
                    stack.Push(stack.Skip(1).First());
                    break;
                }

                case OpCode.OP_3DUP:
                {
                    if (stack.Count < 3)
                    {
                        return(false);
                    }
                    stack.Push(stack.Skip(2).First());
                    stack.Push(stack.Skip(2).First());
                    stack.Push(stack.Skip(2).First());
                    break;
                }

                case OpCode.OP_2OVER:
                {
                    if (stack.Count < 4)
                    {
                        return(false);
                    }
                    stack.Push(stack.Skip(3).First());
                    stack.Push(stack.Skip(3).First());
                    break;
                }

                case OpCode.OP_2ROT:
                {
                    if (stack.Count < 6)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(4).First());
                    altstack.Push(stack.Skip(5).First());
                    altstack.Push(stack.Pop());
                    altstack.Push(stack.Pop());
                    altstack.Push(stack.Pop());
                    altstack.Push(stack.Pop());
                    stack.Pop();
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_2SWAP:
                {
                    if (stack.Count < 4)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(2).First());
                    altstack.Push(stack.Skip(3).First());
                    altstack.Push(stack.Pop());
                    altstack.Push(stack.Pop());
                    stack.Pop();
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_IFDUP:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    if (!new ScriptVarInt(stack.First()).value.IsZero)
                    {
                        stack.Push(stack.First());
                    }
                    break;
                }

                case OpCode.OP_DEPTH:
                {
                    stack.Push(new ScriptVarInt((UInt64)stack.Count).ToBytes());
                    break;
                }

                case OpCode.OP_DROP:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Pop();
                    break;
                }

                case OpCode.OP_DUP:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(stack.First());
                    break;
                }

                case OpCode.OP_NIP:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Pop());
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_OVER:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    stack.Push(stack.Skip(1).First());
                    break;
                }

                case OpCode.OP_PICK:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    int pick = new ScriptVarInt(stack.Pop()).intValue;
                    if (pick < 0 || stack.Count <= pick)
                    {
                        return(false);
                    }
                    stack.Push(stack.Skip(pick).First());
                    break;
                }

                case OpCode.OP_ROLL:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    int roll = new ScriptVarInt(stack.Pop()).intValue;
                    if (roll < 0 || stack.Count <= roll)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(roll).First());
                    for (int i = 0; i < roll; i++)
                    {
                        altstack.Push(stack.Pop());
                    }
                    stack.Pop();
                    for (int i = 0; i < roll + 1; i++)
                    {
                        stack.Push(altstack.Pop());
                    }
                    break;
                }

                case OpCode.OP_ROT:
                {
                    if (stack.Count < 3)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(2).First());
                    altstack.Push(stack.Pop());
                    altstack.Push(stack.Pop());
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_SWAP:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(1).First());
                    altstack.Push(stack.Pop());
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_TUCK:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Pop());
                    altstack.Push(stack.Pop());
                    stack.Push(altstack.Skip(1).First());
                    stack.Push(altstack.Pop());
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_CAT:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(1).First().Concat(stack.First()).ToArray());
                    stack.Pop();
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_SUBSTR:
                {
                    if (stack.Count < 3)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(2).First()
                                  .Skip(new ScriptVarInt(stack.Skip(1).First()).intValue)
                                  .Take(new ScriptVarInt(stack.First()).intValue).ToArray());
                    stack.Pop();
                    stack.Pop();
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_LEFT:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    altstack.Push(stack.Skip(1).First()
                                  .Take(new ScriptVarInt(stack.First()).intValue).ToArray());
                    stack.Pop();
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_RIGHT:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    int count = new ScriptVarInt(stack.First()).intValue;
                    altstack.Push(stack.Skip(1).First()
                                  .Skip(stack.Skip(1).First().Length - count).ToArray());
                    stack.Pop();
                    stack.Pop();
                    stack.Push(altstack.Pop());
                    break;
                }

                case OpCode.OP_SIZE:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(new ScriptVarInt((UInt64)stack.First().Length).ToBytes());
                    break;
                }

                case OpCode.OP_INVERT:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    Byte[] data = stack.Pop();
                    for (int i = 0; i < data.Length; i++)
                    {
                        data[i] ^= 0xFF;
                    }
                    stack.Push(data);
                    break;
                }

                case OpCode.OP_AND:
                case OpCode.OP_OR:
                case OpCode.OP_XOR:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    Byte[] data = stack.Pop();
                    Byte[] data2 = stack.Pop();
                    int    length = new int[] { data.Length, data2.Length }.Max();
                    data  = data.Concat(new Byte[length - data.Length]).ToArray();
                    data2 = data2.Concat(new Byte[length - data2.Length]).ToArray();
                    switch (se.opCode)
                    {
                    case OpCode.OP_AND:
                    {
                        for (int i = 0; i < length; i++)
                        {
                            data[i] &= data2[i];
                        }
                        break;
                    }

                    case OpCode.OP_OR:
                    {
                        for (int i = 0; i < length; i++)
                        {
                            data[i] |= data2[i];
                        }
                        break;
                    }

                    case OpCode.OP_XOR:
                    {
                        for (int i = 0; i < length; i++)
                        {
                            data[i] ^= data2[i];
                        }
                        break;
                    }
                    }
                    stack.Push(data);
                    break;
                }

                case OpCode.OP_EQUAL:
                case OpCode.OP_EQUALVERIFY:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    if (stack.Pop().SequenceEqual(stack.Pop()))
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }

                    if (se.opCode == OpCode.OP_EQUALVERIFY)
                    {
                        if (stack.First().Single() == 0x00)
                        {
                            return(false);
                        }
                        stack.Pop();
                    }
                    break;
                }

                case OpCode.OP_RESERVED1:
                case OpCode.OP_RESERVED2:
                {
                    return(false);
                }

                case OpCode.OP_1ADD:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(((ScriptVarInt)BigInteger.Add(new ScriptVarInt(stack.Pop()), 1)).ToBytes());
                    break;
                }

                case OpCode.OP_1SUB:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(((ScriptVarInt)BigInteger.Subtract(new ScriptVarInt(stack.Pop()), 1)).ToBytes());
                    break;
                }

                case OpCode.OP_2MUL:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(((ScriptVarInt)BigInteger.Multiply(new ScriptVarInt(stack.Pop()), 2)).ToBytes());
                    break;
                }

                case OpCode.OP_2DIV:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(((ScriptVarInt)BigInteger.Divide(new ScriptVarInt(stack.Pop()), 2)).ToBytes());
                    break;
                }

                case OpCode.OP_NEGATE:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(((ScriptVarInt)BigInteger.Negate(new ScriptVarInt(stack.Pop()))).ToBytes());
                    break;
                }

                case OpCode.OP_ABS:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(((ScriptVarInt)BigInteger.Abs(new ScriptVarInt(stack.Pop()))).ToBytes());
                    break;
                }

                case OpCode.OP_NOT:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    if (new ScriptVarInt(stack.Pop()).value.IsZero)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_0NOTEQUAL:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    if (new ScriptVarInt(stack.Pop()).value.IsZero)
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    break;
                }

                case OpCode.OP_ADD:
                case OpCode.OP_SUB:
                case OpCode.OP_MUL:
                case OpCode.OP_DIV:
                case OpCode.OP_MOD:
                case OpCode.OP_LSHIFT:
                case OpCode.OP_RSHIFT:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    ScriptVarInt b = new ScriptVarInt(stack.Pop());
                    ScriptVarInt a = new ScriptVarInt(stack.Pop());
                    switch (se.opCode)
                    {
                    case OpCode.OP_ADD:
                        a = (BigInteger)a + b;
                        break;

                    case OpCode.OP_SUB:
                        a = (BigInteger)a - b;
                        break;

                    case OpCode.OP_MUL:
                        a = (BigInteger)a * b;
                        break;

                    case OpCode.OP_DIV:
                        a = (BigInteger)a / b;
                        break;

                    case OpCode.OP_MOD:
                        a = (BigInteger)a % b;
                        break;

                    case OpCode.OP_LSHIFT:
                        a = (BigInteger)a << b.intValue;
                        break;

                    case OpCode.OP_RSHIFT:
                        a = (BigInteger)a >> b.intValue;
                        break;
                    }
                    stack.Push(a.ToBytes());
                    break;
                }

                case OpCode.OP_BOOLAND:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    if (!new ScriptVarInt(stack.Pop()).value.IsZero&& !new ScriptVarInt(stack.Pop()).value.IsZero)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_BOOLOR:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    if (!new ScriptVarInt(stack.Pop()).value.IsZero || !new ScriptVarInt(stack.Pop()).value.IsZero)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_NUMEQUAL:
                case OpCode.OP_NUMEQUALVERIFY:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    if (new ScriptVarInt(stack.Pop()).value == new ScriptVarInt(stack.Pop()).value)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    if (se.opCode == OpCode.OP_NUMEQUALVERIFY)
                    {
                        if (stack.First().Single() == 0x00)
                        {
                            return(false);
                        }
                        stack.Pop();
                    }
                    break;
                }

                case OpCode.OP_NUMNOTEQUAL:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    if (new ScriptVarInt(stack.Pop()).value != new ScriptVarInt(stack.Pop()).value)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_LESSTHAN:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    ScriptVarInt b = new ScriptVarInt(stack.Pop());
                    ScriptVarInt a = new ScriptVarInt(stack.Pop());
                    if ((BigInteger)a < b)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_GREATERTHAN:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    ScriptVarInt b = new ScriptVarInt(stack.Pop());
                    ScriptVarInt a = new ScriptVarInt(stack.Pop());
                    if ((BigInteger)a > b)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_LESSTHANOREQUAL:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    ScriptVarInt b = new ScriptVarInt(stack.Pop());
                    ScriptVarInt a = new ScriptVarInt(stack.Pop());
                    if ((BigInteger)a <= b)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_GREATERTHANOREQUAL:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    ScriptVarInt b = new ScriptVarInt(stack.Pop());
                    ScriptVarInt a = new ScriptVarInt(stack.Pop());
                    if ((BigInteger)a >= b)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_MIN:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    Byte[] b = stack.Pop();
                    Byte[] a = stack.Pop();
                    if (new ScriptVarInt(a).value < new ScriptVarInt(b).value)
                    {
                        stack.Push(a);
                    }
                    else
                    {
                        stack.Push(b);
                    }
                    break;
                }

                case OpCode.OP_MAX:
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }
                    Byte[] b = stack.Pop();
                    Byte[] a = stack.Pop();
                    if (new ScriptVarInt(a).value > new ScriptVarInt(b).value)
                    {
                        stack.Push(a);
                    }
                    else
                    {
                        stack.Push(b);
                    }
                    break;
                }

                case OpCode.OP_WITHIN:
                {
                    if (stack.Count < 3)
                    {
                        return(false);
                    }
                    ScriptVarInt max = new ScriptVarInt(stack.Pop());
                    ScriptVarInt min = new ScriptVarInt(stack.Pop());
                    ScriptVarInt x   = new ScriptVarInt(stack.Pop());
                    if ((BigInteger)min <= x && (BigInteger)x <= max)
                    {
                        stack.Push(new Byte[] { 0x01 });
                    }
                    else
                    {
                        stack.Push(new Byte[] { 0x00 });
                    }
                    break;
                }

                case OpCode.OP_RIPEMD160:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(ripemd160.ComputeHash(stack.Pop()));
                    break;
                }

                case OpCode.OP_SHA1:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(sha1.ComputeHash(stack.Pop()));
                    break;
                }

                case OpCode.OP_SHA256:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(sha256.ComputeHash(stack.Pop()));
                    break;
                }

                case OpCode.OP_HASH160:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(ripemd160.ComputeHash(sha256.ComputeHash(stack.Pop())));
                    break;
                }

                case OpCode.OP_HASH256:
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }
                    stack.Push(sha256.ComputeHash(sha256.ComputeHash(stack.Pop())));
                    break;
                }

                case OpCode.OP_CODESEPARATOR:
                {
                    lastCodeSeperator = index;
                    break;
                }

                case OpCode.OP_CHECKSIG:
                case OpCode.OP_CHECKSIGVERIFY:
                {
                    if (tx == null)
                    {
                        throw new ArgumentNullException("Transaction is required if script contains OP_CHECKSIG[VERIFY]");
                    }
                    if (stack.Count < 2)
                    {
                        return(false);
                    }

                    PublicKey pubKey = new PublicKey(stack.Pop());
                    Byte[]    sig    = stack.Pop();

                    Script subScript = new Script(elements.Skip(lastCodeSeperator)
                                                  .Where(x => x.opCode != OpCode.OP_CODESEPARATOR).ToArray());

                    stack.Push(new ScriptVarInt(CheckSig(sig, pubKey, txInIndex, subScript, tx) ? 1 : 0).ToBytes());

                    if (se.opCode == OpCode.OP_CHECKSIGVERIFY)
                    {
                        if (stack.First().Single() == 0x00)
                        {
                            return(false);
                        }
                        stack.Pop();
                    }
                    break;
                }

                case OpCode.OP_CHECKMULTISIG:
                case OpCode.OP_CHECKMULTISIGVERIFY:
                {
                    if (tx == null)
                    {
                        throw new ArgumentNullException("Transaction is required if script contains OP_CHECKMULTISIG[VERIFY]");
                    }
                    if (stack.Count < 2)
                    {
                        return(false);
                    }

                    PublicKey[] pubKeys = new PublicKey[new ScriptVarInt(stack.Pop()).intValue];

                    if (stack.Count < pubKeys.Length + 1)
                    {
                        return(false);
                    }

                    for (int i = 0; i < pubKeys.Length; i++)
                    {
                        pubKeys[i] = new PublicKey(stack.Pop());
                    }

                    Byte[][] sigs = new Byte[new ScriptVarInt(stack.Pop()).intValue][];

                    if (stack.Count < sigs.Length)
                    {
                        return(false);
                    }

                    for (int i = 0; i < sigs.Length; i++)
                    {
                        sigs[i] = stack.Pop();
                    }

                    // Remove extra unused value from stack
                    stack.Pop();

                    Script subScript = new Script(elements.Skip(lastCodeSeperator)
                                                  .Where(x => x.opCode != OpCode.OP_CODESEPARATOR).ToArray());

                    int validSigs = 0;
                    foreach (Byte[] sig in sigs)
                    {
                        foreach (PublicKey pubKey in pubKeys)
                        {
                            if (CheckSig(sig, pubKey, txInIndex, subScript, tx))
                            {
                                pubKeys = pubKeys.Where(x => x != pubKey).ToArray();
                                validSigs++;
                                break;
                            }
                        }
                    }

                    stack.Push(new ScriptVarInt((validSigs >= sigs.Length) ? 1 : 0).ToBytes());

                    if (se.opCode == OpCode.OP_CHECKMULTISIGVERIFY)
                    {
                        if (stack.First().Single() == 0x00)
                        {
                            return(false);
                        }
                        stack.Pop();
                    }
                    break;
                }

                case OpCode.OP_NOP1:
                case OpCode.OP_NOP2:
                case OpCode.OP_NOP3:
                case OpCode.OP_NOP4:
                case OpCode.OP_NOP5:
                case OpCode.OP_NOP6:
                case OpCode.OP_NOP7:
                case OpCode.OP_NOP8:
                case OpCode.OP_NOP9:
                case OpCode.OP_NOP10:
                {
                    break;
                }

                case OpCode.OP_SMALLINTEGER:
                case OpCode.OP_PUBKEYS:
                case OpCode.OP_PUBKEYHASH:
                case OpCode.OP_PUBKEY:
                case OpCode.OP_INVALIDOPCODE:
                default:
                {
                    return(false);
                }
                }
            }
            if (ifExec.Count > 0)
            {
                // Missing endif
                return(false);
            }
            if (stack.Count > 0 && new ScriptVarInt(stack.First()).value.IsZero)
            {
                return(false);
            }
            return(true);
        }