/// <summary> /// Initializes a new instance of the <see cref="Block"/> class. /// </summary> /// <param name="blockchainFileName"> /// The name of the Bitcoin blockchain file that contains this block. /// </param> /// <param name="blockHeader"> /// The block header. /// </param> public Block(string blockchainFileName, BlockHeader blockHeader) { this.BlockchainFileName = blockchainFileName; this.BlockHeader = blockHeader; this.transactions = new List<Transaction>(); this.Transactions = new ReadOnlyCollection<Transaction>(this.transactions); }
public Block GenerateBlock( ByteArray blockHash, ByteArray transactionHash, InputInfo[] inputs, OutputInfo[] outputs) { BlockHeader blockHeader = new BlockHeader() { BlockHash = blockHash, BlockNonce = 0, BlockTargetDifficulty = 0, BlockTimestamp = this.GetCurrentBlockTimeStamp(), BlockTimestampUnix = 0, BlockVersion = 1, MerkleRootHash = ByteArray.Empty, PreviousBlockHash = this.previousBlockHash, }; this.blockTimeStamp = this.blockTimeStamp.AddDays(1); string expectedFileName = string.Format(CultureInfo.InvariantCulture, "blk{0:00000}.dat", this.GetCurentBlockchainFileIndex()); Block block = new Block(expectedFileName, blockHeader); Transaction transaction = new Transaction() { TransactionHash = transactionHash, TransactionLockTime = 0, TransactionVersion = 1, }; foreach (InputInfo inputInfo in inputs) { TransactionInput transactionInput = new TransactionInput() { InputScript = ByteArray.Empty, SourceTransactionHash = inputInfo.SourceTransactionHash, SourceTransactionOutputIndex = inputInfo.SourceTransactionOutputIndex, }; transaction.AddInput(transactionInput); } foreach (OutputInfo outputInfo in outputs) { TransactionOutput transactionOutput = new TransactionOutput() { OutputScript = ByteArray.Empty, OutputValueSatoshi = (ulong)(outputInfo.OutputValueSatoshi * DatabaseGenerator.BtcToSatoshi), }; transaction.AddOutput(transactionOutput); } block.AddTransaction(transaction); this.previousBlockHash = block.BlockHeader.BlockHash; return block; }
/// <summary> /// Parses a Bitcoin 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(); // TODO: We need to understand better what is different in V2 and V3. if (blockHeader.BlockVersion != 1 && blockHeader.BlockVersion != 2 && blockHeader.BlockVersion != 3) { throw new UnknownBlockVersionException(string.Format(CultureInfo.InvariantCulture, "Unknown block version: {0}.", blockHeader.BlockVersion)); } blockHeader.PreviousBlockHash = new ByteArray(blockMemoryStreamReader.ReadBytes(32).ReverseByteArray()); blockHeader.MerkleRootHash = 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 = blockMemoryStreamReader.ReadUInt32(); 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) { // 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; }