From ec5eba9c60d5238236b0bf7df55e474747655651 Mon Sep 17 00:00:00 2001 From: catbref Date: Tue, 26 Feb 2019 16:52:22 +0000 Subject: [PATCH] Fix up some group-approval related issues UPDATE_NAME requires txGroupId to match original txGroupId used in REGISTER_NAME UPDATE_GROUP requires txGroupId to match original txGroupId used in CREATE_GROUP Extraneous JAXB unmarshal code removed from various transaction constructors. Incorrect, old, groupID vs txGroupId checks removed from various transactions. Fix bug in UPDATE_GROUP fromBase() method using mismatched column indexes. Fix bug in API's pending transaction fetch not checking admin is of the same group as the txGroupId. (Fix actually in HSQLDBTransactionRepository). Similar fix in GroupApprovalTransaction. --- .../java/org/qora/data/group/GroupData.java | 17 ++++++++-- .../java/org/qora/data/naming/NameData.java | 23 ++++++++++--- .../IssueAssetTransactionData.java | 5 +++ src/main/java/org/qora/group/Group.java | 2 +- src/main/java/org/qora/naming/Name.java | 2 +- .../hsqldb/HSQLDBDatabaseUpdates.java | 15 +++++++++ .../hsqldb/HSQLDBGroupRepository.java | 33 ++++++++++++------- .../hsqldb/HSQLDBNameRepository.java | 23 ++++++++----- .../HSQLDBTransactionRepository.java | 2 +- ...SQLDBUpdateGroupTransactionRepository.java | 6 ++-- .../transaction/AddGroupAdminTransaction.java | 4 --- .../qora/transaction/BuyNameTransaction.java | 4 --- .../CancelGroupBanTransaction.java | 4 --- .../CancelGroupInviteTransaction.java | 4 --- .../CancelSellNameTransaction.java | 4 --- .../transaction/GroupApprovalTransaction.java | 6 +--- .../qora/transaction/GroupBanTransaction.java | 4 --- .../transaction/GroupInviteTransaction.java | 4 --- .../transaction/GroupKickTransaction.java | 4 --- .../transaction/IssueAssetTransaction.java | 4 --- .../transaction/JoinGroupTransaction.java | 5 --- .../transaction/LeaveGroupTransaction.java | 4 --- .../qora/transaction/PaymentTransaction.java | 4 --- .../transaction/RegisterNameTransaction.java | 4 --- .../RemoveGroupAdminTransaction.java | 4 --- .../qora/transaction/SellNameTransaction.java | 4 --- .../org/qora/transaction/Transaction.java | 3 +- .../transaction/UpdateGroupTransaction.java | 6 ++-- .../transaction/UpdateNameTransaction.java | 8 ++--- 29 files changed, 104 insertions(+), 108 deletions(-) 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;