diff --git a/src/main/java/org/qortal/transaction/CreateGroupTransaction.java b/src/main/java/org/qortal/transaction/CreateGroupTransaction.java index 42c69541..0d4cbc12 100644 --- a/src/main/java/org/qortal/transaction/CreateGroupTransaction.java +++ b/src/main/java/org/qortal/transaction/CreateGroupTransaction.java @@ -77,6 +77,16 @@ public class CreateGroupTransaction extends Transaction { if (createGroupTransactionData.getApprovalThreshold() == null) return ValidationResult.INVALID_GROUP_APPROVAL_THRESHOLD; + // Check min/max block delay values + if (createGroupTransactionData.getMinimumBlockDelay() < 0) + return ValidationResult.INVALID_GROUP_BLOCK_DELAY; + + if (createGroupTransactionData.getMaximumBlockDelay() < 1) + return ValidationResult.INVALID_GROUP_BLOCK_DELAY; + + if (createGroupTransactionData.getMaximumBlockDelay() < createGroupTransactionData.getMinimumBlockDelay()) + return ValidationResult.INVALID_GROUP_BLOCK_DELAY; + // Check group name size bounds int groupNameLength = Utf8.encodedLength(createGroupTransactionData.getGroupName()); if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) diff --git a/src/main/java/org/qortal/transaction/Transaction.java b/src/main/java/org/qortal/transaction/Transaction.java index 75e31f8c..69dd42d9 100644 --- a/src/main/java/org/qortal/transaction/Transaction.java +++ b/src/main/java/org/qortal/transaction/Transaction.java @@ -242,6 +242,7 @@ public abstract class Transaction { ACCOUNT_CANNOT_REWARD_SHARE(90), SELF_SHARE_EXISTS(91), ACCOUNT_ALREADY_EXISTS(92), + INVALID_GROUP_BLOCK_DELAY(93), NOT_YET_RELEASED(1000); public final int value; diff --git a/src/main/java/org/qortal/transaction/UpdateGroupTransaction.java b/src/main/java/org/qortal/transaction/UpdateGroupTransaction.java index e25b0b57..26b35c36 100644 --- a/src/main/java/org/qortal/transaction/UpdateGroupTransaction.java +++ b/src/main/java/org/qortal/transaction/UpdateGroupTransaction.java @@ -83,6 +83,16 @@ public class UpdateGroupTransaction extends Transaction { if (updateGroupTransactionData.getNewApprovalThreshold() == null) return ValidationResult.INVALID_GROUP_APPROVAL_THRESHOLD; + // Check min/max block delay values + if (updateGroupTransactionData.getNewMinimumBlockDelay() < 0) + return ValidationResult.INVALID_GROUP_BLOCK_DELAY; + + if (updateGroupTransactionData.getNewMaximumBlockDelay() < 1) + return ValidationResult.INVALID_GROUP_BLOCK_DELAY; + + if (updateGroupTransactionData.getNewMaximumBlockDelay() < updateGroupTransactionData.getNewMinimumBlockDelay()) + return ValidationResult.INVALID_GROUP_BLOCK_DELAY; + // Check new description size bounds int newDescriptionLength = Utf8.encodedLength(updateGroupTransactionData.getNewDescription()); if (newDescriptionLength < 1 || newDescriptionLength > Group.MAX_DESCRIPTION_SIZE) diff --git a/src/test/java/org/qortal/test/group/GroupBlockDelayTests.java b/src/test/java/org/qortal/test/group/GroupBlockDelayTests.java new file mode 100644 index 00000000..1af2857f --- /dev/null +++ b/src/test/java/org/qortal/test/group/GroupBlockDelayTests.java @@ -0,0 +1,111 @@ +package org.qortal.test.group; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.qortal.account.PrivateKeyAccount; +import org.qortal.data.transaction.CreateGroupTransactionData; +import org.qortal.data.transaction.UpdateGroupTransactionData; +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.Common; +import org.qortal.test.common.GroupUtils; +import org.qortal.test.common.TestAccount; +import org.qortal.test.common.transaction.TestTransaction; +import org.qortal.transaction.CreateGroupTransaction; +import org.qortal.transaction.Transaction; +import org.qortal.transaction.Transaction.ValidationResult; +import org.qortal.transaction.UpdateGroupTransaction; + +public class GroupBlockDelayTests extends Common { + + @Before + public void beforeTest() throws DataException { + Common.useDefaultSettings(); + } + + @After + public void afterTest() throws DataException { + Common.orphanCheck(); + } + + @Test + public void testCreateGroupBlockDelayValues() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + TestAccount alice = Common.getTestAccount(repository, "alice"); + + // Check we're starting with something valid + Transaction transaction = buildCreateGroupWithDelays(repository, alice, 10, 40); + assertEquals(ValidationResult.OK, transaction.isValid()); + + transaction = buildCreateGroupWithDelays(repository, alice, -1, 40); + assertNotSame("Negative minimum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildCreateGroupWithDelays(repository, alice, 10, -1); + assertNotSame("Negative maximum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildCreateGroupWithDelays(repository, alice, 10, 0); + assertNotSame("Zero maximum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildCreateGroupWithDelays(repository, alice, 40, 10); + assertNotSame("Maximum block delay smaller than minimum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildCreateGroupWithDelays(repository, alice, 40, 40); + assertEquals("Maximum block delay same as minimum block delay should be OK", ValidationResult.OK, transaction.isValid()); + } + } + + private CreateGroupTransaction buildCreateGroupWithDelays(Repository repository, PrivateKeyAccount account, int minimumBlockDelay, int maximumBlockDelay) throws DataException { + String owner = account.getAddress(); + String groupName = "test group"; + String description = "random test group"; + final boolean isOpen = false; + ApprovalThreshold approvalThreshold = ApprovalThreshold.PCT40; + + CreateGroupTransactionData transactionData = new CreateGroupTransactionData(TestTransaction.generateBase(account), owner, groupName, description, isOpen, approvalThreshold, minimumBlockDelay, maximumBlockDelay); + return new CreateGroupTransaction(repository, transactionData); + } + + @Test + public void testUpdateGroupBlockDelayValues() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + TestAccount alice = Common.getTestAccount(repository, "alice"); + + int groupId = GroupUtils.createGroup(repository, "alice", "test", true, ApprovalThreshold.ONE, 10, 40); + + // Check we're starting with something valid + Transaction transaction = buildUpdateGroupWithDelays(repository, alice, groupId, 10, 40); + assertEquals(ValidationResult.OK, transaction.isValid()); + + transaction = buildUpdateGroupWithDelays(repository, alice, groupId, -1, 40); + assertNotSame("Negative minimum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildUpdateGroupWithDelays(repository, alice, groupId, 10, -1); + assertNotSame("Negative maximum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildUpdateGroupWithDelays(repository, alice, groupId, 10, 0); + assertNotSame("Zero maximum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildUpdateGroupWithDelays(repository, alice, groupId, 40, 10); + assertNotSame("Maximum block delay smaller than minimum block delay should be invalid", ValidationResult.OK, transaction.isValid()); + + transaction = buildUpdateGroupWithDelays(repository, alice, groupId, 40, 40); + assertEquals("Maximum block delay same as minimum block delay should be OK", ValidationResult.OK, transaction.isValid()); + } + } + + private UpdateGroupTransaction buildUpdateGroupWithDelays(Repository repository, PrivateKeyAccount account, int groupId, int newMinimumBlockDelay, int newMaximumBlockDelay) throws DataException { + String newOwner = account.getAddress(); + String newDescription = "random test group"; + final boolean newIsOpen = false; + ApprovalThreshold newApprovalThreshold = ApprovalThreshold.PCT40; + + UpdateGroupTransactionData transactionData = new UpdateGroupTransactionData(TestTransaction.generateBase(account), groupId, newOwner, newDescription, newIsOpen, newApprovalThreshold, newMinimumBlockDelay, newMaximumBlockDelay); + return new UpdateGroupTransaction(repository, transactionData); + } + +} diff --git a/src/test/resources/test-settings-v2.json b/src/test/resources/test-settings-v2.json index 31fc2672..57eb22a5 100644 --- a/src/test/resources/test-settings-v2.json +++ b/src/test/resources/test-settings-v2.json @@ -2,5 +2,6 @@ "restrictedApi": false, "blockchainConfig": "src/test/resources/test-chain-v2.json", "wipeUnconfirmedOnStart": false, + "testNtpOffset": 0, "minPeers": 0 }