private void EnqueueJobs(NodeBlocksRepository repo, ChainBase chain, CloudBlockBlob blobLock, string lease) { int cumul = 0; ChainedBlock from = chain.Genesis; int blockCount = 0; foreach (var block in repo.GetBlocks(new[] { chain.Genesis }.Concat(chain.EnumerateAfter(chain.Genesis)).Where(c => c.Height % BlockGranularity == 0).Select(c => c.HashBlock), default(CancellationToken))) { cumul += block.Transactions.Count * BlockGranularity; blockCount += BlockGranularity; if (cumul > TransactionsPerWork) { var nextFrom = chain.GetBlock(chain.GetBlock(block.GetHash()).Height + BlockGranularity); if (nextFrom == null) { break; } EnqueueRange(chain, from, blockCount); from = nextFrom; blockCount = 0; cumul = 0; } } blockCount = (chain.Tip.Height - from.Height) + 1; EnqueueRange(chain, from, blockCount); var bytes = chain.Tip.GetLocator().ToBytes(); blobLock.UploadText(Encoders.Hex.EncodeData(bytes), null, new AccessCondition() { LeaseId = lease }); }
public static void UpdateChain(this IEnumerable <ChainBlockHeader> entries, ChainBase chain) { Stack <ChainBlockHeader> toApply = new Stack <ChainBlockHeader>(); foreach (var entry in entries) { var prev = chain.GetBlock(entry.Header.HashPrevBlock); if (prev == null) { toApply.Push(entry); } else { toApply.Push(entry); break; } } while (toApply.Count > 0) { var newTip = toApply.Pop(); var chained = new ChainedBlock(newTip.Header, newTip.BlockId, chain.GetBlock(newTip.Header.HashPrevBlock)); chain.SetTip(chained); } }
public static async Task UpdateChain(this IAsyncEnumerable <ChainBlockHeader> entries, ChainBase chain, CancellationToken cancellation = default(CancellationToken)) { var enumerator = await entries.GetAsyncEnumeratorAsync(cancellation).ConfigureAwait(false); Stack <ChainBlockHeader> toApply = new Stack <ChainBlockHeader>(); while (await enumerator.MoveNextAsync(cancellation).ConfigureAwait(false)) { var entry = enumerator.Current; var prev = chain.GetBlock(entry.Header.HashPrevBlock); if (prev == null) { toApply.Push(entry); } else { toApply.Push(entry); break; } } while (toApply.Count > 0) { var newTip = toApply.Pop(); var chained = new ChainedBlock(newTip.Header, newTip.BlockId, chain.GetBlock(newTip.Header.HashPrevBlock)); chain.SetTip(chained); } }
public ChainedBlock GetChainedBlock(ChainBase chain) { ChainedBlock chainedBlock; if (Special != null && Special.Value == SpecialFeature.Last) { chainedBlock = chain.Tip; } else if (Height != -1) { var h = chain.GetBlock(Height); if (h == null) { return(null); } chainedBlock = h; } else { chainedBlock = chain.GetBlock(BlockId); } if (chainedBlock != null) { var height = chainedBlock.Height + Offset; height = Math.Max(0, height); chainedBlock = chain.GetBlock(height); } return(chainedBlock); }
public void SynchronizeChain(ChainBase chain) { Dictionary <uint256, Block> blocks = new Dictionary <uint256, Block>(); Dictionary <uint256, ChainedBlock> chainedBlocks = new Dictionary <uint256, ChainedBlock>(); HashSet <uint256> inChain = new HashSet <uint256>(); inChain.Add(chain.GetBlock(0).HashBlock); chainedBlocks.Add(chain.GetBlock(0).HashBlock, chain.GetBlock(0)); foreach (var block in this.Enumerate(false).Select(b => b.Item)) { var hash = block.GetHash(); blocks.Add(hash, block); } List <uint256> toRemove = new List <uint256>(); while (blocks.Count != 0) { // to optimize keep a track of the last block ChainedBlock last = chain.GetBlock(0); foreach (var block in blocks) { if (inChain.Contains(block.Value.Header.HashPrevBlock)) { toRemove.Add(block.Key); ChainedBlock chainedBlock; if (last.HashBlock == block.Value.Header.HashPrevBlock) { chainedBlock = last; } else { if (!chainedBlocks.TryGetValue(block.Value.Header.HashPrevBlock, out chainedBlock)) { break; } } var chainedHeader = new ChainedBlock(block.Value.Header, block.Value.GetHash(), chainedBlock); chain.SetTip(chainedHeader); chainedBlocks.TryAdd(chainedHeader.HashBlock, chainedHeader); inChain.Add(block.Key); last = chainedHeader; } } foreach (var item in toRemove) { blocks.Remove(item); } if (toRemove.Count == 0) { break; } toRemove.Clear(); } }
public IEnumerator <BlockInfo> GetEnumerator() { Queue <DateTime> lastLogs = new Queue <DateTime>(); Queue <int> lastHeights = new Queue <int>(); var fork = _BlockHeaders.FindFork(_Checkpoint.BlockLocator); var headers = _BlockHeaders.EnumerateAfter(fork); headers = headers.Where(h => h.Height <= ToHeight); var first = headers.FirstOrDefault(); if (first == null) { yield break; } var height = first.Height; if (first.Height == 1) { headers = new[] { fork }.Concat(headers); height = 0; } foreach (var block in _BlocksRepository.GetBlocks(headers.Select(b => b.HashBlock), CancellationToken)) { var header = _BlockHeaders.GetBlock(height); if (block == null) { var storeTip = _BlocksRepository.GetStoreTip(); if (storeTip != null) { // Store is caught up with Chain but the block is missing from the store. if (header.Header.BlockTime <= storeTip.Header.BlockTime) { throw new InvalidOperationException($"Chained block not found in store (height = { height }). Re-create the block store."); } } // Allow Store to catch up with Chain. break; } _LastProcessed = header; yield return(new BlockInfo() { Block = block, BlockId = header.HashBlock, Height = header.Height }); IndexerTrace.Processed(height, Math.Min(ToHeight, _BlockHeaders.Tip.Height), lastLogs, lastHeights); height++; } }
public void SynchronizeChain(ChainBase chain) { Dictionary <uint256, BlockHeader> headers = new Dictionary <uint256, BlockHeader>(); HashSet <uint256> inChain = new HashSet <uint256>(); inChain.Add(chain.GetBlock(0).HashBlock); foreach (var header in Enumerate(true).Select(b => b.Item.Header)) { var hash = header.GetHash(); headers.Add(hash, header); } List <uint256> toRemove = new List <uint256>(); while (headers.Count != 0) { foreach (var header in headers) { if (inChain.Contains(header.Value.HashPrevBlock)) { toRemove.Add(header.Key); chain.SetTip(header.Value); inChain.Add(header.Key); } } foreach (var item in toRemove) { headers.Remove(item); } if (toRemove.Count == 0) { break; } toRemove.Clear(); } }
public BalanceSheet(IEnumerable<OrderedBalanceChange> changes, ChainBase chain) { if (chain == null) throw new ArgumentNullException("chain"); _Chain = chain; var all = changes .Where(c => c.SpentCoins != null) //Remove line whose previous coins have not been loadedcould not be deduced .Where(c => c.MempoolEntry || chain.GetBlock(c.BlockId) != null) //Take only mempool entry, or confirmed one .Where(c => !(c.IsCoinbase && c.MempoolEntry)) //There is no such thing as a Coinbase unconfirmed, by definition a coinbase appear in a block .ToList(); var confirmed = all.Where(o => o.BlockId != null).ToDictionary(o => o.TransactionId); Dictionary<uint256, OrderedBalanceChange> unconfirmed = new Dictionary<uint256, OrderedBalanceChange>(); foreach(var item in all.Where(o => o.MempoolEntry && !confirmed.ContainsKey(o.TransactionId))) { unconfirmed.AddOrReplace(item.TransactionId, item); } _Prunable = all.Where(o => o.BlockId == null && confirmed.ContainsKey(o.TransactionId)).ToList(); _All = all.Where(o => (unconfirmed.ContainsKey(o.TransactionId) || confirmed.ContainsKey(o.TransactionId)) && !(o.BlockId == null && confirmed.ContainsKey(o.TransactionId)) ).ToList(); _Confirmed = _All.Where(o => o.BlockId != null && confirmed.ContainsKey(o.TransactionId)).ToList(); _Unconfirmed = _All.Where(o => o.BlockId == null && unconfirmed.ContainsKey(o.TransactionId)).ToList(); }
public WalletTransaction ToWalletTransaction(ChainBase chain, string wallet) { var chainHeight = chain.Height; var tx = new WalletTransaction() { Proof = Proof, Transaction = Transaction, UnconfirmedSeen = UnconfirmedSeen, AddedDate = AddedDate }; tx.ReceivedCoins = GetCoins(ReceivedCoins, _TrackedScripts, wallet); tx.SpentCoins = GetCoins(SpentCoins, _TrackedScripts, wallet); if (BlockId != null) { var header = chain.GetBlock(BlockId); if (header != null) { tx.BlockInformation = new BlockInformation() { Confirmations = chainHeight - header.Height + 1, Height = header.Height, Header = header.Header }; } } return(tx); }
internal void Index(ChainBase chain, int startHeight, CancellationToken cancellationToken = default(CancellationToken)) { List <ChainPartEntry> entries = new List <ChainPartEntry>(((chain.Height - startHeight) / BlockHeaderPerRow) + 5); startHeight = startHeight - (startHeight % BlockHeaderPerRow); ChainPartEntry chainPart = null; for (int i = startHeight; i <= chain.Tip.Height; i++) { if (chainPart == null) { chainPart = new ChainPartEntry() { ChainOffset = i } } ; var block = chain.GetBlock(i); chainPart.BlockHeaders.Add(block.Header); if (chainPart.BlockHeaders.Count == BlockHeaderPerRow) { entries.Add(chainPart); chainPart = null; } } if (chainPart != null) { entries.Add(chainPart); } this.Index(entries, cancellationToken); }
public BalanceSheet(IEnumerable <OrderedBalanceChange> changes, ChainBase chain, bool colored) { if (chain == null) { throw new ArgumentNullException("chain"); } _Chain = chain; var all = changes .Where(c => c.SpentCoins != null) //Remove line whose previous coins have not been loaded .Where(c => !colored || c.ColoredBalanceChangeEntry != null) //Remove live whose color could not be deduced .Where(c => c.MempoolEntry || chain.GetBlock(c.BlockId) != null) //Take only mempool entry, or confirmed one .Where(c => !(c.IsCoinbase && c.MempoolEntry)) //There is no such thing as a Coinbase unconfirmed, by definition a coinbase appear in a block .ToList(); var confirmed = all.Where(o => o.BlockId != null).ToDictionary(o => o.TransactionId); var unconfirmed = all.Where(o => o.MempoolEntry && !confirmed.ContainsKey(o.TransactionId)).ToDictionary(o => o.TransactionId); _Prunable = all.Where(o => o.BlockId == null && confirmed.ContainsKey(o.TransactionId)).ToList(); _All = all.Where(o => (unconfirmed.ContainsKey(o.TransactionId) || confirmed.ContainsKey(o.TransactionId)) && !(o.BlockId == null && confirmed.ContainsKey(o.TransactionId)) ).ToList(); _Confirmed = _All.Where(o => o.BlockId != null && confirmed.ContainsKey(o.TransactionId)).ToList(); _Unconfirmed = _All.Where(o => o.BlockId == null && unconfirmed.ContainsKey(o.TransactionId)).ToList(); }
public static bool TryGetHeight(this ChainBase chain, uint256 blockId, out int height) { height = 0; var block = chain.GetBlock(blockId); if (block == null) { return(false); } height = block.Height; return(true); }
public IEnumerator <BlockInfo> GetEnumerator() { Queue <DateTime> lastLogs = new Queue <DateTime>(); Queue <int> lastHeights = new Queue <int>(); var fork = _BlockHeaders.FindFork(_Checkpoint.BlockLocator); _LastProcessed = fork; var headers = _BlockHeaders.EnumerateAfter(fork); headers = headers.Where(h => h.Height >= FromHeight && h.Height <= ToHeight); var first = headers.FirstOrDefault(); if (first == null) { yield break; } var height = first.Height; if (first.Height == 1) { headers = new[] { fork }.Concat(headers); height = 0; } foreach (var block in _BlocksRepository.GetBlocks(headers.Select(b => b.HashBlock), CancellationToken).TakeWhile(b => b != null)) { var header = _BlockHeaders.GetBlock(height); _LastProcessed = header; yield return(new BlockInfo() { Block = block, BlockId = header.HashBlock, Height = header.Height }); IndexerTrace.Processed(height, Math.Min(ToHeight, _BlockHeaders.Tip.Height), lastLogs, lastHeights); height++; } }
public static void UpdateChain(this IEnumerable<ChainBlockHeader> entries, ChainBase chain) { Stack<ChainBlockHeader> toApply = new Stack<ChainBlockHeader>(); foreach(var entry in entries) { var prev = chain.GetBlock(entry.Header.HashPrevBlock); if(prev == null) toApply.Push(entry); else { toApply.Push(entry); break; } } while(toApply.Count > 0) { var newTip = toApply.Pop(); var chained = new ChainedBlock(newTip.Header, newTip.BlockId, chain.GetBlock(newTip.Header.HashPrevBlock)); chain.SetTip(chained); } }
public void IndexChain(ChainBase chain, CancellationToken cancellationToken = default(CancellationToken)) { this.logger.LogTrace("()"); if (chain == null) { throw new ArgumentNullException("chain"); } this.SetThrottling(); using (IndexerTrace.NewCorrelation("Index main chain to azure started")) { this.Configuration.GetChainTable().CreateIfNotExistsAsync().GetAwaiter().GetResult(); IndexerTrace.InputChainTip(chain.Tip); var client = this.Configuration.CreateIndexerClient(); var changes = client.GetChainChangesUntilFork(chain.Tip, true, cancellationToken).ToList(); var height = 0; if (changes.Count != 0) { this.logger.LogTrace("Changes count: {0}", changes.Count); IndexerTrace.IndexedChainTip(changes[0].BlockId, changes[0].Height); if (changes[0].Height > chain.Tip.Height) { IndexerTrace.InputChainIsLate(); this.logger.LogTrace("(-):LATE"); return; } height = changes[changes.Count - 1].Height + 1; if (height > chain.Height) { IndexerTrace.IndexedChainIsUpToDate(chain.Tip); this.logger.LogTrace("(-):UP_TO_DATE"); return; } } else { this.logger.LogTrace("No work found"); IndexerTrace.NoForkFoundWithStored(); } IndexerTrace.IndexingChain(chain.GetBlock(height), chain.Tip); this.Index(chain, height, cancellationToken); } this.logger.LogTrace("(-)"); }
public BalanceOperation(OrderedBalanceChange balanceChange, ChainBase chain) { ReceivedCoins = balanceChange.ReceivedCoins.ToList(); SpentCoins = balanceChange.SpentCoins.ToList(); Amount = balanceChange.Amount; TransactionId = balanceChange.TransactionId; if (balanceChange.BlockId != null) { BlockId = balanceChange.BlockId; Height = chain.GetBlock(balanceChange.BlockId).Height; Confirmations = (chain.Tip.Height - Height) + 1; } }
public AnnotatedTransaction(TrackedTransaction tracked, ChainBase 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; } }
public PosBlockModel(Block block, ChainBase chain) { this.Hash = block.GetHash().ToString(); this.Size = block.ToBytes().Length; this.Version = block.Header.Version; this.Bits = block.Header.Bits.ToCompact().ToString("x8"); this.Time = block.Header.BlockTime; this.Nonce = block.Header.Nonce; this.PreviousBlockHash = block.Header.HashPrevBlock.ToString(); this.MerkleRoot = block.Header.HashMerkleRoot.ToString(); this.Difficulty = block.Header.Bits.Difficulty; this.Transactions = block.Transactions.Select(trx => new TransactionVerboseModel(trx, chain.Network)).ToArray(); this.Height = chain.GetBlock(block.GetHash()).Height; }
private static bool IsMinConf(OrderedBalanceChange e, int minConfirmation, ChainBase chain) { if (e.BlockId == null) { return(minConfirmation == 0); } var b = chain.GetBlock(e.BlockId); if (b == null) { return(false); } return((chain.Height - b.Height) + 1 >= minConfirmation); }
/// <summary> /// Retrieves a transaction block given a valid hash. /// This function is used by other methods in this class and not explicitly by RPC/API. /// </summary> /// <param name="trxid">A valid uint256 hash</param> /// <param name="fullNode">The full node. Used to access <see cref="IBlockStore"/>.</param> /// <param name="chain">The full node's chain. Used to get <see cref="ChainedHeader"/> block.</param> /// <returns>A <see cref="ChainedHeader"/> for the given transaction hash. Returns <c>null</c> if fails.</returns> /// <exception cref="ArgumentNullException">Thrown if fullnode is not provided.</exception> internal static async Task <ChainedHeader> GetTransactionBlockAsync(uint256 trxid, IFullNode fullNode, ChainBase chain) { Guard.NotNull(fullNode, nameof(fullNode)); ChainedHeader block = null; var blockStore = fullNode.NodeFeature <IBlockStore>(); uint256 blockid = blockStore != null ? await blockStore.GetBlockIdByTransactionIdAsync(trxid).ConfigureAwait(false) : null; if (blockid != null) { block = chain?.GetBlock(blockid); } return(block); }
public IEnumerator <BlockInfo> GetEnumerator() { Queue <DateTime> lastLogs = new Queue <DateTime>(); Queue <int> lastHeights = new Queue <int>(); var locator = DisableSaving ? new BlockLocator(new List <uint256>() { _Checkpoint.Genesis }) : _Checkpoint.BlockLocator; var fork = _BlockHeaders.FindFork(locator); var headers = _BlockHeaders.EnumerateAfter(fork); headers = headers.Where(h => h.Height >= FromHeight && h.Height <= ToHeight); var first = headers.FirstOrDefault(); if (first == null) { yield break; } var height = first.Height; if (first.Height == 1) { headers = new[] { fork }.Concat(headers); height = 0; } foreach (var block in _Node.GetBlocks(headers.Select(b => b.HashBlock))) { var header = _BlockHeaders.GetBlock(height); _LastProcessed = header; yield return(new BlockInfo() { Block = block, BlockId = header.HashBlock, Height = header.Height }); IndexerTrace.Processed(height, Math.Min(ToHeight, _BlockHeaders.Tip.Height), lastLogs, lastHeights); height++; } }
public void SynchronizeChain(ChainBase chain) { var headers = new Dictionary <uint256, BlockHeader>(); var inChain = new HashSet <uint256>(); inChain.Add(chain.GetBlock(0).HashBlock); foreach (BlockHeader header in Enumerate(true).Select(b => b.Item.Header)) { uint256 hash = header.GetHash(this.Network.NetworkOptions); headers.Add(hash, header); } var toRemove = new List <uint256>(); while (headers.Any()) { foreach (KeyValuePair <uint256, BlockHeader> header in headers) { if (inChain.Contains(header.Value.HashPrevBlock)) { toRemove.Add(header.Key); chain.SetTip(header.Value); inChain.Add(header.Key); } } foreach (uint256 item in toRemove) { headers.Remove(item); } if (!toRemove.Any()) { break; } toRemove.Clear(); } }
public void IndexChain(ChainBase chain) { if (chain == null) { throw new ArgumentNullException("chain"); } SetThrottling(); using (IndexerTrace.NewCorrelation("Index main chain to azure started")) { Configuration.GetChainTable().CreateIfNotExistsAsync().GetAwaiter().GetResult(); IndexerTrace.InputChainTip(chain.Tip); var client = Configuration.CreateIndexerClient(); var changes = client.GetChainChangesUntilFork(chain.Tip, true).ToList(); var height = 0; if (changes.Count != 0) { IndexerTrace.IndexedChainTip(changes[0].BlockId, changes[0].Height); if (changes[0].Height > chain.Tip.Height) { IndexerTrace.InputChainIsLate(); return; } height = changes[changes.Count - 1].Height + 1; if (height > chain.Height) { IndexerTrace.IndexedChainIsUpToDate(chain.Tip); return; } } else { IndexerTrace.NoForkFoundWithStored(); } IndexerTrace.IndexingChain(chain.GetBlock(height), chain.Tip); Index(chain, height); } }
static void Main(string[] args) { try { var options = new IndexerOptions(); if (args.Length == 0) { System.Console.WriteLine(options.GetUsage()); } if (Parser.Default.ParseArguments(args, options)) { System.Console.WriteLine("NBitcoin.Indexer " + typeof(AzureIndexer).Assembly.GetName().Version); if (options.All) { options.IndexAddresses = true; options.IndexBlocks = true; options.IndexWallets = true; options.IndexChain = true; options.IndexTransactions = true; } var indexer = AzureIndexer.CreateIndexer(); indexer.Configuration.EnsureSetup(); indexer.TaskScheduler = new CustomThreadPoolTaskScheduler(30, 100); indexer.CheckpointInterval = TimeSpan.Parse(options.CheckpointInterval); indexer.IgnoreCheckpoints = options.IgnoreCheckpoints; indexer.FromHeight = options.From; indexer.ToHeight = options.To; ChainBase chain = null; var checkpointRepository = indexer.GetCheckpointRepository(); checkpointRepository.CheckpointSet = null; if (options.ListCheckpoints) { foreach (var checkpoint in checkpointRepository.GetCheckpointsAsync().Result) { chain = chain ?? indexer.GetNodeChain(); var fork = chain.FindFork(checkpoint.BlockLocator); System.Console.WriteLine("Name : " + checkpoint.CheckpointName); if (fork != null) { System.Console.WriteLine("Height : " + fork.Height); System.Console.WriteLine("Hash : " + fork.HashBlock); } System.Console.WriteLine(); } } if (options.DeleteCheckpoint != null) { checkpointRepository.GetCheckpoint(options.DeleteCheckpoint).DeleteAsync().Wait(); System.Console.WriteLine("Checkpoint " + options.DeleteCheckpoint + " deleted"); } if (options.AddCheckpoint != null) { chain = chain ?? indexer.GetNodeChain(); var split = options.AddCheckpoint.Split(':'); var name = split[0]; var height = int.Parse(split[1]); var b = chain.GetBlock(height); var checkpoint = checkpointRepository.GetCheckpoint(name); checkpoint.SaveProgress(b.GetLocator()); System.Console.WriteLine("Checkpoint " + options.AddCheckpoint + " saved to height " + b.Height); } if (ConfigurationManager.AppSettings["MainDirectory"] != null) { System.Console.WriteLine("Warning : obsolete appsetting detected, MainDirectory"); string[] oldCheckpoints = new string[] { "transactions", "blocks", "wallets", "balances" }; foreach (var chk in oldCheckpoints) { var path = GetFilePath(indexer.Configuration, chk); if (File.Exists(path)) { var onlineCheckpoint = checkpointRepository.GetCheckpointsAsync().Result.FirstOrDefault(r => r.CheckpointName.ToLowerInvariant() == chk); if (onlineCheckpoint == null) { onlineCheckpoint = checkpointRepository.GetCheckpoint(indexer.Configuration.CheckpointSetName + "/" + chk); BlockLocator offlineLocator = new BlockLocator(); offlineLocator.FromBytes(File.ReadAllBytes(path)); onlineCheckpoint.SaveProgress(offlineLocator); System.Console.WriteLine("Local checkpoint " + chk + " saved in azure"); } File.Delete(path); System.Console.WriteLine("Checkpoint File deleted " + path); } } } if (options.IndexBlocks) { chain = chain ?? indexer.GetNodeChain(); indexer.IndexBlocks(chain); } if (options.IndexTransactions) { chain = chain ?? indexer.GetNodeChain(); indexer.IndexTransactions(chain); } if (options.IndexAddresses) { chain = chain ?? indexer.GetNodeChain(); indexer.IndexOrderedBalances(chain); } if (options.IndexWallets) { chain = chain ?? indexer.GetNodeChain(); indexer.IndexWalletBalances(chain); } if (options.IndexChain) { chain = chain ?? indexer.GetNodeChain(); indexer.IndexChain(chain); } } } catch (ConfigurationErrorsException ex) { System.Console.WriteLine("LocalSettings.config missing settings : " + ex.Message); } }
internal void Index(ChainBase chain, int startHeight) { List<ChainPartEntry> entries = new List<ChainPartEntry>(((chain.Height - startHeight) / BlockHeaderPerRow) + 5); startHeight = startHeight - (startHeight % BlockHeaderPerRow); ChainPartEntry chainPart = null; for(int i = startHeight; i <= chain.Tip.Height; i++) { if(chainPart == null) chainPart = new ChainPartEntry() { ChainOffset = i }; var block = chain.GetBlock(i); chainPart.BlockHeaders.Add(block.Header); if(chainPart.BlockHeaders.Count == BlockHeaderPerRow) { entries.Add(chainPart); chainPart = null; } } if(chainPart != null) entries.Add(chainPart); Index(entries); }
public void IndexChain(ChainBase chain) { if(chain == null) throw new ArgumentNullException("chain"); SetThrottling(); using(IndexerTrace.NewCorrelation("Index main chain to azure started").Open()) { Configuration.GetChainTable().CreateIfNotExists(); IndexerTrace.InputChainTip(chain.Tip); var client = Configuration.CreateIndexerClient(); var changes = client.GetChainChangesUntilFork(chain.Tip, true).ToList(); var height = 0; if(changes.Count != 0) { IndexerTrace.IndexedChainTip(changes[0].BlockId, changes[0].Height); if(changes[0].Height > chain.Tip.Height) { IndexerTrace.InputChainIsLate(); return; } height = changes[changes.Count - 1].Height + 1; if(height > chain.Height) { IndexerTrace.IndexedChainIsUpToDate(chain.Tip); return; } } else { IndexerTrace.NoForkFoundWithStored(); } IndexerTrace.IndexingChain(chain.GetBlock(height), chain.Tip); Index(chain, height); } }
public bool Process(ChainBase mainChain, IBlockProvider blockProvider) { var chainCopy = Chain.Clone(); var chainPosition = chainCopy.Changes.Position; var accountCopy = Account.Clone(); var accountPosition = accountCopy.Entries.Position; bool newChain = false; if (!chainCopy.Initialized) { newChain = true; var firstBlock = mainChain.GetBlock(StartHeight); chainCopy.Initialize(firstBlock.Header, StartHeight); } var forkBlock = mainChain.FindFork(chainCopy); if (forkBlock.HashBlock != chainCopy.Tip.HashBlock) { var subChain = chainCopy.CreateSubChain(forkBlock, false, chainCopy.Tip, true); chainCopy.SetTip(chainCopy.GetBlock(forkBlock.Height)); foreach (var e in accountCopy.GetInChain(subChain, true) .Where(c => c.Reason != AccountEntryReason.Lock && c.Reason != AccountEntryReason.Unlock) .Reverse()) { var neutralized = e.Neutralize(); accountCopy.PushAccountEntry(neutralized); } } var unprocessedBlocks = mainChain.ToEnumerable(true) .TakeWhile(block => block != forkBlock) .Concat(newChain ? new ChainedBlock[] { forkBlock } : new ChainedBlock[0]) .Reverse().ToArray(); foreach (var block in unprocessedBlocks) { List <byte[]> searchedData = new List <byte[]>(); Scanner.GetScannedPushData(searchedData); foreach (var unspent in accountCopy.Unspent) { searchedData.Add(unspent.OutPoint.ToBytes()); } var fullBlock = blockProvider.GetBlock(block.HashBlock, searchedData); if (fullBlock == null) { continue; } List <Tuple <OutPoint, AccountEntry> > spents = new List <Tuple <OutPoint, AccountEntry> >(); foreach (var spent in FindSpent(fullBlock, accountCopy.Unspent)) { var entry = new AccountEntry(AccountEntryReason.Outcome, block.HashBlock, spent.Spendable, -spent.Spendable.TxOut.Value, spent.TxId); spents.Add(Tuple.Create(entry.Spendable.OutPoint, entry)); } if (CheckDoubleSpend) { var spentsDico = spents.ToDictionary(t => t.Item1, t => t.Item2); foreach (var spent in Scanner.FindSpent(fullBlock)) { if (!spentsDico.ContainsKey(spent.PrevOut)) { return(false); } } } foreach (var spent in spents) { if (accountCopy.PushAccountEntry(spent.Item2) == null) { return(false); } } foreach (var coins in Scanner.ScanCoins(fullBlock, (int)block.Height)) { int i = 0; foreach (var output in coins.Coins.Outputs) { if (!output.IsNull) { var entry = new AccountEntry(AccountEntryReason.Income, block.HashBlock, new Spendable(new OutPoint(coins.TxId, i), output), output.Value, null); if (accountCopy.PushAccountEntry(entry) == null) { return(false); } } i++; } } chainCopy.SetTip(block); } accountCopy.Entries.GoTo(accountPosition); Account.PushAccountEntries(accountCopy.Entries); chainCopy.Changes.GoTo(chainPosition); Chain.PushChanges(chainCopy.Changes); return(true); }
public WalletTransaction ToWalletTransaction(ChainBase chain, ConcurrentDictionary<string, TrackedScript> trackedScripts, string wallet) { var chainHeight = chain.Height; var tx = new WalletTransaction() { Proof = Proof, Transaction = Transaction, UnconfirmedSeen = UnconfirmedSeen, AddedDate = AddedDate }; tx.ReceivedCoins = GetCoins(ReceivedCoins, trackedScripts, wallet); tx.SpentCoins = GetCoins(SpentCoins, trackedScripts, wallet); if(BlockId != null) { var header = chain.GetBlock(BlockId); if(header != null) { tx.BlockInformation = new BlockInformation() { Confirmations = chainHeight - header.Height + 1, Height = header.Height, Header = header.Header }; } } return tx; }