Skip to content

Commit 612dc44

Browse files
committed
do not create account when state is empty in overrides
1 parent 7f3c09c commit 612dc44

4 files changed

Lines changed: 64 additions & 1 deletion

File tree

src/Nethermind/Nethermind.Evm.Test/StateOverridesTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,17 @@ public void nonce_override_within_uint64_range_does_not_throw(UInt256 nonce)
7272

7373
Assert.That(act, Throws.Nothing);
7474
}
75+
76+
[Test]
77+
public void override_with_balance_creates_account_in_state()
78+
{
79+
Dictionary<Address, AccountOverride> overrides = new()
80+
{
81+
{ TestItem.AddressA, new AccountOverride { Balance = 100 } },
82+
};
83+
84+
_state.ApplyStateOverridesNoCommit(_codeRepo, overrides, Shanghai.Instance);
85+
86+
Assert.That(_state.TryGetAccount(TestItem.AddressA, out _), Is.True);
87+
}
7588
}

src/Nethermind/Nethermind.Evm/AccountOverride.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ public class AccountOverride
2424
/// Storage difference for AccountOverrideStateDiff
2525
/// </summary>
2626
public Dictionary<UInt256, Hash256>? StateDiff { get; set; }
27+
28+
public bool HasStateChanges => Balance is not null || Nonce is not null || Code is not null || State is not null || StateDiff is not null;
2729
}

src/Nethermind/Nethermind.Evm/StateOverridesExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ public static void ApplyStateOverridesNoCommit(
3333

3434
if (!state.TryGetAccount(address, out AccountStruct account))
3535
{
36-
state.CreateAccount(address, accountOverride.Balance ?? UInt256.Zero, accountOverride.Nonce ?? UInt256.Zero);
36+
if (accountOverride.HasStateChanges)
37+
{
38+
state.CreateAccount(address, accountOverride.Balance ?? UInt256.Zero, accountOverride.Nonce ?? UInt256.Zero);
39+
}
3740
}
3841
else
3942
{

src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsSimplePrecompiles.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,49 @@ public async Task Test_eth_simulate_erc()
110110
Address? mainChainRpcAddress = ECRecoverCall(chain, TestItem.AddressB, transactionData, contractAddress);
111111
Assert.That(mainChainRpcAddress, Is.EqualTo(TestItem.AddressA));
112112
}
113+
114+
/// <summary>
115+
/// Regression test for: moving two precompiles to the same target address must not inject
116+
/// empty accounts for the source addresses into the trie, which would alter the stateRoot.
117+
/// Covers the Hive test case "multicall-move-two-accounts-to-same-38023".
118+
/// </summary>
119+
[Test]
120+
public async Task Test_eth_simulate_two_precompiles_moved_to_same_address_does_not_change_state_root()
121+
{
122+
TestRpcBlockchain chain = await CreateChain();
123+
124+
Hash256 parentStateRoot = chain.BlockFinder.Head!.StateRoot!;
125+
126+
SimulatePayload<TransactionWithSourceDetails> payload = new()
127+
{
128+
BlockStateCalls =
129+
[
130+
new BlockStateCall<TransactionWithSourceDetails>
131+
{
132+
StateOverrides = new Dictionary<Address, AccountOverride>
133+
{
134+
{ ECRecoverPrecompile.Address, new AccountOverride { MovePrecompileToAddress = new Address("0xc200000000000000000000000000000000000000") } },
135+
{ Sha256Precompile.Address, new AccountOverride { MovePrecompileToAddress = new Address("0xc200000000000000000000000000000000000000") } },
136+
}
137+
}
138+
]
139+
};
140+
141+
SimulateOutput<SimulateCallResult> result = chain.Bridge.Simulate(
142+
chain.BlockFinder.Head!.Header!,
143+
payload,
144+
new SimulateBlockMutatorTracerFactory(),
145+
10_000_000,
146+
CancellationToken.None);
147+
148+
using (Assert.EnterMultipleScope())
149+
{
150+
Assert.That(result.Error, Is.Null);
151+
Assert.That(result.Items, Has.Count.EqualTo(1));
152+
}
153+
154+
// The only overrides are movePrecompileToAddress — no state fields — so the trie
155+
// must be identical to the parent block's state root.
156+
Assert.That(result.Items[0].StateRoot, Is.EqualTo(parentStateRoot));
157+
}
113158
}

0 commit comments

Comments
 (0)