Skip to content

Commit a0a0b19

Browse files
committed
perf(evm): integrate hash-aware code info path for extcode cache
1 parent a348e35 commit a0a0b19

7 files changed

Lines changed: 61 additions & 16 deletions

File tree

src/Nethermind/Nethermind.Blockchain/CachedCodeInfoRepository.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IR
3636
return baseCodeInfoRepository.GetCachedCodeInfo(codeSource, followDelegation, vmSpec, out delegationAddress);
3737
}
3838

39+
public ICodeInfo GetCachedCodeInfo(Address codeSource, in ValueHash256 codeHash, IReleaseSpec vmSpec)
40+
{
41+
if (vmSpec.IsPrecompile(codeSource) && _cachedPrecompile.TryGetValue(codeSource, out PrecompileInfo cachedCodeInfo))
42+
{
43+
return cachedCodeInfo;
44+
}
45+
46+
return baseCodeInfoRepository.GetCachedCodeInfo(codeSource, in codeHash, vmSpec);
47+
}
48+
3949
public ValueHash256 GetExecutableCodeHash(Address address, IReleaseSpec spec)
4050
{
4151
return baseCodeInfoRepository.GetExecutableCodeHash(address, spec);

src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IR
4747
return cachedCodeInfo;
4848
}
4949

50+
public ICodeInfo GetCachedCodeInfo(Address codeSource, in ValueHash256 codeHash, IReleaseSpec vmSpec)
51+
{
52+
if (vmSpec.IsPrecompile(codeSource))
53+
{
54+
return _localPrecompiles[codeSource];
55+
}
56+
57+
return InternalGetCachedCode(_worldState, in codeHash, vmSpec);
58+
}
59+
5060
private ICodeInfo InternalGetCachedCode(Address codeSource, IReleaseSpec vmSpec)
5161
{
5262
ref readonly ValueHash256 codeHash = ref _worldState.GetCodeHash(codeSource);
@@ -187,4 +197,3 @@ public bool TryGet(in ValueHash256 codeHash, [NotNullWhen(true)] out ICodeInfo?
187197
}
188198
}
189199
}
190-

src/Nethermind/Nethermind.Evm/ICodeInfoRepository.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Nethermind.Evm;
1212
public interface ICodeInfoRepository
1313
{
1414
ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress);
15+
ICodeInfo GetCachedCodeInfo(Address codeSource, in ValueHash256 codeHash, IReleaseSpec vmSpec);
1516
ValueHash256 GetExecutableCodeHash(Address address, IReleaseSpec spec);
1617
void InsertCode(ReadOnlyMemory<byte> code, Address codeOwner, IReleaseSpec spec);
1718
void SetDelegation(Address codeSource, Address authority, IReleaseSpec spec);

src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.CodeCopy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public static EvmExceptionType InstructionExtCodeCopy<TGasPolicy, TTracingInst>(
179179
}
180180

181181
// If EOF is enabled and the code is an EOF contract, use a predefined magic value.
182-
if (spec.IsEofEnabled && EofValidator.IsEof(externalCode, out _))
182+
if (spec.IsEofEnabled && codeInfo is EofCodeInfo)
183183
{
184184
externalCode = EofValidator.MAGIC;
185185
}

src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Environment.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -675,20 +675,27 @@ public static EvmExceptionType InstructionExtCodeHashEof<TGasPolicy, TTracingIns
675675
{
676676
stack.PushZero<TTracingInst>();
677677
}
678+
else
679+
{
680+
ref readonly ValueHash256 codeHash = ref state.GetCodeHash(address);
681+
if (codeHash == Keccak.OfAnEmptyString.ValueHash256)
682+
{
683+
stack.Push32Bytes<TTracingInst>(in codeHash);
684+
return EvmExceptionType.None;
685+
}
686+
687+
CodeInfo codeInfo = vm.CodeInfoRepository.GetCachedCodeInfo(address, in codeHash, spec);
688+
// If the code is EOF, push the EOF-specific hash.
689+
if (codeInfo is EofCodeInfo)
690+
{
691+
stack.PushBytes<TTracingInst>(EofHash256);
692+
}
678693
else
679694
{
680-
CodeInfo codeInfo = vm.GetExtCodeInfoCached(address, spec);
681-
// If the code is EOF, push the EOF-specific hash.
682-
if (codeInfo is EofCodeInfo)
683-
{
684-
stack.PushBytes<TTracingInst>(EofHash256);
685-
}
686-
else
687-
{
688-
// Otherwise, push the standard code hash.
689-
stack.PushBytes<TTracingInst>(state.GetCodeHash(address).Bytes);
690-
}
695+
// Otherwise, push the standard code hash.
696+
stack.Push32Bytes<TTracingInst>(in codeHash);
691697
}
698+
}
692699

