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); }
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); }