Пример #1
0
        /// <summary>
        ///     Decode - Decodes a raw bitcoin block header
        /// </summary>
        private void Decode()
        {
            // block version number
            BlockVersion = ReadUInt();

            // previous block hash
            PrevBlockHash = ByteHexConverter.ByteArrayToHex(ReadSlice(32).Reverse().ToArray());

            // merkle root hash
            MerkleRootHash = ReadSlice(32);

            // block timestamp (seconds since 1970-01-01T00:00 UTC)
            TimeStamp = ReadUInt();

            // difficulty target in compact format
            DiffTarget = ReadUInt();

            // nonce
            Nonce = ReadUInt();

            // strict validation - we should be at the end of the header
            LengthMatch = Offset == ByteData.Length;

            // don't store the extra data; useful when serializing multiple block headers
            if (!LengthMatch)
            {
                ByteData = ByteData.Take(Offset).ToArray();
            }

            // block hash = sha256(sha256(header_data)) -> reverse byte data -> convert to hex
            SHA256 sha256 = new SHA256Managed();

            BlockHashHex = ByteHexConverter.ByteArrayToHex(sha256.ComputeHash(sha256.ComputeHash(ByteData)).Reverse().ToArray());
        }
Пример #2
0
        /// <inheritdoc />
        /// <summary>
        ///     Constructor
        ///     - decodes the transaction data
        /// </summary>
        /// <param name="txBytes">raw transaction as byte array</param>
        public Transaction(IEnumerable <byte> txBytes) : base(txBytes)
        {
            var sha256 = new SHA256Managed();

            // double sha256 hash, reverse bytes, then convert to hex
            TXID    = sha256.ComputeHash(sha256.ComputeHash(ByteData)).Reverse().ToArray();
            TXIDHex = ByteHexConverter.ByteArrayToHex(TXID);
            Decode();
        }
Пример #3
0
        /// <summary>
        ///     Calculates double sha256 hash of two merkle nodes
        /// </summary>
        /// <param name="a">merkle node 1 hash as hex</param>
        /// <param name="b">merkle node 2 hash as hex</param>
        /// <returns></returns>
        private static string CalculateParentHash(string a, string b)
        {
            // convert string to byte arrays, reverse each, and combine
            var mergeHash = ByteHexConverter.StringToByteArray(a).Reverse().Concat(ByteHexConverter.StringToByteArray(b).Reverse()).ToArray();

            // compute and return lowercase double sha256 hash of merged hashes, reversed, in hex
            var sha256 = SHA256.Create();

            return(ByteHexConverter.ByteArrayToHex(sha256.ComputeHash(sha256.ComputeHash(mergeHash)).Reverse().ToArray()).ToLower());
        }
Пример #4
0
        /// <summary>
        ///     Creates a human readable script with data as hex from the bitcoin script
        /// </summary>
        /// <returns>human readable script</returns>
        public override string ToString()
        {
            var ret = string.Join(" ", OpCodes);

            foreach (var data in DataChunks)
            {
                ret = ret.ReplaceFirst("OP_DATA", ByteHexConverter.ByteArrayToHex(data));
            }
            return(ret);
        }
Пример #5
0
        /// <inheritdoc />
        /// <summary>
        ///     Constructor
        ///     - creates a transaction object given transaction properties
        ///     - used for transactions found in blocks
        /// </summary>
        public Transaction(IEnumerable <byte> txBytes, string inclusionBlockHex, uint txVersion, Input[] inputs, Output[] outputs, uint lockTime) : base(txBytes)
        {
            var sha256 = new SHA256Managed();

            TXID               = sha256.ComputeHash(sha256.ComputeHash(ByteData)).Reverse().ToArray();
            TXIDHex            = ByteHexConverter.ByteArrayToHex(TXID);
            IncludedInBlockHex = inclusionBlockHex;
            TXVersion          = txVersion;
            Inputs             = inputs;
            Outputs            = outputs;
            LockTime           = lockTime;
            LengthMatch        = true;
        }
Пример #6
0
        /// <summary>
        ///     ReadScript
        /// </summary>
        /// <param name="script"></param>
        /// <exception cref="InvalidSLPScriptException"></exception>
        public static void ValidateSLPScriptHeader(Script.Script script)
        {
            /*
             *  <lokad_id: 'SLP\x00'> (4 bytes, ascii)
             *  <token_type: 1> (1 to 2 byte integer)
             */
            if (script.OpCodes.Count < 1 || !script.OpCodes[0].Equals(OpCodeType.OP_RETURN))
            {
                throw new InvalidSLPScriptException("Script is not an op_return");
            }

            if (script.OpCodes.Count < 2 || !script.OpCodes[1].Equals(OpCodeType.OP_DATA) ||
                script.DataChunks.Count < 1)
            {
                throw new InvalidSLPScriptException(
                          "Script is not an SLP op_return. Header is missing.");
            }

            if (script.DataChunks[0].Length != 4)
            {
                throw new InvalidSLPScriptException(
                          "Script is not an SLP op_return. Wrong header - expected 4 bytes, but received " +
                          script.DataChunks[0].Length + ".");
            }

            if (!script.DataChunks[0].SequenceEqual(OpReturnPrefix))
            {
                throw new InvalidSLPScriptException(
                          "Script is not an SLP op_return. Wrong header - expected 0x504c5300, but received " +
                          ByteHexConverter.ByteArrayToHex(script.DataChunks[0]) + ".");
            }

            if (script.DataChunks.Count == 1)
            {
                throw new InvalidSLPScriptException("Script is missing SLP token_type.");
            }


            if (script.DataChunks[1].Length != 1 && script.DataChunks[1].Length != 2)
            {
                throw new InvalidSLPScriptException("SLP version violates spec - expected 1 or 2 bytes, but received " +
                                                    script.DataChunks[1].Length + ".");
            }

            // make sure the script contains only push opcodes, data, and the op_return
            if (script.OpCodes.Where(x => x != OpCodeType.OP_DATA).Count() > 1)
            {
                throw new InvalidSLPScriptException("Script contains invalid op_codes! Invalid codes found: " +
                                                    string.Join(", ", script.OpCodes.Where(x => x != OpCodeType.OP_DATA)));
            }
        }
