mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-11 09:45:50 +00:00
added capabilities for groups with null ownership including banning and kicking members and member ban cancellations; enforcing group approval thresholds to invites and invite cancellations; the established add and remove admin capabilities were used as guidance for this implementation; this was added as a hardfork to preserve group transactions from previous blocks
This commit is contained in:
parent
bdbbd0152f
commit
a300ac2393
@ -90,7 +90,8 @@ public class BlockChain {
|
||||
groupMemberCheckHeight,
|
||||
fixBatchRewardHeight,
|
||||
adminsReplaceFoundersHeight,
|
||||
onlineValidationFailSafeHeight
|
||||
onlineValidationFailSafeHeight,
|
||||
nullGroupMembershipHeight
|
||||
}
|
||||
|
||||
// Custom transaction fees
|
||||
@ -672,6 +673,10 @@ public class BlockChain {
|
||||
return this.featureTriggers.get(FeatureTrigger.onlineValidationFailSafeHeight.name()).intValue();
|
||||
}
|
||||
|
||||
public int getNullGroupMembershipHeight() {
|
||||
return this.featureTriggers.get(FeatureTrigger.nullGroupMembershipHeight.name()).intValue();
|
||||
}
|
||||
|
||||
// More complex getters for aspects that change by height or timestamp
|
||||
|
||||
public long getRewardAtHeight(int ourHeight) {
|
||||
|
@ -24,7 +24,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
public GroupData fromGroupId(int groupId) throws DataException {
|
||||
String sql = "SELECT group_name, owner, description, created_when, updated_when, reference, is_open, "
|
||||
+ "approval_threshold, min_block_delay, max_block_delay, creation_group_id, reduced_group_name "
|
||||
+ "FROM Groups WHERE group_id = ?";
|
||||
+ "FROM `Groups` WHERE group_id = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, groupId)) {
|
||||
if (resultSet == null)
|
||||
@ -62,7 +62,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
public GroupData fromGroupName(String groupName) throws DataException {
|
||||
String sql = "SELECT group_id, owner, description, created_when, updated_when, reference, is_open, "
|
||||
+ "approval_threshold, min_block_delay, max_block_delay, creation_group_id, reduced_group_name "
|
||||
+ "FROM Groups WHERE group_name = ?";
|
||||
+ "FROM `Groups` WHERE group_name = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, groupName)) {
|
||||
if (resultSet == null)
|
||||
@ -99,7 +99,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
@Override
|
||||
public boolean groupExists(int groupId) throws DataException {
|
||||
try {
|
||||
return this.repository.exists("Groups", "group_id = ?", groupId);
|
||||
return this.repository.exists("`Groups`", "group_id = ?", groupId);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to check for group in repository", e);
|
||||
}
|
||||
@ -108,7 +108,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
@Override
|
||||
public boolean groupExists(String groupName) throws DataException {
|
||||
try {
|
||||
return this.repository.exists("Groups", "group_name = ?", groupName);
|
||||
return this.repository.exists("`Groups`", "group_name = ?", groupName);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to check for group in repository", e);
|
||||
}
|
||||
@ -117,7 +117,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
@Override
|
||||
public boolean reducedGroupNameExists(String reducedGroupName) throws DataException {
|
||||
try {
|
||||
return this.repository.exists("Groups", "reduced_group_name = ?", reducedGroupName);
|
||||
return this.repository.exists("`Groups`", "reduced_group_name = ?", reducedGroupName);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to check for reduced group name in repository", e);
|
||||
}
|
||||
@ -129,7 +129,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
sql.append("SELECT group_id, owner, group_name, description, created_when, updated_when, reference, is_open, "
|
||||
+ "approval_threshold, min_block_delay, max_block_delay, creation_group_id, reduced_group_name "
|
||||
+ "FROM Groups ORDER BY group_name");
|
||||
+ "FROM `Groups` ORDER BY group_name");
|
||||
|
||||
if (reverse != null && reverse)
|
||||
sql.append(" DESC");
|
||||
@ -181,7 +181,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
sql.append("SELECT group_id, group_name, description, created_when, updated_when, reference, is_open, "
|
||||
+ "approval_threshold, min_block_delay, max_block_delay, creation_group_id, reduced_group_name "
|
||||
+ "FROM Groups WHERE owner = ? ORDER BY group_name");
|
||||
+ "FROM `Groups` WHERE owner = ? ORDER BY group_name");
|
||||
|
||||
if (reverse != null && reverse)
|
||||
sql.append(" DESC");
|
||||
@ -231,7 +231,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
StringBuilder sql = new StringBuilder(512);
|
||||
|
||||
sql.append("SELECT group_id, owner, group_name, description, created_when, updated_when, reference, is_open, "
|
||||
+ "approval_threshold, min_block_delay, max_block_delay, creation_group_id, reduced_group_name, admin FROM Groups "
|
||||
+ "approval_threshold, min_block_delay, max_block_delay, creation_group_id, reduced_group_name, admin FROM `Groups` "
|
||||
+ "JOIN GroupMembers USING (group_id) "
|
||||
+ "LEFT OUTER JOIN GroupAdmins ON GroupAdmins.group_id = GroupMembers.group_id AND GroupAdmins.admin = GroupMembers.address "
|
||||
+ "WHERE address = ? ORDER BY group_name");
|
||||
@ -289,7 +289,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
@Override
|
||||
public void save(GroupData groupData) throws DataException {
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("Groups");
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("`Groups`");
|
||||
|
||||
saveHelper.bind("group_id", groupData.getGroupId()).bind("owner", groupData.getOwner()).bind("group_name", groupData.getGroupName())
|
||||
.bind("description", groupData.getDescription()).bind("created_when", groupData.getCreated()).bind("updated_when", groupData.getUpdated())
|
||||
@ -302,7 +302,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
if (groupData.getGroupId() == null) {
|
||||
// Fetch new groupId
|
||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id FROM Groups WHERE reference = ?", groupData.getReference())) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id FROM `Groups` WHERE reference = ?", groupData.getReference())) {
|
||||
if (resultSet == null)
|
||||
throw new DataException("Unable to fetch new group ID from repository");
|
||||
|
||||
@ -318,7 +318,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
public void delete(int groupId) throws DataException {
|
||||
try {
|
||||
// Remove group
|
||||
this.repository.delete("Groups", "group_id = ?", groupId);
|
||||
this.repository.delete("`Groups`", "group_id = ?", groupId);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete group info from repository", e);
|
||||
}
|
||||
@ -328,7 +328,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
public void delete(String groupName) throws DataException {
|
||||
try {
|
||||
// Remove group
|
||||
this.repository.delete("Groups", "group_name = ?", groupName);
|
||||
this.repository.delete("`Groups`", "group_name = ?", groupName);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete group info from repository", e);
|
||||
}
|
||||
@ -338,7 +338,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
@Override
|
||||
public String getOwner(int groupId) throws DataException {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT owner FROM Groups WHERE group_id = ?", groupId)) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT owner FROM `Groups` WHERE group_id = ?", groupId)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.transaction;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.group.GroupData;
|
||||
import org.qortal.data.transaction.CancelGroupBanTransactionData;
|
||||
@ -12,6 +13,7 @@ import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CancelGroupBanTransaction extends Transaction {
|
||||
|
||||
@ -70,9 +72,26 @@ public class CancelGroupBanTransaction extends Transaction {
|
||||
if (!this.repository.getGroupRepository().adminExists(groupId, admin.getAddress()))
|
||||
return ValidationResult.NOT_GROUP_ADMIN;
|
||||
|
||||
// Can't unban if not group's current owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
if( this.repository.getBlockRepository().getBlockchainHeight() < BlockChain.getInstance().getNullGroupMembershipHeight() ) {
|
||||
// Can't cancel ban if not group's current owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
}
|
||||
// if( this.repository.getBlockRepository().getBlockchainHeight() >= BlockChain.getInstance().getNullGroupMembershipHeight() )
|
||||
else {
|
||||
String groupOwner = this.repository.getGroupRepository().getOwner(groupId);
|
||||
boolean groupOwnedByNullAccount = Objects.equals(groupOwner, Group.NULL_OWNER_ADDRESS);
|
||||
|
||||
// if null ownership group, then check for admin approval
|
||||
if(groupOwnedByNullAccount ) {
|
||||
// Require approval if transaction relates to a group owned by the null account
|
||||
if (!this.needsGroupApproval())
|
||||
return ValidationResult.GROUP_APPROVAL_REQUIRED;
|
||||
}
|
||||
// Can't cancel ban if not group's current owner
|
||||
else if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
}
|
||||
|
||||
Account member = getMember();
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.transaction;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.group.GroupData;
|
||||
import org.qortal.data.transaction.CancelGroupInviteTransactionData;
|
||||
@ -12,6 +13,7 @@ import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CancelGroupInviteTransaction extends Transaction {
|
||||
|
||||
@ -80,6 +82,16 @@ public class CancelGroupInviteTransaction extends Transaction {
|
||||
if (admin.getConfirmedBalance(Asset.QORT) < this.cancelGroupInviteTransactionData.getFee())
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
// if null ownership group, then check for admin approval
|
||||
if( this.repository.getBlockRepository().getBlockchainHeight() >= BlockChain.getInstance().getNullGroupMembershipHeight() ) {
|
||||
String groupOwner = this.repository.getGroupRepository().getOwner(groupId);
|
||||
boolean groupOwnedByNullAccount = Objects.equals(groupOwner, Group.NULL_OWNER_ADDRESS);
|
||||
|
||||
// Require approval if transaction relates to a group owned by the null account
|
||||
if (groupOwnedByNullAccount && !this.needsGroupApproval())
|
||||
return ValidationResult.GROUP_APPROVAL_REQUIRED;
|
||||
}
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.transaction;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.group.GroupData;
|
||||
import org.qortal.data.transaction.GroupBanTransactionData;
|
||||
@ -12,6 +13,7 @@ import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class GroupBanTransaction extends Transaction {
|
||||
|
||||
@ -70,9 +72,25 @@ public class GroupBanTransaction extends Transaction {
|
||||
if (!this.repository.getGroupRepository().adminExists(groupId, admin.getAddress()))
|
||||
return ValidationResult.NOT_GROUP_ADMIN;
|
||||
|
||||
// Can't ban if not group's current owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
if( this.repository.getBlockRepository().getBlockchainHeight() < BlockChain.getInstance().getNullGroupMembershipHeight() ) {
|
||||
// Can't ban if not group's current owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
}
|
||||
// if( this.repository.getBlockRepository().getBlockchainHeight() >= BlockChain.getInstance().getNullGroupMembershipHeight() )
|
||||
else {
|
||||
String groupOwner = this.repository.getGroupRepository().getOwner(groupId);
|
||||
boolean groupOwnedByNullAccount = Objects.equals(groupOwner, Group.NULL_OWNER_ADDRESS);
|
||||
|
||||
// if null ownership group, then check for admin approval
|
||||
if(groupOwnedByNullAccount ) {
|
||||
// Require approval if transaction relates to a group owned by the null account
|
||||
if (!this.needsGroupApproval())
|
||||
return ValidationResult.GROUP_APPROVAL_REQUIRED;
|
||||
}
|
||||
else if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
}
|
||||
|
||||
Account offender = getOffender();
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.transaction;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.transaction.GroupInviteTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -11,6 +12,7 @@ import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class GroupInviteTransaction extends Transaction {
|
||||
|
||||
@ -85,6 +87,16 @@ public class GroupInviteTransaction extends Transaction {
|
||||
if (admin.getConfirmedBalance(Asset.QORT) < this.groupInviteTransactionData.getFee())
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
// if null ownership group, then check for admin approval
|
||||
if( this.repository.getBlockRepository().getBlockchainHeight() >= BlockChain.getInstance().getNullGroupMembershipHeight() ) {
|
||||
String groupOwner = this.repository.getGroupRepository().getOwner(groupId);
|
||||
boolean groupOwnedByNullAccount = Objects.equals(groupOwner, Group.NULL_OWNER_ADDRESS);
|
||||
|
||||
// Require approval if transaction relates to a group owned by the null account
|
||||
if (groupOwnedByNullAccount && !this.needsGroupApproval())
|
||||
return ValidationResult.GROUP_APPROVAL_REQUIRED;
|
||||
}
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package org.qortal.transaction;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.group.GroupData;
|
||||
import org.qortal.data.transaction.GroupKickTransactionData;
|
||||
@ -14,6 +15,7 @@ import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class GroupKickTransaction extends Transaction {
|
||||
|
||||
@ -82,9 +84,26 @@ public class GroupKickTransaction extends Transaction {
|
||||
if (!admin.getAddress().equals(groupData.getOwner()) && groupRepository.adminExists(groupId, member.getAddress()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
|
||||
// Can't kick if not group's current owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
if( this.repository.getBlockRepository().getBlockchainHeight() < BlockChain.getInstance().getNullGroupMembershipHeight() ) {
|
||||
// Can't kick if not group's current owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
}
|
||||
// if( this.repository.getBlockRepository().getBlockchainHeight() >= BlockChain.getInstance().getNullGroupMembershipHeight() )
|
||||
else {
|
||||
String groupOwner = this.repository.getGroupRepository().getOwner(groupId);
|
||||
boolean groupOwnedByNullAccount = Objects.equals(groupOwner, Group.NULL_OWNER_ADDRESS);
|
||||
|
||||
// if null ownership group, then check for admin approval
|
||||
if(groupOwnedByNullAccount ) {
|
||||
// Require approval if transaction relates to a group owned by the null account
|
||||
if (!this.needsGroupApproval())
|
||||
return ValidationResult.GROUP_APPROVAL_REQUIRED;
|
||||
}
|
||||
// Can't kick if not group's current owner
|
||||
else if (!admin.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
}
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORT) < this.groupKickTransactionData.getFee())
|
||||
|
@ -65,11 +65,11 @@ public abstract class Transaction {
|
||||
UPDATE_GROUP(23, true),
|
||||
ADD_GROUP_ADMIN(24, true),
|
||||
REMOVE_GROUP_ADMIN(25, true),
|
||||
GROUP_BAN(26, false),
|
||||
CANCEL_GROUP_BAN(27, false),
|
||||
GROUP_KICK(28, false),
|
||||
GROUP_INVITE(29, false),
|
||||
CANCEL_GROUP_INVITE(30, false),
|
||||
GROUP_BAN(26, true),
|
||||
CANCEL_GROUP_BAN(27, true),
|
||||
GROUP_KICK(28, true),
|
||||
GROUP_INVITE(29, true),
|
||||
CANCEL_GROUP_INVITE(30, true),
|
||||
JOIN_GROUP(31, false),
|
||||
LEAVE_GROUP(32, false),
|
||||
GROUP_APPROVAL(33, false),
|
||||
|
@ -115,7 +115,8 @@
|
||||
"groupMemberCheckHeight": 1902700,
|
||||
"fixBatchRewardHeight": 1945900,
|
||||
"adminsReplaceFoundersHeight": 9999999,
|
||||
"onlineValidationFailSafeHeight": 9999999
|
||||
"onlineValidationFailSafeHeight": 9999999,
|
||||
"nullGroupMembershipHeight": 9999999
|
||||
},
|
||||
"checkpoints": [
|
||||
{ "height": 1136300, "signature": "3BbwawEF2uN8Ni5ofpJXkukoU8ctAPxYoFB7whq9pKfBnjfZcpfEJT4R95NvBDoTP8WDyWvsUvbfHbcr9qSZuYpSKZjUQTvdFf6eqznHGEwhZApWfvXu6zjGCxYCp65F4jsVYYJjkzbjmkCg5WAwN5voudngA23kMK6PpTNygapCzXt" }
|
||||
|
@ -4,7 +4,10 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.qortal.account.PrivateKeyAccount;
|
||||
import org.qortal.block.Block;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.*;
|
||||
import org.qortal.group.Group;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
@ -16,6 +19,8 @@ import org.qortal.test.common.transaction.TestTransaction;
|
||||
import org.qortal.transaction.Transaction;
|
||||
import org.qortal.transaction.Transaction.ValidationResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
@ -40,8 +45,14 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class DevGroupAdminTests extends Common {
|
||||
|
||||
public static final int NULL_GROUP_MEMBERSHIP_HEIGHT = BlockChain.getInstance().getNullGroupMembershipHeight();
|
||||
private static final int DEV_GROUP_ID = 1;
|
||||
|
||||
public static final String ALICE = "alice";
|
||||
public static final String BOB = "bob";
|
||||
public static final String CHLOE = "chloe";
|
||||
public static final String DILBERT = "dilbert";
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useDefaultSettings();
|
||||
@ -55,8 +66,8 @@ public class DevGroupAdminTests extends Common {
|
||||
@Test
|
||||
public void testGroupKickMember() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, ALICE);
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, BOB);
|
||||
|
||||
// Dev group
|
||||
int groupId = DEV_GROUP_ID;
|
||||
@ -80,16 +91,10 @@ public class DevGroupAdminTests extends Common {
|
||||
|
||||
// Attempt to kick Bob
|
||||
result = groupKick(repository, alice, groupId, bob.getAddress());
|
||||
// Should be OK
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
// Should not be OK, cannot kick member out of null owned group
|
||||
assertNotSame(ValidationResult.OK, result);
|
||||
|
||||
// Confirm Bob no longer a member
|
||||
assertFalse(isMember(repository, bob.getAddress(), groupId));
|
||||
|
||||
// Orphan last block
|
||||
BlockUtils.orphanLastBlock(repository);
|
||||
|
||||
// Confirm Bob now a member
|
||||
// Confirm Bob remains a member
|
||||
assertTrue(isMember(repository, bob.getAddress(), groupId));
|
||||
}
|
||||
}
|
||||
@ -97,8 +102,8 @@ public class DevGroupAdminTests extends Common {
|
||||
@Test
|
||||
public void testGroupKickAdmin() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, ALICE);
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, BOB);
|
||||
|
||||
// Dev group
|
||||
int groupId = DEV_GROUP_ID;
|
||||
@ -123,7 +128,7 @@ public class DevGroupAdminTests extends Common {
|
||||
assertEquals("incorrect transaction approval status", Transaction.ApprovalStatus.PENDING, approvalStatus);
|
||||
|
||||
// Have Alice approve Bob's approval-needed transaction
|
||||
GroupUtils.approveTransaction(repository, "alice", addGroupAdminTransactionData.getSignature(), true);
|
||||
GroupUtils.approveTransaction(repository, ALICE, addGroupAdminTransactionData.getSignature(), true);
|
||||
|
||||
// Mint a block so that the transaction becomes approved
|
||||
BlockUtils.mintBlock(repository);
|
||||
@ -167,8 +172,8 @@ public class DevGroupAdminTests extends Common {
|
||||
@Test
|
||||
public void testGroupBanMember() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, ALICE);
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, BOB);
|
||||
|
||||
// Dev group
|
||||
int groupId = DEV_GROUP_ID;
|
||||
@ -183,18 +188,13 @@ public class DevGroupAdminTests extends Common {
|
||||
|
||||
// Attempt to ban Bob
|
||||
result = groupBan(repository, alice, groupId, bob.getAddress());
|
||||
// Should be OK
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
|
||||
// Bob attempts to rejoin
|
||||
result = joinGroup(repository, bob, groupId);
|
||||
// Should NOT be OK
|
||||
// Should not be OK, cannot ban someone from a null owned group
|
||||
assertNotSame(ValidationResult.OK, result);
|
||||
|
||||
// Orphan last block (Bob ban)
|
||||
BlockUtils.orphanLastBlock(repository);
|
||||
// Delete unconfirmed group-ban transaction
|
||||
TransactionUtils.deleteUnconfirmedTransactions(repository);
|
||||
// Bob attempts to join
|
||||
result = joinGroup(repository, bob, groupId);
|
||||
// Should be OK, but won't actually get him in the group
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
|
||||
// Confirm Bob is not a member
|
||||
assertFalse(isMember(repository, bob.getAddress(), groupId));
|
||||
@ -204,65 +204,38 @@ public class DevGroupAdminTests extends Common {
|
||||
|
||||
// Bob to join
|
||||
result = joinGroup(repository, bob, groupId);
|
||||
// Should be OK
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
// Should not be OK, bob should already be a member, he joined before the invite and
|
||||
// the invite served as an approval
|
||||
assertEquals(ValidationResult.ALREADY_GROUP_MEMBER, result);
|
||||
|
||||
// Confirm Bob now a member
|
||||
// Confirm Bob now a member, now that he got an invite
|
||||
assertTrue(isMember(repository, bob.getAddress(), groupId));
|
||||
|
||||
// Attempt to ban Bob
|
||||
result = groupBan(repository, alice, groupId, bob.getAddress());
|
||||
// Should be OK
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
// Should not be OK, because you can ban a member of a null owned group
|
||||
assertNotSame(ValidationResult.OK, result);
|
||||
|
||||
// Confirm Bob no longer a member
|
||||
assertFalse(isMember(repository, bob.getAddress(), groupId));
|
||||
// Confirm Bob is still a member
|
||||
assertTrue(isMember(repository, bob.getAddress(), groupId));
|
||||
|
||||
// Bob attempts to rejoin
|
||||
result = joinGroup(repository, bob, groupId);
|
||||
// Should NOT be OK
|
||||
// Should NOT be OK, because he is already a member
|
||||
assertNotSame(ValidationResult.OK, result);
|
||||
|
||||
// Cancel Bob's ban
|
||||
result = cancelGroupBan(repository, alice, groupId, bob.getAddress());
|
||||
// Should be OK
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
|
||||
// Bob attempts to rejoin
|
||||
result = joinGroup(repository, bob, groupId);
|
||||
// Should be OK
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
|
||||
// Orphan last block (Bob join)
|
||||
BlockUtils.orphanLastBlock(repository);
|
||||
// Delete unconfirmed join-group transaction
|
||||
TransactionUtils.deleteUnconfirmedTransactions(repository);
|
||||
|
||||
// Orphan last block (Cancel Bob ban)
|
||||
BlockUtils.orphanLastBlock(repository);
|
||||
// Delete unconfirmed cancel-ban transaction
|
||||
TransactionUtils.deleteUnconfirmedTransactions(repository);
|
||||
|
||||
// Bob attempts to rejoin
|
||||
result = joinGroup(repository, bob, groupId);
|
||||
// Should NOT be OK
|
||||
// Should not be OK, because there was no ban to begin with
|
||||
assertNotSame(ValidationResult.OK, result);
|
||||
|
||||
// Orphan last block (Bob ban)
|
||||
BlockUtils.orphanLastBlock(repository);
|
||||
// Delete unconfirmed group-ban transaction
|
||||
TransactionUtils.deleteUnconfirmedTransactions(repository);
|
||||
|
||||
// Confirm Bob now a member
|
||||
assertTrue(isMember(repository, bob.getAddress(), groupId));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupBanAdmin() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, ALICE);
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, BOB);
|
||||
|
||||
// Dev group
|
||||
int groupId = DEV_GROUP_ID;
|
||||
@ -286,7 +259,7 @@ public class DevGroupAdminTests extends Common {
|
||||
assertEquals("incorrect transaction approval status", Transaction.ApprovalStatus.PENDING, approvalStatus);
|
||||
|
||||
// Have Alice approve Bob's approval-needed transaction
|
||||
GroupUtils.approveTransaction(repository, "alice", addGroupAdminTransactionData.getSignature(), true);
|
||||
GroupUtils.approveTransaction(repository, ALICE, addGroupAdminTransactionData.getSignature(), true);
|
||||
|
||||
// Mint a block so that the transaction becomes approved
|
||||
BlockUtils.mintBlock(repository);
|
||||
@ -321,6 +294,302 @@ public class DevGroupAdminTests extends Common {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAdmin2of3() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
// establish accounts
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, ALICE);
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, BOB);
|
||||
PrivateKeyAccount chloe = Common.getTestAccount(repository, CHLOE);
|
||||
PrivateKeyAccount dilbert = Common.getTestAccount(repository, DILBERT);
|
||||
|
||||
// assert admin statuses
|
||||
assertEquals(2, repository.getGroupRepository().countGroupAdmins(DEV_GROUP_ID).intValue());
|
||||
assertTrue(isAdmin(repository, Group.NULL_OWNER_ADDRESS, DEV_GROUP_ID));
|
||||
assertTrue(isAdmin(repository, alice.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, dilbert.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// confirm Bob is not a member
|
||||
assertFalse(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// alice invites bob
|
||||
ValidationResult result = groupInvite(repository, alice, DEV_GROUP_ID, bob.getAddress(), 3600);
|
||||
assertSame(ValidationResult.OK, result);
|
||||
|
||||
// bob joins
|
||||
joinGroup(repository, bob, DEV_GROUP_ID);
|
||||
|
||||
// confirm Bob is a member now, but still not an admin
|
||||
assertTrue(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob creates transaction to add himself as an admin
|
||||
TransactionData addGroupAdminTransactionData1 = addGroupAdmin(repository, bob, DEV_GROUP_ID, bob.getAddress());
|
||||
|
||||
// bob creates add admin transaction for himself, alice signs which is 50% approval while 40% is needed
|
||||
signForGroupApproval(repository, addGroupAdminTransactionData1, List.of(alice));
|
||||
|
||||
// assert 3 admins in group and bob is an admin now
|
||||
assertEquals(3, repository.getGroupRepository().countGroupAdmins(DEV_GROUP_ID).intValue() );
|
||||
assertTrue(isAdmin(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob invites chloe
|
||||
result = groupInvite(repository, bob, DEV_GROUP_ID, chloe.getAddress(), 3600);
|
||||
assertSame(ValidationResult.OK, result);
|
||||
|
||||
// chloe joins
|
||||
joinGroup(repository, chloe, DEV_GROUP_ID);
|
||||
|
||||
// confirm Chloe is a member now, but still not an admin
|
||||
assertTrue(isMember(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// chloe creates transaction to add herself as an admin
|
||||
TransactionData addChloeAsGroupAdmin = addGroupAdmin(repository, chloe, DEV_GROUP_ID, chloe.getAddress());
|
||||
|
||||
// no one has signed, so it should be pending
|
||||
Transaction.ApprovalStatus addChloeAsGroupAdminStatus1 = GroupUtils.getApprovalStatus(repository, addChloeAsGroupAdmin.getSignature());
|
||||
assertEquals( Transaction.ApprovalStatus.PENDING, addChloeAsGroupAdminStatus1);
|
||||
|
||||
// signer 1
|
||||
Transaction.ApprovalStatus addChloeAsGroupAdminStatus2 = signForGroupApproval(repository, addChloeAsGroupAdmin, List.of(alice));
|
||||
|
||||
// 1 out of 3 has signed, so it should be pending, because it is less than 40%
|
||||
assertEquals( Transaction.ApprovalStatus.PENDING, addChloeAsGroupAdminStatus2);
|
||||
|
||||
// signer 2
|
||||
Transaction.ApprovalStatus addChloeAsGroupAdminStatus3 = signForGroupApproval(repository, addChloeAsGroupAdmin, List.of(bob));
|
||||
|
||||
// 2 out of 3 has signed, so it should be approved, because it is more than 40%
|
||||
assertEquals( Transaction.ApprovalStatus.APPROVED, addChloeAsGroupAdminStatus3);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullOwnershipMembership() throws DataException{
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
Block block = BlockUtils.mintBlocks(repository, NULL_GROUP_MEMBERSHIP_HEIGHT);
|
||||
assertEquals(NULL_GROUP_MEMBERSHIP_HEIGHT + 1, block.getBlockData().getHeight().intValue());
|
||||
|
||||
// establish accounts
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, ALICE);
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, BOB);
|
||||
PrivateKeyAccount chloe = Common.getTestAccount(repository, CHLOE);
|
||||
PrivateKeyAccount dilbert = Common.getTestAccount(repository, DILBERT);
|
||||
|
||||
// assert admin statuses
|
||||
assertEquals(2, repository.getGroupRepository().countGroupAdmins(DEV_GROUP_ID).intValue());
|
||||
assertTrue(isAdmin(repository, Group.NULL_OWNER_ADDRESS, DEV_GROUP_ID));
|
||||
assertTrue(isAdmin(repository, alice.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, dilbert.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// confirm Bob is not a member
|
||||
assertFalse(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// alice invites bob, alice signs which is 50% approval while 40% is needed
|
||||
TransactionData createInviteTransactionData = createGroupInviteForGroupApproval(repository, alice, DEV_GROUP_ID, bob.getAddress(), 3600);
|
||||
Transaction.ApprovalStatus bobsInviteStatus = signForGroupApproval(repository, createInviteTransactionData, List.of(alice));
|
||||
|
||||
// assert approval
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, bobsInviteStatus);
|
||||
|
||||
// bob joins
|
||||
joinGroup(repository, bob, DEV_GROUP_ID);
|
||||
|
||||
// confirm Bob is a member now, but still not an admin
|
||||
assertTrue(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
assertFalse(isAdmin(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob creates transaction to add himself as an admin
|
||||
TransactionData addGroupAdminTransactionData1 = addGroupAdmin(repository, bob, DEV_GROUP_ID, bob.getAddress());
|
||||
|
||||
// bob creates add admin transaction for himself, alice signs which is 50% approval while 40% is needed
|
||||
signForGroupApproval(repository, addGroupAdminTransactionData1, List.of(alice));
|
||||
|
||||
// assert 3 admins in group and bob is an admin now
|
||||
assertEquals(3, repository.getGroupRepository().countGroupAdmins(DEV_GROUP_ID).intValue());
|
||||
assertTrue(isAdmin(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob invites chloe, bob signs which is 33% approval while 40% is needed
|
||||
TransactionData chloeInvite = createGroupInviteForGroupApproval(repository, bob, DEV_GROUP_ID, chloe.getAddress(), 3600);
|
||||
Transaction.ApprovalStatus chloeInviteStatus = signForGroupApproval(repository, chloeInvite, List.of(bob));
|
||||
|
||||
// assert pending
|
||||
assertEquals(Transaction.ApprovalStatus.PENDING, chloeInviteStatus);
|
||||
|
||||
// alice signs which is 66% approval while 40% is needed
|
||||
chloeInviteStatus = signForGroupApproval(repository, chloeInvite, List.of(alice));
|
||||
|
||||
// assert approval
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, chloeInviteStatus);
|
||||
|
||||
// chloe joins
|
||||
joinGroup(repository, chloe, DEV_GROUP_ID);
|
||||
|
||||
// assert chloe is in the group
|
||||
assertTrue(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// alice kicks chloe, alice signs which is 33% approval while 40% is needed
|
||||
TransactionData chloeKick = createGroupKickForGroupApproval(repository, alice, DEV_GROUP_ID, chloe.getAddress(),"testing chloe kick");
|
||||
Transaction.ApprovalStatus chloeKickStatus = signForGroupApproval(repository, chloeKick, List.of(alice));
|
||||
|
||||
// assert pending
|
||||
assertEquals(Transaction.ApprovalStatus.PENDING, chloeKickStatus);
|
||||
|
||||
// assert chloe is still in the group
|
||||
assertTrue(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob signs which is 66% approval while 40% is needed
|
||||
chloeKickStatus = signForGroupApproval(repository, chloeKick, List.of(bob));
|
||||
|
||||
// assert approval
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, chloeKickStatus);
|
||||
|
||||
// assert chloe is not in the group
|
||||
assertFalse(isMember(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob invites chloe, alice and bob signs which is 66% approval while 40% is needed
|
||||
TransactionData chloeInviteAgain = createGroupInviteForGroupApproval(repository, bob, DEV_GROUP_ID, chloe.getAddress(), 3600);
|
||||
Transaction.ApprovalStatus chloeInviteAgainStatus = signForGroupApproval(repository, chloeInviteAgain, List.of(alice, bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, chloeInviteAgainStatus);
|
||||
|
||||
// chloe joins again
|
||||
joinGroup(repository, chloe, DEV_GROUP_ID);
|
||||
|
||||
// assert chloe is in the group
|
||||
assertTrue(isMember(repository, bob.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// alice bans chloe, alice signs which is 33% approval while 40% is needed
|
||||
TransactionData chloeBan = createGroupBanForGroupApproval(repository, alice, DEV_GROUP_ID, chloe.getAddress(), "testing group ban", 3600);
|
||||
Transaction.ApprovalStatus chloeBanStatus1 = signForGroupApproval(repository, chloeBan, List.of(alice));
|
||||
|
||||
// assert pending
|
||||
assertEquals(Transaction.ApprovalStatus.PENDING, chloeBanStatus1);
|
||||
|
||||
// bob signs which 66% approval while 40% is needed
|
||||
Transaction.ApprovalStatus chloeBanStatus2 = signForGroupApproval(repository, chloeBan, List.of(bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, chloeBanStatus2);
|
||||
|
||||
// assert chloe is not in the group
|
||||
assertFalse(isMember(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob invites chloe, alice and bob signs which is 66% approval while 40% is needed
|
||||
ValidationResult chloeInviteValidation = signAndImportGroupInvite(repository, bob, DEV_GROUP_ID, chloe.getAddress(), 3600);
|
||||
|
||||
// assert banned status on invite attempt
|
||||
assertEquals(ValidationResult.BANNED_FROM_GROUP, chloeInviteValidation);
|
||||
|
||||
// bob cancel ban on chloe, bob signs which is 33% approval while 40% is needed
|
||||
TransactionData chloeCancelBan = createCancelGroupBanForGroupApproval( repository, bob, DEV_GROUP_ID, chloe.getAddress());
|
||||
Transaction.ApprovalStatus chloeCancelBanStatus1 = signForGroupApproval(repository, chloeCancelBan, List.of(bob));
|
||||
|
||||
// assert pending
|
||||
assertEquals(Transaction.ApprovalStatus.PENDING, chloeCancelBanStatus1);
|
||||
|
||||
// alice signs which is 66% approval while 40% is needed
|
||||
Transaction.ApprovalStatus chloeCancelBanStatus2 = signForGroupApproval(repository, chloeCancelBan, List.of(alice));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, chloeCancelBanStatus2);
|
||||
|
||||
// bob invites chloe, alice and bob signs which is 66% approval while 40% is needed
|
||||
TransactionData chloeInvite4 = createGroupInviteForGroupApproval(repository, bob, DEV_GROUP_ID, chloe.getAddress(), 3600);
|
||||
Transaction.ApprovalStatus chloeInvite4Status = signForGroupApproval(repository, chloeInvite4, List.of(alice, bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, chloeInvite4Status);
|
||||
|
||||
// chloe joins again
|
||||
joinGroup(repository, chloe, DEV_GROUP_ID);
|
||||
|
||||
// assert chloe is in the group
|
||||
assertTrue(isMember(repository, chloe.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob invites dilbert, alice and bob signs which is 66% approval while 40% is needed
|
||||
TransactionData dilbertInvite1 = createGroupInviteForGroupApproval(repository, bob, DEV_GROUP_ID, dilbert.getAddress(), 3600);
|
||||
Transaction.ApprovalStatus dibertInviteStatus1 = signForGroupApproval(repository, dilbertInvite1, List.of(alice, bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, dibertInviteStatus1);
|
||||
|
||||
// alice cancels dilbert's invite, alice signs which is 33% approval while 40% is needed
|
||||
TransactionData cancelDilbertInvite = createCancelInviteForGroupApproval(repository, alice, DEV_GROUP_ID, dilbert.getAddress());
|
||||
Transaction.ApprovalStatus cancelDilbertInviteStatus1 = signForGroupApproval(repository, cancelDilbertInvite, List.of(alice));
|
||||
|
||||
// assert pending
|
||||
assertEquals(Transaction.ApprovalStatus.PENDING, cancelDilbertInviteStatus1);
|
||||
|
||||
// dilbert joins before the group approves cancellation
|
||||
joinGroup(repository, dilbert, DEV_GROUP_ID);
|
||||
|
||||
// assert dilbert is in the group
|
||||
assertTrue(isMember(repository, dilbert.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// alice kicks out dilbert, alice and bob sign which is 66% approval while 40% is needed
|
||||
TransactionData kickDilbert = createGroupKickForGroupApproval(repository, alice, DEV_GROUP_ID, dilbert.getAddress(), "he is sneaky");
|
||||
Transaction.ApprovalStatus kickDilbertStatus = signForGroupApproval(repository, kickDilbert, List.of(alice, bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, kickDilbertStatus);
|
||||
|
||||
// assert dilbert is out of the group
|
||||
assertFalse(isMember(repository, dilbert.getAddress(), DEV_GROUP_ID));
|
||||
|
||||
// bob invites dilbert again, alice and bob signs which is 66% approval while 40% is needed
|
||||
TransactionData dilbertInvite2 = createGroupInviteForGroupApproval(repository, bob, DEV_GROUP_ID, dilbert.getAddress(), 3600);
|
||||
Transaction.ApprovalStatus dibertInviteStatus2 = signForGroupApproval(repository, dilbertInvite2, List.of(alice, bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, dibertInviteStatus2);
|
||||
|
||||
// alice cancels dilbert's invite, alice and bob signs which is 66% approval while 40% is needed
|
||||
TransactionData cancelDilbertInvite2 = createCancelInviteForGroupApproval(repository, alice, DEV_GROUP_ID, dilbert.getAddress());
|
||||
Transaction.ApprovalStatus cancelDilbertInviteStatus2 = signForGroupApproval(repository, cancelDilbertInvite2, List.of(alice, bob));
|
||||
|
||||
// assert approved
|
||||
assertEquals(Transaction.ApprovalStatus.APPROVED, cancelDilbertInviteStatus2);
|
||||
|
||||
// dilbert tries to join after the group approves cancellation
|
||||
joinGroup(repository, dilbert, DEV_GROUP_ID);
|
||||
|
||||
// assert dilbert is not in the group
|
||||
assertFalse(isMember(repository, dilbert.getAddress(), DEV_GROUP_ID));
|
||||
}
|
||||
}
|
||||
|
||||
private Transaction.ApprovalStatus signForGroupApproval(Repository repository, TransactionData data, List<PrivateKeyAccount> signers) throws DataException {
|
||||
|
||||
for (PrivateKeyAccount signer : signers) {
|
||||
signTransactionDataForGroupApproval(repository, signer, data);
|
||||
}
|
||||
|
||||
BlockUtils.mintBlocks(repository, 2);
|
||||
|
||||
// return approval status
|
||||
return GroupUtils.getApprovalStatus(repository, data.getSignature());
|
||||
}
|
||||
|
||||
private static void signTransactionDataForGroupApproval(Repository repository, PrivateKeyAccount signer, TransactionData transactionData) throws DataException {
|
||||
byte[] reference = signer.getLastReference();
|
||||
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
|
||||
|
||||
BaseTransactionData baseTransactionData
|
||||
= new BaseTransactionData(timestamp, Group.NO_GROUP, reference, signer.getPublicKey(), GroupUtils.fee, null);
|
||||
TransactionData groupApprovalTransactionData
|
||||
= new GroupApprovalTransactionData(baseTransactionData, transactionData.getSignature(), true);
|
||||
|
||||
TransactionUtils.signAndImportValid(repository, groupApprovalTransactionData, signer);
|
||||
}
|
||||
|
||||
private ValidationResult joinGroup(Repository repository, PrivateKeyAccount joiner, int groupId) throws DataException {
|
||||
JoinGroupTransactionData transactionData = new JoinGroupTransactionData(TestTransaction.generateBase(joiner), groupId);
|
||||
@ -332,9 +601,31 @@ public class DevGroupAdminTests extends Common {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void groupInvite(Repository repository, PrivateKeyAccount admin, int groupId, String invitee, int timeToLive) throws DataException {
|
||||
private ValidationResult groupInvite(Repository repository, PrivateKeyAccount admin, int groupId, String invitee, int timeToLive) throws DataException {
|
||||
GroupInviteTransactionData transactionData = new GroupInviteTransactionData(TestTransaction.generateBase(admin), groupId, invitee, timeToLive);
|
||||
ValidationResult result = TransactionUtils.signAndImport(repository, transactionData, admin);
|
||||
|
||||
if (result == ValidationResult.OK)
|
||||
BlockUtils.mintBlock(repository);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private TransactionData createGroupInviteForGroupApproval(Repository repository, PrivateKeyAccount admin, int groupId, String invitee, int timeToLive) throws DataException {
|
||||
GroupInviteTransactionData transactionData = new GroupInviteTransactionData(TestTransaction.generateBase(admin, groupId), groupId, invitee, timeToLive);
|
||||
TransactionUtils.signAndMint(repository, transactionData, admin);
|
||||
return transactionData;
|
||||
}
|
||||
|
||||
private TransactionData createCancelInviteForGroupApproval(Repository repository, PrivateKeyAccount admin, int groupId, String inviteeToCancel) throws DataException {
|
||||
CancelGroupInviteTransactionData transactionData = new CancelGroupInviteTransactionData(TestTransaction.generateBase(admin, groupId), groupId, inviteeToCancel);
|
||||
TransactionUtils.signAndMint(repository, transactionData, admin);
|
||||
return transactionData;
|
||||
}
|
||||
|
||||
private ValidationResult signAndImportGroupInvite(Repository repository, PrivateKeyAccount admin, int groupId, String invitee, int timeToLive) throws DataException {
|
||||
GroupInviteTransactionData transactionData = new GroupInviteTransactionData(TestTransaction.generateBase(admin, groupId), groupId, invitee, timeToLive);
|
||||
return TransactionUtils.signAndImport(repository, transactionData, admin);
|
||||
}
|
||||
|
||||
private ValidationResult groupKick(Repository repository, PrivateKeyAccount admin, int groupId, String member) throws DataException {
|
||||
@ -347,6 +638,13 @@ public class DevGroupAdminTests extends Common {
|
||||
return result;
|
||||
}
|
||||
|
||||
private TransactionData createGroupKickForGroupApproval(Repository repository, PrivateKeyAccount admin, int groupId, String kicked, String reason) throws DataException {
|
||||
GroupKickTransactionData transactionData = new GroupKickTransactionData(TestTransaction.generateBase(admin, groupId), groupId, kicked, reason);
|
||||
TransactionUtils.signAndMint(repository, transactionData, admin);
|
||||
|
||||
return transactionData;
|
||||
}
|
||||
|
||||
private ValidationResult groupBan(Repository repository, PrivateKeyAccount admin, int groupId, String member) throws DataException {
|
||||
GroupBanTransactionData transactionData = new GroupBanTransactionData(TestTransaction.generateBase(admin), groupId, member, "testing", 0);
|
||||
ValidationResult result = TransactionUtils.signAndImport(repository, transactionData, admin);
|
||||
@ -357,6 +655,13 @@ public class DevGroupAdminTests extends Common {
|
||||
return result;
|
||||
}
|
||||
|
||||
private TransactionData createGroupBanForGroupApproval(Repository repository, PrivateKeyAccount admin, int groupId, String banned, String reason, int timeToLive) throws DataException {
|
||||
GroupBanTransactionData transactionData = new GroupBanTransactionData(TestTransaction.generateBase(admin, groupId), groupId, banned, reason, timeToLive);
|
||||
TransactionUtils.signAndMint(repository, transactionData, admin);
|
||||
|
||||
return transactionData;
|
||||
}
|
||||
|
||||
private ValidationResult cancelGroupBan(Repository repository, PrivateKeyAccount admin, int groupId, String member) throws DataException {
|
||||
CancelGroupBanTransactionData transactionData = new CancelGroupBanTransactionData(TestTransaction.generateBase(admin), groupId, member);
|
||||
ValidationResult result = TransactionUtils.signAndImport(repository, transactionData, admin);
|
||||
@ -367,6 +672,14 @@ public class DevGroupAdminTests extends Common {
|
||||
return result;
|
||||
}
|
||||
|
||||
private TransactionData createCancelGroupBanForGroupApproval(Repository repository, PrivateKeyAccount admin, int groupId, String unbanned ) throws DataException {
|
||||
CancelGroupBanTransactionData transactionData = new CancelGroupBanTransactionData( TestTransaction.generateBase(admin, groupId), groupId, unbanned);
|
||||
|
||||
TransactionUtils.signAndMint(repository, transactionData, admin);
|
||||
|
||||
return transactionData;
|
||||
}
|
||||
|
||||
private TransactionData addGroupAdmin(Repository repository, PrivateKeyAccount owner, int groupId, String member) throws DataException {
|
||||
AddGroupAdminTransactionData transactionData = new AddGroupAdminTransactionData(TestTransaction.generateBase(owner), groupId, member);
|
||||
transactionData.setTxGroupId(groupId);
|
||||
|
@ -106,7 +106,8 @@
|
||||
"removeOnlyMintWithNameHeight": 9999999999999,
|
||||
"fixBatchRewardHeight": 9999999999999,
|
||||
"adminsReplaceFoundersHeight": 9999999999999,
|
||||
"onlineValidationFailSafeHeight": 9999999999999
|
||||
"onlineValidationFailSafeHeight": 9999999999999,
|
||||
"nullGroupMembershipHeight": 20
|
||||
},
|
||||
"genesisInfo": {
|
||||
"version": 4,
|
||||
|
Loading…
x
Reference in New Issue
Block a user