using System; using System.Text; using System.Collections; using System.Collections.Generic; 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 /// public class CScript { private List codeBytes; /// /// Initializes an empty instance of CScript /// public CScript () { codeBytes = new List(); } /// /// Initializes new instance of CScript and fills it with supplied bytes /// /// List of bytes public CScript(IList bytes) { codeBytes = new List(bytes); } /// /// Initializes new instance of CScript and fills it with supplied bytes /// /// Array of bytes public CScript(byte[] bytes) { codeBytes = new List(bytes); } /// /// Adds specified operation to opcode bytes list /// /// public void AddOp(opcodetype opcode) { if (opcode < opcodetype.OP_0 || opcode > opcodetype.OP_INVALIDOPCODE) { throw new CScriptException("CScript::AddOp() : invalid opcode"); } codeBytes.Add((byte)opcode); } /// /// Adds hash to opcode bytes list. /// New items are added in this format: /// hash_length_byte hash_bytes /// /// Hash160 instance public void AddHash(Hash160 hash) { codeBytes.Add((byte)hash.hashSize); codeBytes.AddRange(hash.hashBytes); } /// /// Adds hash to opcode bytes list. /// New items are added in this format: /// hash_length_byte hash_bytes /// /// Hash256 instance public void AddHash(Hash256 hash) { codeBytes.Add((byte)hash.hashSize); codeBytes.AddRange(hash.hashBytes); } public void PushData(IList dataBytes) { if (dataBytes.Count < (int)opcodetype.OP_PUSHDATA1) { codeBytes.Add((byte)dataBytes.Count); } else if (dataBytes.Count < 0xff) { codeBytes.Add((byte)opcodetype.OP_PUSHDATA1); codeBytes.Add((byte)dataBytes.Count); } else if (dataBytes.Count < 0xffff) { codeBytes.Add((byte)opcodetype.OP_PUSHDATA2); byte[] szBytes = BitConverter.GetBytes((short)dataBytes.Count); if (BitConverter.IsLittleEndian) Array.Reverse(szBytes); codeBytes.AddRange(szBytes); } else if ((uint)dataBytes.Count < 0xffffffff) { codeBytes.Add((byte)opcodetype.OP_PUSHDATA2); byte[] szBytes = BitConverter.GetBytes((uint)dataBytes.Count); if (BitConverter.IsLittleEndian) Array.Reverse(szBytes); codeBytes.AddRange(szBytes); } codeBytes.AddRange(dataBytes); } /// /// Disassemble current script code /// /// Code listing public override string ToString() { StringBuilder sb = new StringBuilder(); WrappedList wCodeBytes = new WrappedList(codeBytes); opcodetype opcode; // Current opcode IEnumerable pushArgs; // OP_PUSHDATAn argument while (ScriptOpcode.GetOp(ref wCodeBytes, out opcode, out pushArgs)) { if (sb.Length != 0) { sb.Append(" "); } if (0 <= opcode && opcode <= opcodetype.OP_PUSHDATA4) { sb.Append(ScriptOpcode.ValueString(pushArgs)); } else { sb.Append(ScriptOpcode.GetOpName(opcode)); } } return sb.ToString(); } } }