public Lineage( IReadOnlyList <CommittedBlock> committed, IReadOnlyList <UncommittedBlock> uncommitted, int coinPruneLimitDistance) { _quasiOrphans = GetQuasiOrphans(committed, uncommitted); ChainTip = GetCommittedBlockOfMaxHeight(committed); CoinPruneHeight = ChainTip.BlockHeight - coinPruneLimitDistance; _uncommitted = new HashSet <BlockAlias>(uncommitted.Select(x => x.Alias)); }
/// <summary> /// Returns whether <see cref="block"/> is considered prunable (i.e. it can /// be removed from the chain). The necessary criteria for this decision /// are that it is not on the main chain and that its first ancestor on /// the main chain is below or equal to the prune limit. /// </summary> private bool IsBlockPermanentlyOrphaned(BlockAlias block) { var current = block; var isInMainChain = true; while (_quasiOrphans.TryGetValue(current, out var parent)) { isInMainChain = false; current = parent; } return(!isInMainChain && current.BlockHeight <= CoinPruneHeight); }
/// <summary> /// Returns true if <see cref="maybeAncestor"/> is an ancestor of /// <see cref="subject"/>, meaning they are on the same branch of the /// blockchain with <see cref="subject"/> being younger. /// </summary> private bool IsAncestor(BlockAlias subject, BlockAlias maybeAncestor) { if (subject.IsPrior(maybeAncestor)) { return(false); } // We climb down the side chain until we find the parent, // a block that is lower than the maybeAncestor or we reach the main chain var parent = subject; do { // Move up the side chain looking for an ancestor on the main branch // A block counts as its own ancestor if (parent == maybeAncestor) { return(true); } // The ancestor has to have a smaller number than anything that comes afterward. if (parent.IsPrior(maybeAncestor)) { return(false); } } while (_quasiOrphans.TryGetValue(parent, out parent)); /* * o * | * o * | * o----o <- maybeAncestorAlias * | * o <- parent * / \ * mainChain -> o o <- subject */ // Here, 'parent' is the most recent ancestor of the original block // ('subject') on the main chain, and 'maybeAncestor < parent', so the // ancestor will be an ancestor if and only if it is also on the // main chain. return(!_quasiOrphans.ContainsKey(maybeAncestor)); }
public bool TryGetEventsInContext(Span <CoinEvent> events, BlockAlias context, out BlockAlias production, out BlockAlias consumption) { production = BlockAlias.Undefined; consumption = BlockAlias.Undefined; foreach (var coinEvent in events) { if (IsAncestor(context, coinEvent.BlockAlias)) { if (coinEvent.Kind == CoinEventKind.Production) { production = coinEvent.BlockAlias; } else { consumption = coinEvent.BlockAlias; } } } return(production.IsDefined || consumption.IsDefined); }
public bool IsUncommitted(BlockAlias block) { return(_uncommitted.Contains(block)); }
public CommittedBlock(CommittedBlockId blockId, BlockAlias alias, BlockAlias parent) { BlockId = blockId; Alias = alias; Parent = parent; }