コード例 #1
0
        private static JoinSplit ParseJoinSplit(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            JoinSplit joinSplit = new JoinSplit();

            joinSplit.AmountIn  = blockMemoryStreamReader.ReadUInt64();
            joinSplit.AmountOut = blockMemoryStreamReader.ReadUInt64();
            joinSplit.Anchor    = new ByteArray(blockMemoryStreamReader.ReadBytes(32));

            for (int i = 0; i < joinSplit.Nullifiers.Length; ++i)
            {
                joinSplit.Nullifiers[i] = new ByteArray(blockMemoryStreamReader.ReadBytes(32));
            }

            for (int i = 0; i < joinSplit.Commitments.Length; ++i)
            {
                joinSplit.Commitments[i] = new ByteArray(blockMemoryStreamReader.ReadBytes(32));
            }

            joinSplit.EphemeralKey = new ByteArray(blockMemoryStreamReader.ReadBytes(32));
            joinSplit.RandomSeed   = new ByteArray(blockMemoryStreamReader.ReadBytes(32));

            for (int i = 0; i < joinSplit.MACs.Length; ++i)
            {
                joinSplit.MACs[i] = new ByteArray(blockMemoryStreamReader.ReadBytes(32));
            }

            joinSplit.Proof = BlockchainParser.ParseZCProof(blockMemoryStreamReader);

            for (int i = 0; i < joinSplit.Ciphertexts.Length; ++i)
            {
                joinSplit.Ciphertexts[i] = new ByteArray(blockMemoryStreamReader.ReadBytes(ZcashConstants.ZC_NOTECIPHERTEXT_SIZE));
            }

            return(joinSplit);
        }
コード例 #2
0
        /// <summary>
        /// Parses one Bitcoin block.
        /// </summary>
        /// <param name="blockchainFileName">
        /// The name of the blockchain file that contains the block being parsed.
        /// </param>
        /// <param name="binaryReader">
        /// Provides access to a Bitcoin blockchain file.
        /// </param>
        private Block ParseBlockchainFile(string blockchainFileName, BinaryReader binaryReader)
        {
            // There are some rare situations where a block is preceded by a section containing zero bytes.
            if (binaryReader.SkipZeroBytes() == false)
            {
                // We reached the end of the file. There is no block to be parsed.
                return(null);
            }

            UInt32 blockId = binaryReader.ReadUInt32();

            if (blockId != this.blockMagicId)
            {
                throw new InvalidBlockchainContentException(string.Format(CultureInfo.InvariantCulture, "Invalid block Id: {0:X}. Expected: {1:X}", blockId, this.blockMagicId));
            }

            int blockLength = (int)binaryReader.ReadUInt32();

            byte[] blockBuffer = binaryReader.ReadBytes(blockLength);

            using (BlockMemoryStreamReader blockMemoryStreamReader = new BlockMemoryStreamReader(blockBuffer))
            {
                return(BlockchainParser.InternalParseBlockchainFile(blockchainFileName, blockMemoryStreamReader));
            }
        }
コード例 #3
0
        /// <summary>
        /// Parses a Bitcoin transaction output.
        /// </summary>
        /// <param name="blockMemoryStreamReader">
        /// Provides access to a section of the Bitcoin blockchain file.
        /// </param>
        /// <returns>
        /// The Bitcoin transaction output that was parsed.
        /// </returns>
        private static TransactionOutput ParseTransactionOutput(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            TransactionOutput transactionOutput = new TransactionOutput();

            transactionOutput.OutputValueSatoshi = blockMemoryStreamReader.ReadUInt64();
            int scriptLength = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

            transactionOutput.OutputScript = new ByteArray(blockMemoryStreamReader.ReadBytes(scriptLength));
            transactionOutput.Address      = AddressParser.GetAddressFromOutputScript(transactionOutput.OutputScript.ToArray());

            return(transactionOutput);
        }
