diff --git a/CHANGELOG.md b/CHANGELOG.md index 92b0e55b8a2..e3004bcef36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Better management of jemalloc presence/absence in startup script [#4237](https://github.com/hyperledger/besu/pull/4237) - Filter out disconnected peers when fetching available peers [#4269](https://github.com/hyperledger/besu/pull/4269) - Updated the default value of fast-sync-min-peers post merge [#4298](https://github.com/hyperledger/besu/pull/4298) +- Log imported block info post merge [#4310](https://github.com/hyperledger/besu/pull/4310) ### Bug Fixes - Accept wit/80 from Nethermind [#4279](https://github.com/hyperledger/besu/pull/4279) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java index 5e23ff8d21a..aa19235fdee 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.plugin.data.Quantity; import java.math.BigInteger; +import java.util.Arrays; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.BaseUInt256Value; @@ -98,4 +99,52 @@ public String toShortHexString() { public static Wei fromQuantity(final Quantity quantity) { return Wei.wrap((Bytes) quantity); } + + public String toHumanReadableString() { + final BigInteger amount = toBigInteger(); + final int numOfDigits = amount.toString().length(); + final Unit preferredUnit = Unit.getPreferred(numOfDigits); + final double res = amount.doubleValue() / preferredUnit.divisor; + return String.format("%1." + preferredUnit.decimals + "f %s", res, preferredUnit); + } + + enum Unit { + Wei(0, 0), + KWei(3), + MWei(6), + GWei(9), + Szabo(12), + Finney(15), + Ether(18), + KEther(21), + MEther(24), + GEther(27), + TEther(30); + + final int pow; + final double divisor; + final int decimals; + + Unit(final int pow) { + this(pow, 2); + } + + Unit(final int pow, final int decimals) { + this.pow = pow; + this.decimals = decimals; + this.divisor = Math.pow(10, pow); + } + + static Unit getPreferred(final int numOfDigits) { + return Arrays.stream(values()) + .filter(u -> numOfDigits <= u.pow + 3) + .findFirst() + .orElse(TEther); + } + + @Override + public String toString() { + return name().toLowerCase(); + } + } } diff --git a/datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java b/datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java new file mode 100644 index 00000000000..aa9a82b9110 --- /dev/null +++ b/datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java @@ -0,0 +1,47 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.datatypes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.math.BigInteger; +import java.util.Arrays; + +import org.junit.Test; + +public class WeiTest { + + @Test + public void toHumanReadableString() { + assertThat(Wei.ZERO.toHumanReadableString()).isEqualTo("0 wei"); + assertThat(Wei.ONE.toHumanReadableString()).isEqualTo("1 wei"); + + assertThat(Wei.of(999).toHumanReadableString()).isEqualTo("999 wei"); + assertThat(Wei.of(1000).toHumanReadableString()).isEqualTo("1.00 kwei"); + + assertThat(Wei.of(1009).toHumanReadableString()).isEqualTo("1.01 kwei"); + assertThat(Wei.of(1011).toHumanReadableString()).isEqualTo("1.01 kwei"); + + assertThat(Wei.of(new BigInteger("1000000000")).toHumanReadableString()).isEqualTo("1.00 gwei"); + + assertThat(Wei.of(new BigInteger("1000000000000000000")).toHumanReadableString()) + .isEqualTo("1.00 ether"); + + final char[] manyZeros = new char[32]; + Arrays.fill(manyZeros, '0'); + assertThat(Wei.of(new BigInteger("1" + String.valueOf(manyZeros))).toHumanReadableString()) + .isEqualTo("100.00 tether"); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index 73c94f47796..ebd541a3991 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockValidator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; @@ -41,6 +42,7 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.rlp.RLPException; @@ -62,13 +64,16 @@ public class EngineNewPayload extends ExecutionEngineJsonRpcMethod { private static final Logger LOG = LoggerFactory.getLogger(EngineNewPayload.class); private static final BlockHeaderFunctions headerFunctions = new MainnetBlockHeaderFunctions(); private final MergeMiningCoordinator mergeCoordinator; + private final EthPeers ethPeers; public EngineNewPayload( final Vertx vertx, final ProtocolContext protocolContext, - final MergeMiningCoordinator mergeCoordinator) { + final MergeMiningCoordinator mergeCoordinator, + final EthPeers ethPeers) { super(vertx, protocolContext); this.mergeCoordinator = mergeCoordinator; + this.ethPeers = ethPeers; } @Override @@ -200,9 +205,11 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) } // execute block and return result response + final long startTimeMs = System.currentTimeMillis(); final BlockValidator.Result executionResult = mergeCoordinator.rememberBlock(block); if (executionResult.errorMessage.isEmpty()) { + logImportedBlockInfo(block, (System.currentTimeMillis() - startTimeMs) / 1000.0); return respondWith(reqId, blockParam, newBlockHeader.getHash(), VALID); } else { LOG.debug("New payload is invalid: {}", executionResult.errorMessage.get()); @@ -252,4 +259,18 @@ JsonRpcResponse respondWithInvalid( requestId, new EnginePayloadStatusResult(INVALID, latestValidHash, Optional.of(validationError))); } + + private void logImportedBlockInfo(final Block block, final double timeInS) { + LOG.info( + String.format( + "Imported #%,d / %d tx / base fee %s / %,d (%01.1f%%) gas / (%s) in %01.3fs. Peers: %d", + block.getHeader().getNumber(), + block.getBody().getTransactions().size(), + block.getHeader().getBaseFee().map(Wei::toHumanReadableString).orElse("N/A"), + block.getHeader().getGasUsed(), + (block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(), + block.getHash().toHexString(), + timeInS, + ethPeers.peerCount())); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index 8c81681974e..7336f461ac6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayload; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import java.util.Map; import java.util.Optional; @@ -38,14 +39,19 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods { private final Optional mergeCoordinator; private final ProtocolContext protocolContext; + private final EthPeers ethPeers; + ExecutionEngineJsonRpcMethods( - final MiningCoordinator miningCoordinator, final ProtocolContext protocolContext) { + final MiningCoordinator miningCoordinator, + final ProtocolContext protocolContext, + final EthPeers ethPeers) { this.mergeCoordinator = Optional.ofNullable(miningCoordinator) .filter(mc -> mc.isCompatibleWithEngineApi()) .map(MergeMiningCoordinator.class::cast); this.protocolContext = protocolContext; + this.ethPeers = ethPeers; } @Override @@ -59,7 +65,7 @@ protected Map create() { if (mergeCoordinator.isPresent()) { return mapOf( new EngineGetPayload(syncVertx, protocolContext, blockResultFactory), - new EngineNewPayload(syncVertx, protocolContext, mergeCoordinator.get()), + new EngineNewPayload(syncVertx, protocolContext, mergeCoordinator.get(), ethPeers), new EngineForkchoiceUpdated(syncVertx, protocolContext, mergeCoordinator.get()), new EngineExchangeTransitionConfiguration(syncVertx, protocolContext)); } else { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index 59bf78ee886..bf63527949a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -94,7 +94,7 @@ public Map methods( blockchainQueries, protocolSchedule, metricsSystem, transactionPool, dataDir), new EeaJsonRpcMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), - new ExecutionEngineJsonRpcMethods(miningCoordinator, protocolContext), + new ExecutionEngineJsonRpcMethods(miningCoordinator, protocolContext, ethPeers), new GoQuorumJsonRpcPrivacyMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), new EthJsonRpcMethods( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java index 74d48c62d29..ce7759feae6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java @@ -48,6 +48,7 @@ import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import java.util.Collections; import java.util.List; @@ -77,11 +78,14 @@ public class EngineNewPayloadTest { @Mock private MutableBlockchain blockchain; + @Mock private EthPeers ethPeers; + @Before public void before() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); - this.method = new EngineNewPayload(vertx, protocolContext, mergeCoordinator); + when(ethPeers.peerCount()).thenReturn(1); + this.method = new EngineNewPayload(vertx, protocolContext, mergeCoordinator, ethPeers); } @Test