diff --git a/src/main/java/org/qora/data/group/GroupData.java b/src/main/java/org/qora/data/group/GroupData.java index 75e50463..b9392a7b 100644 --- a/src/main/java/org/qora/data/group/GroupData.java +++ b/src/main/java/org/qora/data/group/GroupData.java @@ -28,6 +28,12 @@ public class GroupData { @XmlTransient @Schema(hidden = true) private byte[] reference; + // For internal use + @XmlTransient + @Schema( + hidden = true + ) + private int creationGroupId; // Constructors @@ -36,7 +42,7 @@ public class GroupData { } /** Constructs new GroupData with nullable groupId and nullable updated [timestamp] */ - public GroupData(Integer groupId, String owner, String name, String description, long created, Long updated, boolean isOpen, ApprovalThreshold approvalThreshold, int minBlockDelay, int maxBlockDelay, byte[] reference) { + public GroupData(Integer groupId, String owner, String name, String description, long created, Long updated, boolean isOpen, ApprovalThreshold approvalThreshold, int minBlockDelay, int maxBlockDelay, byte[] reference, int creationGroupId) { this.groupId = groupId; this.owner = owner; this.groupName = name; @@ -48,11 +54,12 @@ public class GroupData { this.reference = reference; this.minimumBlockDelay = minBlockDelay; this.maximumBlockDelay = maxBlockDelay; + this.creationGroupId = creationGroupId; } /** Constructs new GroupData with unassigned groupId */ - public GroupData(String owner, String name, String description, long created, boolean isOpen, ApprovalThreshold approvalThreshold, int minBlockDelay, int maxBlockDelay, byte[] reference) { - this(null, owner, name, description, created, null, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference); + public GroupData(String owner, String name, String description, long created, boolean isOpen, ApprovalThreshold approvalThreshold, int minBlockDelay, int maxBlockDelay, byte[] reference, int creationGroupId) { + this(null, owner, name, description, created, null, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference, creationGroupId); } // Getters / setters @@ -129,4 +136,8 @@ public class GroupData { return this.maximumBlockDelay; } + public int getCreationGroupId() { + return this.creationGroupId; + } + } diff --git a/src/main/java/org/qora/data/naming/NameData.java b/src/main/java/org/qora/data/naming/NameData.java index babc086a..ae4bc547 100644 --- a/src/main/java/org/qora/data/naming/NameData.java +++ b/src/main/java/org/qora/data/naming/NameData.java @@ -20,10 +20,18 @@ public class NameData { private Long updated; // No need to expose this via API @XmlTransient - @Schema(hidden = true) + @Schema( + hidden = true + ) private byte[] reference; private boolean isForSale; private BigDecimal salePrice; + // For internal use + @XmlTransient + @Schema( + hidden = true + ) + private int creationGroupId; // Constructors @@ -31,8 +39,8 @@ public class NameData { protected NameData() { } - public NameData(String owner, String name, String data, long registered, Long updated, byte[] reference, boolean isForSale, - BigDecimal salePrice) { + public NameData(String owner, String name, String data, long registered, Long updated, byte[] reference, boolean isForSale, BigDecimal salePrice, + int creationGroupId) { this.owner = owner; this.name = name; this.data = data; @@ -41,10 +49,11 @@ public class NameData { this.reference = reference; this.isForSale = isForSale; this.salePrice = salePrice; + this.creationGroupId = creationGroupId; } - public NameData(String owner, String name, String data, long registered, byte[] reference) { - this(owner, name, data, registered, null, reference, false, null); + public NameData(String owner, String name, String data, long registered, byte[] reference, int creationGroupId) { + this(owner, name, data, registered, null, reference, false, null, creationGroupId); } // Getters / setters @@ -105,4 +114,8 @@ public class NameData { this.salePrice = salePrice; } + public int getCreationGroupId() { + return this.creationGroupId; + } + } diff --git a/src/main/java/org/qora/data/transaction/IssueAssetTransactionData.java b/src/main/java/org/qora/data/transaction/IssueAssetTransactionData.java index d101d3f0..975bbc9e 100644 --- a/src/main/java/org/qora/data/transaction/IssueAssetTransactionData.java +++ b/src/main/java/org/qora/data/transaction/IssueAssetTransactionData.java @@ -46,6 +46,11 @@ public class IssueAssetTransactionData extends TransactionData { } public void afterUnmarshal(Unmarshaller u, Object parent) { + /* + * If we're being constructed as part of the genesis block info inside blockchain config + * and no specific issuer's public key is supplied + * then use genesis account's public key. + */ if (parent instanceof GenesisBlock.GenesisInfo && this.issuerPublicKey == null) this.issuerPublicKey = GenesisAccount.PUBLIC_KEY; diff --git a/src/main/java/org/qora/group/Group.java b/src/main/java/org/qora/group/Group.java index 7a509726..45b62b18 100644 --- a/src/main/java/org/qora/group/Group.java +++ b/src/main/java/org/qora/group/Group.java @@ -116,7 +116,7 @@ public class Group { this.groupData = new GroupData(createGroupTransactionData.getOwner(), createGroupTransactionData.getGroupName(), createGroupTransactionData.getDescription(), createGroupTransactionData.getTimestamp(), createGroupTransactionData.getIsOpen(), createGroupTransactionData.getApprovalThreshold(), createGroupTransactionData.getMinimumBlockDelay(), - createGroupTransactionData.getMaximumBlockDelay(), createGroupTransactionData.getSignature()); + createGroupTransactionData.getMaximumBlockDelay(), createGroupTransactionData.getSignature(), createGroupTransactionData.getTxGroupId()); } /** diff --git a/src/main/java/org/qora/naming/Name.java b/src/main/java/org/qora/naming/Name.java index fb419a3a..f9964df5 100644 --- a/src/main/java/org/qora/naming/Name.java +++ b/src/main/java/org/qora/naming/Name.java @@ -35,7 +35,7 @@ public class Name { this.repository = repository; this.nameData = new NameData(registerNameTransactionData.getOwner(), registerNameTransactionData.getName(), registerNameTransactionData.getData(), registerNameTransactionData.getTimestamp(), - registerNameTransactionData.getSignature()); + registerNameTransactionData.getSignature(), registerNameTransactionData.getTxGroupId()); } /** diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java index 50bf8813..bcb201a6 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -568,6 +568,21 @@ public class HSQLDBDatabaseUpdates { stmt.execute("ALTER TABLE UpdateGroupTransactions ADD COLUMN new_max_block_delay INT NOT NULL DEFAULT 1440 BEFORE group_reference"); break; + case 36: + // Adding group-ness to record types that could require approval for their related transactions + // e.g. REGISTER_NAME might require approval and so Names table requires groupID + // Registered Names + stmt.execute("ALTER TABLE Names ADD COLUMN creation_group_id GroupID NOT NULL DEFAULT 0"); + // Assets aren't ever updated so don't need group-ness + // for future use: stmt.execute("ALTER TABLE Assets ADD COLUMN creation_group_id GroupID NOT NULL DEFAULT 0"); + // Polls aren't ever updated, only voted upon using option index so don't need group-ness + // for future use: stmt.execute("ALTER TABLE Polls ADD COLUMN creation_group_id GroupID NOT NULL DEFAULT 0"); + // CIYAM ATs + stmt.execute("ALTER TABLE ATs ADD COLUMN creation_group_id GroupID NOT NULL DEFAULT 0"); + // Groups can be updated but updates require approval from original groupID + stmt.execute("ALTER TABLE Groups ADD COLUMN creation_group_id GroupID NOT NULL DEFAULT 0"); + break; + default: // nothing to do return false; diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java index 792c71aa..3135ddf9 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java @@ -30,7 +30,7 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public GroupData fromGroupId(int groupId) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_name, owner, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay FROM Groups WHERE group_id = ?", groupId)) { + .checkedExecute("SELECT group_name, owner, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay, creation_group_id FROM Groups WHERE group_id = ?", groupId)) { if (resultSet == null) return null; @@ -51,7 +51,9 @@ public class HSQLDBGroupRepository implements GroupRepository { int minBlockDelay = resultSet.getInt(9); int maxBlockDelay = resultSet.getInt(10); - return new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference); + int creationGroupId = resultSet.getInt(11); + + return new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference, creationGroupId); } catch (SQLException e) { throw new DataException("Unable to fetch group info from repository", e); } @@ -60,7 +62,7 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public GroupData fromGroupName(String groupName) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_id, owner, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay FROM Groups WHERE group_name = ?", groupName)) { + .checkedExecute("SELECT group_id, owner, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay, creation_group_id FROM Groups WHERE group_name = ?", groupName)) { if (resultSet == null) return null; @@ -81,7 +83,9 @@ public class HSQLDBGroupRepository implements GroupRepository { int minBlockDelay = resultSet.getInt(9); int maxBlockDelay = resultSet.getInt(10); - return new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference); + int creationGroupId = resultSet.getInt(11); + + return new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference, creationGroupId); } catch (SQLException e) { throw new DataException("Unable to fetch group info from repository", e); } @@ -107,7 +111,7 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public List getAllGroups(Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT group_id, owner, group_name, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay FROM Groups ORDER BY group_name"; + String sql = "SELECT group_id, owner, group_name, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay, creation_group_id FROM Groups ORDER BY group_name"; if (reverse != null && reverse) sql += " DESC"; sql += HSQLDBRepository.limitOffsetSql(limit, offset); @@ -137,7 +141,9 @@ public class HSQLDBGroupRepository implements GroupRepository { int minBlockDelay = resultSet.getInt(10); int maxBlockDelay = resultSet.getInt(11); - groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference)); + int creationGroupId = resultSet.getInt(12); + + groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference, creationGroupId)); } while (resultSet.next()); return groups; @@ -148,7 +154,7 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public List getGroupsByOwner(String owner, Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT group_id, group_name, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay FROM Groups WHERE owner = ? ORDER BY group_name"; + String sql = "SELECT group_id, group_name, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay, creation_group_id FROM Groups WHERE owner = ? ORDER BY group_name"; if (reverse != null && reverse) sql += " DESC"; sql += HSQLDBRepository.limitOffsetSql(limit, offset); @@ -177,7 +183,9 @@ public class HSQLDBGroupRepository implements GroupRepository { int minBlockDelay = resultSet.getInt(9); int maxBlockDelay = resultSet.getInt(10); - groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference)); + int creationGroupId = resultSet.getInt(11); + + groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference, creationGroupId)); } while (resultSet.next()); return groups; @@ -188,7 +196,7 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public List getGroupsWithMember(String member, Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT group_id, owner, group_name, description, created, updated, reference, is_open, approval_threshold min_block_delay, max_block_delay FROM Groups " + String sql = "SELECT group_id, owner, group_name, description, created, updated, reference, is_open, approval_threshold min_block_delay, max_block_delay, creation_group_id FROM Groups " + "JOIN GroupMembers USING (group_id) WHERE address = ? ORDER BY group_name"; if (reverse != null && reverse) sql += " DESC"; @@ -219,7 +227,9 @@ public class HSQLDBGroupRepository implements GroupRepository { int minBlockDelay = resultSet.getInt(10); int maxBlockDelay = resultSet.getInt(11); - groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference)); + int creationGroupId = resultSet.getInt(12); + + groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, approvalThreshold, minBlockDelay, maxBlockDelay, reference, creationGroupId)); } while (resultSet.next()); return groups; @@ -239,7 +249,8 @@ public class HSQLDBGroupRepository implements GroupRepository { saveHelper.bind("group_id", groupData.getGroupId()).bind("owner", groupData.getOwner()).bind("group_name", groupData.getGroupName()) .bind("description", groupData.getDescription()).bind("created", new Timestamp(groupData.getCreated())).bind("updated", updatedTimestamp) .bind("reference", groupData.getReference()).bind("is_open", groupData.getIsOpen()).bind("approval_threshold", groupData.getApprovalThreshold().value) - .bind("min_block_delay", groupData.getMinimumBlockDelay()).bind("max_block_delay", groupData.getMaximumBlockDelay()); + .bind("min_block_delay", groupData.getMinimumBlockDelay()).bind("max_block_delay", groupData.getMaximumBlockDelay()) + .bind("creation_group_id", groupData.getCreationGroupId()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBNameRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBNameRepository.java index 26446b0c..ce127e3a 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBNameRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBNameRepository.java @@ -23,7 +23,7 @@ public class HSQLDBNameRepository implements NameRepository { @Override public NameData fromName(String name) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT owner, data, registered, updated, reference, is_for_sale, sale_price FROM Names WHERE name = ?", name)) { + .checkedExecute("SELECT owner, data, registered, updated, reference, is_for_sale, sale_price, creation_group_id FROM Names WHERE name = ?", name)) { if (resultSet == null) return null; @@ -38,8 +38,9 @@ public class HSQLDBNameRepository implements NameRepository { byte[] reference = resultSet.getBytes(5); boolean isForSale = resultSet.getBoolean(6); BigDecimal salePrice = resultSet.getBigDecimal(7); + int creationGroupId = resultSet.getInt(8); - return new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice); + return new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice, creationGroupId); } catch (SQLException e) { throw new DataException("Unable to fetch name info from repository", e); } @@ -56,7 +57,7 @@ public class HSQLDBNameRepository implements NameRepository { @Override public List getAllNames(Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT name, data, owner, registered, updated, reference, is_for_sale, sale_price FROM Names ORDER BY name"; + String sql = "SELECT name, data, owner, registered, updated, reference, is_for_sale, sale_price, creation_group_id FROM Names ORDER BY name"; if (reverse != null && reverse) sql += " DESC"; sql += HSQLDBRepository.limitOffsetSql(limit, offset); @@ -80,8 +81,9 @@ public class HSQLDBNameRepository implements NameRepository { byte[] reference = resultSet.getBytes(6); boolean isForSale = resultSet.getBoolean(7); BigDecimal salePrice = resultSet.getBigDecimal(8); + int creationGroupId = resultSet.getInt(9); - names.add(new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice)); + names.add(new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice, creationGroupId)); } while (resultSet.next()); return names; @@ -92,7 +94,7 @@ public class HSQLDBNameRepository implements NameRepository { @Override public List getNamesForSale(Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT name, data, owner, registered, updated, reference, sale_price FROM Names WHERE is_for_sale = TRUE ORDER BY name"; + String sql = "SELECT name, data, owner, registered, updated, reference, sale_price, creation_group_id FROM Names WHERE is_for_sale = TRUE ORDER BY name"; if (reverse != null && reverse) sql += " DESC"; sql += HSQLDBRepository.limitOffsetSql(limit, offset); @@ -116,8 +118,9 @@ public class HSQLDBNameRepository implements NameRepository { byte[] reference = resultSet.getBytes(6); boolean isForSale = true; BigDecimal salePrice = resultSet.getBigDecimal(7); + int creationGroupId = resultSet.getInt(8); - names.add(new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice)); + names.add(new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice, creationGroupId)); } while (resultSet.next()); return names; @@ -128,7 +131,7 @@ public class HSQLDBNameRepository implements NameRepository { @Override public List getNamesByOwner(String owner, Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT name, data, registered, updated, reference, is_for_sale, sale_price FROM Names WHERE owner = ? ORDER BY name"; + String sql = "SELECT name, data, registered, updated, reference, is_for_sale, sale_price, creation_group_id FROM Names WHERE owner = ? ORDER BY name"; if (reverse != null && reverse) sql += " DESC"; sql += HSQLDBRepository.limitOffsetSql(limit, offset); @@ -151,8 +154,9 @@ public class HSQLDBNameRepository implements NameRepository { byte[] reference = resultSet.getBytes(5); boolean isForSale = resultSet.getBoolean(6); BigDecimal salePrice = resultSet.getBigDecimal(7); + int creationGroupId = resultSet.getInt(8); - names.add(new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice)); + names.add(new NameData(owner, name, data, registered, updated, reference, isForSale, salePrice, creationGroupId)); } while (resultSet.next()); return names; @@ -171,7 +175,8 @@ public class HSQLDBNameRepository implements NameRepository { saveHelper.bind("owner", nameData.getOwner()).bind("name", nameData.getName()).bind("data", nameData.getData()) .bind("registered", new Timestamp(nameData.getRegistered())).bind("updated", updatedTimestamp).bind("reference", nameData.getReference()) - .bind("is_for_sale", nameData.getIsForSale()).bind("sale_price", nameData.getSalePrice()); + .bind("is_for_sale", nameData.getIsForSale()).bind("sale_price", nameData.getSalePrice()) + .bind("creation_group_id", nameData.getCreationGroupId()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index 7b59ec46..7a128058 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -508,7 +508,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { String sql = "SELECT signature FROM UnconfirmedTransactions " + "NATURAL JOIN Transactions " + "LEFT OUTER JOIN Accounts ON Accounts.public_key = Transactions.creator " - + "LEFT OUTER JOIN GroupAdmins ON GroupAdmins.admin = Accounts.account " + + "LEFT OUTER JOIN GroupAdmins ON GroupAdmins.admin = Accounts.account AND GroupAdmins.group_id = Transactions.tx_group_id " + "WHERE Transactions.tx_group_id != ? AND GroupAdmins.admin IS NULL " + "AND Transactions.type IN (" + txTypes + ") " + "ORDER BY creation"; diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java index ff479857..6995d090 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java @@ -29,9 +29,9 @@ public class HSQLDBUpdateGroupTransactionRepository extends HSQLDBTransactionRep String newDescription = resultSet.getString(3); boolean newIsOpen = resultSet.getBoolean(4); ApprovalThreshold newApprovalThreshold = ApprovalThreshold.valueOf(resultSet.getInt(5)); - byte[] groupReference = resultSet.getBytes(6); - int newMinBlockDelay = resultSet.getInt(7); - int newMaxBlockDelay = resultSet.getInt(8); + int newMinBlockDelay = resultSet.getInt(6); + int newMaxBlockDelay = resultSet.getInt(7); + byte[] groupReference = resultSet.getBytes(8); return new UpdateGroupTransactionData(timestamp, txGroupId, reference, creatorPublicKey, groupId, newOwner, newDescription, newIsOpen, newApprovalThreshold, newMinBlockDelay, newMaxBlockDelay, groupReference, fee, signature); diff --git a/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java b/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java index 7ecc2ee1..4b703581 100644 --- a/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java +++ b/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java @@ -84,10 +84,6 @@ public class AddGroupAdminTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != addGroupAdminTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account owner = getOwner(); // Check transaction's public key matches group's current owner diff --git a/src/main/java/org/qora/transaction/BuyNameTransaction.java b/src/main/java/org/qora/transaction/BuyNameTransaction.java index 8858bafd..c8c57d55 100644 --- a/src/main/java/org/qora/transaction/BuyNameTransaction.java +++ b/src/main/java/org/qora/transaction/BuyNameTransaction.java @@ -28,10 +28,6 @@ public class BuyNameTransaction extends Transaction { super(repository, transactionData); this.buyNameTransactionData = (BuyNameTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.buyNameTransactionData.getBuyerPublicKey()); } // More information diff --git a/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java b/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java index 92b18853..79ccf456 100644 --- a/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java +++ b/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java @@ -84,10 +84,6 @@ public class CancelGroupBanTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != groupUnbanTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account admin = getAdmin(); // Can't unban if not an admin diff --git a/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java b/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java index cd725f82..d4cbe20b 100644 --- a/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java +++ b/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java @@ -84,10 +84,6 @@ public class CancelGroupInviteTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != cancelGroupInviteTransactionData.getGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account admin = getAdmin(); // Check admin is actually an admin diff --git a/src/main/java/org/qora/transaction/CancelSellNameTransaction.java b/src/main/java/org/qora/transaction/CancelSellNameTransaction.java index d5ba488b..9492d6f5 100644 --- a/src/main/java/org/qora/transaction/CancelSellNameTransaction.java +++ b/src/main/java/org/qora/transaction/CancelSellNameTransaction.java @@ -28,10 +28,6 @@ public class CancelSellNameTransaction extends Transaction { super(repository, transactionData); this.cancelSellNameTransactionData = (CancelSellNameTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.cancelSellNameTransactionData.getOwnerPublicKey()); } // More information diff --git a/src/main/java/org/qora/transaction/GroupApprovalTransaction.java b/src/main/java/org/qora/transaction/GroupApprovalTransaction.java index 00d67287..48e39b3e 100644 --- a/src/main/java/org/qora/transaction/GroupApprovalTransaction.java +++ b/src/main/java/org/qora/transaction/GroupApprovalTransaction.java @@ -69,10 +69,6 @@ public class GroupApprovalTransaction extends Transaction { if (pendingTransactionData == null) return ValidationResult.TRANSACTION_UNKNOWN; - // Check pending transaction's groupID matches our transaction's groupID - if (groupApprovalTransactionData.getTxGroupId() != pendingTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - // Check pending transaction is not already in a block if (this.repository.getTransactionRepository().getHeightFromSignature(groupApprovalTransactionData.getPendingSignature()) != 0) return ValidationResult.TRANSACTION_ALREADY_CONFIRMED; @@ -80,7 +76,7 @@ public class GroupApprovalTransaction extends Transaction { Account admin = getAdmin(); // Can't cast approval decision if not an admin - if (!this.repository.getGroupRepository().adminExists(groupApprovalTransactionData.getTxGroupId(), admin.getAddress())) + if (!this.repository.getGroupRepository().adminExists(pendingTransactionData.getTxGroupId(), admin.getAddress())) return ValidationResult.NOT_GROUP_ADMIN; // Check fee is positive diff --git a/src/main/java/org/qora/transaction/GroupBanTransaction.java b/src/main/java/org/qora/transaction/GroupBanTransaction.java index 3aa1e21a..12bb4883 100644 --- a/src/main/java/org/qora/transaction/GroupBanTransaction.java +++ b/src/main/java/org/qora/transaction/GroupBanTransaction.java @@ -84,10 +84,6 @@ public class GroupBanTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != groupBanTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account admin = getAdmin(); // Can't ban if not an admin diff --git a/src/main/java/org/qora/transaction/GroupInviteTransaction.java b/src/main/java/org/qora/transaction/GroupInviteTransaction.java index b2a3414b..fa26db25 100644 --- a/src/main/java/org/qora/transaction/GroupInviteTransaction.java +++ b/src/main/java/org/qora/transaction/GroupInviteTransaction.java @@ -75,10 +75,6 @@ public class GroupInviteTransaction extends Transaction { public ValidationResult isValid() throws DataException { int groupId = groupInviteTransactionData.getGroupId(); - // Check transaction's groupID matches group's ID - if (groupInviteTransactionData.getTxGroupId() != groupId) - return ValidationResult.GROUP_ID_MISMATCH; - // Check time to live zero (infinite) or positive if (groupInviteTransactionData.getTimeToLive() < 0) return ValidationResult.INVALID_LIFETIME; diff --git a/src/main/java/org/qora/transaction/GroupKickTransaction.java b/src/main/java/org/qora/transaction/GroupKickTransaction.java index 4d632e19..5063656e 100644 --- a/src/main/java/org/qora/transaction/GroupKickTransaction.java +++ b/src/main/java/org/qora/transaction/GroupKickTransaction.java @@ -87,10 +87,6 @@ public class GroupKickTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != groupKickTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account admin = getAdmin(); // Can't kick if not an admin diff --git a/src/main/java/org/qora/transaction/IssueAssetTransaction.java b/src/main/java/org/qora/transaction/IssueAssetTransaction.java index f630ac0c..25870a1f 100644 --- a/src/main/java/org/qora/transaction/IssueAssetTransaction.java +++ b/src/main/java/org/qora/transaction/IssueAssetTransaction.java @@ -32,10 +32,6 @@ public class IssueAssetTransaction extends Transaction { super(repository, transactionData); this.issueAssetTransactionData = (IssueAssetTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.issueAssetTransactionData.getIssuerPublicKey()); } // More information diff --git a/src/main/java/org/qora/transaction/JoinGroupTransaction.java b/src/main/java/org/qora/transaction/JoinGroupTransaction.java index a3cd1540..f9278a61 100644 --- a/src/main/java/org/qora/transaction/JoinGroupTransaction.java +++ b/src/main/java/org/qora/transaction/JoinGroupTransaction.java @@ -67,11 +67,6 @@ public class JoinGroupTransaction extends Transaction { public ValidationResult isValid() throws DataException { int groupId = joinGroupTransactionData.getGroupId(); - // Check txGroupId - int txGroupId = joinGroupTransactionData.getTxGroupId(); - if (txGroupId != Group.NO_GROUP && txGroupId != groupId) - return ValidationResult.GROUP_ID_MISMATCH; - // Check group exists if (!this.repository.getGroupRepository().groupExists(groupId)) return ValidationResult.GROUP_DOES_NOT_EXIST; diff --git a/src/main/java/org/qora/transaction/LeaveGroupTransaction.java b/src/main/java/org/qora/transaction/LeaveGroupTransaction.java index f25d4bd9..6f79e42c 100644 --- a/src/main/java/org/qora/transaction/LeaveGroupTransaction.java +++ b/src/main/java/org/qora/transaction/LeaveGroupTransaction.java @@ -72,10 +72,6 @@ public class LeaveGroupTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != leaveGroupTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account leaver = getLeaver(); // Can't leave if group owner diff --git a/src/main/java/org/qora/transaction/PaymentTransaction.java b/src/main/java/org/qora/transaction/PaymentTransaction.java index a6729b01..2772b5db 100644 --- a/src/main/java/org/qora/transaction/PaymentTransaction.java +++ b/src/main/java/org/qora/transaction/PaymentTransaction.java @@ -26,10 +26,6 @@ public class PaymentTransaction extends Transaction { super(repository, transactionData); this.paymentTransactionData = (PaymentTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.paymentTransactionData.getSenderPublicKey()); } // More information diff --git a/src/main/java/org/qora/transaction/RegisterNameTransaction.java b/src/main/java/org/qora/transaction/RegisterNameTransaction.java index bcd966a4..8e85e014 100644 --- a/src/main/java/org/qora/transaction/RegisterNameTransaction.java +++ b/src/main/java/org/qora/transaction/RegisterNameTransaction.java @@ -28,10 +28,6 @@ public class RegisterNameTransaction extends Transaction { super(repository, transactionData); this.registerNameTransactionData = (RegisterNameTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.registerNameTransactionData.getRegistrantPublicKey()); } // More information diff --git a/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java b/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java index 40dec872..412c1969 100644 --- a/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java +++ b/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java @@ -84,10 +84,6 @@ public class RemoveGroupAdminTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != removeGroupAdminTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; - Account owner = getOwner(); // Check transaction's public key matches group's current owner diff --git a/src/main/java/org/qora/transaction/SellNameTransaction.java b/src/main/java/org/qora/transaction/SellNameTransaction.java index 4b18332a..ac3b01b3 100644 --- a/src/main/java/org/qora/transaction/SellNameTransaction.java +++ b/src/main/java/org/qora/transaction/SellNameTransaction.java @@ -29,10 +29,6 @@ public class SellNameTransaction extends Transaction { super(repository, transactionData); this.sellNameTransactionData = (SellNameTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.sellNameTransactionData.getOwnerPublicKey()); } // More information diff --git a/src/main/java/org/qora/transaction/Transaction.java b/src/main/java/org/qora/transaction/Transaction.java index 6e0f0105..28584d76 100644 --- a/src/main/java/org/qora/transaction/Transaction.java +++ b/src/main/java/org/qora/transaction/Transaction.java @@ -185,6 +185,7 @@ public abstract class Transaction { TRANSACTION_UNKNOWN(65), TRANSACTION_ALREADY_CONFIRMED(66), INVALID_TX_GROUP_ID(67), + TX_GROUP_ID_MISMATCH(68), NOT_YET_RELEASED(1000); public final int value; @@ -665,7 +666,7 @@ public abstract class Transaction { // Group no longer exists? Possibly due to blockchain orphaning undoing group creation? return true; // stops tx being included in block but it will eventually expire - // If transaction's creator is group admin then auto-approve + // If transaction's creator is group admin (of group with ID txGroupId) then auto-approve PublicKeyAccount creator = this.getCreator(); if (groupRepository.adminExists(txGroupId, creator.getAddress())) return false; diff --git a/src/main/java/org/qora/transaction/UpdateGroupTransaction.java b/src/main/java/org/qora/transaction/UpdateGroupTransaction.java index eea0fe6d..483c54a9 100644 --- a/src/main/java/org/qora/transaction/UpdateGroupTransaction.java +++ b/src/main/java/org/qora/transaction/UpdateGroupTransaction.java @@ -95,9 +95,9 @@ public class UpdateGroupTransaction extends Transaction { if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's groupID matches group's ID - if (groupData.getGroupId() != updateGroupTransactionData.getTxGroupId()) - return ValidationResult.GROUP_ID_MISMATCH; + // As this transaction type could require approval, check txGroupId matches groupID at creation + if (groupData.getCreationGroupId() != updateGroupTransactionData.getTxGroupId()) + return ValidationResult.TX_GROUP_ID_MISMATCH; Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/UpdateNameTransaction.java b/src/main/java/org/qora/transaction/UpdateNameTransaction.java index 45cb2d94..fe258d35 100644 --- a/src/main/java/org/qora/transaction/UpdateNameTransaction.java +++ b/src/main/java/org/qora/transaction/UpdateNameTransaction.java @@ -29,10 +29,6 @@ public class UpdateNameTransaction extends Transaction { super(repository, transactionData); this.updateNameTransactionData = (UpdateNameTransactionData) this.transactionData; - - // XXX This is horrible - thanks to JAXB unmarshalling not calling constructor - if (this.transactionData.getCreatorPublicKey() == null) - this.transactionData.setCreatorPublicKey(this.updateNameTransactionData.getOwnerPublicKey()); } // More information @@ -104,6 +100,10 @@ public class UpdateNameTransaction extends Transaction { if (nameData == null) return ValidationResult.NAME_DOES_NOT_EXIST; + // As this transaction type could require approval, check txGroupId matches groupID at creation + if (nameData.getCreationGroupId() != updateNameTransactionData.getTxGroupId()) + return ValidationResult.TX_GROUP_ID_MISMATCH; + // Check name isn't currently for sale if (nameData.getIsForSale()) return ValidationResult.NAME_ALREADY_FOR_SALE;