693700
return EvmExceptionType.None;
694701
// Jump forward to be unpredicted by the branch predictor.

src/Nethermind/Nethermind.Evm/VirtualMachine.ExtCodeCache.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ internal uint GetExtCodeSizeCached(Address address, IReleaseSpec spec)
5454
return entry.CodeSize;
5555
}
5656

57-
CodeInfo codeInfo = _codeInfoRepository.GetCachedCodeInfo(address, followDelegation: false, spec, out _);
57+
CodeInfo codeInfo = _codeInfoRepository.GetCachedCodeInfo(address, in codeHash, spec);
5858
uint codeSize = codeInfo is EofCodeInfo ? (uint)EofValidator.MAGIC.Length : (uint)codeInfo.CodeSpan.Length;
5959

6060
StoreCacheEntry(key, codeHash, codeSize, codeInfo);
@@ -99,7 +99,7 @@ internal CodeInfo GetExtCodeInfoCached(Address address, IReleaseSpec spec)
9999
return entry.CodeInfo;
100100
}
101101

102-
CodeInfo codeInfo = _codeInfoRepository.GetCachedCodeInfo(address, followDelegation: false, spec, out _);
102+
CodeInfo codeInfo = _codeInfoRepository.GetCachedCodeInfo(address, in codeHash, spec);
103103
uint codeSize = codeInfo is EofCodeInfo ? (uint)EofValidator.MAGIC.Length : (uint)codeInfo.CodeSpan.Length;
104104
StoreCacheEntry(key, codeHash, codeSize, codeInfo);
105105
return codeInfo;
@@ -113,10 +113,13 @@ private void StoreCacheEntry(AddressAsKey key, in ValueHash256 codeHash, uint co
113113
return;
114114
}
115115

116+
// Under high-cardinality workloads, clearing the whole dictionary causes avoidable churn.
117+
// Once capacity is reached, keep current hot set and skip admitting new entries.
116118
if (_extCodeCache!.Count >= _maxExtCodeCacheEntries)
117119
{
118-
_extCodeCache.Clear();
120+
return;
119121
}
122+
120123
_extCodeCache[key] = new ExtCodeCacheEntry(codeHash, codeSize, codeInfo);
121124
}
122125

src/Nethermind/Nethermind.State/OverridableEnv/OverridableCodeInfoRepository.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IR
3535
return codeInfoRepository.GetCachedCodeInfo(codeSource, followDelegation, vmSpec, out delegationAddress);
3636
}
3737

38+
public ICodeInfo GetCachedCodeInfo(Address codeSource, in ValueHash256 codeHash, IReleaseSpec vmSpec)
39+
{
40+
if (_precompileOverrides.TryGetValue(codeSource, out var precompile))
41+
{
42+
return precompile.codeInfo;
43+
}
44+
45+
if (_codeOverrides.TryGetValue(codeSource, out var result))
46+
{
47+
return result.codeInfo;
48+
}
49+
50+
return codeInfoRepository.GetCachedCodeInfo(codeSource, in codeHash, vmSpec);
51+
}
52+
3853
public void InsertCode(ReadOnlyMemory<byte> code, Address codeOwner, IReleaseSpec spec) =>
3954
codeInfoRepository.InsertCode(code, codeOwner, spec);
4055

0 commit comments

Comments
 (0)