diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 99ecd41e29..5b68a9de3f 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -47,6 +47,7 @@ public sealed class NeoToken : FungibleToken private const byte Prefix_Candidate = 33; private const byte Prefix_Committee = 14; private const byte Prefix_GasPerBlock = 29; + private const byte Prefix_GasPerBlockCurrent = 30; private const byte Prefix_RegisterPrice = 13; private const byte Prefix_VoterRewardPerCommittee = 23; @@ -187,6 +188,7 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor 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_GasPerBlockCurrent), new StorageItem(new GasPerBlock() { Gas = 5 * GAS.Factor, PreviousGas = 5 * GAS.Factor, Index = 0 })); engine.Snapshot.Add(CreateStorageKey(Prefix_RegisterPrice), new StorageItem(1000 * GAS.Factor)); return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); } @@ -265,9 +267,18 @@ private void SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) throw new ArgumentOutOfRangeException(nameof(gasPerBlock)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - uint index = engine.PersistingBlock.Index + 1; - StorageItem entry = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(index), () => new StorageItem(gasPerBlock)); + var gp = new GasPerBlock() { Gas = gasPerBlock, Index = engine.PersistingBlock.Index + 1 }; + + var entry = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(gp.Index), () => new StorageItem(gasPerBlock)); entry.Set(gasPerBlock); + + // Set current entry + + entry = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_GasPerBlockCurrent), () => new StorageItem(gp)); + var gpCurrent = entry.GetInteroperable(); + gpCurrent.PreviousGas = gpCurrent.Gas; + gpCurrent.Gas = gasPerBlock; + gpCurrent.Index = gp.Index; } /// @@ -278,7 +289,18 @@ private void SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public BigInteger GetGasPerBlock(DataCache snapshot) { - return GetSortedGasRecords(snapshot, Ledger.CurrentIndex(snapshot) + 1).First().GasPerBlock; + var gp = snapshot.TryGet(CreateStorageKey(Prefix_GasPerBlockCurrent)).GetInteroperable(); + + if (gp.Index <= Ledger.CurrentIndex(snapshot)) + { + return gp.Gas; + } + else + { + return gp.PreviousGas; + } + + //return GetSortedGasRecords(snapshot, Ledger.CurrentIndex(snapshot) + 1).First().GasPerBlock; } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] @@ -625,6 +647,26 @@ protected override StackItem ElementToStackItem((ECPoint PublicKey, BigInteger V } } + private record GasPerBlock : IInteroperable + { + public uint Index; + public BigInteger Gas; + public BigInteger PreviousGas; + + public void FromStackItem(StackItem stackItem) + { + Struct @struct = (Struct)stackItem; + Index = (uint)@struct[0].GetInteger(); + Gas = @struct[1].GetInteger(); + PreviousGas = @struct[2].GetInteger(); + } + + public StackItem ToStackItem(ReferenceCounter referenceCounter) + { + return new Struct(referenceCounter) { Index, Gas, PreviousGas }; + } + } + private record GasDistribution { public UInt160 Account { get; init; }