コード例 #4
0
        /// <summary>
        /// Parses a Zcash block header.
        /// </summary>
        /// <param name="blockMemoryStreamReader">
        /// Provides access to a section of the Bitcoin blockchain file.
        /// </param>
        /// <returns>
        /// The block header information.
        /// </returns>
        /// <exception cref="InvalidBlockchainContentException">
        /// Thrown if the block version is unknown.
        /// </exception>
        private static BlockHeader ParseBlockHeader(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            BlockHeader blockHeader = new BlockHeader();

            int positionInBaseStreamAtBlockHeaderStart = (int)blockMemoryStreamReader.BaseStream.Position;

            blockHeader.BlockVersion = blockMemoryStreamReader.ReadUInt32();

            if (blockHeader.BlockVersion != 4)
            {
                throw new UnknownBlockVersionException(string.Format(CultureInfo.InvariantCulture, "Unknown block version: {0} ({0:X}).", blockHeader.BlockVersion));
            }

            blockHeader.PreviousBlockHash = new ByteArray(blockMemoryStreamReader.ReadBytes(32).ReverseByteArray());
            blockHeader.MerkleRootHash    = new ByteArray(blockMemoryStreamReader.ReadBytes(32).ReverseByteArray());
            blockHeader.ReservedHash      = new ByteArray(blockMemoryStreamReader.ReadBytes(32).ReverseByteArray());

            blockHeader.BlockTimestampUnix = blockMemoryStreamReader.ReadUInt32();
            blockHeader.BlockTimestamp     = new DateTime(1970, 1, 1).AddSeconds(blockHeader.BlockTimestampUnix);

            blockHeader.BlockTargetDifficulty = blockMemoryStreamReader.ReadUInt32();
            blockHeader.BlockNonce            = new ByteArray(blockMemoryStreamReader.ReadBytes(32).ReverseByteArray());

            int equihashStart = (int)blockMemoryStreamReader.BaseStream.Position;
            int solutionSize  = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

            blockHeader.Solution = new ByteArray(blockMemoryStreamReader.ReadBytes(solutionSize));
            int equihashSize = (int)blockMemoryStreamReader.BaseStream.Position - equihashStart;

            int positionInBaseStreamAfterBlockHeaderEnd = (int)blockMemoryStreamReader.BaseStream.Position;

            using (SHA256Managed sha256 = new SHA256Managed())
            {
                //// We need to calculate the double SHA256 hash of this transaction.
                //// We need to access the buffer that contains the transaction that we jut read through.
                //// Here we take advantage of the fact that the entire block was loaded as an in-memory buffer.
                //// The base stream of blockMemoryStreamReader is that in-memory buffer.

                byte[] baseBuffer            = blockMemoryStreamReader.GetBuffer();
                int    blockHeaderBufferSize = positionInBaseStreamAfterBlockHeaderEnd - positionInBaseStreamAtBlockHeaderStart;

                if (blockHeaderBufferSize != ExpectedBlockHeaderBufferSize + equihashSize)
                {
                    // We have a problem. The block header should be 80 bytes in size.
                    throw new InvalidBlockchainContentException(string.Format(CultureInfo.InvariantCulture, "Block header buffer size has an invalid length: {0}. Expected: {1}.", blockHeaderBufferSize, ExpectedBlockHeaderBufferSize));
                }

                byte[] hash1 = sha256.ComputeHash(baseBuffer, positionInBaseStreamAtBlockHeaderStart, blockHeaderBufferSize);
                blockHeader.BlockHash = new ByteArray(sha256.ComputeHash(hash1).ReverseByteArray());
            }

            return(blockHeader);
        }
コード例 #5
0
        /// <summary>
        /// Parses one Bitcoin block except for a few fields before the actual block header.
        /// </summary>
        /// <param name="blockchainFileName">
        /// The name of the blockchain file that contains the block being parsed.
        /// </param>
        /// <param name="blockMemoryStreamReader">
        /// Provides access to a section of the Bitcoin blockchain file.
        /// </param>
        private static Block InternalParseBlockchainFile(string blockchainFileName, BlockMemoryStreamReader blockMemoryStreamReader)
        {
            BlockHeader blockHeader = BlockchainParser.ParseBlockHeader(blockMemoryStreamReader);

            Block block = new Block(blockchainFileName, blockHeader);

            int blockTransactionCount = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

            for (int transactionIndex = 0; transactionIndex < blockTransactionCount; transactionIndex++)
            {
                Transaction transaction = BlockchainParser.ParseTransaction(blockMemoryStreamReader);
                block.AddTransaction(transaction);
            }

            return(block);
        }
コード例 #6
0
        private static ZCProof ParseZCProof(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            ZCProof proof = new ZCProof
            {
                G_A       = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader),
                G_A_Prime = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader),
                G_B       = BlockchainParser.ParseCompressedG2Element(blockMemoryStreamReader),
                G_B_Prime = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader),
                G_C       = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader),
                G_C_Prime = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader),
                G_K       = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader),
                G_H       = BlockchainParser.ParseCompressedG1Element(blockMemoryStreamReader)
            };

            return(proof);
        }
