X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=Novacoin%2FCScript.cs;h=229b60b8284554c5b370eefb2f3bc15fbf650eb1;hb=be9d844557911f95165d2c9875c4f5b2822cfc92;hp=f5ea0369a22ed2e24cca52eecc978396998151da;hpb=70c6f23891b719dacc4c6b55a0a6c749d069136a;p=NovacoinLibrary.git diff --git a/Novacoin/CScript.cs b/Novacoin/CScript.cs index f5ea036..229b60b 100644 --- a/Novacoin/CScript.cs +++ b/Novacoin/CScript.cs @@ -20,26 +20,10 @@ using System; using System.Linq; using System.Text; using System.Collections.Generic; +using System.Diagnostics.Contracts; namespace Novacoin { - public class CScriptException : Exception - { - public CScriptException() - { - } - - public CScriptException(string message) - : base(message) - { - } - - public CScriptException(string message, Exception inner) - : base(message, inner) - { - } - } - /// /// Representation of script code /// @@ -68,9 +52,9 @@ namespace Novacoin /// Return a new instance of ByteQueue object for current code bytes /// /// - public ByteQueue GetByteQUeue() + public ByteQueue GetByteQueue() { - return new ByteQueue(codeBytes); + return new ByteQueue(ref codeBytes); } /// @@ -79,10 +63,7 @@ namespace Novacoin /// public void AddInstruction(instruction opcode) { - if (opcode < instruction.OP_0 || opcode > instruction.OP_INVALIDOPCODE) - { - throw new CScriptException("CScript::AddInstruction() : invalid instruction"); - } + Contract.Requires(opcode >= instruction.OP_0 && opcode <= instruction.OP_INVALIDOPCODE, "Invalid instruction."); codeBytes.Add((byte)opcode); } @@ -96,7 +77,7 @@ namespace Novacoin public void AddHash(Hash160 hash) { codeBytes.Add((byte)hash.hashSize); - codeBytes.AddRange(hash.hashBytes); + codeBytes.AddRange((byte[])hash); } /// @@ -108,7 +89,7 @@ namespace Novacoin public void AddHash(Hash256 hash) { codeBytes.Add((byte)hash.hashSize); - codeBytes.AddRange(hash.hashBytes); + codeBytes.AddRange((byte[])hash); } /// @@ -132,18 +113,18 @@ namespace Novacoin } else if (nCount < 0xffff) { - // OP_PUSHDATA1 0x00 0x01 [0x5a] + // OP_PUSHDATA1 0x01 0x00 [0x5a] codeBytes.Add((byte)instruction.OP_PUSHDATA2); - var szBytes = Interop.BEBytes((ushort)nCount); + var szBytes = BitConverter.GetBytes((ushort)nCount); codeBytes.AddRange(szBytes); } else if (nCount < 0xffffffff) { - // OP_PUSHDATA1 0x00 0x00 0x00 0x01 [0x5a] + // OP_PUSHDATA1 0x01 0x00 0x00 0x00 [0x5a] codeBytes.Add((byte)instruction.OP_PUSHDATA4); - var szBytes = Interop.BEBytes((uint)nCount); + var szBytes = BitConverter.GetBytes((uint)nCount); codeBytes.AddRange(szBytes); } @@ -152,21 +133,31 @@ namespace Novacoin } /// + /// Just insert data array without including any prefixes. Please make sure that you know what you're doing, + /// it is recommended to use AddInstruction, AddHash or PushData instead. + /// + /// Data bytes + public void AddRawData(byte[] dataBytes) + { + // Add data bytes + codeBytes.AddRange(dataBytes); + } + + /// /// Scan pushed data bytes for pattern and, in case of exact match, remove it. /// /// Pattern sequence /// Matches count public int RemovePattern(byte[] pattern) { - // There is no sense to continue if pattern is longer than script itself + // There is no sense to continue if pattern is empty or longer than script itself if (pattern.Length == 0 || pattern.Length > codeBytes.Count) { return 0; } var count = 0; - var bq1 = new ByteQueue(codeBytes); - + var bq1 = new ByteQueue(ref codeBytes); byte[] pushData; instruction opcode; @@ -191,7 +182,11 @@ namespace Novacoin } } - codeBytes = newScript.codeBytes; + if (count > 0) + { + // Replace current script if any matches were found + codeBytes = newScript.codeBytes; + } return count; } @@ -203,23 +198,23 @@ namespace Novacoin /// Matches count public int RemoveInstruction(instruction op) { - var count = 0; - var bq1 = new ByteQueue(codeBytes); - - byte[] pushData; instruction opcode; + var count = 0; var newScript = new CScript(); + var bq1 = new ByteQueue(ref codeBytes); while (ScriptCode.GetOp(ref bq1, out opcode, out pushData)) { - if (pushData.Length != 0) + if (pushData.Length != 0 && op != opcode) { + // If instruction didn't match then push its data again newScript.PushData(pushData); } else if (Enum.IsDefined(typeof(instruction), op) && op != opcode) { + // Instruction didn't match newScript.AddInstruction(opcode); } else @@ -228,7 +223,11 @@ namespace Novacoin } } - codeBytes = newScript.codeBytes; + if (count > 0) + { + // Replace current script if any matches were found + codeBytes = newScript.codeBytes; + } return count; } @@ -240,7 +239,7 @@ namespace Novacoin { get { - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); instruction opcode; // Current instruction byte[] pushArgs; // OP_PUSHDATAn argument @@ -266,7 +265,7 @@ namespace Novacoin { get { - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); byte[] pushArgs; // OP_PUSHDATAn argument instruction opcode; // Current instruction @@ -353,14 +352,14 @@ namespace Novacoin /// /// Legacy mode flag /// Amount of sigops - public int GetSigOpCount(bool fAccurate) + public uint GetSigOpCount(bool fAccurate) { - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); instruction opcode; // Current instruction byte[] pushArgs; // OP_PUSHDATAn argument - int nCount = 0; + uint nCount = 0; var lastOpcode = instruction.OP_INVALIDOPCODE; // Scan instructions sequence @@ -374,7 +373,7 @@ namespace Novacoin { if (fAccurate && lastOpcode >= instruction.OP_1 && lastOpcode <= instruction.OP_16) { - nCount += ScriptCode.DecodeOP_N(lastOpcode); + nCount += (uint)ScriptCode.DecodeOP_N(lastOpcode); } else { @@ -392,7 +391,7 @@ namespace Novacoin /// /// pay-to-script-hash scriptPubKey /// SigOps count - public int GetSigOpCount(CScript scriptSig) + public uint GetSigOpCount(CScript scriptSig) { if (!IsPayToScriptHash) { @@ -402,13 +401,20 @@ namespace Novacoin // This is a pay-to-script-hash scriptPubKey; // get the last item that the scriptSig // pushes onto the stack: - ByteQueue wScriptSig = scriptSig.GetByteQUeue(); + ByteQueue wScriptSig = scriptSig.GetByteQueue(); + int nScriptSigSize = scriptSig.Size; instruction opcode; // Current instruction - byte[] pushArgs; // OP_PUSHDATAn argument + byte[] pushArgs = new byte[0]; // OP_PUSHDATAn argument + - while (ScriptCode.GetOp(ref wScriptSig, out opcode, out pushArgs)) + while (wScriptSig.Index < nScriptSigSize) { + if (!ScriptCode.GetOp(ref wScriptSig, out opcode, out pushArgs)) + { + return 0; + } + if (opcode > instruction.OP_16) { return 0; @@ -429,7 +435,7 @@ namespace Novacoin public void SetDestination(CPubKey pubKey) { codeBytes.Clear(); - PushData(pubKey.PublicBytes); + PushData(pubKey); AddInstruction(instruction.OP_CHECKSIG); } @@ -479,7 +485,7 @@ namespace Novacoin foreach (var key in keys) { - PushData(key.PublicBytes); + PushData(key); } AddInstruction(ScriptCode.EncodeOP_N(keys.Length)); @@ -489,9 +495,17 @@ namespace Novacoin /// /// Access to script code. /// - public byte[] Bytes + public static implicit operator byte[] (CScript script) + { + return script.codeBytes.ToArray(); + } + + /// + /// Script size + /// + public int Size { - get { return codeBytes.ToArray(); } + get { return codeBytes.Count; } } public CScriptID ScriptID @@ -506,7 +520,7 @@ namespace Novacoin public override string ToString() { var sb = new StringBuilder(); - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); instruction opcode; // Current instruction byte[] pushArgs; // OP_PUSHDATAn argument