diff --git a/src/neo/Hardfork.cs b/src/neo/Hardfork.cs new file mode 100644 index 0000000000..f13132ffe0 --- /dev/null +++ b/src/neo/Hardfork.cs @@ -0,0 +1,17 @@ +// 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. + +namespace Neo +{ + public enum Hardfork : byte + { + HF_2712_FixSyscallFees + } +} diff --git a/src/neo/ProtocolSettings.cs b/src/neo/ProtocolSettings.cs index 83d1f9c474..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,6 +89,8 @@ public record ProtocolSettings /// public IReadOnlyDictionary NativeUpdateHistory { get; init; } + public ImmutableDictionary Hardforks { get; init; } + /// /// Indicates the amount of gas to distribute during initialization. /// @@ -157,7 +160,8 @@ public record ProtocolSettings [nameof(PolicyContract)] = new[] { 0u }, [nameof(RoleManagement)] = new[] { 0u }, [nameof(OracleContract)] = new[] { 0u } - } + }, + Hardforks = ImmutableDictionary.Empty }; /// @@ -198,7 +202,10 @@ 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().ToImmutableDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value)) + : Default.Hardforks }; } } diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index ed1ecde3b5..0db9e22f2d 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), 0, 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. @@ -120,8 +120,12 @@ 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 = IsHardforkEnabled(Hardfork.HF_2712_FixSyscallFees) + ? CheckSigPrice + : 1 << 8; + AddGas(fee * ExecFeeFactor); return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); } @@ -132,8 +136,12 @@ 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) { + 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; + } } } 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)