From 24b181f34cf03de9e6fe4fe906c3ffcef23960ef Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 13:35:50 +0100 Subject: [PATCH 01/44] Update manifest --- src/Neo/ProtocolSettings.cs | 34 +++++ src/Neo/SmartContract/ApplicationEngine.cs | 24 +--- .../Native/ContractEventAttribute.cs | 134 ++++++++++++++++++ .../Native/ContractManagement.cs | 81 ++++------- .../Native/ContractMethodAttribute.cs | 3 + .../Native/ContractMethodMetadata.cs | 4 + src/Neo/SmartContract/Native/FungibleToken.cs | 40 ++---- .../SmartContract/Native/LedgerContract.cs | 4 +- .../SmartContract/Native/NativeContract.cs | 107 ++++++++++---- src/Neo/SmartContract/Native/NeoToken.cs | 67 ++------- .../SmartContract/Native/OracleContract.cs | 62 ++------ .../SmartContract/Native/PolicyContract.cs | 4 +- .../SmartContract/Native/RoleManagement.cs | 31 +--- src/Neo/SmartContract/Native/StdLib.cs | 3 +- src/Neo/SmartContract/StorageItem.cs | 10 ++ 15 files changed, 330 insertions(+), 278 deletions(-) create mode 100644 src/Neo/SmartContract/Native/ContractEventAttribute.cs diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index f1e4e01b11..69f3934fcd 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -23,6 +23,8 @@ namespace Neo /// public record ProtocolSettings { + private static readonly IList AllHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToArray(); + /// /// The magic number of the NEO network. /// @@ -220,5 +222,37 @@ private static void CheckingHardfork(ProtocolSettings settings) } } } + + /// + /// Check if the Hardfork is Enabled + /// + /// Hardfork + /// Block index + /// True if enabled + public bool IsHardforkEnabled(Hardfork hardfork, uint index) + { + // Return true if there's no specific configuration or PersistingBlock is null + if (Hardforks.Count == 0) + return true; + + // If the hardfork isn't specified in the configuration, check if it's a new one. + if (!Hardforks.ContainsKey(hardfork)) + { + int currentHardforkIndex = AllHardforks.IndexOf(hardfork); + int lastConfiguredHardforkIndex = AllHardforks.IndexOf(Hardforks.Keys.Last()); + + // If it's a newer hardfork compared to the ones in the configuration, disable it. + if (currentHardforkIndex > lastConfiguredHardforkIndex) + return false; + } + + if (Hardforks.TryGetValue(hardfork, out uint height)) + { + // If the hardfork has a specific height in the configuration, check the block height. + return index >= height; + } + // If no specific conditions are met, return true. + return true; + } } } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index a67b622200..925389bdaa 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -46,7 +46,6 @@ public partial class ApplicationEngine : ExecutionEngine /// public static event EventHandler Log; - private static readonly IList AllHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToArray(); private static Dictionary services; private readonly long gas_amount; private Dictionary states; @@ -613,28 +612,11 @@ public void SetState(T state) public bool IsHardforkEnabled(Hardfork hardfork) { - // Return true if there's no specific configuration or PersistingBlock is null - if (PersistingBlock is null || ProtocolSettings.Hardforks.Count == 0) + // Return true if PersistingBlock is null + if (PersistingBlock is null ) return true; - // If the hardfork isn't specified in the configuration, check if it's a new one. - if (!ProtocolSettings.Hardforks.ContainsKey(hardfork)) - { - int currentHardforkIndex = AllHardforks.IndexOf(hardfork); - int lastConfiguredHardforkIndex = AllHardforks.IndexOf(ProtocolSettings.Hardforks.Keys.Last()); - - // If it's a newer hardfork compared to the ones in the configuration, disable it. - if (currentHardforkIndex > lastConfiguredHardforkIndex) - return false; - } - - if (ProtocolSettings.Hardforks.TryGetValue(hardfork, out uint height)) - { - // If the hardfork has a specific height in the configuration, check the block height. - return PersistingBlock.Index >= height; - } - // If no specific conditions are met, return true. - return true; + return ProtocolSettings.IsHardforkEnabled(hardfork, PersistingBlock.Index); } } } diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs new file mode 100644 index 0000000000..f3940f50e3 --- /dev/null +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -0,0 +1,134 @@ +// Copyright (C) 2015-2022 The Neo Project. +// +// The neo is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Diagnostics; +using Neo.SmartContract.Manifest; + +namespace Neo.SmartContract.Native +{ + [DebuggerDisplay("{Descriptor.Name}")] + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = true)] + internal class ContractEventAttribute : Attribute + { + public int Order { get; init; } + public ContractEventDescriptor Descriptor { get; set; } + public Hardfork? ActiveIn { get; init; } = null; + + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + } + } + }; + } + + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + }, + new ContractParameterDefinition() + { + Name = arg2Name, + Type = arg2Value + } + } + }; + } + + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value + ) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + }, + new ContractParameterDefinition() + { + Name = arg2Name, + Type = arg2Value + }, + new ContractParameterDefinition() + { + Name = arg3Name, + Type = arg3Value + } + } + }; + } + + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value, + string arg4Name, ContractParameterType arg4Value + ) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + }, + new ContractParameterDefinition() + { + Name = arg2Name, + Type = arg2Value + }, + new ContractParameterDefinition() + { + Name = arg3Name, + Type = arg3Value + }, + new ContractParameterDefinition() + { + Name = arg4Name, + Type = arg4Value + } + } + }; + } + } +} diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 62e9bb366d..9c5d816c95 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -10,17 +10,17 @@ #pragma warning disable IDE0051 +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; using Neo.VM.Types; -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; namespace Neo.SmartContract.Native { @@ -34,50 +34,10 @@ public sealed class ContractManagement : NativeContract private const byte Prefix_Contract = 8; private const byte Prefix_ContractHash = 12; - internal ContractManagement() - { - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "Deploy", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Hash", - Type = ContractParameterType.Hash160 - } - } - }, - new ContractEventDescriptor - { - Name = "Update", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Hash", - Type = ContractParameterType.Hash160 - } - } - }, - new ContractEventDescriptor - { - Name = "Destroy", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Hash", - Type = ContractParameterType.Hash160 - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); - } + [ContractEvent(0, name: "Deploy", "Hash", ContractParameterType.Hash160)] + [ContractEvent(1, name: "Update", "Hash", ContractParameterType.Hash160)] + [ContractEvent(2, name: "Destroy", "Hash", ContractParameterType.Hash160)] + internal ContractManagement() : base() { } private int GetNextAvailableId(DataCache snapshot) { @@ -108,14 +68,23 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) { if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index)) { - engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState + ContractState contractState = contract.GetContractState(engine.ProtocolSettings, engine.PersistingBlock.Index); + StorageItem state = engine.Snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(contract.Hash)); + + if (state is null) { - Id = contract.Id, - Nef = contract.Nef, - Hash = contract.Hash, - Manifest = contract.Manifest - })); - engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); + // Create the contract state + engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(contractState)); + engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); + } + else + { + // Increase the update counter + contractState.UpdateCounter = (ushort)(state.GetInteroperable().UpdateCounter + 1); + // Update the contract state + state.Set(contractState); + } + await contract.Initialize(engine); } } diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index c4f12ed229..d9989127b5 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -9,9 +9,11 @@ // modifications are permitted. using System; +using System.Diagnostics; namespace Neo.SmartContract.Native { + [DebuggerDisplay("{Name}")] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)] internal class ContractMethodAttribute : Attribute { @@ -19,5 +21,6 @@ internal class ContractMethodAttribute : Attribute public CallFlags RequiredCallFlags { get; init; } public long CpuFee { get; init; } public long StorageFee { get; init; } + public Hardfork? ActiveIn { get; init; } = null; } } diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index e0b342aea1..03d42166b5 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -14,6 +14,7 @@ using Neo.SmartContract.Manifest; using Neo.VM.Types; using System; +using System.Diagnostics; using System.Linq; using System.Numerics; using System.Reflection; @@ -21,6 +22,7 @@ namespace Neo.SmartContract.Native { + [DebuggerDisplay("{Name}")] internal class ContractMethodMetadata { public string Name { get; } @@ -32,6 +34,7 @@ internal class ContractMethodMetadata public long StorageFee { get; } public CallFlags RequiredCallFlags { get; } public ContractMethodDescriptor Descriptor { get; } + public Hardfork? ActiveIn { get; init; } = null; public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { @@ -55,6 +58,7 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu this.CpuFee = attribute.CpuFee; this.StorageFee = attribute.StorageFee; this.RequiredCallFlags = attribute.RequiredCallFlags; + this.ActiveIn = attribute.ActiveIn; this.Descriptor = new ContractMethodDescriptor { Name = Name, diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 068011fad4..9312b3aaba 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -13,7 +13,6 @@ using Neo.SmartContract.Manifest; using Neo.VM.Types; using System; -using System.Collections.Generic; using System.Numerics; using Array = Neo.VM.Types.Array; @@ -56,39 +55,18 @@ public abstract class FungibleToken : NativeContract /// /// Initializes a new instance of the class. /// - protected FungibleToken() + [ContractEvent(0, name: "Transfer", + "from", ContractParameterType.Hash160, + "to", ContractParameterType.Hash160, + "amount", ContractParameterType.Integer)] + protected FungibleToken() : base() { this.Factor = BigInteger.Pow(10, Decimals); + } - Manifest.SupportedStandards = new[] { "NEP-17" }; - - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "Transfer", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "from", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "to", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "amount", - Type = ContractParameterType.Integer - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); + protected override void OnManifestCompose(ContractManifest manifest, ProtocolSettings settings, uint index) + { + manifest.SupportedStandards = new[] { "NEP-17" }; } internal async ContractTask Mint(ApplicationEngine engine, UInt160 account, BigInteger amount, bool callOnPayment) diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index cd405c098b..4058271c01 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -31,9 +31,7 @@ public sealed class LedgerContract : NativeContract private const byte Prefix_Block = 5; private const byte Prefix_Transaction = 11; - internal LedgerContract() - { - } + internal LedgerContract() : base() { } internal override ContractTask OnPersist(ApplicationEngine engine) { diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 8c8ffe986f..51c4456945 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -13,6 +13,8 @@ using Neo.VM; using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.Linq; using System.Reflection; @@ -26,6 +28,9 @@ public abstract class NativeContract private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); private readonly Dictionary methods = new(); + private readonly ImmutableHashSet listenHardforks; + private readonly ReadOnlyCollection methodDescriptors; + private readonly ReadOnlyCollection eventsDescriptors; private static int id_counter = 0; #region Named Native Contracts @@ -92,11 +97,6 @@ public abstract class NativeContract /// public virtual Hardfork? ActiveIn { get; } = null; - /// - /// The nef of the native contract. - /// - public NefFile Nef { get; } - /// /// The hash of the native contract. /// @@ -107,28 +107,56 @@ public abstract class NativeContract /// public int Id { get; } = --id_counter; - /// - /// The manifest of the native contract. - /// - public ContractManifest Manifest { get; } - /// /// Initializes a new instance of the class. /// protected NativeContract() { - List descriptors = new(); + this.Hash = Helper.GetContractHash(UInt160.Zero, 0, Name); + + // Reflection to get the methods + + List listMethods = new(); foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { ContractMethodAttribute attribute = member.GetCustomAttribute(); if (attribute is null) continue; - descriptors.Add(new ContractMethodMetadata(member, attribute)); + listMethods.Add(new ContractMethodMetadata(member, attribute)); } - descriptors = descriptors.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList(); + methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); + + // Reflection to get the events + eventsDescriptors = + GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty())?. + GetCustomAttributes(). + OrderBy(p => p.Order).ToList().AsReadOnly(); + + // Calculate the initializations forks + listenHardforks = + methodDescriptors.Select(u => u.ActiveIn) + .Concat(eventsDescriptors.Select(u => u.ActiveIn)) + .Concat(new Hardfork?[] { ActiveIn }) + .Where(u => u is not null) + .Cast().ToImmutableHashSet(); + + contractsList.Add(this); + contractsDictionary.Add(Hash, this); + } + + /// + /// The of the native contract. + /// + /// The where the HardForks are configured. + /// Block index + /// The . + public ContractState GetContractState(ProtocolSettings settings, uint index) + { + // Reflection to get the ContractMethods + byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in descriptors) + foreach (ContractMethodMetadata method in methodDescriptors) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version @@ -138,33 +166,54 @@ protected NativeContract() } script = sb.ToArray(); } - this.Nef = new NefFile + + // Compose nef file + + NefFile nef = new() { Compiler = "neo-core-v3.0", Source = string.Empty, Tokens = Array.Empty(), Script = script }; - this.Nef.CheckSum = NefFile.ComputeChecksum(Nef); - this.Hash = Helper.GetContractHash(UInt160.Zero, 0, Name); - this.Manifest = new ContractManifest + nef.CheckSum = NefFile.ComputeChecksum(nef); + + // Compose manifest + + ContractManifest manifest = new() { Name = Name, Groups = Array.Empty(), SupportedStandards = Array.Empty(), Abi = new ContractAbi() { - Events = Array.Empty(), - Methods = descriptors.Select(p => p.Descriptor).ToArray() + Events = eventsDescriptors + .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) + .Select(p => p.Descriptor).ToArray(), + Methods = methodDescriptors + .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) + .Select(p => p.Descriptor).ToArray() }, Permissions = new[] { ContractPermission.DefaultPermission }, Trusts = WildcardContainer.Create(), Extra = null }; - contractsList.Add(this); - contractsDictionary.Add(Hash, this); + + OnManifestCompose(manifest, settings, index); + + // Return ContractState + + return new ContractState + { + Id = Id, + Nef = nef, + Hash = Hash, + Manifest = manifest + }; } + protected virtual void OnManifestCompose(ContractManifest manifest, ProtocolSettings settings, uint index) { } + /// /// It is the initialize block /// @@ -173,14 +222,20 @@ protected NativeContract() /// True if the native contract must be initialized internal bool IsInitializeBlock(ProtocolSettings settings, uint index) { + // If is not configured, the Genesis is the a initialized block if (ActiveIn is null) return index == 0; - if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn)) + // If is in the hardfork height, return true + foreach (Hardfork hf in listenHardforks) { - return false; + if (settings.Hardforks.TryGetValue(hf, out var activeIn)) + { + return activeIn == index; + } } - return activeIn == index; + // Initialized not required + return false; } /// @@ -236,6 +291,8 @@ internal async void Invoke(ApplicationEngine engine, byte version) throw new InvalidOperationException($"The native contract of version {version} is not active."); ExecutionContext context = engine.CurrentContext; ContractMethodMetadata method = methods[context.InstructionPointer]; + if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) + throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); ExecutionContextState state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 74fe70db37..db5c49a0f0 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -19,7 +19,6 @@ using Neo.IO; using Neo.Persistence; using Neo.SmartContract.Iterators; -using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; @@ -54,64 +53,18 @@ public sealed class NeoToken : FungibleToken private const byte CommitteeRewardRatio = 10; private const byte VoterRewardRatio = 80; - internal NeoToken() + [ContractEvent(1, name: "CandidateStateChanged", + "pubkey", ContractParameterType.PublicKey, + "registered", ContractParameterType.Boolean, + "votes", ContractParameterType.Integer)] + [ContractEvent(2, name: "Vote", + "account", ContractParameterType.Hash160, + "from", ContractParameterType.PublicKey, + "to", ContractParameterType.PublicKey, + "amount", ContractParameterType.Integer)] + internal NeoToken() : base() { this.TotalAmount = 100000000 * Factor; - - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "CandidateStateChanged", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "pubkey", - Type = ContractParameterType.PublicKey - }, - new ContractParameterDefinition() - { - Name = "registered", - Type = ContractParameterType.Boolean - }, - new ContractParameterDefinition() - { - Name = "votes", - Type = ContractParameterType.Integer - } - } - }, - new ContractEventDescriptor - { - Name = "Vote", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "account", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "from", - Type = ContractParameterType.PublicKey - }, - new ContractParameterDefinition() - { - Name = "to", - Type = ContractParameterType.PublicKey - }, - new ContractParameterDefinition() - { - Name = "amount", - Type = ContractParameterType.Integer - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); } public override BigInteger TotalSupply(DataCache snapshot) diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index df35bd98e8..ab333f1830 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -14,7 +14,6 @@ using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; using System; @@ -40,58 +39,15 @@ public sealed class OracleContract : NativeContract private const byte Prefix_Request = 7; private const byte Prefix_IdList = 6; - internal OracleContract() - { - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "OracleRequest", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Id", - Type = ContractParameterType.Integer - }, - new ContractParameterDefinition() - { - Name = "RequestContract", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "Url", - Type = ContractParameterType.String - }, - new ContractParameterDefinition() - { - Name = "Filter", - Type = ContractParameterType.String - } - } - }, - new ContractEventDescriptor - { - Name = "OracleResponse", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Id", - Type = ContractParameterType.Integer - }, - new ContractParameterDefinition() - { - Name = "OriginalTx", - Type = ContractParameterType.Hash256 - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); - } + [ContractEvent(0, name: "OracleRequest", + "Id", ContractParameterType.Integer, + "RequestContract", ContractParameterType.Hash160, + "Url", ContractParameterType.String, + "Filter", ContractParameterType.String)] + [ContractEvent(1, name: "OracleResponse", + "Id", ContractParameterType.Integer, + "OriginalTx", ContractParameterType.Hash256)] + internal OracleContract() : base() { } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] private void SetPrice(ApplicationEngine engine, long price) diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index c754a15a93..6df1c8dfb5 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -63,9 +63,7 @@ public sealed class PolicyContract : NativeContract private const byte Prefix_StoragePrice = 19; private const byte Prefix_AttributeFee = 20; - internal PolicyContract() - { - } + internal PolicyContract() : base() { } internal override ContractTask Initialize(ApplicationEngine engine) { diff --git a/src/Neo/SmartContract/Native/RoleManagement.cs b/src/Neo/SmartContract/Native/RoleManagement.cs index 5a32f10f32..948bec7a19 100644 --- a/src/Neo/SmartContract/Native/RoleManagement.cs +++ b/src/Neo/SmartContract/Native/RoleManagement.cs @@ -11,11 +11,9 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.Persistence; -using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; using System; -using System.Collections.Generic; using System.Linq; namespace Neo.SmartContract.Native @@ -25,31 +23,10 @@ namespace Neo.SmartContract.Native /// public sealed class RoleManagement : NativeContract { - internal RoleManagement() - { - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "Designation", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Role", - Type = ContractParameterType.Integer - }, - new ContractParameterDefinition() - { - Name = "BlockIndex", - Type = ContractParameterType.Integer - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); - } + [ContractEvent(0, name: "Designation", + "Role", ContractParameterType.Integer, + "BlockIndex", ContractParameterType.Integer)] + internal RoleManagement() : base() { } /// /// Gets the list of nodes for the specified role. diff --git a/src/Neo/SmartContract/Native/StdLib.cs b/src/Neo/SmartContract/Native/StdLib.cs index cb540d36a1..bffc902862 100644 --- a/src/Neo/SmartContract/Native/StdLib.cs +++ b/src/Neo/SmartContract/Native/StdLib.cs @@ -16,7 +16,6 @@ using System; using System.Globalization; using System.Numerics; -using System.Text; namespace Neo.SmartContract.Native { @@ -27,7 +26,7 @@ public sealed class StdLib : NativeContract { private const int MaxInputLength = 1024; - internal StdLib() { } + internal StdLib() : base() { } [ContractMethod(CpuFee = 1 << 12)] private static byte[] Serialize(ApplicationEngine engine, StackItem item) diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index b8cfa179e6..dd9e590db4 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -159,6 +159,16 @@ public void Set(BigInteger integer) value = null; } + /// + /// Sets the interoperable value of the storage. + /// + /// The value of the . + public void Set(IInteroperable interoperable) + { + cache = interoperable; + value = null; + } + public static implicit operator BigInteger(StorageItem item) { item.cache ??= new BigInteger(item.value.Span); From 3c6a1f06d553e69adf707ccc423dc1378e09cff8 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 13:37:18 +0100 Subject: [PATCH 02/44] Fix comment --- 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 69f3934fcd..3e9ef5b28d 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -231,7 +231,7 @@ private static void CheckingHardfork(ProtocolSettings settings) /// True if enabled public bool IsHardforkEnabled(Hardfork hardfork, uint index) { - // Return true if there's no specific configuration or PersistingBlock is null + // Return true if there's no specific configuration if (Hardforks.Count == 0) return true; From a5772bcf8917032aac9e9a81179d4ea62fb289cb Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 13:54:56 +0100 Subject: [PATCH 03/44] Format & fix methods --- src/Neo/SmartContract/ApplicationEngine.cs | 2 +- src/Neo/SmartContract/Native/NativeContract.cs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 925389bdaa..67cff166ab 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -613,7 +613,7 @@ public void SetState(T state) public bool IsHardforkEnabled(Hardfork hardfork) { // Return true if PersistingBlock is null - if (PersistingBlock is null ) + if (PersistingBlock is null) return true; return ProtocolSettings.IsHardforkEnabled(hardfork, PersistingBlock.Index); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 51c4456945..5407d5ee84 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -27,7 +27,7 @@ public abstract class NativeContract { private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); - private readonly Dictionary methods = new(); + private readonly Dictionary currentAllowedMethods; private readonly ImmutableHashSet listenHardforks; private readonly ReadOnlyCollection methodDescriptors; private readonly ReadOnlyCollection eventsDescriptors; @@ -149,10 +149,12 @@ protected NativeContract() /// The where the HardForks are configured. /// Block index /// The . - public ContractState GetContractState(ProtocolSettings settings, uint index) + internal ContractState GetContractState(ProtocolSettings settings, uint index) { - // Reflection to get the ContractMethods + // Methods that are allowed to be called are cached from the last time GetContractState was called, the last time it was initialized + currentAllowedMethods.Clear(); + // Reflection to get the ContractMethods byte[] script; using (ScriptBuilder sb = new()) { @@ -160,7 +162,7 @@ public ContractState GetContractState(ProtocolSettings settings, uint index) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version - methods.Add(sb.Length, method); + currentAllowedMethods.Add(sb.Length, method); sb.EmitSysCall(ApplicationEngine.System_Contract_CallNative); sb.Emit(OpCode.RET); } @@ -168,7 +170,6 @@ public ContractState GetContractState(ProtocolSettings settings, uint index) } // Compose nef file - NefFile nef = new() { Compiler = "neo-core-v3.0", @@ -179,7 +180,6 @@ public ContractState GetContractState(ProtocolSettings settings, uint index) nef.CheckSum = NefFile.ComputeChecksum(nef); // Compose manifest - ContractManifest manifest = new() { Name = Name, @@ -202,7 +202,6 @@ public ContractState GetContractState(ProtocolSettings settings, uint index) OnManifestCompose(manifest, settings, index); // Return ContractState - return new ContractState { Id = Id, @@ -290,7 +289,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); ExecutionContext context = engine.CurrentContext; - ContractMethodMetadata method = methods[context.InstructionPointer]; + ContractMethodMetadata 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}."); ExecutionContextState state = context.GetState(); From 95335e0ae31f798a7f5bcfd5904ad21d7c7f8779 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 13:58:01 +0100 Subject: [PATCH 04/44] Fix new --- src/Neo/SmartContract/Native/NativeContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 5407d5ee84..4491ec4bbc 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -27,7 +27,7 @@ public abstract class NativeContract { private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); - private readonly Dictionary currentAllowedMethods; + private readonly Dictionary currentAllowedMethods = new(); private readonly ImmutableHashSet listenHardforks; private readonly ReadOnlyCollection methodDescriptors; private readonly ReadOnlyCollection eventsDescriptors; From 7ae51e1b6972ddcbbb9001bf441cc639ffff0b0a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 14:53:16 +0100 Subject: [PATCH 05/44] Initialize storage fixes --- .../Native/ContractManagement.cs | 13 +++++++----- src/Neo/SmartContract/Native/GasToken.cs | 10 +++++++--- .../SmartContract/Native/NativeContract.cs | 14 ++++++++++--- src/Neo/SmartContract/Native/NeoToken.cs | 20 +++++++++++-------- .../SmartContract/Native/OracleContract.cs | 9 ++++++--- .../SmartContract/Native/PolicyContract.cs | 11 ++++++---- 6 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 9c5d816c95..156f0b15e3 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -47,10 +47,13 @@ private int GetNextAvailableId(DataCache snapshot) return value; } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); - engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); + if (hardfork is null) + { + engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); + engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); + } return ContractTask.CompletedTask; } @@ -66,7 +69,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) { foreach (NativeContract contract in Contracts) { - if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index)) + if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index, out Hardfork? hf)) { ContractState contractState = contract.GetContractState(engine.ProtocolSettings, engine.PersistingBlock.Index); StorageItem state = engine.Snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(contract.Hash)); @@ -85,7 +88,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) state.Set(contractState); } - await contract.Initialize(engine); + await contract.Initialize(engine, hf); } } } diff --git a/src/Neo/SmartContract/Native/GasToken.cs b/src/Neo/SmartContract/Native/GasToken.cs index a791c891b8..e5b02d2ece 100644 --- a/src/Neo/SmartContract/Native/GasToken.cs +++ b/src/Neo/SmartContract/Native/GasToken.cs @@ -25,10 +25,14 @@ internal GasToken() { } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - UInt160 account = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); - return Mint(engine, account, engine.ProtocolSettings.InitialGasDistribution, false); + if (hardfork is null) + { + UInt160 account = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); + return Mint(engine, account, engine.ProtocolSettings.InitialGasDistribution, false); + } + return ContractTask.CompletedTask; } internal override async ContractTask OnPersist(ApplicationEngine engine) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 4491ec4bbc..65a3a6f715 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -137,6 +137,7 @@ protected NativeContract() .Concat(eventsDescriptors.Select(u => u.ActiveIn)) .Concat(new Hardfork?[] { ActiveIn }) .Where(u => u is not null) + .OrderBy(u => (byte)u) .Cast().ToImmutableHashSet(); contractsList.Add(this); @@ -218,22 +219,29 @@ protected virtual void OnManifestCompose(ContractManifest manifest, ProtocolSett /// /// The where the HardForks are configured. /// Block index + /// Active hardfork /// True if the native contract must be initialized - internal bool IsInitializeBlock(ProtocolSettings settings, uint index) + internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardfork? hardfork) { // If is not configured, the Genesis is the a initialized block - if (ActiveIn is null) return index == 0; + if (ActiveIn is null) + { + hardfork = null; + return index == 0; + } // If is in the hardfork height, return true foreach (Hardfork hf in listenHardforks) { if (settings.Hardforks.TryGetValue(hf, out var activeIn)) { + hardfork = hf; return activeIn == index; } } // Initialized not required + hardfork = null; return false; } @@ -332,7 +340,7 @@ public static bool IsNative(UInt160 hash) return contractsDictionary.ContainsKey(hash); } - internal virtual ContractTask Initialize(ApplicationEngine engine) + internal virtual ContractTask Initialize(ApplicationEngine engine, Hardfork? hardFork) { return ContractTask.CompletedTask; } diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index db5c49a0f0..7d3361d333 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -172,14 +172,18 @@ private void CheckCandidate(DataCache snapshot, ECPoint pubkey, CandidateState c /// if the votes should be recounted; otherwise, . public static bool ShouldRefreshCommittee(uint height, int committeeMembersCount) => height % committeeMembersCount == 0; - internal override ContractTask Initialize(ApplicationEngine engine) - { - var cachedCommittee = new CachedCommittee(engine.ProtocolSettings.StandbyCommittee.Select(p => (p, BigInteger.Zero))); - engine.Snapshot.Add(CreateStorageKey(Prefix_Committee), new StorageItem(cachedCommittee)); - engine.Snapshot.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(System.Array.Empty())); - engine.Snapshot.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(0u), new StorageItem(5 * GAS.Factor)); - engine.Snapshot.Add(CreateStorageKey(Prefix_RegisterPrice), new StorageItem(1000 * GAS.Factor)); - return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) + { + if (hardfork is null) + { + var cachedCommittee = new CachedCommittee(engine.ProtocolSettings.StandbyCommittee.Select(p => (p, BigInteger.Zero))); + engine.Snapshot.Add(CreateStorageKey(Prefix_Committee), new StorageItem(cachedCommittee)); + engine.Snapshot.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(System.Array.Empty())); + engine.Snapshot.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(0u), new StorageItem(5 * GAS.Factor)); + engine.Snapshot.Add(CreateStorageKey(Prefix_RegisterPrice), new StorageItem(1000 * GAS.Factor)); + return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); + } + return ContractTask.CompletedTask; } internal override ContractTask OnPersist(ApplicationEngine engine) diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index ab333f1830..97371143a0 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -133,10 +133,13 @@ private static byte[] GetUrlHash(string url) return Crypto.Hash160(Utility.StrictUTF8.GetBytes(url)); } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - engine.Snapshot.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); - engine.Snapshot.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); + if (hardfork is null) + { + engine.Snapshot.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); + engine.Snapshot.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); + } return ContractTask.CompletedTask; } diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 6df1c8dfb5..d21c89b833 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -65,11 +65,14 @@ public sealed class PolicyContract : NativeContract internal PolicyContract() : base() { } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - engine.Snapshot.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(DefaultFeePerByte)); - engine.Snapshot.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor)); - engine.Snapshot.Add(CreateStorageKey(Prefix_StoragePrice), new StorageItem(DefaultStoragePrice)); + if (hardfork is null) + { + engine.Snapshot.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(DefaultFeePerByte)); + engine.Snapshot.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor)); + engine.Snapshot.Add(CreateStorageKey(Prefix_StoragePrice), new StorageItem(DefaultStoragePrice)); + } return ContractTask.CompletedTask; } From 22d72b5af0f1e4e4b2a0cad32bb6db009b4fef82 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 15:03:40 +0100 Subject: [PATCH 06/44] Fix IsInitializeBlock --- src/Neo/SmartContract/Native/NativeContract.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 65a3a6f715..c0295888ff 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -233,10 +233,10 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardf // If is in the hardfork height, return true foreach (Hardfork hf in listenHardforks) { - if (settings.Hardforks.TryGetValue(hf, out var activeIn)) + if (settings.Hardforks.TryGetValue(hf, out var activeIn) && activeIn == index) { hardfork = hf; - return activeIn == index; + return true; } } From c7602c6254a7b023c019155a7e409e87a1a7eed4 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 15:05:52 +0100 Subject: [PATCH 07/44] Fix update --- src/Neo/SmartContract/Native/NativeContract.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index c0295888ff..231489d78b 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -224,10 +224,10 @@ protected virtual void OnManifestCompose(ContractManifest manifest, ProtocolSett internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardfork? hardfork) { // If is not configured, the Genesis is the a initialized block - if (ActiveIn is null) + if (index == 0 && ActiveIn is null) { hardfork = null; - return index == 0; + return true; } // If is in the hardfork height, return true From b573a0085d965aca04d14fbbd71ec1d4d74582ed Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 15:08:06 +0100 Subject: [PATCH 08/44] Fix GetContractState --- src/Neo/SmartContract/Native/NativeContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 231489d78b..8f51418f9f 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -159,7 +159,7 @@ internal ContractState GetContractState(ProtocolSettings settings, uint index) byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in methodDescriptors) + foreach (ContractMethodMetadata method in methodDescriptors.Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index))) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version From 3adddd2af814460f0f19d56426ac981f47729d6c Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 15:14:31 +0100 Subject: [PATCH 09/44] Optimize --- src/Neo/SmartContract/Native/NativeContract.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 8f51418f9f..0b0a03966a 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -191,8 +191,7 @@ internal ContractState GetContractState(ProtocolSettings settings, uint index) Events = eventsDescriptors .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) .Select(p => p.Descriptor).ToArray(), - Methods = methodDescriptors - .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) + Methods = currentAllowedMethods.Values .Select(p => p.Descriptor).ToArray() }, Permissions = new[] { ContractPermission.DefaultPermission }, From 984d3d71b1929d6f02d3c184a8597608009baaab Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 5 Nov 2023 18:42:43 +0100 Subject: [PATCH 10/44] Fix first invoke without sync --- src/Neo/SmartContract/Native/NativeContract.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 0b0a03966a..81983d691e 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -296,6 +296,12 @@ internal async void Invoke(ApplicationEngine engine, byte version) if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); ExecutionContext context = engine.CurrentContext; + if (currentAllowedMethods.Count == 0) + { + // First call we need to cache it + uint index = engine.PersistingBlock is not null ? engine.PersistingBlock.Index : Ledger.CurrentIndex(engine.Snapshot); + _ = GetContractState(engine.ProtocolSettings, index); + } ContractMethodMetadata 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}."); From 6341bad02a39b2dd533f45e86324faa88dcbf1ef Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 12:43:20 +0100 Subject: [PATCH 11/44] Remove current methods --- .../SmartContract/Native/NativeContract.cs | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 81983d691e..d83c02a18a 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -8,6 +8,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Akka.Util; using Neo.IO; using Neo.SmartContract.Manifest; using Neo.VM; @@ -17,6 +18,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Reflection; +using static Neo.Ledger.Blockchain; namespace Neo.SmartContract.Native { @@ -25,9 +27,15 @@ namespace Neo.SmartContract.Native /// public abstract class NativeContract { + private class NefMethods + { + public Dictionary Methods { get; set; } + public byte[] Script { get; set; } + public bool Initialized { get; set; } + } + private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); - private readonly Dictionary currentAllowedMethods = new(); private readonly ImmutableHashSet listenHardforks; private readonly ReadOnlyCollection methodDescriptors; private readonly ReadOnlyCollection eventsDescriptors; @@ -145,15 +153,14 @@ protected NativeContract() } /// - /// The of the native contract. + /// The allowed methods and his offsets. /// /// The where the HardForks are configured. /// Block index - /// The . - internal ContractState GetContractState(ProtocolSettings settings, uint index) + /// The . + private NefMethods GetAllowedMethods(ProtocolSettings settings, uint index) { - // Methods that are allowed to be called are cached from the last time GetContractState was called, the last time it was initialized - currentAllowedMethods.Clear(); + Dictionary methods = new(); // Reflection to get the ContractMethods byte[] script; @@ -163,20 +170,34 @@ internal ContractState GetContractState(ProtocolSettings settings, uint index) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version - currentAllowedMethods.Add(sb.Length, method); + methods.Add(sb.Length, method); sb.EmitSysCall(ApplicationEngine.System_Contract_CallNative); sb.Emit(OpCode.RET); } script = sb.ToArray(); } + return new NefMethods() { Methods = methods, Script = script, Initialized = true }; + } + + /// + /// The of the native contract. + /// + /// The where the HardForks are configured. + /// Block index + /// The . + internal ContractState GetContractState(ProtocolSettings settings, uint index) + { + // Get allowed methods and nef script + NefMethods allowedMethods = GetAllowedMethods(settings, index); + // Compose nef file NefFile nef = new() { Compiler = "neo-core-v3.0", Source = string.Empty, Tokens = Array.Empty(), - Script = script + Script = allowedMethods.Script }; nef.CheckSum = NefFile.ComputeChecksum(nef); @@ -191,7 +212,7 @@ internal ContractState GetContractState(ProtocolSettings settings, uint index) Events = eventsDescriptors .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) .Select(p => p.Descriptor).ToArray(), - Methods = currentAllowedMethods.Values + Methods = allowedMethods.Methods.Values .Select(p => p.Descriptor).ToArray() }, Permissions = new[] { ContractPermission.DefaultPermission }, @@ -296,13 +317,16 @@ internal async void Invoke(ApplicationEngine engine, byte version) if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); ExecutionContext context = engine.CurrentContext; - if (currentAllowedMethods.Count == 0) + NefMethods currentAllowedMethods = context.GetState(); + if (!currentAllowedMethods.Initialized) { - // First call we need to cache it - uint index = engine.PersistingBlock is not null ? engine.PersistingBlock.Index : Ledger.CurrentIndex(engine.Snapshot); - _ = GetContractState(engine.ProtocolSettings, index); + // Compute the current allowed methods + NefMethods nefMethods = GetAllowedMethods(engine.ProtocolSettings, engine.PersistingBlock.Index); + currentAllowedMethods.Methods = nefMethods.Methods; + currentAllowedMethods.Script = nefMethods.Script; + currentAllowedMethods.Initialized = true; } - ContractMethodMetadata method = currentAllowedMethods[context.InstructionPointer]; + ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); ExecutionContextState state = context.GetState(); From 4f59c43aa484c49993577a17fd1449726abfde7d Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 12:51:09 +0100 Subject: [PATCH 12/44] Clean usings --- src/Neo/SmartContract/Native/NativeContract.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index d83c02a18a..5fa64dc6fd 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -8,7 +8,6 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Akka.Util; using Neo.IO; using Neo.SmartContract.Manifest; using Neo.VM; @@ -18,7 +17,6 @@ using System.Collections.ObjectModel; using System.Linq; using System.Reflection; -using static Neo.Ledger.Blockchain; namespace Neo.SmartContract.Native { From c85a1cc29405c66ecb8258c04406edd7b941df66 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 12:54:36 +0100 Subject: [PATCH 13/44] Improve reading Initialize --- src/Neo/SmartContract/Native/ContractManagement.cs | 2 +- src/Neo/SmartContract/Native/GasToken.cs | 2 +- src/Neo/SmartContract/Native/NeoToken.cs | 2 +- src/Neo/SmartContract/Native/OracleContract.cs | 2 +- src/Neo/SmartContract/Native/PolicyContract.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 156f0b15e3..dcbc2a48c2 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -49,7 +49,7 @@ private int GetNextAvailableId(DataCache snapshot) internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - if (hardfork is null) + if (hardfork == ActiveIn) { engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); diff --git a/src/Neo/SmartContract/Native/GasToken.cs b/src/Neo/SmartContract/Native/GasToken.cs index e5b02d2ece..a3ecfd2dc1 100644 --- a/src/Neo/SmartContract/Native/GasToken.cs +++ b/src/Neo/SmartContract/Native/GasToken.cs @@ -27,7 +27,7 @@ internal GasToken() internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - if (hardfork is null) + if (hardfork == ActiveIn) { UInt160 account = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); return Mint(engine, account, engine.ProtocolSettings.InitialGasDistribution, false); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 7d3361d333..1768479dc9 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -174,7 +174,7 @@ private void CheckCandidate(DataCache snapshot, ECPoint pubkey, CandidateState c internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - if (hardfork is null) + if (hardfork == ActiveIn) { var cachedCommittee = new CachedCommittee(engine.ProtocolSettings.StandbyCommittee.Select(p => (p, BigInteger.Zero))); engine.Snapshot.Add(CreateStorageKey(Prefix_Committee), new StorageItem(cachedCommittee)); diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index 97371143a0..4b776f7781 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -135,7 +135,7 @@ private static byte[] GetUrlHash(string url) internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - if (hardfork is null) + if (hardfork == ActiveIn) { engine.Snapshot.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); engine.Snapshot.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index d21c89b833..a766bb7904 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -67,7 +67,7 @@ internal PolicyContract() : base() { } internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - if (hardfork is null) + if (hardfork == ActiveIn) { engine.Snapshot.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(DefaultFeePerByte)); engine.Snapshot.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor)); From 24902809d85efd80aafbc59a5aad999bd163c391 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 13:02:04 +0100 Subject: [PATCH 14/44] Clean OnManifestCompose --- src/Neo/SmartContract/Native/FungibleToken.cs | 2 +- src/Neo/SmartContract/Native/NativeContract.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 9312b3aaba..33791e09a3 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -64,7 +64,7 @@ protected FungibleToken() : base() this.Factor = BigInteger.Pow(10, Decimals); } - protected override void OnManifestCompose(ContractManifest manifest, ProtocolSettings settings, uint index) + protected override void OnManifestCompose(ContractManifest manifest) { manifest.SupportedStandards = new[] { "NEP-17" }; } diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 5fa64dc6fd..1da7891975 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -218,7 +218,7 @@ internal ContractState GetContractState(ProtocolSettings settings, uint index) Extra = null }; - OnManifestCompose(manifest, settings, index); + OnManifestCompose(manifest); // Return ContractState return new ContractState @@ -230,7 +230,7 @@ internal ContractState GetContractState(ProtocolSettings settings, uint index) }; } - protected virtual void OnManifestCompose(ContractManifest manifest, ProtocolSettings settings, uint index) { } + protected virtual void OnManifestCompose(ContractManifest manifest) { } /// /// It is the initialize block From 47317ee35c10151d4141d8a8057b741acdafc044 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 13:28:32 +0100 Subject: [PATCH 15/44] Use cache for all native contracts --- src/Neo/Neo.csproj | 2 +- .../SmartContract/Native/NativeContract.cs | 40 +++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index c6919a3371..c4395df227 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 1da7891975..2941dd003f 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -25,11 +25,24 @@ namespace Neo.SmartContract.Native /// public abstract class NativeContract { - private class NefMethods + private class NativeContractsCache { - public Dictionary Methods { get; set; } - public byte[] Script { get; set; } - public bool Initialized { get; set; } + public class NativeContractCacheEntry + { + public Dictionary Methods { get; set; } + public byte[] Script { get; set; } + } + + internal Dictionary NativeContracts { get; set; } = new Dictionary(); + + public NativeContractCacheEntry GetAllowedMethods(NativeContract native, ProtocolSettings protocolSettings, uint index) + { + if (NativeContracts.TryGetValue(native.Id, out var value)) return value; + + var methods = native.GetAllowedMethods(protocolSettings, index); + NativeContracts[native.Id] = methods; + return methods; + } } private static readonly List contractsList = new(); @@ -155,8 +168,8 @@ protected NativeContract() /// /// The where the HardForks are configured. /// Block index - /// The . - private NefMethods GetAllowedMethods(ProtocolSettings settings, uint index) + /// The . + private NativeContractsCache.NativeContractCacheEntry GetAllowedMethods(ProtocolSettings settings, uint index) { Dictionary methods = new(); @@ -175,7 +188,7 @@ private NefMethods GetAllowedMethods(ProtocolSettings settings, uint index) script = sb.ToArray(); } - return new NefMethods() { Methods = methods, Script = script, Initialized = true }; + return new NativeContractsCache.NativeContractCacheEntry() { Methods = methods, Script = script }; } /// @@ -187,7 +200,7 @@ private NefMethods GetAllowedMethods(ProtocolSettings settings, uint index) internal ContractState GetContractState(ProtocolSettings settings, uint index) { // Get allowed methods and nef script - NefMethods allowedMethods = GetAllowedMethods(settings, index); + NativeContractsCache.NativeContractCacheEntry allowedMethods = GetAllowedMethods(settings, index); // Compose nef file NefFile nef = new() @@ -315,15 +328,8 @@ internal async void Invoke(ApplicationEngine engine, byte version) if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); ExecutionContext context = engine.CurrentContext; - NefMethods currentAllowedMethods = context.GetState(); - if (!currentAllowedMethods.Initialized) - { - // Compute the current allowed methods - NefMethods nefMethods = GetAllowedMethods(engine.ProtocolSettings, engine.PersistingBlock.Index); - currentAllowedMethods.Methods = nefMethods.Methods; - currentAllowedMethods.Script = nefMethods.Script; - currentAllowedMethods.Initialized = true; - } + NativeContractsCache nativeContracts = context.GetState(); + NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine.ProtocolSettings, engine.PersistingBlock.Index); ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); From 8fd8fc240a7abb4ee172f85f152f808d54e75d1b Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 13:34:03 +0100 Subject: [PATCH 16/44] Fix ut --- src/Neo/SmartContract/Native/NativeContract.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 2941dd003f..547b746cf8 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -329,7 +329,10 @@ internal async void Invoke(ApplicationEngine engine, byte version) throw new InvalidOperationException($"The native contract of version {version} is not active."); ExecutionContext context = engine.CurrentContext; NativeContractsCache nativeContracts = context.GetState(); - NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine.ProtocolSettings, engine.PersistingBlock.Index); + NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = + nativeContracts.GetAllowedMethods(this, engine.ProtocolSettings, + engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : + engine.PersistingBlock.Index); ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); From 7ba6274fe361ffd8fbda0d4d781ab4adcde92a30 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 13:42:45 +0100 Subject: [PATCH 17/44] Move cache to ApplicationEngine --- src/Neo/SmartContract/ApplicationEngine.cs | 19 +++++++++++++++++++ .../SmartContract/Native/NativeContract.cs | 6 ++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 67cff166ab..a98e3c04fd 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -604,6 +604,25 @@ public T GetState() return (T)state; } + public T GetState(Func factory) + { + if (states is null) + { + T state = factory(); + SetState(state); + return state; + } + else + { + if (!states.TryGetValue(typeof(T), out object state)) + { + state = factory(); + SetState(state); + } + return (T)state; + } + } + public void SetState(T state) { states ??= new Dictionary(); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 547b746cf8..8436a4ab77 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -327,12 +327,14 @@ internal async void Invoke(ApplicationEngine engine, byte version) { if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); - ExecutionContext context = engine.CurrentContext; - NativeContractsCache nativeContracts = context.GetState(); + // Get native contracts invocation cache + NativeContractsCache nativeContracts = engine.GetState(() => new NativeContractsCache()); NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine.ProtocolSettings, engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : engine.PersistingBlock.Index); + // Check if the method is allowed + ExecutionContext context = engine.CurrentContext; ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); From 67a93646e3038ec117f144bf45fe23f3b5dac439 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 13:44:41 +0100 Subject: [PATCH 18/44] Clean code --- src/Neo/SmartContract/Native/NativeContract.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 8436a4ab77..52068d2eb9 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -8,15 +8,15 @@ // 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; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; +using Neo.IO; +using Neo.SmartContract.Manifest; +using Neo.VM; namespace Neo.SmartContract.Native { @@ -35,11 +35,12 @@ public class NativeContractCacheEntry internal Dictionary NativeContracts { get; set; } = new Dictionary(); - public NativeContractCacheEntry GetAllowedMethods(NativeContract native, ProtocolSettings protocolSettings, uint index) + public NativeContractCacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine engine) { if (NativeContracts.TryGetValue(native.Id, out var value)) return value; - var methods = native.GetAllowedMethods(protocolSettings, index); + uint index = engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : engine.PersistingBlock.Index; + NativeContractCacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings, index); NativeContracts[native.Id] = methods; return methods; } @@ -329,10 +330,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) throw new InvalidOperationException($"The native contract of version {version} is not active."); // Get native contracts invocation cache NativeContractsCache nativeContracts = engine.GetState(() => new NativeContractsCache()); - NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = - nativeContracts.GetAllowedMethods(this, engine.ProtocolSettings, - engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : - engine.PersistingBlock.Index); + NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine); // Check if the method is allowed ExecutionContext context = engine.CurrentContext; ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; From 8eb82db1ee664f86a11009b4377ae2d071a2141d Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 6 Nov 2023 14:06:40 +0100 Subject: [PATCH 19/44] Allow nullable attribute --- src/Neo/SmartContract/Native/ContractMethodAttribute.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index d9989127b5..5c2d71f25f 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -22,5 +22,12 @@ internal class ContractMethodAttribute : Attribute public long CpuFee { get; init; } public long StorageFee { get; init; } public Hardfork? ActiveIn { get; init; } = null; + + public ContractMethodAttribute() { } + + public ContractMethodAttribute(Hardfork activeIn) + { + ActiveIn = activeIn; + } } } From 8667047d10b0c66d391cda9bf69d9f453230c7c9 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 7 Nov 2023 07:42:37 +0800 Subject: [PATCH 20/44] Update src/Neo/SmartContract/Native/ContractEventAttribute.cs --- src/Neo/SmartContract/Native/ContractEventAttribute.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs index f3940f50e3..c747d4a9ea 100644 --- a/src/Neo/SmartContract/Native/ContractEventAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2023 The Neo Project. // // The neo is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the From ed33b32a677f752415278e664386b2f7384ea12c Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 7 Nov 2023 08:33:51 +0100 Subject: [PATCH 21/44] Add base call --- src/Neo/SmartContract/Native/CryptoLib.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index 16ec960a27..3d00fb0002 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -26,7 +26,7 @@ public sealed partial class CryptoLib : NativeContract [NamedCurve.secp256r1] = ECCurve.Secp256r1 }; - internal CryptoLib() { } + internal CryptoLib() : base() { } /// /// Computes the hash value for the specified byte array using the ripemd160 algorithm. From 594c2e6e61d415bfcaef5ad2d54d4e96671ae443 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 7 Nov 2023 08:43:00 +0100 Subject: [PATCH 22/44] Fix one https://github.com/neo-project/neo/pull/2941#discussion_r1382434903 --- src/Neo/SmartContract/Native/NativeContract.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 52068d2eb9..1bae21403d 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -289,7 +289,8 @@ internal bool IsActive(ProtocolSettings settings, uint index) if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn)) { - return false; + // If is not set in the configuration is treated as enabled from the genesis + activeIn = 0; } return activeIn <= index; From 64e5cfc2a631fdfc0238486c8fcea1ddd9093b3e Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 7 Nov 2023 08:43:59 +0100 Subject: [PATCH 23/44] Fix IsInitializeBlock https://github.com/neo-project/neo/pull/2941#discussion_r1382434903 --- src/Neo/SmartContract/Native/NativeContract.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 1bae21403d..bc254d314b 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -265,7 +265,13 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardf // If is in the hardfork height, return true foreach (Hardfork hf in listenHardforks) { - if (settings.Hardforks.TryGetValue(hf, out var activeIn) && activeIn == index) + if (!settings.Hardforks.TryGetValue(hf, out var activeIn)) + { + // If is not set in the configuration is treated as enabled from the genesis + activeIn = 0; + } + + if (activeIn == index) { hardfork = hf; return true; From 1b210cebe5ad8a85420761c32f146dad5c5fc34b Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 7 Nov 2023 13:08:55 +0100 Subject: [PATCH 24/44] Add ContractEventAttribute constructors for ActiveIn --- .../Native/ContractEventAttribute.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs index c747d4a9ea..0f5bca6ebb 100644 --- a/src/Neo/SmartContract/Native/ContractEventAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -22,6 +22,12 @@ internal class ContractEventAttribute : Attribute public ContractEventDescriptor Descriptor { get; set; } public Hardfork? ActiveIn { get; init; } = null; + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value) : this(order, name, arg1Name, arg1Value) + { + ActiveIn = activeIn; + } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value) { Order = order; @@ -39,6 +45,13 @@ public ContractEventAttribute(int order, string name, string arg1Name, ContractP }; } + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value) + { + ActiveIn = activeIn; + } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value, string arg2Name, ContractParameterType arg2Value) @@ -63,6 +76,14 @@ public ContractEventAttribute(int order, string name, }; } + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value, arg3Name, arg3Value) + { + ActiveIn = activeIn; + } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value, string arg2Name, ContractParameterType arg2Value, @@ -94,6 +115,15 @@ public ContractEventAttribute(int order, string name, }; } + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value, + string arg4Name, ContractParameterType arg4Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value, arg3Name, arg3Value, arg4Name, arg4Value) + { + ActiveIn = activeIn; + } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value, string arg2Name, ContractParameterType arg2Value, From 690b5d4b2e9f7e4a2e1e9a536c337116f43e9427 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 8 Nov 2023 09:36:07 +0100 Subject: [PATCH 25/44] Ensure ommited hfs --- src/Neo/ProtocolSettings.cs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 3e9ef5b28d..72fc769c8a 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -190,11 +190,33 @@ public static ProtocolSettings Load(IConfigurationSection section) MaxTraceableBlocks = section.GetValue("MaxTraceableBlocks", Default.MaxTraceableBlocks), InitialGasDistribution = section.GetValue("InitialGasDistribution", Default.InitialGasDistribution), Hardforks = section.GetSection("Hardforks").Exists() - ? section.GetSection("Hardforks").GetChildren().ToImmutableDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value)) + ? EnsureOmmitedHardforks(section.GetSection("Hardforks").GetChildren().ToDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value))).ToImmutableDictionary() : Default.Hardforks }; } + /// + /// Explicitly set the height of all old omitted hardforks to 0 for proper IsHardforkEnabled behaviour. + /// + /// HardForks + /// Processed hardfork configuration + private static Dictionary EnsureOmmitedHardforks(Dictionary hardForks) + { + foreach (Hardfork hf in AllHardforks) + { + if (!hardForks.ContainsKey(hf)) + { + hardForks[hf] = 0; + } + else + { + break; + } + } + + return hardForks; + } + private static void CheckingHardfork(ProtocolSettings settings) { var allHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToList(); From 8cef6cefffd16ba2e0b11c623349e5b690777dbd Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 8 Nov 2023 09:46:02 +0100 Subject: [PATCH 26/44] Rename --- src/Neo/SmartContract/Native/NativeContract.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index bc254d314b..b8ba7ad442 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -48,7 +48,7 @@ public NativeContractCacheEntry GetAllowedMethods(NativeContract native, Applica private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); - private readonly ImmutableHashSet listenHardforks; + private readonly ImmutableHashSet usedHardforks; private readonly ReadOnlyCollection methodDescriptors; private readonly ReadOnlyCollection eventsDescriptors; private static int id_counter = 0; @@ -152,7 +152,7 @@ protected NativeContract() OrderBy(p => p.Order).ToList().AsReadOnly(); // Calculate the initializations forks - listenHardforks = + usedHardforks = methodDescriptors.Select(u => u.ActiveIn) .Concat(eventsDescriptors.Select(u => u.ActiveIn)) .Concat(new Hardfork?[] { ActiveIn }) @@ -263,7 +263,7 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardf } // If is in the hardfork height, return true - foreach (Hardfork hf in listenHardforks) + foreach (Hardfork hf in usedHardforks) { if (!settings.Hardforks.TryGetValue(hf, out var activeIn)) { From f11498291ee7857966c01ba56f31cbd6c771ec43 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 8 Nov 2023 09:49:08 +0100 Subject: [PATCH 27/44] Case insensitive hf config --- 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 72fc769c8a..9dbf9e86ab 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -190,7 +190,7 @@ public static ProtocolSettings Load(IConfigurationSection section) MaxTraceableBlocks = section.GetValue("MaxTraceableBlocks", Default.MaxTraceableBlocks), InitialGasDistribution = section.GetValue("InitialGasDistribution", Default.InitialGasDistribution), Hardforks = section.GetSection("Hardforks").Exists() - ? EnsureOmmitedHardforks(section.GetSection("Hardforks").GetChildren().ToDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value))).ToImmutableDictionary() + ? EnsureOmmitedHardforks(section.GetSection("Hardforks").GetChildren().ToDictionary(p => Enum.Parse(p.Key, true), p => uint.Parse(p.Value))).ToImmutableDictionary() : Default.Hardforks }; } From 1fee32f1b4ff5d44a4a000d4604ce7b7f1ccdd02 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 9 Nov 2023 12:58:54 +0100 Subject: [PATCH 28/44] Increase coverage --- src/Neo/ProtocolSettings.cs | 4 +- .../Native/UT_ContractEventAttribute.cs | 140 ++++++++++++++++++ tests/Neo.UnitTests/UT_ProtocolSettings.cs | 118 +++++++++++++++ 3 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 9dbf9e86ab..22bddffe0e 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -232,7 +232,7 @@ private static void CheckingHardfork(ProtocolSettings settings) // If they aren't consecutive, return false. if (nextIndex - currentIndex > 1) - throw new Exception("Hardfork configuration is not continuous."); + throw new ArgumentException("Hardfork configuration is not continuous."); } // Check that block numbers are not higher in earlier hardforks than in later ones for (int i = 0; i < sortedHardforks.Count - 1; i++) @@ -240,7 +240,7 @@ private static void CheckingHardfork(ProtocolSettings settings) if (settings.Hardforks[sortedHardforks[i]] > settings.Hardforks[sortedHardforks[i + 1]]) { // This means the block number for the current hardfork is greater than the next one, which should not be allowed. - throw new Exception($"The Hardfork configuration for {sortedHardforks[i]} is greater than for {sortedHardforks[i + 1]}"); + throw new ArgumentException($"The Hardfork configuration for {sortedHardforks[i]} is greater than for {sortedHardforks[i + 1]}"); } } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs new file mode 100644 index 0000000000..d85ed35642 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs @@ -0,0 +1,140 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; +using Neo.SmartContract.Native; + +namespace Neo.UnitTests.SmartContract.Native +{ + [TestClass] + public class UT_ContractEventAttribute + { + [TestMethod] + public void TestConstructorOneArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "1", "a1", ContractParameterType.String); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("1", arg.Descriptor.Name); + Assert.AreEqual(1, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + + arg = new ContractEventAttribute(1, "1", "a1", ContractParameterType.String); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("1", arg.Descriptor.Name); + Assert.AreEqual(1, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + } + + [TestMethod] + public void TestConstructorTwoArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "2", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("2", arg.Descriptor.Name); + Assert.AreEqual(2, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + + arg = new ContractEventAttribute(1, "2", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("2", arg.Descriptor.Name); + Assert.AreEqual(2, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + } + + [TestMethod] + public void TestConstructorThreeArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "3", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("3", arg.Descriptor.Name); + Assert.AreEqual(3, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + + arg = new ContractEventAttribute(1, "3", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("3", arg.Descriptor.Name); + Assert.AreEqual(3, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + } + + [TestMethod] + public void TestConstructorFourArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "4", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean, + "a4", ContractParameterType.Array); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("4", arg.Descriptor.Name); + Assert.AreEqual(4, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + Assert.AreEqual("a4", arg.Descriptor.Parameters[3].Name); + Assert.AreEqual(ContractParameterType.Array, arg.Descriptor.Parameters[3].Type); + + arg = new ContractEventAttribute(1, "4", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean, + "a4", ContractParameterType.Array); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("4", arg.Descriptor.Name); + Assert.AreEqual(4, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + Assert.AreEqual("a4", arg.Descriptor.Parameters[3].Name); + Assert.AreEqual(ContractParameterType.Array, arg.Descriptor.Parameters[3].Type); + } + } +} diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 42be0e69cc..adf2c32af2 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -1,3 +1,5 @@ +using System; +using System.IO; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Wallets; @@ -35,6 +37,122 @@ public void TestGetMillisecondsPerBlock() ProtocolSettings.Default.MillisecondsPerBlock.Should().Be(15000); } + [TestMethod] + public void TestDefaultHardfork() + { + string json = @" +{ + ""ProtocolConfiguration"": { + ""Network"": 860833102, + ""AddressVersion"": 53, + ""MillisecondsPerBlock"": 15000, + ""MaxTransactionsPerBlock"": 512, + ""MemoryPoolMaxTransactions"": 50000, + ""MaxTraceableBlocks"": 2102400, + ""Hardforks"": { + ""HF_Basilisk"": 4120000 + }, + ""InitialGasDistribution"": 5200000000000000, + ""ValidatorsCount"": 7, + ""StandbyCommittee"": [ + ""03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"", + ""02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"", + ""03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"", + ""02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"", + ""024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"", + ""02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"", + ""02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"", + ""023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe"", + ""03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379"", + ""03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050"", + ""03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0"", + ""02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62"", + ""03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0"", + ""0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654"", + ""020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"", + ""0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30"", + ""03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde"", + ""02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad"", + ""0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d"", + ""03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc"", + ""02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a"" + ], + ""SeedList"": [ + ""seed1.neo.org:10333"", + ""seed2.neo.org:10333"", + ""seed3.neo.org:10333"", + ""seed4.neo.org:10333"", + ""seed5.neo.org:10333"" + ] + } +} +"; + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); + settings.Hardforks[Hardfork.HF_Basilisk].Should().Be(4120000); + } + + [TestMethod] + public void TestWrongHardfork() + { + string json = @" +{ + ""ProtocolConfiguration"": { + ""Network"": 860833102, + ""AddressVersion"": 53, + ""MillisecondsPerBlock"": 15000, + ""MaxTransactionsPerBlock"": 512, + ""MemoryPoolMaxTransactions"": 50000, + ""MaxTraceableBlocks"": 2102400, + ""Hardforks"": { + ""HF_Aspidochelone"": 4120001, + ""HF_Basilisk"": 4120000 + }, + ""InitialGasDistribution"": 5200000000000000, + ""ValidatorsCount"": 7, + ""StandbyCommittee"": [ + ""03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"", + ""02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"", + ""03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"", + ""02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"", + ""024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"", + ""02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"", + ""02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"", + ""023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe"", + ""03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379"", + ""03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050"", + ""03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0"", + ""02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62"", + ""03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0"", + ""0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654"", + ""020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"", + ""0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30"", + ""03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde"", + ""02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad"", + ""0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d"", + ""03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc"", + ""02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a"" + ], + ""SeedList"": [ + ""seed1.neo.org:10333"", + ""seed2.neo.org:10333"", + ""seed3.neo.org:10333"", + ""seed4.neo.org:10333"", + ""seed5.neo.org:10333"" + ] + } +} +"; + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + Assert.ThrowsException(() => ProtocolSettings.Load(file, false)); + File.Delete(file); + } + [TestMethod] public void TestGetSeedList() { From 06f1b23974f21fbedbbe9cb26e9f8076984c6d6a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 9 Nov 2023 13:06:01 +0100 Subject: [PATCH 29/44] More uts --- .../Native/UT_ContractMethodAttribute.cs | 21 +++++++++++++++++++ tests/Neo.UnitTests/UT_ProtocolSettings.cs | 8 +++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs new file mode 100644 index 0000000000..4d5c3871fc --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs @@ -0,0 +1,21 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Native; + +namespace Neo.UnitTests.SmartContract.Native +{ + [TestClass] + public class UT_ContractMethodAttribute + { + [TestMethod] + public void TestConstructorOneArg() + { + var arg = new ContractMethodAttribute(); + + Assert.IsNull(arg.ActiveIn); + + arg = new ContractMethodAttribute(Hardfork.HF_Aspidochelone); + + Assert.AreEqual(Hardfork.HF_Aspidochelone, arg.ActiveIn); + } + } +} diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index adf2c32af2..4d2c775c80 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -94,6 +94,14 @@ public void TestDefaultHardfork() settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); settings.Hardforks[Hardfork.HF_Basilisk].Should().Be(4120000); + + // Check IsHardforkEnabled + + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 10).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 0).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 10).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 4120000).Should().BeTrue(); } [TestMethod] From aee4be37fec87bae3086600d02148a576da9974c Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 9 Nov 2023 13:20:06 +0100 Subject: [PATCH 30/44] Rename --- src/Neo/SmartContract/Native/NativeContract.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index b8ba7ad442..a45671f26e 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -27,20 +27,20 @@ public abstract class NativeContract { private class NativeContractsCache { - public class NativeContractCacheEntry + public class CacheEntry { public Dictionary Methods { get; set; } public byte[] Script { get; set; } } - internal Dictionary NativeContracts { get; set; } = new Dictionary(); + internal Dictionary NativeContracts { get; set; } = new Dictionary(); - public NativeContractCacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine engine) + public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine engine) { if (NativeContracts.TryGetValue(native.Id, out var value)) return value; uint index = engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : engine.PersistingBlock.Index; - NativeContractCacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings, index); + CacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings, index); NativeContracts[native.Id] = methods; return methods; } @@ -170,7 +170,7 @@ protected NativeContract() /// The where the HardForks are configured. /// Block index /// The . - private NativeContractsCache.NativeContractCacheEntry GetAllowedMethods(ProtocolSettings settings, uint index) + private NativeContractsCache.CacheEntry GetAllowedMethods(ProtocolSettings settings, uint index) { Dictionary methods = new(); @@ -189,7 +189,7 @@ private NativeContractsCache.NativeContractCacheEntry GetAllowedMethods(Protocol script = sb.ToArray(); } - return new NativeContractsCache.NativeContractCacheEntry() { Methods = methods, Script = script }; + return new NativeContractsCache.CacheEntry() { Methods = methods, Script = script }; } /// @@ -201,7 +201,7 @@ private NativeContractsCache.NativeContractCacheEntry GetAllowedMethods(Protocol internal ContractState GetContractState(ProtocolSettings settings, uint index) { // Get allowed methods and nef script - NativeContractsCache.NativeContractCacheEntry allowedMethods = GetAllowedMethods(settings, index); + NativeContractsCache.CacheEntry allowedMethods = GetAllowedMethods(settings, index); // Compose nef file NefFile nef = new() @@ -337,7 +337,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) throw new InvalidOperationException($"The native contract of version {version} is not active."); // Get native contracts invocation cache NativeContractsCache nativeContracts = engine.GetState(() => new NativeContractsCache()); - NativeContractsCache.NativeContractCacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine); + NativeContractsCache.CacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine); // Check if the method is allowed ExecutionContext context = engine.CurrentContext; ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; From c4b4a887ce94ba12947ab1c5fc6b2dbecd8948c9 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Nov 2023 22:46:04 +0100 Subject: [PATCH 31/44] Update src/Neo/SmartContract/Native/ContractManagement.cs --- src/Neo/SmartContract/Native/ContractManagement.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index dcbc2a48c2..2b57cb1a99 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -89,6 +89,8 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) } await contract.Initialize(engine, hf); + // Emit native contract notification + engine.SendNotification(Hash, state is null ? "Deploy" : "Update", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); } } } From 28ac4e69ea033987cfc60e3643753b33895dfba6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 10 Nov 2023 09:46:58 +0100 Subject: [PATCH 32/44] format code --- src/Neo/SmartContract/Native/ContractManagement.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 2b57cb1a99..31293fe328 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -89,8 +89,8 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) } await contract.Initialize(engine, hf); - // Emit native contract notification - engine.SendNotification(Hash, state is null ? "Deploy" : "Update", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); + // Emit native contract notification + engine.SendNotification(Hash, state is null ? "Deploy" : "Update", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); } } } From ff852a3f44a1fc71ecd956a654e1d32a4b03baf9 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 10 Nov 2023 09:59:46 +0100 Subject: [PATCH 33/44] Fix ProtocolSettings --- src/Neo/ProtocolSettings.cs | 24 +---- tests/Neo.UnitTests/UT_ProtocolSettings.cs | 114 +++++++++++---------- 2 files changed, 63 insertions(+), 75 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 22bddffe0e..d58fe24cc6 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -148,7 +148,7 @@ public record ProtocolSettings MemoryPoolMaxTransactions = 50_000, MaxTraceableBlocks = 2_102_400, InitialGasDistribution = 52_000_000_00000000, - Hardforks = ImmutableDictionary.Empty + Hardforks = EnsureOmmitedHardforks(new Dictionary()).ToImmutableDictionary() }; /// @@ -222,7 +222,7 @@ private static void CheckingHardfork(ProtocolSettings settings) var allHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToList(); // Check for continuity in configured hardforks var sortedHardforks = settings.Hardforks.Keys - .OrderBy(h => allHardforks.IndexOf(h)) + .OrderBy(allHardforks.IndexOf) .ToList(); for (int i = 0; i < sortedHardforks.Count - 1; i++) @@ -253,28 +253,14 @@ private static void CheckingHardfork(ProtocolSettings settings) /// True if enabled public bool IsHardforkEnabled(Hardfork hardfork, uint index) { - // Return true if there's no specific configuration - if (Hardforks.Count == 0) - return true; - - // If the hardfork isn't specified in the configuration, check if it's a new one. - if (!Hardforks.ContainsKey(hardfork)) - { - int currentHardforkIndex = AllHardforks.IndexOf(hardfork); - int lastConfiguredHardforkIndex = AllHardforks.IndexOf(Hardforks.Keys.Last()); - - // If it's a newer hardfork compared to the ones in the configuration, disable it. - if (currentHardforkIndex > lastConfiguredHardforkIndex) - return false; - } - if (Hardforks.TryGetValue(hardfork, out uint height)) { // If the hardfork has a specific height in the configuration, check the block height. return index >= height; } - // If no specific conditions are met, return true. - return true; + + // If the hardfork isn't specified in the configuration, return false. + return false; } } } diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 4d2c775c80..8cb7d01973 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -38,55 +38,10 @@ public void TestGetMillisecondsPerBlock() } [TestMethod] - public void TestDefaultHardfork() + public void HardForkTestBAndNotA() { - string json = @" -{ - ""ProtocolConfiguration"": { - ""Network"": 860833102, - ""AddressVersion"": 53, - ""MillisecondsPerBlock"": 15000, - ""MaxTransactionsPerBlock"": 512, - ""MemoryPoolMaxTransactions"": 50000, - ""MaxTraceableBlocks"": 2102400, - ""Hardforks"": { - ""HF_Basilisk"": 4120000 - }, - ""InitialGasDistribution"": 5200000000000000, - ""ValidatorsCount"": 7, - ""StandbyCommittee"": [ - ""03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"", - ""02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"", - ""03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"", - ""02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"", - ""024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"", - ""02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"", - ""02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"", - ""023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe"", - ""03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379"", - ""03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050"", - ""03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0"", - ""02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62"", - ""03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0"", - ""0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654"", - ""020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"", - ""0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30"", - ""03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde"", - ""02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad"", - ""0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d"", - ""03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc"", - ""02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a"" - ], - ""SeedList"": [ - ""seed1.neo.org:10333"", - ""seed2.neo.org:10333"", - ""seed3.neo.org:10333"", - ""seed4.neo.org:10333"", - ""seed5.neo.org:10333"" - ] - } -} -"; + string json = CreateHKSettings("\"HF_Basilisk\": 4120000"); + var file = Path.GetTempFileName(); File.WriteAllText(file, json); ProtocolSettings settings = ProtocolSettings.Load(file, false); @@ -105,9 +60,61 @@ public void TestDefaultHardfork() } [TestMethod] - public void TestWrongHardfork() + public void HardForkTestAAndNotB() { - string json = @" + string json = CreateHKSettings("\"HF_Aspidochelone\": 0"); + + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); + settings.Hardforks.ContainsKey(Hardfork.HF_Basilisk).Should().BeFalse(); + + // Check IsHardforkEnabled + + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 10).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 0).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 10).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 4120000).Should().BeFalse(); + } + + [TestMethod] + public void HardForkTestNone() + { + string json = CreateHKSettings(""); + + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); + settings.Hardforks[Hardfork.HF_Basilisk].Should().Be(0); + + // Check IsHardforkEnabled + + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 10).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 10).Should().BeTrue(); + } + + [TestMethod] + public void HardForkTestAMoreThanB() + { + string json = CreateHKSettings("\"HF_Aspidochelone\": 4120001, \"HF_Basilisk\": 4120000"); + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + Assert.ThrowsException(() => ProtocolSettings.Load(file, false)); + File.Delete(file); + } + + private static string CreateHKSettings(string hf) + { + return @" { ""ProtocolConfiguration"": { ""Network"": 860833102, @@ -117,8 +124,7 @@ public void TestWrongHardfork() ""MemoryPoolMaxTransactions"": 50000, ""MaxTraceableBlocks"": 2102400, ""Hardforks"": { - ""HF_Aspidochelone"": 4120001, - ""HF_Basilisk"": 4120000 + " + hf + @" }, ""InitialGasDistribution"": 5200000000000000, ""ValidatorsCount"": 7, @@ -155,10 +161,6 @@ public void TestWrongHardfork() } } "; - var file = Path.GetTempFileName(); - File.WriteAllText(file, json); - Assert.ThrowsException(() => ProtocolSettings.Load(file, false)); - File.Delete(file); } [TestMethod] From 405a81642ff2ee1af0df74971727b1083c5cf433 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 11 Dec 2023 03:34:31 -0800 Subject: [PATCH 34/44] Update src/Neo/SmartContract/ApplicationEngine.cs --- src/Neo/SmartContract/ApplicationEngine.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index a98e3c04fd..ab73227208 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -631,9 +631,9 @@ public void SetState(T state) public bool IsHardforkEnabled(Hardfork hardfork) { - // Return true if PersistingBlock is null + // Return true if PersistingBlock is null and Hardfork is enabled if (PersistingBlock is null) - return true; + return ProtocolSettings.Hardforks.ContainsKey(hardfork); return ProtocolSettings.IsHardforkEnabled(hardfork, PersistingBlock.Index); } From d6214760d7a87de9962d1d80a40529c94e864564 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 2 Jan 2024 13:53:44 +0100 Subject: [PATCH 35/44] format --- .../SmartContract/Native/ContractEventAttribute.cs | 13 +++++++------ src/Neo/SmartContract/Native/NativeContract.cs | 6 +++--- .../Native/UT_ContractEventAttribute.cs | 11 +++++++++++ .../Native/UT_ContractMethodAttribute.cs | 11 +++++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs index 0f5bca6ebb..31312acb5a 100644 --- a/src/Neo/SmartContract/Native/ContractEventAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2023 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractEventAttribute.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. diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 6ef52fa0f7..a704920eae 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -9,15 +9,15 @@ // 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; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; -using Neo.IO; -using Neo.SmartContract.Manifest; -using Neo.VM; namespace Neo.SmartContract.Native { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs index d85ed35642..ba8f703253 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractEventAttribute.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract; using Neo.SmartContract.Native; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs index 4d5c3871fc..a2b746d7c8 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractMethodAttribute.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract.Native; From 4ade232e22bdd174e4258104daf60a92847f6dd1 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 2 Jan 2024 13:56:00 +0100 Subject: [PATCH 36/44] reorder using --- src/Neo/SmartContract/Native/ContractEventAttribute.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs index 31312acb5a..656ecef725 100644 --- a/src/Neo/SmartContract/Native/ContractEventAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -9,9 +9,9 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Manifest; using System; using System.Diagnostics; -using Neo.SmartContract.Manifest; namespace Neo.SmartContract.Native { From 487f4ac542d8fcbcaba79e1ea27c40386c13ef35 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 3 Jan 2024 11:18:31 +0100 Subject: [PATCH 37/44] Fix UT --- tests/Neo.UnitTests/SmartContract/UT_InteropService.cs | 6 +++--- tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 909ecd2457..f019318d49 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -76,7 +76,7 @@ public void Runtime_GetNotifications_Test() // Wrong length - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Retrive @@ -93,7 +93,7 @@ public void Runtime_GetNotifications_Test() // All test - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Notification @@ -162,7 +162,7 @@ public void Runtime_GetNotifications_Test() // Script notifications - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Notification diff --git a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs index 3ab32ad7a5..fc29c95c12 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs @@ -272,7 +272,7 @@ public void Serialize_Map_Test() [TestMethod] public void Deserialize_Map_Test() { - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null, null, ProtocolSettings.Default); var items = JsonSerializer.Deserialize(engine, JObject.Parse("{\"test1\":123,\"test2\":321}"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(Map)); @@ -302,7 +302,7 @@ public void Serialize_Array_Bool_Str_Num() [TestMethod] public void Deserialize_Array_Bool_Str_Num() { - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null, null, ProtocolSettings.Default); var items = JsonSerializer.Deserialize(engine, JObject.Parse("[true,\"test\",123,9.05E+28]"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(VM.Types.Array)); @@ -333,7 +333,7 @@ public void Serialize_Array_OfArray() [TestMethod] public void Deserialize_Array_OfArray() { - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null, null, ProtocolSettings.Default); var items = JsonSerializer.Deserialize(engine, JObject.Parse("[[true,\"test1\",123],[true,\"test2\",321]]"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(VM.Types.Array)); From 8c9e0c65372b137bbc71b39379eb85a680623e2c Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 12 Jan 2024 02:44:10 +0800 Subject: [PATCH 38/44] Adding keccak256 (#2925) * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * HF_Manticore * Fix copyright * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * HF_Manticore * Fix copyright * HF_Manticore * Update CryptoLib.cs * Update CryptoLib.cs * Update UT_CryptoLib.cs * Apply suggestions from code review * clean usings --------- Co-authored-by: Shargon --- src/Neo/Hardfork.cs | 3 +- src/Neo/SmartContract/Native/CryptoLib.cs | 16 ++++ .../SmartContract/Native/UT_CryptoLib.cs | 93 +++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/Neo/Hardfork.cs b/src/Neo/Hardfork.cs index a5decc1d0c..9ef6a63c1c 100644 --- a/src/Neo/Hardfork.cs +++ b/src/Neo/Hardfork.cs @@ -14,6 +14,7 @@ namespace Neo public enum Hardfork : byte { HF_Aspidochelone, - HF_Basilisk + HF_Basilisk, + HF_Cockatrice } } diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index fdc6424c43..a7b822e39c 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -11,6 +11,7 @@ using Neo.Cryptography; using Neo.Cryptography.ECC; +using Org.BouncyCastle.Crypto.Digests; using System; using System.Collections.Generic; @@ -64,6 +65,21 @@ public static byte[] Murmur32(byte[] data, uint seed) return murmur.ComputeHash(data); } + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// Computed hash + [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] + public static byte[] Keccak256(byte[] data) + { + KeccakDigest keccak = new(256); + keccak.BlockUpdate(data, 0, data.Length); + byte[] result = new byte[keccak.GetDigestSize()]; + keccak.DoFinal(result, 0); + return result; + } + /// /// Verifies that a digital signature is appropriate for the provided key and message using the ECDSA algorithm. /// diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index 9e36488031..6f150cca12 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -15,6 +15,7 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; +using Org.BouncyCastle.Utilities.Encoders; namespace Neo.UnitTests.SmartContract.Native { @@ -334,5 +335,97 @@ public void TestBls12381ScalarMul_Compat() BLS12381PointType.G2Proj ); } + + /// + /// Keccak256 cases are verified in https://emn178.github.io/online-tools/keccak_256.html + /// + [TestMethod] + public void TestKeccak256_HelloWorld() + { + // Arrange + byte[] inputData = "Hello, World!"u8.ToArray(); + string expectedHashHex = "acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Hello, World!'."); + } + [TestMethod] + public void TestKeccak256_Keccak() + { + // Arrange + byte[] inputData = "Keccak"u8.ToArray(); + string expectedHashHex = "868c016b666c7d3698636ee1bd023f3f065621514ab61bf26f062c175fdbe7f2"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Keccak'."); + } + + [TestMethod] + public void TestKeccak256_Cryptography() + { + // Arrange + byte[] inputData = "Cryptography"u8.ToArray(); + string expectedHashHex = "53d49d225dd2cfe77d8c5e2112bcc9efe77bea1c7aa5e5ede5798a36e99e2d29"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Cryptography'."); + } + + [TestMethod] + public void TestKeccak256_Testing123() + { + // Arrange + byte[] inputData = "Testing123"u8.ToArray(); + string expectedHashHex = "3f82db7b16b0818a1c6b2c6152e265f682d5ebcf497c9aad776ad38bc39cb6ca"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Testing123'."); + } + + [TestMethod] + public void TestKeccak256_LongString() + { + // Arrange + byte[] inputData = "This is a longer string for Keccak256 testing purposes."u8.ToArray(); + string expectedHashHex = "24115e5c2359f85f6840b42acd2f7ea47bc239583e576d766fa173bf711bdd2f"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for the longer string."); + } + + [TestMethod] + public void TestKeccak256_BlankString() + { + // Arrange + byte[] inputData = ""u8.ToArray(); + string expectedHashHex = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for blank string."); + } } } From c13575c1cd0c41fc5be7f4d410a353311904ac5e Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 8 Feb 2024 15:13:13 +0100 Subject: [PATCH 39/44] Fix net standard --- src/Neo/SmartContract/Native/NativeContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index a704920eae..6d5d105b7d 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -148,7 +148,7 @@ protected NativeContract() // Reflection to get the events eventsDescriptors = - GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty())?. + GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null)?. GetCustomAttributes(). OrderBy(p => p.Order).ToList().AsReadOnly(); From 41914d8f3d9f090715a1c9e2f9ae4a2bfe558dca Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 19 Feb 2024 10:52:34 +0100 Subject: [PATCH 40/44] Add ut --- .../SmartContract/Native/UT_NativeContract.cs | 21 +++++++++++++++++++ tests/Neo.UnitTests/UT_ProtocolSettings.cs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 5f4b5b43e0..7f23519e9f 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -11,6 +11,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract.Native; +using System.IO; namespace Neo.UnitTests.SmartContract.Native { @@ -22,5 +23,25 @@ public void TestGetContract() { Assert.IsTrue(NativeContract.NEO == NativeContract.GetContract(NativeContract.NEO.Hash)); } + + [TestMethod] + public void TestIsInitializeBlock() + { + 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.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 0, out var hf)); + Assert.IsNull(hf); + + Assert.IsFalse(NativeContract.CryptoLib.IsInitializeBlock(settings, 1, out hf)); + Assert.IsNull(hf); + + Assert.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 20, out hf)); + Assert.AreEqual(Hardfork.HF_Cockatrice, hf); + } } } diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 5c3948de8e..e5d829ef8b 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -124,7 +124,7 @@ public void HardForkTestAMoreThanB() File.Delete(file); } - private static string CreateHKSettings(string hf) + internal static string CreateHKSettings(string hf) { return @" { From e87e2b205dc0b0f08e2b69d6bd3df86a85ff8837 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 19 Feb 2024 11:00:26 +0100 Subject: [PATCH 41/44] Fix update --- src/Neo/SmartContract/Native/ContractManagement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index a23def15e8..53442289cd 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -86,7 +86,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) // Increase the update counter contractState.UpdateCounter = (ushort)(state.GetInteroperable().UpdateCounter + 1); // Update the contract state - state.Set(contractState); + engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(contractState)); } await contract.Initialize(engine, hf); From 8bcda8709530f768411731a498e0e3ec47caf058 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 21 Feb 2024 11:01:58 +0100 Subject: [PATCH 42/44] Fix update --- src/Neo/NeoSystem.cs | 3 ++- src/Neo/Persistence/DataCache.cs | 2 +- src/Neo/SmartContract/Native/ContractManagement.cs | 11 +++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index d299f8de12..1303770a3f 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -117,7 +117,8 @@ static NeoSystem() /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. public NeoSystem(ProtocolSettings settings, string? storageProvider = null, string? storagePath = null) : - this(settings, StoreFactory.GetStoreProvider(storageProvider ?? nameof(MemoryStore)), storagePath) + this(settings, StoreFactory.GetStoreProvider(storageProvider ?? nameof(MemoryStore)) + ?? throw new ArgumentException($"Can't find the storage provider {storageProvider}", nameof(storageProvider)), storagePath) { } diff --git a/src/Neo/Persistence/DataCache.cs b/src/Neo/Persistence/DataCache.cs index 6a1a5236bc..86fbd69961 100644 --- a/src/Neo/Persistence/DataCache.cs +++ b/src/Neo/Persistence/DataCache.cs @@ -96,7 +96,7 @@ public void Add(StorageKey key, StorageItem value) { TrackState.Deleted => TrackState.Changed, TrackState.NotFound => TrackState.Added, - _ => throw new ArgumentException() + _ => throw new ArgumentException($"The element currently has state {trackable.State}") }; } else diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 53442289cd..3347163a6c 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -73,7 +73,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index, out Hardfork? hf)) { ContractState contractState = contract.GetContractState(engine.ProtocolSettings, engine.PersistingBlock.Index); - StorageItem state = engine.Snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(contract.Hash)); + StorageItem state = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(contract.Hash)); if (state is null) { @@ -83,10 +83,13 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) } else { + // Parse old contract + var oldContract = state.GetInteroperable(); // Increase the update counter - contractState.UpdateCounter = (ushort)(state.GetInteroperable().UpdateCounter + 1); - // Update the contract state - engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(contractState)); + oldContract.UpdateCounter++; + // Modify nef and manifest + oldContract.Nef = contractState.Nef; + oldContract.Manifest = contractState.Manifest; } await contract.Initialize(engine, hf); From f1c01cd73d30db74a61dc7d23cc5a1bd5502160f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 22 Feb 2024 19:14:29 +0100 Subject: [PATCH 43/44] Expose `GetCommitteeAddress` --- src/Neo/SmartContract/Native/NeoToken.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index ed796a9756..ee606638e6 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -464,6 +464,7 @@ public NeoAccountState GetAccountState(DataCache snapshot, UInt160 account) /// /// The snapshot used to read data. /// The address of the committee. + [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 17, RequiredCallFlags = CallFlags.ReadStates)] public UInt160 GetCommitteeAddress(DataCache snapshot) { ECPoint[] committees = GetCommittee(snapshot); From 2d10261aab07d182318fdb28f59525c8acd33ae6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 1 Mar 2024 09:29:56 +0100 Subject: [PATCH 44/44] Update src/Neo/SmartContract/Native/NeoToken.cs --- src/Neo/SmartContract/Native/NeoToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 16dcf62bf8..96e362dd33 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -480,7 +480,7 @@ public NeoAccountState GetAccountState(DataCache snapshot, UInt160 account) /// /// The snapshot used to read data. /// The address of the committee. - [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 17, RequiredCallFlags = CallFlags.ReadStates)] + [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.ReadStates)] public UInt160 GetCommitteeAddress(DataCache snapshot) { ECPoint[] committees = GetCommittee(snapshot);