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 @@ internal class ContractEventAttribute : Attribute 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(int order, string name, string arg1Name, ContractP 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, string arg1Name, ContractP Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, @@ -73,10 +93,18 @@ public ContractEventAttribute(int order, string name, string arg1Name, ContractP 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, string arg1Name, ContractP Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, @@ -112,7 +140,7 @@ public ContractEventAttribute(int order, string name, string arg1Name, ContractP Name = arg3Name, Type = arg3Value } - } + ] }; } @@ -136,8 +164,8 @@ public ContractEventAttribute(int order, string name, string arg1Name, ContractP Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, @@ -158,7 +186,7 @@ public ContractEventAttribute(int order, string name, string arg1Name, ContractP 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 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDeleg [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/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() {