public void UpdateAccountProperties(Account account, string name, uint externalKeyCount, uint internalKeyCount, uint importedKeyCount) { AccountProperties props; if (!_accounts.TryGetValue(account, out props)) { props = new AccountProperties(); _accounts[account] = props; } props.AccountName = name; props.ExternalKeyCount = externalKeyCount; props.InternalKeyCount = internalKeyCount; props.ImportedKeyCount = importedKeyCount; var eventArgs = new ChangesProcessedEventArgs(); eventArgs.ModifiedAccountProperties[account] = props; OnChangesProcessed(eventArgs); }
public void UpdateAccountProperties(Account account, string name, uint externalKeyCount, uint internalKeyCount, uint importedKeyCount) { AccountProperties props; if (account.AccountNumber == ImportedAccountNumber) { props = _importedAccount; } else { var accountNumber = checked ((int)account.AccountNumber); if (accountNumber < _bip0032Accounts.Count) { props = _bip0032Accounts[accountNumber]; } else if (accountNumber == _bip0032Accounts.Count) { props = new AccountProperties(); _bip0032Accounts.Add(props); } else { throw new Exception($"Account {accountNumber} is not the next BIP0032 account."); } } props.AccountName = name; props.ExternalKeyCount = externalKeyCount; props.InternalKeyCount = internalKeyCount; props.ImportedKeyCount = importedKeyCount; var eventArgs = new ChangesProcessedEventArgs(); eventArgs.ModifiedAccountProperties[account] = props; OnChangesProcessed(eventArgs); }
public void UpdateAccountProperties(Account account, string name, uint externalKeyCount, uint internalKeyCount, uint importedKeyCount) { AccountProperties props; if (account.AccountNumber == ImportedAccountNumber) { props = _importedAccount; } else { var accountNumber = checked((int)account.AccountNumber); if (accountNumber < _bip0032Accounts.Count) { props = _bip0032Accounts[accountNumber]; } else if (accountNumber == _bip0032Accounts.Count) { props = new AccountProperties(); _bip0032Accounts.Add(props); } else { throw new Exception($"Account {accountNumber} is not the next BIP0032 account."); } } props.AccountName = name; props.ExternalKeyCount = externalKeyCount; props.InternalKeyCount = internalKeyCount; props.ImportedKeyCount = importedKeyCount; var eventArgs = new ChangesProcessedEventArgs(); eventArgs.ModifiedAccountProperties[account] = props; OnChangesProcessed(eventArgs); }
public void ApplyTransactionChanges(WalletChanges changes) { if (changes == null) throw new ArgumentNullException(nameof(changes)); // A reorganize cannot be handled if the number of removed blocks exceeds the // minimum number saved in memory. if (changes.DetachedBlocks.Count >= NumRecentBlocks(ActiveChain)) throw new BlockChainConsistencyException("Reorganize too deep"); var newChainTip = changes.AttachedBlocks.LastOrDefault(); if (ChainTip.Height >= newChainTip?.Height) { var msg = $"New chain tip {newChainTip.Hash} (height {newChainTip.Height}) neither extends nor replaces " + $"the current chain (currently synced to hash {ChainTip.Hash}, height {ChainTip.Height})"; throw new BlockChainConsistencyException(msg); } if (changes.NewUnminedTransactions.Any(tx => !changes.AllUnminedHashes.Contains(tx.Hash))) throw new BlockChainConsistencyException("New unmined transactions contains tx with hash not found in all unmined transaction hash set"); var eventArgs = new ChangesProcessedEventArgs(); var reorgedBlocks = RecentTransactions.MinedTransactions .ReverseList() .TakeWhile(b => changes.DetachedBlocks.Contains(b.Hash)) .ToList(); var numReorgedBlocks = reorgedBlocks.Count; foreach (var reorgedTx in reorgedBlocks.SelectMany(b => b.Transactions)) { if (BlockChain.IsCoinbase(reorgedTx.Transaction) || !changes.AllUnminedHashes.Contains(reorgedTx.Hash)) { RemoveTransactionFromTotals(reorgedTx, eventArgs.ModifiedAccountProperties); } else { RecentTransactions.UnminedTransactions[reorgedTx.Hash] = reorgedTx; eventArgs.MovedTransactions.Add(reorgedTx.Hash, BlockIdentity.Unmined); } } var numRemoved = RecentTransactions.MinedTransactions.RemoveAll(block => changes.DetachedBlocks.Contains(block.Hash)); if (numRemoved != numReorgedBlocks) { throw new BlockChainConsistencyException("Number of blocks removed exceeds those for which transactions were removed"); } foreach (var block in changes.AttachedBlocks.Where(b => b.Transactions.Count > 0)) { RecentTransactions.MinedTransactions.Add(block); foreach (var tx in block.Transactions) { if (RecentTransactions.UnminedTransactions.ContainsKey(tx.Hash)) { RecentTransactions.UnminedTransactions.Remove(tx.Hash); eventArgs.MovedTransactions[tx.Hash] = block.Identity; } else if (!eventArgs.MovedTransactions.ContainsKey(tx.Hash)) { AddTransactionToTotals(tx, eventArgs.ModifiedAccountProperties); eventArgs.AddedTransactions.Add(Tuple.Create(tx, block.Identity)); } } } // TODO: What about new transactions which were not added in a newly processed // block (e.g. importing an address and rescanning for outputs)? foreach (var tx in changes.NewUnminedTransactions.Where(tx => !RecentTransactions.UnminedTransactions.ContainsKey(tx.Hash))) { RecentTransactions.UnminedTransactions[tx.Hash] = tx; AddTransactionToTotals(tx, eventArgs.ModifiedAccountProperties); // TODO: When reorgs are handled, this will need to check whether the transaction // being added to the unmined collection was previously in a block. eventArgs.AddedTransactions.Add(Tuple.Create(tx, BlockIdentity.Unmined)); } var removedUnmined = RecentTransactions.UnminedTransactions .Where(kvp => !changes.AllUnminedHashes.Contains(kvp.Key)) .ToList(); // Collect to list so UnminedTransactions can be modified below. foreach (var unmined in removedUnmined) { // Transactions that were mined rather than being removed from the unmined // set due to a conflict have already been removed. RecentTransactions.UnminedTransactions.Remove(unmined.Key); RemoveTransactionFromTotals(unmined.Value, eventArgs.ModifiedAccountProperties); eventArgs.RemovedTransactions.Add(unmined.Value); } if (newChainTip != null) { ChainTip = newChainTip.Identity; eventArgs.NewChainTip = newChainTip.Identity; } OnChangesProcessed(eventArgs); }
private void OnChangesProcessed(ChangesProcessedEventArgs e) { ChangesProcessed?.Invoke(this, e); }
public void UpdateAccountProperties(Account account, string name, uint externalKeyCount, uint internalKeyCount, uint importedKeyCount) { AccountState stats; if (!_accounts.TryGetValue(account, out stats)) { stats = new AccountState(); _accounts[account] = stats; } stats.AccountName = name; stats.ExternalKeyCount = externalKeyCount; stats.InternalKeyCount = internalKeyCount; stats.ImportedKeyCount = importedKeyCount; var eventArgs = new ChangesProcessedEventArgs(); eventArgs.ModifiedAccountStates[account] = stats; OnChangesProcessed(eventArgs); }
public void ApplyTransactionChanges(WalletChanges changes) { if (changes == null) { throw new ArgumentNullException(nameof(changes)); } // A reorganize cannot be handled if the number of removed blocks exceeds the // minimum number saved in memory. if (changes.DetachedBlocks.Count >= NumRecentBlocks) { throw new BlockChainConsistencyException("Reorganize too deep"); } var newChainTip = changes.AttachedBlocks.LastOrDefault(); if (ChainTip.Height >= newChainTip?.Height) { var msg = $"New chain tip {newChainTip.Hash} (height {newChainTip.Height}) neither extends nor replaces " + $"the current chain (currently synced to hash {ChainTip.Hash}, height {ChainTip.Height})"; throw new BlockChainConsistencyException(msg); } if (changes.NewUnminedTransactions.Any(tx => !changes.AllUnminedHashes.Contains(tx.Hash))) { throw new BlockChainConsistencyException("New unmined transactions contains tx with hash not found in all unmined transaction hash set"); } var eventArgs = new ChangesProcessedEventArgs(); var reorgedBlocks = RecentTransactions.MinedTransactions .ReverseList() .TakeWhile(b => changes.DetachedBlocks.Contains(b.Hash)) .ToList(); var numReorgedBlocks = reorgedBlocks.Count; foreach (var reorgedTx in reorgedBlocks.SelectMany(b => b.Transactions)) { if (BlockChain.IsCoinbase(reorgedTx.Transaction) || !changes.AllUnminedHashes.Contains(reorgedTx.Hash)) { RemoveTransactionFromTotals(reorgedTx, eventArgs.ModifiedAccountProperties); } else { RecentTransactions.UnminedTransactions[reorgedTx.Hash] = reorgedTx; eventArgs.MovedTransactions.Add(reorgedTx.Hash, BlockIdentity.Unmined); } } var numRemoved = RecentTransactions.MinedTransactions.RemoveAll(block => changes.DetachedBlocks.Contains(block.Hash)); if (numRemoved != numReorgedBlocks) { throw new BlockChainConsistencyException("Number of blocks removed exceeds those for which transactions were removed"); } foreach (var block in changes.AttachedBlocks.Where(b => b.Transactions.Count > 0)) { RecentTransactions.MinedTransactions.Add(block); foreach (var tx in block.Transactions) { if (RecentTransactions.UnminedTransactions.ContainsKey(tx.Hash)) { RecentTransactions.UnminedTransactions.Remove(tx.Hash); eventArgs.MovedTransactions[tx.Hash] = block.Identity; } else if (!eventArgs.MovedTransactions.ContainsKey(tx.Hash)) { AddTransactionToTotals(tx, eventArgs.ModifiedAccountProperties); eventArgs.AddedTransactions.Add(Tuple.Create(tx, block.Identity)); } } } // TODO: What about new transactions which were not added in a newly processed // block (e.g. importing an address and rescanning for outputs)? foreach (var tx in changes.NewUnminedTransactions.Where(tx => !RecentTransactions.UnminedTransactions.ContainsKey(tx.Hash))) { RecentTransactions.UnminedTransactions[tx.Hash] = tx; AddTransactionToTotals(tx, eventArgs.ModifiedAccountProperties); // TODO: When reorgs are handled, this will need to check whether the transaction // being added to the unmined collection was previously in a block. eventArgs.AddedTransactions.Add(Tuple.Create(tx, BlockIdentity.Unmined)); } var removedUnmined = RecentTransactions.UnminedTransactions .Where(kvp => !changes.AllUnminedHashes.Contains(kvp.Key)) .ToList(); // Collect to list so UnminedTransactions can be modified below. foreach (var unmined in removedUnmined) { // Transactions that were mined rather than being removed from the unmined // set due to a conflict have already been removed. RecentTransactions.UnminedTransactions.Remove(unmined.Key); RemoveTransactionFromTotals(unmined.Value, eventArgs.ModifiedAccountProperties); eventArgs.RemovedTransactions.Add(unmined.Value); } if (newChainTip != null) { ChainTip = newChainTip.Identity; eventArgs.NewChainTip = newChainTip.Identity; } OnChangesProcessed(eventArgs); }