From 4a1f660646a99643a9cac6f176732978328b09c7 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 12:29:59 +0100 Subject: [PATCH 01/21] Allow callstates to use HF --- .../Native/ContractMethodMetadata.cs | 19 +++++++++++-- .../SmartContract/Native/NativeContract.cs | 14 ++++++---- src/Neo/SmartContract/Native/NeoToken.cs | 28 +++++++++++++++++-- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index fd5a02be6a..93b59b3beb 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -26,6 +26,10 @@ namespace Neo.SmartContract.Native [DebuggerDisplay("{Name}")] internal class ContractMethodMetadata : IHardforkActivable { + private readonly CheckCallFlagsDelegate _checkCallFlags; + + public delegate bool CheckCallFlagsDelegate(ContractMethodMetadata sender, ApplicationEngine engine, CallFlags callFlags); + public string Name { get; } public MethodInfo Handler { get; } public InteropParameterDescriptor[] Parameters { get; } @@ -38,7 +42,7 @@ internal class ContractMethodMetadata : IHardforkActivable public Hardfork? ActiveIn { get; init; } = null; public Hardfork? DeprecatedIn { get; init; } = null; - public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) + public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute, CheckCallFlagsDelegate checkCallFlags = null) { Name = attribute.Name ?? member.Name.ToLower()[0] + member.Name[1..]; Handler = member switch @@ -47,7 +51,7 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu PropertyInfo p => p.GetMethod, _ => throw new ArgumentException(null, nameof(member)) }; - ParameterInfo[] parameterInfos = Handler.GetParameters(); + var parameterInfos = Handler.GetParameters(); if (parameterInfos.Length > 0) { NeedApplicationEngine = parameterInfos[0].ParameterType.IsAssignableFrom(typeof(ApplicationEngine)); @@ -60,6 +64,7 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu CpuFee = attribute.CpuFee; StorageFee = attribute.StorageFee; RequiredCallFlags = attribute.RequiredCallFlags; + _checkCallFlags = checkCallFlags ?? DefaultCheckCallFlags; ActiveIn = attribute.ActiveIn; DeprecatedIn = attribute.DeprecatedIn; Descriptor = new ContractMethodDescriptor @@ -71,6 +76,16 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu }; } + public bool CheckCallFlags(ApplicationEngine engine, CallFlags callFlags) + { + return _checkCallFlags(this, engine, callFlags); + } + + private static bool DefaultCheckCallFlags(ContractMethodMetadata sender, ApplicationEngine engine, CallFlags callFlags) + { + return callFlags.HasFlag(sender.RequiredCallFlags); + } + private static ContractParameterType ToParameterType(Type type) { if (type.BaseType == typeof(ContractTask)) return ToParameterType(type.GenericTypeArguments[0]); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 97bb0ab69a..d92cea75de 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -9,7 +9,6 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.IO; using Neo.SmartContract.Manifest; using Neo.VM; using System; @@ -142,9 +141,9 @@ protected NativeContract() List listMethods = []; foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { - ContractMethodAttribute attribute = member.GetCustomAttribute(); + var attribute = member.GetCustomAttribute(); if (attribute is null) continue; - listMethods.Add(new ContractMethodMetadata(member, attribute)); + listMethods.Add(CreateMethodMetadataInternal(member, attribute)); } _methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); @@ -171,6 +170,11 @@ protected NativeContract() s_contractsDictionary.Add(Hash, this); } + internal virtual ContractMethodMetadata CreateMethodMetadataInternal(MemberInfo member, ContractMethodAttribute attribute) + { + return new ContractMethodMetadata(member, attribute); + } + /// /// The allowed methods and his offsets. /// @@ -379,8 +383,8 @@ internal async void Invoke(ApplicationEngine engine, byte version) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); if (method.DeprecatedIn is not null && engine.IsHardforkEnabled(method.DeprecatedIn.Value)) throw new InvalidOperationException($"Cannot call this method after hardfork {method.DeprecatedIn}."); - ExecutionContextState state = context.GetState(); - if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) + var state = context.GetState(); + if (!method.CheckCallFlags(engine, state.CallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); // In the unit of datoshi, 1 datoshi = 1e-8 GAS engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 85309b4246..a351984f78 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -23,6 +23,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Reflection; namespace Neo.SmartContract.Native { @@ -72,6 +73,29 @@ internal NeoToken() : base() TotalAmount = 100000000 * Factor; } + internal override ContractMethodMetadata CreateMethodMetadataInternal(MemberInfo member, ContractMethodAttribute attribute) + { + if (member.Name == nameof(RegisterCandidate) || + member.Name == nameof(UnregisterCandidate)) + { + return new ContractMethodMetadata(member, attribute, RegisterAndUnregisterCallflags); + } + + return base.CreateMethodMetadataInternal(member, attribute); + } + + private static bool RegisterAndUnregisterCallflags(ContractMethodMetadata sender, ApplicationEngine engine, CallFlags callFlags) + { + var requiredCallFlags = sender.RequiredCallFlags; + + if (!engine.IsHardforkEnabled(Hardfork.HF_Echidna)) + { + requiredCallFlags = CallFlags.States; + } + + return callFlags.HasFlag(requiredCallFlags); + } + public override BigInteger TotalSupply(DataCache snapshot) { return TotalAmount; @@ -327,7 +351,7 @@ public BigInteger UnclaimedGas(DataCache snapshot, UInt160 account, uint end) return CalculateBonus(snapshot, state, end); } - [ContractMethod(RequiredCallFlags = CallFlags.States)] + [ContractMethod(RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) @@ -344,7 +368,7 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) return true; } - [ContractMethod(CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] + [ContractMethod(CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) From 6f31b4e2849fc124f91755f0b1feb47d19f4439c Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 12:33:00 +0100 Subject: [PATCH 02/21] Rename to method --- src/Neo/SmartContract/Native/ContractMethodMetadata.cs | 4 ++-- src/Neo/SmartContract/Native/NeoToken.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 93b59b3beb..3d19655313 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -81,9 +81,9 @@ public bool CheckCallFlags(ApplicationEngine engine, CallFlags callFlags) return _checkCallFlags(this, engine, callFlags); } - private static bool DefaultCheckCallFlags(ContractMethodMetadata sender, ApplicationEngine engine, CallFlags callFlags) + private static bool DefaultCheckCallFlags(ContractMethodMetadata method, ApplicationEngine engine, CallFlags callFlags) { - return callFlags.HasFlag(sender.RequiredCallFlags); + return callFlags.HasFlag(method.RequiredCallFlags); } private static ContractParameterType ToParameterType(Type type) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index a351984f78..e3b9ccd53a 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -84,9 +84,9 @@ internal override ContractMethodMetadata CreateMethodMetadataInternal(MemberInfo return base.CreateMethodMetadataInternal(member, attribute); } - private static bool RegisterAndUnregisterCallflags(ContractMethodMetadata sender, ApplicationEngine engine, CallFlags callFlags) + private static bool RegisterAndUnregisterCallflags(ContractMethodMetadata method, ApplicationEngine engine, CallFlags callFlags) { - var requiredCallFlags = sender.RequiredCallFlags; + var requiredCallFlags = method.RequiredCallFlags; if (!engine.IsHardforkEnabled(Hardfork.HF_Echidna)) { From a60bdac0969fa86da762b59dccf20cc827ad03ff Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 12:34:08 +0100 Subject: [PATCH 03/21] Other rename --- src/Neo/SmartContract/Native/ContractMethodMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 3d19655313..5d1a33c89b 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -28,7 +28,7 @@ internal class ContractMethodMetadata : IHardforkActivable { private readonly CheckCallFlagsDelegate _checkCallFlags; - public delegate bool CheckCallFlagsDelegate(ContractMethodMetadata sender, ApplicationEngine engine, CallFlags callFlags); + public delegate bool CheckCallFlagsDelegate(ContractMethodMetadata method, ApplicationEngine engine, CallFlags callFlags); public string Name { get; } public MethodInfo Handler { get; } From 6fa19aa861f8e8d48f45693ee06f67b9ccc60df6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 14:51:00 +0100 Subject: [PATCH 04/21] Change the way --- .../Native/ContractMethodMetadata.cs | 17 +------ .../SmartContract/Native/NativeContract.cs | 9 +--- src/Neo/SmartContract/Native/NeoToken.cs | 48 ++++++++----------- 3 files changed, 24 insertions(+), 50 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 5d1a33c89b..638dd9193a 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -26,10 +26,6 @@ namespace Neo.SmartContract.Native [DebuggerDisplay("{Name}")] internal class ContractMethodMetadata : IHardforkActivable { - private readonly CheckCallFlagsDelegate _checkCallFlags; - - public delegate bool CheckCallFlagsDelegate(ContractMethodMetadata method, ApplicationEngine engine, CallFlags callFlags); - public string Name { get; } public MethodInfo Handler { get; } public InteropParameterDescriptor[] Parameters { get; } @@ -42,7 +38,7 @@ internal class ContractMethodMetadata : IHardforkActivable public Hardfork? ActiveIn { get; init; } = null; public Hardfork? DeprecatedIn { get; init; } = null; - public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute, CheckCallFlagsDelegate checkCallFlags = null) + public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { Name = attribute.Name ?? member.Name.ToLower()[0] + member.Name[1..]; Handler = member switch @@ -64,7 +60,6 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu CpuFee = attribute.CpuFee; StorageFee = attribute.StorageFee; RequiredCallFlags = attribute.RequiredCallFlags; - _checkCallFlags = checkCallFlags ?? DefaultCheckCallFlags; ActiveIn = attribute.ActiveIn; DeprecatedIn = attribute.DeprecatedIn; Descriptor = new ContractMethodDescriptor @@ -76,16 +71,6 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu }; } - public bool CheckCallFlags(ApplicationEngine engine, CallFlags callFlags) - { - return _checkCallFlags(this, engine, callFlags); - } - - private static bool DefaultCheckCallFlags(ContractMethodMetadata method, ApplicationEngine engine, CallFlags callFlags) - { - return callFlags.HasFlag(method.RequiredCallFlags); - } - private static ContractParameterType ToParameterType(Type type) { if (type.BaseType == typeof(ContractTask)) return ToParameterType(type.GenericTypeArguments[0]); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index d92cea75de..0a3e98b10b 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -143,7 +143,7 @@ protected NativeContract() { var attribute = member.GetCustomAttribute(); if (attribute is null) continue; - listMethods.Add(CreateMethodMetadataInternal(member, attribute)); + listMethods.Add(new ContractMethodMetadata(member, attribute)); } _methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); @@ -170,11 +170,6 @@ protected NativeContract() s_contractsDictionary.Add(Hash, this); } - internal virtual ContractMethodMetadata CreateMethodMetadataInternal(MemberInfo member, ContractMethodAttribute attribute) - { - return new ContractMethodMetadata(member, attribute); - } - /// /// The allowed methods and his offsets. /// @@ -384,7 +379,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) if (method.DeprecatedIn is not null && engine.IsHardforkEnabled(method.DeprecatedIn.Value)) throw new InvalidOperationException($"Cannot call this method after hardfork {method.DeprecatedIn}."); var state = context.GetState(); - if (!method.CheckCallFlags(engine, state.CallFlags)) + if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); // In the unit of datoshi, 1 datoshi = 1e-8 GAS engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index e3b9ccd53a..66d6b1b1dc 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -23,7 +23,6 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Reflection; namespace Neo.SmartContract.Native { @@ -73,29 +72,6 @@ internal NeoToken() : base() TotalAmount = 100000000 * Factor; } - internal override ContractMethodMetadata CreateMethodMetadataInternal(MemberInfo member, ContractMethodAttribute attribute) - { - if (member.Name == nameof(RegisterCandidate) || - member.Name == nameof(UnregisterCandidate)) - { - return new ContractMethodMetadata(member, attribute, RegisterAndUnregisterCallflags); - } - - return base.CreateMethodMetadataInternal(member, attribute); - } - - private static bool RegisterAndUnregisterCallflags(ContractMethodMetadata method, ApplicationEngine engine, CallFlags callFlags) - { - var requiredCallFlags = method.RequiredCallFlags; - - if (!engine.IsHardforkEnabled(Hardfork.HF_Echidna)) - { - requiredCallFlags = CallFlags.States; - } - - return callFlags.HasFlag(requiredCallFlags); - } - public override BigInteger TotalSupply(DataCache snapshot) { return TotalAmount; @@ -351,7 +327,13 @@ public BigInteger UnclaimedGas(DataCache snapshot, UInt160 account, uint end) return CalculateBonus(snapshot, state, end); } - [ContractMethod(RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(RegisterCandidate), RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + private bool OldRegisterCandidate(ApplicationEngine engine, ECPoint pubkey) + { + return RegisterCandidate(engine, pubkey); + } + + [ContractMethod(Hardfork.HF_Echidna, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) @@ -368,7 +350,13 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) return true; } - [ContractMethod(CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(UnregisterCandidate), CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] + private bool OldUnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) + { + return UnregisterCandidate(engine, pubkey); + } + + [ContractMethod(Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) @@ -385,7 +373,13 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) return true; } - [ContractMethod(CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] + [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(Vote), CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] + private async ContractTask OldVote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) + { + return await Vote(engine, account, voteTo); + } + + [ContractMethod(Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private async ContractTask Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) { if (!engine.CheckWitnessInternal(account)) return false; From 66804ddb1cee7430b75906d70238842fb4719ba6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 14:51:38 +0100 Subject: [PATCH 05/21] Reduce changes --- src/Neo/SmartContract/Native/ContractMethodMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 638dd9193a..fd5a02be6a 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -47,7 +47,7 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu PropertyInfo p => p.GetMethod, _ => throw new ArgumentException(null, nameof(member)) }; - var parameterInfos = Handler.GetParameters(); + ParameterInfo[] parameterInfos = Handler.GetParameters(); if (parameterInfos.Length > 0) { NeedApplicationEngine = parameterInfos[0].ParameterType.IsAssignableFrom(typeof(ApplicationEngine)); From 4bced571e667ff4423f7c9793db40d98021b93c6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 14:52:46 +0100 Subject: [PATCH 06/21] Reduce changes --- src/Neo/SmartContract/Native/NativeContract.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 0a3e98b10b..97bb0ab69a 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.IO; using Neo.SmartContract.Manifest; using Neo.VM; using System; @@ -141,7 +142,7 @@ protected NativeContract() List listMethods = []; foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { - var attribute = member.GetCustomAttribute(); + ContractMethodAttribute attribute = member.GetCustomAttribute(); if (attribute is null) continue; listMethods.Add(new ContractMethodMetadata(member, attribute)); } @@ -378,7 +379,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); if (method.DeprecatedIn is not null && engine.IsHardforkEnabled(method.DeprecatedIn.Value)) throw new InvalidOperationException($"Cannot call this method after hardfork {method.DeprecatedIn}."); - var state = context.GetState(); + ExecutionContextState state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); // In the unit of datoshi, 1 datoshi = 1e-8 GAS From 2d760c145dbd407cce8adeae69602c89718834cd Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 14:54:36 +0100 Subject: [PATCH 07/21] Adapt name always --- src/Neo/SmartContract/Native/ContractMethodMetadata.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index fd5a02be6a..8e8bec132a 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -40,7 +40,8 @@ internal class ContractMethodMetadata : IHardforkActivable public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { - Name = attribute.Name ?? member.Name.ToLower()[0] + member.Name[1..]; + Name = attribute.Name ?? member.Name; + Name = Name.ToLower()[0] + Name[1..]; Handler = member switch { MethodInfo m => m, From 4eb75bcca9169bc00c0e9d13397a442277425e6f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 14:56:25 +0100 Subject: [PATCH 08/21] Avoid string when only is lower the first char --- src/Neo/SmartContract/Native/CryptoLib.cs | 2 +- src/Neo/SmartContract/Native/LedgerContract.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index 9027298752..9ee46d9490 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -100,7 +100,7 @@ public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signatu } // This is for solving the hardfork issue in https://github.com/neo-project/neo/pull/3209 - [ContractMethod(true, Hardfork.HF_Cockatrice, CpuFee = 1 << 15, Name = "verifyWithECDsa")] + [ContractMethod(true, Hardfork.HF_Cockatrice, CpuFee = 1 << 15, Name = nameof(VerifyWithECDsa))] public static bool VerifyWithECDsaV0(byte[] message, byte[] pubkey, byte[] signature, NamedCurveHash curve) { if (curve != NamedCurveHash.secp256k1SHA256 && curve != NamedCurveHash.secp256r1SHA256) diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index 3d2d16e023..feb2801280 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -278,7 +278,7 @@ public Transaction GetTransaction(DataCache snapshot, UInt256 hash) return GetTransactionState(snapshot, hash)?.Transaction; } - [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates, Name = "getTransaction")] + [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates, Name = nameof(GetTransaction))] private Transaction GetTransactionForContract(ApplicationEngine engine, UInt256 hash) { TransactionState state = GetTransactionState(engine.SnapshotCache, hash); From a989f9cf414f2adf7f3a73eb70dd690aca7a64a7 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 16:12:49 +0100 Subject: [PATCH 09/21] UT --- src/Neo/ProtocolSettings.cs | 19 ++++++++- .../SmartContract/Native/NativeContract.cs | 16 +++++--- .../SmartContract/Native/UT_NeoToken.cs | 41 +++++++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 19011dc24c..c5b2bbcff1 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -15,6 +15,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; namespace Neo @@ -123,6 +124,20 @@ public record ProtocolSettings public static ProtocolSettings Custom { get; set; } + /// + /// Loads the at the specified path. + /// + /// The stream of the settings. + /// The loaded . + public static ProtocolSettings Load(Stream stream) + { + var config = new ConfigurationBuilder().AddJsonStream(stream).Build(); + var section = config.GetSection("ProtocolConfiguration"); + var settings = Load(section); + CheckingHardfork(settings); + return settings; + } + /// /// Loads the at the specified path. /// @@ -131,8 +146,8 @@ public record ProtocolSettings /// The loaded . public static ProtocolSettings Load(string path, bool optional = true) { - IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile(path, optional).Build(); - IConfigurationSection section = config.GetSection("ProtocolConfiguration"); + var config = new ConfigurationBuilder().AddJsonFile(path, optional).Build(); + var section = config.GetSection("ProtocolConfiguration"); var settings = Load(section); CheckingHardfork(settings); return settings; diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 97bb0ab69a..3c570805bc 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -363,6 +363,13 @@ public static NativeContract GetContract(UInt160 hash) return contract; } + internal Dictionary GetContractMethods(ApplicationEngine engine) + { + var nativeContracts = engine.GetState(() => new NativeContractsCache()); + var currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine); + return currentAllowedMethods.Methods; + } + internal async void Invoke(ApplicationEngine engine, byte version) { try @@ -370,16 +377,15 @@ internal async void Invoke(ApplicationEngine engine, byte version) if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); // Get native contracts invocation cache - NativeContractsCache nativeContracts = engine.GetState(() => new NativeContractsCache()); - NativeContractsCache.CacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine); + var currentAllowedMethods = GetContractMethods(engine); // Check if the method is allowed - ExecutionContext context = engine.CurrentContext; - ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; + var context = engine.CurrentContext; + var method = currentAllowedMethods[context.InstructionPointer]; if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); if (method.DeprecatedIn is not null && engine.IsHardforkEnabled(method.DeprecatedIn.Value)) throw new InvalidOperationException($"Cannot call this method after hardfork {method.DeprecatedIn}."); - ExecutionContextState state = context.GetState(); + var state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); // In the unit of datoshi, 1 datoshi = 1e-8 GAS diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 2ff07d5a69..8b4b949c9a 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -22,8 +22,11 @@ using Neo.VM; using Neo.Wallets; using System; +using System.IO; using System.Linq; using System.Numerics; +using System.Security.Principal; +using System.Text; using static Neo.SmartContract.Native.NeoToken; namespace Neo.UnitTests.SmartContract.Native @@ -54,6 +57,44 @@ public void TestSetup() [TestMethod] public void Check_Decimals() => NativeContract.NEO.Decimals(_snapshotCache).Should().Be(0); + [TestMethod] + public void Test_HF_Echidna() + { + string json = UT_ProtocolSettings.CreateHFSettings("\"HF_Echidna\": 10"); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var settings = ProtocolSettings.Load(stream); + + var clonedCache = _snapshotCache.CloneCache(); + + // Test WITHOUT HF_Echidna + + var persistingBlock = new Block { Header = new Header { Index = 9 } }; + + using (var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), clonedCache, persistingBlock, settings: settings)) + { + var methods = NativeContract.NEO.GetContractMethods(engine); + var vote = methods.Values.Where(u => u.Name == "vote").ToArray(); + + Assert.AreEqual(vote.Length, 1); + Assert.AreEqual(vote[0].RequiredCallFlags, CallFlags.States); + } + + // Test WITH HF_Echidna + + persistingBlock.Header.Index = 10; + + using (var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), clonedCache, persistingBlock, settings: settings)) + { + var methods = NativeContract.NEO.GetContractMethods(engine); + var vote = methods.Values.Where(u => u.Name == "vote").ToArray(); + + Assert.AreEqual(vote.Length, 1); + Assert.AreEqual(vote[0].RequiredCallFlags, CallFlags.States | CallFlags.AllowNotify); + } + } + [TestMethod] public void Check_Vote() { From f8601469f48fc6f0453f00c268cb349591b422ab Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 26 Nov 2024 16:19:40 +0100 Subject: [PATCH 10/21] Test all --- src/Neo/SmartContract/Native/NeoToken.cs | 2 +- .../SmartContract/Native/UT_NeoToken.cs | 44 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 66d6b1b1dc..cab8501a36 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -327,7 +327,7 @@ public BigInteger UnclaimedGas(DataCache snapshot, UInt160 account, uint end) return CalculateBonus(snapshot, state, end); } - [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(RegisterCandidate), RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(RegisterCandidate), RequiredCallFlags = CallFlags.States)] private bool OldRegisterCandidate(ApplicationEngine engine, ECPoint pubkey) { return RegisterCandidate(engine, pubkey); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 8b4b949c9a..c5f889a252 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -58,40 +58,44 @@ public void TestSetup() public void Check_Decimals() => NativeContract.NEO.Decimals(_snapshotCache).Should().Be(0); [TestMethod] - public void Test_HF_Echidna() + public void Test_HF_EchidnaStates() { string json = UT_ProtocolSettings.CreateHFSettings("\"HF_Echidna\": 10"); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); var settings = ProtocolSettings.Load(stream); var clonedCache = _snapshotCache.CloneCache(); + var persistingBlock = new Block { Header = new Header() }; - // Test WITHOUT HF_Echidna + foreach (var method in new string[] { "vote", "registerCandidate", "unregisterCandidate" }) + { + // Test WITHOUT HF_Echidna - var persistingBlock = new Block { Header = new Header { Index = 9 } }; + persistingBlock.Header.Index = 9; - using (var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), clonedCache, persistingBlock, settings: settings)) - { - var methods = NativeContract.NEO.GetContractMethods(engine); - var vote = methods.Values.Where(u => u.Name == "vote").ToArray(); + using (var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), clonedCache, persistingBlock, settings: settings)) + { + var methods = NativeContract.NEO.GetContractMethods(engine); + var entries = methods.Values.Where(u => u.Name == method).ToArray(); - Assert.AreEqual(vote.Length, 1); - Assert.AreEqual(vote[0].RequiredCallFlags, CallFlags.States); - } + Assert.AreEqual(entries.Length, 1); + Assert.AreEqual(entries[0].RequiredCallFlags, CallFlags.States); + } - // Test WITH HF_Echidna + // Test WITH HF_Echidna - persistingBlock.Header.Index = 10; + persistingBlock.Header.Index = 10; - using (var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), clonedCache, persistingBlock, settings: settings)) - { - var methods = NativeContract.NEO.GetContractMethods(engine); - var vote = methods.Values.Where(u => u.Name == "vote").ToArray(); + using (var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), clonedCache, persistingBlock, settings: settings)) + { + var methods = NativeContract.NEO.GetContractMethods(engine); + var entries = methods.Values.Where(u => u.Name == method).ToArray(); - Assert.AreEqual(vote.Length, 1); - Assert.AreEqual(vote[0].RequiredCallFlags, CallFlags.States | CallFlags.AllowNotify); + Assert.AreEqual(entries.Length, 1); + Assert.AreEqual(entries[0].RequiredCallFlags, CallFlags.States | CallFlags.AllowNotify); + } } } From 68f3fddde26801fc5c66d78779d88a657903ce36 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 26 Nov 2024 23:46:29 +0100 Subject: [PATCH 11/21] Update src/Neo/ProtocolSettings.cs Co-authored-by: Christopher Schuchardt --- src/Neo/ProtocolSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index c5b2bbcff1..c00d4728c3 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -131,7 +131,7 @@ public record ProtocolSettings /// The loaded . public static ProtocolSettings Load(Stream stream) { - var config = new ConfigurationBuilder().AddJsonStream(stream).Build(); + using var config = new ConfigurationBuilder().AddJsonStream(stream).Build(); var section = config.GetSection("ProtocolConfiguration"); var settings = Load(section); CheckingHardfork(settings); From 9bebffe14770b7dcbe34c705afd306767fa5aeaa Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 26 Nov 2024 23:46:43 +0100 Subject: [PATCH 12/21] Update src/Neo/ProtocolSettings.cs Co-authored-by: Christopher Schuchardt --- src/Neo/ProtocolSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index c00d4728c3..d5c914c7ce 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -146,7 +146,7 @@ public static ProtocolSettings Load(Stream stream) /// The loaded . public static ProtocolSettings Load(string path, bool optional = true) { - var config = new ConfigurationBuilder().AddJsonFile(path, optional).Build(); + using var config = new ConfigurationBuilder().AddJsonFile(path, optional).Build(); var section = config.GetSection("ProtocolConfiguration"); var settings = Load(section); CheckingHardfork(settings); From 2dd5e29c291743a76b2110102231a43891edfdc5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Nov 2024 08:54:13 +0100 Subject: [PATCH 13/21] Reuse Load from stream --- src/Neo/ProtocolSettings.cs | 47 +++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index d5c914c7ce..45f58c7ad7 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -125,13 +125,13 @@ public record ProtocolSettings public static ProtocolSettings Custom { get; set; } /// - /// Loads the at the specified path. + /// Loads the from the specified stream. /// /// The stream of the settings. /// The loaded . public static ProtocolSettings Load(Stream stream) { - using var config = new ConfigurationBuilder().AddJsonStream(stream).Build(); + var config = new ConfigurationBuilder().AddJsonStream(stream).Build(); var section = config.GetSection("ProtocolConfiguration"); var settings = Load(section); CheckingHardfork(settings); @@ -146,11 +146,21 @@ public static ProtocolSettings Load(Stream stream) /// The loaded . public static ProtocolSettings Load(string path, bool optional = true) { - using var config = new ConfigurationBuilder().AddJsonFile(path, optional).Build(); - var section = config.GetSection("ProtocolConfiguration"); - var settings = Load(section); - CheckingHardfork(settings); - return settings; + if (!File.Exists(path)) + { + if (optional) + { + // Same as default + return Load(Default); + } + else + { + throw new FileNotFoundException(path); + } + } + + using var stream = File.OpenRead(path); + return Load(stream); } /// @@ -183,6 +193,29 @@ public static ProtocolSettings Load(IConfigurationSection section) return Custom; } + /// + /// Loads the cloning another . + /// + /// The to be cloned. + /// The loaded . + public static ProtocolSettings Load(ProtocolSettings settings) + { + return Custom = new ProtocolSettings + { + Network = settings.Network, + AddressVersion = settings.AddressVersion, + StandbyCommittee = [.. settings.StandbyCommittee], // Clone + ValidatorsCount = settings.ValidatorsCount, + SeedList = [.. settings.SeedList], // Clone + MillisecondsPerBlock = settings.MillisecondsPerBlock, + MaxTransactionsPerBlock = settings.MaxTransactionsPerBlock, + MemoryPoolMaxTransactions = settings.MemoryPoolMaxTransactions, + MaxTraceableBlocks = settings.MaxTraceableBlocks, + InitialGasDistribution = settings.InitialGasDistribution, + Hardforks = settings.Hardforks // Already immutable + }; + } + /// /// Explicitly set the height of all old omitted hardforks to 0 for proper IsHardforkEnabled behaviour. /// From 6c7c89a6a6ecd2250e45b0bfc3313e0c82399afa Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Nov 2024 08:55:57 +0100 Subject: [PATCH 14/21] Unify --- src/Neo/ProtocolSettings.cs | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 45f58c7ad7..ea8a0c428d 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -150,8 +150,10 @@ public static ProtocolSettings Load(string path, bool optional = true) { if (optional) { - // Same as default - return Load(Default); + // Load with default values + var configuration = new ConfigurationBuilder().Build(); + var emptySection = configuration.GetSection("EmptySection"); + return Load(emptySection); } else { @@ -193,29 +195,6 @@ public static ProtocolSettings Load(IConfigurationSection section) return Custom; } - /// - /// Loads the cloning another . - /// - /// The to be cloned. - /// The loaded . - public static ProtocolSettings Load(ProtocolSettings settings) - { - return Custom = new ProtocolSettings - { - Network = settings.Network, - AddressVersion = settings.AddressVersion, - StandbyCommittee = [.. settings.StandbyCommittee], // Clone - ValidatorsCount = settings.ValidatorsCount, - SeedList = [.. settings.SeedList], // Clone - MillisecondsPerBlock = settings.MillisecondsPerBlock, - MaxTransactionsPerBlock = settings.MaxTransactionsPerBlock, - MemoryPoolMaxTransactions = settings.MemoryPoolMaxTransactions, - MaxTraceableBlocks = settings.MaxTraceableBlocks, - InitialGasDistribution = settings.InitialGasDistribution, - Hardforks = settings.Hardforks // Already immutable - }; - } - /// /// Explicitly set the height of all old omitted hardforks to 0 for proper IsHardforkEnabled behaviour. /// From c6db2164d16b3f3aabba54f7468ed424fb2ea962 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Nov 2024 08:56:49 +0100 Subject: [PATCH 15/21] Fix default logic --- src/Neo/ProtocolSettings.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index ea8a0c428d..8a251c6b2b 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -17,6 +17,7 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using static System.Collections.Specialized.BitVector32; namespace Neo { @@ -152,8 +153,10 @@ public static ProtocolSettings Load(string path, bool optional = true) { // Load with default values var configuration = new ConfigurationBuilder().Build(); - var emptySection = configuration.GetSection("EmptySection"); - return Load(emptySection); + var section = configuration.GetSection("EmptySection"); + var settings = Load(section); + CheckingHardfork(settings); + return settings; } else { From dad7e0df1460c26d8e98ccaccec14c1280aed2cd Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Nov 2024 09:00:05 +0100 Subject: [PATCH 16/21] Change ContractMethod to allowMultiple --- .../Native/ContractMethodAttribute.cs | 3 ++- src/Neo/SmartContract/Native/NeoToken.cs | 27 +++++-------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index 38bc065533..c13329a206 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -15,7 +15,8 @@ namespace Neo.SmartContract.Native { [DebuggerDisplay("{Name}")] - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)] + // We allow multiple attributes because the fees or requiredCallFlags may change between hard forks. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] internal class ContractMethodAttribute : Attribute, IHardforkActivable { public string Name { get; init; } diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index cab8501a36..37f1ee78a0 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -327,13 +327,8 @@ public BigInteger UnclaimedGas(DataCache snapshot, UInt160 account, uint end) return CalculateBonus(snapshot, state, end); } - [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(RegisterCandidate), RequiredCallFlags = CallFlags.States)] - private bool OldRegisterCandidate(ApplicationEngine engine, ECPoint pubkey) - { - return RegisterCandidate(engine, pubkey); - } - - [ContractMethod(Hardfork.HF_Echidna, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + [ContractMethod(true, Hardfork.HF_Echidna, RequiredCallFlags = CallFlags.States)] + [ContractMethod(Hardfork.HF_Echidna, /* */ RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) @@ -350,13 +345,8 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) return true; } - [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(UnregisterCandidate), CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] - private bool OldUnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) - { - return UnregisterCandidate(engine, pubkey); - } - - [ContractMethod(Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + [ContractMethod(true, Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] + [ContractMethod(Hardfork.HF_Echidna, /* */ CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) @@ -373,13 +363,8 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) return true; } - [ContractMethod(true, Hardfork.HF_Echidna, Name = nameof(Vote), CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] - private async ContractTask OldVote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) - { - return await Vote(engine, account, voteTo); - } - - [ContractMethod(Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] + [ContractMethod(true, Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)] + [ContractMethod(Hardfork.HF_Echidna, /* */ CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] private async ContractTask Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) { if (!engine.CheckWitnessInternal(account)) return false; From ca9ddadd9116054196a0f2ca613f757ce7be238b Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Nov 2024 09:02:08 +0100 Subject: [PATCH 17/21] Use LowerInvariant --- src/Neo/SmartContract/Native/ContractMethodMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 8e8bec132a..58b67fbf01 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -41,7 +41,7 @@ internal class ContractMethodMetadata : IHardforkActivable public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { Name = attribute.Name ?? member.Name; - Name = Name.ToLower()[0] + Name[1..]; + Name = Name.ToLowerInvariant()[0] + Name[1..]; Handler = member switch { MethodInfo m => m, From 753b66bc1186a48a1d98eb175ff7bebe926b3d6e Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Nov 2024 09:05:18 +0100 Subject: [PATCH 18/21] Move CheckingHardfork --- src/Neo/ProtocolSettings.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 8a251c6b2b..eefe938865 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -134,9 +134,7 @@ public static ProtocolSettings Load(Stream stream) { var config = new ConfigurationBuilder().AddJsonStream(stream).Build(); var section = config.GetSection("ProtocolConfiguration"); - var settings = Load(section); - CheckingHardfork(settings); - return settings; + return Load(section); } /// @@ -154,9 +152,7 @@ public static ProtocolSettings Load(string path, bool optional = true) // Load with default values var configuration = new ConfigurationBuilder().Build(); var section = configuration.GetSection("EmptySection"); - var settings = Load(section); - CheckingHardfork(settings); - return settings; + return Load(section); } else { @@ -195,6 +191,7 @@ public static ProtocolSettings Load(IConfigurationSection section) ? EnsureOmmitedHardforks(section.GetSection("Hardforks").GetChildren().ToDictionary(p => Enum.Parse(p.Key, true), p => uint.Parse(p.Value))).ToImmutableDictionary() : Default.Hardforks }; + CheckingHardfork(Custom); return Custom; } From 21444f043499ec352ecb5e9cab81607854d8d6a3 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 1 Dec 2024 14:21:30 +0100 Subject: [PATCH 19/21] Remove optional arg --- src/Neo/ProtocolSettings.cs | 16 ++-------------- .../SmartContract/Native/UT_NativeContract.cs | 6 +++--- tests/Neo.UnitTests/UT_ProtocolSettings.cs | 10 +++++----- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index eefe938865..5a8fa0bb5b 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -17,7 +17,6 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using static System.Collections.Specialized.BitVector32; namespace Neo { @@ -141,23 +140,12 @@ public static ProtocolSettings Load(Stream stream) /// Loads the at the specified path. /// /// The path of the settings file. - /// Indicates whether the file is optional. /// The loaded . - public static ProtocolSettings Load(string path, bool optional = true) + public static ProtocolSettings Load(string path) { if (!File.Exists(path)) { - if (optional) - { - // Load with default values - var configuration = new ConfigurationBuilder().Build(); - var section = configuration.GetSection("EmptySection"); - return Load(section); - } - else - { - throw new FileNotFoundException(path); - } + throw new FileNotFoundException(path); } using var stream = File.OpenRead(path); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 5de9448013..291d6d2529 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -70,7 +70,7 @@ public void TestActiveDeprecatedIn() string json = UT_ProtocolSettings.CreateHFSettings("\"HF_Cockatrice\": 20"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); - ProtocolSettings settings = ProtocolSettings.Load(file, false); + ProtocolSettings settings = ProtocolSettings.Load(file); File.Delete(file); Assert.IsFalse(NativeContract.IsActive(new active() { ActiveIn = Hardfork.HF_Cockatrice, DeprecatedIn = null }, settings.IsHardforkEnabled, 1)); @@ -86,7 +86,7 @@ public void TestActiveDeprecatedInRoleManagement() string json = UT_ProtocolSettings.CreateHFSettings("\"HF_Echidna\": 20"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); - ProtocolSettings settings = ProtocolSettings.Load(file, false); + ProtocolSettings settings = ProtocolSettings.Load(file); File.Delete(file); var before = NativeContract.RoleManagement.GetContractState(settings.IsHardforkEnabled, 19); @@ -111,7 +111,7 @@ public void TestIsInitializeBlock() var file = Path.GetTempFileName(); File.WriteAllText(file, json); - ProtocolSettings settings = ProtocolSettings.Load(file, false); + ProtocolSettings settings = ProtocolSettings.Load(file); File.Delete(file); Assert.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 0, out var hf)); diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 97a36e5907..757ca5f174 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -56,7 +56,7 @@ public void HardForkTestBAndNotA() var file = Path.GetTempFileName(); File.WriteAllText(file, json); - ProtocolSettings settings = ProtocolSettings.Load(file, false); + ProtocolSettings settings = ProtocolSettings.Load(file); File.Delete(file); settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); @@ -78,7 +78,7 @@ public void HardForkTestAAndNotB() var file = Path.GetTempFileName(); File.WriteAllText(file, json); - ProtocolSettings settings = ProtocolSettings.Load(file, false); + ProtocolSettings settings = ProtocolSettings.Load(file); File.Delete(file); settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); @@ -100,7 +100,7 @@ public void HardForkTestNone() var file = Path.GetTempFileName(); File.WriteAllText(file, json); - ProtocolSettings settings = ProtocolSettings.Load(file, false); + ProtocolSettings settings = ProtocolSettings.Load(file); File.Delete(file); settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); @@ -120,7 +120,7 @@ public void HardForkTestAMoreThanB() string json = CreateHFSettings("\"HF_Aspidochelone\": 4120001, \"HF_Basilisk\": 4120000"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); - Assert.ThrowsException(() => ProtocolSettings.Load(file, false)); + Assert.ThrowsException(() => ProtocolSettings.Load(file)); File.Delete(file); } @@ -316,7 +316,7 @@ public void TestTimePerBlockCalculation() [TestMethod] public void TestLoad() { - var loadedSetting = ProtocolSettings.Load("test.config.json", false); + var loadedSetting = ProtocolSettings.Load("test.config.json"); // Comparing all properties TestProtocolSettings.Default.Network.Should().Be(loadedSetting.Network); From 01ef2269acb66ad67c7ce86158d1ea4c749156a5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 1 Dec 2024 14:41:05 +0100 Subject: [PATCH 20/21] Fix build --- src/Neo/SmartContract/Native/NativeContract.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 3c570805bc..8b355464c9 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -140,11 +140,12 @@ protected NativeContract() // Reflection to get the methods List listMethods = []; - foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) + foreach (var member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { - ContractMethodAttribute attribute = member.GetCustomAttribute(); - if (attribute is null) continue; - listMethods.Add(new ContractMethodMetadata(member, attribute)); + foreach (var attribute in member.GetCustomAttributes()) + { + listMethods.Add(new ContractMethodMetadata(member, attribute)); + } } _methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); From 9432a2a7175662747fd3c18391a6a98e7f175df7 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 3 Dec 2024 09:55:31 +0100 Subject: [PATCH 21/21] Avoid file not found error --- src/Neo/ProtocolSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 5a8fa0bb5b..cef7ef6de1 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -145,7 +145,7 @@ public static ProtocolSettings Load(string path) { if (!File.Exists(path)) { - throw new FileNotFoundException(path); + return Default; } using var stream = File.OpenRead(path);