From 907a39d22189f88cd64c6322626cee2add8825df Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 25 Aug 2022 15:14:50 +0200 Subject: [PATCH] Log wei amount in human readable form Signed-off-by: Fabio Di Fabio --- .../org/hyperledger/besu/datatypes/Wei.java | 49 +++++++++++++++++++ .../hyperledger/besu/datatypes/WeiTest.java | 47 ++++++++++++++++++ .../methods/engine/EngineNewPayload.java | 10 ++-- 3 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java 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 b262e061105..fd66cc1ed85 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; @@ -59,7 +60,6 @@ public class EngineNewPayload extends ExecutionEngineJsonRpcMethod { private static final Hash OMMERS_HASH_CONSTANT = Hash.EMPTY_LIST_HASH; - private static final double TO_GWEI_DIVISOR = Math.pow(10, 9); private static final Logger LOG = LoggerFactory.getLogger(EngineNewPayload.class); private static final BlockHeaderFunctions headerFunctions = new MainnetBlockHeaderFunctions(); private final MergeMiningCoordinator mergeCoordinator; @@ -259,16 +259,12 @@ JsonRpcResponse respondWithInvalid( private void logImportedBlockInfo(final Block block, final double timeInS) { LOG.info( String.format( - "Imported #%,d / %d tx / %,d (%01.1f%%) gas / base fee %01.2f%% gwei / (%s) in %01.3fs.", + "Imported #%,d / %d tx / %,d (%01.1f%%) gas / base fee %s / (%s) in %01.3fs.", block.getHeader().getNumber(), block.getBody().getTransactions().size(), block.getHeader().getGasUsed(), (block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(), - block - .getHeader() - .getBaseFee() - .map(wei -> wei.getAsBigInteger().doubleValue() / TO_GWEI_DIVISOR) - .orElse(Double.NaN), + block.getHeader().getBaseFee().map(Wei::toHumanReadableString).orElse("N/A"), block.getHash().toHexString(), timeInS)); }