From 4d1ee15e1048d41a9c3765357a40c33ff284e288 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 28 Apr 2022 20:06:01 +0800 Subject: [PATCH 1/7] Fix fee of CreateMultisigAccount --- src/neo/SmartContract/ApplicationEngine.Contract.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index ed1ecde3b5..bd4bf7d8c5 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -41,13 +41,13 @@ partial class ApplicationEngine /// The of System.Contract.CreateStandardAccount. /// Calculates corresponding account scripthash for the given public key. /// - public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), 1 << 8, CallFlags.None); + public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), CheckSigPrice, CallFlags.None); /// /// The of System.Contract.CreateMultisigAccount. /// Calculates corresponding multisig account scripthash for the given public keys. /// - public static readonly InteropDescriptor System_Contract_CreateMultisigAccount = Register("System.Contract.CreateMultisigAccount", nameof(CreateMultisigAccount), 1 << 8, CallFlags.None); + public static readonly InteropDescriptor System_Contract_CreateMultisigAccount = Register("System.Contract.CreateMultisigAccount", nameof(CreateMultisigAccount), 0, CallFlags.None); /// /// The of System.Contract.NativeOnPersist. @@ -132,8 +132,9 @@ internal protected static UInt160 CreateStandardAccount(ECPoint pubKey) /// The minimum number of correct signatures that need to be provided in order for the verification to pass. /// The public keys of the account. /// The hash of the account. - internal protected static UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) + internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) { + AddGas(CheckSigPrice * pubKeys.Length * ExecFeeFactor); return Contract.CreateMultiSigRedeemScript(m, pubKeys).ToScriptHash(); } From 74012ce6f6c49cdd3c0797d1195244988eae7ba7 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 30 Apr 2022 15:01:11 +0800 Subject: [PATCH 2/7] Add Hardforks --- src/neo/ProtocolSettings.cs | 22 +++++++++++++++++-- .../ApplicationEngine.Contract.cs | 17 +++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/neo/ProtocolSettings.cs b/src/neo/ProtocolSettings.cs index 83d1f9c474..d97c26025b 100644 --- a/src/neo/ProtocolSettings.cs +++ b/src/neo/ProtocolSettings.cs @@ -88,6 +88,8 @@ public record ProtocolSettings /// public IReadOnlyDictionary NativeUpdateHistory { get; init; } + public uint[] Hardforks { get; init; } + /// /// Indicates the amount of gas to distribute during initialization. /// @@ -157,7 +159,8 @@ public record ProtocolSettings [nameof(PolicyContract)] = new[] { 0u }, [nameof(RoleManagement)] = new[] { 0u }, [nameof(OracleContract)] = new[] { 0u } - } + }, + Hardforks = new[] { 0u } }; /// @@ -198,8 +201,23 @@ public static ProtocolSettings Load(IConfigurationSection section) InitialGasDistribution = section.GetValue("InitialGasDistribution", Default.InitialGasDistribution), NativeUpdateHistory = section.GetSection("NativeUpdateHistory").Exists() ? section.GetSection("NativeUpdateHistory").GetChildren().ToDictionary(p => p.Key, p => p.GetChildren().Select(q => uint.Parse(q.Value)).ToArray()) - : Default.NativeUpdateHistory + : Default.NativeUpdateHistory, + Hardforks = section.GetSection("Hardforks").Exists() + ? section.GetSection("Hardforks").GetChildren().Select(p => p.Get()).ToArray() + : Default.Hardforks }; } + + public int GetHardfork(Block block) + { + return GetHardfork(block?.Index); + } + + public int GetHardfork(uint? blockIndex) + { + if (!blockIndex.HasValue) return Hardforks.Length; + int index = Array.BinarySearch(Hardforks, blockIndex.Value); + return index >= 0 ? index + 1 : ~index; + } } } diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index bd4bf7d8c5..0aa9078bab 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -41,7 +41,7 @@ partial class ApplicationEngine /// The of System.Contract.CreateStandardAccount. /// Calculates corresponding account scripthash for the given public key. /// - public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), CheckSigPrice, CallFlags.None); + public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), 0, CallFlags.None); /// /// The of System.Contract.CreateMultisigAccount. @@ -120,8 +120,14 @@ protected internal CallFlags GetCallFlags() /// /// The public key of the account. /// The hash of the account. - internal protected static UInt160 CreateStandardAccount(ECPoint pubKey) + internal protected UInt160 CreateStandardAccount(ECPoint pubKey) { + long fee = ProtocolSettings.GetHardfork(PersistingBlock) switch + { + 0 => 1 << 8, + _ => CheckSigPrice + }; + AddGas(fee * ExecFeeFactor); return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); } @@ -134,7 +140,12 @@ internal protected static UInt160 CreateStandardAccount(ECPoint pubKey) /// The hash of the account. internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) { - AddGas(CheckSigPrice * pubKeys.Length * ExecFeeFactor); + long fee = ProtocolSettings.GetHardfork(PersistingBlock) switch + { + 0 => 1 << 8, + _ => CheckSigPrice * pubKeys.Length + }; + AddGas(fee * ExecFeeFactor); return Contract.CreateMultiSigRedeemScript(m, pubKeys).ToScriptHash(); } From b2c2f39bd7056501bee2612d1001cb4dbd27fe99 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 30 Apr 2022 15:06:16 +0800 Subject: [PATCH 3/7] Fix UT --- tests/neo.UnitTests/SmartContract/UT_InteropService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 0e49b41918..140f94a5e7 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -586,7 +586,7 @@ public void TestContract_Destroy() public void TestContract_CreateStandardAccount() { ECPoint pubkey = ECPoint.Parse("024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e", ECCurve.Secp256r1); - ApplicationEngine.CreateStandardAccount(pubkey).ToArray().ToHexString().Should().Be("c44ea575c5f79638f0e73f39d7bd4b3337c81691"); + GetEngine().CreateStandardAccount(pubkey).ToArray().ToHexString().Should().Be("c44ea575c5f79638f0e73f39d7bd4b3337c81691"); } public static void LogEvent(object sender, LogEventArgs args) From 421fa2758dfe4fbe154d9c9f03c69ca6b37654cb Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Wed, 4 May 2022 09:17:23 +0800 Subject: [PATCH 4/7] Hard fork names --- src/neo/Hardfork.cs | 17 +++++++++++++++++ src/neo/ProtocolSettings.cs | 19 ++++--------------- .../ApplicationEngine.Contract.cs | 16 ++++++---------- src/neo/SmartContract/ApplicationEngine.cs | 9 +++++++++ 4 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 src/neo/Hardfork.cs diff --git a/src/neo/Hardfork.cs b/src/neo/Hardfork.cs new file mode 100644 index 0000000000..dd21e9915f --- /dev/null +++ b/src/neo/Hardfork.cs @@ -0,0 +1,17 @@ +// Copyright (C) 2015-2021 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. + +namespace Neo +{ + public enum Hardfork : byte + { + HF_2712_FixSyscallFees + } +} diff --git a/src/neo/ProtocolSettings.cs b/src/neo/ProtocolSettings.cs index d97c26025b..391a3e1921 100644 --- a/src/neo/ProtocolSettings.cs +++ b/src/neo/ProtocolSettings.cs @@ -14,6 +14,7 @@ using Neo.SmartContract.Native; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; namespace Neo @@ -88,7 +89,7 @@ public record ProtocolSettings /// public IReadOnlyDictionary NativeUpdateHistory { get; init; } - public uint[] Hardforks { get; init; } + public ImmutableDictionary Hardforks { get; init; } /// /// Indicates the amount of gas to distribute during initialization. @@ -160,7 +161,7 @@ public record ProtocolSettings [nameof(RoleManagement)] = new[] { 0u }, [nameof(OracleContract)] = new[] { 0u } }, - Hardforks = new[] { 0u } + Hardforks = ImmutableDictionary.Empty }; /// @@ -203,21 +204,9 @@ public static ProtocolSettings Load(IConfigurationSection section) ? section.GetSection("NativeUpdateHistory").GetChildren().ToDictionary(p => p.Key, p => p.GetChildren().Select(q => uint.Parse(q.Value)).ToArray()) : Default.NativeUpdateHistory, Hardforks = section.GetSection("Hardforks").Exists() - ? section.GetSection("Hardforks").GetChildren().Select(p => p.Get()).ToArray() + ? section.GetSection("Hardforks").GetChildren().ToImmutableDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value)) : Default.Hardforks }; } - - public int GetHardfork(Block block) - { - return GetHardfork(block?.Index); - } - - public int GetHardfork(uint? blockIndex) - { - if (!blockIndex.HasValue) return Hardforks.Length; - int index = Array.BinarySearch(Hardforks, blockIndex.Value); - return index >= 0 ? index + 1 : ~index; - } } } diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 0aa9078bab..0db9e22f2d 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -122,11 +122,9 @@ protected internal CallFlags GetCallFlags() /// The hash of the account. internal protected UInt160 CreateStandardAccount(ECPoint pubKey) { - long fee = ProtocolSettings.GetHardfork(PersistingBlock) switch - { - 0 => 1 << 8, - _ => CheckSigPrice - }; + long fee = IsHardforkEnabled(Hardfork.HF_2712_FixSyscallFees) + ? CheckSigPrice + : 1 << 8; AddGas(fee * ExecFeeFactor); return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); } @@ -140,11 +138,9 @@ internal protected UInt160 CreateStandardAccount(ECPoint pubKey) /// The hash of the account. internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) { - long fee = ProtocolSettings.GetHardfork(PersistingBlock) switch - { - 0 => 1 << 8, - _ => CheckSigPrice * pubKeys.Length - }; + long fee = IsHardforkEnabled(Hardfork.HF_2712_FixSyscallFees) + ? CheckSigPrice * pubKeys.Length + : 1 << 8; AddGas(fee * ExecFeeFactor); return Contract.CreateMultiSigRedeemScript(m, pubKeys).ToScriptHash(); } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index cd07184f02..40a0de72df 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -579,5 +579,14 @@ public void SetState(T state) states ??= new Dictionary(); states[typeof(T)] = state; } + + private bool IsHardforkEnabled(Hardfork hardfork) + { + if (PersistingBlock is null) + return true; + if (!ProtocolSettings.Hardforks.TryGetValue(hardfork, out uint height)) + return true; + return PersistingBlock.Index >= height; + } } } From 15bea615e36a368ef6f27064aa16f247feaeef75 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 4 May 2022 10:15:42 +0200 Subject: [PATCH 5/7] T4 testnet compatible with 3.2.2 https://github.com/neo-project/neo/pull/2712#issuecomment-1116996495 --- src/neo/Hardfork.cs | 5 ++-- src/neo/SmartContract/ApplicationEngine.cs | 2 +- .../Native/ContractManagement.cs | 25 ++++++++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/neo/Hardfork.cs b/src/neo/Hardfork.cs index dd21e9915f..cae9d387e2 100644 --- a/src/neo/Hardfork.cs +++ b/src/neo/Hardfork.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2021 The Neo Project. +// 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 @@ -12,6 +12,7 @@ namespace Neo { public enum Hardfork : byte { - HF_2712_FixSyscallFees + HF_2712_FixSyscallFees, + HF_2653_DeployUpdateCallFlags } } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 40a0de72df..83dde36d72 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -580,7 +580,7 @@ public void SetState(T state) states[typeof(T)] = state; } - private bool IsHardforkEnabled(Hardfork hardfork) + internal bool IsHardforkEnabled(Hardfork hardfork) { if (PersistingBlock is null) return true; diff --git a/src/neo/SmartContract/Native/ContractManagement.cs b/src/neo/SmartContract/Native/ContractManagement.cs index 2a3da77b44..d7ed21779d 100644 --- a/src/neo/SmartContract/Native/ContractManagement.cs +++ b/src/neo/SmartContract/Native/ContractManagement.cs @@ -14,6 +14,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; +using Neo.VM; using Neo.VM.Types; using System; using System.Collections.Generic; @@ -154,15 +155,23 @@ public IEnumerable ListContracts(DataCache snapshot) return snapshot.Find(listContractsPrefix).Select(kvp => kvp.Value.GetInteroperable()); } - [ContractMethod(RequiredCallFlags = CallFlags.All)] + [ContractMethod(RequiredCallFlags = CallFlags.None)] private ContractTask Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest) { return Deploy(engine, nefFile, manifest, StackItem.Null); } - [ContractMethod(RequiredCallFlags = CallFlags.All)] + [ContractMethod(RequiredCallFlags = CallFlags.None)] private async ContractTask Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data) { + CallFlags requiredCallFlags = engine.IsHardforkEnabled(Hardfork.HF_2653_DeployUpdateCallFlags) + ? CallFlags.All + : CallFlags.States | CallFlags.AllowNotify; + + ExecutionContextState state = engine.CurrentContext.GetState(); + if (!state.CallFlags.HasFlag(requiredCallFlags)) + throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); + if (engine.ScriptContainer is not Transaction tx) throw new InvalidOperationException(); if (nefFile.Length == 0) @@ -204,15 +213,23 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ return contract; } - [ContractMethod(RequiredCallFlags = CallFlags.All)] + [ContractMethod(RequiredCallFlags = CallFlags.None)] private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest) { return Update(engine, nefFile, manifest, StackItem.Null); } - [ContractMethod(RequiredCallFlags = CallFlags.All)] + [ContractMethod(RequiredCallFlags = CallFlags.None)] private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data) { + CallFlags requiredCallFlags = engine.IsHardforkEnabled(Hardfork.HF_2653_DeployUpdateCallFlags) + ? CallFlags.All + : CallFlags.States | CallFlags.AllowNotify; + + ExecutionContextState state = engine.CurrentContext.GetState(); + if (!state.CallFlags.HasFlag(requiredCallFlags)) + throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); + if (nefFile is null && manifest is null) throw new ArgumentException(); engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); From 83e7534a475e7c829997008988e151ca61975a32 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 4 May 2022 10:15:42 +0200 Subject: [PATCH 6/7] Revert "T4 testnet compatible with 3.2.2" This reverts commit 15bea615e36a368ef6f27064aa16f247feaeef75. --- src/neo/Hardfork.cs | 5 ++-- src/neo/SmartContract/ApplicationEngine.cs | 2 +- .../Native/ContractManagement.cs | 25 +++---------------- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/neo/Hardfork.cs b/src/neo/Hardfork.cs index cae9d387e2..dd21e9915f 100644 --- a/src/neo/Hardfork.cs +++ b/src/neo/Hardfork.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2021 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 @@ -12,7 +12,6 @@ namespace Neo { public enum Hardfork : byte { - HF_2712_FixSyscallFees, - HF_2653_DeployUpdateCallFlags + HF_2712_FixSyscallFees } } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 83dde36d72..40a0de72df 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -580,7 +580,7 @@ public void SetState(T state) states[typeof(T)] = state; } - internal bool IsHardforkEnabled(Hardfork hardfork) + private bool IsHardforkEnabled(Hardfork hardfork) { if (PersistingBlock is null) return true; diff --git a/src/neo/SmartContract/Native/ContractManagement.cs b/src/neo/SmartContract/Native/ContractManagement.cs index d7ed21779d..2a3da77b44 100644 --- a/src/neo/SmartContract/Native/ContractManagement.cs +++ b/src/neo/SmartContract/Native/ContractManagement.cs @@ -14,7 +14,6 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; -using Neo.VM; using Neo.VM.Types; using System; using System.Collections.Generic; @@ -155,23 +154,15 @@ public IEnumerable ListContracts(DataCache snapshot) return snapshot.Find(listContractsPrefix).Select(kvp => kvp.Value.GetInteroperable()); } - [ContractMethod(RequiredCallFlags = CallFlags.None)] + [ContractMethod(RequiredCallFlags = CallFlags.All)] private ContractTask Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest) { return Deploy(engine, nefFile, manifest, StackItem.Null); } - [ContractMethod(RequiredCallFlags = CallFlags.None)] + [ContractMethod(RequiredCallFlags = CallFlags.All)] private async ContractTask Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data) { - CallFlags requiredCallFlags = engine.IsHardforkEnabled(Hardfork.HF_2653_DeployUpdateCallFlags) - ? CallFlags.All - : CallFlags.States | CallFlags.AllowNotify; - - ExecutionContextState state = engine.CurrentContext.GetState(); - if (!state.CallFlags.HasFlag(requiredCallFlags)) - throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); - if (engine.ScriptContainer is not Transaction tx) throw new InvalidOperationException(); if (nefFile.Length == 0) @@ -213,23 +204,15 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ return contract; } - [ContractMethod(RequiredCallFlags = CallFlags.None)] + [ContractMethod(RequiredCallFlags = CallFlags.All)] private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest) { return Update(engine, nefFile, manifest, StackItem.Null); } - [ContractMethod(RequiredCallFlags = CallFlags.None)] + [ContractMethod(RequiredCallFlags = CallFlags.All)] private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data) { - CallFlags requiredCallFlags = engine.IsHardforkEnabled(Hardfork.HF_2653_DeployUpdateCallFlags) - ? CallFlags.All - : CallFlags.States | CallFlags.AllowNotify; - - ExecutionContextState state = engine.CurrentContext.GetState(); - if (!state.CallFlags.HasFlag(requiredCallFlags)) - throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); - if (nefFile is null && manifest is null) throw new ArgumentException(); engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); From 9be585b568def4e526903870798db5955470a119 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 4 May 2022 10:49:25 +0200 Subject: [PATCH 7/7] Change year --- src/neo/Hardfork.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Hardfork.cs b/src/neo/Hardfork.cs index dd21e9915f..f13132ffe0 100644 --- a/src/neo/Hardfork.cs +++ b/src/neo/Hardfork.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2021 The Neo Project. +// 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