Пример #7
0
        /// <summary>
        ///     Processes raw bitcoin transactions
        ///     - decodes the transaction, output scripts, and output addresses
        /// </summary>
        /// <param name="data">raw transaction byte array</param>
        protected override Transaction DoWork(byte[] data)
        {
            // hex version of the transaction
            var txHex = ByteHexConverter.ByteArrayToHex(data);

            // attempt to decode the transaction (also decodes output scripts and addresses)
            Transaction transaction;

            try
            {
                transaction = new Transaction(data);
            }
            catch (Exception e)
            {
                Console.WriteLine("Unable to decode transaction: \n" + txHex + "\n" + e.Message);
                return(null);
            }

            return(transaction);
        }
Пример #8
0
        public static void Main(string[] args)
        {
            Console.WriteLine("Creating output script for 'bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a'...");
            // input cash address and produce an output script
            var decoded = CashAddress.DecodeCashAddress("bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a");

            // so far, cash addresses have two defined types
            // let's print the readable output script for the address
            switch (decoded.Type)
            {
            // our demo happens to be a P2PKH cash address...
            case ScriptType.P2PKH:
                // use ByteHexConverter to convert raw byte data for output script to readable hex
                Console.WriteLine("Output script: " +
                                  "OP_DUP OP_HASH160 " + ByteHexConverter.ByteArrayToHex(decoded.Hash) + " OP_EQUALVERIFY OP_CHECKSIG");
                break;

            // if it was a P2SH cash address...
            case ScriptType.P2SH:
                // use ByteHexConverter to convert raw byte data for output script to readable hex
                Console.WriteLine("Output script: " +
                                  "OP_HASH160 " + ByteHexConverter.ByteArrayToHex(decoded.Hash) + " OP_CHECKSIG");
                break;

            // whoa... another type?
            default:
                Console.WriteLine("This shouldn't happen! That's an unknown cash address type!");
                break;
            }

            // let's use script builder now
            var outputScript = ScriptBuilder.CreateOutputScript(decoded.Type, decoded.Hash);

            // same thing if we go straight from a Cash Address
            outputScript = ScriptBuilder.CreateOutputScript("bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a");
            Console.WriteLine("Output script from ScriptBuilder: " + outputScript);
            Console.WriteLine("Output script RAW from ScriptBuilder: " + ByteHexConverter.ByteArrayToHex(outputScript.ScriptBytes));

            // What about if we want to create an OP_RETURN output?
            // ASCII encode "My Bitcoin OP_RETURN!" and create an output script
            var opReturn = ScriptBuilder.CreateOpReturn(Encoding.ASCII.GetBytes("My Bitcoin OP_RETURN!"));

            Console.WriteLine("OP_RETURN script from ScriptBuilder: " + opReturn);
            Console.WriteLine("OP_RETURN script RAW from ScriptBuilder: " + ByteHexConverter.ByteArrayToHex(opReturn.ScriptBytes));


            // encode a hash160 from an output script as a cash address (demo script is P2PKH)
            Console.WriteLine("Encoding output script 'OP_DUP OP_HASH160 76a04053bda0a88bda5177b86a15c3b29f559873 OP_EQUALVERIFY OP_CHECKSIG'...");
            // use ByteHexConverter to convert the readable hex to raw byte data (as it would actually be encoded in an output script)
            var encoded = CashAddress.EncodeCashAddress(AddressPrefix.bitcoincash, ScriptType.P2PKH,
                                                        ByteHexConverter.StringToByteArray("76a04053bda0a88bda5177b86a15c3b29f559873"));

            Console.WriteLine("Cash Address: " + encoded);


            // let's try decoding a raw transaction!
            var txHex =
                "020000000113b15104613103365466d9c1773a2c60c3dec7ab6ea41f7f2824f6b00556bd98370000006b483045022100bda8b53dcffbcbf3c005b7c55a923cd04eb3d3abd7632dd260f97d15cc2982ed02202dc15d4a9ad826f4b3a0781693050fe8c1cdeb919903ba11385f0b5e83c1ea5641210384dd3ad997f2e10980e755236b474f986c519599946027876cdeb4eb5a30a09fffffffff0110270000000000001976a91476a04053bda0a88bda5177b86a15c3b29f55987388ac00000000";

            var tx = new Transaction(ByteHexConverter.StringToByteArray(txHex));

            Console.WriteLine("Decoded transaction. TXID: " + tx.TXIDHex + ". Inputs: " + tx.Inputs.Length + ". Outputs: " + tx.Outputs.Length + ". Output Scripts:");
            foreach (var output in tx.Outputs)
            {
                Console.WriteLine(output);
            }

            // wait
            Console.ReadKey();
        }