Skip to content

Commit

Permalink
Prefer code from code cache for Create (#5854)
Browse files Browse the repository at this point in the history
* Prefer code from code cache for Create

* Filter code inserts

* Add Note
  • Loading branch information
benaadams authored Jun 22, 2023
1 parent 226e0fd commit 7804661
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 3 deletions.
12 changes: 11 additions & 1 deletion src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2444,14 +2444,24 @@ private bool InstructionSelfDestruct<TTracing>(EvmState vmState, ref EvmStack<TT
}

_state.SubtractFromBalance(env.ExecutingAccount, value, spec);

ValueKeccak codeHash = ValueKeccak.Compute(initCode);
// Prefer code from code cache (e.g. if create from a factory contract or copypasta)
if (!_codeCache.TryGet(codeHash, out CodeInfo codeInfo))
{
codeInfo = new(initCode.ToArray());
// Prime the code cache as likely to be used by more txs
_codeCache.Set(codeHash, codeInfo);
}

ExecutionEnvironment callEnv = new
(
txExecutionContext: env.TxExecutionContext,
callDepth: env.CallDepth + 1,
caller: env.ExecutingAccount,
executingAccount: contractAddress,
codeSource: null,
codeInfo: new CodeInfo(initCode.ToArray()),
codeInfo: codeInfo,
inputData: default,
transferValue: value,
value: value
Expand Down
33 changes: 31 additions & 2 deletions src/Nethermind/Nethermind.State/StateProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Nethermind.Core;
using Nethermind.Core.Caching;
using Nethermind.Core.Crypto;
using Nethermind.Core.Resettables;
using Nethermind.Core.Specs;
using Nethermind.Db;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.State.Tracing;
Expand All @@ -23,6 +25,11 @@ internal class StateProvider
private const int StartCapacity = Resettable.StartCapacity;
private readonly ResettableDictionary<Address, Stack<int>> _intraBlockCache = new();
private readonly ResettableHashSet<Address> _committedThisRound = new();
// Only guarding against hot duplicates so filter doesn't need to be too big
// Note:
// False negatives are fine as they will just result in a overwrite set
// False positives would be problematic as the code _must_ be persisted
private readonly LruKeyCache<Keccak> _codeInsertFilter = new(2048, "Code Insert Filter");

private readonly List<Change> _keptInCache = new();
private readonly ILogger _logger;
Expand Down Expand Up @@ -141,7 +148,29 @@ public void InsertCode(Address address, ReadOnlyMemory<byte> code, IReleaseSpec
{
_needsStateRootUpdate = true;
Keccak codeHash = code.Length == 0 ? Keccak.OfAnEmptyString : Keccak.Compute(code.Span);
_codeDb[codeHash.Bytes] = code.ToArray();

// Don't reinsert if already inserted. This can be the case when the same
// code is used by multiple deployments. Either from factory contracts (e.g. LPs)
// or people copy and pasting popular contracts
if (!_codeInsertFilter.Get(codeHash))
{
if (_codeDb is IDbWithSpan dbWithSpan)
{
dbWithSpan.PutSpan(codeHash.Bytes, code.Span);
}
else if (MemoryMarshal.TryGetArray(code, out ArraySegment<byte> codeArray)
&& codeArray.Offset == 0
&& codeArray.Count == code.Length)
{
_codeDb[codeHash.Bytes] = codeArray.Array;
}
else
{
_codeDb[codeHash.Bytes] = code.ToArray();
}

_codeInsertFilter.Set(codeHash);
}

Account? account = GetThroughCache(address);
if (account is null)
Expand Down

0 comments on commit 7804661

Please sign in to comment.