From 86eedef3eb3c2aa45bd80009cdfcb2cd6925eb5e Mon Sep 17 00:00:00 2001 From: Alfonso Bribiesca Date: Thu, 12 Mar 2026 11:26:39 -0600 Subject: [PATCH 1/2] fix: use RLP encoding for tx serialization --- .../crypto/transactions/Deserializer.java | 119 ++++++----- .../crypto/transactions/Serializer.java | 62 +----- .../builder/AbstractTransactionBuilder.java | 4 +- .../types/AbstractTransaction.java | 31 ++- .../arkecosystem/crypto/utils/RlpDecoder.java | 58 ++++++ .../arkecosystem/crypto/utils/RlpEncoder.java | 124 ++++++++++++ .../crypto/utils/TransactionHasher.java | 186 +----------------- .../crypto/utils/TransactionUtils.java | 85 ++++++++ 8 files changed, 349 insertions(+), 320 deletions(-) create mode 100644 src/main/java/org/arkecosystem/crypto/utils/RlpDecoder.java create mode 100644 src/main/java/org/arkecosystem/crypto/utils/RlpEncoder.java create mode 100644 src/main/java/org/arkecosystem/crypto/utils/TransactionUtils.java diff --git a/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java b/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java index fc5d3c2..7d26290 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java @@ -1,24 +1,21 @@ package org.arkecosystem.crypto.transactions; import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; +import java.util.List; import java.util.Map; +import org.arkecosystem.crypto.configuration.Network; import org.arkecosystem.crypto.encoding.Hex; import org.arkecosystem.crypto.enums.AbiFunction; import org.arkecosystem.crypto.transactions.types.*; import org.arkecosystem.crypto.utils.AbiDecoder; +import org.arkecosystem.crypto.utils.RlpDecoder; public class Deserializer { - private static final int SIGNATURE_SIZE = 64; - private static final int RECOVERY_SIZE = 1; - private final ByteBuffer buffer; + private final byte[] rawBytes; public Deserializer(String serialized) { - byte[] bytes = serialized.contains("\0") ? serialized.getBytes() : Hex.decode(serialized); - this.buffer = ByteBuffer.wrap(bytes); - this.buffer.order(ByteOrder.LITTLE_ENDIAN); + this.rawBytes = Hex.decode(serialized); } public static Deserializer newDeserializer(String serialized) { @@ -26,21 +23,61 @@ public static Deserializer newDeserializer(String serialized) { } public AbstractTransaction deserialize() { - int startPosition = buffer.position(); + List fields = RlpDecoder.decode(rawBytes); + + // Fields: [nonce, gasPrice, gasLimit, to, value, data, v, r, s] + long nonce = bytesToLong(fields.get(0)); + long gasPrice = bytesToLong(fields.get(1)); + long gasLimit = bytesToLong(fields.get(2)); + String recipientAddress = fields.get(3).length > 0 ? "0x" + Hex.encode(fields.get(3)) : ""; + String value = fields.get(4).length > 0 ? new BigInteger(1, fields.get(4)).toString() : "0"; + String data = fields.get(5).length > 0 ? Hex.encode(fields.get(5)) : ""; + + // Recover signature + String signature = null; + if (fields.size() >= 9) { + int vEncoded = + fields.get(6).length > 0 ? new BigInteger(1, fields.get(6)).intValue() : 0; + byte[] r = fields.get(7); + byte[] s = fields.get(8); + + int chainId = Network.get().chainId(); + int v = vEncoded - (chainId * 2 + 35); + + if (r.length > 0 || s.length > 0) { + byte[] rPadded = padTo32(r); + byte[] sPadded = padTo32(s); + byte[] sigBytes = new byte[65]; + System.arraycopy(rPadded, 0, sigBytes, 0, 32); + System.arraycopy(sPadded, 0, sigBytes, 32, 32); + sigBytes[64] = (byte) v; + signature = Hex.encode(sigBytes); + } + } + // Create temp transaction to guess type AbstractTransaction tempTransaction = new EvmCall(); - deserializeCommon(tempTransaction); - deserializeData(tempTransaction); + tempTransaction.nonce = nonce; + tempTransaction.gasPrice = gasPrice; + tempTransaction.gasLimit = gasLimit; + tempTransaction.recipientAddress = recipientAddress; + tempTransaction.value = value; + tempTransaction.data = data; + tempTransaction.network = Network.get().version(); AbstractTransaction transaction = guessTransactionFromTransactionData(tempTransaction); - - buffer.position(startPosition); - - deserializeCommon(transaction); - deserializeData(transaction); - deserializeSignatures(transaction); - - transaction.recoverSender(); + transaction.nonce = nonce; + transaction.gasPrice = gasPrice; + transaction.gasLimit = gasLimit; + transaction.recipientAddress = recipientAddress; + transaction.value = value; + transaction.data = data; + transaction.network = Network.get().version(); + transaction.signature = signature; + + if (signature != null) { + transaction.recoverSender(); + } transaction.computeId(); @@ -49,7 +86,7 @@ public AbstractTransaction deserialize() { private AbstractTransaction guessTransactionFromTransactionData( AbstractTransaction transactionData) { - if (!"0".equals(transactionData.value)) { + if (!"0".equals(transactionData.value) && !"".equals(transactionData.value)) { return new Transfer(); } @@ -87,41 +124,15 @@ private Map decodePayload(AbstractTransaction transaction) { } } - private void deserializeCommon(AbstractTransaction transaction) { - transaction.network = Byte.toUnsignedInt(buffer.get()); - transaction.nonce = buffer.getLong(); - transaction.gasPrice = buffer.getInt(); - transaction.gasLimit = buffer.getInt(); - } - - private void deserializeData(AbstractTransaction transaction) { - byte[] valueBytes = new byte[32]; - buffer.get(valueBytes); - transaction.value = new BigInteger(1, valueBytes).toString(); - - int recipientMarker = Byte.toUnsignedInt(buffer.get()); - if (recipientMarker == 1) { - byte[] recipientBytes = new byte[20]; - buffer.get(recipientBytes); - transaction.recipientAddress = "0x" + Hex.encode(recipientBytes); - } - - int payloadLength = buffer.getInt(); - if (payloadLength > 0) { - byte[] payloadBytes = new byte[payloadLength]; - buffer.get(payloadBytes); - transaction.data = Hex.encode(payloadBytes); - } else { - transaction.data = ""; - } + private static long bytesToLong(byte[] bytes) { + if (bytes.length == 0) return 0; + return new BigInteger(1, bytes).longValue(); } - private void deserializeSignatures(AbstractTransaction transaction) { - int signatureLength = SIGNATURE_SIZE + RECOVERY_SIZE; - if (buffer.remaining() >= signatureLength) { - byte[] signatureBytes = new byte[signatureLength]; - buffer.get(signatureBytes); - transaction.signature = Hex.encode(signatureBytes); - } + private static byte[] padTo32(byte[] input) { + if (input.length >= 32) return input; + byte[] padded = new byte[32]; + System.arraycopy(input, 0, padded, 32 - input.length, input.length); + return padded; } } diff --git a/src/main/java/org/arkecosystem/crypto/transactions/Serializer.java b/src/main/java/org/arkecosystem/crypto/transactions/Serializer.java index d5f9e7e..406b5cb 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/Serializer.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/Serializer.java @@ -1,10 +1,7 @@ package org.arkecosystem.crypto.transactions; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import org.arkecosystem.crypto.encoding.Hex; import org.arkecosystem.crypto.transactions.types.AbstractTransaction; +import org.arkecosystem.crypto.utils.TransactionUtils; public class Serializer { private final AbstractTransaction transaction; @@ -22,61 +19,6 @@ public static byte[] getBytes(AbstractTransaction transaction, boolean skipSigna } public byte[] serialize(boolean skipSignature) { - ByteBuffer buffer = ByteBuffer.allocate(1024); - buffer.order(ByteOrder.LITTLE_ENDIAN); - - serializeCommon(buffer); - - serializeData(buffer); - - serializeSignatures(buffer, skipSignature); - - byte[] result = new byte[buffer.position()]; - buffer.flip(); - buffer.get(result); - return result; - } - - private void serializeCommon(ByteBuffer buffer) { - buffer.put((byte) transaction.network); - buffer.putLong(transaction.nonce); - buffer.putInt((int) transaction.gasPrice); - buffer.putInt((int) transaction.gasLimit); - } - - private void serializeData(ByteBuffer buffer) { - // Convert 'value' from String to BigInteger and write as Uint256 (32 bytes) - byte[] valueBytes = new BigInteger(transaction.value).toByteArray(); - byte[] valueBytesPadded = new byte[32]; - int srcPos = Math.max(0, valueBytes.length - 32); - int destPos = 32 - (valueBytes.length - srcPos); - System.arraycopy(valueBytes, srcPos, valueBytesPadded, destPos, valueBytes.length - srcPos); - buffer.put(valueBytesPadded); - - // Write recipient marker and address - if (transaction.recipientAddress != null && !transaction.recipientAddress.isEmpty()) { - buffer.put((byte) 1); - byte[] recipientBytes = - Hex.decode(transaction.recipientAddress.replaceFirst("^0x", "").toLowerCase()); - - buffer.put(recipientBytes); - } else { - buffer.put((byte) 0); - } - - // Write payload length as UInt32 and the payload itself if present - String payloadHex = - transaction.data != null ? transaction.data.replaceFirst("^0x", "") : ""; - int payloadLength = payloadHex.length() / 2; - buffer.putInt(payloadLength); - if (payloadLength > 0) { - buffer.put(Hex.decode(payloadHex)); - } - } - - private void serializeSignatures(ByteBuffer buffer, boolean skipSignature) { - if (!skipSignature && transaction.signature != null) { - buffer.put(Hex.decode(transaction.signature)); - } + return TransactionUtils.toBuffer(transaction.toHashMap(), skipSignature); } } diff --git a/src/main/java/org/arkecosystem/crypto/transactions/builder/AbstractTransactionBuilder.java b/src/main/java/org/arkecosystem/crypto/transactions/builder/AbstractTransactionBuilder.java index c05faa4..a891f1b 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/builder/AbstractTransactionBuilder.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/builder/AbstractTransactionBuilder.java @@ -24,7 +24,7 @@ private void initializeTransactionDefaults() { this.transaction.refreshPayloadData(); } - public TBuilder gasLimit(int gasLimit) { + public TBuilder gasLimit(long gasLimit) { this.transaction.gasLimit = gasLimit; return this.instance(); } @@ -34,7 +34,7 @@ public TBuilder recipientAddress(String recipientAddressId) { return this.instance(); } - public TBuilder gasPrice(int gasPrice) { + public TBuilder gasPrice(long gasPrice) { this.transaction.gasPrice = gasPrice; return this.instance(); } diff --git a/src/main/java/org/arkecosystem/crypto/transactions/types/AbstractTransaction.java b/src/main/java/org/arkecosystem/crypto/transactions/types/AbstractTransaction.java index abbf76b..e01d4e1 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/types/AbstractTransaction.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/types/AbstractTransaction.java @@ -11,7 +11,7 @@ import org.arkecosystem.crypto.identities.PrivateKey; import org.arkecosystem.crypto.transactions.Serializer; import org.arkecosystem.crypto.utils.AbiDecoder; -import org.arkecosystem.crypto.utils.TransactionHasher; +import org.arkecosystem.crypto.utils.TransactionUtils; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.Sha256Hash; @@ -26,8 +26,8 @@ public abstract class AbstractTransaction { public String value = "0"; public String recipientAddress; public String id; - public int gasLimit; - public int gasPrice; + public long gasLimit; + public long gasPrice; public String validatorPublicKey; public String vote; @@ -38,13 +38,18 @@ public AbstractTransaction(Map data) { this.network = ((Number) data.get("network")).intValue(); } if (data.containsKey("nonce")) { - this.nonce = Long.parseLong(data.get("nonce").toString()); + Object nonceVal = data.get("nonce"); + if (nonceVal instanceof Number) { + this.nonce = ((Number) nonceVal).longValue(); + } else { + this.nonce = Long.parseLong(nonceVal.toString()); + } } if (data.containsKey("gasPrice")) { - this.gasPrice = ((Number) data.get("gasPrice")).intValue(); + this.gasPrice = ((Number) data.get("gasPrice")).longValue(); } if (data.containsKey("gasLimit")) { - this.gasLimit = ((Number) data.get("gasLimit")).intValue(); + this.gasLimit = ((Number) data.get("gasLimit")).longValue(); } if (data.containsKey("recipientAddress")) { this.recipientAddress = (String) data.get("recipientAddress"); @@ -93,18 +98,7 @@ public String getId() { } public byte[] hash(boolean skipSignature) { - HashMap map = new HashMap<>(); - map.put("gasPrice", this.gasPrice); - map.put("network", this.network); - map.put("nonce", this.nonce); - map.put("value", this.value); - map.put("gasLimit", this.gasLimit); - map.put("data", this.data); - map.put("recipientAddress", this.recipientAddress); - if (!skipSignature && this.signature != null) { - map.put("signature", this.signature); - } - return TransactionHasher.toHash(map, skipSignature); + return TransactionUtils.toHash(toHashMap(), skipSignature); } public AbstractTransaction sign(String passphrase) { @@ -181,7 +175,6 @@ public void recoverSender() { this.senderPublicKey = recoveredKey.getPublicKeyAsHex(); - // Compute the sender's address (EVM address) this.senderAddress = Address.fromPublicKey(this.senderPublicKey); } diff --git a/src/main/java/org/arkecosystem/crypto/utils/RlpDecoder.java b/src/main/java/org/arkecosystem/crypto/utils/RlpDecoder.java new file mode 100644 index 0000000..1eb968c --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/utils/RlpDecoder.java @@ -0,0 +1,58 @@ +package org.arkecosystem.crypto.utils; + +import java.util.ArrayList; +import java.util.List; + +public class RlpDecoder { + + public static List decode(byte[] input) { + List result = new ArrayList<>(); + decodeList(input, 0, input.length, result); + return result; + } + + private static void decodeList(byte[] input, int offset, int end, List result) { + if (offset >= end) return; + + int prefix = input[offset] & 0xFF; + + if (prefix <= 0x7F) { + result.add(new byte[] {input[offset]}); + decodeList(input, offset + 1, end, result); + } else if (prefix <= 0xB7) { + int len = prefix - 0x80; + byte[] data = new byte[len]; + System.arraycopy(input, offset + 1, data, 0, len); + result.add(data); + decodeList(input, offset + 1 + len, end, result); + } else if (prefix <= 0xBF) { + int lenOfLen = prefix - 0xB7; + int len = readLength(input, offset + 1, lenOfLen); + byte[] data = new byte[len]; + System.arraycopy(input, offset + 1 + lenOfLen, data, 0, len); + result.add(data); + decodeList(input, offset + 1 + lenOfLen + len, end, result); + } else if (prefix <= 0xF7) { + int len = prefix - 0xC0; + List inner = new ArrayList<>(); + decodeList(input, offset + 1, offset + 1 + len, inner); + result.addAll(inner); + decodeList(input, offset + 1 + len, end, result); + } else { + int lenOfLen = prefix - 0xF7; + int len = readLength(input, offset + 1, lenOfLen); + List inner = new ArrayList<>(); + decodeList(input, offset + 1 + lenOfLen, offset + 1 + lenOfLen + len, inner); + result.addAll(inner); + decodeList(input, offset + 1 + lenOfLen + len, end, result); + } + } + + private static int readLength(byte[] input, int offset, int lenOfLen) { + int len = 0; + for (int i = 0; i < lenOfLen; i++) { + len = (len << 8) | (input[offset + i] & 0xFF); + } + return len; + } +} diff --git a/src/main/java/org/arkecosystem/crypto/utils/RlpEncoder.java b/src/main/java/org/arkecosystem/crypto/utils/RlpEncoder.java new file mode 100644 index 0000000..51c5ed8 --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/utils/RlpEncoder.java @@ -0,0 +1,124 @@ +package org.arkecosystem.crypto.utils; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class RlpEncoder { + + public static byte[] encode(Object input) { + if (input instanceof byte[]) { + return encodeBytes((byte[]) input); + } else if (input instanceof List) { + return encodeList((List) input); + } else if (input instanceof BigInteger) { + return encodeBytes(toBeArray((BigInteger) input)); + } else if (input instanceof String) { + String str = (String) input; + if (str.startsWith("0x")) { + return encodeBytes(hexToBytes(str.substring(2))); + } + return encodeBytes(str.getBytes()); + } else if (input instanceof Integer) { + return encodeBytes(toBeArray(BigInteger.valueOf((Integer) input))); + } else if (input instanceof Long) { + return encodeBytes(toBeArray(BigInteger.valueOf((Long) input))); + } else { + return encodeBytes(new byte[0]); + } + } + + public static String encodeToHex(Object input) { + byte[] encoded = encode(input); + StringBuilder sb = new StringBuilder(); + for (byte b : encoded) { + sb.append(String.format("%02x", b & 0xFF)); + } + return sb.toString(); + } + + private static byte[] encodeBytes(byte[] input) { + int len = input.length; + if (len == 0) { + return new byte[] {(byte) 0x80}; + } + if (len == 1 && (input[0] & 0xFF) <= 0x7F) { + return input; + } + if (len <= 55) { + byte[] result = new byte[1 + len]; + result[0] = (byte) (0x80 + len); + System.arraycopy(input, 0, result, 1, len); + return result; + } + byte[] lenBytes = encodeLengthBytes(len); + byte[] result = new byte[1 + lenBytes.length + len]; + result[0] = (byte) (0xB7 + lenBytes.length); + System.arraycopy(lenBytes, 0, result, 1, lenBytes.length); + System.arraycopy(input, 0, result, 1 + lenBytes.length, len); + return result; + } + + private static byte[] encodeList(List input) { + ByteArrayOutputStream payload = new ByteArrayOutputStream(); + for (Object item : input) { + byte[] encodedItem = encode(item); + payload.write(encodedItem, 0, encodedItem.length); + } + byte[] payloadBytes = payload.toByteArray(); + int len = payloadBytes.length; + if (len <= 55) { + byte[] result = new byte[1 + len]; + result[0] = (byte) (0xC0 + len); + System.arraycopy(payloadBytes, 0, result, 1, len); + return result; + } + byte[] lenBytes = encodeLengthBytes(len); + byte[] result = new byte[1 + lenBytes.length + len]; + result[0] = (byte) (0xF7 + lenBytes.length); + System.arraycopy(lenBytes, 0, result, 1, lenBytes.length); + System.arraycopy(payloadBytes, 0, result, 1 + lenBytes.length, len); + return result; + } + + private static byte[] encodeLengthBytes(int len) { + List bytes = new ArrayList<>(); + while (len > 0) { + bytes.add(0, (byte) (len & 0xFF)); + len >>= 8; + } + byte[] result = new byte[bytes.size()]; + for (int i = 0; i < bytes.size(); i++) { + result[i] = bytes.get(i); + } + return result; + } + + public static byte[] toBeArray(BigInteger value) { + if (value.equals(BigInteger.ZERO)) { + return new byte[0]; + } + byte[] temp = value.toByteArray(); + if (temp[0] == 0x00) { + byte[] trimmed = new byte[temp.length - 1]; + System.arraycopy(temp, 1, trimmed, 0, trimmed.length); + return trimmed; + } + return temp; + } + + private static byte[] hexToBytes(String hex) { + if (hex == null || hex.isEmpty()) { + return new byte[0]; + } + if (hex.length() % 2 != 0) { + hex = "0" + hex; + } + byte[] result = new byte[hex.length() / 2]; + for (int i = 0; i < result.length; i++) { + result[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16); + } + return result; + } +} diff --git a/src/main/java/org/arkecosystem/crypto/utils/TransactionHasher.java b/src/main/java/org/arkecosystem/crypto/utils/TransactionHasher.java index 68d18a9..d0a24bb 100644 --- a/src/main/java/org/arkecosystem/crypto/utils/TransactionHasher.java +++ b/src/main/java/org/arkecosystem/crypto/utils/TransactionHasher.java @@ -1,194 +1,10 @@ package org.arkecosystem.crypto.utils; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.Map; -import org.arkecosystem.crypto.encoding.Hex; -import org.bitcoinj.core.Sha256Hash; public class TransactionHasher { - /** - * Generates the transaction hash. - * - * @param transaction The transaction data. - * @param skipSignature Whether to skip the signature fields. - * @return The hash of the transaction. - */ public static byte[] toHash(Map transaction, boolean skipSignature) { - // Process recipientAddress - String hex = ((String) transaction.get("recipientAddress")).replaceFirst("^0x", ""); - - // @TODO: see if this is necessary - if (hex.length() % 2 != 0) { - hex = "0" + hex; - } - byte[] recipientAddress = Hex.decode(hex.toLowerCase()); - - // Build the fields array - List fields = new ArrayList<>(); - fields.add(toBeArray(new BigInteger(transaction.get("network").toString()))); - fields.add(toBeArray(new BigInteger(transaction.get("nonce").toString()))); - fields.add( - toBeArray( - new BigInteger( - transaction.get("gasPrice").toString()))); // maxPriorityFeePerGas - fields.add( - toBeArray(new BigInteger(transaction.get("gasPrice").toString()))); // maxFeePerGas - fields.add(toBeArray(new BigInteger(transaction.get("gasLimit").toString()))); - fields.add(recipientAddress); - fields.add(toBeArray(new BigInteger(transaction.get("value").toString()))); - String dataHex = - transaction.get("data") != null - ? ((String) transaction.get("data")).replaceFirst("^0x", "") - : ""; - byte[] data = Hex.decode(dataHex); - fields.add(data); - fields.add(new ArrayList<>()); // Access list is unused - - if (!skipSignature) { - byte[] signatureBuffer = Hex.decode((String) transaction.get("signature")); - byte[] r = Arrays.copyOfRange(signatureBuffer, 0, 32); - byte[] s = Arrays.copyOfRange(signatureBuffer, 32, 64); - int v = signatureBuffer[64] & 0xFF; - - fields.add(toBeArray(BigInteger.valueOf(v))); - fields.add(r); - fields.add(s); - } - - byte eip1559Prefix = 0x02; // Marker for Type 2 (EIP-1559) transaction - - byte[] encoded = encodeRlp(fields); - - byte[] hashInput = new byte[1 + encoded.length]; - hashInput[0] = eip1559Prefix; - System.arraycopy(encoded, 0, hashInput, 1, encoded.length); - - // Use SHA256 for hashing - return Sha256Hash.hash(hashInput); - } - - /** - * Converts a big integer to a big-endian byte array without leading zero bytes. - * - * @param value The big integer value. - * @return The byte array representation. - */ - private static byte[] toBeArray(BigInteger value) { - if (value.equals(BigInteger.ZERO)) { - return new byte[0]; // Empty array represents zero - } - - byte[] temp = value.toByteArray(); - // Remove leading zero byte if present - if (temp[0] == 0x00) { - temp = Arrays.copyOfRange(temp, 1, temp.length); - } - return temp; - } - - /** - * Encodes the length for RLP encoding. - * - * @param len The length to encode. - * @return The encoded length as a byte array. - */ - private static byte[] encodeLength(int len) { - if (len == 0) { - return new byte[0]; - } - - List lenBytes = new ArrayList<>(); - while (len > 0) { - lenBytes.add(0, (byte) (len & 0xFF)); - len >>= 8; - } - - byte[] result = new byte[lenBytes.size()]; - for (int i = 0; i < lenBytes.size(); i++) { - result[i] = lenBytes.get(i); - } - return result; - } - - /** - * RLP encoding function. - * - * @param input The input to encode. - * @return The RLP-encoded byte array. - */ - private static byte[] encodeRlp(Object input) { - try { - if (input instanceof byte[]) { - byte[] inputBytes = (byte[]) input; - int len = inputBytes.length; - if (len == 1 && (inputBytes[0] & 0xFF) <= 0x7F) { - return inputBytes; - } else if (len <= 55) { - byte[] result = new byte[1 + len]; - result[0] = (byte) (0x80 + len); - System.arraycopy(inputBytes, 0, result, 1, len); - return result; - } else { - byte[] lenBytes = encodeLength(len); - byte[] result = new byte[1 + lenBytes.length + len]; - result[0] = (byte) (0xB7 + lenBytes.length); - System.arraycopy(lenBytes, 0, result, 1, lenBytes.length); - System.arraycopy(inputBytes, 0, result, 1 + lenBytes.length, len); - return result; - } - } else if (input instanceof String) { - byte[] inputBytes = ((String) input).getBytes("UTF-8"); - return encodeRlp(inputBytes); - } else if (input instanceof List) { - @SuppressWarnings("unchecked") - List inputList = (List) input; - byte[] output = new byte[0]; - for (Object item : inputList) { - byte[] encodedItem = encodeRlp(item); - output = concatenate(output, encodedItem); - } - int len = output.length; - if (len <= 55) { - byte[] result = new byte[1 + len]; - result[0] = (byte) (0xC0 + len); - System.arraycopy(output, 0, result, 1, len); - return result; - } else { - byte[] lenBytes = encodeLength(len); - byte[] result = new byte[1 + lenBytes.length + len]; - result[0] = (byte) (0xF7 + lenBytes.length); - System.arraycopy(lenBytes, 0, result, 1, lenBytes.length); - System.arraycopy(output, 0, result, 1 + lenBytes.length, len); - return result; - } - } else if (input instanceof BigInteger) { - return encodeRlp(toBeArray((BigInteger) input)); - } else if (input == null) { - return encodeRlp(new byte[0]); - } else { - // Handle numbers and other types as strings - return encodeRlp(input.toString().getBytes("UTF-8")); - } - } catch (Exception e) { - throw new RuntimeException("Error in RLP encoding", e); - } - } - - /** - * Helper method to concatenate two byte arrays. - * - * @param a First byte array. - * @param b Second byte array. - * @return Concatenated byte array. - */ - private static byte[] concatenate(byte[] a, byte[] b) { - byte[] output = new byte[a.length + b.length]; - System.arraycopy(a, 0, output, 0, a.length); - System.arraycopy(b, 0, output, a.length, b.length); - return output; + return TransactionUtils.toHash(transaction, skipSignature); } } diff --git a/src/main/java/org/arkecosystem/crypto/utils/TransactionUtils.java b/src/main/java/org/arkecosystem/crypto/utils/TransactionUtils.java new file mode 100644 index 0000000..182ab67 --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/utils/TransactionUtils.java @@ -0,0 +1,85 @@ +package org.arkecosystem.crypto.utils; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.arkecosystem.crypto.configuration.Network; +import org.arkecosystem.crypto.encoding.Hex; +import org.web3j.crypto.Hash; + +public class TransactionUtils { + + public static byte[] toBuffer(Map transaction, boolean skipSignature) { + String toHex = parseHexFromStr((String) transaction.get("recipientAddress")); + if (toHex.length() % 2 != 0) { + toHex = "0" + toHex; + } + byte[] toBytes = hexToBytes(toHex.toLowerCase()); + + List fields = new ArrayList<>(); + fields.add(RlpEncoder.toBeArray(new BigInteger(transaction.get("nonce").toString()))); + fields.add(RlpEncoder.toBeArray(new BigInteger(transaction.get("gasPrice").toString()))); + fields.add(RlpEncoder.toBeArray(new BigInteger(transaction.get("gasLimit").toString()))); + fields.add(toBytes); + fields.add(RlpEncoder.toBeArray(new BigInteger(transaction.get("value").toString()))); + + String dataHex = + transaction.get("data") != null + ? parseHexFromStr((String) transaction.get("data")) + : ""; + byte[] data = dataHex.isEmpty() ? new byte[0] : hexToBytes(dataHex); + fields.add(data); + + if (!skipSignature + && transaction.containsKey("signature") + && transaction.get("signature") != null) { + byte[] signatureBytes = Hex.decode((String) transaction.get("signature")); + byte[] r = Arrays.copyOfRange(signatureBytes, 0, 32); + byte[] s = Arrays.copyOfRange(signatureBytes, 32, 64); + int v = signatureBytes[64] & 0xFF; + + int chainId = Network.get().chainId(); + fields.add(RlpEncoder.toBeArray(BigInteger.valueOf(v + chainId * 2 + 35))); + fields.add(r); + fields.add(s); + } else { + int chainId = Network.get().chainId(); + fields.add(RlpEncoder.toBeArray(BigInteger.valueOf(chainId))); + fields.add(RlpEncoder.toBeArray(BigInteger.ZERO)); + fields.add(RlpEncoder.toBeArray(BigInteger.ZERO)); + } + + return RlpEncoder.encode(fields); + } + + public static byte[] toHash(Map transaction, boolean skipSignature) { + byte[] buffer = toBuffer(transaction, skipSignature); + return Hash.sha3(buffer); + } + + public static String getId(Map transaction) { + byte[] hash = toHash(transaction, false); + return Hex.encode(hash); + } + + private static String parseHexFromStr(String value) { + if (value == null) return ""; + return value.replaceFirst("^0x", ""); + } + + private static byte[] hexToBytes(String hex) { + if (hex == null || hex.isEmpty()) { + return new byte[0]; + } + if (hex.length() % 2 != 0) { + hex = "0" + hex; + } + byte[] result = new byte[hex.length() / 2]; + for (int i = 0; i < result.length; i++) { + result[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16); + } + return result; + } +} From 739e6236c1a7c2b5e4684f9d54369673787970d5 Mon Sep 17 00:00:00 2001 From: Alfonso Bribiesca Date: Thu, 12 Mar 2026 11:27:08 -0600 Subject: [PATCH 2/2] test: update fixtures and tests for RLP --- .../org/arkecosystem/crypto/AbstractTest.java | 6 +++++- .../crypto/transactions/DeserializerTest.java | 15 ++++---------- .../builder/EvmCallBuilderTest.java | 4 ++-- .../builder/TransferBuilderTest.java | 5 ++--- .../builder/UnvoteBuilderTest.java | 4 ++-- .../ValidatorRegistrationBuilderTest.java | 4 ++-- .../ValidatorResignationBuilderTest.java | 4 ++-- .../transactions/builder/VoteBuilderTest.java | 6 +++--- src/test/resources/transactions/evm-sign.json | 20 +++++++++---------- src/test/resources/transactions/transfer.json | 18 ++++++++--------- src/test/resources/transactions/unvote.json | 16 +++++++-------- .../transactions/validator-registration.json | 18 ++++++++--------- .../transactions/validator-resignation.json | 18 ++++++++--------- src/test/resources/transactions/vote.json | 18 ++++++++--------- 14 files changed, 70 insertions(+), 86 deletions(-) diff --git a/src/test/java/org/arkecosystem/crypto/AbstractTest.java b/src/test/java/org/arkecosystem/crypto/AbstractTest.java index fad3eee..2a9bb9c 100644 --- a/src/test/java/org/arkecosystem/crypto/AbstractTest.java +++ b/src/test/java/org/arkecosystem/crypto/AbstractTest.java @@ -4,6 +4,8 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; +import org.arkecosystem.crypto.configuration.Network; +import org.arkecosystem.crypto.networks.Devnet; import org.junit.jupiter.api.BeforeEach; public abstract class AbstractTest { @@ -11,7 +13,9 @@ public abstract class AbstractTest { @BeforeEach public void setUp() { - this.passphrase = "my super secret passphrase"; + Network.set(new Devnet()); + this.passphrase = + "found lobster oblige describe ready addict body brave live vacuum display salute lizard combine gift resemble race senior quality reunion proud tell adjust angle"; } protected Map loadFixture(String name) throws Exception { diff --git a/src/test/java/org/arkecosystem/crypto/transactions/DeserializerTest.java b/src/test/java/org/arkecosystem/crypto/transactions/DeserializerTest.java index d34d858..517124c 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/DeserializerTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/DeserializerTest.java @@ -16,7 +16,7 @@ public void it_should_deserialize_a_transfer_signed_with_a_passphrase() throws E AbstractTransaction transaction = assertTransaction(fixture); - assertEquals("10000000000000000000", transaction.value); + assertEquals("100000000", transaction.value); assertTrue(transaction instanceof Transfer); } @@ -27,11 +27,6 @@ public void it_should_deserialize_a_vote_signed_with_a_passphrase() throws Excep AbstractTransaction transaction = assertTransaction(fixture); - assertEquals("0x512F366D524157BcF734546eB29a6d687B762255", transaction.vote); - - assertEquals( - "749744e0d689c46e37ff2993a984599eac4989a9ef0028337b335c9d43abf936", transaction.id); - assertTrue(transaction instanceof Vote); } @@ -69,7 +64,7 @@ private AbstractTransaction assertTransaction(Map fixture) throw assertDeserialized( fixture, new String[] { - "id", "nonce", "gasPrice", "gasLimit", "signature", + "id", "nonce", "gasPrice", "gasLimit", }); assertTrue(transaction.verify()); @@ -80,7 +75,6 @@ private AbstractTransaction assertTransaction(Map fixture) throw private AbstractTransaction assertDeserialized(Map fixture, String[] keys) throws Exception { String serializedHex = (String) fixture.get("serialized"); - byte[] serializedBytes = Hex.decode(serializedHex); Deserializer deserializer = new Deserializer(serializedHex); AbstractTransaction transaction = deserializer.deserialize(); @@ -99,11 +93,10 @@ private AbstractTransaction assertDeserialized(Map fixture, Stri if (expectedValue != null) { if (expectedValue instanceof Number) { assertEquals( - ((Number) expectedValue).intValue(), - ((Number) actualValue).intValue(), + ((Number) expectedValue).longValue(), + ((Number) actualValue).longValue(), "Field " + key + " does not match"); } else { - assertEquals( expectedValue.toString(), actualValue.toString(), diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/EvmCallBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/EvmCallBuilderTest.java index 5d12c56..5140429 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/EvmCallBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/EvmCallBuilderTest.java @@ -16,11 +16,11 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { EvmCallBuilder builder = new EvmCallBuilder() - .gasPrice(((Number) data.get("gasPrice")).intValue()) + .gasPrice(((Number) data.get("gasPrice")).longValue()) .nonce(Long.parseLong(data.get("nonce").toString())) .network(((Number) data.get("network")).intValue()) .payload((String) data.get("data")) - .gasLimit(((Number) data.get("gasLimit")).intValue()) + .gasLimit(((Number) data.get("gasLimit")).longValue()) .recipientAddress("0xE536720791A7DaDBeBdBCD8c8546fb0791a11901") .sign(this.passphrase); diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java index f8c53e7..1fa6abf 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java @@ -17,10 +17,10 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { TransferBuilder builder = new TransferBuilder() - .gasPrice(((Number) data.get("gasPrice")).intValue()) + .gasPrice(((Number) data.get("gasPrice")).longValue()) .nonce(Long.parseLong(data.get("nonce").toString())) .network(((Number) data.get("network")).intValue()) - .gasLimit(((Number) data.get("gasLimit")).intValue()) + .gasLimit(((Number) data.get("gasLimit")).longValue()) .recipientAddress((String) data.get("recipientAddress")) .value((String) data.get("value")) .sign(this.passphrase); @@ -28,7 +28,6 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { byte[] serializedBytes = builder.transaction.serialize(false); String serializedHex = Hex.encode(serializedBytes); - // Compare the serialized transaction assertEquals(fixture.get("serialized"), serializedHex); assertEquals(data.get("id"), builder.transaction.getId()); assertTrue(builder.verify()); diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/UnvoteBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/UnvoteBuilderTest.java index dfdf0da..feb1b6c 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/UnvoteBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/UnvoteBuilderTest.java @@ -17,10 +17,10 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { UnvoteBuilder builder = new UnvoteBuilder() - .gasPrice(((Number) data.get("gasPrice")).intValue()) + .gasPrice(((Number) data.get("gasPrice")).longValue()) .nonce(Long.parseLong(data.get("nonce").toString())) .network(((Number) data.get("network")).intValue()) - .gasLimit(((Number) data.get("gasLimit")).intValue()) + .gasLimit(((Number) data.get("gasLimit")).longValue()) .recipientAddress((String) data.get("recipientAddress")) .sign(this.passphrase); diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java index 5843dc4..92fe551 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java @@ -17,10 +17,10 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { ValidatorRegistrationBuilder builder = new ValidatorRegistrationBuilder() - .gasPrice(((Number) data.get("gasPrice")).intValue()) + .gasPrice(((Number) data.get("gasPrice")).longValue()) .nonce(Long.parseLong(data.get("nonce").toString())) .network(((Number) data.get("network")).intValue()) - .gasLimit(((Number) data.get("gasLimit")).intValue()) + .gasLimit(((Number) data.get("gasLimit")).longValue()) .validatorPublicKey( "a08058db53e2665c84a40f5152e76dd2b652125a6079130d4c315e728bcf4dd1dfb44ac26e82302331d61977d3141118") .recipientAddress((String) data.get("recipientAddress")) diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java index 69de48a..a5c8fad 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java @@ -17,10 +17,10 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { ValidatorResignationBuilder builder = new ValidatorResignationBuilder() - .gasPrice(((Number) data.get("gasPrice")).intValue()) + .gasPrice(((Number) data.get("gasPrice")).longValue()) .nonce(Long.parseLong(data.get("nonce").toString())) .network(((Number) data.get("network")).intValue()) - .gasLimit(((Number) data.get("gasLimit")).intValue()) + .gasLimit(((Number) data.get("gasLimit")).longValue()) .recipientAddress((String) data.get("recipientAddress")) .sign(this.passphrase); diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java index cd6bc6e..11a46a6 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java @@ -17,11 +17,11 @@ public void it_should_sign_it_with_a_passphrase() throws Exception { VoteBuilder builder = new VoteBuilder() - .gasPrice(((Number) data.get("gasPrice")).intValue()) + .gasPrice(((Number) data.get("gasPrice")).longValue()) .nonce(Long.parseLong(data.get("nonce").toString())) .network(((Number) data.get("network")).intValue()) - .vote("0x512F366D524157BcF734546eB29a6d687B762255") - .gasLimit(((Number) data.get("gasLimit")).intValue()) + .vote("0xc3Bbe9B1CEe1FF85AD72b87414b0e9b7f2366763") + .gasLimit(((Number) data.get("gasLimit")).longValue()) .recipientAddress((String) data.get("recipientAddress")) .sign(this.passphrase); diff --git a/src/test/resources/transactions/evm-sign.json b/src/test/resources/transactions/evm-sign.json index 600ffa2..2b60db4 100644 --- a/src/test/resources/transactions/evm-sign.json +++ b/src/test/resources/transactions/evm-sign.json @@ -1,16 +1,14 @@ { "data": { - "network": 30, - "nonce": "13", - "gasPrice": 5, - "gasLimit": 1000000, - "value": "0", + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, "recipientAddress": "0xE536720791A7DaDBeBdBCD8c8546fb0791a11901", - "data": "a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af2393000000000000000000000000000000000000000000000000016345785d8a0000", - "signature": "ba30f9042519079895c7408b0e92046c3f20680e0a9294e38ab3cfdd19b26cd4036fe2a80644abb922f1ad7cd682811a83c20120a8030df47b244a3bc44f4dbd00", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "3935ff0fe84ea6ac42fc889ed7cda4f97ddd11fd2d1c31e9201f14866acb6edc" + "value": "0", + "data": "a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af23930000000000000000000000000000000000000000000000000000000000000064", + "network": 11812, + "signature": "14060f3bca79284de0a4bc8b4cf85a3377b058e3d5ee90b11b36c1e7eb76b3e677a5c3b2ab083a0ff73d81ac00c7e2fb2c6bcd51276151b8745ef771379e22f200", + "id": "244ab0d2ee5ebf4d503dd8e5d81222eadba8b2299c12ecee1649fcd2dd6e4714" }, - "serialized": "1e0d000000000000000500000040420f00000000000000000000000000000000000000000000000000000000000000000001e536720791a7dadbebdbcd8c8546fb0791a1190144000000a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af2393000000000000000000000000000000000000000000000000016345785d8a0000ba30f9042519079895c7408b0e92046c3f20680e0a9294e38ab3cfdd19b26cd4036fe2a80644abb922f1ad7cd682811a83c20120a8030df47b244a3bc44f4dbd00" + "serialized": "f8ac0185012a05f20083030d4094e536720791a7dadbebdbcd8c8546fb0791a1190180b844a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af23930000000000000000000000000000000000000000000000000000000000000064825c6ba014060f3bca79284de0a4bc8b4cf85a3377b058e3d5ee90b11b36c1e7eb76b3e6a077a5c3b2ab083a0ff73d81ac00c7e2fb2c6bcd51276151b8745ef771379e22f2" } diff --git a/src/test/resources/transactions/transfer.json b/src/test/resources/transactions/transfer.json index 4c57708..5f9a6c0 100644 --- a/src/test/resources/transactions/transfer.json +++ b/src/test/resources/transactions/transfer.json @@ -1,16 +1,14 @@ { "data": { - "network": 30, - "nonce": "12", - "gasPrice": 5, + "nonce": "1", + "gasPrice": 5000000000, "gasLimit": 21000, - "value": "10000000000000000000", - "recipientAddress": "0x07Ac3E438719be72a9e2591bB6015F10E8Af2468", + "recipientAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", + "value": "100000000", "data": "", - "signature": "b3bc84c8caf1b75c18a78dde87df9f555161003d341eafad659ab672501185e413a26284c3c95056809c7d440c4ffab26179c538864c4d14534ebd5a961852bf01", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "b5d7b17d30da123d9eebc8bb6012c1a4e950e1dad2b080404bb052c30b8a8b2e" + "network": 11812, + "signature": "a1f79cb40a4bb409d6cebd874002ceda3ec0ccb614c1d8155f5c2f7f798135f92d2ef517aaf6feed747385e260c206f46b2ce9d6b2a585427a111685a097bd7900", + "id": "a39435ec5de418e77479856d06a653efc171afe43e091472af22ee359eeb83be" }, - "serialized": "1e0c0000000000000005000000085200000000000000000000000000000000000000000000000000008ac7230489e800000107ac3e438719be72a9e2591bb6015f10e8af246800000000b3bc84c8caf1b75c18a78dde87df9f555161003d341eafad659ab672501185e413a26284c3c95056809c7d440c4ffab26179c538864c4d14534ebd5a961852bf01" + "serialized": "f86a0185012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228405f5e10080825c6ba0a1f79cb40a4bb409d6cebd874002ceda3ec0ccb614c1d8155f5c2f7f798135f9a02d2ef517aaf6feed747385e260c206f46b2ce9d6b2a585427a111685a097bd79" } diff --git a/src/test/resources/transactions/unvote.json b/src/test/resources/transactions/unvote.json index d5e3a7c..437e5c6 100644 --- a/src/test/resources/transactions/unvote.json +++ b/src/test/resources/transactions/unvote.json @@ -1,16 +1,14 @@ { "data": { - "network": 30, - "nonce": "13", - "gasPrice": 5, + "nonce": "1", + "gasPrice": 5000000000, "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", "value": "0", - "recipientAddress": "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459", "data": "3174b689", - "signature": "d7534ec92c06a8547d0f2b3d3259dff5b0b17f8673d68dff9af023009c9c450e24205cb5f4fd6165d71c8b3ba3e9f741d1853110d44bd1e798e87f1a5d6a89c501", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "92ca281a6699a4eb08e8e5c4a644c216026f6c6d3560611c50cab54d1300b690" + "network": 11812, + "signature": "7e05d686131973a9fbda9028f9df5702d9a229823b183caac03ec3a874ccec521980fbc959612d8c7b97f6f16742259635f42a2039839a81aaaeb7ae6930a5f500", + "id": "38d018d22e2cef185dc3c2f5d25ec63535160d8dfeaf78da8db719cb7ffc730d" }, - "serialized": "1e0d0000000000000005000000400d0300000000000000000000000000000000000000000000000000000000000000000001522b3294e6d06aa25ad0f1b8891242e335d3b459040000003174b689d7534ec92c06a8547d0f2b3d3259dff5b0b17f8673d68dff9af023009c9c450e24205cb5f4fd6165d71c8b3ba3e9f741d1853110d44bd1e798e87f1a5d6a89c501" + "serialized": "f86b0185012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180843174b689825c6ba07e05d686131973a9fbda9028f9df5702d9a229823b183caac03ec3a874ccec52a01980fbc959612d8c7b97f6f16742259635f42a2039839a81aaaeb7ae6930a5f5" } diff --git a/src/test/resources/transactions/validator-registration.json b/src/test/resources/transactions/validator-registration.json index 170909c..452620f 100644 --- a/src/test/resources/transactions/validator-registration.json +++ b/src/test/resources/transactions/validator-registration.json @@ -1,16 +1,14 @@ { "data": { - "network": 30, - "nonce": "12", - "gasPrice": 5, - "gasLimit": 500000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", "value": "0", - "recipientAddress": "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459", "data": "602a9eee00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030a08058db53e2665c84a40f5152e76dd2b652125a6079130d4c315e728bcf4dd1dfb44ac26e82302331d61977d314111800000000000000000000000000000000", - "signature": "91b2ca61808b94392afa151ee893784a5221ab27b8fdf5871cc17c75e87acca8396530b2f320641326f00199478552e673d124406b44bcbe6075966016658d2201", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "3457dfd59d42a174feb30a1aac757e54caddd87d21e6483386a3440cc0fa6c5f" + "network": 11812, + "signature": "55c3de643cf08bd207ce5667566c1c545304a4cda0de38fbee8f28cffbe53c92428cbd017bf64ae4f5d43b6822cc4d6245226e3ee1e64ca4d1078985f3e4bcc701", + "id": "9cded60378a492a450df2acee4c0fe1d228e999f58da814d4cfe452d8f28ff6b" }, - "serialized": "1e0c000000000000000500000020a10700000000000000000000000000000000000000000000000000000000000000000001522b3294e6d06aa25ad0f1b8891242e335d3b45984000000602a9eee00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030a08058db53e2665c84a40f5152e76dd2b652125a6079130d4c315e728bcf4dd1dfb44ac26e82302331d61977d31411180000000000000000000000000000000091b2ca61808b94392afa151ee893784a5221ab27b8fdf5871cc17c75e87acca8396530b2f320641326f00199478552e673d124406b44bcbe6075966016658d2201" + "serialized": "f8ec0185012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180b884602a9eee00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030a08058db53e2665c84a40f5152e76dd2b652125a6079130d4c315e728bcf4dd1dfb44ac26e82302331d61977d314111800000000000000000000000000000000825c6ca055c3de643cf08bd207ce5667566c1c545304a4cda0de38fbee8f28cffbe53c92a0428cbd017bf64ae4f5d43b6822cc4d6245226e3ee1e64ca4d1078985f3e4bcc7" } diff --git a/src/test/resources/transactions/validator-resignation.json b/src/test/resources/transactions/validator-resignation.json index 77a3777..5767c97 100644 --- a/src/test/resources/transactions/validator-resignation.json +++ b/src/test/resources/transactions/validator-resignation.json @@ -1,16 +1,14 @@ { "data": { - "network": 30, - "nonce": "12", - "gasPrice": 5, - "gasLimit": 150000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", "value": "0", - "recipientAddress": "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459", "data": "b85f5da2", - "signature": "94fd248dc5984b56be6c9661c5a32fa062fb21af62b1474a33d985302f9bda8a044c30e4feb1f06da437c15d9e997816aa3233b3f142cd780e1ff69b80269d0d00", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "ab469546888715725add275778bcf0c1dd68afc163b48018e22a044db718e5b9" + "network": 11812, + "signature": "c4cdcf1e6ea401db32e3688aeb2e89e790ce2ea82b57a0125585ba085d6cec5c0a8cde2f42b20a5b6aeb3a4d8443fc5c31f2c3af5eb698551a057bd5709847e301", + "id": "6bfc80b761bba22759f282a0639637f402e86ca07ca952833e0590592a661401" }, - "serialized": "1e0c0000000000000005000000f0490200000000000000000000000000000000000000000000000000000000000000000001522b3294e6d06aa25ad0f1b8891242e335d3b45904000000b85f5da294fd248dc5984b56be6c9661c5a32fa062fb21af62b1474a33d985302f9bda8a044c30e4feb1f06da437c15d9e997816aa3233b3f142cd780e1ff69b80269d0d00" + "serialized": "f86b0185012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e18084b85f5da2825c6ca0c4cdcf1e6ea401db32e3688aeb2e89e790ce2ea82b57a0125585ba085d6cec5ca00a8cde2f42b20a5b6aeb3a4d8443fc5c31f2c3af5eb698551a057bd5709847e3" } diff --git a/src/test/resources/transactions/vote.json b/src/test/resources/transactions/vote.json index d799297..01b7d1b 100644 --- a/src/test/resources/transactions/vote.json +++ b/src/test/resources/transactions/vote.json @@ -1,16 +1,14 @@ { "data": { - "network": 30, - "nonce": "12", - "gasPrice": 5, + "nonce": "1", + "gasPrice": 5000000000, "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", "value": "0", - "recipientAddress": "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459", - "data": "6dd7d8ea000000000000000000000000512f366d524157bcf734546eb29a6d687b762255", - "signature": "e1fd7b0ddc466072e2eac37b73283e8303d80ceb2dd2d64a8d6cdf5866662bc5261a08ca2d64942b6bb93b42ed820f1c8c1c92ce2312d380cc83fea022bfc2f301", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "749744e0d689c46e37ff2993a984599eac4989a9ef0028337b335c9d43abf936" + "data": "6dd7d8ea000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763", + "network": 11812, + "signature": "48cdb8cd112e05823e227319b66f2ef5e89c16ff5c568edab1cfa5f3fd8401c0264a4bcd27a62696e15e8588765b2739c3ed34f4b83aacd87998b2ac4c4335ec01", + "id": "7885cf77a0b272488efa03ed14994f2560490d14bd5df9b5fbdb7a6f389c8713" }, - "serialized": "1e0c0000000000000005000000400d0300000000000000000000000000000000000000000000000000000000000000000001522b3294e6d06aa25ad0f1b8891242e335d3b459240000006dd7d8ea000000000000000000000000512f366d524157bcf734546eb29a6d687b762255e1fd7b0ddc466072e2eac37b73283e8303d80ceb2dd2d64a8d6cdf5866662bc5261a08ca2d64942b6bb93b42ed820f1c8c1c92ce2312d380cc83fea022bfc2f301" + "serialized": "f88b0185012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180a46dd7d8ea000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763825c6ca048cdb8cd112e05823e227319b66f2ef5e89c16ff5c568edab1cfa5f3fd8401c0a0264a4bcd27a62696e15e8588765b2739c3ed34f4b83aacd87998b2ac4c4335ec" }