/// <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"); } } }
/// <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 })); }