public SozuFactory(ILineage lineage, Hash256 start, Hash256 end, SozuFactoryConfig[] sozuFactoryConfig, string path) { _lineage = lineage; _start = start; _end = end; _sozuFactoryConfig = sozuFactoryConfig; _path = path; }
public CoinChangeStatus Remove(ulong outpointHash, ref Outpoint outpoint, BlockAlias context, CoinRemoveOption option, ILineage lineage) { if (!_coins.TryGetValue(outpoint, out var fatCoin)) { return(CoinChangeStatus.OutpointNotFound); } fatCoin.Events.RemoveAll(ev => ev.BlockAlias == context && (((option & CoinRemoveOption.RemoveProduction) != 0 && ev.Kind == CoinEventKind.Production) || ((option & CoinRemoveOption.RemoveConsumption) != 0 && ev.Kind == CoinEventKind.Consumption))); return(CoinChangeStatus.Success); }
public CoinChangeStatus AddConsumption(ulong outpointHash, ref Outpoint outpoint, BlockAlias context, ILineage lineage) { if (!_coins.TryGetValue(outpoint, out var fatCoin)) { return(CoinChangeStatus.OutpointNotFound); } var consumption = new CoinEvent(context, CoinEventKind.Consumption); if (fatCoin.Events.Contains(consumption)) { return(CoinChangeStatus.Success); } fatCoin.Events.Add(consumption); return(CoinChangeStatus.Success); }
/// <param name="config"></param> /// <param name="lineage"></param> /// <param name="store"></param> /// <param name="subTable"></param> public SozuTable(SozuConfig config, ILineage lineage, ISectorStore store, SozuTable subTable = null) { _config = config; _lineage = lineage; _store = store; _subTable = subTable; _residue = TxoPack.Create(); _rangeOutputs = TxoPack.Create(); _deserialized = TxoPack.Create(); _complement = TxoPack.Create(); _kept = TxoPack.Create(); _flowDown = TxoPack.Create(); _merged = TxoPack.Create(2); store.Initialize(); if (config.ImplicitSectors && !store.HasSectors()) { store.AllocateSectors(1 << config.SectorBitDepth); EnsurePersistence(); } }
public CoinChangeStatus AddProduction(ulong outpointHash, ref Outpoint outpoint, bool isCoinBase, Payload payload, BlockAlias context, ILineage lineage) { var production = new CoinEvent(context, CoinEventKind.Production); if (_coins.TryGetValue(outpoint, out var fatCoin)) { if (fatCoin.Events.Contains(production)) { return(CoinChangeStatus.Success); // done } fatCoin.Events.Add(production); return(CoinChangeStatus.Success); } var coin = new Coin(ref outpoint, isCoinBase, payload, production, _pool); _coins.Add(outpoint, new FatCoin(coin, production)); return(CoinChangeStatus.Success); }
// HACK: [vermorel] Constructor used as the setup of the unit tests, should be refactored. public LineageTests() { var store = new VolatileChainStore(); //var chain = new SimpleBlockchain(); store.TryOpenBlock(CommittedBlockId.GenesisParent, out var b0); var id = b0.Alias; // U(0) store.TryCommitBlock(id, CommittedBlockId.Genesis, out _); // C(0) store.TryOpenBlock(CommittedBlockId.Genesis, out var b1); Assert.Equal(_1, b1.Alias); // C(0) -> U(1) store.TryCommitBlock(_1, _id_1, out _); // C(0) -> C(1) store.TryOpenBlock(_id_1, out var b2); Assert.Equal(_2_0, b2.Alias); // C(0) -> C(1) -> U(2) store.TryCommitBlock(_2_0, _id_2_0, out _); // C(0) -> C(1) -> C(2) // Second child for second block store.TryOpenBlock(_id_1, out var b21); Assert.Equal(_2_1, b21.Alias); // C(0) -> C(1) -> C(2) // \-> U(2-1) store.TryCommitBlock(_2_1, _id_2_1, out _); // C(0) -> C(1) -> C(2) // \-> C(2-1) var lineage = (Lineage)store.GetLineage(); lineage.CoinPruneHeight = _1.BlockHeight; _lineage = lineage; }
public CoinChangeStatus AddProduction( ulong outpointHash, ref Outpoint outpoint, bool isCoinBase, Payload payload, BlockAlias context, ILineage lineage) { try { var sectorIndex = (uint)(outpointHash % (uint)_store.SectorCount); var sig = OutpointSig.From(outpointHash); var evt = new CoinEvent(context, CoinEventKind.Production); // Oversized payload, insert in the last layer directly. if (payload.SizeInBytes > PayloadOversizeInBytes) { // HACK: [vermorel] edge-case, is-it possible to have an oversized coinbase? return(AddOversizedProduction(sectorIndex, sig, ref outpoint, isCoinBase, payload, evt, lineage)); } // Layer 0, the only layer to have outpoint signatures. var pack0 = _store.Read(layerIndex: 0, sectorIndex); var extendedPack = CoinPack.Empty; // The coin already exists on another chain. if (pack0.TryGet(ref outpoint, out var coin, out var coinOffset)) { if (coin.HasEvent(evt)) { return(CoinChangeStatus.Success); } if (!lineage.IsAddConsistent(coin.Events, evt)) { return(CoinChangeStatus.InvalidContext); } // HACK: [vermorel] edge-case, is-it possible to have the same coinbase on multiple chains? extendedPack = CoinPack.WithExtraCoinEvent(pack0, coin, coinOffset, evt, _pool); } // A probabilistic match exists, checking deeper layers. else if (pack0.PositiveMatch(sig)) { for (var layerIndex = 1; layerIndex < _store.LayerCount; layerIndex++) { // Check deeper layers var packN = _store.Read(layerIndex: layerIndex, sectorIndex); if (packN.TryGet(ref outpoint, out coin, out coinOffset)) { if (coin.HasEvent(evt)) { return(CoinChangeStatus.Success); } if (!lineage.IsAddConsistent(coin.Events, evt)) { return(CoinChangeStatus.InvalidContext); } extendedPack = CoinPack.WithExtraCoinEvent(packN, coin, coinOffset, evt, _pool); break; } // False-positive match, adding the coin as new in layer 0. if (layerIndex == _store.LayerCount - 1) { var newCoin = new Coin(ref outpoint, isCoinBase, payload, evt, _pool); extendedPack = CoinPack.WithExtraCoin(pack0, newCoin, _pool); } } // 'for' loop above should not exit without assigned a value to 'extendedPack'. Debug.Assert(!extendedPack.IsEmpty); } else // The coin does not exist on any chain. { var newCoin = new Coin(ref outpoint, isCoinBase, payload, evt, _pool); extendedPack = CoinPack.WithExtraCoin(pack0, newCoin, _pool); } // Check of overflow var packs = extendedPack.SizeInBytes < _store.SectorSizeInBytes[extendedPack.LayerIndex] ? new ShortCoinPackCollection(extendedPack) : GetOverflow(extendedPack, lineage, _hash); // Persist the pack(s), several coin packs in case of overflow. _store.Write(packs); return(CoinChangeStatus.Success); }
public bool TryGet(ulong outpointHash, ref Outpoint outpoint, BlockAlias context, ILineage lineage, out Coin coin, out BlockAlias production, out BlockAlias consumption) { var sectorIndex = (uint)(outpointHash % (uint)_store.SectorCount); production = BlockAlias.Undefined; consumption = BlockAlias.Undefined; // Check layer 0. var pack0 = _store.Read(layerIndex: 0, sectorIndex); if (pack0.TryGet(ref outpoint, out coin)) { return(lineage.TryGetEventsInContext(coin.Events, context, out production, out consumption)); } var sig = OutpointSig.From(outpointHash); // Layer 0 has a probabilistic filter. No false negative are possible. if (!pack0.PositiveMatch(sig)) { return(false); } // Check next layers. for (var layerIndex = 1; layerIndex < _store.LayerCount; layerIndex++) { var packN = _store.Read(layerIndex: layerIndex, sectorIndex); if (packN.TryGet(ref outpoint, out coin)) { return(lineage.TryGetEventsInContext(coin.Events, context, out production, out consumption)); } } // Not found, it was a false positive on the probabilistic filter. return(false); }
// HACK: [vermorel] Constructor used as the setup of the unit tests, should be refactored. public LineagePruneTests() { var store = new VolatileChainStore(); UncommittedBlock freshBlock; store.TryOpenBlock(CommittedBlockId.GenesisParent, out var b0); var id = b0.Alias; // U(0) store.TryCommitBlock(id, CommittedBlockId.Genesis, out _); // C(0) store.TryOpenBlock(CommittedBlockId.Genesis, out freshBlock); Assert.Equal(_1, freshBlock.Alias); // C(0) -> U(1) store.TryCommitBlock(_1, _id_1, out _); // C(0) -> C(1) store.TryOpenBlock(_id_1, out freshBlock); Assert.Equal(_2, freshBlock.Alias); // C(0) -> C(1) -> U(2) store.TryCommitBlock(_2, _id_2, out _); // C(0) -> C(1) -> C(2) // Second child for second block store.TryOpenBlock(_id_1, out freshBlock); Assert.Equal(_2_1, freshBlock.Alias); // C(0) -> C(1) -> C(2) // \-> U(2-1) store.TryCommitBlock(_2_1, _id_2_1, out _); // C(0) -> C(1) -> C(2) // \-> C(2-1) store.TryOpenBlock(_id_2, out freshBlock); Assert.Equal(_3, freshBlock.Alias); store.TryCommitBlock(_3, _id_3, out _); store.TryOpenBlock(_id_2_1, out freshBlock); Assert.Equal(_3_1, freshBlock.Alias); store.TryCommitBlock(_3_1, _id_3_1, out _); // C(0) -> C(1) -> C(2) -> C(3) // \-> C(2-1) -> C(3-1) store.TryOpenBlock(_id_3_1, out freshBlock); Assert.Equal(_4, freshBlock.Alias); store.TryCommitBlock(_4, _id_4, out _); store.TryOpenBlock(_id_4, out freshBlock); Assert.Equal(_5, freshBlock.Alias); store.TryCommitBlock(_5, _id_5, out _); store.TryOpenBlock(_id_4, out freshBlock); Assert.Equal(_5_1, freshBlock.Alias); store.TryCommitBlock(_5_1, _id_5_1, out _); // C(0) -> C(1) -> C(2) -> C(3) // \-> C(2-1) -> C(3-1) -> C(4) -> C(5) // \ -> C(5-1) // pruning limit is _3_1 var lineage = (Lineage)store.GetLineage(); lineage.CoinPruneHeight = _3_1.BlockHeight; _lineage = lineage; }
private void RefreshAndPropagateLineage() { _lineage = _store.GetLineage(); _propagateLineage(_lineage); }
public bool TryGet(ulong outpointHash, ref Outpoint outpoint, BlockAlias context, ILineage lineage, out Coin coin, out BlockAlias production, out BlockAlias consumption) { production = BlockAlias.Undefined; consumption = BlockAlias.Undefined; if (_coins.TryGetValue(outpoint, out var fatCoin)) { foreach (var ev in fatCoin.Events) { if (ev.Kind == CoinEventKind.Production) { production = ev.BlockAlias; } if (ev.Kind == CoinEventKind.Consumption) { consumption = ev.BlockAlias; } } if (lineage == null || lineage.TryGetEventsInContext(fatCoin.Events.ToArray(), context, out production, out consumption)) { coin = fatCoin.Coin; return(true); } } coin = Coin.Empty; return(false); }