Update eth call post 1559 (#2445)

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
pull/2463/head
matkt 3 years ago committed by GitHub
parent e92c9bc697
commit 87e8770c50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java
  2. 138
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java
  3. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java
  4. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java
  5. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java
  6. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java
  7. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockHashAndIndexIntegrationTest.java
  8. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockNumberAndIndexIntegrationTest.java
  9. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java
  10. 270
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java
  11. 59
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java
  12. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java
  13. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java
  14. 16
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java
  15. 24
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_gasPriceTooHigh_block_8.json
  16. 59
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  17. 13
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
  18. 28
      testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java
  19. BIN
      testutil/src/main/resources/fork-london-data/testLondonBlockchain.blocks
  20. 23
      testutil/src/main/resources/fork-london-data/testLondonGenesis.json

@ -31,7 +31,6 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@ -76,8 +75,8 @@ public class JsonRpcTestMethodsFactory {
final MutableBlockchain blockchain = createInMemoryBlockchain(importer.getGenesisBlock());
final ProtocolContext context = new ProtocolContext(blockchain, stateArchive, null);
final ProtocolSchedule protocolSchedule = importer.getProtocolSchedule();
for (final Block block : importer.getBlocks()) {
final ProtocolSchedule protocolSchedule = importer.getProtocolSchedule();
final ProtocolSpec protocolSpec =
protocolSchedule.getByBlockNumber(block.getHeader().getNumber());
final BlockImporter blockImporter = protocolSpec.getBlockImporter();
@ -127,7 +126,7 @@ public class JsonRpcTestMethodsFactory {
peerDiscovery,
blockchainQueries,
synchronizer,
ProtocolScheduleFixture.MAINNET,
protocolSchedule,
filterManager,
transactionPool,
miningCoordinator,

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
@ -200,6 +200,142 @@ public class EthCallIntegrationTest {
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithGasPriceTooHigh() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"),
null,
Wei.fromHexString("0x10000000000000"),
null,
null,
null,
Bytes.fromHexString("0x12a7b914"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithValidGasPrice() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"),
null,
Wei.fromHexString("0x10"),
null,
null,
null,
Bytes.fromHexString("0x12a7b914"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithGasPriceAndEmptyBalance() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xdeadbeef00000000000000000000000000000000"),
Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"),
null,
Wei.fromHexString("0x10"),
null,
null,
null,
Bytes.fromHexString("0x12a7b914"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithZeroGasPriceAndEmptyBalance() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xdeadbeef00000000000000000000000000000000"),
Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"),
null,
Wei.fromHexString("0x0"),
null,
null,
null,
Bytes.fromHexString("0x12a7b914"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithoutGasPriceAndEmptyBalance() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xdeadbeef00000000000000000000000000000000"),
Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"),
null,
null,
null,
null,
null,
Bytes.fromHexString("0x12a7b914"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithInvalidGasPricingAndEmptyBalance() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xdeadbeef00000000000000000000000000000000"),
Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"),
null,
null,
Wei.fromHexString("0x0A"),
null,
null,
Bytes.fromHexString("0x12a7b914"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnEmptyHashResultForCallWithOnlyToField() {
final JsonCallParameter callParameter =

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static org.assertj.core.api.Assertions.assertThat;

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static org.assertj.core.api.Assertions.assertThat;

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static org.assertj.core.api.Assertions.assertThat;

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static org.assertj.core.api.Assertions.assertThat;

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
package org.hyperledger.besu.ethereum.api.jsonrpc.methods.fork.frontier;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;

@ -0,0 +1,270 @@
/*
* 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.ethereum.api.jsonrpc.methods.fork.london;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.ethereum.api.jsonrpc.BlockchainImporter;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcTestMethodsFactory;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.testutil.BlockTestUtil;
import java.util.Map;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import org.apache.tuweni.bytes.Bytes;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class EthCallIntegrationTest {
private static JsonRpcTestMethodsFactory BLOCKCHAIN;
private JsonRpcMethod method;
@BeforeClass
public static void setUpOnce() throws Exception {
final String genesisJson =
Resources.toString(BlockTestUtil.getTestLondonGenesisUrl(), Charsets.UTF_8);
BLOCKCHAIN =
new JsonRpcTestMethodsFactory(
new BlockchainImporter(BlockTestUtil.getTestLondonBlockchainUrl(), genesisJson));
}
@Before
public void setUp() {
final Map<String, JsonRpcMethod> methods = BLOCKCHAIN.methods();
method = methods.get("eth_call");
}
@Test
public void shouldReturnSuccessWithoutGasPriceAndEmptyBalance() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xdeadbeef00000000000000000000000000000000"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
null,
null,
null,
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithGasPriceTooHigh() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
Wei.fromHexString("0x10000000000000"),
null,
null,
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithValidGasPrice() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
Wei.fromHexString("0x3B9ACA01"),
null,
null,
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithGasPriceLessThanCurrentBaseFee() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
Wei.fromHexString("0x0A"),
null,
null,
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.INVALID_PARAMS);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithValidMaxFeePerGas() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
null,
null,
Wei.fromHexString("0x3B9ACA01"),
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnSuccessWithValidMaxFeePerGasAndMaxPriorityFeePerGas() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
null,
Wei.fromHexString("0x3B9ACA00"),
Wei.fromHexString("0x3B9ACA01"),
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
null, "0x0000000000000000000000000000000000000000000000000000000000000001");
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithValidMaxFeePerGasLessThanCurrentBaseFee() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
null,
null,
Wei.fromHexString("0x0A"),
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.INVALID_PARAMS);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithValidMaxFeePerGasLessThanMaxPriorityFeePerGas() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
null,
Wei.fromHexString("0x3B9ACA02"),
Wei.fromHexString("0x3B9ACA01"),
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
null, JsonRpcError.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWithMaxFeePerGasAndEmptyBalance() {
final JsonCallParameter callParameter =
new JsonCallParameter(
Address.fromHexString("0xdeadbeef00000000000000000000000000000000"),
Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"),
null,
null,
null,
Wei.fromHexString("0x3B9ACA01"),
null,
Bytes.fromHexString("0x2e64cec1"),
null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
final JsonRpcResponse response = method.response(request);
assertThat(response).isEqualToComparingFieldByField(expectedResponse);
}
private JsonRpcRequestContext requestWithParams(final Object... params) {
return new JsonRpcRequestContext(new JsonRpcRequest("2.0", "eth_call", params));
}
}

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.BLOCK_NOT_FOUND;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
@ -29,6 +30,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSucces
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
@ -60,16 +62,17 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
@Override
protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
final JsonCallParameter callParams = validateAndGetCallParams(request);
JsonCallParameter callParams = validateAndGetCallParams(request);
final BlockHeader header = blockchainQueries.get().getBlockHeaderByHash(blockHash).orElse(null);
if (header == null) {
return errorResponse(request, BLOCK_NOT_FOUND);
}
return transactionSimulator
.process(
callParams,
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(!callParams.isStrict())
.build(),
buildTransactionValidationParams(header, callParams),
OperationTracer.NO_TRACING,
header)
.map(
@ -86,7 +89,7 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
new JsonRpcErrorResponse(
request.getRequest().getId(),
JsonRpcErrorConverter.convertTransactionInvalidReason(reason))))
.orElse(errorResponse(request, BLOCK_NOT_FOUND));
.orElse(errorResponse(request, INTERNAL_ERROR));
}
@Override
@ -134,4 +137,48 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
}
return callParams;
}
private TransactionValidationParams buildTransactionValidationParams(
final BlockHeader header, final JsonCallParameter callParams) {
ImmutableTransactionValidationParams.Builder transactionValidationParams =
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator());
// if it is not set explicitly whether we want a strict check of the balance or not. this will
// be decided according to the provided parameters
if (callParams.isMaybeStrict().isEmpty()) {
boolean isZeroGasPrice =
callParams.getGasPrice() == null || Wei.ZERO.equals(callParams.getGasPrice());
header
.getBaseFee()
.ifPresentOrElse(
__ -> {
boolean isZeroMaxFeePerGas =
callParams.getMaxFeePerGas().orElse(Wei.ZERO).equals(Wei.ZERO);
boolean isZeroMaxPriorityFeePerGas =
callParams.getMaxPriorityFeePerGas().orElse(Wei.ZERO).equals(Wei.ZERO);
if (isZeroGasPrice && isZeroMaxFeePerGas && isZeroMaxPriorityFeePerGas) {
// After 1559, when gas pricing is not provided, 0 is used and the balance is not
// checked
transactionValidationParams.isAllowExceedingBalance(true);
} else {
// After 1559, when gas price is provided, it is interpreted as both the max and
// priority fee and the balance is checked
transactionValidationParams.isAllowExceedingBalance(false);
}
},
() -> {
// Prior 1559, when gas price == 0 or is not provided the balance is not checked
transactionValidationParams.isAllowExceedingBalance(isZeroGasPrice);
});
} else {
transactionValidationParams.isAllowExceedingBalance(
!callParams.isMaybeStrict().orElse(Boolean.FALSE));
}
return transactionValidationParams.build();
}
}

@ -82,7 +82,7 @@ public class EthEstimateGas implements JsonRpcMethod {
modifiedCallParams,
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(!callParams.isStrict())
.isAllowExceedingBalance(!callParams.isMaybeStrict().orElse(Boolean.FALSE))
.build(),
operationTracer,
blockHeader.getNumber())

@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
import static java.lang.Boolean.FALSE;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
@ -34,7 +32,7 @@ import org.apache.tuweni.bytes.Bytes;
@JsonIgnoreProperties({"nonce", "privateFor"})
public class JsonCallParameter extends CallParameter {
private final boolean strict;
private final Optional<Boolean> strict;
@JsonCreator
public JsonCallParameter(
@ -57,10 +55,10 @@ public class JsonCallParameter extends CallParameter {
Optional.ofNullable(maxFeePerGas),
value,
payload);
this.strict = Optional.ofNullable(strict).orElse(FALSE);
this.strict = Optional.ofNullable(strict);
}
public boolean isStrict() {
public Optional<Boolean> isMaybeStrict() {
return strict;
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.BLOCK_NOT_FOUND;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
@ -36,6 +37,7 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.ChainHead;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Wei;
@ -102,11 +104,13 @@ public class EthCallTest {
@Test
public void shouldReturnInternalErrorWhenProcessorReturnsEmpty() {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest");
final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, BLOCK_NOT_FOUND);
final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, INTERNAL_ERROR);
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchainQueries.getBlockchain().getChainHead()).thenReturn(chainHead);
when(blockchainQueries.getBlockchain().getChainHead().getHash()).thenReturn(Hash.ZERO);
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class)));
when(transactionSimulator.process(any(), any(), any(), any())).thenReturn(Optional.empty());
final JsonRpcResponse response = method.response(request);
@ -128,6 +132,8 @@ public class EthCallTest {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchainQueries.getBlockchain().getChainHead()).thenReturn(chainHead);
when(blockchainQueries.getBlockchain().getChainHead().getHash()).thenReturn(Hash.ZERO);
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class)));
final JsonRpcResponse response = method.response(request);
@ -144,6 +150,8 @@ public class EthCallTest {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchainQueries.getBlockchain().getChainHead()).thenReturn(chainHead);
when(blockchainQueries.getBlockchain().getChainHead().getHash()).thenReturn(Hash.ZERO);
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class)));
final JsonRpcResponse response = method.response(request);
@ -157,6 +165,8 @@ public class EthCallTest {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchainQueries.getBlockchain().getChainHead()).thenReturn(chainHead);
when(blockchainQueries.getBlockchain().getChainHead().getHash()).thenReturn(Hash.ZERO);
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class)));
when(transactionSimulator.process(any(), any(), any(), any())).thenReturn(Optional.empty());
method.response(request);
@ -169,6 +179,8 @@ public class EthCallTest {
public void shouldUseCorrectBlockNumberWhenEarliest() {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "earliest");
when(blockchainQueries.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(Hash.ZERO));
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class)));
when(transactionSimulator.process(any(), any(), any(), any())).thenReturn(Optional.empty());
method.response(request);
@ -181,6 +193,8 @@ public class EthCallTest {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), Quantity.create(13L));
when(blockchainQueries.headBlockNumber()).thenReturn(14L);
when(blockchainQueries.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(Hash.ZERO));
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class)));
when(transactionSimulator.process(any(), any(), any(), any())).thenReturn(Optional.empty());
method.response(request);

@ -8,7 +8,8 @@
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"gasPrice": "0x10000000000000"
"gasPrice": "0x10000000000000",
"strict": false
},
"0x8"
]
@ -17,6 +18,19 @@
"id": 4,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"gasPrice": "0x10000000000000"
},
"0x8"
]
},
{
"id": 5,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
@ -41,6 +55,14 @@
"code": -32004,
"message": "Upfront cost exceeds account balance"
}
},
{
"jsonrpc": "2.0",
"id": 5,
"error": {
"code": -32004,
"message": "Upfront cost exceeds account balance"
}
}
],
"statusCode": 200

@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
@ -151,41 +152,65 @@ public class TransactionSimulator {
}
final WorldUpdater updater = getEffectiveWorldStateUpdater(header, publicWorldState);
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockNumber(header.getNumber());
final Address senderAddress =
callParams.getFrom() != null ? callParams.getFrom() : DEFAULT_FROM;
final Account sender = publicWorldState.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L;
final long gasLimit =
callParams.getGasLimit() >= 0 ? callParams.getGasLimit() : header.getGasLimit();
final Wei gasPrice = callParams.getGasPrice() != null ? callParams.getGasPrice() : Wei.ZERO;
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;
BlockHeader blockHeaderToProcess = header;
if (transactionValidationParams.isAllowExceedingBalance()) {
updater.getOrCreate(senderAddress).getMutable().setBalance(Wei.of(UInt256.MAX_VALUE));
if (header.getBaseFee().isPresent()) {
blockHeaderToProcess =
BlockHeaderBuilder.fromHeader(header)
.baseFee(0L)
.blockHeaderFunctions(protocolSpec.getBlockHeaderFunctions())
.buildBlockHeader();
}
}
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockNumber(header.getNumber());
final Account sender = publicWorldState.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L;
final Wei gasPrice = callParams.getGasPrice() != null ? callParams.getGasPrice() : Wei.ZERO;
final long gasLimit =
callParams.getGasLimit() >= 0
? callParams.getGasLimit()
: blockHeaderToProcess.getGasLimit();
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;
final MainnetTransactionProcessor transactionProcessor =
protocolSchedule.getByBlockNumber(header.getNumber()).getTransactionProcessor();
protocolSchedule
.getByBlockNumber(blockHeaderToProcess.getNumber())
.getTransactionProcessor();
final Transaction.Builder transactionBuilder =
Transaction.builder()
.nonce(nonce)
.gasPrice(gasPrice)
.gasLimit(gasLimit)
.to(callParams.getTo())
.sender(senderAddress)
.value(value)
.payload(payload)
.signature(FAKE_SIGNATURE);
callParams.getMaxPriorityFeePerGas().ifPresent(transactionBuilder::maxPriorityFeePerGas);
callParams.getMaxFeePerGas().ifPresent(transactionBuilder::maxFeePerGas);
if (header.getBaseFee().isEmpty()) {
transactionBuilder.gasPrice(gasPrice);
} else if (protocolSchedule.getChainId().isPresent()) {
transactionBuilder
.maxFeePerGas(callParams.getMaxFeePerGas().orElse(gasPrice))
.maxPriorityFeePerGas(callParams.getMaxPriorityFeePerGas().orElse(gasPrice));
} else {
return Optional.empty();
}
transactionBuilder.guessType();
if (transactionBuilder.getTransactionType().requiresChainId()) {
transactionBuilder.chainId(BigInteger.ONE); // needed to make some transactions valid
transactionBuilder.chainId(
protocolSchedule
.getChainId()
.orElse(BigInteger.ONE)); // needed to make some transactions valid
}
final Transaction transaction = transactionBuilder.build();
@ -193,10 +218,12 @@ public class TransactionSimulator {
transactionProcessor.processTransaction(
blockchain,
updater,
header,
blockHeaderToProcess,
transaction,
protocolSpec.getMiningBeneficiaryCalculator().calculateBeneficiary(header),
new BlockHashLookup(header, blockchain),
protocolSpec
.getMiningBeneficiaryCalculator()
.calculateBeneficiary(blockHeaderToProcess),
new BlockHashLookup(blockHeaderToProcess, blockchain),
false,
transactionValidationParams,
operationTracer);

@ -400,7 +400,7 @@ public class TransactionSimulatorTest {
public void shouldReturnSuccessfulResultWhenEip1559TransactionProcessingIsSuccessful() {
final CallParameter callParameter = eip1559TransactionCallParameter();
mockBlockchainForBlockHeader(Hash.ZERO, 1L);
mockBlockchainForBlockHeader(Hash.ZERO, 1L, 1L);
mockWorldStateForAccount(Hash.ZERO, callParameter.getFrom(), 1L);
final Transaction expectedTransaction =
@ -408,7 +408,6 @@ public class TransactionSimulatorTest {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
@ -466,8 +465,18 @@ public class TransactionSimulatorTest {
when(blockchain.getBlockHeader(headerHash)).thenReturn(Optional.of(blockHeader));
}
private void mockBlockchainForBlockHeader(
final Hash stateRoot, final long blockNumber, final long baseFee) {
final BlockHeader blockHeader = mock(BlockHeader.class);
when(blockHeader.getStateRoot()).thenReturn(stateRoot);
when(blockHeader.getNumber()).thenReturn(blockNumber);
when(blockHeader.getBaseFee()).thenReturn(Optional.of(baseFee));
when(blockchain.getBlockHeader(blockNumber)).thenReturn(Optional.of(blockHeader));
}
private void mockProcessorStatusForTransaction(
final long blockNumber, final Transaction transaction, final Status status) {
when(protocolSchedule.getChainId()).thenReturn(Optional.of(BigInteger.ONE));
when(protocolSchedule.getByBlockNumber(eq(blockNumber))).thenReturn(protocolSpec);
when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor);
when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase);

@ -33,6 +33,8 @@ public final class BlockTestUtil {
private static final Supplier<ChainResources> testChainSupplier =
Suppliers.memoize(BlockTestUtil::supplyTestChainResources);
private static final Supplier<ChainResources> testChainLondonSupplier =
Suppliers.memoize(BlockTestUtil::supplyTestChainLondonResources);
private static final Supplier<ChainResources> mainnetChainSupplier =
Suppliers.memoize(BlockTestUtil::supplyMainnetChainResources);
private static final Supplier<ChainResources> badPowChainSupplier =
@ -46,14 +48,26 @@ public final class BlockTestUtil {
return getTestChainResources().getBlocksURL();
}
public static URL getTestLondonBlockchainUrl() {
return getTestChainLondonResources().getBlocksURL();
}
public static URL getTestGenesisUrl() {
return getTestChainResources().getGenesisURL();
}
public static URL getTestLondonGenesisUrl() {
return getTestChainLondonResources().getGenesisURL();
}
public static ChainResources getTestChainResources() {
return testChainSupplier.get();
}
public static ChainResources getTestChainLondonResources() {
return testChainLondonSupplier.get();
}
public static ChainResources getMainnetResources() {
return mainnetChainSupplier.get();
}
@ -78,6 +92,20 @@ public final class BlockTestUtil {
return new ChainResources(genesisURL, blocksURL);
}
private static ChainResources supplyTestChainLondonResources() {
final URL genesisURL =
ensureFileUrl(
BlockTestUtil.class
.getClassLoader()
.getResource("fork-london-data/testLondonGenesis.json"));
final URL blocksURL =
ensureFileUrl(
BlockTestUtil.class
.getClassLoader()
.getResource("fork-london-data/testLondonBlockchain.blocks"));
return new ChainResources(genesisURL, blocksURL);
}
private static ChainResources supplyMainnetChainResources() {
final URL genesisURL =
ensureFileUrl(

@ -0,0 +1,23 @@
{
"config": {
"londonBlock":3,
"ethash": {
"fixeddifficulty": 15
},
"chainID": 1982,
"networkID": 1982
},
"nonce": "0x0000000000000042",
"gasLimit": "0x100000000",
"difficulty": "0xf",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"fe3b557e8fb62b89f4916b721be55ceb828dbd73": {
"balance" : "90000000000000000000000"
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance" : "90000000000000000000000"
}
}
}
Loading…
Cancel
Save