Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add readonly StorageKeys to eliminate some allocations #3616

Merged
merged 1 commit into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading