Esempio n. 1
0
        private IEnumerable <SlimChainedBlock> EnumerateToTip(BlockLocator fork, SlimChain chain)
        {
            var bh = chain.FindFork(fork);

            if (bh is null)
            {
                throw new InvalidOperationException("No fork found with the chain");
            }
            int height = bh.Height + 1;
            var prev   = bh.Hash;

            while (true)
            {
                bh = chain.GetBlock(height);
                if (bh is null)
                {
                    yield break;
                }
                if (bh.Previous != prev)
                {
                    yield break;
                }

                yield return(bh);

                height = bh.Height + 1;
                prev   = bh.Hash;
            }
        }
Esempio n. 2
0
        private async Task UpdateRepository(RPCClient client, DerivationSchemeTrackedSource trackedSource, Repository repo, SlimChain chain, ScanTxoutOutput[] outputs, ScannedItems scannedItems, ScanUTXOProgress progressObj)
        {
            var data = outputs
                       .GroupBy(o => o.Coin.Outpoint.Hash)
                       .Select(o => (Coins: o.Select(c => c.Coin).ToList(),
                                     BlockId: chain.GetBlock(o.First().Height)?.Hash,
                                     TxId: o.Select(c => c.Coin.Outpoint.Hash).FirstOrDefault(),
                                     KeyPathInformations: o.Select(c => scannedItems.KeyPathInformations[c.Coin.ScriptPubKey]).ToList()))
                       .Where(o => o.BlockId != null)
                       .Select(o =>
            {
                foreach (var keyInfo in o.KeyPathInformations)
                {
                    var index   = keyInfo.KeyPath.Indexes.Last();
                    var highest = progressObj.HighestKeyIndexFound[keyInfo.Feature];
                    if (highest == null || index > highest.Value)
                    {
                        progressObj.HighestKeyIndexFound[keyInfo.Feature] = (int)index;
                    }
                }
                return(o);
            }).ToList();

            var headers             = new ConcurrentDictionary <uint256, BlockHeader>();
            var clientBatch         = client.PrepareBatch();
            var gettingBlockHeaders = Task.WhenAll(data.Select(async o =>
            {
                headers.TryAdd(o.BlockId, await clientBatch.GetBlockHeaderAsync(o.BlockId));
            }).Concat(new[] { clientBatch.SendBatchAsync() }).ToArray());
            await repo.SaveKeyInformations(scannedItems.
                                           KeyPathInformations.
                                           Select(p => p.Value).
                                           Where(p =>
            {
                var highest = progressObj.HighestKeyIndexFound[p.Feature];
                if (highest == null)
                {
                    return(false);
                }
                return(p.KeyPath.Indexes.Last() <= highest.Value);
            }).ToArray());

            await repo.UpdateAddressPool(trackedSource, progressObj.HighestKeyIndexFound);

            await          gettingBlockHeaders;
            DateTimeOffset now = DateTimeOffset.UtcNow;
            await repo.SaveMatches(data.Select(o => new TrackedTransaction(new TrackedTransactionKey(o.TxId, o.BlockId, true), trackedSource, o.Coins, o.KeyPathInformations)
            {
                Inserted = now,
                FirstSeen = headers.TryGetValue(o.BlockId, out var header) && header != null ? header.BlockTime : NBitcoin.Utils.UnixTimeToDateTime(0)
            }).ToArray());
Esempio n. 3
0
 public AnnotatedTransaction(TrackedTransaction tracked, SlimChain chain)
 {
     Record = tracked;
     if (tracked.BlockHash == null)
     {
         Type = AnnotatedTransactionType.Unconfirmed;
     }
     else
     {
         var block = chain.GetBlock(tracked.BlockHash);
         Type   = block == null ? AnnotatedTransactionType.Orphan : AnnotatedTransactionType.Confirmed;
         Height = block?.Height;
     }
 }
Esempio n. 4
0
        public void CanCreateBigSlimChain()
        {
            var main = new ConcurrentChain(LoadMainChain(), Network.Main);
            var c    = new SlimChain(main.GetBlock(0).HashBlock);

            foreach (var item in main.EnumerateToTip(main.GetBlock(0).HashBlock))
            {
                c.TrySetTip(item.HashBlock, item.Previous?.HashBlock);
            }
            Assert.Equal(main.Height, c.Height);
            Assert.Equal(main.Tip.HashBlock, c.Tip);
            // Can up the capacity without errors
            c.SetCapacity(main.Height + 3000);
            Assert.Equal(main.Height, c.Height);
            Assert.Equal(main.Tip.HashBlock, c.Tip);
            Assert.Equal(main.GetBlock(main.Tip.HashBlock).HashBlock, c.GetBlock(c.Tip).Hash);
        }
 public AnnotatedTransaction(TrackedTransaction tracked, SlimChain chain)
 {
     if (tracked == null)
     {
         throw new ArgumentNullException(nameof(tracked));
     }
     Record = tracked;
     if (tracked.BlockHash == null)
     {
         Type = AnnotatedTransactionType.Unconfirmed;
     }
     else
     {
         var block = chain?.GetBlock(tracked.BlockHash);
         Type   = block == null ? AnnotatedTransactionType.Orphan : AnnotatedTransactionType.Confirmed;
         Height = block?.Height;
     }
 }
Esempio n. 6
0
        public static TransactionResult ToTransactionResult(SlimChain chain, Repository.SavedTransaction[] result)
        {
            var noDate = NBitcoin.Utils.UnixTimeToDateTime(0);
            var oldest = result
                         .Where(o => o.Timestamp != noDate)
                         .OrderBy(o => o.Timestamp).FirstOrDefault() ?? result.First();

            var confBlock = result
                            .Where(r => r.BlockHash != null)
                            .Select(r => chain.GetBlock(r.BlockHash))
                            .Where(r => r != null)
                            .FirstOrDefault();

            var conf = confBlock == null ? 0 : chain.Height - confBlock.Height + 1;

            return(new TransactionResult()
            {
                Confirmations = conf, BlockId = confBlock?.Hash, Transaction = oldest.Transaction, TransactionHash = oldest.Transaction.GetHash(), Height = confBlock?.Height, Timestamp = oldest.Timestamp
            });
        }
Esempio n. 7
0
        private async Task UpdateRepository(DerivationSchemeTrackedSource trackedSource, Repository repo, SlimChain chain, ScanTxoutOutput[] outputs, ScannedItems scannedItems, ScanUTXOProgress progressObj)
        {
            var data = outputs
                       .GroupBy(o => o.Coin.Outpoint.Hash)
                       .Select(o => (Coins: o.Select(c => c.Coin).ToList(),
                                     BlockId: chain.GetBlock(o.First().Height)?.Hash,
                                     TxId: o.Select(c => c.Coin.Outpoint.Hash).FirstOrDefault(),
                                     KeyPathInformations: o.Select(c => scannedItems.KeyPathInformations[c.Coin.ScriptPubKey]).ToList()))
                       .Where(o => o.BlockId != null)
                       .Select(o =>
            {
                foreach (var keyInfo in o.KeyPathInformations)
                {
                    var index   = keyInfo.KeyPath.Indexes.Last();
                    var highest = progressObj.HighestKeyIndexFound[keyInfo.Feature];
                    if (highest == null || index > highest.Value)
                    {
                        progressObj.HighestKeyIndexFound[keyInfo.Feature] = (int)index;
                    }
                }
                return(o);
            }).ToList();

            await repo.SaveKeyInformations(scannedItems.
                                           KeyPathInformations.
                                           Select(p => p.Value).
                                           Where(p =>
            {
                var highest = progressObj.HighestKeyIndexFound[p.Feature];
                if (highest == null)
                {
                    return(false);
                }
                return(p.KeyPath.Indexes.Last() <= highest.Value);
            }).ToArray());

            await repo.UpdateAddressPool(trackedSource, progressObj.HighestKeyIndexFound);

            DateTimeOffset now = DateTimeOffset.UtcNow;
            await repo.SaveMatches(data.Select(o => new TrackedTransaction(new TrackedTransactionKey(o.TxId, o.BlockId, true), trackedSource, o.Coins, o.KeyPathInformations)).ToArray());
        }
Esempio n. 8
0
        public void CanBuildSlimChain()
        {
            var       b0    = RandomUInt256();
            SlimChain chain = new SlimChain(b0);
            var       b1    = RandomUInt256();

            Assert.Throws <ArgumentException>(() => chain.TrySetTip(b0, b0));
            Assert.True(chain.TrySetTip(b1, b0));
            var b2 = RandomUInt256();

            Assert.True(chain.TrySetTip(b2, b1));
            Assert.True(chain.TrySetTip(b2, b1));
            Assert.Equal(b0, chain.Genesis);
            Assert.Equal(b2, chain.Tip);
            Assert.True(chain.Contains(b2));
            Assert.Equal(2, chain.Height);
            Assert.False(chain.TrySetTip(b1, b0, true));
            Assert.True(chain.TrySetTip(b1, b0, false));
            Assert.Equal(b1, chain.Tip);
            Assert.False(chain.TryGetHeight(b2, out int height));
            Assert.False(chain.Contains(b2));
            Assert.True(chain.TryGetHeight(b1, out height));
            Assert.Equal(1, height);

            Assert.True(chain.TrySetTip(b2, b1));
            Assert.Throws <ArgumentException>(() => chain.TrySetTip(b1, b2));            // Incoherent
            Assert.Throws <ArgumentException>(() => chain.TrySetTip(b0, b1, true));      // Genesis block should not have previosu
            Assert.Throws <ArgumentException>(() => chain.TrySetTip(b0, b1, false));
            Assert.True(chain.TrySetTip(b0, null));
            Assert.Equal(0, chain.Height);
            Assert.True(chain.TrySetTip(b1, b0, true));
            Assert.True(chain.TrySetTip(b2, b1));

            var b3    = RandomUInt256();
            var block = chain.GetBlock(b2);

            Assert.Equal(b2, block.Hash);
            Assert.Equal(b1, block.Previous);
            Assert.Equal(2, block.Height);
            Assert.Null(chain.GetBlock(b3));

            block = chain.GetBlock(2);
            Assert.Equal(b2, block.Hash);
            Assert.Equal(b1, block.Previous);
            Assert.Equal(2, block.Height);
            Assert.Null(chain.GetBlock(3));
            Assert.Null(chain.GetBlock(-1));

            block = chain.GetBlock(0);
            Assert.Equal(b0, block.Hash);
            Assert.Null(block.Previous);
            Assert.Equal(0, block.Height);

            var chain2 = new SlimChain(RandomUInt256());
            var ms     = new MemoryStream();

            chain.Save(ms);
            ms.Position = 0;
            // Not good genesis
            Assert.Throws <InvalidOperationException>(() => chain2.Load(ms));

            chain2      = new SlimChain(b0);
            ms.Position = 0;
            chain2.Load(ms);
            Assert.Equal(chain.Tip, chain2.Tip);
            Assert.Equal(2, chain2.Height);
        }