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); }
/// <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); }