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 out) byte[] encoded = msg.getEncoded(); if (loggerWire.isDebugEnabled()) { - loggerWire.debug("Send: Encoded: {} [{}]", getCode(msg.getCommand()), ByteUtil.toHexString(encoded)); + loggerWire.debug("Send: Encoded: {} [{}]", getCode(msg.getCommand()), Bytes.of(encoded)); } List frames = splitMessageToFrames(msg); @@ -227,7 +228,7 @@ private Message createMessage(byte code, byte[] payload) { return ethMessageFactory.create(resolved, payload); } - throw new IllegalArgumentException("No such message: " + code + " [" + ByteUtil.toHexString(payload) + "]"); + throw new IllegalArgumentException("No such message: " + code + " [" + Bytes.of(payload) + "]"); } public void setChannel(Channel channel){ diff --git a/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java b/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java index 4cff21586ba..bfc2fdd696a 100644 --- a/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java +++ b/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java @@ -19,6 +19,7 @@ package org.ethereum.net.server; +import co.rsk.core.types.bytes.Bytes; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; @@ -30,7 +31,6 @@ import org.ethereum.config.SystemProperties; import org.ethereum.listener.EthereumListener; import org.ethereum.net.EthereumChannelInitializerFactory; -import org.ethereum.util.ByteUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,7 +73,7 @@ public void start() { peerServiceExecutor.execute(() -> start(config.getBindAddress(), config.getPeerPort())); } - logger.info("RskJ node started: enode://{}@{}:{}" , ByteUtil.toHexString(config.nodeId()), config.getPublicIp(), config.getPeerPort()); + logger.info("RskJ node started: enode://{}@{}:{}" , Bytes.of(config.nodeId()), config.getPublicIp(), config.getPeerPort()); } @Override @@ -110,7 +110,7 @@ private void start(InetAddress host, int port) { // Start the client. logger.info("Listening for incoming connections, host: {}, port: [{}] ", host, port); - logger.info("NodeId: [{}] ", ByteUtil.toHexString(config.nodeId())); + logger.info("NodeId: [{}] ", Bytes.of(config.nodeId())); ChannelFuture f = b.bind(host, port).sync(); diff --git a/rskj-core/src/main/java/org/ethereum/rpc/Topic.java b/rskj-core/src/main/java/org/ethereum/rpc/Topic.java index e32e591ff2c..d7f6cffc98b 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/Topic.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/Topic.java @@ -18,12 +18,11 @@ package org.ethereum.rpc; -import java.util.Arrays; - -import org.ethereum.util.ByteUtil; - +import co.rsk.core.types.bytes.Bytes; import co.rsk.util.HexUtils; +import java.util.Arrays; + /** * Created by ajlopez on 18/01/2018. */ @@ -79,7 +78,7 @@ public int hashCode() { @Override public String toString() { - return ByteUtil.toHexString(bytes); + return Bytes.toPrintableString(bytes); } public String toJsonString() { diff --git a/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java b/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java index ea0b8a2dfff..a4ef7aa34be 100644 --- a/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java +++ b/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java @@ -19,6 +19,7 @@ package org.ethereum.solidity; +import co.rsk.core.types.bytes.Bytes; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import org.ethereum.util.ByteUtil; @@ -375,7 +376,7 @@ public byte[] encode(Object value) { byte[] addr = super.encode(value); for (int i = 0; i < 12; i++) { if (addr[i] != 0) { - throw new RuntimeException("Invalid address (should be 20 bytes length): " + ByteUtil.toHexString(addr)); + throw new RuntimeException("Invalid address (should be 20 bytes length): " + Bytes.of(addr)); } } return addr; diff --git a/rskj-core/src/main/java/org/ethereum/vm/VM.java b/rskj-core/src/main/java/org/ethereum/vm/VM.java index f7568f1f067..2f829c8b426 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -21,6 +21,7 @@ import co.rsk.config.VmConfig; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import co.rsk.crypto.Keccak256; import co.rsk.rpc.netty.ExecTimeoutContext; import org.bouncycastle.util.BigIntegers; @@ -2175,8 +2176,8 @@ private void dumpLine(OpCode op, long gasBefore, long gasCost, long memWords, Pr DataWord key = keysIterator.next(); DataWord value = storage.getStorageValue(ownerAddress, key); dumpLogger.trace("{} {}", - ByteUtil.toHexString(key.getNoLeadZeroesData()), - ByteUtil.toHexString(value.getNoLeadZeroesData())); + Bytes.of(key.getNoLeadZeroesData()), + Bytes.of(value.getNoLeadZeroesData())); } break; default: diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java index 1fb34df8b82..33ef0607727 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java @@ -21,6 +21,7 @@ import co.rsk.config.VmConfig; import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import co.rsk.crypto.Keccak256; import co.rsk.pcc.NativeContract; import co.rsk.peg.Bridge; @@ -581,7 +582,7 @@ private void refundRemainingGas(long gasLimit, ProgramResult programResult) { refundGas(refundGas, "remaining gas from the internal call"); if (isGasLogEnabled) { gasLogger.info("The remaining gas is refunded, account: [{}], gas: [{}] ", - ByteUtil.toHexString(getOwnerAddress().getLast20Bytes()), + Bytes.of(getOwnerAddress().getLast20Bytes()), refundGas ); } diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java b/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java index 286c2662b19..258c3ecf416 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java @@ -20,6 +20,7 @@ import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.core.Block; import org.ethereum.core.Repository; import org.ethereum.core.SignatureCache; @@ -118,19 +119,19 @@ public ProgramInvoke createProgramInvoke(Transaction tx, int txindex, Block bloc "minimumGasPrice={}\n", addr, - ByteUtil.toHexString(origin), - ByteUtil.toHexString(caller), + Bytes.of(origin), + Bytes.of(caller), balance, txGasPrice, new BigInteger(1, gas).longValue(), callValue, - ByteUtil.toHexString(data), - ByteUtil.toHexString(lastHash), - ByteUtil.toHexString(coinbase), + Bytes.of(data), + Bytes.of(lastHash), + Bytes.of(coinbase), timestamp, number, txindex, - ByteUtil.toHexString(difficulty), + Bytes.of(difficulty), gaslimit, minimumGasPrice); } @@ -190,20 +191,20 @@ public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, Da "difficulty={}\n" + "gaslimit={}\n" + "minimumGasPrice={}\n", - ByteUtil.toHexString(address.getLast20Bytes()), - ByteUtil.toHexString(origin.getLast20Bytes()), - ByteUtil.toHexString(caller.getLast20Bytes()), + Bytes.of(address.getLast20Bytes()), + Bytes.of(origin.getLast20Bytes()), + Bytes.of(caller.getLast20Bytes()), balance.toString(), txGasPrice.longValue(), agas, - ByteUtil.toHexString(callValue.getNoLeadZeroesData()), + Bytes.of(callValue.getNoLeadZeroesData()), data == null ? "" : ByteUtil.toHexString(data), - ByteUtil.toHexString(lastHash.getData()), - ByteUtil.toHexString(coinbase.getLast20Bytes()), + Bytes.of(lastHash.getData()), + Bytes.of(coinbase.getLast20Bytes()), timestamp.longValue(), number.longValue(), transactionIndex.intValue(), - ByteUtil.toHexString(difficulty.getNoLeadZeroesData()), + Bytes.of(difficulty.getNoLeadZeroesData()), gasLimit.bigIntValue(), minimumGasPrice.longValue()); } diff --git a/rskj-core/src/main/resources/version.properties b/rskj-core/src/main/resources/version.properties index da76564f104..f055a4c4135 100644 --- a/rskj-core/src/main/resources/version.properties +++ b/rskj-core/src/main/resources/version.properties @@ -1,2 +1,2 @@ versionNumber='6.3.1' -modifier="RC" +modifier="ARROWHEAD" diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java new file mode 100644 index 00000000000..93707953604 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java @@ -0,0 +1,77 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * 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.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BytesSliceTest { + + @Test + void testCopyArrayOfRange() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + byte[] expectedResult = new byte[]{3, 4, 5}; + assertArrayEquals(expectedResult, Bytes.of(bArray).slice(0, bArray.length).copyArrayOfRange(2, 5)); + } + + @Test + void testCopyArray() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + byte[] expectedResult = new byte[]{3, 4, 5}; + byte[] actualResult = Bytes.of(bArray).slice(2, 5).copyArray(); + assertNotSame(expectedResult, actualResult); // refs are different + assertArrayEquals(expectedResult, actualResult); + } + + @Test + void testCopyBytesOfRange() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + Bytes expectedResult = Bytes.of(new byte[]{3, 4, 5}); + assertTrue(Bytes.equalBytes(expectedResult, Bytes.of(bArray).slice(0, bArray.length).copyBytesOfRange(2, 5))); + } + + @Test + void testCopyBytes() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + Bytes expectedResult = Bytes.of(new byte[]{3, 4, 5}); + Bytes actualResult = Bytes.of(bArray).slice(2, 5).copyBytes(); + assertTrue(Bytes.equalBytes(expectedResult, actualResult)); + assertArrayEquals(expectedResult.asUnsafeByteArray(), actualResult.asUnsafeByteArray()); + } + + @Test + void testSlice() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + BytesSlice actualResult = Bytes.of(bArray).slice(1, 6).slice(1, 4).slice(1, 3); + byte[] expectedResult = new byte[]{4, 5}; + assertEquals(2, actualResult.length()); + assertArrayEquals(expectedResult, actualResult.copyArray()); + } + + @Test + void testEmptySlice() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + BytesSlice actualResult = Bytes.of(bArray).slice(1, 6).slice(1, 4).slice(1, 3).slice(0, 0); + byte[] expectedResult = new byte[]{}; + assertEquals(0, actualResult.length()); + assertArrayEquals(expectedResult, actualResult.copyArray()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java new file mode 100644 index 00000000000..b60ca431ddc --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java @@ -0,0 +1,119 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * 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.TestUtils; +import org.ethereum.util.ByteUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BytesTest { + + @Test + void testBytesOf() { + assertNull(Bytes.of(null)); + assertNotNull(Bytes.of(new byte[]{})); + assertNotNull(Bytes.of(new byte[]{1})); + } + + @Test + void testToPrintableString() { + assertEquals("0a", Bytes.toPrintableString(new byte[]{10})); + } + + @Test + void testToPrintableStringWithNull() { + assertEquals("", Bytes.toPrintableString((byte[]) null)); + } + + @Test + void testToPrintableStringWithDefaultValue() { + assertEquals("xyz", Bytes.toPrintableString(null, "xyz")); + } + + @Test + void testAsUnsafeByteArray() { + byte[] bArray = {1, 2, 3}; + assertTrue(bArray == Bytes.of(bArray).asUnsafeByteArray()); + } + + @Test + void testEqualBytes() { + byte[] b1Array = {1, 2, 3}; + byte[] b2Array = {1, 2, 3}; + assertTrue(Bytes.equalBytes(Bytes.of(b1Array), Bytes.of(b2Array))); + } + + @Test + void testBytesToString() { + byte[] bArray = new byte[]{1, 2, 3, 5, 8, 13}; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '" + ByteUtil.toHexString(bArray) + "' hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testShortEnoughBytesToString() { + byte[] bArray = TestUtils.generateBytes("hash",32); + + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '" + ByteUtil.toHexString(bArray) + "' hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testLongBytesToString() { + byte[] bArray1 = TestUtils.generateBytes("hash1",15); + byte[] bArray2 = TestUtils.generateBytes("hash2",15); + byte[] finalArray = ByteUtil.merge(bArray1, new byte[]{1, 2, 3}, bArray2); + + assertEquals(33, finalArray.length); + + String actualMessage = String.format("Some '%s' hex", Bytes.of(finalArray)); + String expectedMessage = "Some '" + + ByteUtil.toHexString(bArray1) + + ".." + + ByteUtil.toHexString(bArray2) + + "' hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testNullBytesToString() { + byte[] bArray = null; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '" + null + "' hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testEmptyBytesToString() { + byte[] bArray = new byte[]{}; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '' hex"; + + assertEquals(expectedMessage, actualMessage); + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java index ba09d62c288..1fbe8101c0b 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java @@ -79,7 +79,7 @@ void validatesExtendedPublicKeyFormat() { }); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertTrue(e.getMessage().contains("Invalid extended public key")); + Assertions.assertEquals("Invalid extended public key 'this-is-not-an-xpub'", e.getMessage()); } } @@ -91,7 +91,7 @@ void failsUponInvalidPublicKey() { }); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertTrue(e.getMessage().contains("Invalid extended public key")); + Assertions.assertEquals("Invalid extended public key 'tpubD6NzVbkrYhZ4YHQqwWz3Tm1ESZ9AidobeyLG4mEezB6hN8gFFWrcjczyF77L...'", e.getMessage()); } } @@ -101,7 +101,7 @@ void failsUponNull() { method.execute(null); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertTrue(e.getMessage().contains("Invalid extended public key")); + Assertions.assertEquals("Invalid extended public key 'null'", e.getMessage()); } } diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java index 2e4dbad3eb4..7722487229c 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java @@ -25,6 +25,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + class HDWalletUtilsHelperTest { private HDWalletUtilsHelper helper; @@ -35,7 +37,7 @@ void createHelper() { @Test void validateAndExtractNetworkFromExtendedPublicKeyMainnet() throws NativeContractIllegalArgumentException { - Assertions.assertEquals( + assertEquals( NetworkParameters.fromID(NetworkParameters.ID_MAINNET), helper.validateAndExtractNetworkFromExtendedPublicKey("xpubSomethingSomething") ); @@ -43,14 +45,25 @@ void validateAndExtractNetworkFromExtendedPublicKeyMainnet() throws NativeContra @Test void validateAndExtractNetworkFromExtendedPublicKeyTestnet() throws NativeContractIllegalArgumentException { - Assertions.assertEquals( + assertEquals( NetworkParameters.fromID(NetworkParameters.ID_TESTNET), helper.validateAndExtractNetworkFromExtendedPublicKey("tpubSomethingSomething") ); } @Test - void validateAndExtractNetworkFromExtendedPublicKeyInvalid() { - Assertions.assertThrows(NativeContractIllegalArgumentException.class, () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidStuff")); + void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidXpub() { + NativeContractIllegalArgumentException exception = Assertions.assertThrows( + NativeContractIllegalArgumentException.class, + () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidStuff")); + assertEquals("Invalid extended public key 'completelyInvalidStuff'", exception.getMessage()); + } + + @Test + void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidLongXpub() { + NativeContractIllegalArgumentException exception = Assertions.assertThrows( + NativeContractIllegalArgumentException.class, + () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidLongLongLongLongLongLongLongLongLongLongLonStuff")); + assertEquals("Invalid extended public key 'completelyInvalidLongLongLongLongLongLongLongLongLongLongLonStuf...'", exception.getMessage()); } } diff --git a/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java b/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java new file mode 100644 index 00000000000..2cd58093e6f --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java @@ -0,0 +1,55 @@ +/* + * 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 org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StringUtilsTest { + + private static final String STR_64_CHARS = "ee5c851e70650111887bb6c04e18ef4353391abe37846234c17895a9ca2b33d5"; + private static final String STR_65_CHARS = STR_64_CHARS + "a"; + + @Test + void testTrim() { + assertNull(StringUtils.trim(null)); + assertEquals("", StringUtils.trim("")); + assertEquals("a", StringUtils.trim("a")); + + assertEquals(64, STR_64_CHARS.length()); + assertEquals(65, STR_65_CHARS.length()); + + assertEquals(STR_64_CHARS, StringUtils.trim(STR_64_CHARS)); + assertEquals(STR_64_CHARS + "...", StringUtils.trim(STR_65_CHARS)); + } + + @Test + void testTrimWithMaxLength() { + assertEquals("...", StringUtils.trim("abc", 0)); + assertEquals("abc", StringUtils.trim("abc", 3)); + assertEquals("abc", StringUtils.trim("abc", 4)); + assertEquals("abc...", StringUtils.trim("abcd", 3)); + } + + @Test + void testTrimWithInvalidMaxLength() { + assertThrows(IllegalArgumentException.class, () -> StringUtils.trim("abc", -1)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/core/BloomTest.java b/rskj-core/src/test/java/org/ethereum/core/BloomTest.java index fc09358c9ab..798775ba7e7 100644 --- a/rskj-core/src/test/java/org/ethereum/core/BloomTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/BloomTest.java @@ -19,6 +19,7 @@ package org.ethereum.core; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.crypto.HashUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -30,10 +31,8 @@ */ class BloomTest { - @Test /// based on http://bit.ly/1MtXxFg - void test1(){ - + void test1() { byte[] address = Hex.decode("095e7baea6a6c7c4c2dfeb977efac326af552d87"); Bloom addressBloom = Bloom.create(HashUtil.keccak256(address)); @@ -44,10 +43,9 @@ void test1(){ totalBloom.or(addressBloom); totalBloom.or(topicBloom); - Assertions.assertEquals( "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000", - totalBloom.toString() + Bytes.of(totalBloom.getData()).toHexString() ); }