예제 #1
0
        /// <summary>
        /// Removes the second item from top of stack. Return value indicates success.
        /// </summary>
        /// <param name="opData">Data to use</param>
        /// <param name="error">Error message (null if sucessful, otherwise will contain information about the failure)</param>
        /// <returns>True if operation was successful, false if otherwise</returns>
        public override bool Run(IOpData opData, out string error)
        {
            if (opData.ItemCount < 2)
            {
                error = "There was not enough items left in the stack to drop (\"nip\").";
                return(false);
            }

            opData.PopAtIndex(1); // discard the popped value

            error = null;
            return(true);
        }
        /// <summary>
        /// Removes the second item from top of stack. Return value indicates success.
        /// </summary>
        /// <param name="opData">Data to use</param>
        /// <param name="error">Error message (null if sucessful, otherwise will contain information about the failure)</param>
        /// <returns>True if operation was successful, false if otherwise</returns>
        public override bool Run(IOpData opData, out string error)
        {
            if (opData.ItemCount < 2)
            {
                error = Err.OpNotEnoughItems;
                return(false);
            }

            // Throw away the popped value
            _ = opData.PopAtIndex(1);

            error = null;
            return(true);
        }
        /// <summary>
        /// Moves the nth item from top of the stack to the top. Return value indicates success.
        /// </summary>
        /// <param name="opData">Data to use</param>
        /// <param name="error">Error message (null if sucessful, otherwise will contain information about the failure)</param>
        /// <returns>True if operation was successful, false if otherwise</returns>
        public override bool Run(IOpData opData, out string error)
        {
            // At least 2 items is needed. 1 telling us the index and the other is the item to move
            if (opData.ItemCount < 2)
            {
                error = Err.OpNotEnoughItems;
                return(false);
            }

            byte[] data = opData.Pop();
            // Initial test to reject any huge numbers
            if (data.Length > 4)
            {
                error = "'n' is too big.";
                return(false);
            }

            // TODO: set isStrict field based on BIP62

            if (!TryConvertToLong(data, out long n, true))
            {
                error = "Invalid number format.";
                return(false);
            }
            if (n < 0)
            {
                error = "'n' can not be negative.";
                return(false);
            }
            // 'n' is index so it can't be equal to ItemCount
            if (opData.ItemCount <= n)
            {
                error = Err.OpNotEnoughItems;
                return(false);
            }

            opData.Push(opData.PopAtIndex((int)n));

            error = null;
            return(true);
        }
예제 #4
0
        /// <summary>
        /// Moves the nth item from top of the stack to the top. Return value indicates success.
        /// </summary>
        /// <param name="opData">Data to use</param>
        /// <param name="error">Error message (null if sucessful, otherwise will contain information about the failure)</param>
        /// <returns>True if operation was successful, false if otherwise</returns>
        public override bool Run(IOpData opData, out string error)
        {
            if (opData.ItemCount < 2) // At least 2 items is needed. 1 telling us the index and the other to move
            {
                error = "There was not enough items left in the stack to move to top.";
                return(false);
            }

            byte[] data = opData.Pop();
            if (data.Length > 4) // Initial test to reject any huge numbers
            {
                error = "'n' is too big.";
                return(false);
            }

            if (!OpHelper.TryConvertByteArrayToInt(data, out long n, true)) // TODO: set isStrict field based on BIP62
            {
                error = "Invalid number format.";
                return(false);
            }
            if (n < 0)
            {
                error = "'n' can not be negative.";
                return(false);
            }
            if (opData.ItemCount <= n) // 'n' is index so it can't be equal to ItemCount
            {
                error = "There was not enough items left in the stack to move to top.";
                return(false);
            }

            opData.Push(opData.PopAtIndex((int)n));

            error = null;
            return(true);
        }
예제 #5
0
        /// <summary>
        /// Removes all needed items from the stack as public keys and signatures and calls
        /// <see cref="IOpData.Verify(byte[][], byte[][], int, out string)"/>.
        /// Return value indicates success.
        /// </summary>
        /// <param name="opData">Stack to use</param>
        /// <param name="error">Error message (null if sucessful, otherwise will contain information about the failure)</param>
        /// <returns>True if operation was successful, false if otherwise</returns>
        public bool ExtractAndVerify(IOpData opData, out string error)
        {
            // A multi-sig stack is (extra item, usually OP_0) + (m*sig) + (OP_m) + (n*pub) + (OP_n)
            // both m and n values are needed and the extra item is also mandatory. but since both m and n can be zero
            // the key[] and sig[] can be empty so the smallest stack item count should be 3 items [OP_0 (m=0) (n=0)]
            if (opData.ItemCount < 3)
            {
                error = Err.OpNotEnoughItems;
                return(false);
            }

            byte[] nBa = opData.Pop();
            if (!TryConvertToLong(nBa, out long n, opData.StrictNumberEncoding, maxDataLength: 4))
            {
                error = "Invalid number (n) format.";
                return(false);
            }

            if (n < 0 || n > Constants.MaxMultisigPubkeyCount)
            {
                error = "Invalid number of public keys in multi-sig.";
                return(false);
            }

            opData.OpCount += (int)n;
            if (opData.OpCount > Constants.MaxScriptOpCount)
            {
                error = "Number of OPs in this script exceeds the allowed number.";
                return(false);
            }

            // By knowing n we know the number of public keys and the "index" of m to be popped
            // eg. indes:item => n=3 => 3:m 2:pub1 1:pub2 0:pub3    n=2 => 2:m 1:pub1 0:pub2
            // The "remaining" ItemCount must also have the "garbage" item. Assuming m=0 there is no signatures so min count is:
            //      n=0 : GM(N)   n=1 : GMP(N)    n=2 : GMPP(N)    n=3 : GMPPP(N)
            if (opData.ItemCount < n + 2)
            {
                error = Err.OpNotEnoughItems;
                return(false);
            }

            byte[] mBa = opData.PopAtIndex((int)n);
            if (!TryConvertToLong(mBa, out long m, opData.StrictNumberEncoding, maxDataLength: 4))
            {
                error = "Invalid number (m) format.";
                return(false);
            }
            if (m < 0 || m > n)
            {
                error = "Invalid number of signatures in multi-sig.";
                return(false);
            }

            // Note that m and n are already popped (removed) from the stack so it looks like this:
            // (extra item, usually OP_0) + (m*sig) + (n*pub)
            if (opData.ItemCount < n + m + 1)
            {
                error = Err.OpNotEnoughItems;
                return(false);
            }

            if (n == 0)
            {
                if (opData.CheckMultiSigGarbage(opData.Pop()))
                {
                    error = null;
                    return(true);
                }
                else
                {
                    error = "The extra item should be OP_0.";
                    return(false);
                }
            }

            byte[][] allPubs = opData.Pop((int)n);
            byte[][] allSigs = opData.Pop((int)m);

            // Handle bitcoin-core bug before checking signatures (has to pop 1 extra item)
            byte[] garbage = opData.Pop();
            if (!opData.CheckMultiSigGarbage(garbage))
            {
                error = "The extra item should be OP_0.";
                return(false);
            }

            if (m == 0)
            {
                error = null;
                return(true);
            }

            return(opData.Verify(allSigs, allPubs, (int)m, out error));
        }