private ScannedItems GetScannedItems(ScanUTXOWorkItem workItem, ScanUTXOProgress progress) { var items = new ScannedItems(); var derivationStrategy = workItem.DerivationStrategy; foreach (var feature in workItem.Options.DerivationFeatures) { var path = DerivationStrategyBase.GetKeyPath(feature); var lineDerivation = workItem.DerivationStrategy.DerivationStrategy.GetLineFor(feature); Enumerable.Range(progress.From, progress.Count) .Select(index => { var derivation = lineDerivation.Derive((uint)index); var info = new KeyPathInformation() { ScriptPubKey = derivation.ScriptPubKey, Redeem = derivation.Redeem, TrackedSource = derivationStrategy, DerivationStrategy = derivationStrategy.DerivationStrategy, Feature = feature, KeyPath = path.Derive(index, false) }; items.Descriptors.Add(new ScanTxoutSetObject(ScanTxoutDescriptor.Raw(info.ScriptPubKey))); items.KeyPathInformations.TryAdd(info.ScriptPubKey, info); return(info); }).All(_ => true); } Logs.Explorer.LogInformation($"{workItem.Network.CryptoCode}: Start scanning batch {progress.BatchNumber} of {workItem.DerivationStrategy.ToPrettyString()} from index {progress.From}"); return(items); }
private ScannedItems GetScannedItems(ScanUTXOWorkItem workItem, ScanUTXOProgress progress, NBXplorerNetwork network) { var items = new ScannedItems(); var derivationStrategy = workItem.DerivationStrategy; foreach (var feature in keyPathTemplates.GetSupportedDerivationFeatures()) { var keyPathTemplate = keyPathTemplates.GetKeyPathTemplate(feature); var lineDerivation = workItem.DerivationStrategy.DerivationStrategy.GetLineFor(keyPathTemplate); Enumerable.Range(progress.From, progress.Count) .Select(index => { var derivation = lineDerivation.Derive((uint)index); var info = new KeyPathInformation(derivation, derivationStrategy, feature, keyPathTemplate.GetKeyPath(index, false), network); items.Descriptors.Add(new ScanTxoutSetObject(ScanTxoutDescriptor.Raw(info.ScriptPubKey))); items.KeyPathInformations.TryAdd(info.ScriptPubKey, info); return(info); }).All(_ => true); } Logs.Explorer.LogInformation($"{workItem.Network.CryptoCode}: Start scanning batch {progress.BatchNumber} of {workItem.DerivationStrategy.ToPrettyString()} from index {progress.From}"); return(items); }
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()); }
private async Task UpdateRepository(RPCClient client, DerivationSchemeTrackedSource trackedSource, Repository repo, ScanTxoutOutput[] outputs, ScannedItems scannedItems, ScanUTXOProgress progressObj) { var clientBatch = client.PrepareBatch(); var blockIdsByHeight = new ConcurrentDictionary <int, uint256>(); await Task.WhenAll(outputs.Select(async o => { blockIdsByHeight.TryAdd(o.Height, await clientBatch.GetBlockHashAsync(o.Height)); }).Concat(new[] { clientBatch.SendBatchAsync() }).ToArray()); var data = outputs .GroupBy(o => o.Coin.Outpoint.Hash) .Select(o => (Coins: o.Select(c => c.Coin).ToList(), BlockId: blockIdsByHeight.TryGet(o.First().Height), 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 blockHeadersByBlockId = new ConcurrentDictionary <uint256, BlockHeader>(); clientBatch = client.PrepareBatch(); var gettingBlockHeaders = Task.WhenAll(data.Select(async o => { blockHeadersByBlockId.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 => { var trackedTransaction = repo.CreateTrackedTransaction(trackedSource, new TrackedTransactionKey(o.TxId, o.BlockId, true), o.Coins, ToDictionary(o.KeyPathInformations)); trackedTransaction.Inserted = now; trackedTransaction.FirstSeen = blockHeadersByBlockId.TryGetValue(o.BlockId, out var header) && header != null ? header.BlockTime : NBitcoin.Utils.UnixTimeToDateTime(0); return(trackedTransaction); }).ToArray()); }