Skip to content

Commit 33bb0b4

Browse files
committed
eth_config prototype
A prototype for eth_cofig, sharing operational client configuration data via RPC. Signed-off-by: Danno Ferrin <danno@numisight.com>
1 parent 5b6cd5f commit 33bb0b4

File tree

24 files changed

+266
-21
lines changed

24 files changed

+266
-21
lines changed

consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,9 @@ public void setPublicWorldStateArchiveForPrivacyBlockProcessor(
244244
public void setProtocolContext(final ProtocolContext protocolContext) {
245245
this.protocolContext = protocolContext;
246246
}
247+
248+
@Override
249+
public Optional<ProtocolSpec> getNextProtocolSpec(final ProtocolSpec currentProtocolSpec) {
250+
return getPostMergeSchedule().getNextProtocolSpec(currentProtocolSpec);
251+
}
247252
}

ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public enum RpcMethod {
9898
ETH_CALL("eth_call"),
9999
ETH_CHAIN_ID("eth_chainId"),
100100
ETH_COINBASE("eth_coinbase"),
101+
ETH_CONFIG("eth_config"),
101102
ETH_ESTIMATE_GAS("eth_estimateGas"),
102103
ETH_CREATE_ACCESS_LIST("eth_createAccessList"),
103104
ETH_FEE_HISTORY("eth_feeHistory"),
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright ConsenSys AG.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
16+
17+
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
18+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
19+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
20+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
21+
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
22+
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
23+
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
24+
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator;
25+
import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry;
26+
27+
import java.nio.charset.StandardCharsets;
28+
import java.util.Map;
29+
import java.util.TreeMap;
30+
import java.util.function.Supplier;
31+
import java.util.zip.CRC32;
32+
33+
import com.fasterxml.jackson.databind.JsonNode;
34+
import com.fasterxml.jackson.databind.ObjectMapper;
35+
import com.fasterxml.jackson.databind.node.ObjectNode;
36+
import com.google.common.base.Suppliers;
37+
38+
public class EthConfig implements JsonRpcMethod {
39+
40+
private static final Supplier<ObjectMapper> mapperSupplier = Suppliers.memoize(ObjectMapper::new);
41+
42+
private final BlockchainQueries blockchain;
43+
private final ProtocolSchedule protocolSchedule;
44+
45+
public EthConfig(final BlockchainQueries blockchain, final ProtocolSchedule protocolSchedule) {
46+
this.blockchain = blockchain;
47+
this.protocolSchedule = protocolSchedule;
48+
}
49+
50+
@Override
51+
public String getName() {
52+
return RpcMethod.ETH_CONFIG.getMethodName();
53+
}
54+
55+
@Override
56+
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
57+
var header = blockchain.getBlockchain().getChainHeadHeader();
58+
var current = protocolSchedule.getForNextBlockHeader(header, System.currentTimeMillis() / 1000);
59+
var next = protocolSchedule.getNextProtocolSpec(current);
60+
61+
var currentConfig = generateConfig(current);
62+
var nextConfig = next.map(this::generateConfig).orElse(null);
63+
64+
ObjectNode result = mapperSupplier.get().createObjectNode();
65+
result.put("current", currentConfig);
66+
result.put("currentHash", configHash(currentConfig));
67+
result.put("next", nextConfig);
68+
result.put("nextHash", configHash(nextConfig));
69+
70+
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result);
71+
}
72+
73+
JsonNode generateConfig(final ProtocolSpec spec) {
74+
var result = mapperSupplier.get().createObjectNode();
75+
var forkId = protocolSchedule.hardforkFor(x -> x.spec() == spec).orElseThrow();
76+
77+
result.put("activation", forkId.milestone());
78+
79+
var blobs = result.putObject("blobs");
80+
blobs.put(
81+
"baseFeeUpdateFraction", spec.getFeeMarket().getBaseFeeUpdateFraction().longValueExact());
82+
blobs.put("max", spec.getGasLimitCalculator().currentBlobGasLimit() / (128 * 1024));
83+
blobs.put("target", spec.getGasCalculator().getBlobTarget());
84+
85+
result.put(
86+
"chainId", protocolSchedule.getChainId().map(c -> "0x" + c.toString(16)).orElse(null));
87+
88+
var contracts =
89+
new TreeMap<>(
90+
spec.getRequestProcessorCoordinator()
91+
.map(RequestProcessorCoordinator::getContractConfigs)
92+
.orElse(Map.of()));
93+
spec.getBlockHashProcessor()
94+
.getHistoryContract()
95+
.ifPresent(a -> contracts.put("HISTORY", a.toHexString()));
96+
if (!contracts.isEmpty()) {
97+
var jsonContracts = result.putObject("contracts");
98+
contracts.forEach(jsonContracts::put);
99+
}
100+
101+
PrecompileContractRegistry registry = spec.getPrecompileContractRegistry();
102+
var precompiles = result.putObject("precompiles");
103+
registry.getPrecompileAddresses().stream()
104+
.sorted()
105+
.forEach(a -> precompiles.put(a.toHexString(), registry.get(a).getName()));
106+
107+
return result;
108+
}
109+
110+
String configHash(final JsonNode node) {
111+
if (node == null) {
112+
return null;
113+
} else {
114+
final CRC32 crc = new CRC32();
115+
crc.update(node.toString().getBytes(StandardCharsets.UTF_8));
116+
return Long.toHexString(crc.getValue());
117+
}
118+
}
119+
}

ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCall;
2424
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthChainId;
2525
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCoinbase;
26+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthConfig;
2627
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCreateAccessList;
2728
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthEstimateGas;
2829
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthFeeHistory;
@@ -156,6 +157,7 @@ protected Map<String, JsonRpcMethod> create() {
156157
new EthCreateAccessList(blockchainQueries, transactionSimulator),
157158
new EthMining(miningCoordinator),
158159
new EthCoinbase(miningCoordinator),
160+
new EthConfig(blockchainQueries, protocolSchedule),
159161
new EthProtocolVersion(supportedCapabilities),
160162
new EthGasPrice(blockchainQueries, apiConfiguration),
161163
new EthGetWork(miningCoordinator),

ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_chainId.json

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"request": {
3+
"id": 8,
4+
"jsonrpc": "2.0",
5+
"method": "eth_config",
6+
"params": []
7+
},
8+
"response": {
9+
"jsonrpc": "2.0",
10+
"id": 8,
11+
"result": {
12+
"current": {
13+
"activation": 1444660040,
14+
"blobs": {
15+
"baseFeeUpdateFraction": 3338477,
16+
"max": 6,
17+
"target": 3
18+
},
19+
"chainId": "0x1",
20+
"precompiles": {
21+
"0x0000000000000000000000000000000000000001": "ECREC",
22+
"0x0000000000000000000000000000000000000002": "SHA256",
23+
"0x0000000000000000000000000000000000000003": "RIPEMD160",
24+
"0x0000000000000000000000000000000000000004": "ID",
25+
"0x0000000000000000000000000000000000000005": "EXPMOD",
26+
"0x0000000000000000000000000000000000000006": "BN256_ADD",
27+
"0x0000000000000000000000000000000000000007": "BN256_MUL",
28+
"0x0000000000000000000000000000000000000008": "BN256_PAIRING",
29+
"0x0000000000000000000000000000000000000009": "BLAKE2F",
30+
"0x000000000000000000000000000000000000000a": "KZG_POINT_EVALUATION"
31+
}
32+
},
33+
"currentHash": "1b5fbed",
34+
"next": null,
35+
"nextHash": null
36+
}
37+
},
38+
"statusCode": 200
39+
}

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,30 @@ public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) {
7474
return null;
7575
}
7676

