Move EVM operation Tests (#4858)

Move the EVM individual operation tests into the EVM module.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
pull/4709/head
Danno Ferrin 2 years ago committed by GitHub
parent 719ea398f1
commit 165c6d95a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      evm/src/test/java/org/hyperledger/besu/evm/operations/BaseFeeOperationTest.java
  2. 56
      evm/src/test/java/org/hyperledger/besu/evm/operations/BlockHashOperationTest.java
  3. 2
      evm/src/test/java/org/hyperledger/besu/evm/operations/ChainIdOperationTest.java
  4. 50
      evm/src/test/java/org/hyperledger/besu/evm/operations/ConstantinopleSStoreOperationGasCostTest.java
  5. 9
      evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java
  6. 14
      evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java
  7. 29
      evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCodeHashOperationTest.java
  8. 34
      evm/src/test/java/org/hyperledger/besu/evm/operations/JumpOperationTest.java
  9. 48
      evm/src/test/java/org/hyperledger/besu/evm/operations/LondonSStoreOperationGasCostTest.java
  10. 2
      evm/src/test/java/org/hyperledger/besu/evm/operations/PrevRanDaoOperationTest.java
  11. 10
      evm/src/test/java/org/hyperledger/besu/evm/operations/Push0OperationTest.java
  12. 36
      evm/src/test/java/org/hyperledger/besu/evm/operations/RelativeJumpOperationTest.java
  13. 2
      evm/src/test/java/org/hyperledger/besu/evm/operations/RevertOperationTest.java
  14. 26
      evm/src/test/java/org/hyperledger/besu/evm/operations/SStoreOperationTest.java
  15. 6
      evm/src/test/java/org/hyperledger/besu/evm/operations/SarOperationTest.java
  16. 6
      evm/src/test/java/org/hyperledger/besu/evm/operations/ShlOperationTest.java
  17. 6
      evm/src/test/java/org/hyperledger/besu/evm/operations/ShrOperationTest.java
  18. 48
      evm/src/test/java/org/hyperledger/besu/evm/testutils/FakeBlockValues.java
  19. 60
      evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java
  20. 172
      evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java
  21. 10
      evm/src/test/java/org/hyperledger/besu/evm/toy/ToyAccount.java
  22. 29
      evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ -20,7 +20,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator;
@ -79,7 +79,7 @@ public class BaseFeeOperationTest {
private MessageFrame createMessageFrame(final long initialGas, final Optional<Wei> baseFee) {
final MessageFrame frame = mock(MessageFrame.class);
when(frame.getRemainingGas()).thenReturn(initialGas);
final BlockHeader blockHeader = mock(BlockHeader.class);
final BlockValues blockHeader = mock(BlockValues.class);
when(blockHeader.getBaseFee()).thenReturn(baseFee);
when(frame.getBlockValues()).thenReturn(blockHeader);
return frame;

@ -12,54 +12,44 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
import java.util.function.Function;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.After;
import org.junit.Test;
public class BlockHashOperationTest {
private static final int MAXIMUM_COMPLETE_BLOCKS_BEHIND = 256;
private final BlockHashLookup blockHashLookup = mock(BlockHashLookup.class);
private final BlockHashOperation blockHashOperation =
new BlockHashOperation(new FrontierGasCalculator());
@After
public void verifyNoUnexpectedHashLookups() {
verifyNoMoreInteractions(blockHashLookup);
}
@Test
public void shouldReturnZeroWhenArgIsBiggerThanALong() {
assertBlockHash(Bytes32.fromHexString("F".repeat(64)), Bytes32.ZERO, 100);
assertBlockHash(
Bytes32.fromHexString("F".repeat(64)), Bytes32.ZERO, 100, n -> Hash.EMPTY_LIST_HASH);
}
@Test
public void shouldReturnZeroWhenCurrentBlockIsGenesis() {
assertBlockHash(Bytes32.ZERO, Bytes32.ZERO, BlockHeader.GENESIS_BLOCK_NUMBER);
assertBlockHash(Bytes32.ZERO, Bytes32.ZERO, 0, block -> Hash.EMPTY_LIST_HASH);
}
@Test
public void shouldReturnZeroWhenRequestedBlockAheadOfCurrent() {
assertBlockHash(250, Bytes32.ZERO, 100);
assertBlockHash(250, Bytes32.ZERO, 100, block -> Hash.EMPTY_LIST_HASH);
}
@Test
@ -67,38 +57,44 @@ public class BlockHashOperationTest {
final int requestedBlock = 10;
// Our block is the one after the chain head (it's a new block), hence the + 1.
final int importingBlockNumber = MAXIMUM_COMPLETE_BLOCKS_BEHIND + requestedBlock + 1;
assertBlockHash(requestedBlock, Bytes32.ZERO, importingBlockNumber);
assertBlockHash(
requestedBlock, Bytes32.ZERO, importingBlockNumber, block -> Hash.EMPTY_LIST_HASH);
}
@Test
public void shouldReturnZeroWhenRequestedBlockGreaterThanImportingBlock() {
assertBlockHash(101, Bytes32.ZERO, 100);
assertBlockHash(101, Bytes32.ZERO, 100, block -> Hash.EMPTY_LIST_HASH);
}
@Test
public void shouldReturnZeroWhenRequestedBlockEqualToImportingBlock() {
assertBlockHash(100, Bytes32.ZERO, 100);
assertBlockHash(100, Bytes32.ZERO, 100, block -> Hash.EMPTY_LIST_HASH);
}
@Test
public void shouldReturnBlockHashUsingLookupFromFrameWhenItIsWithinTheAllowedRange() {
final Hash blockHash = Hash.hash(Bytes.fromHexString("0x1293487297"));
when(blockHashLookup.apply(100L)).thenReturn(blockHash);
assertBlockHash(100, blockHash, 200);
verify(blockHashLookup).apply(100L);
assertBlockHash(100, blockHash, 200, block -> block == 100 ? blockHash : Hash.EMPTY_LIST_HASH);
}
private void assertBlockHash(
final long requestedBlock, final Bytes32 expectedOutput, final long currentBlockNumber) {
assertBlockHash(UInt256.valueOf(requestedBlock), expectedOutput, currentBlockNumber);
final long requestedBlock,
final Bytes32 expectedOutput,
final long currentBlockNumber,
final Function<Long, Hash> blockHashLookup) {
assertBlockHash(
UInt256.valueOf(requestedBlock), expectedOutput, currentBlockNumber, blockHashLookup);
}
private void assertBlockHash(
final Bytes32 input, final Bytes32 expectedOutput, final long currentBlockNumber) {
final Bytes32 input,
final Bytes32 expectedOutput,
final long currentBlockNumber,
final Function<Long, Hash> blockHashLookup) {
final MessageFrame frame =
new MessageFrameTestFixture()
new TestMessageFrameBuilder()
.blockHashLookup(blockHashLookup)
.blockHeader(new BlockHeaderTestFixture().number(currentBlockNumber).buildHeader())
.blockValues(new FakeBlockValues(currentBlockNumber))
.pushStackItem(UInt256.fromBytes(input))
.build();
blockHashOperation.execute(frame, null);

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

@ -12,34 +12,22 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.ethereum.core.TestCodeExecutor;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.frame.MessageFrame.State;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.testutils.TestCodeExecutor;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@RunWith(Parameterized.class)
public class ConstantinopleSStoreOperationGasCostTest {
private static final ProtocolSchedule protocolSchedule =
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().constantinopleBlock(0), EvmConfiguration.DEFAULT);
@Parameters(name = "Code: {0}, Original: {1}")
public static Object[][] scenarios() {
// Tests specified in EIP-1283.
return new Object[][] {
@ -63,26 +51,17 @@ public class ConstantinopleSStoreOperationGasCostTest {
};
}
private TestCodeExecutor codeExecutor;
@Parameter public String code;
@Parameter(value = 1)
public int originalValue;
@ParameterizedTest
@MethodSource("scenarios")
void shouldCalculateGasAccordingToEip1283(
final String code,
final int originalValue,
final int expectedGasUsed,
final int expectedGasRefund) {
@Parameter(value = 2)
public int expectedGasUsed;
@Parameter(value = 3)
public int expectedGasRefund;
@Before
public void setUp() {
codeExecutor = new TestCodeExecutor(protocolSchedule);
}
TestCodeExecutor codeExecutor =
new TestCodeExecutor(MainnetEVMs.constantinople(EvmConfiguration.DEFAULT));
@Test
public void shouldCalculateGasAccordingToEip1283() {
final long gasLimit = 1_000_000;
final MessageFrame frame =
codeExecutor.executeCode(
@ -90,6 +69,7 @@ public class ConstantinopleSStoreOperationGasCostTest {
gasLimit,
account -> account.setStorageValue(UInt256.ZERO, UInt256.valueOf(originalValue)));
assertThat(frame.getState()).isEqualTo(State.COMPLETED_SUCCESS);
System.out.println(gasLimit - frame.getRemainingGas());
assertThat(frame.getRemainingGas()).isEqualTo(gasLimit - expectedGasUsed);
assertThat(frame.getGasRefund()).isEqualTo(expectedGasRefund);
}

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -22,11 +22,10 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.operation.Create2Operation;
@ -146,8 +145,8 @@ public class Create2OperationTest {
.depth(1)
.completer(__ -> {})
.address(Address.fromHexString(sender))
.blockHashLookup(mock(BlockHashLookup.class))
.blockValues(mock(ProcessableBlockHeader.class))
.blockHashLookup(n -> Hash.hash(Bytes.ofUnsignedLong(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.messageFrameStack(new ArrayDeque<>())
.miningBeneficiary(Address.ZERO)

@ -13,10 +13,9 @@
* SPDX-License-Identifier: Apache-2.0
*
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSpecs.SHANDONG_CONTRACT_SIZE_LIMIT;
import static org.hyperledger.besu.evm.MainnetEVMs.DEV_NET_CHAIN_ID;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@ -25,12 +24,11 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -181,7 +179,7 @@ public class CreateOperationTest {
@Test
public void shandongMaxInitCodeSizeCreate() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.valueOf(SHANDONG_CONTRACT_SIZE_LIMIT);
final UInt256 memoryLength = UInt256.fromHexString("0xc000");
final ArrayDeque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final MessageFrame messageFrame =
testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack);
@ -213,7 +211,7 @@ public class CreateOperationTest {
@Test
public void shandongMaxInitCodeSizePlus1Create() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.valueOf(SHANDONG_CONTRACT_SIZE_LIMIT + 1);
final UInt256 memoryLength = UInt256.fromHexString("0xc001");
final ArrayDeque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final MessageFrame messageFrame =
testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack);
@ -254,8 +252,8 @@ public class CreateOperationTest {
.depth(depth)
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup(mock(BlockHashLookup.class))
.blockValues(mock(ProcessableBlockHeader.class))
.blockHashLookup(n -> Hash.hash(Bytes.ofUnsignedLong(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.messageFrameStack(messageFrameStack)
.miningBeneficiary(Address.ZERO)

@ -12,28 +12,24 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.AddressHelpers;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.operation.ExtCodeHashOperation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
import org.hyperledger.besu.evm.toy.ToyWorld;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.apache.tuweni.bytes.Bytes;
@ -43,12 +39,10 @@ import org.junit.Test;
public class ExtCodeHashOperationTest {
private static final Address REQUESTED_ADDRESS = AddressHelpers.ofValue(22222222);
private static final Address REQUESTED_ADDRESS = Address.fromHexString("0x22222222");
private final Blockchain blockchain = mock(Blockchain.class);
private final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
private final WorldUpdater worldStateUpdater = worldStateArchive.getMutable().updater();
ToyWorld toyWorld = new ToyWorld();
private final WorldUpdater worldStateUpdater = toyWorld.updater();
private final ExtCodeHashOperation operation =
new ExtCodeHashOperation(new ConstantinopleGasCalculator());
@ -132,12 +126,11 @@ public class ExtCodeHashOperationTest {
}
private MessageFrame createMessageFrame(final UInt256 stackItem) {
final BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader();
final BlockValues blockValues = new FakeBlockValues(1337);
final MessageFrame frame =
new MessageFrameTestFixture()
new TestMessageFrameBuilder()
.worldUpdater(worldStateUpdater)
.blockHeader(blockHeader)
.blockchain(blockchain)
.blockValues(blockValues)
.build();
frame.pushStackItem(stackItem);

@ -12,23 +12,16 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
@ -37,7 +30,8 @@ import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.JumpOperation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
@ -53,33 +47,21 @@ public class JumpOperationTest {
private static final int CURRENT_PC = 1;
private Blockchain blockchain;
private Address address;
private WorldUpdater worldStateUpdater;
private EVM evm;
private MessageFrameTestFixture createMessageFrameBuilder(final long initialGas) {
final BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader();
return new MessageFrameTestFixture()
private TestMessageFrameBuilder createMessageFrameBuilder(final long initialGas) {
final BlockValues blockValues = new FakeBlockValues(1337);
return new TestMessageFrameBuilder()
.address(address)
.worldUpdater(worldStateUpdater)
.blockHeader(blockHeader)
.blockchain(blockchain)
.blockValues(blockValues)
.initialGas(initialGas);
}
@Before
public void init() {
blockchain = mock(Blockchain.class);
address = Address.fromHexString("0x18675309");
final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
worldStateUpdater = worldStateArchive.getMutable().updater();
worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1));
worldStateUpdater.commit();
final OperationRegistry registry = new OperationRegistry();
registry.put(new JumpOperation(gasCalculator));
registry.put(new JumpDestOperation(gasCalculator));

@ -12,32 +12,23 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.ethereum.core.TestCodeExecutor;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.frame.MessageFrame.State;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.testutils.TestCodeExecutor;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@RunWith(Parameterized.class)
public class LondonSStoreOperationGasCostTest {
private static ProtocolSchedule protocolSchedule;
@Parameters(name = "Code: {0}, Original: {1}")
public static Object[][] scenarios() {
// Tests specified in EIP-3539.
return new Object[][] {
@ -63,27 +54,18 @@ public class LondonSStoreOperationGasCostTest {
private TestCodeExecutor codeExecutor;
@Parameter public String code;
@Parameter(value = 1)
public int originalValue;
@Parameter(value = 2)
public int expectedGasUsed;
@Parameter(value = 3)
public int expectedGasRefund;
@Before
@BeforeEach
public void setUp() {
protocolSchedule =
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().londonBlock(0), EvmConfiguration.DEFAULT);
codeExecutor = new TestCodeExecutor(protocolSchedule);
codeExecutor = new TestCodeExecutor(MainnetEVMs.london(EvmConfiguration.DEFAULT));
}
@Test
public void shouldCalculateGasAccordingToEip3529() {
@ParameterizedTest
@MethodSource("scenarios")
void shouldCalculateGasAccordingToEip3529(
final String code,
final int originalValue,
final int expectedGasUsed,
final int expectedGasRefund) {
final long gasLimit = 1_000_000;
final MessageFrame frame =
codeExecutor.executeCode(

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

@ -12,21 +12,22 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.evm.code.CodeV0;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.Push0Operation;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import java.util.Optional;
@ -56,9 +57,8 @@ class Push0OperationTest {
private MessageFrame createMessageFrame(final long initialGas, final Optional<Wei> baseFee) {
final MessageFrame frame = mock(MessageFrame.class);
when(frame.getRemainingGas()).thenReturn(initialGas);
final BlockHeader blockHeader = mock(BlockHeader.class);
when(blockHeader.getBaseFee()).thenReturn(baseFee);
when(frame.getBlockValues()).thenReturn(blockHeader);
final BlockValues blockValues = new FakeBlockValues(baseFee);
when(frame.getBlockValues()).thenReturn(blockValues);
when(frame.getCode()).thenReturn(CodeV0.EMPTY_CODE);
return frame;
}

@ -13,17 +13,19 @@
* SPDX-License-Identifier: Apache-2.0
*
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.RelativeJumpIfOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpVectorOperation;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
import org.apache.tuweni.bytes.Bytes;
import org.assertj.core.api.Assertions;
@ -39,11 +41,13 @@ class RelativeJumpOperationTest {
void rjumpOperation(final int jumpLength) {
final GasCalculator gasCalculator = mock(GasCalculator.class);
final MessageFrame messageFrame = mock(MessageFrame.class, Mockito.RETURNS_DEEP_STUBS);
final Code mockCode = mock(Code.class);
final String twosComplementJump = String.format("%08x", jumpLength).substring(4);
final int rjumpOperationIndex = 3;
final Bytes code = Bytes.fromHexString("00".repeat(3) + "5c" + twosComplementJump);
when(messageFrame.getCode().getCodeBytes(messageFrame.getSection())).thenReturn(code);
when(messageFrame.getCode()).thenReturn(mockCode);
when(mockCode.getCodeBytes(messageFrame.getSection())).thenReturn(code);
when(messageFrame.getRemainingGas()).thenReturn(3L);
when(messageFrame.getPC()).thenReturn(rjumpOperationIndex);
@ -57,14 +61,18 @@ class RelativeJumpOperationTest {
@Test
void rjumpiOperation() {
final GasCalculator gasCalculator = mock(GasCalculator.class);
final MessageFrame messageFrame = mock(MessageFrame.class, Mockito.RETURNS_DEEP_STUBS);
final Code mockCode = mock(Code.class);
final int rjumpOperationIndex = 3;
final Bytes code = Bytes.fromHexString("00".repeat(rjumpOperationIndex) + "5d0004");
when(messageFrame.getCode().getCodeBytes(messageFrame.getSection())).thenReturn(code);
when(messageFrame.getPC()).thenReturn(rjumpOperationIndex);
when(messageFrame.getRemainingGas()).thenReturn(5L);
when(messageFrame.popStackItem()).thenReturn(Bytes.EMPTY);
MessageFrame messageFrame =
new TestMessageFrameBuilder()
.code(mockCode)
.pc(rjumpOperationIndex)
.initialGas(5L)
.pushStackItem(Bytes.EMPTY)
.build();
when(mockCode.getCodeBytes(messageFrame.getSection())).thenReturn(code);
RelativeJumpIfOperation rjumpi = new RelativeJumpIfOperation(gasCalculator);
Operation.OperationResult rjumpResult = rjumpi.execute(messageFrame, null);
@ -75,7 +83,7 @@ class RelativeJumpOperationTest {
@Test
void rjumpvOperation() {
final GasCalculator gasCalculator = mock(GasCalculator.class);
final MessageFrame messageFrame = mock(MessageFrame.class, Mockito.RETURNS_DEEP_STUBS);
final Code mockCode = mock(Code.class);
final int rjumpOperationIndex = 3;
final int jumpVectorSize = 1;
final int jumpLength = 4;
@ -84,10 +92,14 @@ class RelativeJumpOperationTest {
"00".repeat(rjumpOperationIndex)
+ String.format("5e%02x%04x", jumpVectorSize, jumpLength));
when(messageFrame.getCode().getCodeBytes(messageFrame.getSection())).thenReturn(code);
when(messageFrame.getPC()).thenReturn(rjumpOperationIndex);
when(messageFrame.getRemainingGas()).thenReturn(5L);
when(messageFrame.popStackItem()).thenReturn(Bytes.of(jumpVectorSize));
MessageFrame messageFrame =
new TestMessageFrameBuilder()
.code(mockCode)
.pc(rjumpOperationIndex)
.initialGas(5L)
.pushStackItem(Bytes.of(jumpVectorSize))
.build();
when(mockCode.getCodeBytes(messageFrame.getSection())).thenReturn(code);
RelativeJumpVectorOperation rjumpv = new RelativeJumpVectorOperation(gasCalculator);
Operation.OperationResult rjumpResult = rjumpv.execute(messageFrame, null);

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyLong;

@ -12,26 +12,23 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive;
import static org.hyperledger.besu.evm.frame.ExceptionalHaltReason.INSUFFICIENT_GAS;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.SStoreOperation;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
import org.hyperledger.besu.evm.toy.ToyWorld;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Arrays;
@ -91,17 +88,14 @@ public class SStoreOperationTest {
private MessageFrame createMessageFrame(
final Address address, final long initialGas, final long remainingGas) {
final Blockchain blockchain = mock(Blockchain.class);
final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
final WorldUpdater worldStateUpdater = worldStateArchive.getMutable().updater();
final BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader();
final ToyWorld toyWorld = new ToyWorld();
final WorldUpdater worldStateUpdater = toyWorld.updater();
final BlockValues blockHeader = new FakeBlockValues(1337);
final MessageFrame frame =
new MessageFrameTestFixture()
new TestMessageFrameBuilder()
.address(address)
.worldUpdater(worldStateUpdater)
.blockHeader(blockHeader)
.blockchain(blockchain)
.blockValues(blockHeader)
.initialGas(initialGas)
.build();
worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1));

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -205,8 +205,8 @@ public class SarOperationTest {
};
@Parameterized.Parameters(name = "{index}: {0}, {1}, {2}")
public static Iterable<Object[]> data() {
return Arrays.asList((Object[][]) testData);
public static Iterable<String[]> data() {
return Arrays.asList(testData);
}
public SarOperationTest(final String number, final String shift, final String expectedResult) {

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -125,8 +125,8 @@ public class ShlOperationTest {
};
@Parameterized.Parameters(name = "{index}: {0}, {1}, {2}")
public static Iterable<Object[]> data() {
return Arrays.asList((Object[][]) testData);
public static Iterable<String[]> data() {
return Arrays.asList(testData);
}
public ShlOperationTest(final String number, final String shift, final String expectedResult) {

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
package org.hyperledger.besu.evm.operations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -144,8 +144,8 @@ public class ShrOperationTest {
};
@Parameterized.Parameters(name = "{index}: {0}, {1}, {2}")
public static Iterable<Object[]> data() {
return Arrays.asList((Object[][]) testData);
public static Iterable<String[]> data() {
return Arrays.asList(testData);
}
public ShrOperationTest(final String number, final String shift, final String expectedResult) {

@ -0,0 +1,48 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.testutils;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.frame.BlockValues;
import java.util.Optional;
public class FakeBlockValues implements BlockValues {
final long number;
final Optional<Wei> baseFee;
public FakeBlockValues(final long number) {
this(number, Optional.empty());
}
public FakeBlockValues(final Optional<Wei> baseFee) {
this(1337, baseFee);
}
public FakeBlockValues(final long number, final Optional<Wei> baseFee) {
this.number = number;
this.baseFee = baseFee;
}
@Override
public long getNumber() {
return number;
}
@Override
public Optional<Wei> getBaseFee() {
return baseFee;
}
}

@ -12,26 +12,22 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core;
package org.hyperledger.besu.evm.testutils;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry;
import org.hyperledger.besu.evm.processor.MessageCallProcessor;
import org.hyperledger.besu.evm.toy.ToyWorld;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.TransactionType;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.function.Consumer;
@ -40,58 +36,40 @@ import org.apache.tuweni.bytes.Bytes;
public class TestCodeExecutor {
private final ExecutionContextTestFixture fixture;
private final BlockHeader blockHeader = new BlockHeaderTestFixture().number(13).buildHeader();
private static final Address SENDER_ADDRESS = AddressHelpers.ofValue(244259721);
private final BlockValues blockValues = new FakeBlockValues(13);
private static final Address SENDER_ADDRESS = Address.fromHexString("0xe8f1b89");
private final EVM evm;
public TestCodeExecutor(final ProtocolSchedule protocolSchedule) {
fixture = ExecutionContextTestFixture.builder().protocolSchedule(protocolSchedule).build();
public TestCodeExecutor(final EVM evm) {
this.evm = evm;
}
public MessageFrame executeCode(
final String codeHexString,
final long gasLimit,
final Consumer<MutableAccount> accountSetup) {
final ProtocolSpec protocolSpec = fixture.getProtocolSchedule().getByBlockNumber(0);
final WorldUpdater worldUpdater =
createInitialWorldState(accountSetup, fixture.getStateArchive());
final WorldUpdater worldUpdater = createInitialWorldState(accountSetup);
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final EVM evm = protocolSpec.getEvm();
final MessageCallProcessor messageCallProcessor =
new MessageCallProcessor(evm, new PrecompileContractRegistry());
final Bytes codeBytes = Bytes.fromHexString(codeHexString);
final Code code = evm.getCode(Hash.hash(codeBytes), codeBytes);
final Transaction transaction =
Transaction.builder()
.type(TransactionType.FRONTIER)
.value(Wei.ZERO)
.sender(SENDER_ADDRESS)
.signature(
SignatureAlgorithmFactory.getInstance()
.createSignature(BigInteger.ONE, BigInteger.TEN, (byte) 1))
.gasLimit(gasLimit)
.to(SENDER_ADDRESS)
.payload(Bytes.EMPTY)
.gasPrice(Wei.ZERO)
.nonce(0)
.build();
final MessageFrame initialFrame =
new MessageFrameTestFixture()
new TestMessageFrameBuilder()
.messageFrameStack(messageFrameStack)
.blockchain(fixture.getBlockchain())
.worldUpdater(worldUpdater)
.initialGas(gasLimit)
.address(SENDER_ADDRESS)
.originator(SENDER_ADDRESS)
.contract(SENDER_ADDRESS)
.gasPrice(transaction.getGasPrice().get())
.inputData(transaction.getPayload())
.gasPrice(Wei.ZERO)
.inputData(Bytes.EMPTY)
.sender(SENDER_ADDRESS)
.value(transaction.getValue())
.value(Wei.ZERO)
.code(code)
.blockHeader(blockHeader)
.blockValues(blockValues)
.depth(0)
.build();
messageFrameStack.addFirst(initialFrame);
@ -102,16 +80,14 @@ public class TestCodeExecutor {
return initialFrame;
}
private WorldUpdater createInitialWorldState(
final Consumer<MutableAccount> accountSetup, final WorldStateArchive stateArchive) {
final MutableWorldState initialWorldState = stateArchive.getMutable();
private WorldUpdater createInitialWorldState(final Consumer<MutableAccount> accountSetup) {
ToyWorld toyWorld = new ToyWorld();
final WorldUpdater worldState = initialWorldState.updater();
final WorldUpdater worldState = toyWorld.updater();
final MutableAccount senderAccount =
worldState.getOrCreate(TestCodeExecutor.SENDER_ADDRESS).getMutable();
accountSetup.accept(senderAccount);
worldState.commit();
initialWorldState.persist(null);
return stateArchive.getMutable(initialWorldState.rootHash(), null).get().updater();
return toyWorld.updater();
}
}

@ -0,0 +1,172 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.testutils;
import static org.hyperledger.besu.evm.frame.MessageFrame.DEFAULT_MAX_STACK_SIZE;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeV0;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.toy.ToyWorld;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.apache.tuweni.bytes.Bytes;
public class TestMessageFrameBuilder {
public static final Address DEFAUT_ADDRESS = Address.fromHexString("0xe8f1b89");
private static final int maxStackSize = DEFAULT_MAX_STACK_SIZE;
private Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
private Optional<BlockValues> blockValues = Optional.empty();
private Optional<WorldUpdater> worldUpdater = Optional.empty();
private long initialGas = Long.MAX_VALUE;
private Address address = DEFAUT_ADDRESS;
private Address sender = DEFAUT_ADDRESS;
private Address originator = DEFAUT_ADDRESS;
private Address contract = DEFAUT_ADDRESS;
private Wei gasPrice = Wei.ZERO;
private Wei value = Wei.ZERO;
private Bytes inputData = Bytes.EMPTY;
private Code code = CodeV0.EMPTY_CODE;
private int pc = 0;
private final List<Bytes> stackItems = new ArrayList<>();
private int depth = 0;
private Optional<Function<Long, Hash>> blockHashLookup = Optional.empty();
TestMessageFrameBuilder messageFrameStack(final Deque<MessageFrame> messageFrameStack) {
this.messageFrameStack = messageFrameStack;
return this;
}
public TestMessageFrameBuilder worldUpdater(final WorldUpdater worldUpdater) {
this.worldUpdater = Optional.of(worldUpdater);
return this;
}
public TestMessageFrameBuilder initialGas(final long initialGas) {
this.initialGas = initialGas;
return this;
}
public TestMessageFrameBuilder sender(final Address sender) {
this.sender = sender;
return this;
}
public TestMessageFrameBuilder address(final Address address) {
this.address = address;
return this;
}
TestMessageFrameBuilder originator(final Address originator) {
this.originator = originator;
return this;
}
public TestMessageFrameBuilder contract(final Address contract) {
this.contract = contract;
return this;
}
public TestMessageFrameBuilder gasPrice(final Wei gasPrice) {
this.gasPrice = gasPrice;
return this;
}
public TestMessageFrameBuilder value(final Wei value) {
this.value = value;
return this;
}
TestMessageFrameBuilder inputData(final Bytes inputData) {
this.inputData = inputData;
return this;
}
public TestMessageFrameBuilder code(final Code code) {
this.code = code;
return this;
}
public TestMessageFrameBuilder pc(final int pc) {
this.pc = pc;
return this;
}
public TestMessageFrameBuilder blockValues(final BlockValues blockValues) {
this.blockValues = Optional.of(blockValues);
return this;
}
public TestMessageFrameBuilder depth(final int depth) {
this.depth = depth;
return this;
}
public TestMessageFrameBuilder pushStackItem(final Bytes item) {
stackItems.add(item);
return this;
}
public TestMessageFrameBuilder blockHashLookup(final Function<Long, Hash> blockHashLookup) {
this.blockHashLookup = Optional.of(blockHashLookup);
return this;
}
public MessageFrame build() {
final MessageFrame frame =
MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(messageFrameStack)
.worldUpdater(worldUpdater.orElseGet(this::createDefaultWorldUpdater))
.initialGas(initialGas)
.address(address)
.originator(originator)
.gasPrice(gasPrice)
.inputData(inputData)
.sender(sender)
.value(value)
.apparentValue(value)
.contract(contract)
.code(code)
.blockValues(blockValues.orElseGet(() -> new FakeBlockValues(1337)))
.depth(depth)
.completer(c -> {})
.miningBeneficiary(Address.ZERO)
.blockHashLookup(
blockHashLookup.orElse(number -> Hash.hash(Bytes.ofUnsignedLong(number))))
.maxStackSize(maxStackSize)
.build();
frame.setPC(pc);
stackItems.forEach(frame::pushStackItem);
return frame;
}
private WorldUpdater createDefaultWorldUpdater() {
return new ToyWorld();
}
}

@ -48,10 +48,6 @@ public class ToyAccount implements EvmAccount, MutableAccount {
Suppliers.memoize(() -> code == null ? Hash.EMPTY : Hash.hash(code));
private final Map<UInt256, UInt256> storage = new HashMap<>();
public ToyAccount(final Address address, final long nonce, final Wei balance) {
this(null, address, nonce, balance, Bytes.EMPTY);
}
public ToyAccount(
final Account parent,
final Address address,
@ -99,8 +95,10 @@ public class ToyAccount implements EvmAccount, MutableAccount {
public UInt256 getStorageValue(final UInt256 key) {
if (storage.containsKey(key)) {
return storage.get(key);
} else {
} else if (parent != null) {
return getOriginalStorageValue(key);
} else {
return UInt256.ZERO;
}
}
@ -109,7 +107,7 @@ public class ToyAccount implements EvmAccount, MutableAccount {
if (parent != null) {
return parent.getStorageValue(key);
} else {
return UInt256.ZERO;
return getStorageValue(key);
}
}

@ -27,6 +27,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
public class ToyWorld implements WorldUpdater {
ToyWorld parent;
@ -58,7 +60,16 @@ public class ToyWorld implements WorldUpdater {
@Override
public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) {
ToyAccount account = new ToyAccount(address, nonce, balance);
return createAccount(null, address, nonce, balance, Bytes.EMPTY);
}
public EvmAccount createAccount(
final Account parentAccount,
final Address address,
final long nonce,
final Wei balance,
final Bytes code) {
ToyAccount account = new ToyAccount(parentAccount, address, nonce, balance, code);
accounts.put(address, account);
return account;
}
@ -68,7 +79,17 @@ public class ToyWorld implements WorldUpdater {
if (accounts.containsKey(address)) {
return accounts.get(address);
} else if (parent != null) {
return parent.getAccount(address);
Account parentAccount = parent.getAccount(address);
if (parentAccount == null) {
return null;
} else {
return createAccount(
parentAccount,
parentAccount.getAddress(),
parentAccount.getNonce(),
parentAccount.getBalance(),
parentAccount.getCode());
}
} else {
return null;
}
@ -99,7 +120,9 @@ public class ToyWorld implements WorldUpdater {
@Override
public void commit() {
parent.accounts.putAll(accounts);
if (parent != null) {
parent.accounts.putAll(accounts);
}
}
@Override

Loading…
Cancel
Save