diff --git a/src/Neo/Network/P2P/Payloads/Transaction.cs b/src/Neo/Network/P2P/Payloads/Transaction.cs index 4e59c1b9c5..cae0944bd1 100644 --- a/src/Neo/Network/P2P/Payloads/Transaction.cs +++ b/src/Neo/Network/P2P/Payloads/Transaction.cs @@ -339,11 +339,11 @@ public virtual VerifyResult VerifyStateDependent(ProtocolSettings settings, Data return VerifyResult.InvalidAttribute; attributesFee += attribute.CalculateNetworkFee(snapshot, this); } - long netFeeDatoshi = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee; + var netFeeDatoshi = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee; if (netFeeDatoshi < 0) return VerifyResult.InsufficientFunds; if (netFeeDatoshi > MaxVerificationGas) netFeeDatoshi = MaxVerificationGas; - uint execFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); + var execFeeFactor = NativeContract.Policy.GetExecFeeFactor(settings, snapshot, height); for (int i = 0; i < hashes.Length; i++) { if (IsSignatureContract(Witnesses[i].VerificationScript.Span) && IsSingleSignatureInvocationScript(Witnesses[i].InvocationScript, out var _)) diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index 05562604fc..bc914030e8 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -124,7 +124,7 @@ internal protected UInt160 CreateStandardAccount(ECPoint pubKey) long fee = IsHardforkEnabled(Hardfork.HF_Aspidochelone) ? CheckSigPrice : 1 << 8; - AddFee(fee * ExecFeeFactor); + AddFee(fee * _execFeeFactor); return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); } @@ -141,7 +141,7 @@ internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) long fee = IsHardforkEnabled(Hardfork.HF_Aspidochelone) ? CheckSigPrice * pubKeys.Length : 1 << 8; - AddFee(fee * ExecFeeFactor); + AddFee(fee * _execFeeFactor); return Contract.CreateMultiSigRedeemScript(m, pubKeys).ToScriptHash(); } diff --git a/src/Neo/SmartContract/ApplicationEngine.Crypto.cs b/src/Neo/SmartContract/ApplicationEngine.Crypto.cs index b8fdb62ba0..e006fb3176 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Crypto.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Crypto.cs @@ -69,7 +69,7 @@ protected internal bool CheckMultisig(byte[][] pubkeys, byte[][] signatures) if (n == 0) throw new ArgumentException("pubkeys array cannot be empty."); if (m == 0) throw new ArgumentException("signatures array cannot be empty."); if (m > n) throw new ArgumentException($"signatures count ({m}) cannot be greater than pubkeys count ({n})."); - AddFee(CheckSigPrice * n * ExecFeeFactor); + AddFee(CheckSigPrice * n * _execFeeFactor); try { for (int i = 0, j = 0; i < m && j < n;) diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 2b813338d0..aca7af2b75 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -324,7 +324,7 @@ protected internal BigInteger GetRandom() buffer = nonceData = Cryptography.Helper.Murmur128(nonceData, ProtocolSettings.Network); price = 1 << 4; } - AddFee(price * ExecFeeFactor); + AddFee(price * _execFeeFactor); return new BigInteger(buffer, isUnsigned: true); } @@ -449,7 +449,7 @@ protected internal void BurnGas(long datoshi) { if (datoshi <= 0) throw new InvalidOperationException("GAS must be positive."); - AddFee(datoshi); + AddFee(datoshi * FeeFactor); } /// diff --git a/src/Neo/SmartContract/ApplicationEngine.Storage.cs b/src/Neo/SmartContract/ApplicationEngine.Storage.cs index 36c3769893..db1190afaa 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Storage.cs @@ -256,7 +256,7 @@ protected internal void Put(StorageContext context, byte[] key, byte[] value) else newDataSize = (item.Value.Length - 1) / 4 + 1 + value.Length - item.Value.Length; } - AddFee(newDataSize * StoragePrice); + AddFee(newDataSize * StoragePrice * FeeFactor); item.Value = value; } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index e3b10b746d..2d66654fee 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -66,15 +66,19 @@ public partial class ApplicationEngine : ExecutionEngine private static Dictionary? services; // Total amount of GAS spent to execute. - // In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi - private readonly long _feeAmount; + // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS + private readonly BigInteger _feeAmount; + private BigInteger _feeConsumed; + // Decimals for fee calculation + public const uint FeeFactor = 10000; private Dictionary? states; private readonly DataCache originalSnapshotCache; private List? notifications; private List? disposables; private readonly Dictionary invocationCounter = new(); private readonly Dictionary contractTasks = new(); - internal readonly uint ExecFeeFactor; + // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS + private readonly BigInteger _execFeeFactor; // In the unit of datoshi, 1 datoshi = 1e-8 GAS internal readonly uint StoragePrice; private byte[] nonceData; @@ -132,19 +136,29 @@ public partial class ApplicationEngine : ExecutionEngine /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi /// [Obsolete("This property is deprecated. Use FeeConsumed instead.")] - public long GasConsumed { get; protected set; } = 0; + public long GasConsumed => FeeConsumed; + + /// + /// Exec Fee Factor. In the unit of datoshi, 1 datoshi = 1e-8 GAS + /// + internal long ExecFeeFactor => (long)_execFeeFactor.DivideCeiling(FeeFactor); /// /// GAS spent to execute. /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi /// - public long FeeConsumed { get; protected set; } = 0; + public long FeeConsumed => (long)_feeConsumed.DivideCeiling(FeeFactor); + + /// + /// Exec Fee Factor. In the unit of picoGAS, 1 picoGAS = 1e-12 GAS + /// + internal BigInteger ExecFeePicoFactor => _execFeeFactor; /// /// The remaining GAS that can be spent in order to complete the execution. /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi /// - public long GasLeft => _feeAmount - FeeConsumed; + public long GasLeft => (long)((_feeAmount - _feeConsumed) / FeeFactor); /// /// The exception that caused the execution to terminate abnormally. This field could be if no exception is thrown. @@ -206,17 +220,31 @@ protected ApplicationEngine( originalSnapshotCache = snapshotCache; PersistingBlock = persistingBlock; ProtocolSettings = settings; - _feeAmount = gas; + _feeAmount = gas * FeeFactor; // PicoGAS Diagnostic = diagnostic; nonceData = container is Transaction tx ? tx.Hash.ToArray()[..16] : new byte[16]; if (snapshotCache is null || persistingBlock?.Index == 0) { - ExecFeeFactor = PolicyContract.DefaultExecFeeFactor; + _execFeeFactor = PolicyContract.DefaultExecFeeFactor * FeeFactor; // Add fee decimals StoragePrice = PolicyContract.DefaultStoragePrice; } else { - ExecFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshotCache); + var persistingIndex = persistingBlock?.Index ?? NativeContract.Ledger.CurrentIndex(snapshotCache); + + if (settings == null || !settings.IsHardforkEnabled(Hardfork.HF_Faun, persistingIndex)) + { + // The values doesn't have the decimals stored + _execFeeFactor = NativeContract.Policy.GetExecFeeFactor(this) * FeeFactor; + } + else + { + // The values have the decimals stored starting from OnPersist of Faun's block. + _execFeeFactor = NativeContract.Policy.GetExecPicoFeeFactor(this); + if (trigger == TriggerType.OnPersist && persistingIndex > 0 && !settings.IsHardforkEnabled(Hardfork.HF_Faun, persistingIndex - 1)) + _execFeeFactor *= FeeFactor; + } + StoragePrice = NativeContract.Policy.GetStoragePrice(snapshotCache); } @@ -297,13 +325,11 @@ protected static void OnSysCall(ExecutionEngine engine, Instruction instruction) /// /// Adds GAS to and checks if it has exceeded the maximum limit. /// - /// The amount of GAS, in the unit of datoshi, 1 datoshi = 1e-8 GAS, to be added. - protected internal void AddFee(long datoshi) + /// The amount of GAS, in the unit of picoGAS, 1 picoGAS = 1e-12 GAS, to be added. + protected internal void AddFee(BigInteger picoGas) { -#pragma warning disable CS0618 // Type or member is obsolete - FeeConsumed = GasConsumed = checked(FeeConsumed + datoshi); -#pragma warning restore CS0618 // Type or member is obsolete - if (FeeConsumed > _feeAmount) + _feeConsumed = _feeConsumed + picoGas; + if (_feeConsumed > _feeAmount) throw new InvalidOperationException("Insufficient GAS."); } @@ -657,7 +683,7 @@ internal protected void ValidateCallFlags(CallFlags requiredCallFlags) protected virtual void OnSysCall(InteropDescriptor descriptor) { ValidateCallFlags(descriptor.RequiredCallFlags); - AddFee(descriptor.FixedPrice * ExecFeeFactor); + AddFee(descriptor.FixedPrice * _execFeeFactor); object?[] parameters = new object?[descriptor.Parameters.Count]; for (int i = 0; i < parameters.Length; i++) @@ -671,7 +697,7 @@ protected virtual void OnSysCall(InteropDescriptor descriptor) protected override void PreExecuteInstruction(Instruction instruction) { Diagnostic?.PreExecuteInstruction(instruction); - AddFee(ExecFeeFactor * OpCodePriceTable[(byte)instruction.OpCode]); + AddFee(_execFeeFactor * OpCodePriceTable[(byte)instruction.OpCode]); } protected override void PostExecuteInstruction(Instruction instruction) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index d71771189e..f4c2ccd03f 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -267,10 +267,10 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ if (manifest.Length == 0) throw new ArgumentException($"Manifest length cannot be zero."); - engine.AddFee(Math.Max( - engine.StoragePrice * (nefFile.Length + manifest.Length), - GetMinimumDeploymentFee(engine.SnapshotCache) - )); + // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS + engine.AddFee(BigInteger.Max(engine.StoragePrice * (nefFile.Length + manifest.Length), + GetMinimumDeploymentFee(engine.SnapshotCache)) + * ApplicationEngine.FeeFactor); NefFile nef = nefFile.AsSerializable(); ContractManifest parsedManifest = ContractManifest.Parse(manifest); @@ -336,7 +336,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man if (nefFile is null && manifest is null) throw new ArgumentException("NEF file and manifest cannot both be null."); - engine.AddFee(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); + engine.AddFee(engine.StoragePrice * ApplicationEngine.FeeFactor * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); var contractState = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Contract, engine.CallingScriptHash!)) ?? throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}"); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index dc514468a4..7453ceb947 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -432,8 +432,10 @@ internal async void Invoke(ApplicationEngine engine, byte version) var state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); - // In the unit of datoshi, 1 datoshi = 1e-8 GAS - engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice); + // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS + engine.AddFee( + (method.CpuFee * engine.ExecFeePicoFactor) + + (method.StorageFee * engine.StoragePrice * ApplicationEngine.FeeFactor)); List parameters = new(); if (method.NeedApplicationEngine) parameters.Add(engine); if (method.NeedSnapshot) parameters.Add(engine.SnapshotCache); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 5032aeb409..7f81067aa6 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -406,8 +406,8 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) if (!engine.IsHardforkEnabled(Hardfork.HF_Echidna) && !engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; - // In the unit of datoshi, 1 datoshi = 1e-8 GAS - engine.AddFee(GetRegisterPrice(engine.SnapshotCache)); + // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS + engine.AddFee(GetRegisterPrice(engine.SnapshotCache) * ApplicationEngine.FeeFactor); return RegisterInternal(engine, pubkey); } diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index 5dfe9992f6..06aa647e63 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -228,10 +228,10 @@ private async ContractTask Request(ApplicationEngine engine, string url, string? if (gasForResponse < 0_10000000) throw new ArgumentException($"gasForResponse {gasForResponse} must be at least 0.1 datoshi."); - engine.AddFee(GetPrice(engine.SnapshotCache)); + engine.AddFee(GetPrice(engine.SnapshotCache) * ApplicationEngine.FeeFactor); //Mint gas for the response - engine.AddFee(gasForResponse); + engine.AddFee(gasForResponse * ApplicationEngine.FeeFactor); await GAS.Mint(engine, Hash, gasForResponse, false); //Increase the request id diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 3a1c8fa3a5..11f5c3e7de 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -53,7 +53,7 @@ public sealed class PolicyContract : NativeContract /// /// The maximum execution fee factor that the committee can set. /// - public const uint MaxExecFeeFactor = 100; + public const ulong MaxExecFeeFactor = 100; /// /// The maximum fee for attribute that the committee can set. @@ -132,6 +132,16 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor engine.SnapshotCache.Add(_maxValidUntilBlockIncrement, new StorageItem(engine.ProtocolSettings.MaxValidUntilBlockIncrement)); engine.SnapshotCache.Add(_maxTraceableBlocks, new StorageItem(engine.ProtocolSettings.MaxTraceableBlocks)); } + + // After Faun Hardfork the unit it's pico-gas, before it was datoshi + + if (hardfork == Hardfork.HF_Faun) + { + // Add decimals to exec fee factor + var item = engine.SnapshotCache.TryGet(_execFeeFactor) ?? + throw new InvalidOperationException("Policy was not initialized"); + item.Set((uint)(BigInteger)item * ApplicationEngine.FeeFactor); + } return ContractTask.CompletedTask; } @@ -149,12 +159,34 @@ public long GetFeePerByte(IReadOnlyStore snapshot) /// /// Gets the execution fee factor. This is a multiplier that can be adjusted by the committee to adjust the system fees for transactions. /// - /// The snapshot used to read data. + /// The execution engine. /// The execution fee factor. [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] - public uint GetExecFeeFactor(IReadOnlyStore snapshot) + public uint GetExecFeeFactor(ApplicationEngine engine) + { + if (engine.IsHardforkEnabled(Hardfork.HF_Faun)) + return (uint)((BigInteger)engine.SnapshotCache[_execFeeFactor] / ApplicationEngine.FeeFactor); + + return (uint)(BigInteger)engine.SnapshotCache[_execFeeFactor]; + } + + public long GetExecFeeFactor(ProtocolSettings settings, IReadOnlyStore snapshot, uint index) + { + if (settings.IsHardforkEnabled(Hardfork.HF_Faun, index)) + return (long)((BigInteger)snapshot[_execFeeFactor] / ApplicationEngine.FeeFactor); + + return (long)(BigInteger)snapshot[_execFeeFactor]; + } + + /// + /// Gets the execution fee factor. This is a multiplier that can be adjusted by the committee to adjust the system fees for transactions. + /// + /// The execution engine. + /// The execution fee factor in the unit of pico Gas. 1 picoGAS = 1e-12 GAS + [ContractMethod(Hardfork.HF_Faun, CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] + public BigInteger GetExecPicoFeeFactor(ApplicationEngine engine) { - return (uint)(BigInteger)snapshot[_execFeeFactor]; + return (BigInteger)engine.SnapshotCache[_execFeeFactor]; } /// @@ -341,12 +373,15 @@ private void SetFeePerByte(ApplicationEngine engine, long value) } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] - private void SetExecFeeFactor(ApplicationEngine engine, uint value) + private void SetExecFeeFactor(ApplicationEngine engine, ulong value) { - if (value == 0 || value > MaxExecFeeFactor) - throw new ArgumentOutOfRangeException(nameof(value), $"ExecFeeFactor must be between [1, {MaxExecFeeFactor}], got {value}"); - AssertCommittee(engine); + // After FAUN hardfork, the max exec fee factor is with decimals defined in ApplicationEngine.FeeFactor + var maxValue = engine.IsHardforkEnabled(Hardfork.HF_Faun) ? ApplicationEngine.FeeFactor * MaxExecFeeFactor : MaxExecFeeFactor; + if (value == 0 || value > maxValue) + throw new ArgumentOutOfRangeException(nameof(value), $"ExecFeeFactor must be between [1, {maxValue}], got {value}"); + + AssertCommittee(engine); engine.SnapshotCache.GetAndChange(_execFeeFactor)!.Set(value); } diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index e58cdd7ed1..5427ae7d73 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -19,6 +19,7 @@ using Neo.VM; using Neo.VM.Types; using System; +using System.Numerics; using static Neo.SmartContract.Helper; using Array = System.Array; @@ -116,8 +117,8 @@ public static long CalculateNetworkFee(this Transaction tx, DataCache snapshot, int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize() + tx.Script.GetVarSize() + hashes.Length.GetVarSize(); int index = -1; - var execFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); - long networkFee = 0; + var execFeeFactor = NativeContract.Policy.GetExecFeeFactor(settings, snapshot, NativeContract.Ledger.CurrentIndex(snapshot) + 1); + BigInteger networkFee = 0; foreach (var hash in hashes) { index++; @@ -226,7 +227,7 @@ public static long CalculateNetworkFee(this Transaction tx, DataCache snapshot, { networkFee += attr.CalculateNetworkFee(snapshot, tx); } - return networkFee; + return (long)networkFee; } } } diff --git a/tests/Neo.UnitTests/GasTests/Fixtures/StdLib.json b/tests/Neo.UnitTests/GasTests/Fixtures/StdLib.json index 6255549683..f1226d92ef 100644 --- a/tests/Neo.UnitTests/GasTests/Fixtures/StdLib.json +++ b/tests/Neo.UnitTests/GasTests/Fixtures/StdLib.json @@ -1,6 +1,6 @@ [ { - + "Name": "Test Stdlib with default execution fee", "Execute": [ { "Script": "ERHAHwwEaXRvYQwUwO85zuDk6SXGwqBqeeFEDdhvzqxBYn1bUg==", @@ -11,5 +11,25 @@ "Fee": 1047210 } ] + }, + { + "Name" : "Test Stdlib with half default execution fee", + "Environment": { + "Policy": { + "ExecutionFee": 150000, + "StorageFee": 100000, + "FeePerByte": 1000 + } + }, + "Execute": [ + { + "Script": "ERHAHwwEaXRvYQwUwO85zuDk6SXGwqBqeeFEDdhvzqxBYn1bUg==", + "Fee": 583980 + }, + { + "Script": "DAExEcAfDARhdG9pDBTA7znO4OTpJcbCoGp54UQN2G/OrEFifVtS", + "Fee": 523605 + } + ] } ] diff --git a/tests/Neo.UnitTests/GasTests/GasFixturesTests.cs b/tests/Neo.UnitTests/GasTests/GasFixturesTests.cs index 5ff674dfb2..9e6256dea0 100644 --- a/tests/Neo.UnitTests/GasTests/GasFixturesTests.cs +++ b/tests/Neo.UnitTests/GasTests/GasFixturesTests.cs @@ -10,11 +10,13 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; +using Neo.VM; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -75,6 +77,40 @@ public static void AssertFixture(GasTestFixture fixture, DataCache snapshot) Transactions = null! }; + // Set state + + if (fixture.Environment != null) + { + // Set fee values + + using var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep17NativeContractExtensions.ManualWitness(NativeContract.NEO.GetCommitteeAddress(snapshot)), + snapshot, persistingBlock, settings: TestProtocolSettings.Default); + + // Build set script + + var script = new ScriptBuilder(); + script.EmitDynamicCall(NativeContract.Policy.Hash, "setFeePerByte", fixture.Environment.Policy.FeePerByte); + script.EmitDynamicCall(NativeContract.Policy.Hash, "setStoragePrice", fixture.Environment.Policy.StorageFee); + script.EmitDynamicCall(NativeContract.Policy.Hash, "setExecFeeFactor", fixture.Environment.Policy.ExecutionFee); + + engine.LoadScript(script.ToArray()); + Assert.AreEqual(VMState.HALT, engine.Execute()); + + // Check storage + + if (fixture.Environment.Storage != null) + { + foreach (var preStore in fixture.Environment.Storage) + { + var key = new StorageKey(Convert.FromBase64String(preStore.Key)); + var value = Convert.FromBase64String(preStore.Value); + + snapshot.Add(key, value); + } + } + } + // Signature List signatures = []; diff --git a/tests/Neo.UnitTests/GasTests/GasTestFixture.cs b/tests/Neo.UnitTests/GasTests/GasTestFixture.cs index 1fc8d9741f..8fa7607e27 100644 --- a/tests/Neo.UnitTests/GasTests/GasTestFixture.cs +++ b/tests/Neo.UnitTests/GasTests/GasTestFixture.cs @@ -9,7 +9,11 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using System.Collections.Generic; using System.Numerics; @@ -29,15 +33,32 @@ public class PreExecutionData public Dictionary Storage { get; set; } = []; } + public class PolicyValues + { + public BigInteger ExecutionFee { get; set; } = PolicyContract.DefaultExecFeeFactor * ApplicationEngine.FeeFactor; + public BigInteger StorageFee { get; set; } = PolicyContract.DefaultStoragePrice; + public BigInteger FeePerByte { get; set; } = PolicyContract.DefaultFeePerByte; + } + + public class EnvironmentState + { + public PolicyValues? Policy { get; set; } + public Dictionary? Storage { get; set; } + } + public class NeoExecution { public byte[] Script { get; set; } = []; public BigInteger Fee { get; set; } = BigInteger.Zero; + + [JsonConverter(typeof(StringEnumConverter))] public VMState State { get; set; } = VMState.HALT; } + public string? Name { get; set; } public SignatureData? Signature { get; set; } = null; public PreExecutionData? PreExecution { get; set; } = null; + public EnvironmentState? Environment { get; set; } = null; public List Execute { get; set; } = []; } } diff --git a/tests/Neo.UnitTests/GasTests/GenerateGasFixturesTests.cs b/tests/Neo.UnitTests/GasTests/GenerateGasFixturesTests.cs index 4ee8d24daf..581d38f3d2 100644 --- a/tests/Neo.UnitTests/GasTests/GenerateGasFixturesTests.cs +++ b/tests/Neo.UnitTests/GasTests/GenerateGasFixturesTests.cs @@ -23,8 +23,9 @@ public class GenerateGasFixturesTests [TestMethod] public void StdLibTest() { - var fixture = new GasTestFixture() + var fixtureA = new GasTestFixture() { + Name = "Test Stdlib with default execution fee", Execute = [ new () @@ -42,7 +43,36 @@ public void StdLibTest() ] }; - var json = JsonConvert.SerializeObject(fixture); + // With half execution fee + + var fixtureB = new GasTestFixture() + { + Name = "Test Stdlib with half default execution fee", + Environment = new GasTestFixture.EnvironmentState() + { + Policy = new GasTestFixture.PolicyValues() + { + ExecutionFee = 15_0000 + } + }, + Execute = + [ + new () + { + // itoa + Script = new ScriptBuilder().EmitDynamicCall(NativeContract.StdLib.Hash, "itoa", [1]).ToArray(), + Fee = 583980 + }, + new () + { + // atoi + Script = new ScriptBuilder().EmitDynamicCall(NativeContract.StdLib.Hash, "atoi", ["1"]).ToArray(), + Fee = 523605 + } + ] + }; + + var json = JsonConvert.SerializeObject(new GasTestFixture[] { fixtureA, fixtureB }); Assert.IsNotNull(json); } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 538ebdeeef..d9770024f5 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -189,7 +189,9 @@ public void FeeIsMultiSigContract() // Check + long feePerByte = 0; long verificationGas = 0; + foreach (var witness in tx.Witnesses) { using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, @@ -200,9 +202,10 @@ public void FeeIsMultiSigContract() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + var sizeGas = tx.Size * feePerByte; Assert.AreEqual(1967100, verificationGas); Assert.AreEqual(348000, sizeGas); Assert.AreEqual(2315100, tx.NetworkFee); @@ -264,7 +267,9 @@ public void FeeIsSignatureContractDetailed() // Check + long feePerByte = 0; long verificationGas = 0; + foreach (var witness in tx.Witnesses) { using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, @@ -275,6 +280,7 @@ public void FeeIsSignatureContractDetailed() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } // ------------------ @@ -299,8 +305,8 @@ public void FeeIsSignatureContractDetailed() // I + II + III + IV Assert.AreEqual(25 + 22 + 1 + 88 + 109, tx.Size); - Assert.AreEqual(1000, NativeContract.Policy.GetFeePerByte(snapshotCache)); - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + Assert.AreEqual(1000, feePerByte); + var sizeGas = tx.Size * feePerByte; // final check: verification_cost and tx_size Assert.AreEqual(245000, sizeGas); @@ -369,7 +375,9 @@ public void FeeIsSignatureContract_TestScope_Global() Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check + long feePerByte = 0; long verificationGas = 0; + foreach (var witness in tx.Witnesses) { using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, @@ -380,9 +388,10 @@ public void FeeIsSignatureContract_TestScope_Global() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + var sizeGas = tx.Size * feePerByte; // final check on sum: verification_cost + tx_size Assert.AreEqual(1228520, verificationGas + sizeGas); // final assert @@ -449,6 +458,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check + long feePerByte = 0; long verificationGas = 0; foreach (var witness in tx.Witnesses) { @@ -460,9 +470,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + var sizeGas = tx.Size * feePerByte; // final check on sum: verification_cost + tx_size Assert.AreEqual(1249520, verificationGas + sizeGas); // final assert @@ -533,7 +544,9 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check + long feePerByte = 0; long verificationGas = 0; + foreach (var witness in tx.Witnesses) { using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, @@ -544,9 +557,10 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + var sizeGas = tx.Size * feePerByte; // final check on sum: verification_cost + tx_size Assert.AreEqual(1249520, verificationGas + sizeGas); // final assert @@ -664,7 +678,9 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check + long feePerByte = 0; long verificationGas = 0; + foreach (var witness in tx.Witnesses) { using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, @@ -675,9 +691,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + var sizeGas = tx.Size * feePerByte; // final check on sum: verification_cost + tx_size Assert.AreEqual(1269520, verificationGas + sizeGas); // final assert @@ -1049,6 +1066,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check + long feePerByte = 0; long verificationGas = 0; foreach (var witness in tx.Witnesses) { @@ -1060,9 +1078,10 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() Assert.HasCount(1, engine.ResultStack); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.FeeConsumed; + feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); + var sizeGas = tx.Size * feePerByte; // final check on sum: verification_cost + tx_size Assert.AreEqual(1228520, verificationGas + sizeGas); // final assert diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 03f58a8dbd..a811505502 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -48,7 +48,7 @@ public void TestSetup() {"LedgerContract", """{"id":-4,"updatecounter":0,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"currentHash","parameters":[],"returntype":"Hash256","offset":0,"safe":true},{"name":"currentIndex","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlock","parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","offset":14,"safe":true},{"name":"getTransaction","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":21,"safe":true},{"name":"getTransactionFromBlock","parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getTransactionHeight","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":35,"safe":true},{"name":"getTransactionSigners","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":42,"safe":true},{"name":"getTransactionVMState","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":49,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"NeoToken", """{"id":-5,"updatecounter":0,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"NeoToken","groups":[],"features":{},"supportedstandards":["NEP-17","NEP-27"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getAccountState","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","offset":14,"safe":true},{"name":"getAllCandidates","parameters":[],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"getCandidateVote","parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","offset":28,"safe":true},{"name":"getCandidates","parameters":[],"returntype":"Array","offset":35,"safe":true},{"name":"getCommittee","parameters":[],"returntype":"Array","offset":42,"safe":true},{"name":"getCommitteeAddress","parameters":[],"returntype":"Hash160","offset":49,"safe":true},{"name":"getGasPerBlock","parameters":[],"returntype":"Integer","offset":56,"safe":true},{"name":"getNextBlockValidators","parameters":[],"returntype":"Array","offset":63,"safe":true},{"name":"getRegisterPrice","parameters":[],"returntype":"Integer","offset":70,"safe":true},{"name":"onNEP17Payment","parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","offset":77,"safe":false},{"name":"registerCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":84,"safe":false},{"name":"setGasPerBlock","parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","offset":91,"safe":false},{"name":"setRegisterPrice","parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","offset":98,"safe":false},{"name":"symbol","parameters":[],"returntype":"String","offset":105,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":112,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":119,"safe":false},{"name":"unclaimedGas","parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","offset":126,"safe":true},{"name":"unregisterCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":133,"safe":false},{"name":"vote","parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","offset":140,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"GasToken", """{"id":-6,"updatecounter":0,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, - {"PolicyContract", """{"id":-7,"updatecounter":0,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":2208257578},"manifest":{"name":"PolicyContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"blockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":0,"safe":false},{"name":"getAttributeFee","parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlockedAccounts","parameters":[],"returntype":"InteropInterface","offset":14,"safe":true},{"name":"getExecFeeFactor","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"getFeePerByte","parameters":[],"returntype":"Integer","offset":28,"safe":true},{"name":"getMaxTraceableBlocks","parameters":[],"returntype":"Integer","offset":35,"safe":true},{"name":"getMaxValidUntilBlockIncrement","parameters":[],"returntype":"Integer","offset":42,"safe":true},{"name":"getMillisecondsPerBlock","parameters":[],"returntype":"Integer","offset":49,"safe":true},{"name":"getStoragePrice","parameters":[],"returntype":"Integer","offset":56,"safe":true},{"name":"isBlocked","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":63,"safe":true},{"name":"setAttributeFee","parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","offset":70,"safe":false},{"name":"setExecFeeFactor","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":77,"safe":false},{"name":"setFeePerByte","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":84,"safe":false},{"name":"setMaxTraceableBlocks","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":91,"safe":false},{"name":"setMaxValidUntilBlockIncrement","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":98,"safe":false},{"name":"setMillisecondsPerBlock","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":105,"safe":false},{"name":"setStoragePrice","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":112,"safe":false},{"name":"unblockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":119,"safe":false}],"events":[{"name":"MillisecondsPerBlockChanged","parameters":[{"name":"old","type":"Integer"},{"name":"new","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"PolicyContract", """{"id":-7,"updatecounter":0,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":65467259},"manifest":{"name":"PolicyContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"blockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":0,"safe":false},{"name":"getAttributeFee","parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlockedAccounts","parameters":[],"returntype":"InteropInterface","offset":14,"safe":true},{"name":"getExecFeeFactor","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"getExecPicoFeeFactor","parameters":[],"returntype":"Integer","offset":28,"safe":true},{"name":"getFeePerByte","parameters":[],"returntype":"Integer","offset":35,"safe":true},{"name":"getMaxTraceableBlocks","parameters":[],"returntype":"Integer","offset":42,"safe":true},{"name":"getMaxValidUntilBlockIncrement","parameters":[],"returntype":"Integer","offset":49,"safe":true},{"name":"getMillisecondsPerBlock","parameters":[],"returntype":"Integer","offset":56,"safe":true},{"name":"getStoragePrice","parameters":[],"returntype":"Integer","offset":63,"safe":true},{"name":"isBlocked","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":70,"safe":true},{"name":"setAttributeFee","parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","offset":77,"safe":false},{"name":"setExecFeeFactor","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":84,"safe":false},{"name":"setFeePerByte","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":91,"safe":false},{"name":"setMaxTraceableBlocks","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":98,"safe":false},{"name":"setMaxValidUntilBlockIncrement","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":105,"safe":false},{"name":"setMillisecondsPerBlock","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":112,"safe":false},{"name":"setStoragePrice","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":119,"safe":false},{"name":"unblockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":126,"safe":false}],"events":[{"name":"MillisecondsPerBlockChanged","parameters":[{"name":"old","type":"Integer"},{"name":"new","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"RoleManagement", """{"id":-8,"updatecounter":0,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"designateAsRole","parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","offset":0,"safe":false},{"name":"getDesignatedByRole","parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","offset":7,"safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"},{"name":"Old","type":"Array"},{"name":"New","type":"Array"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"OracleContract", """{"id":-9,"updatecounter":0,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"finish","parameters":[],"returntype":"Void","offset":0,"safe":false},{"name":"getPrice","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"request","parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","offset":14,"safe":false},{"name":"setPrice","parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","offset":21,"safe":false},{"name":"verify","parameters":[],"returntype":"Boolean","offset":28,"safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"Notary", """{"id":-10,"updatecounter":0,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","groups":[],"features":{},"supportedstandards":["NEP-27"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"expirationOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":7,"safe":true},{"name":"getMaxNotValidBeforeDelta","parameters":[],"returntype":"Integer","offset":14,"safe":true},{"name":"lockDepositUntil","parameters":[{"name":"account","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","offset":21,"safe":false},{"name":"onNEP17Payment","parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","offset":28,"safe":false},{"name":"setMaxNotValidBeforeDelta","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":35,"safe":false},{"name":"verify","parameters":[{"name":"signature","type":"ByteArray"}],"returntype":"Boolean","offset":42,"safe":true},{"name":"withdraw","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","offset":49,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""} diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 07dd41df5c..ba0471e1a1 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -196,7 +196,7 @@ public void Check_SetBaseExecFee() Assert.ThrowsExactly(() => { NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block, - "setExecFeeFactor", new ContractParameter(ContractParameterType.Integer) { Value = 100500 }); + "setExecFeeFactor", new ContractParameter(ContractParameterType.Integer) { Value = 100500_0000 }); }); ret = NativeContract.Policy.Call(snapshot, "getExecFeeFactor"); @@ -205,7 +205,7 @@ public void Check_SetBaseExecFee() // Proper set ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block, - "setExecFeeFactor", new ContractParameter(ContractParameterType.Integer) { Value = 50 }); + "setExecFeeFactor", new ContractParameter(ContractParameterType.Integer) { Value = 50_0000 }); Assert.IsTrue(ret.IsNull); ret = NativeContract.Policy.Call(snapshot, "getExecFeeFactor");