77+
@Override
78+
public Optional<ProtocolSpec> getNextProtocolSpec(final ProtocolSpec currentProtocolSpec) {
79+
checkArgument(
80+
!protocolSpecs.isEmpty(), "At least 1 milestone must be provided to the protocol schedule");
81+
checkArgument(
82+
protocolSpecs.last().fork().milestone() == 0,
83+
"There must be a milestone starting from block 0");
84+
85+
// protocolSpecs is sorted in descending block order, so the first one we find that's lower than
86+
// the requested level will be the most appropriate spec
87+
ScheduledProtocolSpec priorProtocolSpec = null;
88+
for (final ScheduledProtocolSpec spec : protocolSpecs) {
89+
if (spec.spec() == currentProtocolSpec) {
90+
if (priorProtocolSpec == null) {
91+
return Optional.empty();
92+
} else {
93+
return Optional.of(priorProtocolSpec.spec());
94+
}
95+
}
96+
priorProtocolSpec = spec;
97+
}
98+
return Optional.empty();
99+
}
100+
77101
@Override
78102
public Optional<BigInteger> getChainId() {
79103
return chainId;

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ default ProtocolSpec getForNextBlockHeader(
4040
return getByBlockHeader(nextBlockHeader);
4141
}
4242

43+
Optional<ProtocolSpec> getNextProtocolSpec(final ProtocolSpec currentProtocolSpec);
44+
4345
Optional<BigInteger> getChainId();
4446

4547
String listMilestones();

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockhash/BlockHashProcessor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@
1414
*/
1515
package org.hyperledger.besu.ethereum.mainnet.blockhash;
1616

17+
import org.hyperledger.besu.datatypes.Address;
1718
import org.hyperledger.besu.ethereum.chain.Blockchain;
1819
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
1920
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockContextProcessor;
2021
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
2122
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
2223

24+
import java.util.Optional;
25+
2326
public interface BlockHashProcessor extends BlockContextProcessor<Void, BlockProcessingContext> {
2427

2528
BlockHashLookup createBlockHashLookup(Blockchain blockchain, ProcessableBlockHeader blockHeader);
29+
30+
default Optional<Address> getHistoryContract() {
31+
return Optional.empty();
32+
}
2633
}

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockhash/PragueBlockHashProcessor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
1919
import org.hyperledger.besu.ethereum.mainnet.systemcall.SystemCallProcessor;
2020

21+
import java.util.Optional;
22+
2123
import com.google.common.annotations.VisibleForTesting;
2224
import org.apache.tuweni.bytes.Bytes;
2325

@@ -58,4 +60,9 @@ public Void process(final BlockProcessingContext context) {
5860
processor.process(historyStorageAddress, context, inputData);
5961
return null;
6062
}
63+
64+
@Override
65+
public Optional<Address> getHistoryContract() {
66+
return Optional.of(historyStorageAddress);
67+
}
6168
}

0 commit comments

Comments
 (0)