Beispiel #1
0
        /// <summary>
        /// Verifies that this script (interpreted as a scriptSig) correctly spends the given scriptPubKey. </summary>
        /// <param name="txContainingThis"> The transaction in which this input scriptSig resides. </param>
        /// <param name="scriptSigIndex"> The index in txContainingThis of the scriptSig (note: NOT the index of the scriptPubKey). </param>
        /// <param name="scriptPubKey"> The connected scriptPubKey containing the conditions needed to claim the value. </param>
        /// <param name="enforceP2SH"> Whether "pay to script hash" rules should be enforced. If in doubt, set to true. </param>
        /// <exception cref="VerificationException"> if this script does not correctly spend the scriptPubKey </exception>
        public virtual void CorrectlySpends(Transaction txContainingThis, long scriptSigIndex, Script scriptPubKey, bool enforceP2SH)
        {
            if (program.Length > 10000 || scriptPubKey.program.Length > 10000)
            {
                throw new ScriptException("Script larger than 10,000 bytes");
            }

            Stack <byte[]> stack     = new Stack <byte[]>();
            Stack <byte[]> p2shStack = null;

            ScriptRunner.ExecuteScript(txContainingThis, scriptSigIndex, this, stack);
            if (enforceP2SH)
            {
                p2shStack = new Stack <byte[]>(stack);
            }
            ScriptRunner.ExecuteScript(txContainingThis, scriptSigIndex, scriptPubKey, stack);

            if (stack.Count == 0)
            {
                throw new ScriptException("Stack empty at end of script execution.");
            }

            if (!ScriptRunner.CastToBool(stack.Pop()))
            {
                throw new ScriptException("Script resulted in a non-true stack");
            }

            // P2SH is pay to script hash. It means that the scriptPubKey has a special form which is a valid
            // program but it has "useless" form that if evaluated as a normal program always returns true.
            // Instead, miners recognize it as special based on its template - it provides a hash of the real scriptPubKey
            // and that must be provided by the input. The goal of this bizarre arrangement is twofold:
            //
            // (1) You can sum up a large, complex script (like a CHECKMULTISIG script) with an address that's the same
            //     size as a regular address. This means it doesn't overload scannable QR codes/NFC tags or become
            //     un-wieldy to copy/paste.
            // (2) It allows the working set to be smaller: nodes perform best when they can store as many unspent outputs
            //     in RAM as possible, so if the outputs are made smaller and the inputs get bigger, then it's better for
            //     overall scalability and performance.

            // TODO: Check if we can take out enforceP2SH if there's a checkpoint at the enforcement block.
            if (enforceP2SH && scriptPubKey.PayToScriptHash)
            {
                foreach (ScriptChunk chunk in chunks)
                {
                    if (chunk.IsOpCode && (OpCode)(chunk.Data[0] & 0xff) > OpCode.OP_16)
                    {
                        throw new ScriptException("Attempted to spend a P2SH scriptPubKey with a script that contained script ops");
                    }
                }

                byte[] scriptPubKeyBytes = p2shStack.Pop();
                var    scriptPubKeyP2SH  = new Script(netParams, scriptPubKeyBytes, 0, scriptPubKeyBytes.Length);

                ScriptRunner.ExecuteScript(txContainingThis, scriptSigIndex, scriptPubKeyP2SH, p2shStack);

                if (p2shStack.Count == 0)
                {
                    throw new ScriptException("P2SH stack empty at end of script execution.");
                }

                if (!ScriptRunner.CastToBool(p2shStack.Pop()))
                {
                    throw new ScriptException("P2SH script execution resulted in a non-true stack");
                }
            }
        }
Beispiel #2
0
 /// <summary>
 /// Returns the script bytes of inputScript with all instances of the given op code removed
 /// </summary>
 public static byte[] RemoveAllInstancesOfOp(byte[] inputScript, int opCode)
 {
     return(ScriptRunner.RemoveAllInstancesOf(inputScript, new byte[] { (byte)opCode }));
 }