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