Skip to content

Commit

Permalink
feat: add readonly StorageKeys to eliminate some allocations (#3616)
Browse files Browse the repository at this point in the history
  • Loading branch information
nan01ab authored Dec 8, 2024
1 parent ac8e532 commit 86c526e
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 21 deletions.
13 changes: 9 additions & 4 deletions src/Neo/SmartContract/Native/LedgerContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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>();
HashIndexState state = engine.SnapshotCache.GetAndChange(_currentBlock, () => new StorageItem(new HashIndexState())).GetInteroperable<HashIndexState>();
state.Hash = engine.PersistingBlock.Hash;
state.Index = engine.PersistingBlock.Index;
return ContractTask.CompletedTask;
Expand Down Expand Up @@ -116,7 +121,7 @@ public UInt256 CurrentHash(DataCache snapshot)
if (snapshot is null)
throw new ArgumentNullException(nameof(snapshot));

return snapshot[CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable<HashIndexState>().Hash;
return snapshot[_currentBlock].GetInteroperable<HashIndexState>().Hash;
}

/// <summary>
Expand All @@ -130,7 +135,7 @@ public uint CurrentIndex(DataCache snapshot)
if (snapshot is null)
throw new ArgumentNullException(nameof(snapshot));

return snapshot[CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable<HashIndexState>().Index;
return snapshot[_currentBlock].GetInteroperable<HashIndexState>().Index;
}

/// <summary>
Expand Down
19 changes: 12 additions & 7 deletions src/Neo/SmartContract/Native/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public sealed class NeoToken : FungibleToken<NeoToken.NeoAccountState>
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,
Expand All @@ -70,6 +73,8 @@ public sealed class NeoToken : FungibleToken<NeoToken.NeoAccountState>
internal NeoToken() : base()
{
TotalAmount = 100000000 * Factor;
_votersCount = CreateStorageKey(Prefix_VotersCount);
_registerPrice = CreateStorageKey(Prefix_RegisterPrice);
}

public override BigInteger TotalSupply(DataCache snapshot)
Expand All @@ -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<CandidateState>();
candidate.Votes += amount;
Expand Down Expand Up @@ -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<byte>()));
engine.SnapshotCache.Add(_votersCount, new StorageItem(System.Array.Empty<byte>()));
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;
Expand Down Expand Up @@ -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);
}

/// <summary>
Expand All @@ -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)
Expand Down Expand Up @@ -377,7 +382,7 @@ private async ContractTask<bool> 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
Expand Down Expand Up @@ -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))
Expand Down
30 changes: 20 additions & 10 deletions src/Neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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];
}

/// <summary>
Expand All @@ -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];
}

/// <summary>
Expand All @@ -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];
}

/// <summary>
Expand Down Expand Up @@ -154,23 +164,23 @@ 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)]
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)]
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)]
Expand Down

0 comments on commit 86c526e

Please sign in to comment.