Skip to content

Commit

Permalink
refactor ChargeAccountAccessGas
Browse files Browse the repository at this point in the history
  • Loading branch information
ak88 committed Aug 24, 2024
1 parent 29ea2ec commit 6625445
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 47 deletions.
82 changes: 47 additions & 35 deletions src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,51 +114,52 @@ public CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IR
return _localPrecompiles[codeSource];
}

CodeInfo cachedCodeInfo = GetCachedCode(worldState, codeSource);
CodeInfo cachedCodeInfo = InternalGetCachedCode(worldState, codeSource);

if (HasDelegatedCode(cachedCodeInfo.MachineCode.Span))
if (IsDelegatedCode(cachedCodeInfo))
{
cachedCodeInfo = GetCachedCode(worldState, ParseDelegatedAddress(cachedCodeInfo.MachineCode.Span));
cachedCodeInfo = InternalGetCachedCode(worldState, ParseDelegatedAddress(cachedCodeInfo.MachineCode.Span));
}

return cachedCodeInfo;

[DoesNotReturn]
[StackTraceHidden]
static void MissingCode(Address codeSource, in ValueHash256 codeHash)
}

private static CodeInfo InternalGetCachedCode(IWorldState worldState, Address codeSource)
{
CodeInfo? cachedCodeInfo = null;
ValueHash256 codeHash = worldState.GetCodeHash(codeSource);
if (codeHash == Keccak.OfAnEmptyString.ValueHash256)
{
throw new NullReferenceException($"Code {codeHash} missing in the state for address {codeSource}");
cachedCodeInfo = CodeInfo.Empty;
}

static CodeInfo GetCachedCode(IWorldState worldState, Address codeSource)
cachedCodeInfo ??= _codeCache.Get(codeHash);
if (cachedCodeInfo is null)
{
CodeInfo? cachedCodeInfo = null;
ValueHash256 codeHash = worldState.GetCodeHash(codeSource);
if (codeHash == Keccak.OfAnEmptyString.ValueHash256)
{
cachedCodeInfo = CodeInfo.Empty;
}
byte[]? code = worldState.GetCode(codeHash);

cachedCodeInfo ??= _codeCache.Get(codeHash);
if (cachedCodeInfo is null)
if (code is null)
{
byte[]? code = worldState.GetCode(codeHash);
MissingCode(codeSource, codeHash);
}

if (code is null)
{
MissingCode(codeSource, codeHash);
}
cachedCodeInfo = new CodeInfo(code);
cachedCodeInfo.AnalyseInBackgroundIfRequired();
_codeCache.Set(codeHash, cachedCodeInfo);
}
else
{
Db.Metrics.IncrementCodeDbCache();
}

cachedCodeInfo = new CodeInfo(code);
cachedCodeInfo.AnalyseInBackgroundIfRequired();
_codeCache.Set(codeHash, cachedCodeInfo);
}
else
{
Db.Metrics.IncrementCodeDbCache();
}
return cachedCodeInfo;

return cachedCodeInfo;
[DoesNotReturn]
[StackTraceHidden]
static void MissingCode(Address codeSource, in ValueHash256 codeHash)
{
throw new NullReferenceException($"Code {codeHash} missing in the state for address {codeSource}");
}
}

Expand Down Expand Up @@ -217,7 +218,6 @@ public CodeInsertResult InsertFromAuthorizations(
refunds++;

InsertAuthorizedCode(worldState, authTuple.CodeAddress, authTuple.Authority, spec);

worldState.IncrementNonce(authTuple.Authority);
}
return new CodeInsertResult(result, refunds);
Expand Down Expand Up @@ -274,15 +274,15 @@ private bool IsValidForExecution(
private bool HasDelegatedCode(IWorldState worldState, Address source)
{
return
HasDelegatedCode(worldState.GetCode(source));
IsDelegatedCode(InternalGetCachedCode(worldState, source));
}

private static bool HasDelegatedCode(ReadOnlySpan<byte> code)
private static bool IsDelegatedCode(CodeInfo code)
{
return
code.Length >= Eip7702Constants.DelegationHeader.Length
code.MachineCode.Length == 23
&& Eip7702Constants.DelegationHeader.SequenceEqual(
code.Slice(0, Eip7702Constants.DelegationHeader.Length));
code.MachineCode.Span.Slice(0, Eip7702Constants.DelegationHeader.Length));
}

private static Address ParseDelegatedAddress(ReadOnlySpan<byte> code)
Expand All @@ -297,6 +297,18 @@ private CodeInfo CreateCachedPrecompile(
ConcurrentDictionary<PreBlockCaches.PrecompileCacheKey, (ReadOnlyMemory<byte>, bool)> cache) =>
new(new CachedPrecompile(originalPrecompile.Key.Value, originalPrecompile.Value.Precompile!, cache));

public bool IsDelegation(IWorldState worldState, Address address,[NotNullWhen(true)] out Address? delegatedAddress)
{
CodeInfo codeInfo = InternalGetCachedCode(worldState, address);
if (IsDelegatedCode(codeInfo))
{
delegatedAddress = ParseDelegatedAddress(codeInfo.MachineCode.Span);
return true;
}
delegatedAddress = null;
return false;
}

