diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs
index 77fb73f8f8..a3974d5e48 100644
--- a/src/Neo.CLI/CLI/MainService.Plugins.cs
+++ b/src/Neo.CLI/CLI/MainService.Plugins.cs
@@ -80,6 +80,7 @@ private void OnReinstallCommand(string pluginName)
/// Downloaded content
private static async Task DownloadPluginAsync(string pluginName, Version pluginVersion, string? customDownloadUrl = null, bool prerelease = false)
{
+ ConsoleHelper.Info($"Downloading {pluginName} {pluginVersion}...");
using var httpClient = new HttpClient();
var asmName = Assembly.GetExecutingAssembly().GetName();
@@ -104,7 +105,6 @@ private static async Task DownloadPluginAsync(string pluginName, Version
?? throw new Exception($"Could not find {pluginName}");
var downloadUrl = jsonPlugin["browser_download_url"]!.GetValue();
-
return await httpClient.GetStreamAsync(downloadUrl);
}
diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs
index 19ea5d9334..de667bc63d 100644
--- a/src/Neo.CLI/CLI/MainService.cs
+++ b/src/Neo.CLI/CLI/MainService.cs
@@ -33,7 +33,6 @@
using System.Net;
using System.Numerics;
using System.Reflection;
-using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -383,7 +382,7 @@ public async void Start(CommandLineOptions options)
}
catch (DllNotFoundException ex) when (ex.Message.Contains("libleveldb"))
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ if (OperatingSystem.IsWindows())
{
if (File.Exists("libleveldb.dll"))
{
@@ -392,25 +391,32 @@ public async void Start(CommandLineOptions options)
}
else
{
- DisplayError("DLL not found, please get libleveldb.dll.");
+ DisplayError("DLL not found, please get libleveldb.dll.",
+ "Download from https://github.com/neo-ngd/leveldb/releases");
}
}
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ else if (OperatingSystem.IsLinux())
+ {
+ DisplayError("Shared library libleveldb.so not found, please get libleveldb.so.",
+ "Use command \"sudo apt-get install libleveldb-dev\" in terminal or download from https://github.com/neo-ngd/leveldb/releases");
+ }
+ else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst())
{
DisplayError("Shared library libleveldb.dylib not found, please get libleveldb.dylib.",
- "From https://github.com/neo-project/neo/releases");
+ "Use command \"brew install leveldb\" in terminal or download from https://github.com/neo-ngd/leveldb/releases");
}
else
{
DisplayError("Neo CLI is broken, please reinstall it.",
- "From https://github.com/neo-project/neo/releases");
+ "Download from https://github.com/neo-project/neo/releases");
}
-
+ return;
}
catch (DllNotFoundException)
{
DisplayError("Neo CLI is broken, please reinstall it.",
- "From https://github.com/neo-project/neo/releases");
+ "Download from https://github.com/neo-project/neo/releases");
+ return;
}
NeoSystem.AddService(this);
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) });
}
diff --git a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs
index f1f22d99d8..d950d25c62 100644
--- a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs
+++ b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs
@@ -114,7 +114,8 @@ public bool Equals(ContractPermissionDescriptor other)
if (this == other) return true;
if (IsWildcard == other.IsWildcard) return true;
if (IsHash) return Hash.Equals(other.Hash);
- else return Group.Equals(other.Group);
+ if (IsGroup) return Group.Equals(other.Group);
+ return false;
}
public override int GetHashCode()
diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs
index 656ecef725..b2ff30891a 100644
--- a/src/Neo/SmartContract/Native/ContractEventAttribute.cs
+++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs
@@ -17,11 +17,12 @@ namespace Neo.SmartContract.Native
{
[DebuggerDisplay("{Descriptor.Name}")]
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = true)]
- internal class ContractEventAttribute : Attribute
+ internal class ContractEventAttribute : Attribute, IHardforkActivable
{
public int Order { get; init; }
public ContractEventDescriptor Descriptor { get; set; }
public Hardfork? ActiveIn { get; init; } = null;
+ public Hardfork? DeprecatedIn { get; init; } = null;
public ContractEventAttribute(Hardfork activeIn, int order, string name,
string arg1Name, ContractParameterType arg1Value) : this(order, name, arg1Name, arg1Value)
@@ -29,23 +30,35 @@ public ContractEventAttribute(Hardfork activeIn, int order, string name,
ActiveIn = activeIn;
}
+ public ContractEventAttribute(Hardfork activeIn, int order, string name,
+ string arg1Name, ContractParameterType arg1Value, Hardfork deprecatedIn) : this(activeIn, order, name, arg1Name, arg1Value)
+ {
+ DeprecatedIn = deprecatedIn;
+ }
+
public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value)
{
Order = order;
Descriptor = new ContractEventDescriptor()
{
Name = name,
- Parameters = new ContractParameterDefinition[]
- {
+ Parameters =
+ [
new ContractParameterDefinition()
{
Name = arg1Name,
Type = arg1Value
}
- }
+ ]
};
}
+ public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value, Hardfork deprecatedIn)
+ : this(order, name, arg1Name, arg1Value)
+ {
+ DeprecatedIn = deprecatedIn;
+ }
+
public ContractEventAttribute(Hardfork activeIn, int order, string name,
string arg1Name, ContractParameterType arg1Value,
string arg2Name, ContractParameterType arg2Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value)
@@ -53,6 +66,13 @@ public ContractEventAttribute(Hardfork activeIn, int order, string name,
ActiveIn = activeIn;
}
+ public ContractEventAttribute(Hardfork activeIn, int order, string name,
+ string arg1Name, ContractParameterType arg1Value,
+ string arg2Name, ContractParameterType arg2Value, Hardfork deprecatedIn) : this(activeIn, order, name, arg1Name, arg1Value, arg2Name, arg2Value)
+ {
+ DeprecatedIn = deprecatedIn;
+ }
+
public ContractEventAttribute(int order, string name,
string arg1Name, ContractParameterType arg1Value,
string arg2Name, ContractParameterType arg2Value)
@@ -61,8 +81,8 @@ public ContractEventAttribute(int order, string name,
Descriptor = new ContractEventDescriptor()
{
Name = name,
- Parameters = new ContractParameterDefinition[]
- {
+ Parameters =
+ [
new ContractParameterDefinition()
{
Name = arg1Name,
@@ -73,10 +93,18 @@ public ContractEventAttribute(int order, string name,
Name = arg2Name,
Type = arg2Value
}
- }
+ ]
};
}
+ public ContractEventAttribute(int order, string name,
+ string arg1Name, ContractParameterType arg1Value,
+ string arg2Name, ContractParameterType arg2Value, Hardfork deprecatedIn) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value)
+ {
+ DeprecatedIn = deprecatedIn;
+ }
+
+
public ContractEventAttribute(Hardfork activeIn, int order, string name,
string arg1Name, ContractParameterType arg1Value,
string arg2Name, ContractParameterType arg2Value,
@@ -95,8 +123,8 @@ public ContractEventAttribute(int order, string name,
Descriptor = new ContractEventDescriptor()
{
Name = name,
- Parameters = new ContractParameterDefinition[]
- {
+ Parameters =
+ [
new ContractParameterDefinition()
{
Name = arg1Name,
@@ -112,7 +140,7 @@ public ContractEventAttribute(int order, string name,
Name = arg3Name,
Type = arg3Value
}
- }
+ ]
};
}
@@ -136,8 +164,8 @@ public ContractEventAttribute(int order, string name,
Descriptor = new ContractEventDescriptor()
{
Name = name,
- Parameters = new ContractParameterDefinition[]
- {
+ Parameters =
+ [
new ContractParameterDefinition()
{
Name = arg1Name,
@@ -158,7 +186,7 @@ public ContractEventAttribute(int order, string name,
Name = arg4Name,
Type = arg4Value
}
- }
+ ]
};
}
}
diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs
index 7caa27c8b0..38bc065533 100644
--- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs
+++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs
@@ -16,7 +16,7 @@ namespace Neo.SmartContract.Native
{
[DebuggerDisplay("{Name}")]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
- internal class ContractMethodAttribute : Attribute
+ internal class ContractMethodAttribute : Attribute, IHardforkActivable
{
public string Name { get; init; }
public CallFlags RequiredCallFlags { get; init; }
@@ -32,6 +32,11 @@ public ContractMethodAttribute(Hardfork activeIn)
ActiveIn = activeIn;
}
+ public ContractMethodAttribute(Hardfork activeIn, Hardfork deprecatedIn) : this(activeIn)
+ {
+ DeprecatedIn = deprecatedIn;
+ }
+
public ContractMethodAttribute(bool isDeprecated, Hardfork deprecatedIn)
{
if (!isDeprecated) throw new ArgumentException("isDeprecated must be true", nameof(isDeprecated));
diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs
index 30874efb47..fd5a02be6a 100644
--- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs
+++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs
@@ -24,7 +24,7 @@
namespace Neo.SmartContract.Native
{
[DebuggerDisplay("{Name}")]
- internal class ContractMethodMetadata
+ internal class ContractMethodMetadata : IHardforkActivable
{
public string Name { get; }
public MethodInfo Handler { get; }
diff --git a/src/Neo/SmartContract/Native/IHardforkActivable.cs b/src/Neo/SmartContract/Native/IHardforkActivable.cs
new file mode 100644
index 0000000000..7794d03f25
--- /dev/null
+++ b/src/Neo/SmartContract/Native/IHardforkActivable.cs
@@ -0,0 +1,19 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// IHardforkActivable.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.
+
+namespace Neo.SmartContract.Native
+{
+ internal interface IHardforkActivable
+ {
+ public Hardfork? ActiveIn { get; }
+ public Hardfork? DeprecatedIn { get; }
+ }
+}
diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs
index 1cc244408d..b030f06c9b 100644
--- a/src/Neo/SmartContract/Native/NativeContract.cs
+++ b/src/Neo/SmartContract/Native/NativeContract.cs
@@ -161,6 +161,7 @@ protected NativeContract()
_usedHardforks =
_methodDescriptors.Select(u => u.ActiveIn)
.Concat(_methodDescriptors.Select(u => u.DeprecatedIn))
+ .Concat(_eventsDescriptors.Select(u => u.DeprecatedIn))
.Concat(_eventsDescriptors.Select(u => u.ActiveIn))
.Concat([ActiveIn])
.Where(u => u is not null)
@@ -184,15 +185,7 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDeleg
byte[] script;
using (ScriptBuilder sb = new())
{
- foreach (ContractMethodMetadata method in _methodDescriptors.Where(u
- =>
- // no hardfork is involved
- u.ActiveIn is null && u.DeprecatedIn is null ||
- // deprecated method hardfork is involved
- u.DeprecatedIn is not null && hfChecker(u.DeprecatedIn.Value, blockHeight) == false ||
- // active method hardfork is involved
- u.ActiveIn is not null && hfChecker(u.ActiveIn.Value, blockHeight))
- )
+ foreach (ContractMethodMetadata method in _methodDescriptors.Where(u => IsActive(u, hfChecker, blockHeight)))
{
method.Descriptor.Offset = sb.Length;
sb.EmitPush(0); //version
@@ -215,6 +208,16 @@ u.ActiveIn is null && u.DeprecatedIn is null ||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ContractState GetContractState(ProtocolSettings settings, uint blockHeight) => GetContractState(settings.IsHardforkEnabled, blockHeight);
+ internal static bool IsActive(IHardforkActivable u, IsHardforkEnabledDelegate hfChecker, uint blockHeight)
+ {
+ return // no hardfork is involved
+ u.ActiveIn is null && u.DeprecatedIn is null ||
+ // deprecated method hardfork is involved
+ u.DeprecatedIn is not null && hfChecker(u.DeprecatedIn.Value, blockHeight) == false ||
+ // active method hardfork is involved
+ u.ActiveIn is not null && hfChecker(u.ActiveIn.Value, blockHeight);
+ }
+
///
/// The of the native contract.
///
@@ -245,7 +248,7 @@ public ContractState GetContractState(IsHardforkEnabledDelegate hfChecker, uint
Abi = new ContractAbi
{
Events = _eventsDescriptors
- .Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, blockHeight))
+ .Where(u => IsActive(u, hfChecker, blockHeight))
.Select(p => p.Descriptor).ToArray(),
Methods = allowedMethods.Methods.Values
.Select(p => p.Descriptor).ToArray()
diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props
index 72e96f0300..ecd9a2735f 100644
--- a/src/Plugins/Directory.Build.props
+++ b/src/Plugins/Directory.Build.props
@@ -3,11 +3,6 @@
-
-
-
-
-
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs
index 0dee8b0f67..1ef2397d69 100644
--- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs
@@ -11,6 +11,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract.Manifest;
+using Neo.SmartContract.Native;
using Neo.Wallets;
using System.Security.Cryptography;
@@ -44,5 +45,18 @@ public void TestFromAndToJson()
Assert.AreEqual(null, result.Hash);
Assert.AreEqual(result.Group, result.Group);
}
+
+ [TestMethod]
+ public void TestEquals()
+ {
+ var descriptor1 = ContractPermissionDescriptor.CreateWildcard();
+ var descriptor2 = ContractPermissionDescriptor.Create(LedgerContract.NEO.Hash);
+
+ Assert.AreNotEqual(descriptor1, descriptor2);
+
+ var descriptor3 = ContractPermissionDescriptor.Create(LedgerContract.NEO.Hash);
+
+ Assert.AreEqual(descriptor2, descriptor3);
+ }
}
}
diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs
index 1989b4323b..61e6e67f48 100644
--- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs
+++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs
@@ -58,6 +58,28 @@ public void Clean()
TestBlockchain.ResetStore();
}
+ class active : IHardforkActivable
+ {
+ public Hardfork? ActiveIn { get; init; }
+ public Hardfork? DeprecatedIn { get; init; }
+ }
+
+ [TestMethod]
+ public void TestActiveDeprecatedIn()
+ {
+ string json = UT_ProtocolSettings.CreateHKSettings("\"HF_Cockatrice\": 20");
+ var file = Path.GetTempFileName();
+ File.WriteAllText(file, json);
+ ProtocolSettings settings = ProtocolSettings.Load(file, false);
+ File.Delete(file);
+
+ Assert.IsFalse(NativeContract.IsActive(new active() { ActiveIn = Hardfork.HF_Cockatrice, DeprecatedIn = null }, settings.IsHardforkEnabled, 1));
+ Assert.IsTrue(NativeContract.IsActive(new active() { ActiveIn = Hardfork.HF_Cockatrice, DeprecatedIn = null }, settings.IsHardforkEnabled, 20));
+
+ Assert.IsTrue(NativeContract.IsActive(new active() { ActiveIn = null, DeprecatedIn = Hardfork.HF_Cockatrice }, settings.IsHardforkEnabled, 1));
+ Assert.IsFalse(NativeContract.IsActive(new active() { ActiveIn = null, DeprecatedIn = Hardfork.HF_Cockatrice }, settings.IsHardforkEnabled, 20));
+ }
+
[TestMethod]
public void TestGetContract()
{