private ILineage MakeLineage() { var blockId1 = CommittedBlockId.ReadFromHex("0000000000000000000000000000000000000000000000000000000000AAA333"); var commBlock1 = new CommittedBlock(blockId1, BlockAlias.Genesis, BlockAlias.GenesisParent); var blockId2 = CommittedBlockId.ReadFromHex("0000000000000000000000000000000000000000000000000000000000BBB444"); var commBlock2 = new CommittedBlock(blockId2, new BlockAlias(2), BlockAlias.Genesis); var blockId3 = CommittedBlockId.ReadFromHex("0000000000000000000000000000000000000000000000000000000000CCC555"); var commBlock3 = new CommittedBlock(blockId3, new BlockAlias(3), new BlockAlias(2)); var uncommBlock = new UncommittedBlock(UncommittedBlockId.Create(), new BlockAlias(4), new BlockAlias(3)); var committedBlocks = new List <CommittedBlock>(); committedBlocks.Add(commBlock1); committedBlocks.Add(commBlock2); committedBlocks.Add(commBlock3); var uncommittedBlocks = new List <UncommittedBlock>(); uncommittedBlocks.Add(uncommBlock); return(new Lineage(committedBlocks, uncommittedBlocks, 100)); }
/// <summary> /// Reads blockchain information from a stream in the following order: /// - number of blocks to read /// - blocks with Hash256 representing the blockId first, then int /// representing the parentAlias /// The blockHeight is calculated for each block based on the /// blockHeight of its parent, so it should not be stored. /// The corresponding Serialization method is <see cref="WriteTo"/>. /// </summary> /// <returns>A new list representing the blockchain.</returns> public static SimpleBlockchain ReadFrom(BinaryReader reader) { var committedBlocks = new List <CommittedBlock>(); var uncommittedBlocks = new List <UncommittedBlock>(); var maxBlockHeight = 0; // track the blockHeight so that it doesn't have to be recalculated afterward // Read blocks var committedBlockCount = reader.ReadInt32(); for (var i = 0; i < committedBlockCount; i++) { var blockId = new BlockId(reader.ReadHash256()); var blockAlias = new BlockAlias(reader.ReadUInt32()); var parentAlias = new BlockAlias(reader.ReadUInt32()); // Only the first block can have parentAlias 0. if (parentAlias == BlockAlias.GenesisParent && !blockId.Equals(BlockId.Genesis) || blockAlias.IsPrior(parentAlias)) { throw new FormatException( $"Parent alias {parentAlias} is an invalid parent for block {blockAlias}."); } if (!TryFindCommitted(parentAlias, committedBlocks, out var parentBlock) && !blockId.Equals(BlockId.Genesis)) { throw new ArgumentNullException($"No parent {parentAlias} found."); } // The first block, which is the only one to have parent 0, has block height 0. var blockHeight = parentAlias == BlockAlias.GenesisParent ? 0 : parentBlock.BlockHeight + 1; var newBlock = new CommittedBlock(blockHeight, blockId, blockAlias, parentAlias); if (blockHeight > maxBlockHeight) { maxBlockHeight = blockHeight; } committedBlocks.Add(newBlock); } var numUncommmittedBlocks = reader.ReadInt32(); for (var i = 0; i < numUncommmittedBlocks; i++) { var blockId = new TempBlockId(reader.ReadHash128()); var blockAlias = new BlockAlias(reader.ReadUInt32()); var parentAlias = new BlockAlias(reader.ReadUInt32()); // Only the first block can have parentAlias 0. if ((uncommittedBlocks.Count != 0 || committedBlocks.Count != 0) && parentAlias == BlockAlias.GenesisParent || blockAlias.IsPrior(parentAlias)) { throw new FormatException( $"Parent alias {parentAlias} is an invalid parent for block {blockAlias}."); } int blockHeight; if (TryFindCommitted(parentAlias, committedBlocks, out var parentBlock)) { blockHeight = parentBlock.BlockHeight + 1; } else { if (uncommittedBlocks.Count == 0 && committedBlocks.Count == 0 && parentAlias == BlockAlias.GenesisParent) // we're adding the first block { blockHeight = 1; } else { if (!TryFindUncommitted(parentAlias, uncommittedBlocks, out var uParentBlock)) { throw new ArgumentNullException($"No parent {parentAlias} found."); } blockHeight = uParentBlock.BlockHeight + 1; } } var newBlock = new UncommittedBlock(blockHeight, blockId, blockAlias, parentAlias); if (blockHeight > maxBlockHeight) { maxBlockHeight = blockHeight; } uncommittedBlocks.Add(newBlock); } return(new SimpleBlockchain(committedBlocks, uncommittedBlocks, maxBlockHeight)); }
/// <summary> /// Find a given committed block in a chain of committed blocks that is /// enumerated from the end. /// </summary> /// <remarks> /// The enumerator of the blockchain cannot be used as the blockchain /// has not been created yet. /// </remarks> private static bool TryFindCommitted(BlockAlias alias, List <CommittedBlock> blocks, out CommittedBlock foundCommittedBlock) { foundCommittedBlock = blocks.FindLast(b => b.Alias == alias); return(!foundCommittedBlock.Equals(default));