mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 13:58:02 -05:00
Simulation: Add state to StateOverride (eth_call, eth_simulateV1). (#8166)
Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
This commit is contained in:
committed by
GitHub
parent
6d51821614
commit
8d360a3d0e
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
package org.hyperledger.besu.datatypes;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -35,6 +37,7 @@ public class StateOverride {
|
||||
private final Optional<Wei> balance;
|
||||
private final Optional<Long> nonce;
|
||||
private final Optional<String> code;
|
||||
private final Optional<Map<String, String>> state;
|
||||
private final Optional<Map<String, String>> stateDiff;
|
||||
private final Optional<Address> movePrecompileToAddress;
|
||||
|
||||
@@ -42,11 +45,13 @@ public class StateOverride {
|
||||
final Optional<Wei> balance,
|
||||
final Optional<Long> nonce,
|
||||
final Optional<String> code,
|
||||
final Optional<Map<String, String>> state,
|
||||
final Optional<Map<String, String>> stateDiff,
|
||||
final Optional<Address> movePrecompileToAddress) {
|
||||
this.balance = balance;
|
||||
this.nonce = nonce;
|
||||
this.code = code;
|
||||
this.state = state;
|
||||
this.stateDiff = stateDiff;
|
||||
this.movePrecompileToAddress = movePrecompileToAddress;
|
||||
}
|
||||
@@ -83,6 +88,15 @@ public class StateOverride {
|
||||
*
|
||||
* @return the state override map if present
|
||||
*/
|
||||
public Optional<Map<String, String>> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state diff override map
|
||||
*
|
||||
* @return the state diff override map if present
|
||||
*/
|
||||
public Optional<Map<String, String>> getStateDiff() {
|
||||
return stateDiff;
|
||||
}
|
||||
@@ -102,6 +116,7 @@ public class StateOverride {
|
||||
private Optional<Wei> balance = Optional.empty();
|
||||
private Optional<Long> nonce = Optional.empty();
|
||||
private Optional<String> code = Optional.empty();
|
||||
private Optional<Map<String, String>> state = Optional.empty();
|
||||
private Optional<Map<String, String>> stateDiff = Optional.empty();
|
||||
private Optional<Address> movePrecompileToAddress = Optional.empty();
|
||||
|
||||
@@ -141,6 +156,17 @@ public class StateOverride {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state override
|
||||
*
|
||||
* @param state the map of state overrides
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder withState(final Map<String, String> state) {
|
||||
this.state = Optional.ofNullable(state);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state diff override
|
||||
*
|
||||
@@ -169,7 +195,8 @@ public class StateOverride {
|
||||
* @return account override
|
||||
*/
|
||||
public StateOverride build() {
|
||||
return new StateOverride(balance, nonce, code, stateDiff, movePrecompileToAddress);
|
||||
checkState(state.isEmpty() || stateDiff.isEmpty(), "Cannot set both state and stateDiff");
|
||||
return new StateOverride(balance, nonce, code, state, stateDiff, movePrecompileToAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,12 +227,13 @@ public class StateOverride {
|
||||
return balance.equals(stateOverride.balance)
|
||||
&& nonce.equals(stateOverride.nonce)
|
||||
&& code.equals(stateOverride.code)
|
||||
&& state.equals(stateOverride.state)
|
||||
&& stateDiff.equals(stateOverride.stateDiff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(balance, nonce, code, stateDiff);
|
||||
return Objects.hash(balance, nonce, code, state, stateDiff);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,6 +245,8 @@ public class StateOverride {
|
||||
+ nonce
|
||||
+ ", code="
|
||||
+ code
|
||||
+ ", state="
|
||||
+ state
|
||||
+ ", stateDiff="
|
||||
+ stateDiff
|
||||
+ ", movePrecompileToAddress="
|
||||
|
||||
@@ -124,6 +124,27 @@ public class EthCallTest {
|
||||
assertThat(overrideMap).containsValue(override);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateOverridesWithState() {
|
||||
StateOverrideMap expectedOverrides = new StateOverrideMap();
|
||||
StateOverride override =
|
||||
new StateOverride.Builder().withState(Map.of("0x1234", "0x5678")).build();
|
||||
final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3");
|
||||
expectedOverrides.put(address, override);
|
||||
|
||||
final JsonRpcRequestContext request =
|
||||
ethCallRequestWithStateOverrides(callParameter(), "latest", expectedOverrides);
|
||||
|
||||
Optional<StateOverrideMap> maybeOverrideMap = method.getAddressStateOverrideMap(request);
|
||||
assertThat(maybeOverrideMap.isPresent()).isTrue();
|
||||
StateOverrideMap overrideMap = maybeOverrideMap.get();
|
||||
assertThat(overrideMap.keySet()).hasSize(1);
|
||||
assertThat(overrideMap.values()).hasSize(1);
|
||||
|
||||
assertThat(overrideMap).containsKey(address);
|
||||
assertThat(overrideMap).containsValue(override);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fullStateOverrides() {
|
||||
StateOverrideMap suppliedOverrides = new StateOverrideMap();
|
||||
|
||||
@@ -54,7 +54,6 @@ import java.util.Optional;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.apache.tuweni.units.bigints.UInt256;
|
||||
|
||||
/**
|
||||
* Simulates the execution of a block, processing transactions and applying state overrides. This
|
||||
@@ -248,19 +247,7 @@ public class BlockSimulator {
|
||||
for (Address accountToOverride : stateOverrideMap.keySet()) {
|
||||
final StateOverride override = stateOverrideMap.get(accountToOverride);
|
||||
MutableAccount account = updater.getOrCreate(accountToOverride);
|
||||
override.getNonce().ifPresent(account::setNonce);
|
||||
if (override.getBalance().isPresent()) {
|
||||
account.setBalance(override.getBalance().get());
|
||||
}
|
||||
override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n)));
|
||||
override
|
||||
.getStateDiff()
|
||||
.ifPresent(
|
||||
d ->
|
||||
d.forEach(
|
||||
(key, value) ->
|
||||
account.setStorageValue(
|
||||
UInt256.fromHexString(key), UInt256.fromHexString(value))));
|
||||
TransactionSimulator.applyOverrides(account, override);
|
||||
}
|
||||
updater.commit();
|
||||
}
|
||||
|
||||
@@ -460,13 +460,21 @@ public class TransactionSimulator {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void applyOverrides(final MutableAccount account, final StateOverride override) {
|
||||
protected static void applyOverrides(final MutableAccount account, final StateOverride override) {
|
||||
LOG.debug("applying overrides to state for account {}", account.getAddress());
|
||||
override.getNonce().ifPresent(account::setNonce);
|
||||
if (override.getBalance().isPresent()) {
|
||||
account.setBalance(override.getBalance().get());
|
||||
}
|
||||
override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n)));
|
||||
override.getBalance().ifPresent(account::setBalance);
|
||||
override.getCode().ifPresent(code -> account.setCode(Bytes.fromHexString(code)));
|
||||
override
|
||||
.getState()
|
||||
.ifPresent(
|
||||
d -> {
|
||||
account.clearStorage();
|
||||
d.forEach(
|
||||
(key, value) ->
|
||||
account.setStorageValue(
|
||||
UInt256.fromHexString(key), UInt256.fromHexString(value)));
|
||||
});
|
||||
override
|
||||
.getStateDiff()
|
||||
.ifPresent(
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.datatypes.StateOverride;
|
||||
import org.hyperledger.besu.datatypes.StateOverrideMap;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
|
||||
import org.hyperledger.besu.ethereum.GasLimitCalculator;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
|
||||
@@ -50,11 +51,9 @@ import org.hyperledger.besu.plugin.data.BlockOverrides;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.apache.tuweni.units.bigints.UInt256;
|
||||
@@ -168,24 +167,25 @@ public class BlockSimulatorTest {
|
||||
|
||||
@Test
|
||||
public void shouldApplyStateOverridesCorrectly() {
|
||||
StateOverrideMap stateOverrideMap = mock(StateOverrideMap.class);
|
||||
StateOverrideMap stateOverrideMap = new StateOverrideMap();
|
||||
Address address = mock(Address.class);
|
||||
StateOverride stateOverride = mock(StateOverride.class);
|
||||
MutableAccount mutableAccount = mock(MutableAccount.class);
|
||||
StateOverride stateOverride =
|
||||
new StateOverride.Builder()
|
||||
.withBalance(Wei.of(456L))
|
||||
.withNonce(new UnsignedLongParameter(123L))
|
||||
.withCode("")
|
||||
.withStateDiff(Map.of("0x0", "0x1"))
|
||||
.build();
|
||||
|
||||
when(stateOverrideMap.keySet()).thenReturn(Set.of(address));
|
||||
when(stateOverrideMap.get(address)).thenReturn(stateOverride);
|
||||
stateOverrideMap.put(address, stateOverride);
|
||||
|
||||
WorldUpdater worldUpdater = mock(WorldUpdater.class);
|
||||
when(mutableWorldState.updater()).thenReturn(worldUpdater);
|
||||
|
||||
MutableAccount mutableAccount = mock(MutableAccount.class);
|
||||
when(mutableAccount.getAddress()).thenReturn(address);
|
||||
when(worldUpdater.getOrCreate(address)).thenReturn(mutableAccount);
|
||||
|
||||
when(stateOverride.getNonce()).thenReturn(Optional.of(123L));
|
||||
when(stateOverride.getBalance()).thenReturn(Optional.of(Wei.of(456L)));
|
||||
when(stateOverride.getCode()).thenReturn(Optional.of(""));
|
||||
when(stateOverride.getStateDiff()).thenReturn(Optional.of(new HashMap<>(Map.of("0x0", "0x1"))));
|
||||
|
||||
blockSimulator.applyStateOverrides(stateOverrideMap, mutableWorldState);
|
||||
|
||||
verify(mutableAccount).setNonce(anyLong());
|
||||
|
||||
@@ -121,7 +121,7 @@ public class TransactionSimulatorTest {
|
||||
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM); // called from logging
|
||||
StateOverride.Builder builder = new StateOverride.Builder();
|
||||
StateOverride override = builder.build();
|
||||
transactionSimulator.applyOverrides(mutableAccount, override);
|
||||
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||
verify(mutableAccount).getAddress();
|
||||
verifyNoMoreInteractions(mutableAccount);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public class TransactionSimulatorTest {
|
||||
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
|
||||
StateOverride.Builder builder = new StateOverride.Builder().withBalance(Wei.of(99));
|
||||
StateOverride override = builder.build();
|
||||
transactionSimulator.applyOverrides(mutableAccount, override);
|
||||
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||
verify(mutableAccount).setBalance(eq(Wei.of(99)));
|
||||
}
|
||||
|
||||
@@ -145,7 +145,25 @@ public class TransactionSimulatorTest {
|
||||
StateOverride.Builder builder =
|
||||
new StateOverride.Builder().withStateDiff(Map.of(storageKey, storageValue));
|
||||
StateOverride override = builder.build();
|
||||
transactionSimulator.applyOverrides(mutableAccount, override);
|
||||
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||
verify(mutableAccount)
|
||||
.setStorageValue(
|
||||
eq(UInt256.fromHexString(storageKey)), eq(UInt256.fromHexString(storageValue)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrides_whenStateOverrides_stateIsUpdated() {
|
||||
MutableAccount mutableAccount = mock(MutableAccount.class);
|
||||
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
|
||||
final String storageKey = "0x01a2";
|
||||
final String storageValue = "0x00ff";
|
||||
StateOverride.Builder builder =
|
||||
new StateOverride.Builder().withState(Map.of(storageKey, storageValue));
|
||||
StateOverride override = builder.build();
|
||||
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||
|
||||
verify(mutableAccount).clearStorage();
|
||||
|
||||
verify(mutableAccount)
|
||||
.setStorageValue(
|
||||
eq(UInt256.fromHexString(storageKey)), eq(UInt256.fromHexString(storageValue)));
|
||||
|
||||
@@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
@@ -25,6 +26,7 @@ import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -63,6 +65,7 @@ public class StateOverrideParameterTest {
|
||||
|
||||
assertThat(stateOverride.getNonce().get()).isEqualTo(158);
|
||||
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
||||
assertFalse(stateOverride.getState().isPresent());
|
||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||
}
|
||||
|
||||
@@ -91,6 +94,7 @@ public class StateOverrideParameterTest {
|
||||
assertFalse(stateOverride.getNonce().isPresent());
|
||||
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
||||
assertThat(stateOverride.getCode()).isEqualTo(Optional.of(CODE_STRING));
|
||||
assertFalse(stateOverride.getState().isPresent());
|
||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||
}
|
||||
|
||||
@@ -118,6 +122,7 @@ public class StateOverrideParameterTest {
|
||||
|
||||
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
||||
assertThat(stateOverride.getNonce().get()).isEqualTo(158); // 0x9e
|
||||
assertFalse(stateOverride.getState().isPresent());
|
||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||
}
|
||||
|
||||
@@ -133,7 +138,7 @@ public class StateOverrideParameterTest {
|
||||
+ "{"
|
||||
+ "\"balance\": \"0x01\","
|
||||
+ "\"nonce\": \"0x9E\","
|
||||
+ "\"stateDiff\": {"
|
||||
+ "\"state\": {"
|
||||
+ "\""
|
||||
+ STORAGE_KEY
|
||||
+ "\": \""
|
||||
@@ -150,8 +155,9 @@ public class StateOverrideParameterTest {
|
||||
final StateOverride stateOverride = stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
|
||||
assertThat(stateOverride.getNonce().get()).isEqualTo(158);
|
||||
|
||||
assertTrue(stateOverride.getStateDiff().isPresent());
|
||||
assertThat(stateOverride.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||
assertTrue(stateOverride.getState().isPresent());
|
||||
assertThat(stateOverride.getState().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,7 +172,7 @@ public class StateOverrideParameterTest {
|
||||
+ "{"
|
||||
+ "\"balance\": \"0x01\","
|
||||
+ "\"nonce\": \"0x9E\","
|
||||
+ "\"stateDiff\": {"
|
||||
+ "\"state\": {"
|
||||
+ "\""
|
||||
+ STORAGE_KEY
|
||||
+ "\": \""
|
||||
@@ -179,7 +185,7 @@ public class StateOverrideParameterTest {
|
||||
+ "{"
|
||||
+ "\"balance\": \"0xFF\","
|
||||
+ "\"nonce\": \"0x9D\","
|
||||
+ "\"stateDiff\": {"
|
||||
+ "\"state\": {"
|
||||
+ "\""
|
||||
+ STORAGE_KEY
|
||||
+ "\": \""
|
||||
@@ -197,18 +203,35 @@ public class StateOverrideParameterTest {
|
||||
stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
|
||||
assertThat(stateOverride1.getNonce().get()).isEqualTo(158);
|
||||
assertThat(stateOverride1.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0x01")));
|
||||
assertTrue(stateOverride1.getStateDiff().isPresent());
|
||||
assertThat(stateOverride1.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||
assertTrue(stateOverride1.getState().isPresent());
|
||||
assertThat(stateOverride1.getState().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||
assertFalse(stateOverride1.getStateDiff().isPresent());
|
||||
|
||||
final StateOverride stateOverride2 =
|
||||
stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX2));
|
||||
assertThat(stateOverride2.getNonce().get()).isEqualTo(157);
|
||||
assertThat(stateOverride2.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0xFF")));
|
||||
assertTrue(stateOverride2.getStateDiff().isPresent());
|
||||
assertThat(stateOverride2.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||
assertTrue(stateOverride2.getState().isPresent());
|
||||
assertThat(stateOverride2.getState().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||
assertFalse(stateOverride2.getStateDiff().isPresent());
|
||||
}
|
||||
|
||||
private JsonRpcRequest readJsonAsJsonRpcRequest(final String json) throws java.io.IOException {
|
||||
return new ObjectMapper().readValue(json, JsonRpcRequest.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowExceptionWhenStateAndStateDiffAreBothPresent() {
|
||||
Exception exception =
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() ->
|
||||
new StateOverride.Builder()
|
||||
.withState(Map.of("0x1234", "0x5678"))
|
||||
.withStateDiff(Map.of("0x1234", "0x5678"))
|
||||
.build());
|
||||
|
||||
final String expectedMessage = "Cannot set both state and stateDiff";
|
||||
assertThat(exception.getMessage()).isEqualTo(expectedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user