diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java index ca12c205285..4b7b67691f6 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java @@ -31,7 +31,6 @@ 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 Map methods() { 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 Map methods() { peerDiscovery, blockchainQueries, synchronizer, - ProtocolScheduleFixture.MAINNET, + protocolSchedule, filterManager, transactionPool, miningCoordinator, diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthCallIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java similarity index 61% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthCallIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java index 2d0e82518b0..4b1be001906 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthCallIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java @@ -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 void shouldReturnSuccessWithGasPriceTooHighNotStrict() { 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 = diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthEstimateGasIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java similarity index 99% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthEstimateGasIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java index 943d1b3f2cf..52bd4af1481 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthEstimateGasIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByHashIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java similarity index 99% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByHashIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java index 38cb0cb80c8..14682084997 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByHashIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByNumberIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java similarity index 99% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByNumberIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java index 6fbb74c5b1c..141016122a6 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByNumberIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java similarity index 99% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java index bdb74ad4181..67cfa0b3e04 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetUncleByBlockHashAndIndexIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockHashAndIndexIntegrationTest.java similarity index 98% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetUncleByBlockHashAndIndexIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockHashAndIndexIntegrationTest.java index 11b5b7ad555..e659ff8f60a 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetUncleByBlockHashAndIndexIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockHashAndIndexIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetUncleByBlockNumberAndIndexIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockNumberAndIndexIntegrationTest.java similarity index 98% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetUncleByBlockNumberAndIndexIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockNumberAndIndexIntegrationTest.java index a9df9d765a0..6accd88cd48 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetUncleByBlockNumberAndIndexIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetUncleByBlockNumberAndIndexIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java similarity index 99% rename from ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java rename to ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java index e9cb8933684..ac69ee69201 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java @@ -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; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java new file mode 100644 index 00000000000..39bc1ca33f6 --- /dev/null +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java @@ -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 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)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java index dc7083794aa..61d98ac678c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java @@ -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.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 @@ protected BlockParameterOrBlockHash blockParameterOrBlockHash( @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 @@ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Ha new JsonRpcErrorResponse( request.getRequest().getId(), JsonRpcErrorConverter.convertTransactionInvalidReason(reason)))) - .orElse(errorResponse(request, BLOCK_NOT_FOUND)); + .orElse(errorResponse(request, INTERNAL_ERROR)); } @Override @@ -134,4 +137,48 @@ private JsonCallParameter validateAndGetCallParams(final JsonRpcRequestContext r } 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(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java index 05eee958327..3aabf0b7a8a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java @@ -82,7 +82,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { modifiedCallParams, ImmutableTransactionValidationParams.builder() .from(TransactionValidationParams.transactionSimulator()) - .isAllowExceedingBalance(!callParams.isStrict()) + .isAllowExceedingBalance(!callParams.isMaybeStrict().orElse(Boolean.FALSE)) .build(), operationTracer, blockHeader.getNumber()) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java index 23a5db41943..4638af44850 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java @@ -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 @@ @JsonIgnoreProperties({"nonce", "privateFor"}) public class JsonCallParameter extends CallParameter { - private final boolean strict; + private final Optional strict; @JsonCreator public JsonCallParameter( @@ -57,10 +55,10 @@ public JsonCallParameter( Optional.ofNullable(maxFeePerGas), value, payload); - this.strict = Optional.ofNullable(strict).orElse(FALSE); + this.strict = Optional.ofNullable(strict); } - public boolean isStrict() { + public Optional isMaybeStrict() { return strict; } } 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 e160e2fd5d4..212d91e4b02 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 @@ -17,6 +17,7 @@ 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.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 void shouldThrowInvalidJsonRpcParametersExceptionWhenMissingToField() { @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 void shouldAcceptRequestWhenMissingOptionalFields() { 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 void shouldReturnExecutionResultWhenExecutionIsSuccessful() { 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 void shouldUseCorrectBlockNumberWhenLatest() { 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 void shouldUseCorrectBlockNumberWhenLatest() { 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 void shouldUseCorrectBlockNumberWhenSpecified() { 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); diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_gasPriceTooHigh_block_8.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_gasPriceTooHigh_block_8.json index 89495202b9d..fe81d9f74d8 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_gasPriceTooHigh_block_8.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_gasPriceTooHigh_block_8.json @@ -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 diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index 94e797fa929..de1eddd117c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -24,6 +24,7 @@ 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 Optional process( } 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 Optional process( 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); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java index 30bd5abf5b7..d6be8aba14c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java @@ -400,7 +400,7 @@ public void shouldReturnFailureResultWhenProcessingFailsByHash() { 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 void shouldReturnSuccessfulResultWhenEip1559TransactionProcessingIsSucces .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 @@ private void mockBlockchainForBlockHeader( 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); diff --git a/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java b/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java index d75b728717a..ed65189b920 100644 --- a/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java +++ b/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java @@ -33,6 +33,8 @@ public final class BlockTestUtil { private static final Supplier testChainSupplier = Suppliers.memoize(BlockTestUtil::supplyTestChainResources); + private static final Supplier testChainLondonSupplier = + Suppliers.memoize(BlockTestUtil::supplyTestChainLondonResources); private static final Supplier mainnetChainSupplier = Suppliers.memoize(BlockTestUtil::supplyMainnetChainResources); private static final Supplier badPowChainSupplier = @@ -46,14 +48,26 @@ public static URL getTestBlockchainUrl() { 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 @@ private static ChainResources supplyTestChainResources() { 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( diff --git a/testutil/src/main/resources/fork-london-data/testLondonBlockchain.blocks b/testutil/src/main/resources/fork-london-data/testLondonBlockchain.blocks new file mode 100644 index 00000000000..9d77f2277fe Binary files /dev/null and b/testutil/src/main/resources/fork-london-data/testLondonBlockchain.blocks differ diff --git a/testutil/src/main/resources/fork-london-data/testLondonGenesis.json b/testutil/src/main/resources/fork-london-data/testLondonGenesis.json new file mode 100644 index 00000000000..5d95fdb5093 --- /dev/null +++ b/testutil/src/main/resources/fork-london-data/testLondonGenesis.json @@ -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" + } + } +}