From bf9341222e04b7f38d4e4e606412435b4c4acc0a Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 2 Jul 2024 04:46:11 -0400 Subject: [PATCH 1/6] Part-1 `Neo.IO` - move --- src/{Neo/IO => Neo.IO}/Caching/Cache.cs | 56 ++++++++----------- src/{Neo/IO => Neo.IO}/Caching/FIFOCache.cs | 9 +-- .../IO => Neo.IO}/Caching/HashSetCache.cs | 36 ++++++------ .../IO => Neo.IO}/Caching/IndexedQueue.cs | 16 +++--- .../Caching/KeyedCollectionSlim.cs | 23 ++++---- src/Neo/Cryptography/Crypto.cs | 2 +- src/Neo/IO/Caching/ECDsaCache.cs | 5 +- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 6 +- 8 files changed, 72 insertions(+), 81 deletions(-) rename src/{Neo/IO => Neo.IO}/Caching/Cache.cs (80%) rename src/{Neo/IO => Neo.IO}/Caching/FIFOCache.cs (72%) rename src/{Neo/IO => Neo.IO}/Caching/HashSetCache.cs (76%) rename src/{Neo/IO => Neo.IO}/Caching/IndexedQueue.cs (95%) rename src/{Neo/IO => Neo.IO}/Caching/KeyedCollectionSlim.cs (61%) diff --git a/src/Neo/IO/Caching/Cache.cs b/src/Neo.IO/Caching/Cache.cs similarity index 80% rename from src/Neo/IO/Caching/Cache.cs rename to src/Neo.IO/Caching/Cache.cs index 7895a8ca2d..1a66e6dca5 100644 --- a/src/Neo/IO/Caching/Cache.cs +++ b/src/Neo.IO/Caching/Cache.cs @@ -17,25 +17,21 @@ namespace Neo.IO.Caching { - internal abstract class Cache : ICollection, IDisposable + internal abstract class Cache + (int max_capacity, IEqualityComparer? comparer = null) : ICollection, IDisposable + where TKey : notnull { protected class CacheItem + (TKey key, TValue value) { - public readonly TKey Key; - public readonly TValue Value; - public readonly DateTime Time; - - public CacheItem(TKey key, TValue value) - { - Key = key; - Value = value; - Time = TimeProvider.Current.UtcNow; - } + public readonly TKey Key = key; + public readonly TValue Value = value; + public readonly DateTime Time = DateTime.UtcNow; } protected readonly ReaderWriterLockSlim RwSyncRootLock = new(LockRecursionPolicy.SupportsRecursion); - protected readonly Dictionary InnerDictionary; - private readonly int max_capacity; + protected readonly Dictionary InnerDictionary = new Dictionary(comparer); + private readonly int _max_capacity = max_capacity; public TValue this[TKey key] { @@ -44,7 +40,7 @@ public TValue this[TKey key] RwSyncRootLock.EnterReadLock(); try { - if (!InnerDictionary.TryGetValue(key, out CacheItem item)) throw new KeyNotFoundException(); + if (!InnerDictionary.TryGetValue(key, out CacheItem? item)) throw new KeyNotFoundException(); OnAccess(item); return item.Value; } @@ -73,15 +69,9 @@ public int Count public bool IsReadOnly => false; - public Cache(int max_capacity, IEqualityComparer comparer = null) - { - this.max_capacity = max_capacity; - InnerDictionary = new Dictionary(comparer); - } - public void Add(TValue item) { - TKey key = GetKeyForItem(item); + var key = GetKeyForItem(item); RwSyncRootLock.EnterWriteLock(); try { @@ -95,16 +85,16 @@ public void Add(TValue item) private void AddInternal(TKey key, TValue item) { - if (InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) + if (InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) { OnAccess(cacheItem); } else { - if (InnerDictionary.Count >= max_capacity) + if (InnerDictionary.Count >= _max_capacity) { //TODO: Perform a performance test on the PLINQ query to determine which algorithm is better here (parallel or not) - foreach (CacheItem item_del in InnerDictionary.Values.AsParallel().OrderBy(p => p.Time).Take(InnerDictionary.Count - max_capacity + 1)) + foreach (var item_del in InnerDictionary.Values.AsParallel().OrderBy(p => p.Time).Take(InnerDictionary.Count - _max_capacity + 1)) { RemoveInternal(item_del); } @@ -118,9 +108,9 @@ public void AddRange(IEnumerable items) RwSyncRootLock.EnterWriteLock(); try { - foreach (TValue item in items) + foreach (var item in items) { - TKey key = GetKeyForItem(item); + var key = GetKeyForItem(item); AddInternal(key, item); } } @@ -135,7 +125,7 @@ public void Clear() RwSyncRootLock.EnterWriteLock(); try { - foreach (CacheItem item_del in InnerDictionary.Values.ToArray()) + foreach (var item_del in InnerDictionary.Values.ToArray()) { RemoveInternal(item_del); } @@ -151,7 +141,7 @@ public bool Contains(TKey key) RwSyncRootLock.EnterReadLock(); try { - if (!InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) return false; + if (!InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) return false; OnAccess(cacheItem); return true; } @@ -171,7 +161,7 @@ public void CopyTo(TValue[] array, int arrayIndex) if (array == null) throw new ArgumentNullException(); if (arrayIndex < 0) throw new ArgumentOutOfRangeException(); if (arrayIndex + InnerDictionary.Count > array.Length) throw new ArgumentException(); - foreach (TValue item in this) + foreach (var item in this) { array[arrayIndex++] = item; } @@ -188,7 +178,7 @@ public IEnumerator GetEnumerator() RwSyncRootLock.EnterReadLock(); try { - foreach (TValue item in InnerDictionary.Values.Select(p => p.Value)) + foreach (var item in InnerDictionary.Values.Select(p => p.Value)) { yield return item; } @@ -211,7 +201,7 @@ public bool Remove(TKey key) RwSyncRootLock.EnterWriteLock(); try { - if (!InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) return false; + if (!InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) return false; RemoveInternal(cacheItem); return true; } @@ -242,7 +232,7 @@ public bool TryGet(TKey key, out TValue item) RwSyncRootLock.EnterReadLock(); try { - if (InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) + if (InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) { OnAccess(cacheItem); item = cacheItem.Value; @@ -253,7 +243,7 @@ public bool TryGet(TKey key, out TValue item) { RwSyncRootLock.ExitReadLock(); } - item = default; + item = default!; return false; } } diff --git a/src/Neo/IO/Caching/FIFOCache.cs b/src/Neo.IO/Caching/FIFOCache.cs similarity index 72% rename from src/Neo/IO/Caching/FIFOCache.cs rename to src/Neo.IO/Caching/FIFOCache.cs index af3e5e469d..b7e9f39e98 100644 --- a/src/Neo/IO/Caching/FIFOCache.cs +++ b/src/Neo.IO/Caching/FIFOCache.cs @@ -13,13 +13,10 @@ namespace Neo.IO.Caching { - internal abstract class FIFOCache : Cache + internal abstract class FIFOCache + (int max_capacity, IEqualityComparer? comparer = null) : Cache(max_capacity, comparer) + where TKey : notnull { - public FIFOCache(int max_capacity, IEqualityComparer comparer = null) - : base(max_capacity, comparer) - { - } - protected override void OnAccess(CacheItem item) { } diff --git a/src/Neo/IO/Caching/HashSetCache.cs b/src/Neo.IO/Caching/HashSetCache.cs similarity index 76% rename from src/Neo/IO/Caching/HashSetCache.cs rename to src/Neo.IO/Caching/HashSetCache.cs index bdef1c5e3a..577893e924 100644 --- a/src/Neo/IO/Caching/HashSetCache.cs +++ b/src/Neo.IO/Caching/HashSetCache.cs @@ -20,17 +20,17 @@ class HashSetCache : IReadOnlyCollection where T : IEquatable /// /// Sets where the Hashes are stored /// - private readonly LinkedList> sets = new(); + private readonly LinkedList> _sets = new(); /// - /// Maximum capacity of each bucket inside each HashSet of . + /// Maximum capacity of each bucket inside each HashSet of . /// - private readonly int bucketCapacity; + private readonly int _bucketCapacity; /// /// Maximum number of buckets for the LinkedList, meaning its maximum cardinality. /// - private readonly int maxBucketCount; + private readonly int _maxBucketCount; /// /// Entry count @@ -43,32 +43,32 @@ public HashSetCache(int bucketCapacity, int maxBucketCount = 10) if (maxBucketCount <= 0) throw new ArgumentOutOfRangeException($"{nameof(maxBucketCount)} should be greater than 0"); Count = 0; - this.bucketCapacity = bucketCapacity; - this.maxBucketCount = maxBucketCount; - sets.AddFirst(new HashSet()); + _bucketCapacity = bucketCapacity; + _maxBucketCount = maxBucketCount; + _sets.AddFirst([]); } public bool Add(T item) { if (Contains(item)) return false; Count++; - if (sets.First.Value.Count < bucketCapacity) return sets.First.Value.Add(item); + if (_sets.First?.Value.Count < _bucketCapacity) return _sets.First.Value.Add(item); var newSet = new HashSet { item }; - sets.AddFirst(newSet); - if (sets.Count > maxBucketCount) + _sets.AddFirst(newSet); + if (_sets.Count > _maxBucketCount) { - Count -= sets.Last.Value.Count; - sets.RemoveLast(); + Count -= _sets.Last?.Value.Count ?? 0; + _sets.RemoveLast(); } return true; } public bool Contains(T item) { - foreach (var set in sets) + foreach (var set in _sets) { if (set.Contains(item)) return true; } @@ -77,17 +77,17 @@ public bool Contains(T item) public void ExceptWith(IEnumerable items) { - List> removeList = null; + List> removeList = default!; foreach (var item in items) { - foreach (var set in sets) + foreach (var set in _sets) { if (set.Remove(item)) { Count--; if (set.Count == 0) { - removeList ??= new List>(); + removeList ??= []; removeList.Add(set); } break; @@ -97,13 +97,13 @@ public void ExceptWith(IEnumerable items) if (removeList == null) return; foreach (var set in removeList) { - sets.Remove(set); + _sets.Remove(set); } } public IEnumerator GetEnumerator() { - foreach (var set in sets) + foreach (var set in _sets) { foreach (var item in set) { diff --git a/src/Neo/IO/Caching/IndexedQueue.cs b/src/Neo.IO/Caching/IndexedQueue.cs similarity index 95% rename from src/Neo/IO/Caching/IndexedQueue.cs rename to src/Neo.IO/Caching/IndexedQueue.cs index 54440a871b..29b39a4947 100644 --- a/src/Neo/IO/Caching/IndexedQueue.cs +++ b/src/Neo.IO/Caching/IndexedQueue.cs @@ -89,14 +89,14 @@ public void Enqueue(T item) { if (_array.Length == _count) { - int newSize = _array.Length * GrowthFactor; + var newSize = _array.Length * GrowthFactor; if (_head == 0) { Array.Resize(ref _array, newSize); } else { - T[] buffer = new T[newSize]; + var buffer = new T[newSize]; Array.Copy(_array, _head, buffer, 0, _array.Length - _head); Array.Copy(_array, 0, buffer, _array.Length - _head, _head); _array = buffer; @@ -127,7 +127,7 @@ public bool TryPeek(out T item) { if (_count == 0) { - item = default; + item = default!; return false; } else @@ -145,7 +145,7 @@ public T Dequeue() { if (_count == 0) throw new InvalidOperationException("The queue is empty"); - T result = _array[_head]; + var result = _array[_head]; ++_head; _head %= _array.Length; --_count; @@ -161,7 +161,7 @@ public bool TryDequeue(out T item) { if (_count == 0) { - item = default; + item = default!; return false; } else @@ -194,7 +194,7 @@ public void TrimExcess() } else if (_array.Length * TrimThreshold >= _count) { - T[] arr = new T[_count]; + var arr = new T[_count]; CopyTo(arr, 0); _array = arr; _head = 0; @@ -228,14 +228,14 @@ public void CopyTo(T[] array, int arrayIndex) /// An array containing the queue's items public T[] ToArray() { - T[] result = new T[_count]; + var result = new T[_count]; CopyTo(result, 0); return result; } public IEnumerator GetEnumerator() { - for (int i = 0; i < _count; i++) + for (var i = 0; i < _count; i++) yield return _array[(_head + i) % _array.Length]; } diff --git a/src/Neo/IO/Caching/KeyedCollectionSlim.cs b/src/Neo.IO/Caching/KeyedCollectionSlim.cs similarity index 61% rename from src/Neo/IO/Caching/KeyedCollectionSlim.cs rename to src/Neo.IO/Caching/KeyedCollectionSlim.cs index a24dd87e4c..f632dc0927 100644 --- a/src/Neo/IO/Caching/KeyedCollectionSlim.cs +++ b/src/Neo.IO/Caching/KeyedCollectionSlim.cs @@ -10,43 +10,46 @@ // modifications are permitted. using System; +using System.Collections; using System.Collections.Generic; namespace Neo.IO.Caching; -abstract class KeyedCollectionSlim where TKey : notnull +abstract class KeyedCollectionSlim + where TKey : notnull + where TItem : class, IStructuralEquatable, IStructuralComparable, IComparable { private readonly LinkedList _items = new(); - private readonly Dictionary> dict = new(); + private readonly Dictionary> _dict = []; - public int Count => dict.Count; - public TItem First => _items.First.Value; + public int Count => _dict.Count; + public TItem? First => _items.First?.Value; - protected abstract TKey GetKeyForItem(TItem item); + protected abstract TKey GetKeyForItem(TItem? item); public void Add(TItem item) { var key = GetKeyForItem(item); var node = _items.AddLast(item); - if (!dict.TryAdd(key, node)) + if (!_dict.TryAdd(key, node)) { _items.RemoveLast(); throw new ArgumentException("An element with the same key already exists in the collection."); } } - public bool Contains(TKey key) => dict.ContainsKey(key); + public bool Contains(TKey key) => _dict.ContainsKey(key); public void Remove(TKey key) { - if (dict.Remove(key, out var node)) + if (_dict.Remove(key, out var node)) _items.Remove(node); } public void RemoveFirst() { - var key = GetKeyForItem(_items.First.Value); - dict.Remove(key); + var key = GetKeyForItem(_items.First?.Value); + _dict.Remove(key); _items.RemoveFirst(); } } diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index 85ed0411a8..a2e89dc787 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -170,7 +170,7 @@ public static ECDsa CreateECDsa(ECC.ECPoint pubkey) { if (CacheECDsa.TryGet(pubkey, out var cache)) { - return cache.value; + return cache.Value; } var curve = pubkey.Curve == ECC.ECCurve.Secp256r1 ? ECCurve.NamedCurves.nistP256 : diff --git a/src/Neo/IO/Caching/ECDsaCache.cs b/src/Neo/IO/Caching/ECDsaCache.cs index b25f29da8e..b41a058b61 100644 --- a/src/Neo/IO/Caching/ECDsaCache.cs +++ b/src/Neo/IO/Caching/ECDsaCache.cs @@ -14,7 +14,8 @@ namespace Neo.IO.Caching { - record ECDsaCacheItem(Cryptography.ECC.ECPoint key, ECDsa value); + record ECDsaCacheItem(Cryptography.ECC.ECPoint Key, ECDsa Value); + internal class ECDsaCache : FIFOCache { public ECDsaCache(int max_capacity = 20000) : base(max_capacity, EqualityComparer.Default) @@ -23,7 +24,7 @@ public ECDsaCache(int max_capacity = 20000) : base(max_capacity, EqualityCompare protected override Cryptography.ECC.ECPoint GetKeyForItem(ECDsaCacheItem item) { - return item.key; + return item.Key; } } } diff --git a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 4606723cd0..4e7861a562 100644 --- a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -30,9 +30,9 @@ namespace Neo.Network.P2P partial class RemoteNode { private class Timer { } - private class PendingKnownHashesCollection : KeyedCollectionSlim + private class PendingKnownHashesCollection : KeyedCollectionSlim> { - protected override UInt256 GetKeyForItem((UInt256, DateTime) item) + protected override UInt256 GetKeyForItem(Tuple item) { return item.Item1; } @@ -354,7 +354,7 @@ private void OnInvMessageReceived(InvPayload payload) } if (hashes.Length == 0) return; foreach (UInt256 hash in hashes) - pendingKnownHashes.Add((hash, TimeProvider.Current.UtcNow)); + pendingKnownHashes.Add(Tuple.Create(hash, TimeProvider.Current.UtcNow)); system.TaskManager.Tell(new TaskManager.NewTasks { Payload = InvPayload.Create(payload.Type, hashes) }); } From 4d08154ccb0832c0a4e8ad5f04d56d4c8ccabe3b Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 2 Jul 2024 05:22:54 -0400 Subject: [PATCH 2/6] Part-2 --- src/{Neo/IO => Neo.IO}/Actors/Idle.cs | 2 +- .../Caching/ReflectionCacheAttribute.cs | 18 ++++------ src/Neo/IO/Actors/PriorityMailbox.cs | 14 +++----- src/Neo/IO/Actors/PriorityMessageQueue.cs | 35 ++++++++----------- src/Neo/IO/Caching/ReflectionCache.cs | 17 ++++----- src/Neo/IO/Caching/RelayCache.cs | 8 ++--- 6 files changed, 38 insertions(+), 56 deletions(-) rename src/{Neo/IO => Neo.IO}/Actors/Idle.cs (89%) rename src/{Neo/IO => Neo.IO}/Caching/ReflectionCacheAttribute.cs (67%) diff --git a/src/Neo/IO/Actors/Idle.cs b/src/Neo.IO/Actors/Idle.cs similarity index 89% rename from src/Neo/IO/Actors/Idle.cs rename to src/Neo.IO/Actors/Idle.cs index e722d057ee..c372062783 100644 --- a/src/Neo/IO/Actors/Idle.cs +++ b/src/Neo.IO/Actors/Idle.cs @@ -13,6 +13,6 @@ namespace Neo.IO.Actors { internal sealed class Idle { - public static Idle Instance { get; } = new Idle(); + public static Idle Instance { get; } = new(); } } diff --git a/src/Neo/IO/Caching/ReflectionCacheAttribute.cs b/src/Neo.IO/Caching/ReflectionCacheAttribute.cs similarity index 67% rename from src/Neo/IO/Caching/ReflectionCacheAttribute.cs rename to src/Neo.IO/Caching/ReflectionCacheAttribute.cs index 20aeb91320..7071e879e4 100644 --- a/src/Neo/IO/Caching/ReflectionCacheAttribute.cs +++ b/src/Neo.IO/Caching/ReflectionCacheAttribute.cs @@ -13,21 +13,17 @@ namespace Neo.IO.Caching { + /// + /// Constructor + /// + /// Type [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] - internal class ReflectionCacheAttribute : Attribute + internal class ReflectionCacheAttribute + (Type type) : Attribute { /// /// Type /// - public Type Type { get; } - - /// - /// Constructor - /// - /// Type - public ReflectionCacheAttribute(Type type) - { - Type = type; - } + public Type Type { get; } = type; } } diff --git a/src/Neo/IO/Actors/PriorityMailbox.cs b/src/Neo/IO/Actors/PriorityMailbox.cs index 0b08c04d70..b51d5ee861 100644 --- a/src/Neo/IO/Actors/PriorityMailbox.cs +++ b/src/Neo/IO/Actors/PriorityMailbox.cs @@ -17,17 +17,11 @@ namespace Neo.IO.Actors { - internal abstract class PriorityMailbox : MailboxType, IProducesMessageQueue + internal abstract class PriorityMailbox + (Settings settings, Config config) : MailboxType(settings, config), IProducesMessageQueue { - public PriorityMailbox(Akka.Actor.Settings settings, Config config) - : base(settings, config) - { - } - - public override IMessageQueue Create(IActorRef owner, ActorSystem system) - { - return new PriorityMessageQueue(ShallDrop, IsHighPriority); - } + public override IMessageQueue Create(IActorRef owner, ActorSystem system) => + new PriorityMessageQueue(ShallDrop, IsHighPriority); internal protected virtual bool IsHighPriority(object message) => false; internal protected virtual bool ShallDrop(object message, IEnumerable queue) => false; diff --git a/src/Neo/IO/Actors/PriorityMessageQueue.cs b/src/Neo/IO/Actors/PriorityMessageQueue.cs index 225720ec97..8723416adf 100644 --- a/src/Neo/IO/Actors/PriorityMessageQueue.cs +++ b/src/Neo/IO/Actors/PriorityMessageQueue.cs @@ -20,22 +20,17 @@ namespace Neo.IO.Actors { - internal class PriorityMessageQueue : IMessageQueue, IUnboundedMessageQueueSemantics + internal class PriorityMessageQueue + (Func dropper, Func priority_generator) : IMessageQueue, IUnboundedMessageQueueSemantics { - private readonly ConcurrentQueue high = new(); - private readonly ConcurrentQueue low = new(); - private readonly Func dropper; - private readonly Func priority_generator; - private int idle = 1; + private readonly ConcurrentQueue _high = new(); + private readonly ConcurrentQueue _low = new(); + private readonly Func _dropper = dropper; + private readonly Func _priority_generator = priority_generator; + private int _idle = 1; - public bool HasMessages => !high.IsEmpty || !low.IsEmpty; - public int Count => high.Count + low.Count; - - public PriorityMessageQueue(Func dropper, Func priority_generator) - { - this.dropper = dropper; - this.priority_generator = priority_generator; - } + public bool HasMessages => !_high.IsEmpty || !_low.IsEmpty; + public int Count => _high.Count + _low.Count; public void CleanUp(IActorRef owner, IMessageQueue deadletters) { @@ -43,19 +38,19 @@ public void CleanUp(IActorRef owner, IMessageQueue deadletters) public void Enqueue(IActorRef receiver, Envelope envelope) { - Interlocked.Increment(ref idle); + Interlocked.Increment(ref _idle); if (envelope.Message is Idle) return; - if (dropper(envelope.Message, high.Concat(low).Select(p => p.Message))) + if (_dropper(envelope.Message, _high.Concat(_low).Select(p => p.Message))) return; - ConcurrentQueue queue = priority_generator(envelope.Message) ? high : low; + var queue = _priority_generator(envelope.Message) ? _high : _low; queue.Enqueue(envelope); } public bool TryDequeue(out Envelope envelope) { - if (high.TryDequeue(out envelope)) return true; - if (low.TryDequeue(out envelope)) return true; - if (Interlocked.Exchange(ref idle, 0) > 0) + if (_high.TryDequeue(out envelope)) return true; + if (_low.TryDequeue(out envelope)) return true; + if (Interlocked.Exchange(ref _idle, 0) > 0) { envelope = new Envelope(Idle.Instance, ActorRefs.NoSender); return true; diff --git a/src/Neo/IO/Caching/ReflectionCache.cs b/src/Neo/IO/Caching/ReflectionCache.cs index 2fd8f5fceb..5007b67740 100644 --- a/src/Neo/IO/Caching/ReflectionCache.cs +++ b/src/Neo/IO/Caching/ReflectionCache.cs @@ -15,29 +15,30 @@ namespace Neo.IO.Caching { - internal static class ReflectionCache where T : Enum + internal static class ReflectionCache + where T : Enum { - private static readonly Dictionary dictionary = new(); + private static readonly Dictionary s_dictionary = []; - public static int Count => dictionary.Count; + public static int Count => s_dictionary.Count; static ReflectionCache() { - foreach (FieldInfo field in typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static)) + foreach (var field in typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static)) { // Get attribute - ReflectionCacheAttribute attribute = field.GetCustomAttribute(); + var attribute = field.GetCustomAttribute(); if (attribute == null) continue; // Append to cache - dictionary.Add((T)field.GetValue(null), attribute.Type); + s_dictionary.Add((T)field.GetValue(null), attribute.Type); } } public static object CreateInstance(T key, object def = null) { // Get Type from cache - if (dictionary.TryGetValue(key, out Type t)) + if (s_dictionary.TryGetValue(key, out var t)) return Activator.CreateInstance(t); // return null @@ -46,7 +47,7 @@ public static object CreateInstance(T key, object def = null) public static ISerializable CreateSerializable(T key, ReadOnlyMemory data) { - if (dictionary.TryGetValue(key, out Type t)) + if (s_dictionary.TryGetValue(key, out var t)) return data.AsSerializable(t); return null; } diff --git a/src/Neo/IO/Caching/RelayCache.cs b/src/Neo/IO/Caching/RelayCache.cs index 0f617f4d24..56466d9a7f 100644 --- a/src/Neo/IO/Caching/RelayCache.cs +++ b/src/Neo/IO/Caching/RelayCache.cs @@ -13,13 +13,9 @@ namespace Neo.IO.Caching { - internal class RelayCache : FIFOCache + internal class RelayCache + (int max_capacity) : FIFOCache(max_capacity) { - public RelayCache(int max_capacity) - : base(max_capacity) - { - } - protected override UInt256 GetKeyForItem(IInventory item) { return item.Hash; From 988157973228e73fa7bc30984eb7cd0d9559ffa6 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 5 Jul 2024 04:55:22 -0400 Subject: [PATCH 3/6] Added `BigInteger` to `Neo.Extensions` --- src/Neo.Extensions/BigIntegerExtensions.cs | 66 ++++++++++++++++++++++ src/Neo.Extensions/Neo.Extensions.csproj | 2 +- src/Neo/Cryptography/ECC/ECFieldElement.cs | 1 + src/Neo/Cryptography/ECC/ECPoint.cs | 1 + src/Neo/Helper.cs | 46 --------------- tests/Neo.UnitTests/Neo.UnitTests.csproj | 1 + tests/Neo.UnitTests/UT_Helper.cs | 1 + 7 files changed, 71 insertions(+), 47 deletions(-) create mode 100644 src/Neo.Extensions/BigIntegerExtensions.cs diff --git a/src/Neo.Extensions/BigIntegerExtensions.cs b/src/Neo.Extensions/BigIntegerExtensions.cs new file mode 100644 index 0000000000..9bdcafe15b --- /dev/null +++ b/src/Neo.Extensions/BigIntegerExtensions.cs @@ -0,0 +1,66 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// BigIntegerExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.Extensions +{ + internal static class BigIntegerExtensions + { + internal static int GetLowestSetBit(this BigInteger i) + { + if (i.Sign == 0) + return -1; + var b = i.ToByteArray(); + var w = 0; + while (b[w] == 0) + w++; + for (var x = 0; x < 8; x++) + if ((b[w] & 1 << x) > 0) + return x + w * 8; + throw new Exception(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static BigInteger Mod(this BigInteger x, BigInteger y) + { + x %= y; + if (x.Sign < 0) + x += y; + return x; + } + + internal static BigInteger ModInverse(this BigInteger a, BigInteger n) + { + BigInteger i = n, v = 0, d = 1; + while (a > 0) + { + BigInteger t = i / a, x = a; + a = i % x; + i = x; + x = d; + d = v - t * x; + v = x; + } + v %= n; + if (v < 0) v = (v + n) % n; + return v; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool TestBit(this BigInteger i, int index) + { + return (i & (BigInteger.One << index)) > BigInteger.Zero; + } + } +} diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index a7f4870568..aa79170ddb 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Neo/Cryptography/ECC/ECFieldElement.cs b/src/Neo/Cryptography/ECC/ECFieldElement.cs index 47d8bfa274..d77a8b0451 100644 --- a/src/Neo/Cryptography/ECC/ECFieldElement.cs +++ b/src/Neo/Cryptography/ECC/ECFieldElement.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using System; using System.Numerics; diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index 3b7bdcc885..77d01b90ea 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using Neo.IO.Caching; using System; diff --git a/src/Neo/Helper.cs b/src/Neo/Helper.cs index 00099bc148..a5f28cab2a 100644 --- a/src/Neo/Helper.cs +++ b/src/Neo/Helper.cs @@ -82,20 +82,6 @@ public static byte[] Concat(ReadOnlySpan a, ReadOnlySpan b) return buffer; } - internal static int GetLowestSetBit(this BigInteger i) - { - if (i.Sign == 0) - return -1; - byte[] b = i.ToByteArray(); - int w = 0; - while (b[w] == 0) - w++; - for (int x = 0; x < 8; x++) - if ((b[w] & 1 << x) > 0) - return x + w * 8; - throw new Exception(); - } - internal static void Remove(this HashSet set, ISet other) { if (set.Count > other.Count) @@ -157,32 +143,6 @@ public static byte[] HexToBytes(this string value) return result; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static BigInteger Mod(this BigInteger x, BigInteger y) - { - x %= y; - if (x.Sign < 0) - x += y; - return x; - } - - internal static BigInteger ModInverse(this BigInteger a, BigInteger n) - { - BigInteger i = n, v = 0, d = 1; - while (a > 0) - { - BigInteger t = i / a, x = a; - a = i % x; - i = x; - x = d; - d = v - t * x; - v = x; - } - v %= n; - if (v < 0) v = (v + n) % n; - return v; - } - internal static BigInteger NextBigInteger(this Random rand, int sizeInBits) { if (sizeInBits < 0) @@ -210,12 +170,6 @@ public static BigInteger Sum(this IEnumerable source) return sum; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool TestBit(this BigInteger i, int index) - { - return (i & (BigInteger.One << index)) > BigInteger.Zero; - } - /// /// Converts a to byte array and eliminates all the leading zeros. /// diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index fb246cbdc3..b2e0e03b59 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -19,6 +19,7 @@ + diff --git a/tests/Neo.UnitTests/UT_Helper.cs b/tests/Neo.UnitTests/UT_Helper.cs index b7dc4f1681..3f5ca78c98 100644 --- a/tests/Neo.UnitTests/UT_Helper.cs +++ b/tests/Neo.UnitTests/UT_Helper.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO.Caching; using Neo.Network.P2P; using Neo.SmartContract; From 8779151cf799c542eec9b6a21bafa4c5a0816765 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 5 Jul 2024 05:06:28 -0400 Subject: [PATCH 4/6] Found more `BigInteger` --- src/Neo.Extensions/BigIntegerExtensions.cs | 27 +++++++++++++++++++++- src/Neo.GUI/GUI/MainForm.cs | 1 + src/Neo/Helper.cs | 24 ------------------- src/Neo/SmartContract/StorageItem.cs | 1 + src/Neo/Wallets/Wallet.cs | 1 + 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/Neo.Extensions/BigIntegerExtensions.cs b/src/Neo.Extensions/BigIntegerExtensions.cs index 9bdcafe15b..6856a2a426 100644 --- a/src/Neo.Extensions/BigIntegerExtensions.cs +++ b/src/Neo.Extensions/BigIntegerExtensions.cs @@ -10,12 +10,13 @@ // modifications are permitted. using System; +using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; namespace Neo.Extensions { - internal static class BigIntegerExtensions + public static class BigIntegerExtensions { internal static int GetLowestSetBit(this BigInteger i) { @@ -62,5 +63,29 @@ internal static bool TestBit(this BigInteger i, int index) { return (i & (BigInteger.One << index)) > BigInteger.Zero; } + + /// + /// Finds the sum of the specified integers. + /// + /// The specified integers. + /// The sum of the integers. + public static BigInteger Sum(this IEnumerable source) + { + var sum = BigInteger.Zero; + foreach (var bi in source) sum += bi; + return sum; + } + + /// + /// Converts a to byte array and eliminates all the leading zeros. + /// + /// The to convert. + /// The converted byte array. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] ToByteArrayStandard(this BigInteger i) + { + if (i.IsZero) return Array.Empty(); + return i.ToByteArray(); + } } } diff --git a/src/Neo.GUI/GUI/MainForm.cs b/src/Neo.GUI/GUI/MainForm.cs index 3114e542b6..66d5cc8c0e 100644 --- a/src/Neo.GUI/GUI/MainForm.cs +++ b/src/Neo.GUI/GUI/MainForm.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Akka.Actor; +using Neo.Extensions; using Neo.IO.Actors; using Neo.Ledger; using Neo.Network.P2P.Payloads; diff --git a/src/Neo/Helper.cs b/src/Neo/Helper.cs index a5f28cab2a..7acf69b0e9 100644 --- a/src/Neo/Helper.cs +++ b/src/Neo/Helper.cs @@ -158,30 +158,6 @@ internal static BigInteger NextBigInteger(this Random rand, int sizeInBits) return new BigInteger(b); } - /// - /// Finds the sum of the specified integers. - /// - /// The specified integers. - /// The sum of the integers. - public static BigInteger Sum(this IEnumerable source) - { - var sum = BigInteger.Zero; - foreach (var bi in source) sum += bi; - return sum; - } - - /// - /// Converts a to byte array and eliminates all the leading zeros. - /// - /// The to convert. - /// The converted byte array. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] ToByteArrayStandard(this BigInteger i) - { - if (i.IsZero) return Array.Empty(); - return i.ToByteArray(); - } - /// /// Converts a byte array to hex . /// diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index 133a8fa1dd..61fa62e3c4 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using Neo.VM; using System; diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index aca30b008f..43cfadb9b7 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.Cryptography; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; From b64435bfb5fcd974dbf91fe74c6031bb6fe922af Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 9 Jul 2024 14:14:03 -0400 Subject: [PATCH 5/6] Added Tests --- .github/workflows/main.yml | 2 + neo.sln | 7 +++ src/Neo.Extensions/BigIntegerExtensions.cs | 8 ++-- .../Neo.Extensions.Tests.csproj | 23 +++++++++ .../UT_BigIntegerExtensions.cs | 48 +++++++++++++++++++ tests/Neo.UnitTests/UT_Helper.cs | 10 ---- 6 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj create mode 100644 tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c5f315dd27..d634e15afb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,6 +81,7 @@ jobs: dotnet test ./tests/Neo.UnitTests --output ./bin/tests/Neo.UnitTests dotnet test ./tests/Neo.VM.Tests --output ./bin/tests/Neo.VM.Tests dotnet test ./tests/Neo.Json.UnitTests --output ./bin/tests/Neo.Json.UnitTests + dotnet test ./tests/Neo.Extensions.Tests --output ./bin/tests/Neo.Extensions.Tests # Plugins dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests --output ./bin/tests/Neo.Cryptography.MPTTrie.Tests @@ -105,6 +106,7 @@ jobs: ${{ github.workspace }}/tests/Neo.Plugins.OracleService.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Plugins.RpcServer.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Plugins.Storage.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.Extensions.Tests/TestResults/coverage.info PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/neo.sln b/neo.sln index b0de1c27b1..5d55b0d785 100644 --- a/neo.sln +++ b/neo.sln @@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensTracker", "src\Plugin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\Plugins\RpcClient\RpcClient.csproj", "{185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions.Tests", "tests\Neo.Extensions.Tests\Neo.Extensions.Tests.csproj", "{77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -216,6 +218,10 @@ Global {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.Build.0 = Release|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -255,6 +261,7 @@ Global {FF76D8A4-356B-461A-8471-BC1B83E57BBC} = {C2DC830A-327A-42A7-807D-295216D30DBB} {5E4947F3-05D3-4806-B0F3-30DAC71B5986} = {C2DC830A-327A-42A7-807D-295216D30DBB} {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.Extensions/BigIntegerExtensions.cs b/src/Neo.Extensions/BigIntegerExtensions.cs index 6856a2a426..38a0e60bb5 100644 --- a/src/Neo.Extensions/BigIntegerExtensions.cs +++ b/src/Neo.Extensions/BigIntegerExtensions.cs @@ -18,7 +18,7 @@ namespace Neo.Extensions { public static class BigIntegerExtensions { - internal static int GetLowestSetBit(this BigInteger i) + public static int GetLowestSetBit(this BigInteger i) { if (i.Sign == 0) return -1; @@ -33,7 +33,7 @@ internal static int GetLowestSetBit(this BigInteger i) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static BigInteger Mod(this BigInteger x, BigInteger y) + public static BigInteger Mod(this BigInteger x, BigInteger y) { x %= y; if (x.Sign < 0) @@ -41,7 +41,7 @@ internal static BigInteger Mod(this BigInteger x, BigInteger y) return x; } - internal static BigInteger ModInverse(this BigInteger a, BigInteger n) + public static BigInteger ModInverse(this BigInteger a, BigInteger n) { BigInteger i = n, v = 0, d = 1; while (a > 0) @@ -59,7 +59,7 @@ internal static BigInteger ModInverse(this BigInteger a, BigInteger n) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool TestBit(this BigInteger i, int index) + public static bool TestBit(this BigInteger i, int index) { return (i & (BigInteger.One << index)) > BigInteger.Zero; } diff --git a/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj b/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj new file mode 100644 index 0000000000..a2b2b20daf --- /dev/null +++ b/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + + + + + + + + + + + + + + + + + + diff --git a/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs b/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs new file mode 100644 index 0000000000..574dd87653 --- /dev/null +++ b/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_BigIntegerExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using FluentAssertions; +using Neo.Extensions; +using System.Numerics; + +namespace Neo.Extensions.Tests +{ + [TestClass] + public class UT_BigIntegerExtensions + { + + [TestMethod] + public void TestGetLowestSetBit() + { + var big1 = new BigInteger(0); + big1.GetLowestSetBit().Should().Be(-1); + + var big2 = new BigInteger(512); + big2.GetLowestSetBit().Should().Be(9); + + var big3 = new BigInteger(int.MinValue); + big3.GetLowestSetBit().Should().Be(31); + + var big4 = new BigInteger(long.MinValue); + big4.GetLowestSetBit().Should().Be(63); + } + + [TestMethod] + public void TestToByteArrayStandard() + { + BigInteger number = BigInteger.Zero; + Assert.AreEqual("", number.ToByteArrayStandard().ToHexString()); + + number = BigInteger.One; + Assert.AreEqual("01", number.ToByteArrayStandard().ToHexString()); + } + } +} diff --git a/tests/Neo.UnitTests/UT_Helper.cs b/tests/Neo.UnitTests/UT_Helper.cs index 3f5ca78c98..7fa3902cba 100644 --- a/tests/Neo.UnitTests/UT_Helper.cs +++ b/tests/Neo.UnitTests/UT_Helper.cs @@ -191,16 +191,6 @@ public void TestGetVersion() version.Should().Be("0.0.0"); } - [TestMethod] - public void TestToByteArrayStandard() - { - BigInteger number = BigInteger.Zero; - Assert.AreEqual("", number.ToByteArrayStandard().ToHexString()); - - number = BigInteger.One; - Assert.AreEqual("01", number.ToByteArrayStandard().ToHexString()); - } - [TestMethod] public void TestNextBigIntegerForRandom() { From ee7e3cadbf6af4e022fc3079d7c795f785e3dca6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 16 Jul 2024 00:26:50 -0700 Subject: [PATCH 6/6] Update tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs --- tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs b/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs index 574dd87653..b887d1c973 100644 --- a/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs +++ b/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs @@ -18,7 +18,6 @@ namespace Neo.Extensions.Tests [TestClass] public class UT_BigIntegerExtensions { - [TestMethod] public void TestGetLowestSetBit() {