diff --git a/CHANGELOG.md b/CHANGELOG.md index e4486dfbf..fde10cc44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ - Proper support for `pending` block tag when calling `eth_estimateGas` and `eth_createAccessList` [#7951](https://github.com/hyperledger/besu/pull/7951) ### Bug fixes -- Correct default parameters for frontier transactions in `eth_call` and `eth_estimateGas` [#7965](https://github.com/hyperledger/besu/pull/7965) +- Correct default parameters for frontier transactions in `eth_call` and `eth_estimateGas` [#7965](https://github.com/hyperledger/besu/pull/7965) ## 24.12.0 @@ -73,6 +73,7 @@ - Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825) - Fix CVE-2024-47535 [7878](https://github.com/hyperledger/besu/pull/7878) - Fix QBFT prepared block based proposal validation [#7875](https://github.com/hyperledger/besu/pull/7875) +- Correctly parse nonce as hex in `eth_call` account overrides [#7999](https://github.com/hyperledger/besu/pull/7999) ## 24.10.0 diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/AccountOverride.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/AccountOverride.java index e414e97eb..8bbc1d3c0 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/AccountOverride.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/AccountOverride.java @@ -21,6 +21,7 @@ import java.util.Optional; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -106,11 +107,11 @@ public class AccountOverride { /** * Sets the nonce override * - * @param nonce the nonce override + * @param nonce the nonce override in hex * @return the builder */ - public Builder withNonce(final Long nonce) { - this.nonce = Optional.ofNullable(nonce); + public Builder withNonce(final String nonce) { + this.nonce = Optional.of(Bytes.fromHexStringLenient(nonce).toLong()); return this; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java index 7de6f65aa..867d1619a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java @@ -104,7 +104,7 @@ public class EthCallTest { @Test public void someAccountOverrides() { AccountOverrideMap expectedOverrides = new AccountOverrideMap(); - AccountOverride override = new AccountOverride.Builder().withNonce(88L).build(); + AccountOverride override = new AccountOverride.Builder().withNonce("0x9e").build(); final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"); expectedOverrides.put(address, override); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java index 74c040824..11010202e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java @@ -116,7 +116,7 @@ public class EthEstimateGasTest { @Test public void someAccountOverrides() { AccountOverrideMap expectedOverrides = new AccountOverrideMap(); - AccountOverride override = new AccountOverride.Builder().withNonce(88L).build(); + AccountOverride override = new AccountOverride.Builder().withNonce("0x9e").build(); final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"); expectedOverrides.put(address, override); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/AccountOverrideParameterTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/AccountOverrideParameterTest.java index 1b6d8c1cb..1b676e8c5 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/AccountOverrideParameterTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/AccountOverrideParameterTest.java @@ -52,7 +52,7 @@ public class AccountOverrideParameterTest { + "\":" + "{" + "\"balance\": \"0x01\"," - + "\"nonce\": 88" + + "\"nonce\": \"0x9e\"" + "}}],\"id\":1}"; final JsonRpcRequestContext request = new JsonRpcRequestContext(readJsonAsJsonRpcRequest(json)); @@ -62,7 +62,7 @@ public class AccountOverrideParameterTest { final AccountOverride accountOverride = accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1)); - assertThat(accountOverride.getNonce()).isEqualTo(Optional.of(88L)); + assertThat(accountOverride.getNonce().get()).isEqualTo(158); assertThat(accountOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1))); assertFalse(accountOverride.getStateDiff().isPresent()); } @@ -96,6 +96,34 @@ public class AccountOverrideParameterTest { assertFalse(accountOverride.getStateDiff().isPresent()); } + @Test + public void jsonWithHexNonceDeserializesCorrectly() throws Exception { + final String json = + "{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{" + + "\"from\":\"0x0\", \"to\": \"0x0\"}, " + + "\"latest\"," + + "{\"" + + ADDRESS_HEX1 + + "\":" + + "{" + + "\"balance\": \"0x01\"," + + "\"nonce\": \"" + + "0x9e" + + "\"" + + "}}],\"id\":1}"; + + final JsonRpcRequestContext request = new JsonRpcRequestContext(readJsonAsJsonRpcRequest(json)); + final AccountOverrideMap accountOverrideParam = + request.getRequiredParameter(2, AccountOverrideMap.class); + + final AccountOverride accountOverride = + accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1)); + + assertThat(accountOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1))); + assertThat(accountOverride.getNonce().get()).isEqualTo(158); // 0x9e + assertFalse(accountOverride.getStateDiff().isPresent()); + } + @Test public void jsonWithStorageOverridesDeserializesCorrectly() throws Exception { final String json = @@ -107,7 +135,7 @@ public class AccountOverrideParameterTest { + "\":" + "{" + "\"balance\": \"0x01\"," - + "\"nonce\": 88," + + "\"nonce\": \"0x9E\"," + "\"stateDiff\": {" + "\"" + STORAGE_KEY @@ -124,7 +152,7 @@ public class AccountOverrideParameterTest { final AccountOverride accountOverride = accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1)); - assertThat(accountOverride.getNonce()).isEqualTo(Optional.of(88L)); + assertThat(accountOverride.getNonce().get()).isEqualTo(158); assertTrue(accountOverride.getStateDiff().isPresent()); assertThat(accountOverride.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE); @@ -141,7 +169,7 @@ public class AccountOverrideParameterTest { + "\":" + "{" + "\"balance\": \"0x01\"," - + "\"nonce\": 88," + + "\"nonce\": \"0x9E\"," + "\"stateDiff\": {" + "\"" + STORAGE_KEY @@ -154,7 +182,7 @@ public class AccountOverrideParameterTest { + "\":" + "{" + "\"balance\": \"0xFF\"," - + "\"nonce\": 99," + + "\"nonce\": \"0x9D\"," + "\"stateDiff\": {" + "\"" + STORAGE_KEY @@ -171,14 +199,14 @@ public class AccountOverrideParameterTest { final AccountOverride accountOverride1 = accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1)); - assertThat(accountOverride1.getNonce()).isEqualTo(Optional.of(88L)); + assertThat(accountOverride1.getNonce().get()).isEqualTo(158); assertThat(accountOverride1.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0x01"))); assertTrue(accountOverride1.getStateDiff().isPresent()); assertThat(accountOverride1.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE); final AccountOverride accountOverride2 = accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX2)); - assertThat(accountOverride2.getNonce()).isEqualTo(Optional.of(99L)); + assertThat(accountOverride2.getNonce().get()).isEqualTo(157); assertThat(accountOverride2.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0xFF"))); assertTrue(accountOverride2.getStateDiff().isPresent()); assertThat(accountOverride2.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index 5d9bea61c..a7977491a 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.evm.operation; import static org.hyperledger.besu.evm.internal.Words.clampedToLong; -import static org.hyperledger.besu.evm.operation.AbstractCallOperation.LEGACY_FAILURE_STACK_ITEM; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; @@ -158,12 +157,18 @@ public abstract class AbstractCreateOperation extends AbstractOperation { */ protected abstract Code getInitCode(MessageFrame frame, EVM evm); - private void fail(final MessageFrame frame) { + /** + * Handles stack items when operation fails for validation reasons (noe enough ether, bad eof + * code) + * + * @param frame the current execution frame + */ + protected void fail(final MessageFrame frame) { final long inputOffset = clampedToLong(frame.getStackItem(1)); final long inputSize = clampedToLong(frame.getStackItem(2)); frame.readMutableMemory(inputOffset, inputSize); frame.popStackItems(getStackItemsConsumed()); - frame.pushStackItem(LEGACY_FAILURE_STACK_ITEM); + frame.pushStackItem(Bytes.EMPTY); } private void spawnChildMessage(final MessageFrame parent, final Code code, final EVM evm) { @@ -227,12 +232,12 @@ public abstract class AbstractCreateOperation extends AbstractOperation { } else { frame.getWorldUpdater().deleteAccount(childFrame.getRecipientAddress()); frame.setReturnData(childFrame.getOutputData()); - frame.pushStackItem(LEGACY_FAILURE_STACK_ITEM); + frame.pushStackItem(Bytes.EMPTY); onInvalid(frame, (CodeInvalid) outputCode); } } else { frame.setReturnData(childFrame.getOutputData()); - frame.pushStackItem(LEGACY_FAILURE_STACK_ITEM); + frame.pushStackItem(Bytes.EMPTY); onFailure(frame, childFrame.getExceptionalHaltReason()); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java index 7a0296bf5..5f6c70eb6 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.evm.operation; +import static org.hyperledger.besu.evm.internal.Words.clampedAdd; import static org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper.deductDelegatedCodeGasCost; import org.hyperledger.besu.datatypes.Address; @@ -116,9 +117,11 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { } if (toBytes.size() > Address.SIZE) { return new OperationResult( - gasCalculator.memoryExpansionGasCost(frame, inputOffset, inputLength) - + (zeroValue ? 0 : gasCalculator.callValueTransferGasCost()) - + gasCalculator.getColdAccountAccessCost(), + clampedAdd( + clampedAdd( + gasCalculator.memoryExpansionGasCost(frame, inputOffset, inputLength), + (zeroValue ? 0 : gasCalculator.callValueTransferGasCost())), + gasCalculator.getColdAccountAccessCost()), ExceptionalHaltReason.ADDRESS_OUT_OF_RANGE); } Address to = Words.toAddress(toBytes); @@ -135,16 +138,21 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { boolean accountCreation = contract == null && !zeroValue; long cost = - gasCalculator.memoryExpansionGasCost(frame, inputOffset, inputLength) - + (zeroValue ? 0 : gasCalculator.callValueTransferGasCost()) - + (frame.warmUpAddress(to) || gasCalculator.isPrecompile(to) - ? gasCalculator.getWarmStorageReadCost() - : gasCalculator.getColdAccountAccessCost()) - + (accountCreation ? gasCalculator.newAccountGasCost() : 0); - long currentGas = frame.getRemainingGas() - cost; - if (currentGas < 0) { + clampedAdd( + clampedAdd( + clampedAdd( + gasCalculator.memoryExpansionGasCost(frame, inputOffset, inputLength), + (zeroValue ? 0 : gasCalculator.callValueTransferGasCost())), + (frame.warmUpAddress(to) || gasCalculator.isPrecompile(to) + ? gasCalculator.getWarmStorageReadCost() + : gasCalculator.getColdAccountAccessCost())), + (accountCreation ? gasCalculator.newAccountGasCost() : 0)); + long currentGas = frame.getRemainingGas(); + if (currentGas < cost) { return new OperationResult(cost, ExceptionalHaltReason.INSUFFICIENT_GAS); } + currentGas -= cost; + frame.expandMemory(inputOffset, inputLength); final Code code = contract == null @@ -202,7 +210,7 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { .build(); frame.setState(MessageFrame.State.CODE_SUSPENDED); - return new OperationResult(cost + childGas, null, 0); + return new OperationResult(clampedAdd(cost, childGas), null, 0); } private @Nonnull OperationResult softFailure(final MessageFrame frame, final long cost) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java index 3ea3ef140..7d3f10a03 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java @@ -16,7 +16,6 @@ package org.hyperledger.besu.evm.operation; import static org.hyperledger.besu.crypto.Hash.keccak256; import static org.hyperledger.besu.evm.internal.Words.clampedAdd; -import static org.hyperledger.besu.evm.internal.Words.clampedToInt; import static org.hyperledger.besu.evm.internal.Words.clampedToLong; import org.hyperledger.besu.datatypes.Address; @@ -49,8 +48,8 @@ public class EOFCreateOperation extends AbstractCreateOperation { @Override public long cost(final MessageFrame frame, final Supplier codeSupplier) { - final int inputOffset = clampedToInt(frame.getStackItem(2)); - final int inputSize = clampedToInt(frame.getStackItem(3)); + final long inputOffset = clampedToLong(frame.getStackItem(2)); + final long inputSize = clampedToLong(frame.getStackItem(3)); return clampedAdd( gasCalculator().memoryExpansionGasCost(frame, inputOffset, inputSize), clampedAdd( @@ -86,4 +85,13 @@ public class EOFCreateOperation extends AbstractCreateOperation { protected int getPcIncrement() { return 2; } + + @Override + protected void fail(final MessageFrame frame) { + final long inputOffset = clampedToLong(frame.getStackItem(2)); + final long inputSize = clampedToLong(frame.getStackItem(3)); + frame.readMutableMemory(inputOffset, inputSize); + frame.popStackItems(getStackItemsConsumed()); + frame.pushStackItem(Bytes.EMPTY); + } }