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)); }
public OpenBlockStatus TryOpenBlock(CommittedBlockId parent, out UncommittedBlock freshBlock) { var blocks = GetBlocks(); var blockCount = AsHeader.BlockCount; var lowerIndex = Math.Max(0, blockCount - BlockScanLimit); freshBlock = default; if (blockCount == 0 && !parent.Equals(CommittedBlockId.GenesisParent)) { return(OpenBlockStatus.ParentNotFound); } // Find the parent, and assess the block height int parentBlockHeight = -1; var parentAlias = BlockAlias.Undefined; for (var i = blockCount - 1; i >= lowerIndex; i--) { ref var candidate = ref blocks[i]; if (candidate.IsDeleted) { continue; } if (candidate.BlockId.Equals(parent)) { parentBlockHeight = candidate.BlockHeight; parentAlias = candidate.Alias; break; } if (i == 0) { return(OpenBlockStatus.ParentNotFound); } }
/// <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)); }