Support chainId in CallParameters (#7720)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
pull/7729/head
Fabio Di Fabio 2 months ago committed by GitHub
parent 67d738c8a1
commit 5fd87d61f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 12
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java
  3. 22
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java
  4. 30
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthEstimateGasIntegrationTest.java
  5. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java
  6. 19
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java
  7. 46
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java
  8. 18
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java
  9. 9
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  10. 1
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java

@ -18,7 +18,8 @@
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
- Interrupt pending transaction processing on block creation timeout [#7673](https://github.com/hyperledger/besu/pull/7673)
- Align gas cap calculation for transaction simulation to Geth approach [#7703](https://github.com/hyperledger/besu/pull/7703)
- Expose chainId in the `BlockchainService` [7702](https://github.com/hyperledger/besu/pull/7702)
- Expose chainId in the `BlockchainService` [#7702](https://github.com/hyperledger/besu/pull/7702)
- Add support for `chainId` in `CallParameters` [#7720](https://github.com/hyperledger/besu/pull/7720)
### Bug fixes
- Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575)

@ -68,7 +68,6 @@ public class JsonRpcTestMethodsFactory {
private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0";
private static final String CLIENT_VERSION = "0.1.0";
private static final String CLIENT_COMMIT = "12345678";
private static final BigInteger NETWORK_ID = BigInteger.valueOf(123);
private final BlockchainImporter importer;
private final MutableBlockchain blockchain;
@ -76,6 +75,7 @@ public class JsonRpcTestMethodsFactory {
private final ProtocolContext context;
private final BlockchainQueries blockchainQueries;
private final Synchronizer synchronizer;
private final ProtocolSchedule protocolSchedule;
public JsonRpcTestMethodsFactory(final BlockchainImporter importer) {
this.importer = importer;
@ -84,7 +84,7 @@ public class JsonRpcTestMethodsFactory {
this.importer.getGenesisState().writeStateTo(stateArchive.getMutable());
this.context = new ProtocolContext(blockchain, stateArchive, null, new BadBlockManager());
final ProtocolSchedule protocolSchedule = importer.getProtocolSchedule();
this.protocolSchedule = importer.getProtocolSchedule();
this.synchronizer = mock(Synchronizer.class);
for (final Block block : importer.getBlocks()) {
@ -106,6 +106,7 @@ public class JsonRpcTestMethodsFactory {
this.blockchain = blockchain;
this.stateArchive = stateArchive;
this.context = context;
this.protocolSchedule = importer.getProtocolSchedule();
this.blockchainQueries =
new BlockchainQueries(
importer.getProtocolSchedule(),
@ -126,6 +127,7 @@ public class JsonRpcTestMethodsFactory {
this.stateArchive = stateArchive;
this.context = context;
this.synchronizer = synchronizer;
this.protocolSchedule = importer.getProtocolSchedule();
this.blockchainQueries =
new BlockchainQueries(
importer.getProtocolSchedule(),
@ -142,6 +144,10 @@ public class JsonRpcTestMethodsFactory {
return stateArchive;
}
public BigInteger getChainId() {
return protocolSchedule.getChainId().get();
}
public Map<String, JsonRpcMethod> methods() {
final P2PNetwork peerDiscovery = mock(P2PNetwork.class);
final EthPeers ethPeers = mock(EthPeers.class);
@ -183,7 +189,7 @@ public class JsonRpcTestMethodsFactory {
CLIENT_NODE_NAME,
CLIENT_VERSION,
CLIENT_COMMIT,
NETWORK_ID,
getChainId(),
new StubGenesisConfigOptions(),
peerDiscovery,
blockchainQueries,

@ -30,6 +30,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSucces
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.testutil.BlockTestUtil;
import java.math.BigInteger;
import java.util.Map;
import com.google.common.base.Charsets;
@ -142,6 +143,7 @@ public class EthCallIntegrationTest {
public void shouldReturnSuccessWithValidMaxFeePerGas() {
final JsonCallParameter callParameter =
new JsonCallParameter.JsonCallParameterBuilder()
.withChainId(BLOCKCHAIN.getChainId())
.withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"))
.withTo(Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"))
.withMaxFeePerGas(Wei.fromHexString("0x3B9ACA01"))
@ -158,6 +160,26 @@ public class EthCallIntegrationTest {
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnErrorWithInvalidChainId() {
final JsonCallParameter callParameter =
new JsonCallParameter.JsonCallParameterBuilder()
.withChainId(BLOCKCHAIN.getChainId().add(BigInteger.ONE))
.withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"))
.withTo(Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517"))
.withMaxFeePerGas(Wei.fromHexString("0x3B9ACA01"))
.withInput(Bytes.fromHexString("0x2e64cec1"))
.build();
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.WRONG_CHAIN_ID);
final JsonRpcResponse response = method.response(request);
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnSuccessWithValidMaxFeePerGasAndMaxPriorityFeePerGas() {
final JsonCallParameter callParameter =

@ -25,10 +25,15 @@ 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.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.testutil.BlockTestUtil;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
@ -112,6 +117,7 @@ public class EthEstimateGasIntegrationTest {
public void shouldReturnExpectedValueForContractDeploy_WithAccessList() {
final JsonCallParameter callParameter =
new JsonCallParameter.JsonCallParameterBuilder()
.withChainId(BLOCKCHAIN.getChainId())
.withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"))
.withInput(
Bytes.fromHexString(
@ -124,6 +130,30 @@ public class EthEstimateGasIntegrationTest {
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnErrorWithInvalidChainId() {
final JsonCallParameter callParameter =
new JsonCallParameter.JsonCallParameterBuilder()
.withChainId(BLOCKCHAIN.getChainId().add(BigInteger.ONE))
.withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"))
.withTo(Address.fromHexString("0x8888f1f195afa192cfee860698584c030f4c9db1"))
.withValue(Wei.ONE)
.build();
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
null,
JsonRpcError.from(
ValidationResult.invalid(
TransactionInvalidReason.WRONG_CHAIN_ID,
"transaction was meant for chain id 1983 and not this chain id 1982")));
final JsonRpcResponse response = method.response(request);
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
}
private List<AccessListEntry> createAccessList() {
return List.of(
new AccessListEntry(

@ -103,6 +103,7 @@ public abstract class AbstractEstimateGas extends AbstractBlockParameterMethod {
protected CallParameter overrideGasLimitAndPrice(
final JsonCallParameter callParams, final long gasLimit) {
return new CallParameter(
callParams.getChainId(),
callParams.getFrom(),
callParams.getTo(),
gasLimit,
@ -111,7 +112,9 @@ public abstract class AbstractEstimateGas extends AbstractBlockParameterMethod {
callParams.getMaxFeePerGas(),
callParams.getValue(),
callParams.getPayload(),
callParams.getAccessList());
callParams.getAccessList(),
callParams.getMaxFeePerBlobGas(),
callParams.getBlobVersionedHashes());
}
/**

@ -18,10 +18,12 @@ import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.json.ChainIdDeserializer;
import org.hyperledger.besu.ethereum.core.json.GasDeserializer;
import org.hyperledger.besu.ethereum.core.json.HexStringDeserializer;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
@ -41,6 +43,7 @@ import org.slf4j.LoggerFactory;
*
* <pre>{@code
* JsonCallParameter param = new JsonCallParameter.JsonCallParameterBuilder()
* .withChainId(Optional.of(BigInteger.ONE))
* .withFrom(Address.fromHexString("0x..."))
* .withTo(Address.fromHexString("0x..."))
* .withGas(21000L)
@ -71,6 +74,7 @@ public class JsonCallParameter extends CallParameter {
private final Optional<Boolean> strict;
private JsonCallParameter(
final Optional<BigInteger> chainId,
final Address from,
final Address to,
final Long gasLimit,
@ -85,6 +89,7 @@ public class JsonCallParameter extends CallParameter {
final Optional<List<VersionedHash>> blobVersionedHashes) {
super(
chainId,
from,
to,
gasLimit,
@ -115,6 +120,7 @@ public class JsonCallParameter extends CallParameter {
*/
public static final class JsonCallParameterBuilder {
private Optional<Boolean> strict = Optional.empty();
private Optional<BigInteger> chainId = Optional.empty();
private Address from;
private Address to;
private long gas = -1;
@ -145,6 +151,18 @@ public class JsonCallParameter extends CallParameter {
return this;
}
/**
* Sets the optional "chainId" for the {@link JsonCallParameter}.
*
* @param chainId the chainId
* @return the {@link JsonCallParameterBuilder} instance for chaining
*/
@JsonDeserialize(using = ChainIdDeserializer.class)
public JsonCallParameterBuilder withChainId(final BigInteger chainId) {
this.chainId = Optional.of(chainId);
return this;
}
/**
* Sets the "from" address for the {@link JsonCallParameter}. This address represents the sender
* of the call.
@ -346,6 +364,7 @@ public class JsonCallParameter extends CallParameter {
final Bytes payload = input != null ? input : data;
return new JsonCallParameter(
chainId,
from,
to,
gas,

@ -0,0 +1,46 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.json;
import java.io.IOException;
import java.math.BigInteger;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.apache.tuweni.units.bigints.UInt256;
public class ChainIdDeserializer extends StdDeserializer<BigInteger> {
public ChainIdDeserializer() {
this(null);
}
public ChainIdDeserializer(final Class<?> vc) {
super(vc);
}
@Override
public BigInteger deserialize(final JsonParser jsonparser, final DeserializationContext context)
throws IOException {
final var chainId =
UInt256.fromHexString(jsonparser.getCodec().readValue(jsonparser, String.class))
.toBigInteger();
if (chainId.signum() <= 0) {
throw new IllegalArgumentException("Non positive chain id: " + chainId);
}
return chainId;
}
}

@ -20,6 +20,7 @@ import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import java.math.BigInteger;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -28,6 +29,7 @@ import org.apache.tuweni.bytes.Bytes;
// Represents parameters for eth_call and eth_estimateGas JSON-RPC methods.
public class CallParameter {
private final Optional<BigInteger> chainId;
private final Address from;
@ -56,6 +58,7 @@ public class CallParameter {
final Wei gasPrice,
final Wei value,
final Bytes payload) {
this.chainId = Optional.empty();
this.from = from;
this.to = to;
this.gasLimit = gasLimit;
@ -79,6 +82,7 @@ public class CallParameter {
final Wei value,
final Bytes payload,
final Optional<List<AccessListEntry>> accessList) {
this.chainId = Optional.empty();
this.from = from;
this.to = to;
this.gasLimit = gasLimit;
@ -93,6 +97,7 @@ public class CallParameter {
}
public CallParameter(
final Optional<BigInteger> chainId,
final Address from,
final Address to,
final long gasLimit,
@ -104,6 +109,7 @@ public class CallParameter {
final Optional<List<AccessListEntry>> accessList,
final Optional<Wei> maxFeePerBlobGas,
final Optional<List<VersionedHash>> blobVersionedHashes) {
this.chainId = chainId;
this.from = from;
this.to = to;
this.gasLimit = gasLimit;
@ -117,6 +123,10 @@ public class CallParameter {
this.blobVersionedHashes = blobVersionedHashes;
}
public Optional<BigInteger> getChainId() {
return chainId;
}
public Address getFrom() {
return from;
}
@ -171,6 +181,7 @@ public class CallParameter {
}
final CallParameter that = (CallParameter) o;
return gasLimit == that.gasLimit
&& chainId.equals(that.chainId)
&& Objects.equals(from, that.from)
&& Objects.equals(to, that.to)
&& Objects.equals(gasPrice, that.gasPrice)
@ -186,6 +197,7 @@ public class CallParameter {
@Override
public int hashCode() {
return Objects.hash(
chainId,
from,
to,
gasLimit,
@ -202,7 +214,9 @@ public class CallParameter {
@Override
public String toString() {
return "CallParameter{"
+ "from="
+ "chainId="
+ chainId
+ ", from="
+ from
+ ", to="
+ to
@ -229,6 +243,7 @@ public class CallParameter {
public static CallParameter fromTransaction(final Transaction tx) {
return new CallParameter(
tx.getChainId(),
tx.getSender(),
tx.getTo().orElse(null),
tx.getGasLimit(),
@ -244,6 +259,7 @@ public class CallParameter {
public static CallParameter fromTransaction(final org.hyperledger.besu.datatypes.Transaction tx) {
return new CallParameter(
tx.getChainId(),
tx.getSender(),
tx.getTo().orElse(null),
tx.getGasLimit(),

@ -369,10 +369,13 @@ public class TransactionSimulator {
transactionBuilder.maxFeePerBlobGas(maxFeePerBlobGas);
}
if (transactionBuilder.getTransactionType().requiresChainId()) {
transactionBuilder.chainId(
protocolSchedule
callParams
.getChainId()
.orElse(BigInteger.ONE)); // needed to make some transactions valid
.ifPresentOrElse(
transactionBuilder::chainId,
() ->
// needed to make some transactions valid
transactionBuilder.chainId(protocolSchedule.getChainId().orElse(BigInteger.ONE)));
}
final Transaction transaction = transactionBuilder.build();

@ -858,6 +858,7 @@ public class TransactionSimulatorTest {
final int numberOfBlobs) {
BlobsWithCommitments bwc = new BlobTestFixture().createBlobsWithCommitments(numberOfBlobs);
return new CallParameter(
Optional.of(BigInteger.ONE),
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
gasLimit,

Loading…
Cancel
Save