Пример #1
0
        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);
        }
Пример #2
0
        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);
            }