forked from Qortal/qortal
Allow MESSAGE transactions to have no recipient.
This allows on-chain messages to a group, including NO_GROUP / groupID zero. No-recipient messages cannot have an amount - where would it go? Changed MESSAGE serialization layout to add boolean indicating whether recipient is present. Changed MESSAGE serialization layout so assetID is after amount, and only present if amount is non-zero. Changed DB table structures to cover above. Added unit tests to cover above.
This commit is contained in:
parent
f6ed3388a4
commit
24eb7c6933
@ -815,9 +815,10 @@ public class CrossChainResource {
|
||||
|
||||
Long fee = null;
|
||||
long amount = 0L;
|
||||
Long assetId = null; // no assetId as amount is zero
|
||||
|
||||
BaseTransactionData baseTransactionData = new BaseTransactionData(txTimestamp, Group.NO_GROUP, lastReference, senderPublicKey, fee, null);
|
||||
TransactionData messageTransactionData = new MessageTransactionData(baseTransactionData, 4, atAddress, Asset.QORT, amount, messageData, false, false);
|
||||
TransactionData messageTransactionData = new MessageTransactionData(baseTransactionData, 4, atAddress, amount, assetId, messageData, false, false);
|
||||
|
||||
MessageTransaction messageTransaction = new MessageTransaction(repository, messageTransactionData);
|
||||
|
||||
|
@ -5,7 +5,6 @@ import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.transaction.Transaction.TransactionType;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@ -16,14 +15,24 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
public class MessageTransactionData extends TransactionData {
|
||||
|
||||
// Properties
|
||||
|
||||
private byte[] senderPublicKey;
|
||||
|
||||
private int version;
|
||||
|
||||
// Not always present
|
||||
private String recipient;
|
||||
private Long assetId;
|
||||
|
||||
@XmlJavaTypeAdapter(value = org.qortal.api.AmountTypeAdapter.class)
|
||||
private long amount;
|
||||
|
||||
// Not present if amount is zero
|
||||
private Long assetId;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
private boolean isText;
|
||||
|
||||
private boolean isEncrypted;
|
||||
|
||||
// Constructors
|
||||
@ -38,19 +47,14 @@ public class MessageTransactionData extends TransactionData {
|
||||
}
|
||||
|
||||
public MessageTransactionData(BaseTransactionData baseTransactionData,
|
||||
int version, String recipient, Long assetId, long amount, byte[] data, boolean isText, boolean isEncrypted) {
|
||||
int version, String recipient, long amount, Long assetId, byte[] data, boolean isText, boolean isEncrypted) {
|
||||
super(TransactionType.MESSAGE, baseTransactionData);
|
||||
|
||||
this.senderPublicKey = baseTransactionData.creatorPublicKey;
|
||||
this.version = version;
|
||||
this.recipient = recipient;
|
||||
|
||||
if (assetId != null)
|
||||
this.assetId = assetId;
|
||||
else
|
||||
this.assetId = Asset.QORT;
|
||||
|
||||
this.amount = amount;
|
||||
this.assetId = assetId;
|
||||
this.data = data;
|
||||
this.isText = isText;
|
||||
this.isEncrypted = isEncrypted;
|
||||
@ -70,23 +74,23 @@ public class MessageTransactionData extends TransactionData {
|
||||
return this.recipient;
|
||||
}
|
||||
|
||||
public Long getAssetId() {
|
||||
return this.assetId;
|
||||
}
|
||||
|
||||
public long getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Long getAssetId() {
|
||||
return this.assetId;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public boolean getIsText() {
|
||||
public boolean isText() {
|
||||
return this.isText;
|
||||
}
|
||||
|
||||
public boolean getIsEncrypted() {
|
||||
public boolean isEncrypted() {
|
||||
return this.isEncrypted;
|
||||
}
|
||||
|
||||
|
@ -269,8 +269,8 @@ public class HSQLDBDatabaseUpdates {
|
||||
case 6:
|
||||
// Message Transactions
|
||||
stmt.execute("CREATE TABLE MessageTransactions (signature Signature, version TINYINT NOT NULL, "
|
||||
+ "sender QortalPublicKey NOT NULL, recipient QortalAddress NOT NULL, "
|
||||
+ "is_text BOOLEAN NOT NULL, is_encrypted BOOLEAN NOT NULL, amount QortalAmount NOT NULL, asset_id AssetID NOT NULL, data MessageData NOT NULL, "
|
||||
+ "sender QortalPublicKey NOT NULL, recipient QortalAddress, amount QortalAmount NOT NULL, asset_id AssetID, "
|
||||
+ "is_text BOOLEAN NOT NULL, is_encrypted BOOLEAN NOT NULL, data MessageData NOT NULL, "
|
||||
+ TRANSACTION_KEYS + ")");
|
||||
break;
|
||||
|
||||
|
@ -36,7 +36,7 @@ public class HSQLDBMessageTransactionRepository extends HSQLDBTransactionReposit
|
||||
|
||||
byte[] data = resultSet.getBytes(7);
|
||||
|
||||
return new MessageTransactionData(baseTransactionData, version, recipient, assetId, amount, data, isText, isEncrypted);
|
||||
return new MessageTransactionData(baseTransactionData, version, recipient, amount, assetId, data, isText, isEncrypted);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch message transaction from repository", e);
|
||||
}
|
||||
@ -50,7 +50,7 @@ public class HSQLDBMessageTransactionRepository extends HSQLDBTransactionReposit
|
||||
|
||||
saveHelper.bind("signature", messageTransactionData.getSignature()).bind("version", messageTransactionData.getVersion())
|
||||
.bind("sender", messageTransactionData.getSenderPublicKey()).bind("recipient", messageTransactionData.getRecipient())
|
||||
.bind("is_text", messageTransactionData.getIsText()).bind("is_encrypted", messageTransactionData.getIsEncrypted())
|
||||
.bind("is_text", messageTransactionData.isText()).bind("is_encrypted", messageTransactionData.isEncrypted())
|
||||
.bind("amount", messageTransactionData.getAmount()).bind("asset_id", messageTransactionData.getAssetId())
|
||||
.bind("data", messageTransactionData.getData());
|
||||
|
||||
|
@ -4,6 +4,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.MessageTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -13,14 +14,17 @@ import org.qortal.repository.Repository;
|
||||
|
||||
public class MessageTransaction extends Transaction {
|
||||
|
||||
// Useful constants
|
||||
|
||||
public static final int MAX_DATA_SIZE = 4000;
|
||||
|
||||
// Properties
|
||||
|
||||
private MessageTransactionData messageTransactionData;
|
||||
|
||||
/** Cached, lazy-instantiated payment data. Use {@link #getPaymentData()} instead! */
|
||||
private PaymentData paymentData = null;
|
||||
|
||||
// Other useful constants
|
||||
public static final int MAX_DATA_SIZE = 4000;
|
||||
private static final boolean isZeroAmountValid = true;
|
||||
|
||||
// Constructors
|
||||
|
||||
@ -34,6 +38,9 @@ public class MessageTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public List<String> getRecipientAddresses() throws DataException {
|
||||
if (this.messageTransactionData.getRecipient() == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
return Collections.singletonList(this.messageTransactionData.getRecipient());
|
||||
}
|
||||
|
||||
@ -62,42 +69,80 @@ public class MessageTransaction extends Transaction {
|
||||
if (this.messageTransactionData.getData().length < 1 || this.messageTransactionData.getData().length > MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// If message has no recipient then it cannot have a payment
|
||||
if (this.messageTransactionData.getRecipient() == null && this.messageTransactionData.getAmount() != 0)
|
||||
return ValidationResult.INVALID_AMOUNT;
|
||||
|
||||
// If message has no payment then we only need to do a simple balance check for fee
|
||||
if (this.messageTransactionData.getAmount() == 0) {
|
||||
if (getSender().getConfirmedBalance(Asset.QORT) < this.messageTransactionData.getFee())
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
// Wrap and delegate final payment checks to Payment class
|
||||
return new Payment(this.repository).isValid(this.messageTransactionData.getSenderPublicKey(), getPaymentData(), this.messageTransactionData.getFee(),
|
||||
isZeroAmountValid);
|
||||
return new Payment(this.repository).isValid(this.messageTransactionData.getSenderPublicKey(), getPaymentData(),
|
||||
this.messageTransactionData.getFee(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// If we have no amount then we can always process
|
||||
if (this.messageTransactionData.getAmount() == 0L)
|
||||
return ValidationResult.OK;
|
||||
|
||||
// Wrap and delegate final processable checks to Payment class
|
||||
return new Payment(this.repository).isProcessable(this.messageTransactionData.getSenderPublicKey(), getPaymentData(), this.messageTransactionData.getFee(),
|
||||
isZeroAmountValid);
|
||||
return new Payment(this.repository).isProcessable(this.messageTransactionData.getSenderPublicKey(),
|
||||
getPaymentData(), this.messageTransactionData.getFee(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// If we have no amount then there's nothing to do
|
||||
if (this.messageTransactionData.getAmount() == 0L)
|
||||
return;
|
||||
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(this.messageTransactionData.getSenderPublicKey(), getPaymentData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// If we have no amount then we only need to process sender's reference and fees
|
||||
if (this.messageTransactionData.getAmount() == 0L) {
|
||||
super.processReferencesAndFees();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrap and delegate references processing to Payment class. Only update recipient's last reference if transferring QORT.
|
||||
new Payment(this.repository).processReferencesAndFees(this.messageTransactionData.getSenderPublicKey(), getPaymentData(), this.messageTransactionData.getFee(),
|
||||
this.messageTransactionData.getSignature(), false);
|
||||
new Payment(this.repository).processReferencesAndFees(this.messageTransactionData.getSenderPublicKey(),
|
||||
getPaymentData(), this.messageTransactionData.getFee(), this.messageTransactionData.getSignature(),
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// If we have no amount then there's nothing to do
|
||||
if (this.messageTransactionData.getAmount() == 0L)
|
||||
return;
|
||||
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).orphan(this.messageTransactionData.getSenderPublicKey(), getPaymentData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// If we have no amount then we only need to orphan sender's reference and fees
|
||||
if (this.messageTransactionData.getAmount() == 0L) {
|
||||
super.orphanReferencesAndFees();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrap and delegate references processing to Payment class. Only revert recipient's last reference if transferring QORT.
|
||||
new Payment(this.repository).orphanReferencesAndFees(this.messageTransactionData.getSenderPublicKey(), getPaymentData(), this.messageTransactionData.getFee(),
|
||||
this.messageTransactionData.getSignature(), this.messageTransactionData.getReference(), false);
|
||||
new Payment(this.repository).orphanReferencesAndFees(this.messageTransactionData.getSenderPublicKey(),
|
||||
getPaymentData(), this.messageTransactionData.getFee(), this.messageTransactionData.getSignature(),
|
||||
this.messageTransactionData.getReference(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,12 +19,13 @@ import com.google.common.primitives.Longs;
|
||||
public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
// Property lengths
|
||||
private static final int HAS_RECIPIENT_LENGTH = BOOLEAN_LENGTH;
|
||||
private static final int RECIPIENT_LENGTH = ADDRESS_LENGTH;
|
||||
private static final int DATA_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int IS_TEXT_LENGTH = BOOLEAN_LENGTH;
|
||||
private static final int IS_ENCRYPTED_LENGTH = BOOLEAN_LENGTH;
|
||||
|
||||
private static final int EXTRAS_LENGTH = RECIPIENT_LENGTH + ASSET_ID_LENGTH + AMOUNT_LENGTH + DATA_SIZE_LENGTH + IS_ENCRYPTED_LENGTH + IS_TEXT_LENGTH;
|
||||
private static final int EXTRAS_LENGTH = HAS_RECIPIENT_LENGTH + AMOUNT_LENGTH + DATA_SIZE_LENGTH + IS_ENCRYPTED_LENGTH + IS_TEXT_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
@ -35,9 +36,10 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
layout.add("transaction's groupID", TransformationType.INT);
|
||||
layout.add("reference", TransformationType.SIGNATURE);
|
||||
layout.add("sender's public key", TransformationType.PUBLIC_KEY);
|
||||
layout.add("recipient", TransformationType.ADDRESS);
|
||||
layout.add("asset ID of payment", TransformationType.LONG);
|
||||
layout.add("has recipient?", TransformationType.BOOLEAN);
|
||||
layout.add("? recipient", TransformationType.ADDRESS);
|
||||
layout.add("payment (can be zero)", TransformationType.AMOUNT);
|
||||
layout.add("asset ID of payment (if payment not zero)", TransformationType.LONG);
|
||||
layout.add("message length", TransformationType.INT);
|
||||
layout.add("message", TransformationType.DATA);
|
||||
layout.add("is message encrypted?", TransformationType.BOOLEAN);
|
||||
@ -58,12 +60,13 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
byte[] senderPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
long assetId = byteBuffer.getLong();
|
||||
boolean hasRecipient = byteBuffer.get() != 0;
|
||||
String recipient = hasRecipient ? Serialization.deserializeAddress(byteBuffer) : null;
|
||||
|
||||
long amount = byteBuffer.getLong();
|
||||
|
||||
Long assetId = amount != 0 ? byteBuffer.getLong() : null;
|
||||
|
||||
int dataSize = byteBuffer.getInt();
|
||||
// Don't allow invalid dataSize here to avoid run-time issues
|
||||
if (dataSize > MessageTransaction.MAX_DATA_SIZE)
|
||||
@ -83,13 +86,21 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, senderPublicKey, fee, signature);
|
||||
|
||||
return new MessageTransactionData(baseTransactionData, version, recipient, assetId, amount, data, isText, isEncrypted);
|
||||
return new MessageTransactionData(baseTransactionData, version, recipient, amount, assetId, data, isText, isEncrypted);
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
MessageTransactionData messageTransactionData = (MessageTransactionData) transactionData;
|
||||
|
||||
return getBaseLength(transactionData) + EXTRAS_LENGTH + messageTransactionData.getData().length;
|
||||
int dataLength = getBaseLength(transactionData) + EXTRAS_LENGTH + messageTransactionData.getData().length;
|
||||
|
||||
if (messageTransactionData.getRecipient() != null)
|
||||
dataLength += RECIPIENT_LENGTH;
|
||||
|
||||
if (messageTransactionData.getAmount() != 0)
|
||||
dataLength += ASSET_ID_LENGTH;
|
||||
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
@ -100,19 +111,25 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
transformCommonBytes(transactionData, bytes);
|
||||
|
||||
Serialization.serializeAddress(bytes, messageTransactionData.getRecipient());
|
||||
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getAssetId()));
|
||||
if (messageTransactionData.getRecipient() != null) {
|
||||
bytes.write((byte) 1);
|
||||
Serialization.serializeAddress(bytes, messageTransactionData.getRecipient());
|
||||
} else {
|
||||
bytes.write((byte) 0);
|
||||
}
|
||||
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getAmount()));
|
||||
|
||||
if (messageTransactionData.getAmount() != 0)
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getAssetId()));
|
||||
|
||||
bytes.write(Ints.toByteArray(messageTransactionData.getData().length));
|
||||
|
||||
bytes.write(messageTransactionData.getData());
|
||||
|
||||
bytes.write((byte) (messageTransactionData.getIsEncrypted() ? 1 : 0));
|
||||
bytes.write((byte) (messageTransactionData.isEncrypted() ? 1 : 0));
|
||||
|
||||
bytes.write((byte) (messageTransactionData.getIsText() ? 1 : 0));
|
||||
bytes.write((byte) (messageTransactionData.isText() ? 1 : 0));
|
||||
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getFee()));
|
||||
|
||||
|
154
src/test/java/org/qortal/test/MessageTests.java
Normal file
154
src/test/java/org/qortal/test/MessageTests.java
Normal file
@ -0,0 +1,154 @@
|
||||
package org.qortal.test;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.data.transaction.MessageTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.group.Group;
|
||||
import org.qortal.group.Group.ApprovalThreshold;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.test.common.BlockUtils;
|
||||
import org.qortal.test.common.Common;
|
||||
import org.qortal.test.common.GroupUtils;
|
||||
import org.qortal.test.common.TestAccount;
|
||||
import org.qortal.test.common.TransactionUtils;
|
||||
import org.qortal.test.common.transaction.TestTransaction;
|
||||
import org.qortal.transaction.MessageTransaction;
|
||||
import org.qortal.transaction.Transaction;
|
||||
import org.qortal.transaction.Transaction.TransactionType;
|
||||
import org.qortal.transaction.Transaction.ValidationResult;
|
||||
import org.qortal.transform.TransformationException;
|
||||
import org.qortal.transform.transaction.MessageTransactionTransformer;
|
||||
import org.qortal.transform.transaction.TransactionTransformer;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class MessageTests extends Common {
|
||||
|
||||
private static final int version = 3;
|
||||
private static final String recipient = Common.getTestAccount(null, "bob").getAddress();
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useDefaultSettings();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws DataException {
|
||||
Common.orphanCheck();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validityTests() throws DataException {
|
||||
// with recipient, with amount
|
||||
assertTrue(isValid(Group.NO_GROUP, recipient, 123L, Asset.QORT));
|
||||
|
||||
// with recipient, no amount
|
||||
assertTrue(isValid(Group.NO_GROUP, recipient, 0L, null));
|
||||
|
||||
// no recipient (message to group), no amount
|
||||
assertTrue(isValid(Group.NO_GROUP, null, 0L, null));
|
||||
|
||||
// can't have amount if no recipient!
|
||||
assertFalse(isValid(Group.NO_GROUP, null, 123L, Asset.QORT));
|
||||
|
||||
// Alice is part of group 1
|
||||
assertTrue(isValid(1, null, 0L, null));
|
||||
|
||||
int newGroupId;
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
newGroupId = GroupUtils.createGroup(repository, "chloe", "non-alice-group", false, ApprovalThreshold.ONE, 10, 1440);
|
||||
}
|
||||
|
||||
// Alice is not part of new group
|
||||
assertFalse(isValid(newGroupId, null, 0L, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withRecipentNoAmount() throws DataException {
|
||||
testMessage(Group.NO_GROUP, recipient, 0L, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withRecipentWithAmount() throws DataException {
|
||||
testMessage(Group.NO_GROUP, recipient, 123L, Asset.QORT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRecipentNoAmount() throws DataException {
|
||||
testMessage(Group.NO_GROUP, null, 0L, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRecipentNoAmountWithGroup() throws DataException {
|
||||
testMessage(1, null, 0L, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializationTests() throws DataException, TransformationException {
|
||||
// with recipient, with amount
|
||||
testSerialization(recipient, 123L, Asset.QORT);
|
||||
|
||||
// with recipient, no amount
|
||||
testSerialization(recipient, 0L, null);
|
||||
|
||||
// no recipient (message to group), no amount
|
||||
testSerialization(null, 0L, null);
|
||||
}
|
||||
|
||||
private boolean isValid(int txGroupId, String recipient, long amount, Long assetId) throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TestAccount alice = Common.getTestAccount(repository, "alice");
|
||||
|
||||
MessageTransactionData transactionData = new MessageTransactionData(TestTransaction.generateBase(alice, txGroupId),
|
||||
version, recipient, amount, assetId, new byte[1], false, false);
|
||||
|
||||
Transaction transaction = new MessageTransaction(repository, transactionData);
|
||||
|
||||
return transaction.isValidUnconfirmed() == ValidationResult.OK;
|
||||
}
|
||||
}
|
||||
|
||||
private void testMessage(int txGroupId, String recipient, long amount, Long assetId) throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TestAccount alice = Common.getTestAccount(repository, "alice");
|
||||
|
||||
MessageTransactionData transactionData = new MessageTransactionData(TestTransaction.generateBase(alice, txGroupId),
|
||||
version, recipient, amount, assetId, new byte[1], false, false);
|
||||
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
BlockUtils.orphanLastBlock(repository);
|
||||
}
|
||||
}
|
||||
|
||||
private void testSerialization(String recipient, long amount, Long assetId) throws DataException, TransformationException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TestAccount alice = Common.getTestAccount(repository, "alice");
|
||||
|
||||
MessageTransactionData expectedTransactionData = new MessageTransactionData(TestTransaction.generateBase(alice),
|
||||
version, recipient, amount, assetId, new byte[1], false, false);
|
||||
|
||||
Transaction transaction = new MessageTransaction(repository, expectedTransactionData);
|
||||
transaction.sign(alice);
|
||||
|
||||
MessageTransactionTransformer.getDataLength(expectedTransactionData);
|
||||
byte[] transactionBytes = MessageTransactionTransformer.toBytes(expectedTransactionData);
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(transactionBytes);
|
||||
assertEquals(TransactionType.MESSAGE, transactionData.getType());
|
||||
|
||||
MessageTransactionData actualTransactionData = (MessageTransactionData) transactionData;
|
||||
|
||||
assertEquals(expectedTransactionData.getRecipient(), actualTransactionData.getRecipient());
|
||||
assertEquals(expectedTransactionData.getAmount(), actualTransactionData.getAmount());
|
||||
assertEquals(expectedTransactionData.getAssetId(), actualTransactionData.getAssetId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -474,9 +474,10 @@ public class AtTests extends Common {
|
||||
|
||||
Long fee = null;
|
||||
long amount = 0;
|
||||
Long assetId = null; // because amount is zero
|
||||
|
||||
BaseTransactionData baseTransactionData = new BaseTransactionData(txTimestamp, Group.NO_GROUP, lastReference, sender.getPublicKey(), fee, null);
|
||||
TransactionData messageTransactionData = new MessageTransactionData(baseTransactionData, 4, recipient, Asset.QORT, amount, data, false, false);
|
||||
TransactionData messageTransactionData = new MessageTransactionData(baseTransactionData, 4, recipient, amount, assetId, data, false, false);
|
||||
|
||||
MessageTransaction messageTransaction = new MessageTransaction(repository, messageTransactionData);
|
||||
|
||||
|
@ -19,7 +19,7 @@ public class MessageTestTransaction extends TestTransaction {
|
||||
final boolean isText = true;
|
||||
final boolean isEncrypted = false;
|
||||
|
||||
return new MessageTransactionData(generateBase(account), version, recipient, assetId, amount, data, isText, isEncrypted);
|
||||
return new MessageTransactionData(generateBase(account), version, recipient, amount, assetId, data, isText, isEncrypted);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,8 +12,12 @@ public abstract class TestTransaction {
|
||||
|
||||
protected static final Random random = new Random();
|
||||
|
||||
public static BaseTransactionData generateBase(PrivateKeyAccount account, int txGroupId) throws DataException {
|
||||
return new BaseTransactionData(System.currentTimeMillis(), txGroupId, account.getLastReference(), account.getPublicKey(), BlockChain.getInstance().getUnitFee(), null);
|
||||
}
|
||||
|
||||
public static BaseTransactionData generateBase(PrivateKeyAccount account) throws DataException {
|
||||
return new BaseTransactionData(System.currentTimeMillis(), Group.NO_GROUP, account.getLastReference(), account.getPublicKey(), BlockChain.getInstance().getUnitFee(), null);
|
||||
return generateBase(account, Group.NO_GROUP);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user