diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java
new file mode 100644
index 00000000000..a771bbd200c
--- /dev/null
+++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java
@@ -0,0 +1,49 @@
+/*
+ * This file is part of RskJ
+ * Copyright (C) 2024 RSK Labs Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package co.rsk.core.types.bytes;
+
+/**
+ * {@link ByteSequence} is the most basic interface that represents read-only sequence of byte values.
+ */
+public interface ByteSequence {
+
+ /**
+ * Returns the length of this byte sequence.
+ *
+ * @return the length of the sequence of bytes represented by this
+ * object.
+ */
+ int length();
+
+ /**
+ * Returns the {@code byte} value at the
+ * specified index. An index ranges from {@code 0} to
+ * {@code length() - 1}. The first {@code byte} value of the sequence
+ * is at index {@code 0}, the next at index {@code 1},
+ * and so on, as for array indexing.
+ *
+ * @param index the index of the {@code byte} value.
+ * @return the {@code byte} value at the specified index of this array.
+ * The first {@code byte} value is at index {@code 0}.
+ * @exception IndexOutOfBoundsException if the {@code index}
+ * argument is negative or not less than the length of this
+ * array.
+ */
+ byte byteAt(int index);
+}
diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java
new file mode 100644
index 00000000000..ce988888068
--- /dev/null
+++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java
@@ -0,0 +1,167 @@
+/*
+ * This file is part of RskJ
+ * Copyright (C) 2024 RSK Labs Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package co.rsk.core.types.bytes;
+
+import org.ethereum.util.ByteUtil;
+import org.ethereum.util.FastByteComparisons;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A {@link Bytes} is a readable sequence of byte values. This
+ * interface provides uniform, read-only access to many different kinds of
+ * byte sequences.
+ *
+ *
This interface does not refine the general contracts of the {@link
+ * java.lang.Object#equals(java.lang.Object) equals} and {@link
+ * java.lang.Object#hashCode() hashCode} methods. The result of comparing two
+ * objects that implement Bytes is therefore, in general,
+ * undefined. Each object may be implemented by a different class, and there
+ * is no guarantee that each class will be capable of testing its instances
+ * for equality with those of the other. It is therefore inappropriate to use
+ * arbitrary Bytes instances as elements in a set or as keys in
+ * a map.
+ */
+public interface Bytes extends BytesSlice {
+
+ /**
+ * Returns an instance of the {@link Bytes} interface, which represents {@code unsafeByteArray}.
+ *
+ * @return the instance of the {@link Bytes} interface that wraps a provided byte array.
+ */
+ static Bytes of(@Nullable byte[] unsafeByteArray) {
+ if (unsafeByteArray == null) {
+ return null;
+ }
+ return new BytesImpl(unsafeByteArray);
+ }
+
+ /**
+ * A helper method for printing "nullable" byte arrays.
+ *
+ * @return {@code valueIfNull}, if {@code byteArray} is {@code null}. Otherwise - {@code Bytes.of(byteArray).toPrintableString()}.
+ */
+ static String toPrintableString(@Nullable byte[] byteArray, @Nullable String valueIfNull) {
+ if (byteArray == null) {
+ return valueIfNull;
+ }
+ return of(byteArray).toPrintableString();
+ }
+
+ /**
+ * A helper method for printing "nullable" byte arrays.
+ *
+ * @return {@code ""}, if {@code byteArray} is {@code null}. Otherwise - {@code Bytes.of(byteArray).toPrintableString()}.
+ */
+ @Nonnull
+ static String toPrintableString(@Nullable byte[] byteArray) {
+ return toPrintableString(byteArray, "");
+ }
+
+ /**
+ * A helper method for extracting "unsafe" underlying byte array from the {@code bytes} instance.
+ *
+ * @return {@code null}, if {@code bytes} is {@code null}. Otherwise - {@code bytes.asUnsafeByteArray()}.
+ */
+ @Nullable
+ static byte[] asUnsafeByteArray(@Nullable Bytes bytes) {
+ if (bytes == null) {
+ return null;
+ }
+ return bytes.asUnsafeByteArray();
+ }
+
+ static boolean equalBytes(Bytes b1, Bytes b2) {
+ if (b1 == null && b2 == null) {
+ return true;
+ }
+ if (b1 == null || b2 == null) {
+ return false;
+ }
+ return FastByteComparisons.equalBytes(b1.asUnsafeByteArray(), b2.asUnsafeByteArray());
+ }
+
+ /**
+ * Returns an underlying byte array, which is backing this instance. Any mutations that are being done with the bytes
+ * of returned array will have direct impact on the byte array that is being wrapped by this instance.
+ *
+ * @return the wrapped by this instance byte array.
+ */
+ byte[] asUnsafeByteArray();
+}
+
+/**
+ * The {@link BytesImpl} class represents a read-only sequence of byte values.
+ *
+ * Instances of the {@link BytesImpl} class are constant; their values cannot be changed after they
+ * are created via the methods that this class provides. But a {@code byteArray} instance itself provided in the constructor
+ * is mutable and can be modified outside the class. It's generally a bad idea to mutate a byte array that's being wrapped
+ * by an instance of this class, as the idea is to make a byte sequence immutable, which is not the case with the Java
+ * built-in {@code byte[]} type.
+ *
+ * Because {@link BytesImpl} objects are immutable they can be safely used by multiple Java threads, if the wrapped array
+ * is not being referenced and modified outside.
+ */
+class BytesImpl implements Bytes {
+
+ private final byte[] byteArray;
+
+ BytesImpl(@Nonnull byte[] unsafeByteArray) {
+ this.byteArray = Objects.requireNonNull(unsafeByteArray);
+ }
+
+ @Override
+ public int length() {
+ return byteArray.length;
+ }
+
+ @Override
+ public byte byteAt(int index) {
+ return byteArray[index];
+ }
+
+ @Override
+ public byte[] copyArrayOfRange(int from, int to) {
+ return Arrays.copyOfRange(byteArray, from, to);
+ }
+
+ @Override
+ public String toHexString() {
+ return ByteUtil.toHexString(byteArray);
+ }
+
+ @Override
+ public String toHexString(int off, int length) {
+ return ByteUtil.toHexString(byteArray, off, length);
+ }
+
+ @Nonnull
+ @Override
+ public byte[] asUnsafeByteArray() {
+ return byteArray;
+ }
+
+ @Override
+ public String toString() {
+ return toPrintableString();
+ }
+}
diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java
new file mode 100644
index 00000000000..5210ff8eea0
--- /dev/null
+++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java
@@ -0,0 +1,131 @@
+/*
+ * This file is part of RskJ
+ * Copyright (C) 2024 RSK Labs Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package co.rsk.core.types.bytes;
+
+/**
+ * A {@link BytesSlice} is a subsequence of bytes backed by another broader byte sequence.
+ */
+public interface BytesSlice extends HexPrintableBytes {
+
+ /**
+ * Copies the specified range of the specified array into a new array.
+ * The initial index of the range (from) must lie between zero
+ * and original.length, inclusive. The value at
+ * original[from] is placed into the initial element of the copy
+ * (unless from == original.length or from == to).
+ * Values from subsequent elements in the original array are placed into
+ * subsequent elements in the copy. The final index of the range
+ * (to), which must be greater than or equal to from,
+ * may be greater than original.length, in which case
+ * (byte)0 is placed in all elements of the copy whose index is
+ * greater than or equal to original.length - from. The length
+ * of the returned array will be to - from.
+ *
+ * @param from the initial index of the range to be copied, inclusive
+ * @param to the final index of the range to be copied, exclusive.
+ * (This index may lie outside the array.)
+ * @return a new array containing the specified range from the original array,
+ * truncated or padded with zeros to obtain the required length
+ * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+ * or {@code from > original.length}
+ * @throws IllegalArgumentException if from > to
+ * @throws NullPointerException if original is null
+ */
+ byte[] copyArrayOfRange(int from, int to);
+
+ default byte[] copyArray() {
+ return copyArrayOfRange(0, length());
+ }
+
+ default Bytes copyBytesOfRange(int from, int to) {
+ return Bytes.of(copyArrayOfRange(from, to));
+ }
+
+ default Bytes copyBytes() {
+ return Bytes.of(copyArrayOfRange(0, length()));
+ }
+
+ default BytesSlice slice(int from, int to) {
+ return new BytesSliceImpl(this, from, to);
+ }
+}
+
+class BytesSliceImpl implements BytesSlice {
+
+ private final BytesSlice originBytes;
+
+ private final int from;
+ private final int to;
+
+ BytesSliceImpl(BytesSlice originBytes, int from, int to) {
+ this.originBytes = originBytes;
+
+ if (from < 0) {
+ throw new IndexOutOfBoundsException(from + " < " + 0);
+ }
+ if (from > to) {
+ throw new IndexOutOfBoundsException(from + " > " + to);
+ }
+ if (to > originBytes.length()) {
+ throw new IndexOutOfBoundsException(to + " > " + "length");
+ }
+
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public int length() {
+ return to - from;
+ }
+
+ @Override
+ public byte byteAt(int index) {
+ if (index < 0 || index >= length()) {
+ throw new IndexOutOfBoundsException("invalid index: " + index);
+ }
+ return originBytes.byteAt(from + index);
+ }
+
+ @Override
+ public byte[] copyArrayOfRange(int from, int to) {
+ if (from < 0 || from > to || to > length()) {
+ throw new IndexOutOfBoundsException("invalid 'from' and/or 'to': [" + from + ";" + to + ")");
+ }
+ return originBytes.copyArrayOfRange(this.from + from, this.from + to);
+ }
+
+ @Override
+ public String toHexString(int off, int length) {
+ if (off < 0 || length < 0 || off + length > length()) {
+ throw new IndexOutOfBoundsException("invalid 'off' and/or 'length': " + off + "; " + length);
+ }
+ return originBytes.toHexString(from + off, length);
+ }
+
+ @Override
+ public String toHexString() {
+ return toHexString(0, length());
+ }
+
+ @Override
+ public String toString() {
+ return toPrintableString();
+ }
+}
diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java
new file mode 100644
index 00000000000..d700c0cc6a6
--- /dev/null
+++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java
@@ -0,0 +1,92 @@
+/*
+ * This file is part of RskJ
+ * Copyright (C) 2024 RSK Labs Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package co.rsk.core.types.bytes;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Objects;
+
+/**
+ * A {@link HexPrintableBytes} is an extension of the {@link PrintableBytes} class with capabilities to
+ * represent it in hexadecimal format.
+ */
+public interface HexPrintableBytes extends PrintableBytes {
+
+ Formatter SIMPLE_HEX_FORMATTER = new PrintableBytesHexFormatter();
+ Formatter SIMPLE_JSON_HEX_FORMATTER = new PrintableBytesJsonHexFormatter();
+
+
+ @Nullable
+ static String toHexString(@Nullable HexPrintableBytes bytes, @Nullable String defaultValue) {
+ if (bytes == null) {
+ return defaultValue;
+ }
+ return bytes.toHexString();
+ }
+
+ @Nullable
+ static String toHexString(@Nullable HexPrintableBytes bytes) {
+ return toHexString(bytes, null);
+ }
+
+ default String toPrintableString(@Nonnull Formatter formatter, int off, int length) {
+ return formatter.toFormattedString(this, off, length);
+ }
+
+ default String toPrintableString(@Nonnull Formatter formatter) {
+ return toPrintableString(formatter, 0, length());
+ }
+
+ @Override
+ default String toPrintableString() {
+ return toPrintableString(SIMPLE_HEX_FORMATTER);
+ }
+
+ default String toJsonHexFormattedString() {
+ return toPrintableString(SIMPLE_JSON_HEX_FORMATTER);
+ }
+
+ String toHexString(int off, int length);
+
+ String toHexString();
+}
+
+class PrintableBytesHexFormatter implements PrintableBytes.Formatter {
+
+ @Override
+ public String toFormattedString(@Nonnull HexPrintableBytes printableBytes, int off, int length) {
+ int bytesLen = Objects.requireNonNull(printableBytes).length();
+ if (off + length > bytesLen) {
+ throw new IndexOutOfBoundsException("invalid 'off' and/or 'length': " + off + "; " + length);
+ }
+
+ if (length > 32) {
+ return printableBytes.toHexString(off, 15) + ".." + printableBytes.toHexString(off + length - 15, 15);
+ }
+ return printableBytes.toHexString(off, length);
+ }
+}
+
+class PrintableBytesJsonHexFormatter extends PrintableBytesHexFormatter {
+
+ @Override
+ public String toFormattedString(@Nonnull HexPrintableBytes printableBytes, int off, int length) {
+ return "0x" + super.toFormattedString(printableBytes, off, length);
+ }
+}
diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java
new file mode 100644
index 00000000000..10b21f00c92
--- /dev/null
+++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of RskJ
+ * Copyright (C) 2024 RSK Labs Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package co.rsk.core.types.bytes;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link PrintableBytes} is a sequence of byte values that
+ * can be represented as a {@link String} value.
+ */
+public interface PrintableBytes extends ByteSequence {
+
+ interface Formatter {
+ String toFormattedString(@Nonnull T printableBytes, int off, int length);
+ }
+
+ String toPrintableString();
+
+}
diff --git a/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java b/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java
index 96e2d3a2adc..743a1e5a903 100644
--- a/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java
+++ b/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java
@@ -19,13 +19,13 @@
package co.rsk.net.discovery;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.net.discovery.message.MessageDecoder;
import co.rsk.net.discovery.message.PeerDiscoveryMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
-import org.ethereum.util.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +48,7 @@ public DiscoveryEvent decodeMessage(ChannelHandlerContext ctx, byte[] encoded, I
PeerDiscoveryMessage msg = MessageDecoder.decode(encoded);
return new DiscoveryEvent(msg, sender);
} catch (Exception e) {
- logger.error("Exception processing inbound message from {} : {}", ctx.channel().remoteAddress(), ByteUtil.toHexString(encoded), e);
+ logger.error("Exception processing inbound message from {} : {}", ctx.channel().remoteAddress(), Bytes.of(encoded), e);
throw e;
}
}
diff --git a/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java b/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java
index ab98a03f4db..5aef6eac662 100644
--- a/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java
+++ b/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java
@@ -18,6 +18,7 @@
package co.rsk.net.discovery.message;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.net.NodeID;
import co.rsk.net.discovery.PeerDiscoveryException;
import org.apache.commons.lang3.builder.ToStringBuilder;
@@ -179,10 +180,10 @@ public DiscoveryMessageType getMessageType() {
@Override
public String toString() {
return new ToStringBuilder(this)
- .append("mdc", ByteUtil.toHexString(mdc))
- .append("signature", ByteUtil.toHexString(signature))
- .append("type", ByteUtil.toHexString(type))
- .append("data", ByteUtil.toHexString(data)).toString();
+ .append("mdc", Bytes.of(mdc))
+ .append("signature", Bytes.of(signature))
+ .append("type", Bytes.of(type))
+ .append("data", Bytes.of(data)).toString();
}
protected String extractMessageId(RLPItem chk) {
diff --git a/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java b/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java
index 5d333737d5f..ac1d0a11a10 100644
--- a/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java
+++ b/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java
@@ -81,11 +81,15 @@ private synchronized boolean acceptVirtualGasConsumption(double virtualGasToCons
if (this.availableVirtualGas < virtualGasToConsume) {
String acceptanceNote = forcingAcceptance ? "Forcing tx acceptance" : "NOT enough virtualGas";
- logger.warn("{} for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", acceptanceNote, blockNumber, sender, tx, this.availableVirtualGas, virtualGasToConsume);
+ if (logger.isWarnEnabled()) {
+ logger.warn("{} for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", acceptanceNote, blockNumber, sender, tx.getHash(), this.availableVirtualGas, virtualGasToConsume);
+ }
return false;
}
- logger.trace("Enough virtualGas for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", blockNumber, sender, tx, this.availableVirtualGas, virtualGasToConsume);
+ if (logger.isTraceEnabled()) {
+ logger.trace("Enough virtualGas for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", blockNumber, sender, tx.getHash(), this.availableVirtualGas, virtualGasToConsume);
+ }
this.availableVirtualGas -= virtualGasToConsume;
return true;
}
diff --git a/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java b/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java
index 45d34ea7526..281d498d66c 100644
--- a/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java
+++ b/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java
@@ -19,10 +19,10 @@
package co.rsk.pcc;
import co.rsk.core.RskAddress;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.panic.PanicProcessor;
import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
-import org.ethereum.util.ByteUtil;
import org.ethereum.vm.PrecompiledContractArgs;
import org.ethereum.vm.PrecompiledContracts;
import org.ethereum.vm.exception.VMException;
@@ -119,7 +119,7 @@ public byte[] execute(byte[] data) throws VMException {
// No function found with the given data? => halt!
if (!methodWithArguments.isPresent()) {
- String errorMessage = String.format("Invalid data given: %s.", ByteUtil.toHexString(data));
+ String errorMessage = String.format("Invalid data given: %s.", Bytes.of(data));
logger.info(errorMessage);
throw new NativeContractIllegalArgumentException(errorMessage);
}
@@ -174,7 +174,7 @@ public byte[] execute(byte[] data) throws VMException {
private Optional parseData(byte[] data) {
if (data != null && (data.length >= 1 && data.length <= 3)) {
- logger.warn("Invalid function signature {}.", ByteUtil.toHexString(data));
+ logger.warn("Invalid function signature {}.", Bytes.of(data));
return Optional.empty();
}
@@ -194,7 +194,7 @@ private Optional parseData(byte[] data) {
).findFirst();
if (!maybeMethod.isPresent()) {
- logger.warn("Invalid function signature {}.", ByteUtil.toHexString(encodedSignature));
+ logger.warn("Invalid function signature {}.", Bytes.of(encodedSignature));
return Optional.empty();
}
@@ -209,7 +209,7 @@ private Optional parseData(byte[] data) {
Object[] arguments = method.getFunction().decode(data);
return Optional.of(method.new WithArguments(arguments, data));
} catch (Exception e) {
- logger.warn(String.format("Invalid arguments %s for function %s.", ByteUtil.toHexString(data), ByteUtil.toHexString(encodedSignature)), e);
+ logger.warn(String.format("Invalid arguments %s for function %s.", Bytes.of(data), Bytes.of(encodedSignature)), e);
return Optional.empty();
}
}
diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java b/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java
index 9592e402c44..989dad2004e 100644
--- a/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java
+++ b/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java
@@ -24,8 +24,9 @@
import co.rsk.bitcoinj.crypto.HDKeyDerivation;
import co.rsk.bitcoinj.crypto.HDUtils;
import co.rsk.pcc.ExecutionEnvironment;
-import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
import co.rsk.pcc.NativeMethod;
+import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
+import co.rsk.util.StringUtils;
import org.ethereum.core.CallTransaction;
import java.util.Arrays;
@@ -126,7 +127,7 @@ private void throwInvalidPath(String path) throws NativeContractIllegalArgumentE
}
private String getInvalidPathErrorMessage(String path) {
- return String.format("Invalid path '%s'", path);
+ return String.format("Invalid path '%s'", StringUtils.trim(path));
}
private boolean isDecimal(String s) {
diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java b/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java
index 16e2f3f975d..924af82a306 100644
--- a/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java
+++ b/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java
@@ -21,8 +21,9 @@
import co.rsk.bitcoinj.core.NetworkParameters;
import co.rsk.bitcoinj.crypto.DeterministicKey;
import co.rsk.pcc.ExecutionEnvironment;
-import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
import co.rsk.pcc.NativeMethod;
+import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
+import co.rsk.util.StringUtils;
import org.ethereum.core.CallTransaction;
/**
@@ -40,7 +41,7 @@ public class ExtractPublicKeyFromExtendedPublicKey extends NativeMethod {
private final HDWalletUtilsHelper helper;
- private final static String INVALID_EXTENDED_PUBLIC_KEY = "Invalid extended public key '%s";
+ private final static String INVALID_EXTENDED_PUBLIC_KEY = "Invalid extended public key '%s'";
public ExtractPublicKeyFromExtendedPublicKey(ExecutionEnvironment executionEnvironment, HDWalletUtilsHelper helper) {
super(executionEnvironment);
@@ -64,7 +65,7 @@ public Object execute(Object[] arguments) throws NativeContractIllegalArgumentEx
try {
key = DeterministicKey.deserializeB58(xpub, params);
} catch (IllegalArgumentException e) {
- throw new NativeContractIllegalArgumentException(String.format(INVALID_EXTENDED_PUBLIC_KEY, xpub), e);
+ throw new NativeContractIllegalArgumentException(String.format(INVALID_EXTENDED_PUBLIC_KEY, StringUtils.trim(xpub)), e);
}
return key.getPubKeyPoint().getEncoded(true);
diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java b/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java
index c4524d3fcb0..a0b91cb143f 100644
--- a/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java
+++ b/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java
@@ -21,11 +21,11 @@
import co.rsk.bitcoinj.core.BtcECKey;
import co.rsk.bitcoinj.script.Script;
import co.rsk.bitcoinj.script.ScriptBuilder;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.pcc.ExecutionEnvironment;
import co.rsk.pcc.NativeMethod;
import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
import org.ethereum.core.CallTransaction;
-import org.ethereum.util.ByteUtil;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -118,7 +118,7 @@ public Object execute(Object[] arguments) throws NativeContractIllegalArgumentEx
btcPublicKeys.add(btcPublicKey);
} catch (IllegalArgumentException e) {
throw new NativeContractIllegalArgumentException(String.format(
- "Invalid public key format: %s", ByteUtil.toHexString(publicKey)
+ "Invalid public key format: %s", Bytes.of(publicKey)
), e);
}
}
diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java b/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java
index 9b7ce14c813..08073811b8d 100644
--- a/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java
+++ b/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java
@@ -2,6 +2,7 @@
import co.rsk.bitcoinj.core.NetworkParameters;
import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
+import co.rsk.util.StringUtils;
public class HDWalletUtilsHelper {
public NetworkParameters validateAndExtractNetworkFromExtendedPublicKey(String xpub) throws NativeContractIllegalArgumentException {
@@ -15,7 +16,7 @@ public NetworkParameters validateAndExtractNetworkFromExtendedPublicKey(String x
} else if (xpub.startsWith("tpub")) {
return NetworkParameters.fromID(NetworkParameters.ID_TESTNET);
} else {
- throw new NativeContractIllegalArgumentException(String.format("Invalid extended public key '%s'", xpub));
+ throw new NativeContractIllegalArgumentException(String.format("Invalid extended public key '%s'", StringUtils.trim(xpub)));
}
}
}
diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java b/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java
index 9e413842a79..7b69a0b0cbb 100644
--- a/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java
+++ b/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java
@@ -18,11 +18,11 @@
package co.rsk.pcc.bto;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.pcc.ExecutionEnvironment;
-import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
import co.rsk.pcc.NativeMethod;
+import co.rsk.pcc.exception.NativeContractIllegalArgumentException;
import org.ethereum.core.CallTransaction;
-import org.ethereum.util.ByteUtil;
import java.math.BigInteger;
@@ -77,7 +77,7 @@ public Object execute(Object[] arguments) throws NativeContractIllegalArgumentEx
if (hash.length != 20) {
throw new NativeContractIllegalArgumentException(String.format(
HASH_INVALID,
- ByteUtil.toHexString(hash), hash.length
+ Bytes.of(hash), hash.length
));
}
diff --git a/rskj-core/src/main/java/co/rsk/peg/Bridge.java b/rskj-core/src/main/java/co/rsk/peg/Bridge.java
index 1c5cfb82024..6af54db63e1 100644
--- a/rskj-core/src/main/java/co/rsk/peg/Bridge.java
+++ b/rskj-core/src/main/java/co/rsk/peg/Bridge.java
@@ -22,6 +22,7 @@
import co.rsk.bitcoinj.core.*;
import co.rsk.bitcoinj.script.Script;
import co.rsk.bitcoinj.store.BlockStoreException;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.peg.constants.BridgeConstants;
import co.rsk.core.RskAddress;
import co.rsk.crypto.Keccak256;
@@ -301,7 +302,7 @@ BridgeParsedData parseData(byte[] data) {
BridgeParsedData bridgeParsedData = new BridgeParsedData();
if (data != null && (data.length >= 1 && data.length <= 3)) {
- logger.warn("Invalid function signature {}.", ByteUtil.toHexString(data));
+ logger.warn("Invalid function signature {}.", Bytes.of(data));
return null;
}
@@ -312,14 +313,14 @@ BridgeParsedData parseData(byte[] data) {
byte[] functionSignature = Arrays.copyOfRange(data, 0, 4);
Optional invokedMethod = BridgeMethods.findBySignature(functionSignature);
if (!invokedMethod.isPresent()) {
- logger.warn("Invalid function signature {}.", ByteUtil.toHexString(functionSignature));
+ logger.warn("Invalid function signature {}.", Bytes.of(functionSignature));
return null;
}
bridgeParsedData.bridgeMethod = invokedMethod.get();
try {
bridgeParsedData.args = bridgeParsedData.bridgeMethod.getFunction().decode(data);
} catch (Exception e) {
- logger.warn("Invalid function arguments {} for function {}.", ByteUtil.toHexString(data), ByteUtil.toHexString(functionSignature));
+ logger.warn("Invalid function arguments {} for function {}.", Bytes.of(data), Bytes.of(functionSignature));
return null;
}
}
@@ -370,7 +371,7 @@ public byte[] execute(byte[] data) throws VMException {
// Function parsing from data returned null => invalid function selected, halt!
if (bridgeParsedData == null) {
- String errorMessage = String.format("Invalid data given: %s.", ByteUtil.toHexString(data));
+ String errorMessage = String.format("Invalid data given: %s.", Bytes.of(data));
logger.info("[execute] {}", errorMessage);
if (!activations.isActive(ConsensusRule.RSKIP88)) {
return null;
@@ -527,7 +528,7 @@ public void receiveHeaders(Object[] args) throws VMException {
BtcBlock header = bridgeConstants.getBtcParams().getDefaultSerializer().makeBlock(btcBlockSerialized);
btcBlockArray[i] = header;
} catch (ProtocolException e) {
- throw new BridgeIllegalArgumentException("Block " + i + " could not be parsed " + ByteUtil.toHexString(btcBlockSerialized), e);
+ throw new BridgeIllegalArgumentException("Block " + i + " could not be parsed " + Bytes.of(btcBlockSerialized), e);
}
}
try {
@@ -599,7 +600,7 @@ public void addSignature(Object[] args) throws VMException {
try {
federatorPublicKey = BtcECKey.fromPublicOnly(federatorPublicKeySerialized);
} catch (Exception e) {
- throw new BridgeIllegalArgumentException("Public key could not be parsed " + ByteUtil.toHexString(federatorPublicKeySerialized), e);
+ throw new BridgeIllegalArgumentException("Public key could not be parsed " + Bytes.of(federatorPublicKeySerialized), e);
}
Object[] signaturesObjectArray = (Object[]) args[1];
if (signaturesObjectArray.length == 0) {
@@ -611,13 +612,13 @@ public void addSignature(Object[] args) throws VMException {
try {
BtcECKey.ECDSASignature.decodeFromDER((byte[])signatureObject);
} catch (Exception e) {
- throw new BridgeIllegalArgumentException("Signature could not be parsed " + ByteUtil.toHexString(signatureByteArray), e);
+ throw new BridgeIllegalArgumentException("Signature could not be parsed " + Bytes.of(signatureByteArray), e);
}
signatures.add(signatureByteArray);
}
byte[] rskTxHash = (byte[]) args[2];
if (rskTxHash.length!=32) {
- throw new BridgeIllegalArgumentException("Invalid rsk tx hash " + ByteUtil.toHexString(rskTxHash));
+ throw new BridgeIllegalArgumentException("Invalid rsk tx hash " + Bytes.of(rskTxHash));
}
try {
bridgeSupport.addSignature(federatorPublicKey, signatures, rskTxHash);
diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
index b97ecfde42e..a027e0fdd17 100644
--- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
+++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
@@ -29,6 +29,7 @@
import co.rsk.bitcoinj.store.BlockStoreException;
import co.rsk.bitcoinj.wallet.SendRequest;
import co.rsk.bitcoinj.wallet.Wallet;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.peg.constants.BridgeConstants;
import co.rsk.core.RskAddress;
import co.rsk.crypto.Keccak256;
@@ -1517,7 +1518,7 @@ private void processSigning(
"Malformed signature for input {} of tx {}: {}",
i,
new Keccak256(rskTxHash),
- ByteUtil.toHexString(signatures.get(i))
+ Bytes.of(signatures.get(i))
);
return;
}
@@ -1528,7 +1529,7 @@ private void processSigning(
logger.warn(
"Signature {} {} is not valid for hash {} and public key {}",
i,
- ByteUtil.toHexString(sig.encodeToDER()),
+ Bytes.of(sig.encodeToDER()),
sighash,
federatorBtcPublicKey
);
@@ -1538,7 +1539,7 @@ private void processSigning(
TransactionSignature txSig = new TransactionSignature(sig, BtcTransaction.SigHash.ALL, false);
txSigs.add(txSig);
if (!txSig.isCanonical()) {
- logger.warn("Signature {} {} is not canonical.", i, ByteUtil.toHexString(signatures.get(i)));
+ logger.warn("Signature {} {} is not canonical.", i, Bytes.of(signatures.get(i)));
return;
}
}
@@ -1586,7 +1587,7 @@ private void processSigning(
}
if (BridgeUtils.hasEnoughSignatures(btcContext, btcTx)) {
- logger.info("Tx fully signed {}. Hex: {}", btcTx, Hex.toHexString(btcTx.bitcoinSerialize()));
+ logger.info("Tx fully signed {}. Hex: {}", btcTx, Bytes.of(btcTx.bitcoinSerialize()));
provider.getPegoutsWaitingForSignatures().remove(new Keccak256(rskTxHash));
eventLogger.logReleaseBtc(btcTx, rskTxHash);
@@ -2317,7 +2318,7 @@ private ABICallVoteResult executeVoteFederationChangeFunction(boolean dryRun, AB
publicKey = BtcECKey.fromPublicOnly(publicKeyBytes);
publicKeyEc = ECKey.fromPublicOnly(publicKeyBytes);
} catch (Exception e) {
- throw new BridgeIllegalArgumentException("Public key could not be parsed " + ByteUtil.toHexString(publicKeyBytes), e);
+ throw new BridgeIllegalArgumentException("Public key could not be parsed " + Bytes.of(publicKeyBytes), e);
}
executionResult = addFederatorPublicKeyMultikey(dryRun, publicKey, publicKeyEc, publicKeyEc);
result = new ABICallVoteResult(executionResult == 1, executionResult);
@@ -2329,19 +2330,19 @@ private ABICallVoteResult executeVoteFederationChangeFunction(boolean dryRun, AB
try {
btcPublicKey = BtcECKey.fromPublicOnly(callSpec.getArguments()[0]);
} catch (Exception e) {
- throw new BridgeIllegalArgumentException("BTC public key could not be parsed " + ByteUtil.toHexString(callSpec.getArguments()[0]), e);
+ throw new BridgeIllegalArgumentException("BTC public key could not be parsed " + Bytes.of(callSpec.getArguments()[0]), e);
}
try {
rskPublicKey = ECKey.fromPublicOnly(callSpec.getArguments()[1]);
} catch (Exception e) {
- throw new BridgeIllegalArgumentException("RSK public key could not be parsed " + ByteUtil.toHexString(callSpec.getArguments()[1]), e);
+ throw new BridgeIllegalArgumentException("RSK public key could not be parsed " + Bytes.of(callSpec.getArguments()[1]), e);
}
try {
mstPublicKey = ECKey.fromPublicOnly(callSpec.getArguments()[2]);
} catch (Exception e) {
- throw new BridgeIllegalArgumentException("MST public key could not be parsed " + ByteUtil.toHexString(callSpec.getArguments()[2]), e);
+ throw new BridgeIllegalArgumentException("MST public key could not be parsed " + Bytes.of(callSpec.getArguments()[2]), e);
}
executionResult = addFederatorPublicKeyMultikey(dryRun, btcPublicKey, rskPublicKey, mstPublicKey);
result = new ABICallVoteResult(executionResult == 1, executionResult);
@@ -2670,7 +2671,7 @@ public void registerBtcCoinbaseTransaction(byte[] btcTxSerialized, Sha256Hash bl
}
} catch (VerificationException e) {
logger.warn("[btcTx:{}] PartialMerkleTree could not be parsed", btcTxHash);
- throw new BridgeIllegalArgumentException(String.format("PartialMerkleTree could not be parsed %s", ByteUtil.toHexString(pmtSerialized)), e);
+ throw new BridgeIllegalArgumentException(String.format("PartialMerkleTree could not be parsed %s", Bytes.of(pmtSerialized)), e);
}
// Check merkle root equals btc block merkle root at the specified height in the btc best chain
diff --git a/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java b/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java
index 0704bd24f0c..2adf53a0913 100644
--- a/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java
+++ b/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java
@@ -4,6 +4,7 @@
import co.rsk.bitcoinj.core.Coin;
import co.rsk.bitcoinj.core.TransactionInput;
import co.rsk.bitcoinj.core.VarInt;
+import co.rsk.core.types.bytes.Bytes;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -11,7 +12,6 @@
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
-import org.spongycastle.util.encoders.Hex;
public final class UtxoUtils {
@@ -40,7 +40,7 @@ public static List decodeOutpointValues(byte[] encodedOutpointValues) {
} catch (Exception ex) {
throw new InvalidOutpointValueException(
String.format("Invalid value with invalid VarInt format: %s",
- Hex.toHexString(encodedOutpointValues).toUpperCase()
+ Bytes.toPrintableString(encodedOutpointValues).toUpperCase()
),
ex
);
diff --git a/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java b/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java
index bc42ea29c0f..16d68d6f954 100644
--- a/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java
+++ b/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java
@@ -19,6 +19,7 @@
package co.rsk.peg.federation;
import co.rsk.bitcoinj.core.BtcECKey;
+import co.rsk.util.StringUtils;
import org.ethereum.crypto.ECKey;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
@@ -79,7 +80,7 @@ public static KeyType byValue(String value) {
case "btc":
return KeyType.BTC;
default:
- throw new IllegalArgumentException(String.format("Invalid value for FederationMember.KeyType: %s", value));
+ throw new IllegalArgumentException(String.format("Invalid value for FederationMember.KeyType: %s", StringUtils.trim(value)));
}
}
}
diff --git a/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java b/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java
index ea249c5f8fb..53b2b874c48 100644
--- a/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java
+++ b/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java
@@ -6,6 +6,8 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+
+import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,7 +36,7 @@ public Optional buildPeginInstructions(BtcTransaction btcTx)
throw new PeginInstructionsException(message, e);
}
- logger.trace("[buildPeginInstructions] OP_RETURN data: {}", Hex.toHexString(opReturnOutputData));
+ logger.trace("[buildPeginInstructions] OP_RETURN data: {}", Bytes.of(opReturnOutputData));
int protocolVersion = PeginInstructionsBase.extractProtocolVersion(opReturnOutputData);
diff --git a/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java b/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java
index a938f4c7d59..23c569d37e9 100644
--- a/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java
+++ b/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java
@@ -20,13 +20,13 @@
import co.rsk.config.RemascConfig;
import co.rsk.core.RskAddress;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.panic.PanicProcessor;
import co.rsk.rpc.modules.trace.ProgramSubtrace;
import org.ethereum.config.Constants;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.core.CallTransaction;
import org.ethereum.db.ByteArrayWrapper;
-import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.PrecompiledContractArgs;
import org.ethereum.vm.PrecompiledContracts;
@@ -130,7 +130,7 @@ private CallTransaction.Function getFunction(byte[] data) {
function = PROCESS_MINERS_FEES;
} else {
if (data.length != 4) {
- logger.warn("Invalid function: signature longer than expected {}.", ByteUtil.toHexString(data));
+ logger.warn("Invalid function: signature longer than expected {}.", Bytes.of(data));
throw new RemascInvalidInvocationException("Invalid function signature");
}
@@ -138,7 +138,7 @@ private CallTransaction.Function getFunction(byte[] data) {
function = functions.get(new ByteArrayWrapper(functionSignature));
if (function == null) {
- logger.warn("Invalid function: signature does not match an existing function {}.", ByteUtil.toHexString(functionSignature));
+ logger.warn("Invalid function: signature does not match an existing function {}.", Bytes.of(functionSignature));
throw new RemascInvalidInvocationException("Invalid function signature");
}
}
diff --git a/rskj-core/src/main/java/co/rsk/util/StringUtils.java b/rskj-core/src/main/java/co/rsk/util/StringUtils.java
new file mode 100644
index 00000000000..a7c58a322b3
--- /dev/null
+++ b/rskj-core/src/main/java/co/rsk/util/StringUtils.java
@@ -0,0 +1,40 @@
+/*
+ * This file is part of RskJ
+ * Copyright (C) 2024 RSK Labs Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package co.rsk.util;
+
+import javax.annotation.Nullable;
+
+public class StringUtils {
+
+ private static final int DEFAULT_MAX_LEN = 64;
+
+ public static String trim(@Nullable String src) {
+ return trim(src, DEFAULT_MAX_LEN);
+ }
+
+ public static String trim(@Nullable String src, int maxLength) {
+ if (maxLength < 0) {
+ throw new IllegalArgumentException("maxLength: " + maxLength);
+ }
+ if (src == null || src.length() <= maxLength) {
+ return src;
+ }
+ return src.substring(0, maxLength) + "...";
+ }
+}
diff --git a/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java b/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java
index 034e9d808c9..cad08aff0d4 100644
--- a/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java
+++ b/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java
@@ -19,11 +19,11 @@
package co.rsk.validators;
import co.rsk.core.bc.BlockHashesHelper;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.panic.PanicProcessor;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ConsensusRule;
import org.ethereum.core.Block;
-import org.ethereum.util.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,7 +55,7 @@ public boolean isValid(Block block) {
if (!Arrays.equals(blockTxRootHash, txListRootHash)) {
String message = String.format("Block's given Trie Hash doesn't match: %s != %s",
- ByteUtil.toHexString(blockTxRootHash), ByteUtil.toHexString(txListRootHash));
+ Bytes.of(blockTxRootHash), Bytes.of(txListRootHash));
logger.warn(message);
panicProcessor.panic("invalidtrie", message);
diff --git a/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java b/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java
index 3d25bc706c1..037aab5b5c7 100644
--- a/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java
+++ b/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java
@@ -1,5 +1,6 @@
package co.rsk.validators;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.panic.PanicProcessor;
import org.ethereum.core.Block;
import org.ethereum.core.BlockHeader;
@@ -20,7 +21,7 @@ public boolean isValid(Block block) {
if (!ByteUtil.fastEquals(unclesHeader, unclesBlock)) {
String message = String.format("Block's given Uncle Hash doesn't match: %s != %s",
- ByteUtil.toHexString(unclesHeader), ByteUtil.toHexString(unclesBlock));
+ Bytes.of(unclesHeader), Bytes.of(unclesBlock));
logger.warn(message);
panicProcessor.panic("invaliduncle", message);
return false;
diff --git a/rskj-core/src/main/java/org/ethereum/core/Block.java b/rskj-core/src/main/java/org/ethereum/core/Block.java
index 178782b70cb..627662d0519 100644
--- a/rskj-core/src/main/java/org/ethereum/core/Block.java
+++ b/rskj-core/src/main/java/org/ethereum/core/Block.java
@@ -23,12 +23,12 @@
import co.rsk.core.Coin;
import co.rsk.core.RskAddress;
import co.rsk.core.bc.BlockHashesHelper;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.crypto.Keccak256;
import co.rsk.panic.PanicProcessor;
import com.google.common.collect.ImmutableList;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
-import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
import javax.annotation.Nonnull;
@@ -208,7 +208,7 @@ public Coin getMinimumGasPrice() {
@Override
public String toString() {
StringBuilder toStringBuff = new StringBuilder();
- toStringBuff.append(ByteUtil.toHexString(this.getEncoded())).append("\n");
+ toStringBuff.append(Bytes.of(this.getEncoded())).append("\n");
toStringBuff.append("BlockData [ ");
toStringBuff.append("hash=").append(this.getHash()).append("\n");
toStringBuff.append(header.toString());
diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java b/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java
index 4a3729e18c8..2d7862d1016 100644
--- a/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java
+++ b/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-import org.ethereum.util.ByteUtil;
+import co.rsk.core.types.bytes.Bytes;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
@@ -74,7 +74,7 @@ public byte[] getEncoded() {
@Override
public String toString() {
return "BlockIdentifier {" +
- "hash=" + ByteUtil.toHexString(hash) +
+ "hash=" + Bytes.of(hash) +
", number=" + number +
'}';
}
diff --git a/rskj-core/src/main/java/org/ethereum/core/Bloom.java b/rskj-core/src/main/java/org/ethereum/core/Bloom.java
index b5061c63bec..ff3690d9208 100644
--- a/rskj-core/src/main/java/org/ethereum/core/Bloom.java
+++ b/rskj-core/src/main/java/org/ethereum/core/Bloom.java
@@ -19,6 +19,7 @@
package org.ethereum.core;
+import co.rsk.core.types.bytes.Bytes;
import org.ethereum.util.ByteUtil;
import java.util.Arrays;
@@ -84,7 +85,7 @@ public Bloom copy() {
@Override
public String toString() {
- return ByteUtil.toHexString(data);
+ return Bytes.toPrintableString(data);
}
@Override
diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java b/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java
index 913c4481186..71102b8d3f3 100644
--- a/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java
+++ b/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java
@@ -19,6 +19,7 @@
package org.ethereum.core;
+ import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.util.BigIntegers;
import org.ethereum.util.*;
import org.ethereum.vm.LogInfo;
@@ -232,8 +233,8 @@ public String toString() {
return "TransactionReceipt[" +
"\n , " + (hasTxStatus() ? ("txStatus=" + (isSuccessful()? "OK" : "FAILED"))
- : ("postTxState=" + ByteUtil.toHexString(postTxState))) +
- "\n , cumulativeGas=" + ByteUtil.toHexString(cumulativeGas) +
+ : ("postTxState=" + Bytes.of(postTxState))) +
+ "\n , cumulativeGas=" + Bytes.of(cumulativeGas) +
"\n , bloom=" + bloomFilter.toString() +
"\n , logs=" + logInfoList +
']';
diff --git a/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java b/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java
index a0805dfe01c..c14eb12e018 100644
--- a/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java
+++ b/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java
@@ -23,6 +23,7 @@
import co.rsk.core.BlockDifficulty;
import co.rsk.core.bc.BlockChainImpl;
import co.rsk.core.bc.BlockExecutor;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.db.RepositoryLocator;
import co.rsk.db.StateRootHandler;
import co.rsk.validators.BlockValidator;
@@ -32,7 +33,6 @@
import org.ethereum.db.BlockStore;
import org.ethereum.db.ReceiptStore;
import org.ethereum.listener.EthereumListener;
-import org.ethereum.util.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -95,7 +95,7 @@ public BlockChainImpl loadBlockchain() {
logger.info("*** Loaded up to block [{}] totalDifficulty [{}] with stateRoot [{}]",
bestBlock.getNumber(),
totalDifficulty,
- ByteUtil.toHexString(bestBlock.getStateRoot()));
+ Bytes.of(bestBlock.getStateRoot()));
}
if (!isBlockConsistent(bestBlock)) {
diff --git a/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java b/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java
index 29458e43b94..5897e2cdd14 100644
--- a/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java
+++ b/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java
@@ -19,6 +19,7 @@
package org.ethereum.datasource;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.metrics.profilers.Metric;
import co.rsk.metrics.profilers.Profiler;
import co.rsk.metrics.profilers.ProfilerFactory;
@@ -140,13 +141,13 @@ public byte[] get(byte[] key) {
resetDbLock.readLock().lock();
try {
if (logger.isTraceEnabled()) {
- logger.trace("~> LevelDbDataSource.get(): {}, key: {}", name, ByteUtil.toHexString(key));
+ logger.trace("~> LevelDbDataSource.get(): {}, key: {}", name, Bytes.of(key));
}
try {
byte[] ret = db.get(key);
if (logger.isTraceEnabled()) {
- logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), (ret == null ? "null" : ret.length));
+ logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, Bytes.of(key), (ret == null ? "null" : ret.length));
}
return ret;
@@ -155,7 +156,7 @@ public byte[] get(byte[] key) {
try {
byte[] ret = db.get(key);
if (logger.isTraceEnabled()) {
- logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), (ret == null ? "null" : ret.length));
+ logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, Bytes.of(key), (ret == null ? "null" : ret.length));
}
return ret;
@@ -180,12 +181,12 @@ public byte[] put(byte[] key, byte[] value) {
resetDbLock.readLock().lock();
try {
if (logger.isTraceEnabled()) {
- logger.trace("~> LevelDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length);
+ logger.trace("~> LevelDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length);
}
db.put(key, value);
if (logger.isTraceEnabled()) {
- logger.trace("<~ LevelDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length);
+ logger.trace("<~ LevelDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length);
}
return value;
@@ -201,12 +202,12 @@ public void delete(byte[] key) {
resetDbLock.readLock().lock();
try {
if (logger.isTraceEnabled()) {
- logger.trace("~> LevelDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key));
+ logger.trace("~> LevelDbDataSource.delete(): {}, key: {}", name, Bytes.of(key));
}
db.delete(key);
if (logger.isTraceEnabled()) {
- logger.trace("<~ LevelDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key));
+ logger.trace("<~ LevelDbDataSource.delete(): {}, key: {}", name, Bytes.of(key));
}
} finally {
diff --git a/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java b/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java
index 12567a24f92..552bc3c863f 100644
--- a/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java
+++ b/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java
@@ -19,6 +19,7 @@
package org.ethereum.datasource;
+import co.rsk.core.types.bytes.Bytes;
import co.rsk.metrics.profilers.Metric;
import co.rsk.metrics.profilers.Profiler;
import co.rsk.metrics.profilers.ProfilerFactory;
@@ -151,13 +152,13 @@ public byte[] get(byte[] key) {
while (retries < MAX_RETRIES) {
try {
if (logger.isTraceEnabled()) {
- logger.trace("~> RocksDbDataSource.get(): {}, key: {}", name, ByteUtil.toHexString(key));
+ logger.trace("~> RocksDbDataSource.get(): {}, key: {}", name, Bytes.of(key));
}
byte[] ret = db.get(key);
if (logger.isTraceEnabled()) {
- logger.trace("<~ RocksDbDataSource.get(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), (ret == null ? "null" : ret.length));
+ logger.trace("<~ RocksDbDataSource.get(): {}, key: {}, return length: {}", name, Bytes.of(key), (ret == null ? "null" : ret.length));
}
result = ret;
@@ -193,13 +194,13 @@ public byte[] put(byte[] key, byte[] value) {
try {
if (logger.isTraceEnabled()) {
- logger.trace("~> RocksDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length);
+ logger.trace("~> RocksDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length);
}
db.put(key, value);
if (logger.isTraceEnabled()) {
- logger.trace("<~ RocksDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length);
+ logger.trace("<~ RocksDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length);
}
} catch (RocksDBException e) {
logger.error("Exception. Not retrying.", e);
@@ -219,12 +220,12 @@ public void delete(byte[] key) {
try {
if (logger.isTraceEnabled()) {
- logger.trace("~> RocksDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key));
+ logger.trace("~> RocksDbDataSource.delete(): {}, key: {}", name, Bytes.of(key));
}
db.delete(key);
if (logger.isTraceEnabled()) {
- logger.trace("<~ RocksDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key));
+ logger.trace("<~ RocksDbDataSource.delete(): {}, key: {}", name, Bytes.of(key));
}
} catch (RocksDBException e) {
diff --git a/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java b/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java
index 8e98d96b5b9..6f203681c95 100644
--- a/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java
+++ b/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java
@@ -19,6 +19,7 @@
package org.ethereum.db;
+import co.rsk.core.types.bytes.Bytes;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.FastByteComparisons;
@@ -69,7 +70,7 @@ public byte[] getData() {
@Override
public String toString() {
- return ByteUtil.toHexString(data);
+ return Bytes.toPrintableString(data);
}
public boolean equalsToByteArray(byte[] otherData) {
diff --git a/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java b/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java
index caafa569b30..572864bab13 100644
--- a/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java
+++ b/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java
@@ -19,6 +19,7 @@
package org.ethereum.net.eth.message;
+import co.rsk.core.types.bytes.Bytes;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
@@ -155,9 +156,9 @@ public String toString() {
return "[" + this.getCommand().name() +
" protocolVersion=" + this.protocolVersion +
" networkId=" + this.networkId +
- " totalDifficulty=" + ByteUtil.toHexStringOrEmpty(this.totalDifficulty) +
- " bestHash=" + ByteUtil.toHexString(this.bestHash) +
- " genesisHash=" + ByteUtil.toHexString(this.genesisHash) +
+ " totalDifficulty=" + Bytes.of(this.totalDifficulty) +
+ " bestHash=" + Bytes.of(this.bestHash) +
+ " genesisHash=" + Bytes.of(this.genesisHash) +
"]";
}
}
diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java
index 687f25965e8..d0e419ebe24 100644
--- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java
+++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java
@@ -19,10 +19,10 @@
package org.ethereum.net.rlpx;
+import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.math.ec.ECPoint;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.signature.ECDSASignature;
-import org.ethereum.util.ByteUtil;
import static org.bouncycastle.util.BigIntegers.asUnsignedByteArray;
import static org.ethereum.util.ByteUtil.merge;
@@ -121,10 +121,10 @@ public String toString() {
asUnsignedByteArray(signature.getS()), new byte[]{EncryptionHandshake.recIdFromSignatureV(signature.getV())});
return "AuthInitiateMessage{" +
- "\n sigBytes=" + ByteUtil.toHexString(sigBytes) +
- "\n ephemeralPublicHash=" + ByteUtil.toHexString(ephemeralPublicHash) +
- "\n publicKey=" + ByteUtil.toHexString(publicKey.getEncoded(false)) +
- "\n nonce=" + ByteUtil.toHexString(nonce) +
+ "\n sigBytes=" + Bytes.of(sigBytes) +
+ "\n ephemeralPublicHash=" + Bytes.of(ephemeralPublicHash) +
+ "\n publicKey=" + Bytes.of(publicKey.getEncoded(false)) +
+ "\n nonce=" + Bytes.of(nonce) +
"\n}";
}
}
diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java
index 2b35c43e3eb..861c791e0ba 100644
--- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java
+++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java
@@ -19,6 +19,7 @@
package org.ethereum.net.rlpx;
+import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.math.ec.ECPoint;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.signature.ECDSASignature;
@@ -111,9 +112,9 @@ public String toString() {
asUnsignedByteArray(signature.getS()), new byte[]{EncryptionHandshake.recIdFromSignatureV(signature.getV())});
return "AuthInitiateMessage{" +
- "\n sigBytes=" + ByteUtil.toHexString(sigBytes) +
- "\n publicKey=" + ByteUtil.toHexString(publicKey.getEncoded(false)) +
- "\n nonce=" + ByteUtil.toHexString(nonce) +
+ "\n sigBytes=" + Bytes.of(sigBytes) +
+ "\n publicKey=" + Bytes.of(publicKey.getEncoded(false)) +
+ "\n nonce=" + Bytes.of(nonce) +
"\n version=" + version +
"\n}";
}
diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java
index e1bcd67547e..0f59e3391c7 100644
--- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java
+++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java
@@ -19,9 +19,9 @@
package org.ethereum.net.rlpx;
+import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.math.ec.ECPoint;
import org.ethereum.crypto.ECKey;
-import org.ethereum.util.ByteUtil;
/**
* Authentication response message, to be wrapped inside
@@ -74,7 +74,7 @@ public byte[] encode() {
public String toString() {
return "AuthResponseMessage{" +
"\n ephemeralPublicKey=" + ephemeralPublicKey +
- "\n nonce=" + ByteUtil.toHexString(nonce) +
+ "\n nonce=" + Bytes.of(nonce) +
"\n isTokenUsed=" + isTokenUsed +
'}';
}
diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java
index da57466a9eb..38772ec3dee 100644
--- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java
+++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java
@@ -19,6 +19,7 @@
package org.ethereum.net.rlpx;
+import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.math.ec.ECPoint;
import org.ethereum.crypto.ECKey;
import org.ethereum.util.ByteUtil;
@@ -74,7 +75,7 @@ public byte[] encode() {
public String toString() {
return "AuthResponseMessage{" +
"\n ephemeralPublicKey=" + ephemeralPublicKey +
- "\n nonce=" + ByteUtil.toHexString(nonce) +
+ "\n nonce=" + Bytes.of(nonce) +
"\n version=" + version +
'}';
}
diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java
index 7f087ee01a4..f38432e1a2b 100644
--- a/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java
+++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java
@@ -19,6 +19,7 @@
package org.ethereum.net.rlpx;
+import co.rsk.core.types.bytes.Bytes;
import com.google.common.io.ByteStreams;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
@@ -136,7 +137,7 @@ private Message decodeMessage(List frames) throws IOException {
}
if (loggerWire.isDebugEnabled()) {
- loggerWire.debug("Recv: Encoded: {} [{}]", frameType, ByteUtil.toHexString(payload));
+ loggerWire.debug("Recv: Encoded: {} [{}]", frameType, Bytes.of(payload));
}
Message msg = createMessage((byte) frameType, payload);
@@ -159,7 +160,7 @@ protected void encode(ChannelHandlerContext ctx, Message msg, List