private class CachedPrecompile(
Address address,
IPrecompile precompile,
Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Evm/ICodeInfoRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
Expand All @@ -17,4 +18,5 @@ public interface ICodeInfoRepository
CodeInfo GetOrAdd(ValueHash256 codeHash, ReadOnlySpan<byte> initCode);
void InsertCode(IWorldState state, ReadOnlyMemory<byte> code, Address codeOwner, IReleaseSpec spec, bool isSystemEnv);
CodeInsertResult InsertFromAuthorizations(IWorldState worldState, AuthorizationTuple?[] authorizations, IReleaseSpec spec);
bool IsDelegation(IWorldState worldState, Address address, [NotNullWhen(true)] out Address? delegatedAddress);
}
35 changes: 23 additions & 12 deletions src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,13 +474,25 @@ private static void UpdateGasUp(long refund, ref long gasAvailable)
gasAvailable += refund;
}

private bool ChargeAccountAccessGas(ref long gasAvailable, EvmState vmState, Address address, IReleaseSpec spec, bool chargeForWarm = true)
private bool ChargeAccountAccessGas(ref long gasAvailable, EvmState vmState, Address address, bool chargeForDelegation, IReleaseSpec spec, bool chargeForWarm = true)
{
// Console.WriteLine($"Accessing {address}");
if (!spec.UseHotAndColdStorage)
{
return true;
}
if (chargeForDelegation
&& vmState.Env.TxExecutionContext.CodeInfoRepository.IsDelegation(_state, address, out Address delegated))
{
address = delegated;
if (!ChargeAccountGas(ref gasAvailable, vmState, address, spec))
return false;
}
return ChargeAccountGas(ref gasAvailable, vmState, address, spec);

bool result = true;
if (spec.UseHotAndColdStorage)
bool ChargeAccountGas(ref long gasAvailable, EvmState vmState, Address address, IReleaseSpec spec)
{
bool result = false;
if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list
{
vmState.WarmUp(address);
Expand All @@ -495,9 +507,8 @@ private bool ChargeAccountAccessGas(ref long gasAvailable, EvmState vmState, Add
{
result = UpdateGas(GasCostOf.WarmStateRead, ref gasAvailable);
}
return result;
}

return result;
}

private enum StorageAccessType
Expand Down Expand Up @@ -1148,7 +1159,7 @@ private CallResult ExecuteCode<TTracingInstructions, TTracingRefunds, TTracingSt
Address address = stack.PopAddress();
if (address is null) goto StackUnderflow;

if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) goto OutOfGas;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, false, spec)) goto OutOfGas;

result = _state.GetBalance(address);
stack.PushUInt256(in result);
Expand Down Expand Up @@ -1253,8 +1264,8 @@ private CallResult ExecuteCode<TTracingInstructions, TTracingRefunds, TTracingSt

Address address = stack.PopAddress();
if (address is null) goto StackUnderflow;

if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) goto OutOfGas;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, true, spec)) goto OutOfGas;

if (typeof(TTracingInstructions) != typeof(IsTracing) && programCounter < code.Length)
{
Expand Down Expand Up @@ -1318,7 +1329,7 @@ private CallResult ExecuteCode<TTracingInstructions, TTracingRefunds, TTracingSt

gasAvailable -= spec.GetExtCodeCost() + GasCostOf.Memory * EvmPooledMemory.Div32Ceiling(in result);

if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) goto OutOfGas;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, true, spec)) goto OutOfGas;

if (!result.IsZero)
{
Expand Down Expand Up @@ -1880,7 +1891,7 @@ private CallResult ExecuteCode<TTracingInstructions, TTracingRefunds, TTracingSt

Address address = stack.PopAddress();
if (address is null) goto StackUnderflow;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) goto OutOfGas;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address,true, spec)) goto OutOfGas;

if (!_state.AccountExists(address) || _state.IsDeadAccount(address))
{
Expand Down Expand Up @@ -2057,7 +2068,7 @@ private EvmExceptionType InstructionCall<TTracingInstructions, TTracingRefunds>(
Address codeSource = stack.PopAddress();
if (codeSource is null) return EvmExceptionType.StackUnderflow;

if (!ChargeAccountAccessGas(ref gasAvailable, vmState, codeSource, spec)) return EvmExceptionType.OutOfGas;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, codeSource, true, spec)) return EvmExceptionType.OutOfGas;

UInt256 callValue;
switch (instruction)
Expand Down Expand Up @@ -2277,7 +2288,7 @@ private EvmExceptionType InstructionSelfDestruct<TTracing>(EvmState vmState, ref

Address inheritor = stack.PopAddress();
if (inheritor is null) return EvmExceptionType.StackUnderflow;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, inheritor, spec, false)) return EvmExceptionType.OutOfGas;
if (!ChargeAccountAccessGas(ref gasAvailable, vmState, inheritor, false, spec, false)) return EvmExceptionType.OutOfGas;

Address executingAccount = vmState.Env.ExecutingAccount;
bool createInSameTx = vmState.CreateList.Contains(executingAccount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
Expand Down Expand Up @@ -50,4 +51,9 @@ public CodeInsertResult InsertFromAuthorizations(IWorldState worldState, Authori
{
return codeInfoRepository.InsertFromAuthorizations(worldState, authorizations, spec);
}

public bool IsDelegation(IWorldState worldState, Address address, [NotNullWhen(true)] out Address? delegatedAddress)
{
return codeInfoRepository.IsDelegation(worldState, address, out delegatedAddress);
}
}

0 comments on commit 6625445

Please sign in to comment.