From bb76fa80cdad885f8c7cdc8ca3482aaeadae36f2 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Thu, 15 Jul 2021 09:27:49 +0100 Subject: [PATCH] Another significant upgrade of arbitrary transactions Adds "name", "method", "secret", and "compression" properties. These are the foundations needed in order to handle updates, encryption, and name registration. Compression has been added so that we have the option of switching to different algorithms whilst maintaining support for existing transactions. --- .../api/resource/ArbitraryResource.java | 9 +- .../qortal/api/resource/WebsiteResource.java | 14 ++- .../transaction/ArbitraryTransactionData.java | 101 +++++++++++++++++- .../hsqldb/HSQLDBDatabaseUpdates.java | 14 ++- .../HSQLDBArbitraryTransactionRepository.java | 16 ++- .../transaction/ArbitraryTransaction.java | 9 -- .../org/qortal/transform/Transformer.java | 1 + .../ArbitraryTransactionTransformer.java | 54 ++++++++-- .../arbitrary/ArbitraryTransactionTests.java | 6 +- .../transaction/ArbitraryTestTransaction.java | 9 +- 10 files changed, 199 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/ArbitraryResource.java b/src/main/java/org/qortal/api/resource/ArbitraryResource.java index 8e1b043d..cefffd67 100644 --- a/src/main/java/org/qortal/api/resource/ArbitraryResource.java +++ b/src/main/java/org/qortal/api/resource/ArbitraryResource.java @@ -263,6 +263,12 @@ public class ArbitraryResource { } byte[] creatorPublicKey = Base58.decode(creatorPublicKeyBase58); + String name = null; + byte[] secret = null; + ArbitraryTransactionData.Method method = ArbitraryTransactionData.Method.PUT; + ArbitraryTransactionData.Service service = ArbitraryTransactionData.Service.ARBITRARY_DATA; + ArbitraryTransactionData.Compression compression = ArbitraryTransactionData.Compression.NONE; + // Check if a file or directory has been supplied File file = new File(path); if (!file.isFile()) { @@ -309,7 +315,8 @@ public class ArbitraryResource { List payments = new ArrayList<>(); ArbitraryTransactionData transactionData = new ArbitraryTransactionData(baseTransactionData, - 5, ArbitraryTransaction.SERVICE_ARBITRARY_DATA, 0, size, digest, dataType, chunkHashes, payments); + 5, service, 0, size, name, method, + secret, compression, digest, dataType, chunkHashes, payments); ArbitraryTransaction transaction = (ArbitraryTransaction) Transaction.fromData(repository, transactionData); transaction.computeNonce(); diff --git a/src/main/java/org/qortal/api/resource/WebsiteResource.java b/src/main/java/org/qortal/api/resource/WebsiteResource.java index 3d4984c3..ccfdc21f 100644 --- a/src/main/java/org/qortal/api/resource/WebsiteResource.java +++ b/src/main/java/org/qortal/api/resource/WebsiteResource.java @@ -95,6 +95,12 @@ public class WebsiteResource { } byte[] creatorPublicKey = Base58.decode(creatorPublicKeyBase58); + String name = null; + byte[] secret = null; + ArbitraryTransactionData.Method method = ArbitraryTransactionData.Method.PUT; + ArbitraryTransactionData.Service service = ArbitraryTransactionData.Service.WEBSITE; + ArbitraryTransactionData.Compression compression = ArbitraryTransactionData.Compression.ZIP; + DataFile dataFile = this.hostWebsite(path); if (dataFile == null) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); @@ -120,7 +126,8 @@ public class WebsiteResource { List payments = new ArrayList<>(); ArbitraryTransactionData transactionData = new ArbitraryTransactionData(baseTransactionData, - 5, ArbitraryTransaction.SERVICE_WEBSITE, 0, size, digest, dataType, chunkHashes, payments); + 5, service, 0, size, name, method, + secret, compression, digest, dataType, chunkHashes, payments); ArbitraryTransaction transaction = (ArbitraryTransaction) Transaction.fromData(repository, transactionData); transaction.computeNonce(); @@ -318,7 +325,10 @@ public class WebsiteResource { } try { - ZipUtils.unzip(dataFile.getFilePath(), destPath); + // TODO: compression types + //if (transactionData.getCompression() == ArbitraryTransactionData.Compression.ZIP) { + ZipUtils.unzip(dataFile.getFilePath(), destPath); + //} } catch (IOException e) { LOGGER.info("Unable to unzip file"); } diff --git a/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java b/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java index 19c0d0dc..9fc91465 100644 --- a/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java +++ b/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java @@ -1,6 +1,7 @@ package org.qortal.data.transaction; import java.util.List; +import java.util.Map; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAccessType; @@ -12,6 +13,9 @@ import org.qortal.transaction.Transaction.TransactionType; import io.swagger.v3.oas.annotations.media.Schema; +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toMap; + // All properties to be converted to JSON via JAXB @XmlAccessorType(XmlAccessType.FIELD) @Schema(allOf = { TransactionData.class }) @@ -25,21 +29,87 @@ public class ArbitraryTransactionData extends TransactionData { DATA_HASH; } + // Service types + public enum Service { + AUTO_UPDATE(1), + ARBITRARY_DATA(100), + WEBSITE(200), + GIT_REPOSITORY(300), + BLOG_POST(777), + BLOG_COMMENT(778); + + public final int value; + + private static final Map map = stream(Service.values()) + .collect(toMap(service -> service.value, service -> service)); + + Service(int value) { + this.value = value; + } + + public static Service valueOf(int value) { + return map.get(value); + } + } + + // Methods + public enum Method { + PUT(0), // A complete replacement of a resource + PATCH(1); // An update / partial replacement of a resource + + public final int value; + + private static final Map map = stream(Method.values()) + .collect(toMap(method -> method.value, method -> method)); + + Method(int value) { + this.value = value; + } + + public static Method valueOf(int value) { + return map.get(value); + } + } + + // Compression types + public enum Compression { + NONE(0), + ZIP(1); + + public final int value; + + private static final Map map = stream(Compression.values()) + .collect(toMap(compression -> compression.value, compression -> compression)); + + Compression(int value) { + this.value = value; + } + + public static Compression valueOf(int value) { + return map.get(value); + } + } + // Properties private int version; - @Schema(example = "sender_public_key") private byte[] senderPublicKey; - private int service; + private Service service; private int nonce; private int size; + private String name; + private Method method; + private byte[] secret; + private Compression compression; + @Schema(example = "raw_data_in_base58") private byte[] data; private DataType dataType; @Schema(example = "chunk_hashes_in_base58") private byte[] chunkHashes; + private List payments; // Constructors @@ -54,8 +124,9 @@ public class ArbitraryTransactionData extends TransactionData { } public ArbitraryTransactionData(BaseTransactionData baseTransactionData, - int version, int service, int nonce, int size, byte[] data, - DataType dataType, byte[] chunkHashes, List payments) { + int version, Service service, int nonce, int size, + String name, Method method, byte[] secret, Compression compression, + byte[] data, DataType dataType, byte[] chunkHashes, List payments) { super(TransactionType.ARBITRARY, baseTransactionData); this.senderPublicKey = baseTransactionData.creatorPublicKey; @@ -63,6 +134,10 @@ public class ArbitraryTransactionData extends TransactionData { this.service = service; this.nonce = nonce; this.size = size; + this.name = name; + this.method = method; + this.secret = secret; + this.compression = compression; this.data = data; this.dataType = dataType; this.chunkHashes = chunkHashes; @@ -79,7 +154,7 @@ public class ArbitraryTransactionData extends TransactionData { return this.version; } - public int getService() { + public Service getService() { return this.service; } @@ -95,6 +170,22 @@ public class ArbitraryTransactionData extends TransactionData { return this.size; } + public String getName() { + return this.name; + } + + public Method getMethod() { + return this.method; + } + + public byte[] getSecret() { + return this.secret; + } + + public Compression getCompression() { + return this.compression; + } + public byte[] getData() { return this.data; } diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabaseUpdates.java index 5e906d75..2fcbd4e3 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -4,8 +4,6 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.Arrays; -import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -781,10 +779,18 @@ public class HSQLDBDatabaseUpdates { stmt.execute("ALTER TABLE ArbitraryTransactions ADD chunk_hashes ArbitraryDataHashes"); // For finding data files by hash stmt.execute("CREATE INDEX ArbitraryDataIndex ON ArbitraryTransactions (is_data_raw, data)"); - - // TODO: resource ID, compression, layers break; + case 35: + // We need the ability for arbitrary transactions to be associated with a name + stmt.execute("ALTER TABLE ArbitraryTransactions ADD name RegisteredName"); + // A "method" specifies how the data should be applied (e.g. PUT or PATCH) + stmt.execute("ALTER TABLE ArbitraryTransactions ADD update_method INTEGER NOT NULL DEFAULT 0"); + // For public data, the AES shared secret needs to be available. This is more for data obfuscation as apposed to actual encryption. + stmt.execute("ALTER TABLE ArbitraryTransactions ADD secret VARBINARY(32)"); + // We want to support compressed and uncompressed data, as well as different compression algorithms + stmt.execute("ALTER TABLE ArbitraryTransactions ADD compression INTEGER NOT NULL DEFAULT 0"); + default: // nothing to do return false; diff --git a/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java b/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java index 97f52f61..2a9aa764 100644 --- a/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java @@ -20,7 +20,8 @@ public class HSQLDBArbitraryTransactionRepository extends HSQLDBTransactionRepos } TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException { - String sql = "SELECT version, nonce, service, size, is_data_raw, data, chunk_hashes from ArbitraryTransactions WHERE signature = ?"; + String sql = "SELECT version, nonce, service, size, is_data_raw, data, chunk_hashes, " + + "name, update_method, secret, compression from ArbitraryTransactions WHERE signature = ?"; try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) { if (resultSet == null) @@ -28,15 +29,20 @@ public class HSQLDBArbitraryTransactionRepository extends HSQLDBTransactionRepos int version = resultSet.getInt(1); int nonce = resultSet.getInt(2); - int service = resultSet.getInt(3); + ArbitraryTransactionData.Service service = ArbitraryTransactionData.Service.valueOf(resultSet.getInt(3)); int size = resultSet.getInt(4); boolean isDataRaw = resultSet.getBoolean(5); // NOT NULL, so no null to false DataType dataType = isDataRaw ? DataType.RAW_DATA : DataType.DATA_HASH; byte[] data = resultSet.getBytes(6); byte[] chunkHashes = resultSet.getBytes(7); + String name = resultSet.getString(8); + ArbitraryTransactionData.Method method = ArbitraryTransactionData.Method.valueOf(resultSet.getInt(9)); + byte[] secret = resultSet.getBytes(10); + ArbitraryTransactionData.Compression compression = ArbitraryTransactionData.Compression.valueOf(resultSet.getInt(11)); List payments = this.getPaymentsFromSignature(baseTransactionData.getSignature()); - return new ArbitraryTransactionData(baseTransactionData, version, service, nonce, size, data, dataType, chunkHashes, payments); + return new ArbitraryTransactionData(baseTransactionData, version, service, nonce, size, name, method, + secret, compression, data, dataType, chunkHashes, payments); } catch (SQLException e) { throw new DataException("Unable to fetch arbitrary transaction from repository", e); } @@ -56,7 +62,9 @@ public class HSQLDBArbitraryTransactionRepository extends HSQLDBTransactionRepos .bind("version", arbitraryTransactionData.getVersion()).bind("service", arbitraryTransactionData.getService()) .bind("nonce", arbitraryTransactionData.getNonce()).bind("size", arbitraryTransactionData.getSize()) .bind("is_data_raw", arbitraryTransactionData.getDataType() == DataType.RAW_DATA).bind("data", arbitraryTransactionData.getData()) - .bind("chunk_hashes", arbitraryTransactionData.getChunkHashes()); + .bind("chunk_hashes", arbitraryTransactionData.getChunkHashes()).bind("name", arbitraryTransactionData.getName()) + .bind("method", arbitraryTransactionData.getMethod()).bind("secret", arbitraryTransactionData.getSecret()) + .bind("compression", arbitraryTransactionData.getCompression()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qortal/transaction/ArbitraryTransaction.java b/src/main/java/org/qortal/transaction/ArbitraryTransaction.java index 8f42aff9..6ee8d5ff 100644 --- a/src/main/java/org/qortal/transaction/ArbitraryTransaction.java +++ b/src/main/java/org/qortal/transaction/ArbitraryTransaction.java @@ -24,15 +24,6 @@ public class ArbitraryTransaction extends Transaction { // Properties private ArbitraryTransactionData arbitraryTransactionData; - // Services - public static final int SERVICE_AUTO_UPDATE = 1; - public static final int SERVICE_NAME_STORAGE = 10; - public static final int SERVICE_ARBITRARY_DATA = 100; - public static final int SERVICE_WEBSITE = 200; - public static final int SERVICE_GIT_REPOSITORY = 300; - public static final int SERVICE_BLOG_POST = 777; - public static final int SERVICE_BLOG_COMMENT = 778; - // Other useful constants public static final int MAX_DATA_SIZE = 4000; public static final int MAX_CHUNK_HASHES_LENGTH = 8000; diff --git a/src/main/java/org/qortal/transform/Transformer.java b/src/main/java/org/qortal/transform/Transformer.java index 341d545b..e78d3284 100644 --- a/src/main/java/org/qortal/transform/Transformer.java +++ b/src/main/java/org/qortal/transform/Transformer.java @@ -20,5 +20,6 @@ public abstract class Transformer { public static final int MD5_LENGTH = 16; public static final int SHA256_LENGTH = 32; + public static final int AES256_LENGTH = 32; } diff --git a/src/main/java/org/qortal/transform/transaction/ArbitraryTransactionTransformer.java b/src/main/java/org/qortal/transform/transaction/ArbitraryTransactionTransformer.java index f9df86af..4df2e148 100644 --- a/src/main/java/org/qortal/transform/transaction/ArbitraryTransactionTransformer.java +++ b/src/main/java/org/qortal/transform/transaction/ArbitraryTransactionTransformer.java @@ -6,12 +6,14 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import com.google.common.base.Utf8; import org.qortal.crypto.Crypto; import org.qortal.data.PaymentData; import org.qortal.data.transaction.ArbitraryTransactionData; import org.qortal.data.transaction.BaseTransactionData; import org.qortal.data.transaction.TransactionData; import org.qortal.data.transaction.ArbitraryTransactionData.DataType; +import org.qortal.naming.Name; import org.qortal.transaction.ArbitraryTransaction; import org.qortal.transaction.Transaction; import org.qortal.transaction.Transaction.TransactionType; @@ -32,8 +34,12 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { private static final int RAW_DATA_SIZE_LENGTH = INT_LENGTH; private static final int CHUNKS_SIZE_LENGTH = INT_LENGTH; private static final int NUMBER_PAYMENTS_LENGTH = INT_LENGTH; + private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int SECRET_LENGTH = AES256_LENGTH; + private static final int COMPRESSION_LENGTH = INT_LENGTH; - private static final int EXTRAS_LENGTH = SERVICE_LENGTH + NONCE_LENGTH + DATA_TYPE_LENGTH + DATA_SIZE_LENGTH + RAW_DATA_SIZE_LENGTH + CHUNKS_SIZE_LENGTH; + private static final int EXTRAS_LENGTH = SERVICE_LENGTH + NONCE_LENGTH + NAME_SIZE_LENGTH + SERVICE_LENGTH + + COMPRESSION_LENGTH + DATA_TYPE_LENGTH + DATA_SIZE_LENGTH + RAW_DATA_SIZE_LENGTH + CHUNKS_SIZE_LENGTH; protected static final TransactionLayout layout; @@ -46,6 +52,11 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { layout.add("sender's public key", TransformationType.PUBLIC_KEY); layout.add("nonce", TransformationType.INT); // Version 5+ + layout.add("name", TransformationType.DATA); // Version 5+ + layout.add("method", TransformationType.INT); // Version 5+ + layout.add("secret", TransformationType.DATA); // Version 5+ + layout.add("compression", TransformationType.INT); // Version 5+ + layout.add("number of payments", TransformationType.INT); layout.add("* recipient", TransformationType.ADDRESS); layout.add("* asset ID of payment", TransformationType.LONG); @@ -77,8 +88,22 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { byte[] senderPublicKey = Serialization.deserializePublicKey(byteBuffer); int nonce = 0; + String name = null; + ArbitraryTransactionData.Method method = null; + byte[] secret = null; + ArbitraryTransactionData.Compression compression = null; + if (version >= 5) { nonce = byteBuffer.getInt(); + + name = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE); + + method = ArbitraryTransactionData.Method.valueOf(byteBuffer.getInt()); + + secret = new byte[SECRET_LENGTH]; + byteBuffer.get(secret); + + compression = ArbitraryTransactionData.Compression.valueOf(byteBuffer.getInt()); } // Always return a list of payments, even if empty @@ -90,7 +115,7 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { payments.add(PaymentTransformer.fromByteBuffer(byteBuffer)); } - int service = byteBuffer.getInt(); + ArbitraryTransactionData.Service service = ArbitraryTransactionData.Service.valueOf(byteBuffer.getInt()); // We might be receiving hash of data instead of actual raw data boolean isRaw = byteBuffer.get() != 0; @@ -124,16 +149,17 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, senderPublicKey, fee, signature); - return new ArbitraryTransactionData(baseTransactionData, version, service, nonce, size, data, dataType, chunkHashes, payments); + return new ArbitraryTransactionData(baseTransactionData, version, service, nonce, size, name, method, secret, compression, data, dataType, chunkHashes, payments); } public static int getDataLength(TransactionData transactionData) throws TransformationException { ArbitraryTransactionData arbitraryTransactionData = (ArbitraryTransactionData) transactionData; + int nameLength = Utf8.encodedLength(arbitraryTransactionData.getName()); int dataLength = (arbitraryTransactionData.getData() != null) ? arbitraryTransactionData.getData().length : 0; int chunkHashesLength = (arbitraryTransactionData.getChunkHashes() != null) ? arbitraryTransactionData.getChunkHashes().length : 0; - int length = getBaseLength(transactionData) + EXTRAS_LENGTH + dataLength + chunkHashesLength; + int length = getBaseLength(transactionData) + EXTRAS_LENGTH + nameLength + dataLength + chunkHashesLength; // Optional payments length += NUMBER_PAYMENTS_LENGTH + arbitraryTransactionData.getPayments().size() * PaymentTransformer.getDataLength(); @@ -151,6 +177,14 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { if (arbitraryTransactionData.getVersion() >= 5) { bytes.write(Ints.toByteArray(arbitraryTransactionData.getNonce())); + + Serialization.serializeSizedString(bytes, arbitraryTransactionData.getName()); + + bytes.write(Ints.toByteArray(arbitraryTransactionData.getMethod().value)); + + bytes.write(arbitraryTransactionData.getSecret()); + + bytes.write(Ints.toByteArray(arbitraryTransactionData.getCompression().value)); } List payments = arbitraryTransactionData.getPayments(); @@ -159,7 +193,7 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { for (PaymentData paymentData : payments) bytes.write(PaymentTransformer.toBytes(paymentData)); - bytes.write(Ints.toByteArray(arbitraryTransactionData.getService())); + bytes.write(Ints.toByteArray(arbitraryTransactionData.getService().value)); bytes.write((byte) (arbitraryTransactionData.getDataType() == DataType.RAW_DATA ? 1 : 0)); @@ -204,6 +238,14 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { if (arbitraryTransactionData.getVersion() >= 5) { bytes.write(Ints.toByteArray(arbitraryTransactionData.getNonce())); + + Serialization.serializeSizedString(bytes, arbitraryTransactionData.getName()); + + bytes.write(Ints.toByteArray(arbitraryTransactionData.getMethod().value)); + + bytes.write(arbitraryTransactionData.getSecret()); + + bytes.write(Ints.toByteArray(arbitraryTransactionData.getCompression().value)); } if (arbitraryTransactionData.getVersion() != 1) { @@ -214,7 +256,7 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { bytes.write(PaymentTransformer.toBytes(paymentData)); } - bytes.write(Ints.toByteArray(arbitraryTransactionData.getService())); + bytes.write(Ints.toByteArray(arbitraryTransactionData.getService().value)); bytes.write(Ints.toByteArray(arbitraryTransactionData.getData().length)); diff --git a/src/test/java/org/qortal/test/arbitrary/ArbitraryTransactionTests.java b/src/test/java/org/qortal/test/arbitrary/ArbitraryTransactionTests.java index 39204167..4d0280b6 100644 --- a/src/test/java/org/qortal/test/arbitrary/ArbitraryTransactionTests.java +++ b/src/test/java/org/qortal/test/arbitrary/ArbitraryTransactionTests.java @@ -36,10 +36,14 @@ public class ArbitraryTransactionTests extends Common { TestAccount alice = Common.getTestAccount(repository, "alice"); ArbitraryTransactionData.DataType dataType = ArbitraryTransactionData.DataType.DATA_HASH; + ArbitraryTransactionData.Service service = ArbitraryTransactionData.Service.ARBITRARY_DATA; + ArbitraryTransactionData.Method method = ArbitraryTransactionData.Method.PUT; + ArbitraryTransactionData.Compression compression = ArbitraryTransactionData.Compression.NONE; List payments = new ArrayList<>(); ArbitraryTransactionData transactionData = new ArbitraryTransactionData(TestTransaction.generateBase(alice), - 5, ArbitraryTransaction.SERVICE_ARBITRARY_DATA, 0, 0, null, dataType, null, payments); + 5, service, 0, 0, null, method, + null, compression, null, dataType, null, payments); ArbitraryTransaction transaction = (ArbitraryTransaction) Transaction.fromData(repository, transactionData); assertEquals(12, transaction.difficultyForFileSize(1)); diff --git a/src/test/java/org/qortal/test/common/transaction/ArbitraryTestTransaction.java b/src/test/java/org/qortal/test/common/transaction/ArbitraryTestTransaction.java index 9e9814f8..53cdf990 100644 --- a/src/test/java/org/qortal/test/common/transaction/ArbitraryTestTransaction.java +++ b/src/test/java/org/qortal/test/common/transaction/ArbitraryTestTransaction.java @@ -17,9 +17,13 @@ public class ArbitraryTestTransaction extends TestTransaction { public static TransactionData randomTransaction(Repository repository, PrivateKeyAccount account, boolean wantValid) throws DataException { final int version = 4; - final int service = 123; + final ArbitraryTransactionData.Service service = ArbitraryTransactionData.Service.ARBITRARY_DATA; final int nonce = 0; // Version 4 doesn't need a nonce final int size = 0; // Version 4 doesn't need a size + final String name = null; // Version 4 doesn't need a name + final ArbitraryTransactionData.Method method = ArbitraryTransactionData.Method.PUT; // Version 4 doesn't need a method + final byte[] secret = null; // Version 4 doesn't need a secret + final ArbitraryTransactionData.Compression compression = ArbitraryTransactionData.Compression.NONE; // Version 4 doesn't use compression final byte[] chunkHashes = null; // Version 4 doesn't use chunk hashes byte[] data = new byte[1024]; @@ -34,7 +38,8 @@ public class ArbitraryTestTransaction extends TestTransaction { List payments = new ArrayList<>(); payments.add(new PaymentData(recipient, assetId, amount)); - return new ArbitraryTransactionData(generateBase(account), version, service, nonce, size, data, dataType, chunkHashes, payments); + return new ArbitraryTransactionData(generateBase(account), version, service, nonce, size, name, method, + secret, compression, data, dataType, chunkHashes, payments); } }