コード例 #7
0
        private static CompressedElement ParseCompressedG2Element(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            CompressedElement element = new CompressedElement();

            byte leadingByte = blockMemoryStreamReader.ReadByte();

            if ((leadingByte & (~1)) != ZcashConstants.G2_PREFIX_MASK)
            {
                throw new InvalidBlockchainContentException("Unexpected lead byte for G2 point");
            }

            element.YIndicator = (leadingByte & 1) == 1;
            element.X          = new ByteArray(blockMemoryStreamReader.ReadBytes(64));

            return(element);
        }
コード例 #8
0
        /// <summary>
        /// Parses a Bitcoin transaction input.
        /// </summary>
        /// <param name="blockMemoryStreamReader">
        /// Provides access to a section of the Bitcoin blockchain file.
        /// </param>
        /// <returns>
        /// The Bitcoin transaction input that was parsed.
        /// </returns>
        private static TransactionInput ParseTransactionInput(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            TransactionInput transactionInput = new TransactionInput();

            transactionInput.SourceTransactionHash        = new ByteArray(blockMemoryStreamReader.ReadBytes(32).ReverseByteArray());
            transactionInput.SourceTransactionOutputIndex = blockMemoryStreamReader.ReadUInt32();

            int scriptLength = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

            // Ignore the script portion.
            transactionInput.InputScript = new ByteArray(blockMemoryStreamReader.ReadBytes(scriptLength));

            // Ignore the sequence number.
            blockMemoryStreamReader.SkipBytes(4);

            return(transactionInput);
        }
コード例 #9
0
        /// <summary>
        /// Parses a Bitcoin transaction.
        /// </summary>
        /// <param name="blockMemoryStreamReader">
        /// Provides access to a section of the Bitcoin blockchain file.
        /// </param>
        /// <returns>
        /// The Bitcoin transaction that was parsed.
        /// </returns>
        private static Transaction ParseTransaction(BlockMemoryStreamReader blockMemoryStreamReader)
        {
            Transaction transaction = new Transaction();

            int positionInBaseStreamAtTransactionStart = (int)blockMemoryStreamReader.BaseStream.Position;

            transaction.TransactionVersion = blockMemoryStreamReader.ReadUInt32();

            int inputsCount = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

            for (int inputIndex = 0; inputIndex < inputsCount; inputIndex++)
            {
                TransactionInput transactionInput = BlockchainParser.ParseTransactionInput(blockMemoryStreamReader);
                transaction.AddInput(transactionInput);
            }

            int outputsCount = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

            for (int outputIndex = 0; outputIndex < outputsCount; outputIndex++)
            {
                TransactionOutput transactionOutput = BlockchainParser.ParseTransactionOutput(blockMemoryStreamReader);
                transaction.AddOutput(transactionOutput);
            }

            // TODO: Need to find out more details about the semantic of TransactionLockTime.
            transaction.TransactionLockTime = blockMemoryStreamReader.ReadUInt32();

            if (transaction.TransactionVersion >= 2)
            {
                int joinSplitCount = (int)blockMemoryStreamReader.ReadVariableLengthInteger();

                for (int jsIndex = 0; jsIndex < joinSplitCount; ++jsIndex)
                {
                    JoinSplit joinSplit = BlockchainParser.ParseJoinSplit(blockMemoryStreamReader);
                    transaction.AddJoinSplit(joinSplit);
                }

                if (joinSplitCount > 0)
                {
                    transaction.JoinSplitPublicKey = new ByteArray(blockMemoryStreamReader.ReadBytes(32));
                    transaction.JoinSplitSignature = new ByteArray(blockMemoryStreamReader.ReadBytes(64));
                }
            }

            int positionInBaseStreamAfterTransactionEnd = (int)blockMemoryStreamReader.BaseStream.Position;

            using (SHA256Managed sha256 = new SHA256Managed())
            {
                //// We need to calculate the double SHA256 hash of this transaction.
                //// We need to access the buffer that contains the transaction that we jut read through.
                //// Here we take advantage of the fact that the entire block was loaded as an in-memory buffer.
                //// The base stream of blockMemoryStreamReader is that in-memory buffer.

                byte[] baseBuffer = blockMemoryStreamReader.GetBuffer();

                int    transactionBufferSize = positionInBaseStreamAfterTransactionEnd - positionInBaseStreamAtTransactionStart;
                byte[] hash1 = sha256.ComputeHash(baseBuffer, positionInBaseStreamAtTransactionStart, transactionBufferSize);

                transaction.TransactionHash = new ByteArray(sha256.ComputeHash(hash1).ReverseByteArray());
            }

            return(transaction);
        }