From 31979f111fcf2fbeeae4891791e71e83e9995733 Mon Sep 17 00:00:00 2001 From: nan01ab Date: Sun, 8 Dec 2024 00:17:04 +0800 Subject: [PATCH] feat: add readonly StorageKeys to eliminate some allocations --- .../SmartContract/Native/LedgerContract.cs | 13 +++++--- src/Neo/SmartContract/Native/NeoToken.cs | 19 +++++++----- .../SmartContract/Native/PolicyContract.cs | 30 ++++++++++++------- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index b10b7b7f0d..ec88701d9c 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -33,7 +33,12 @@ public sealed class LedgerContract : NativeContract private const byte Prefix_Block = 5; private const byte Prefix_Transaction = 11; - internal LedgerContract() : base() { } + private readonly StorageKey _currentBlock; + + internal LedgerContract() : base() + { + _currentBlock = CreateStorageKey(Prefix_CurrentBlock); + } internal override ContractTask OnPersistAsync(ApplicationEngine engine) { @@ -68,7 +73,7 @@ internal override ContractTask OnPersistAsync(ApplicationEngine engine) internal override ContractTask PostPersistAsync(ApplicationEngine engine) { - HashIndexState state = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable(); + HashIndexState state = engine.SnapshotCache.GetAndChange(_currentBlock, () => new StorageItem(new HashIndexState())).GetInteroperable(); state.Hash = engine.PersistingBlock.Hash; state.Index = engine.PersistingBlock.Index; return ContractTask.CompletedTask; @@ -116,7 +121,7 @@ public UInt256 CurrentHash(DataCache snapshot) if (snapshot is null) throw new ArgumentNullException(nameof(snapshot)); - return snapshot[CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable().Hash; + return snapshot[_currentBlock].GetInteroperable().Hash; } /// @@ -130,7 +135,7 @@ public uint CurrentIndex(DataCache snapshot) if (snapshot is null) throw new ArgumentNullException(nameof(snapshot)); - return snapshot[CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable().Index; + return snapshot[_currentBlock].GetInteroperable().Index; } /// diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 85309b4246..f0321897f2 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -55,6 +55,9 @@ public sealed class NeoToken : FungibleToken private const byte CommitteeRewardRatio = 10; private const byte VoterRewardRatio = 80; + private readonly StorageKey _votersCount; + private readonly StorageKey _registerPrice; + [ContractEvent(1, name: "CandidateStateChanged", "pubkey", ContractParameterType.PublicKey, "registered", ContractParameterType.Boolean, @@ -70,6 +73,8 @@ public sealed class NeoToken : FungibleToken internal NeoToken() : base() { TotalAmount = 100000000 * Factor; + _votersCount = CreateStorageKey(Prefix_VotersCount); + _registerPrice = CreateStorageKey(Prefix_RegisterPrice); } public override BigInteger TotalSupply(DataCache snapshot) @@ -87,7 +92,7 @@ internal override void OnBalanceChanging(ApplicationEngine engine, UInt160 accou } if (amount.IsZero) return; if (state.VoteTo is null) return; - engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_VotersCount)).Add(amount); + engine.SnapshotCache.GetAndChange(_votersCount).Add(amount); StorageKey key = CreateStorageKey(Prefix_Candidate).Add(state.VoteTo); CandidateState candidate = engine.SnapshotCache.GetAndChange(key).GetInteroperable(); candidate.Votes += amount; @@ -186,9 +191,9 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor { var cachedCommittee = new CachedCommittee(engine.ProtocolSettings.StandbyCommittee.Select(p => (p, BigInteger.Zero))); engine.SnapshotCache.Add(CreateStorageKey(Prefix_Committee), new StorageItem(cachedCommittee)); - engine.SnapshotCache.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(System.Array.Empty())); + engine.SnapshotCache.Add(_votersCount, new StorageItem(System.Array.Empty())); engine.SnapshotCache.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(0u), new StorageItem(5 * GAS.Factor)); - engine.SnapshotCache.Add(CreateStorageKey(Prefix_RegisterPrice), new StorageItem(1000 * GAS.Factor)); + engine.SnapshotCache.Add(_registerPrice, new StorageItem(1000 * GAS.Factor)); return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); } return ContractTask.CompletedTask; @@ -288,7 +293,7 @@ private void SetRegisterPrice(ApplicationEngine engine, long registerPrice) if (registerPrice <= 0) throw new ArgumentOutOfRangeException(nameof(registerPrice)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_RegisterPrice)).Set(registerPrice); + engine.SnapshotCache.GetAndChange(_registerPrice).Set(registerPrice); } /// @@ -300,7 +305,7 @@ private void SetRegisterPrice(ApplicationEngine engine, long registerPrice) public long GetRegisterPrice(DataCache snapshot) { // In the unit of datoshi, 1 datoshi = 1e-8 GAS - return (long)(BigInteger)snapshot[CreateStorageKey(Prefix_RegisterPrice)]; + return (long)(BigInteger)snapshot[_registerPrice]; } private IEnumerable<(uint Index, BigInteger GasPerBlock)> GetSortedGasRecords(DataCache snapshot, uint end) @@ -377,7 +382,7 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, } if (state_account.VoteTo is null ^ voteTo is null) { - StorageItem item = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_VotersCount)); + StorageItem item = engine.SnapshotCache.GetAndChange(_votersCount); if (state_account.VoteTo is null) item.Add(state_account.Balance); else @@ -521,7 +526,7 @@ public ECPoint[] ComputeNextBlockValidators(DataCache snapshot, ProtocolSettings private IEnumerable<(ECPoint PublicKey, BigInteger Votes)> ComputeCommitteeMembers(DataCache snapshot, ProtocolSettings settings) { - decimal votersCount = (decimal)(BigInteger)snapshot[CreateStorageKey(Prefix_VotersCount)]; + decimal votersCount = (decimal)(BigInteger)snapshot[_votersCount]; decimal voterTurnout = votersCount / (decimal)TotalAmount; var candidates = GetCandidatesInternal(snapshot) .Select(p => (p.PublicKey, p.State.Votes)) diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 744b7b3ab6..8e26e85477 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -65,15 +65,25 @@ public sealed class PolicyContract : NativeContract private const byte Prefix_StoragePrice = 19; private const byte Prefix_AttributeFee = 20; - internal PolicyContract() : base() { } + private readonly StorageKey _feePerByte; + private readonly StorageKey _execFeeFactor; + private readonly StorageKey _storagePrice; + + + internal PolicyContract() : base() + { + _feePerByte = CreateStorageKey(Prefix_FeePerByte); + _execFeeFactor = CreateStorageKey(Prefix_ExecFeeFactor); + _storagePrice = CreateStorageKey(Prefix_StoragePrice); + } internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardfork) { if (hardfork == ActiveIn) { - engine.SnapshotCache.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(DefaultFeePerByte)); - engine.SnapshotCache.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor)); - engine.SnapshotCache.Add(CreateStorageKey(Prefix_StoragePrice), new StorageItem(DefaultStoragePrice)); + engine.SnapshotCache.Add(_feePerByte, new StorageItem(DefaultFeePerByte)); + engine.SnapshotCache.Add(_execFeeFactor, new StorageItem(DefaultExecFeeFactor)); + engine.SnapshotCache.Add(_storagePrice, new StorageItem(DefaultStoragePrice)); } return ContractTask.CompletedTask; } @@ -86,7 +96,7 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public long GetFeePerByte(DataCache snapshot) { - return (long)(BigInteger)snapshot[CreateStorageKey(Prefix_FeePerByte)]; + return (long)(BigInteger)snapshot[_feePerByte]; } /// @@ -97,7 +107,7 @@ public long GetFeePerByte(DataCache snapshot) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public uint GetExecFeeFactor(DataCache snapshot) { - return (uint)(BigInteger)snapshot[CreateStorageKey(Prefix_ExecFeeFactor)]; + return (uint)(BigInteger)snapshot[_execFeeFactor]; } /// @@ -108,7 +118,7 @@ public uint GetExecFeeFactor(DataCache snapshot) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public uint GetStoragePrice(DataCache snapshot) { - return (uint)(BigInteger)snapshot[CreateStorageKey(Prefix_StoragePrice)]; + return (uint)(BigInteger)snapshot[_storagePrice]; } /// @@ -154,7 +164,7 @@ private void SetFeePerByte(ApplicationEngine engine, long value) { if (value < 0 || value > 1_00000000) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_FeePerByte)).Set(value); + engine.SnapshotCache.GetAndChange(_feePerByte).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] @@ -162,7 +172,7 @@ private void SetExecFeeFactor(ApplicationEngine engine, uint value) { if (value == 0 || value > MaxExecFeeFactor) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_ExecFeeFactor)).Set(value); + engine.SnapshotCache.GetAndChange(_execFeeFactor).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] @@ -170,7 +180,7 @@ private void SetStoragePrice(ApplicationEngine engine, uint value) { if (value == 0 || value > MaxStoragePrice) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_StoragePrice)).Set(value); + engine.SnapshotCache.GetAndChange(_storagePrice).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)]