X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=Novacoin%2FScriptCode.cs;h=ab0db3fe04b795a77ee2235f977dbb762da1528a;hb=1dcac5faa2b1477034f82466ffb16170fa2e9bb6;hp=e1964b35b6a752fb5f1dd981297a461a3b9801ff;hpb=397772c7e6df61eaf558b3502ae403b7abfd86a2;p=NovacoinLibrary.git diff --git a/Novacoin/ScriptCode.cs b/Novacoin/ScriptCode.cs index e1964b3..ab0db3f 100644 --- a/Novacoin/ScriptCode.cs +++ b/Novacoin/ScriptCode.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.Linq; using System.Numerics; using System.Text; @@ -246,23 +247,18 @@ namespace Novacoin /// Found instruction. /// IEnumerable out param which is used to get the push arguments. /// Result of operation - public static bool GetOp(ref ByteQueue codeBytes, out instruction opcodeRet, out byte[] bytesRet) + public static bool GetOp(ref InstructionQueue codeBytes, out instruction opcodeRet, out byte[] bytesRet) { bytesRet = new byte[0]; - opcodeRet = instruction.OP_INVALIDOPCODE; + instruction opcode = opcodeRet = instruction.OP_INVALIDOPCODE; - instruction opcode; - - try + // Read instruction + byte opVal = 0xff; + if (!codeBytes.TryGet(ref opVal)) { - // Read instruction - opcode = (instruction)codeBytes.Get(); - } - catch (ByteQueueException) - { - // No instruction found there return false; } + opcode = (instruction)opVal; // Immediate operand if (opcode <= instruction.OP_PUSHDATA4) @@ -296,7 +292,7 @@ namespace Novacoin nSize = BitConverter.ToInt32(codeBytes.Get(4), 0); } } - catch (ByteQueueException) + catch (InstructionQueueException) { // Unable to read operand length return false; @@ -304,13 +300,8 @@ namespace Novacoin if (nSize > 0) { - // If nSize is greater than zero then there is some data available - try - { - // Read found number of bytes into list of OP_PUSHDATAn arguments. - bytesRet = codeBytes.Get(nSize); - } - catch (ByteQueueException) + // Trying to read found number of bytes into list of OP_PUSHDATAn arguments. + if (!codeBytes.TryGet(nSize, ref bytesRet)) { // Unable to read data return false; @@ -369,23 +360,18 @@ namespace Novacoin /// Small integer public static int DecodeOP_N(instruction opcode, bool AllowNegate = false) { - if (AllowNegate && opcode == instruction.OP_1NEGATE) - { - return -1; - } - - if (opcode == instruction.OP_0) - { - return 0; - } - // Only OP_n instructions are supported, throw exception otherwise. - if (opcode < instruction.OP_1 || opcode > instruction.OP_16) + Contract.Requires((opcode == instruction.OP_1NEGATE && AllowNegate) || (opcode >= instruction.OP_0 && opcode <= instruction.OP_16), "Invalid integer instruction."); + + switch (opcode) { - throw new ArgumentException("Invalid integer instruction."); + case instruction.OP_1NEGATE: + return -1; + case instruction.OP_0: + return 0; + default: + return (int)opcode - (int)(instruction.OP_1 - 1); } - - return (int)opcode - (int)(instruction.OP_1 - 1); } /// @@ -395,20 +381,18 @@ namespace Novacoin /// Corresponding instruction. public static instruction EncodeOP_N(int n, bool allowNegate = false) { - if (allowNegate && n == -1) - { - return instruction.OP_1NEGATE; - } + // The n value must be in the range of 1 to 16. + Contract.Requires((n == -1 && allowNegate) || (n >= 0 && n <= 16), "Invalid integer value."); - if (n == 0) + switch (n) { - return instruction.OP_0; + case -1: + return instruction.OP_1NEGATE; + case 0: + return instruction.OP_0; + default: + return (instruction.OP_1 + n - 1); } - - // The n value must be in the range of 0 to 16. - if (n < 0 || n > 16) - throw new ArgumentException("Invalid integer value."); - return (instruction.OP_1 + n - 1); } public static int ScriptSigArgsExpected(txnouttype t, IList solutions) @@ -478,6 +462,8 @@ namespace Novacoin /// Result public static bool Solver(CScript scriptPubKey, out txnouttype typeRet, out IList solutions) { + byte[] scriptBytes = scriptPubKey; + solutions = new List(); // There are shortcuts for pay-to-script-hash and pay-to-pubkey-hash, which are more constrained than the other types. @@ -488,7 +474,7 @@ namespace Novacoin typeRet = txnouttype.TX_SCRIPTHASH; // Take 20 bytes with offset of 2 bytes - var hashBytes = scriptPubKey.Bytes.Skip(2).Take(20); + var hashBytes = scriptBytes.Skip(2).Take(20); solutions.Add(hashBytes.ToArray()); return true; @@ -500,7 +486,7 @@ namespace Novacoin typeRet = txnouttype.TX_PUBKEYHASH; // Take 20 bytes with offset of 3 bytes - var hashBytes = scriptPubKey.Bytes.Skip(3).Take(20); + var hashBytes = scriptBytes.Skip(3).Take(20); solutions.Add(hashBytes.ToArray()); return true; @@ -555,17 +541,17 @@ namespace Novacoin instruction opcode1, opcode2; // Compare - var bq1 = script1.GetByteQUeue(); - var bq2 = script2.GetByteQUeue(); + var bq1 = script1.GetInstructionQueue(); + var bq2 = script2.GetInstructionQueue(); byte[] args1, args2; - int last1 = script1.Bytes.Count() -1; - int last2 = script2.Bytes.Count() - 1; + int last1 = ((byte[])script1).Length - 1; + int last2 = ((byte[])script2).Length - 1; while (true) { - if (bq1.CurrentIndex == last1 && bq2.CurrentIndex == last2) + if (bq1.Index == last1 && bq2.Index == last2) { // Found a match typeRet = templateTuple.Item1; @@ -670,14 +656,9 @@ namespace Novacoin /// Input number /// Hash type flag /// - public static Hash256 SignatureHash(CScript script, CTransaction txTo, int nIn, int nHashType) + public static uint256 SignatureHash(CScript script, CTransaction txTo, int nIn, int nHashType) { - if (nIn >= txTo.vin.Length) - { - var sb = new StringBuilder(); - sb.AppendFormat("ERROR: SignatureHash() : nIn={0} out of range\n", nIn); - throw new ArgumentOutOfRangeException("nIn", sb.ToString()); - } + Contract.Requires(nIn < txTo.vin.Length, "nIn out of range."); // Init a copy of transaction var txTmp = new CTransaction(txTo); @@ -743,10 +724,10 @@ namespace Novacoin } // Concatenate and hash - var txBytes = txTmp.Bytes; + var txBytes = (byte[])txTmp; var nHashTypeBytes = BitConverter.GetBytes(nHashType); - return Hash256.Compute256(ref txBytes, ref nHashTypeBytes); + return CryptoUtils.ComputeHash256(ref txBytes, ref nHashTypeBytes); } // @@ -757,6 +738,7 @@ namespace Novacoin /// /// Script machine exception /// + [Serializable] public class StackMachineException : Exception { public StackMachineException() @@ -780,10 +762,9 @@ namespace Novacoin /// Stack reference private static void popstack(ref List stack) { - int nCount = stack.Count; - if (nCount == 0) - throw new StackMachineException("popstack() : stack empty"); - stack.RemoveAt(nCount - 1); + Contract.Requires(stack.Count > 0, "Stack is empty."); + + stack.RemoveAt(stack.Count - 1); } /// @@ -794,25 +775,10 @@ namespace Novacoin /// Byte sequence private static byte[] stacktop(ref List stack, int nDepth) { - int nStackElement = stack.Count + nDepth; - - if (nDepth >= 0) - { - StringBuilder sb = new StringBuilder(); - sb.AppendFormat("stacktop() : positive depth ({0}) has no sense.", nDepth); - - throw new StackMachineException(sb.ToString()); - } - - if (nStackElement < 0) - { - StringBuilder sb = new StringBuilder(); - sb.AppendFormat("stacktop() : nDepth={0} exceeds real stack depth ({1})", nDepth, stack.Count); - - throw new StackMachineException(sb.ToString()); - } + Contract.Requires(nDepth < 0, "Positive or zero stack depth makes no sense."); + Contract.Requires(stack.Count + nDepth >= 0, "Value exceeds real stack depth."); - return stack[nStackElement]; + return stack[stack.Count + nDepth]; } /// @@ -846,10 +812,7 @@ namespace Novacoin /// private static BigInteger CastToBigInteger(byte[] value) { - if (value.Length > 4) - { - throw new StackMachineException("CastToBigInteger() : overflow"); - } + Contract.Requires(value.Length <= 4, "Size limit failed."); return new BigInteger(value); } @@ -866,7 +829,9 @@ namespace Novacoin /// public static bool EvalScript(ref List stack, CScript script, CTransaction txTo, int nIn, int flags, int nHashType) { - if (script.Bytes.Count() > 10000) + var scriptBytes = ((byte[])script); + + if (scriptBytes.Length > 10000) { return false; // Size limit failed } @@ -879,11 +844,13 @@ namespace Novacoin var falseBytes = new byte[0]; var trueBytes = new byte[] { 0x01 }; - var CodeQueue = script.GetByteQUeue(); + var CodeQueue = script.GetInstructionQueue(); var altStack = new List(); +#if !DEBUG try { +#endif instruction opcode; byte[] pushArg; @@ -1525,36 +1492,36 @@ namespace Novacoin { return false; } - Hash hash = null; + byte[] hash = null; var data = stacktop(ref stack, -1); switch (opcode) { case instruction.OP_HASH160: - hash = Hash160.Compute160(data); + hash = CryptoUtils.ComputeHash160(data); break; case instruction.OP_HASH256: - hash = Hash256.Compute256(data); + hash = CryptoUtils.ComputeHash256(data); break; case instruction.OP_SHA1: - hash = SHA1.Compute1(data); + hash = CryptoUtils.ComputeSha1(data); break; case instruction.OP_SHA256: - hash = SHA256.Compute256(data); + hash = CryptoUtils.ComputeSha256(data); break; case instruction.OP_RIPEMD160: - hash = RIPEMD160.Compute160(data); + hash = CryptoUtils.ComputeRipeMD160(data); break; } popstack(ref stack); - stack.Add(hash.hashBytes); + stack.Add(hash); } break; case instruction.OP_CODESEPARATOR: { // Hash starts after the code separator - nCodeHashBegin = CodeQueue.CurrentIndex; + nCodeHashBegin = CodeQueue.Index; } break; @@ -1571,7 +1538,7 @@ namespace Novacoin var pubkeyBytes = stacktop(ref stack, -1); // Subset of script starting at the most recent codeseparator - var scriptCode = new CScript(script.Bytes.Skip(nCodeHashBegin).ToArray()); + var scriptCode = new CScript(scriptBytes.Skip(nCodeHashBegin).ToArray()); // There's no way for a signature to sign itself scriptCode.RemovePattern(sigBytes); @@ -1638,7 +1605,7 @@ namespace Novacoin } // Subset of script starting at the most recent codeseparator - var scriptCode = new CScript(script.Bytes.Skip(nCodeHashBegin).ToArray()); + var scriptCode = new CScript(scriptBytes.Skip(nCodeHashBegin).ToArray()); // There is no way for a signature to sign itself, so we need to drop the signatures for (int k = 0; k < nSigsCount; k++) @@ -1719,12 +1686,14 @@ namespace Novacoin return false; } } +#if !DEBUG } catch (Exception) { // If there are any exceptions then just return false. return false; } +#endif if (vfExec.Count() != 0) {