Пример #1
0
        public override bool Equals(object obj)
        {
            if (this == obj)
            {
                return(true);
            }

            if (obj == null)
            {
                return(false);
            }

            ScriptChunk other = (ScriptChunk)obj;

            return(this.Opcode == other.Opcode && this.startLocationInProgram == other.startLocationInProgram && this.Data.Equals(other.Data));
        }
Пример #2
0
        /// <summary>
        /// Returns the public key in this script. If a script contains two constants and nothing else, it is assumed to
        /// be a scriptSig (input) for a pay-to-address output and the second constant is returned (the first is the
        /// signature). If a script contains a constant and an ScriptOpCodes.OP_CHECKSIG opcode, the constant is returned as it is
        /// assumed to be a direct pay-to-key scriptPubKey (output) and the first constant is the public key.
        /// </summary>
        public byte[] GetPubKey()
        {
            Thrower.If(this.Chunks.Count() != 2).Throw <ScriptException>("Script not of right size, expecting 2 but got " + this.Chunks.Count());

            ScriptChunk firstChunk  = this.Chunks.ElementAt(0);
            ScriptChunk secondChunk = this.Chunks.ElementAt(1);

            if (firstChunk.Data != null && firstChunk.Data.Length > 2 && secondChunk.Data != null && secondChunk.Data.Length > 2)
            {
                // If we have two large constants assume the input to a pay-to-address output.
                return(secondChunk.Data);
            }

            if (secondChunk.EqualsOpCode(ScriptOpCodes.OP_CHECKSIG) && firstChunk.Data != null && firstChunk.Data.Length > 2)
            {
                // A large constant followed by an ScriptOpCodes.OP_CHECKSIG is the key.
                return(firstChunk.Data);
            }

            throw new ScriptException("Script did not match expected form: " + this);
        }
Пример #3
0
 /// <summary>
 /// Adds the given chunk at the given index in the program
 /// </summary>
 public ScriptBuilder AddChunk(int index, ScriptChunk chunk)
 {
     this.chunks.Insert(index, chunk);
     return(this);
 }
Пример #4
0
 /// <summary>
 /// Adds the given chunk to the end of the program
 /// </summary>
 public ScriptBuilder AddChunk(ScriptChunk chunk)
 {
     return(this.AddChunk(this.chunks.Count(), chunk));
 }
Пример #5
0
        /// <summary>
        /// <p>To run a script, first we parse it which breaks it up into chunks representing pushes of data or logical
        /// opcodes. Then we can run the parsed chunks.</p>
        ///
        /// <p>The reason for this split, instead of just interpreting directly, is to make it easier
        /// to reach into a programs structure and pull out bits of data without having to run it.
        /// This is necessary to render the to/from addresses of transactions in a user interface.
        /// Bitcoin Core does something similar.</p>
        /// </summary>
        /// <param name="program">
        /// The program.
        /// </param>
        /// <exception cref="ScriptException">
        /// </exception>
        private void Parse(byte[] program)
        {
            this.Chunks = new List <ScriptChunk>(5); // Common size.
            using (var stream = new MemoryStream(program))
            {
                using (var reader = new BinaryReader(stream))
                {
                    var initialSize = reader.BaseStream.Length;
                    while (reader.Available() > 0)
                    {
                        var startLocationInProgram = reader.BaseStream.Position;
                        int opcode = reader.ReadByte();

                        long dataToRead = -1;
                        if (opcode >= 0 && opcode < ScriptOpCodes.OP_PUSHDATA1)
                        {
                            // Read some bytes of data, where how many is the opcode value itself.
                            dataToRead = opcode;
                        }
                        else if (opcode == ScriptOpCodes.OP_PUSHDATA1)
                        {
                            if (reader.Available() < 1)
                            {
                                throw new ScriptException("Unexpected end of script");
                            }

                            dataToRead = reader.ReadInt16();
                        }
                        else if (opcode == ScriptOpCodes.OP_PUSHDATA2)
                        {
                            // Read a short, then read that many bytes of data.
                            if (reader.Available() < 2)
                            {
                                throw new ScriptException("Unexpected end of script");
                            }

                            dataToRead = reader.ReadInt32();
                        }
                        else if (opcode == ScriptOpCodes.OP_PUSHDATA4)
                        {
                            // Read a uint32, then read that many bytes of data.
                            // Though this is allowed, because its value cannot be > 520, it should never actually be used
                            if (reader.Available() < 4)
                            {
                                throw new ScriptException("Unexpected end of script");
                            }

                            dataToRead = reader.ReadInt64();
                        }

                        ScriptChunk chunk;
                        if (dataToRead == -1)
                        {
                            chunk = new ScriptChunk(opcode, null, startLocationInProgram);
                        }
                        else
                        {
                            if (dataToRead > reader.Available())
                            {
                                throw new ScriptException("Push of data element that is larger than remaining data");
                            }

                            byte[] data = reader.ReadBytes((int)dataToRead);
                            chunk = new ScriptChunk(opcode, data, startLocationInProgram);
                        }

                        this.Chunks.Add(chunk);
                    }
                }
            }
        }