diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index 23eb711e87..7f59bc6e92 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +#nullable enable using Akka.Util.Internal; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; @@ -16,6 +17,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; @@ -27,8 +29,8 @@ namespace Neo.Ledger /// public class MemoryPool : IReadOnlyCollection { - public event EventHandler TransactionAdded; - public event EventHandler TransactionRemoved; + public event EventHandler? TransactionAdded; + public event EventHandler? TransactionRemoved; // Allow a reverified transaction to be rebroadcast if it has been this many block times since last broadcast. private const int BlocksTillRebroadcast = 10; @@ -157,15 +159,15 @@ public bool ContainsKey(UInt256 hash) /// The hash of the to get. /// When this method returns, contains the associated with the specified hash, if the hash is found; otherwise, . /// if the contains a with the specified hash; otherwise, . - public bool TryGetValue(UInt256 hash, out Transaction tx) + public bool TryGetValue(UInt256 hash, [MaybeNullWhen(false)] out Transaction? tx) { _txRwLock.EnterReadLock(); try { - bool ret = _unsortedTransactions.TryGetValue(hash, out PoolItem item) - || _unverifiedTransactions.TryGetValue(hash, out item); - tx = ret ? item.Tx : null; - return ret; + _ = _unsortedTransactions.TryGetValue(hash, out var item) + || _unverifiedTransactions.TryGetValue(hash, out item); + tx = item?.Tx; + return tx != null; } finally { @@ -247,13 +249,13 @@ public IEnumerable GetSortedVerifiedTransactions() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static PoolItem GetLowestFeeTransaction(SortedSet verifiedTxSorted, - SortedSet unverifiedTxSorted, out SortedSet sortedPool) + private static PoolItem? GetLowestFeeTransaction(SortedSet verifiedTxSorted, + SortedSet unverifiedTxSorted, out SortedSet? sortedPool) { - PoolItem minItem = unverifiedTxSorted.Min; + var minItem = unverifiedTxSorted.Min; sortedPool = minItem != null ? unverifiedTxSorted : null; - PoolItem verifiedMin = verifiedTxSorted.Min; + var verifiedMin = verifiedTxSorted.Min; if (verifiedMin == null) return minItem; if (minItem != null && verifiedMin.CompareTo(minItem) >= 0) @@ -265,7 +267,7 @@ private static PoolItem GetLowestFeeTransaction(SortedSet verifiedTxSo return minItem; } - private PoolItem GetLowestFeeTransaction(out Dictionary unsortedTxPool, out SortedSet sortedPool) + private PoolItem? GetLowestFeeTransaction(out Dictionary unsortedTxPool, out SortedSet? sortedPool) { sortedPool = null; @@ -286,7 +288,10 @@ internal bool CanTransactionFitInPool(Transaction tx) { if (Count < Capacity) return true; - return GetLowestFeeTransaction(out _, out _).CompareTo(tx) <= 0; + var item = GetLowestFeeTransaction(out _, out _); + if (item == null) return false; + + return item.CompareTo(tx) <= 0; } internal VerifyResult TryAdd(Transaction tx, DataCache snapshot) @@ -295,7 +300,7 @@ internal VerifyResult TryAdd(Transaction tx, DataCache snapshot) if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyInPool; - List removedTransactions = null; + List? removedTransactions = null; _txRwLock.EnterWriteLock(); try { @@ -368,7 +373,7 @@ private bool CheckConflicts(Transaction tx, out List conflictsList) // Step 2: check if unsorted transactions were in `tx`'s Conflicts attributes. foreach (var hash in tx.GetAttributes().Select(p => p.Hash)) { - if (_unsortedTransactions.TryGetValue(hash, out PoolItem unsortedTx)) + if (_unsortedTransactions.TryGetValue(hash, out var unsortedTx)) { if (!tx.Signers.Select(p => p.Account).Intersect(unsortedTx.Tx.Signers.Select(p => p.Account)).Any()) return false; conflictsFeeSum += unsortedTx.Tx.NetworkFee; @@ -390,7 +395,8 @@ private List RemoveOverCapacity() List removedTransactions = new(); do { - PoolItem minItem = GetLowestFeeTransaction(out var unsortedPool, out var sortedPool); + var minItem = GetLowestFeeTransaction(out var unsortedPool, out var sortedPool); + if (minItem == null || sortedPool == null) break; unsortedPool.Remove(minItem.Tx.Hash); sortedPool.Remove(minItem); @@ -407,7 +413,7 @@ private List RemoveOverCapacity() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool TryRemoveVerified(UInt256 hash, out PoolItem item) + private bool TryRemoveVerified(UInt256 hash, [MaybeNullWhen(false)] out PoolItem? item) { if (!_unsortedTransactions.TryGetValue(hash, out item)) return false; @@ -425,7 +431,7 @@ private void RemoveConflictsOfVerified(PoolItem item) { foreach (var h in item.Tx.GetAttributes().Select(attr => attr.Hash)) { - if (_conflicts.TryGetValue(h, out HashSet conflicts)) + if (_conflicts.TryGetValue(h, out var conflicts)) { conflicts.Remove(item.Tx.Hash); if (conflicts.Count() == 0) @@ -437,7 +443,7 @@ private void RemoveConflictsOfVerified(PoolItem item) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TryRemoveUnVerified(UInt256 hash, out PoolItem item) + internal bool TryRemoveUnVerified(UInt256 hash, [MaybeNullWhen(false)] out PoolItem? item) { if (!_unverifiedTransactions.TryGetValue(hash, out item)) return false;