X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=Novacoin%2FScriptCode.cs;h=14bc2e5d45668edb72449cd0d0d3f2573ec642ed;hb=0fe762d6eee8a8a23033f813217c1675a34f2d6a;hp=19850c90d1a30e2ac46505cb89c8a14b6e20bd14;hpb=70c6f23891b719dacc4c6b55a0a6c749d069136a;p=NovacoinLibrary.git diff --git a/Novacoin/ScriptCode.cs b/Novacoin/ScriptCode.cs index 19850c9..14bc2e5 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,72 +247,61 @@ 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) { var szBytes = new byte[4] { 0, 0, 0, 0 }; // Zero length + int nSize = 0; try { if (opcode < instruction.OP_PUSHDATA1) { // Zero value instructions (OP_0, OP_FALSE) - szBytes[3] = (byte)opcode; + nSize = (int) opcode; } else if (opcode == instruction.OP_PUSHDATA1) { // The next byte contains the number of bytes to be pushed onto the stack, // i.e. you have something like OP_PUSHDATA1 0x01 [0x5a] - szBytes[3] = codeBytes.Get(); + nSize = codeBytes.Get(); } else if (opcode == instruction.OP_PUSHDATA2) { // The next two bytes contain the number of bytes to be pushed onto the stack, - // i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a] - codeBytes.Get(2).CopyTo(szBytes, 2); + // i.e. now your operation will seem like this: OP_PUSHDATA2 0x01 0x00 [0x5a] + nSize = BitConverter.ToInt16(codeBytes.Get(2), 0); } else if (opcode == instruction.OP_PUSHDATA4) { // The next four bytes contain the number of bytes to be pushed onto the stack, - // OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a] - szBytes = codeBytes.Get(4); + // OP_PUSHDATA4 0x01 0x00 0x00 0x00 [0x5a] + nSize = BitConverter.ToInt32(codeBytes.Get(4), 0); } } - catch (ByteQueueException) + catch (InstructionQueueException) { // Unable to read operand length return false; } - int nSize = (int)Interop.BEBytesToUInt32(szBytes); - 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; @@ -337,7 +327,7 @@ namespace Novacoin if (bytes.Length <= 4) { - sb.Append(Interop.BEBytesToUInt32(bytes)); + sb.Append(new BigInteger(bytes)); } else { @@ -370,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); } /// @@ -396,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) @@ -479,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. @@ -489,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; @@ -501,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; @@ -556,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; @@ -673,12 +658,7 @@ namespace Novacoin /// public static Hash256 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); @@ -744,7 +724,7 @@ 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); @@ -758,6 +738,7 @@ namespace Novacoin /// /// Script machine exception /// + [Serializable] public class StackMachineException : Exception { public StackMachineException() @@ -781,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); } /// @@ -795,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); + Contract.Requires(nDepth < 0, "Positive or zero stack depth makes no sense."); + Contract.Requires(stack.Count + nDepth >= 0, "Value exceeds real stack depth."); - 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()); - } - - return stack[nStackElement]; + return stack[stack.Count + nDepth]; } /// @@ -847,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); } @@ -867,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 } @@ -880,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; @@ -1526,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; @@ -1572,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); @@ -1639,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++) @@ -1720,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) {