From a3d4cf29003ccc2ee522ba2f2a72e27a23362ab1 Mon Sep 17 00:00:00 2001 From: catbref Date: Wed, 22 May 2019 14:50:37 +0100 Subject: [PATCH] MAJOR: Don't delete transactions when orphaning - make them unconfirmed again Lots of edits to Transaction subclasses to change/remove 'delete'. Corresponding extra changes to help reset some transaction fields to pre-process state during orphaning. Changed Block, GenesisBlock & Synchronizer to save transactions where appropriate. Added enhanced GET_SIGNATURES_V2 network message to reduce the number of block signatures sent over network. Peers are now version 2 if they send a new-style build version string, instead of using first digit from build version. --- src/main/java/org/qora/asset/Asset.java | 3 + src/main/java/org/qora/block/Block.java | 18 ++- .../java/org/qora/block/GenesisBlock.java | 4 + .../java/org/qora/controller/Controller.java | 28 +++++ .../org/qora/controller/Synchronizer.java | 16 ++- .../transaction/SetGroupTransactionData.java | 2 +- src/main/java/org/qora/group/Group.java | 86 ++++++++----- src/main/java/org/qora/naming/Name.java | 10 +- src/main/java/org/qora/network/Peer.java | 9 +- .../message/GetSignaturesV2Message.java | 67 ++++++++++ .../org/qora/network/message/Message.java | 3 +- .../transaction/AccountFlagsTransaction.java | 5 +- .../transaction/AddGroupAdminTransaction.java | 6 +- .../transaction/ArbitraryTransaction.java | 18 +-- .../org/qora/transaction/AtTransaction.java | 10 +- .../qora/transaction/BuyNameTransaction.java | 6 +- .../CancelAssetOrderTransaction.java | 6 +- .../CancelGroupBanTransaction.java | 4 +- .../CancelGroupInviteTransaction.java | 4 +- .../CancelSellNameTransaction.java | 10 +- .../CreateAssetOrderTransaction.java | 6 +- .../transaction/CreateGroupTransaction.java | 7 +- .../transaction/CreatePollTransaction.java | 6 +- .../qora/transaction/DeployAtTransaction.java | 6 +- .../transaction/EnableForgingTransaction.java | 6 +- .../qora/transaction/GenesisTransaction.java | 6 +- .../transaction/GroupApprovalTransaction.java | 7 +- .../qora/transaction/GroupBanTransaction.java | 4 +- .../transaction/GroupInviteTransaction.java | 4 +- .../transaction/GroupKickTransaction.java | 4 +- .../transaction/IssueAssetTransaction.java | 7 +- .../transaction/JoinGroupTransaction.java | 6 +- .../transaction/LeaveGroupTransaction.java | 4 +- .../qora/transaction/MessageTransaction.java | 8 +- .../transaction/MultiPaymentTransaction.java | 8 +- .../qora/transaction/PaymentTransaction.java | 8 +- .../transaction/ProxyForgingTransaction.java | 5 +- .../transaction/RegisterNameTransaction.java | 6 +- .../RemoveGroupAdminTransaction.java | 6 +- .../qora/transaction/SellNameTransaction.java | 8 +- .../qora/transaction/SetGroupTransaction.java | 5 +- .../transaction/TransferAssetTransaction.java | 8 +- .../transaction/UpdateAssetTransaction.java | 7 +- .../transaction/UpdateGroupTransaction.java | 4 +- .../transaction/UpdateNameTransaction.java | 4 +- .../transaction/VoteOnPollTransaction.java | 5 +- src/test/java/org/qora/test/BlockTests.java | 114 ++++++++++-------- .../java/org/qora/test/BlockchainTests.java | 15 --- src/test/java/org/qora/test/GenesisTests.java | 54 --------- src/test/java/org/qora/test/LoadTests.java | 93 -------------- .../java/org/qora/test/NavigationTests.java | 46 ------- .../java/org/qora/test/RepositoryTests.java | 14 ++- .../qora/test/common/TransactionUtils.java | 25 +++- .../transaction/PaymentTransaction.java | 18 +++ .../test/common/transaction/Transaction.java | 4 + .../qora/test/forging/GrantForgingTests.java | 1 - 56 files changed, 410 insertions(+), 444 deletions(-) create mode 100644 src/main/java/org/qora/network/message/GetSignaturesV2Message.java delete mode 100644 src/test/java/org/qora/test/BlockchainTests.java delete mode 100644 src/test/java/org/qora/test/GenesisTests.java delete mode 100644 src/test/java/org/qora/test/LoadTests.java delete mode 100644 src/test/java/org/qora/test/NavigationTests.java create mode 100644 src/test/java/org/qora/test/common/transaction/PaymentTransaction.java create mode 100644 src/test/java/org/qora/test/common/transaction/Transaction.java diff --git a/src/main/java/org/qora/asset/Asset.java b/src/main/java/org/qora/asset/Asset.java index 11a2137c..cae5fe01 100644 --- a/src/main/java/org/qora/asset/Asset.java +++ b/src/main/java/org/qora/asset/Asset.java @@ -156,6 +156,9 @@ public class Asset { // Save reverted asset this.repository.getAssetRepository().save(this.assetData); + + // Remove reference to previous asset-changing transaction + updateAssetTransactionData.setOrphanReference(null); } } diff --git a/src/main/java/org/qora/block/Block.java b/src/main/java/org/qora/block/Block.java index f7253483..e0b1a7f9 100644 --- a/src/main/java/org/qora/block/Block.java +++ b/src/main/java/org/qora/block/Block.java @@ -34,6 +34,7 @@ import org.qora.repository.Repository; import org.qora.transaction.AtTransaction; import org.qora.transaction.GenesisTransaction; import org.qora.transaction.Transaction; +import org.qora.transaction.Transaction.TransactionType; import org.qora.transform.TransformationException; import org.qora.transform.block.BlockTransformer; import org.qora.transform.transaction.TransactionTransformer; @@ -1045,10 +1046,15 @@ public class Block { processBlockRewards(); // Process transactions (we'll link them to this block after saving the block itself) - // AT-generated transactions are already added to our transactions so no special handling is needed here. + // AT-generated transactions are already prepended to our transactions at this point. List transactions = this.getTransactions(); - for (Transaction transaction : transactions) + for (Transaction transaction : transactions) { + // AT_TRANSACTIONs are created locally and need saving into repository before processing + if (transaction.getTransactionData().getType() == TransactionType.AT) + this.repository.getTransactionRepository().save(transaction.getTransactionData()); + transaction.process(); + } // Give transaction fees to generator/proxy rewardTransactionFees(); @@ -1158,9 +1164,11 @@ public class Block { transaction.getTransactionData().getSignature()); this.repository.getBlockRepository().delete(blockTransactionData); - // Add to unconfirmed pile - // XXX WE CAN'T ADD TO UNCONFIRMED AS TRANSACTION HAS BEEN DELETED BY transaction.orphan() ABOVE - // this.repository.getTransactionRepository().unconfirmTransaction(transaction.getTransactionData()); + // Add to unconfirmed pile, or delete if AT_TRANSACTION + if (transaction.getTransactionData().getType() == TransactionType.AT) + this.repository.getTransactionRepository().delete(transaction.getTransactionData()); + else + this.repository.getTransactionRepository().unconfirmTransaction(transaction.getTransactionData()); this.repository.getTransactionRepository().deleteParticipants(transaction.getTransactionData()); } diff --git a/src/main/java/org/qora/block/GenesisBlock.java b/src/main/java/org/qora/block/GenesisBlock.java index cb47ee42..246cc88c 100644 --- a/src/main/java/org/qora/block/GenesisBlock.java +++ b/src/main/java/org/qora/block/GenesisBlock.java @@ -318,6 +318,10 @@ public class GenesisBlock extends Block { this.repository.rollbackToSavepoint(); } + // Save transactions into repository ready for processing + for (Transaction transaction : this.getTransactions()) + this.repository.getTransactionRepository().save(transaction.getTransactionData()); + super.process(); } diff --git a/src/main/java/org/qora/controller/Controller.java b/src/main/java/org/qora/controller/Controller.java index 9792e169..2687649f 100644 --- a/src/main/java/org/qora/controller/Controller.java +++ b/src/main/java/org/qora/controller/Controller.java @@ -34,6 +34,7 @@ import org.qora.network.message.GetBlockMessage; import org.qora.network.message.GetBlockSummariesMessage; import org.qora.network.message.GetPeersMessage; import org.qora.network.message.GetSignaturesMessage; +import org.qora.network.message.GetSignaturesV2Message; import org.qora.network.message.HeightMessage; import org.qora.network.message.Message; import org.qora.network.message.SignaturesMessage; @@ -165,6 +166,7 @@ public class Controller extends Thread { LOGGER.info("Validating blockchain"); try { BlockChain.validate(); + LOGGER.info(String.format("Our chain height at start-up: %d", getInstance().getChainHeight())); } catch (DataException e) { LOGGER.error("Couldn't validate blockchain", e); System.exit(2); @@ -415,6 +417,32 @@ public class Controller extends Thread { } break; + case GET_SIGNATURES_V2: + try (final Repository repository = RepositoryManager.getRepository()) { + GetSignaturesV2Message getSignaturesMessage = (GetSignaturesV2Message) message; + byte[] parentSignature = getSignaturesMessage.getParentSignature(); + + List signatures = new ArrayList<>(); + + do { + BlockData blockData = repository.getBlockRepository().fromReference(parentSignature); + + if (blockData == null) + break; + + parentSignature = blockData.getSignature(); + signatures.add(parentSignature); + } while (signatures.size() < getSignaturesMessage.getNumberRequested()); + + Message signaturesMessage = new SignaturesMessage(signatures); + signaturesMessage.setId(message.getId()); + if (!peer.sendMessage(signaturesMessage)) + peer.disconnect(); + } catch (DataException e) { + LOGGER.error(String.format("Repository issue while responding to %s from peer %s", message.getType().name(), peer), e); + } + break; + case GET_BLOCK: try (final Repository repository = RepositoryManager.getRepository()) { GetBlockMessage getBlockMessage = (GetBlockMessage) message; diff --git a/src/main/java/org/qora/controller/Synchronizer.java b/src/main/java/org/qora/controller/Synchronizer.java index f7f6b7a0..6f5001b6 100644 --- a/src/main/java/org/qora/controller/Synchronizer.java +++ b/src/main/java/org/qora/controller/Synchronizer.java @@ -18,12 +18,14 @@ import org.qora.network.message.BlockSummariesMessage; import org.qora.network.message.GetBlockMessage; import org.qora.network.message.GetBlockSummariesMessage; import org.qora.network.message.GetSignaturesMessage; +import org.qora.network.message.GetSignaturesV2Message; import org.qora.network.message.Message; import org.qora.network.message.Message.MessageType; import org.qora.network.message.SignaturesMessage; import org.qora.repository.DataException; import org.qora.repository.Repository; import org.qora.repository.RepositoryManager; +import org.qora.transaction.Transaction; public class Synchronizer { @@ -168,10 +170,11 @@ public class Synchronizer { // Fetch, and apply, blocks from peer byte[] signature = commonBlockData.getSignature(); - while (ourHeight < peerHeight && ourHeight < commonBlockHeight + SYNC_BATCH_SIZE) { + int maxBatchHeight = commonBlockHeight + SYNC_BATCH_SIZE; + while (ourHeight < peerHeight && ourHeight < maxBatchHeight) { // Do we need more signatures? if (signatures.isEmpty()) { - signatures = this.getBlockSignatures(peer, signature, MAXIMUM_BLOCK_STEP); + signatures = this.getBlockSignatures(peer, signature, maxBatchHeight - ourHeight); if (signatures == null || signatures.isEmpty()) { LOGGER.info(String.format("Peer %s failed to respond with more block signatures after height %d", peer, ourHeight)); return SynchronizationResult.NO_REPLY; @@ -200,6 +203,10 @@ public class Synchronizer { return SynchronizationResult.INVALID_DATA; } + // Save transactions attached to this block + for (Transaction transaction : newBlock.getTransactions()) + repository.getTransactionRepository().save(transaction.getTransactionData()); + newBlock.process(); // If we've grown our blockchain then at least save progress so far @@ -316,8 +323,9 @@ public class Synchronizer { } private List getBlockSignatures(Peer peer, byte[] parentSignature, int numberRequested) { - // TODO numberRequested is v2+ feature - Message getSignaturesMessage = new GetSignaturesMessage(parentSignature); + // numberRequested is v2+ feature + Message getSignaturesMessage = peer.getVersion() >= 2 ? new GetSignaturesV2Message(parentSignature, numberRequested) : new GetSignaturesMessage(parentSignature); + // Message getSignaturesMessage = new GetSignaturesMessage(parentSignature); Message message = peer.getResponse(getSignaturesMessage); if (message == null || message.getType() != MessageType.SIGNATURES) diff --git a/src/main/java/org/qora/data/transaction/SetGroupTransactionData.java b/src/main/java/org/qora/data/transaction/SetGroupTransactionData.java index d15a534c..d1274a44 100644 --- a/src/main/java/org/qora/data/transaction/SetGroupTransactionData.java +++ b/src/main/java/org/qora/data/transaction/SetGroupTransactionData.java @@ -65,7 +65,7 @@ public class SetGroupTransactionData extends TransactionData { return this.previousDefaultGroupId; } - public void setPreviousDefaultGroupId(int previousDefaultGroupId) { + public void setPreviousDefaultGroupId(Integer previousDefaultGroupId) { this.previousDefaultGroupId = previousDefaultGroupId; } diff --git a/src/main/java/org/qora/group/Group.java b/src/main/java/org/qora/group/Group.java index cee0456d..f83f66e2 100644 --- a/src/main/java/org/qora/group/Group.java +++ b/src/main/java/org/qora/group/Group.java @@ -361,6 +361,9 @@ public class Group { if (Arrays.equals(groupMemberData.getReference(), updateGroupTransactionData.getSignature())) this.deleteMember(newOwner); } + + // Remove cached reference to previous group change from transaction data + updateGroupTransactionData.setGroupReference(null); } /** Reverts groupData using previous values stored in referenced transaction. */ @@ -485,27 +488,27 @@ public class Group { if (joinReference != null) { // Rebuild join-request this.rebuildJoinRequest(member, joinReference); + } else { + // Rebuild member entry using stored transaction reference + this.rebuildMember(member, groupKickTransactionData.getMemberReference()); - return; + // Revert member's defaultGroupId if necessary + Integer previousDefaultGroupId = groupKickTransactionData.getPreviousGroupId(); + if (previousDefaultGroupId != null) { + Account memberAccount = new Account(this.repository, member); + memberAccount.setDefaultGroupId(previousDefaultGroupId); + } + + if (groupKickTransactionData.getAdminReference() != null) + // Rebuild admin entry using stored transaction reference + this.rebuildAdmin(member, groupKickTransactionData.getAdminReference()); } - // Rebuild member entry using stored transaction reference - this.rebuildMember(member, groupKickTransactionData.getMemberReference()); - - // Revert member's defaultGroupId if necessary - Integer previousDefaultGroupId = groupKickTransactionData.getPreviousGroupId(); - if (previousDefaultGroupId != null) { - Account memberAccount = new Account(this.repository, member); - memberAccount.setDefaultGroupId(previousDefaultGroupId); - } - - if (groupKickTransactionData.getAdminReference() != null) - // Rebuild admin entry using stored transaction reference - this.rebuildAdmin(member, groupKickTransactionData.getAdminReference()); - // Clean cached references to transactions used to rebuild member/admin info groupKickTransactionData.setMemberReference(null); groupKickTransactionData.setAdminReference(null); + groupKickTransactionData.setJoinReference(null); + groupKickTransactionData.setPreviousGroupId(null); } public void ban(GroupBanTransactionData groupBanTransactionData) throws DataException { @@ -622,6 +625,12 @@ public class Group { } } } + + // Remove any group-related references from transaction data + groupBanTransactionData.setMemberReference(null); + groupBanTransactionData.setAdminReference(null); + groupBanTransactionData.setJoinInviteReference(null); + groupBanTransactionData.setPreviousGroupId(null); } public void cancelBan(CancelGroupBanTransactionData groupUnbanTransactionData) throws DataException { @@ -697,6 +706,10 @@ public class Group { // Delete invite this.deleteInvite(invitee); + + // Clear cached references + groupInviteTransactionData.setJoinReference(null); + groupInviteTransactionData.setPreviousGroupId(null); } public void cancelInvite(CancelGroupInviteTransactionData cancelGroupInviteTransactionData) throws DataException { @@ -769,27 +782,29 @@ public class Group { if (inviteReference == null && !groupData.getIsOpen()) { // Delete join request this.deleteJoinRequest(joiner.getAddress()); + } else { + // Any invite to rebuild? + if (inviteReference != null) { + // Rebuild invite using cache reference to invite transaction + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(inviteReference); + this.addInvite((GroupInviteTransactionData) transactionData); - return; + // Clear cached reference to invite transaction + joinGroupTransactionData.setInviteReference(null); + } + + // Delete member + this.deleteMember(joiner.getAddress()); + + // Revert joiner's defaultGroupId if necessary + Integer previousDefaultGroupId = joinGroupTransactionData.getPreviousGroupId(); + if (previousDefaultGroupId != null) + joiner.setDefaultGroupId(previousDefaultGroupId); } - // Any invite to rebuild? - if (inviteReference != null) { - // Rebuild invite using cache reference to invite transaction - TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(inviteReference); - this.addInvite((GroupInviteTransactionData) transactionData); - - // Clear cached reference to invite transaction - joinGroupTransactionData.setInviteReference(null); - } - - // Delete member - this.deleteMember(joiner.getAddress()); - - // Revert joiner's defaultGroupId if necessary - Integer previousDefaultGroupId = joinGroupTransactionData.getPreviousGroupId(); - if (previousDefaultGroupId != null) - joiner.setDefaultGroupId(previousDefaultGroupId); + // Clear cached references + joinGroupTransactionData.setInviteReference(null); + joinGroupTransactionData.setPreviousGroupId(null); } public void leave(LeaveGroupTransactionData leaveGroupTransactionData) throws DataException { @@ -842,6 +857,11 @@ public class Group { Integer previousDefaultGroupId = leaveGroupTransactionData.getPreviousGroupId(); if (previousDefaultGroupId != null) leaver.setDefaultGroupId(previousDefaultGroupId); + + // Clear cached references + leaveGroupTransactionData.setAdminReference(null); + leaveGroupTransactionData.setMemberReference(null); + leaveGroupTransactionData.setPreviousGroupId(null); } } diff --git a/src/main/java/org/qora/naming/Name.java b/src/main/java/org/qora/naming/Name.java index f9964df5..37275e0f 100644 --- a/src/main/java/org/qora/naming/Name.java +++ b/src/main/java/org/qora/naming/Name.java @@ -113,6 +113,9 @@ public class Name { // Save reverted name data this.repository.getNameRepository().save(this.nameData); + + // Remove reference to previous name-changing transaction + updateNameTransactionData.setNameReference(null); } public void sell(SellNameTransactionData sellNameTransactionData) throws DataException { @@ -133,7 +136,7 @@ public class Name { this.repository.getNameRepository().save(this.nameData); } - public void sell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException { + public void cancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException { // Mark not for-sale but leave price in case we want to orphan this.nameData.setIsForSale(false); @@ -141,7 +144,7 @@ public class Name { this.repository.getNameRepository().save(this.nameData); } - public void unsell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException { + public void uncancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException { // Mark as for-sale using existing price this.nameData.setIsForSale(true); @@ -180,6 +183,9 @@ public class Name { // Previous name reference is taken from this transaction's cached copy this.nameData.setReference(buyNameTransactionData.getNameReference()); + // Remove reference in transaction data + buyNameTransactionData.setNameReference(null); + // Revert buyer's balance Account buyer = new PublicKeyAccount(this.repository, buyNameTransactionData.getBuyerPublicKey()); buyer.setConfirmedBalance(Asset.QORA, buyer.getConfirmedBalance(Asset.QORA).add(buyNameTransactionData.getAmount())); diff --git a/src/main/java/org/qora/network/Peer.java b/src/main/java/org/qora/network/Peer.java index 8d2baf77..834c7a88 100644 --- a/src/main/java/org/qora/network/Peer.java +++ b/src/main/java/org/qora/network/Peer.java @@ -99,14 +99,9 @@ public class Peer implements Runnable { this.versionMessage = versionMessage; if (this.versionMessage.getVersionString().startsWith(Controller.VERSION_PREFIX)) { - int index = Controller.VERSION_PREFIX.length(); - try { - this.version = Integer.parseInt(this.versionMessage.getVersionString().substring(index, index + 1)); - } catch (NumberFormatException e) { - this.version = 1; - } + this.version = 2; // enhanced protocol } else { - this.version = 1; + this.version = 1; // legacy protocol } } diff --git a/src/main/java/org/qora/network/message/GetSignaturesV2Message.java b/src/main/java/org/qora/network/message/GetSignaturesV2Message.java new file mode 100644 index 00000000..fde3b253 --- /dev/null +++ b/src/main/java/org/qora/network/message/GetSignaturesV2Message.java @@ -0,0 +1,67 @@ +package org.qora.network.message; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; + +import org.qora.transform.Transformer; +import org.qora.transform.block.BlockTransformer; + +import com.google.common.primitives.Ints; + +public class GetSignaturesV2Message extends Message { + + private static final int BLOCK_SIGNATURE_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH; + private static final int NUMBER_REQUESTED_LENGTH = Transformer.INT_LENGTH; + + private byte[] parentSignature; + private int numberRequested; + + public GetSignaturesV2Message(byte[] parentSignature, int numberRequested) { + this(-1, parentSignature, numberRequested); + } + + private GetSignaturesV2Message(int id, byte[] parentSignature, int numberRequested) { + super(id, MessageType.GET_SIGNATURES_V2); + + this.parentSignature = parentSignature; + this.numberRequested = numberRequested; + } + + public byte[] getParentSignature() { + return this.parentSignature; + } + + public int getNumberRequested() { + return this.numberRequested; + } + + public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException { + if (bytes.remaining() != BLOCK_SIGNATURE_LENGTH + NUMBER_REQUESTED_LENGTH) + return null; + + byte[] parentSignature = new byte[BLOCK_SIGNATURE_LENGTH]; + bytes.get(parentSignature); + + int numberRequested = bytes.getInt(); + + return new GetSignaturesV2Message(id, parentSignature, numberRequested); + } + + @Override + protected byte[] toData() { + try { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + + bytes.write(this.parentSignature); + + bytes.write(Ints.toByteArray(this.numberRequested)); + + return bytes.toByteArray(); + } catch (IOException e) { + return null; + } + } + +} diff --git a/src/main/java/org/qora/network/message/Message.java b/src/main/java/org/qora/network/message/Message.java index 6b826d7c..8859f1d9 100644 --- a/src/main/java/org/qora/network/message/Message.java +++ b/src/main/java/org/qora/network/message/Message.java @@ -42,7 +42,8 @@ public abstract class Message { PROOF(12), PEERS_V2(13), GET_BLOCK_SUMMARIES(14), - BLOCK_SUMMARIES(15); + BLOCK_SUMMARIES(15), + GET_SIGNATURES_V2(16); public final int value; public final Method fromByteBuffer; diff --git a/src/main/java/org/qora/transaction/AccountFlagsTransaction.java b/src/main/java/org/qora/transaction/AccountFlagsTransaction.java index 55d511aa..a49e0c40 100644 --- a/src/main/java/org/qora/transaction/AccountFlagsTransaction.java +++ b/src/main/java/org/qora/transaction/AccountFlagsTransaction.java @@ -129,8 +129,9 @@ public class AccountFlagsTransaction extends Transaction { else target.setFlags(previousFlags); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(accountFlagsTransactionData); + // Remove previous flags from transaction itself + accountFlagsTransactionData.setPreviousFlags(null); + this.repository.getTransactionRepository().save(accountFlagsTransactionData); Account creator = getCreator(); diff --git a/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java b/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java index 4b703581..9e027d63 100644 --- a/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java +++ b/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java @@ -121,8 +121,7 @@ public class AddGroupAdminTransaction extends Transaction { Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupId()); group.promoteToAdmin(addGroupAdminTransactionData); - // Save this transaction - this.repository.getTransactionRepository().save(addGroupAdminTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update owner's balance Account owner = getOwner(); @@ -138,8 +137,7 @@ public class AddGroupAdminTransaction extends Transaction { Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupId()); group.unpromoteToAdmin(addGroupAdminTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(addGroupAdminTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/ArbitraryTransaction.java b/src/main/java/org/qora/transaction/ArbitraryTransaction.java index 082bbce8..e203321b 100644 --- a/src/main/java/org/qora/transaction/ArbitraryTransaction.java +++ b/src/main/java/org/qora/transaction/ArbitraryTransaction.java @@ -115,14 +115,7 @@ public class ArbitraryTransaction extends Transaction { @Override public void process() throws DataException { - /* - * Save the transaction. - * - * We might have either raw data or only a hash of data, depending on content filtering. - * If we have raw data then the repository save will store the raw data somewhere and save the data's hash in the repository. - * This also modifies the passed transactionData. - */ - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Wrap and delegate payment processing to Payment class. Always update recipients' last references regardless of asset. new Payment(this.repository).process(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(), @@ -131,16 +124,11 @@ public class ArbitraryTransaction extends Transaction { @Override public void orphan() throws DataException { - /* - * Delete the transaction. - * - * The repository will also remove the stored raw data, if present. - */ - this.repository.getTransactionRepository().delete(this.transactionData); - // Wrap and delegate payment processing to Payment class. Always revert recipients' last references regardless of asset. new Payment(this.repository).orphan(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(), arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature(), arbitraryTransactionData.getReference(), true); + + // We would save transaction in orphaned form at this point, but it hasn't been modified } // Data access diff --git a/src/main/java/org/qora/transaction/AtTransaction.java b/src/main/java/org/qora/transaction/AtTransaction.java index 3babce38..58f3fc65 100644 --- a/src/main/java/org/qora/transaction/AtTransaction.java +++ b/src/main/java/org/qora/transaction/AtTransaction.java @@ -159,8 +159,7 @@ public class AtTransaction extends Transaction { @Override public void process() throws DataException { - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified if (this.atTransactionData.getAmount() != null) { Account sender = getATAccount(); @@ -185,9 +184,6 @@ public class AtTransaction extends Transaction { @Override public void orphan() throws DataException { - // Delete this transaction - this.repository.getTransactionRepository().delete(this.transactionData); - if (this.atTransactionData.getAmount() != null) { Account sender = getATAccount(); Account recipient = getRecipient(); @@ -208,6 +204,10 @@ public class AtTransaction extends Transaction { if (assetId == Asset.QORA && Arrays.equals(recipient.getLastReference(), this.atTransactionData.getSignature())) recipient.setLastReference(null); } + + // We would save updated transaction at this point, but it hasn't been modified + + // As AT_TRANSACTIONs are really part of a block, the caller (Block) will probably delete this transaction after orphaning } } diff --git a/src/main/java/org/qora/transaction/BuyNameTransaction.java b/src/main/java/org/qora/transaction/BuyNameTransaction.java index c8c57d55..9a2fbb4c 100644 --- a/src/main/java/org/qora/transaction/BuyNameTransaction.java +++ b/src/main/java/org/qora/transaction/BuyNameTransaction.java @@ -127,7 +127,7 @@ public class BuyNameTransaction extends Transaction { Name name = new Name(this.repository, buyNameTransactionData.getName()); name.buy(buyNameTransactionData); - // Save this transaction, now with updated "name reference" to previous transaction that updated name + // Save transaction with updated "name reference" pointing to previous transaction that updated name this.repository.getTransactionRepository().save(buyNameTransactionData); // Update buyer's balance @@ -144,8 +144,8 @@ public class BuyNameTransaction extends Transaction { Name name = new Name(this.repository, buyNameTransactionData.getName()); name.unbuy(buyNameTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(buyNameTransactionData); + // Save this transaction, with removed "name reference" + this.repository.getTransactionRepository().save(buyNameTransactionData); // Update buyer's balance Account buyer = getBuyer(); diff --git a/src/main/java/org/qora/transaction/CancelAssetOrderTransaction.java b/src/main/java/org/qora/transaction/CancelAssetOrderTransaction.java index 970f8edf..0e5c4337 100644 --- a/src/main/java/org/qora/transaction/CancelAssetOrderTransaction.java +++ b/src/main/java/org/qora/transaction/CancelAssetOrderTransaction.java @@ -101,8 +101,7 @@ public class CancelAssetOrderTransaction extends Transaction { public void process() throws DataException { Account creator = getCreator(); - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update creator's balance regarding fee creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(cancelOrderTransactionData.getFee())); @@ -120,8 +119,7 @@ public class CancelAssetOrderTransaction extends Transaction { public void orphan() throws DataException { Account creator = getCreator(); - // Save this transaction itself - this.repository.getTransactionRepository().delete(this.transactionData); + // We would save transaction in orphaned form at this point, but it hasn't been modified // Update creator's balance regarding fee creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(cancelOrderTransactionData.getFee())); diff --git a/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java b/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java index 79ccf456..9121999d 100644 --- a/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java +++ b/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java @@ -134,8 +134,8 @@ public class CancelGroupBanTransaction extends Transaction { Group group = new Group(this.repository, groupUnbanTransactionData.getGroupId()); group.uncancelBan(groupUnbanTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(groupUnbanTransactionData); + // Save this transaction with removed member/admin references + this.repository.getTransactionRepository().save(groupUnbanTransactionData); // Update admin's balance Account admin = getAdmin(); diff --git a/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java b/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java index d4cbe20b..f7c876f0 100644 --- a/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java +++ b/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java @@ -134,8 +134,8 @@ public class CancelGroupInviteTransaction extends Transaction { Group group = new Group(this.repository, cancelGroupInviteTransactionData.getGroupId()); group.uncancelInvite(cancelGroupInviteTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(cancelGroupInviteTransactionData); + // Save this transaction with removed member/admin references + this.repository.getTransactionRepository().save(cancelGroupInviteTransactionData); // Update admin's balance Account admin = getAdmin(); diff --git a/src/main/java/org/qora/transaction/CancelSellNameTransaction.java b/src/main/java/org/qora/transaction/CancelSellNameTransaction.java index 9492d6f5..1331982b 100644 --- a/src/main/java/org/qora/transaction/CancelSellNameTransaction.java +++ b/src/main/java/org/qora/transaction/CancelSellNameTransaction.java @@ -112,9 +112,9 @@ public class CancelSellNameTransaction extends Transaction { public void process() throws DataException { // Update Name Name name = new Name(this.repository, cancelSellNameTransactionData.getName()); - name.sell(cancelSellNameTransactionData); + name.cancelSell(cancelSellNameTransactionData); - // Save this transaction, now with updated "name reference" to previous transaction that updated name + // Save this transaction, with updated "name reference" to previous transaction that updated name this.repository.getTransactionRepository().save(cancelSellNameTransactionData); // Update owner's balance @@ -129,10 +129,10 @@ public class CancelSellNameTransaction extends Transaction { public void orphan() throws DataException { // Revert name Name name = new Name(this.repository, cancelSellNameTransactionData.getName()); - name.unsell(cancelSellNameTransactionData); + name.uncancelSell(cancelSellNameTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(cancelSellNameTransactionData); + // Save this transaction, with removed "name reference" + this.repository.getTransactionRepository().save(cancelSellNameTransactionData); // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/CreateAssetOrderTransaction.java b/src/main/java/org/qora/transaction/CreateAssetOrderTransaction.java index 47d878b4..8f561cb2 100644 --- a/src/main/java/org/qora/transaction/CreateAssetOrderTransaction.java +++ b/src/main/java/org/qora/transaction/CreateAssetOrderTransaction.java @@ -186,8 +186,7 @@ public class CreateAssetOrderTransaction extends Transaction { // Update creator's last reference creator.setLastReference(createOrderTransactionData.getSignature()); - // Save this transaction itself - this.repository.getTransactionRepository().save(createOrderTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Order Id is transaction's signature byte[] orderId = createOrderTransactionData.getSignature(); @@ -217,8 +216,7 @@ public class CreateAssetOrderTransaction extends Transaction { OrderData orderData = this.repository.getAssetRepository().fromOrderId(orderId); new Order(this.repository, orderData).orphan(); - // Delete this transaction - this.repository.getTransactionRepository().delete(createOrderTransactionData); + // We would save updated transaction at this point, but it hasn't been modified } } diff --git a/src/main/java/org/qora/transaction/CreateGroupTransaction.java b/src/main/java/org/qora/transaction/CreateGroupTransaction.java index 5bb29987..669d557b 100644 --- a/src/main/java/org/qora/transaction/CreateGroupTransaction.java +++ b/src/main/java/org/qora/transaction/CreateGroupTransaction.java @@ -139,8 +139,11 @@ public class CreateGroupTransaction extends Transaction { Group group = new Group(this.repository, createGroupTransactionData.getGroupId()); group.uncreate(); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(createGroupTransactionData); + // Remove assigned group ID from transaction record + createGroupTransactionData.setGroupId(null); + + // Save this transaction with removed group ID + this.repository.getTransactionRepository().save(createGroupTransactionData); // Update creator's balance Account creator = getCreator(); diff --git a/src/main/java/org/qora/transaction/CreatePollTransaction.java b/src/main/java/org/qora/transaction/CreatePollTransaction.java index 24b25978..f0bbd6ec 100644 --- a/src/main/java/org/qora/transaction/CreatePollTransaction.java +++ b/src/main/java/org/qora/transaction/CreatePollTransaction.java @@ -153,8 +153,7 @@ public class CreatePollTransaction extends Transaction { Poll poll = new Poll(this.repository, createPollTransactionData); poll.publish(); - // Save this transaction, now with corresponding pollId - this.repository.getTransactionRepository().save(createPollTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update creator's balance Account creator = getCreator(); @@ -170,8 +169,7 @@ public class CreatePollTransaction extends Transaction { Poll poll = new Poll(this.repository, createPollTransactionData.getPollName()); poll.unpublish(); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(createPollTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update creator's balance Account creator = getCreator(); diff --git a/src/main/java/org/qora/transaction/DeployAtTransaction.java b/src/main/java/org/qora/transaction/DeployAtTransaction.java index d30c8ccd..61bc6531 100644 --- a/src/main/java/org/qora/transaction/DeployAtTransaction.java +++ b/src/main/java/org/qora/transaction/DeployAtTransaction.java @@ -216,8 +216,7 @@ public class DeployAtTransaction extends Transaction { AT at = new AT(this.repository, this.deployATTransactionData); at.deploy(); - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified long assetId = deployATTransactionData.getAssetId(); @@ -243,8 +242,7 @@ public class DeployAtTransaction extends Transaction { AT at = new AT(this.repository, this.deployATTransactionData); at.undeploy(); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(deployATTransactionData); + // We would save updated transaction at this point, but it hasn't been modified long assetId = deployATTransactionData.getAssetId(); diff --git a/src/main/java/org/qora/transaction/EnableForgingTransaction.java b/src/main/java/org/qora/transaction/EnableForgingTransaction.java index 46b34494..22eb1944 100644 --- a/src/main/java/org/qora/transaction/EnableForgingTransaction.java +++ b/src/main/java/org/qora/transaction/EnableForgingTransaction.java @@ -152,8 +152,7 @@ public class EnableForgingTransaction extends Transaction { target.setFlags(targetFlags); target.setForgingEnabler(creator.getAddress()); - // Save this transaction - this.repository.getTransactionRepository().save(enableForgingTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update creator's balance creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(enableForgingTransactionData.getFee())); @@ -182,8 +181,7 @@ public class EnableForgingTransaction extends Transaction { target.setFlags(targetFlags); target.setForgingEnabler(null); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(enableForgingTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update creator's balance creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(enableForgingTransactionData.getFee())); diff --git a/src/main/java/org/qora/transaction/GenesisTransaction.java b/src/main/java/org/qora/transaction/GenesisTransaction.java index c39ed7eb..2c9048a3 100644 --- a/src/main/java/org/qora/transaction/GenesisTransaction.java +++ b/src/main/java/org/qora/transaction/GenesisTransaction.java @@ -136,8 +136,7 @@ public class GenesisTransaction extends Transaction { @Override public void process() throws DataException { - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified Account recipient = new Account(repository, genesisTransactionData.getRecipient()); @@ -150,8 +149,7 @@ public class GenesisTransaction extends Transaction { @Override public void orphan() throws DataException { - // Delete this transaction - this.repository.getTransactionRepository().delete(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Delete recipient's account (and balance) this.repository.getAccountRepository().delete(genesisTransactionData.getRecipient()); diff --git a/src/main/java/org/qora/transaction/GroupApprovalTransaction.java b/src/main/java/org/qora/transaction/GroupApprovalTransaction.java index 48e39b3e..76ba1a68 100644 --- a/src/main/java/org/qora/transaction/GroupApprovalTransaction.java +++ b/src/main/java/org/qora/transaction/GroupApprovalTransaction.java @@ -115,10 +115,9 @@ public class GroupApprovalTransaction extends Transaction { @Override public void orphan() throws DataException { - // Revert? - - // Delete this transaction itself - this.repository.getTransactionRepository().delete(groupApprovalTransactionData); + // Save this transaction with removed prior reference + groupApprovalTransactionData.setPriorReference(null); + this.repository.getTransactionRepository().save(groupApprovalTransactionData); // Update admin's balance Account admin = getAdmin(); diff --git a/src/main/java/org/qora/transaction/GroupBanTransaction.java b/src/main/java/org/qora/transaction/GroupBanTransaction.java index 12bb4883..9231d5cf 100644 --- a/src/main/java/org/qora/transaction/GroupBanTransaction.java +++ b/src/main/java/org/qora/transaction/GroupBanTransaction.java @@ -135,8 +135,8 @@ public class GroupBanTransaction extends Transaction { Group group = new Group(this.repository, groupBanTransactionData.getGroupId()); group.unban(groupBanTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(groupBanTransactionData); + // Save this transaction with removed member/admin references + this.repository.getTransactionRepository().save(groupBanTransactionData); // Update admin's balance Account admin = getAdmin(); diff --git a/src/main/java/org/qora/transaction/GroupInviteTransaction.java b/src/main/java/org/qora/transaction/GroupInviteTransaction.java index fa26db25..fb39f809 100644 --- a/src/main/java/org/qora/transaction/GroupInviteTransaction.java +++ b/src/main/java/org/qora/transaction/GroupInviteTransaction.java @@ -141,8 +141,8 @@ public class GroupInviteTransaction extends Transaction { Group group = new Group(this.repository, groupInviteTransactionData.getGroupId()); group.uninvite(groupInviteTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(groupInviteTransactionData); + // Save this transaction with removed member/admin references + this.repository.getTransactionRepository().save(groupInviteTransactionData); // Update admin's balance Account admin = getAdmin(); diff --git a/src/main/java/org/qora/transaction/GroupKickTransaction.java b/src/main/java/org/qora/transaction/GroupKickTransaction.java index 5063656e..2c8c2b14 100644 --- a/src/main/java/org/qora/transaction/GroupKickTransaction.java +++ b/src/main/java/org/qora/transaction/GroupKickTransaction.java @@ -141,8 +141,8 @@ public class GroupKickTransaction extends Transaction { Group group = new Group(this.repository, groupKickTransactionData.getGroupId()); group.unkick(groupKickTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(groupKickTransactionData); + // Save this transaction with removed member/admin references + this.repository.getTransactionRepository().save(groupKickTransactionData); // Update admin's balance Account admin = getAdmin(); diff --git a/src/main/java/org/qora/transaction/IssueAssetTransaction.java b/src/main/java/org/qora/transaction/IssueAssetTransaction.java index 345b189b..37ef0139 100644 --- a/src/main/java/org/qora/transaction/IssueAssetTransaction.java +++ b/src/main/java/org/qora/transaction/IssueAssetTransaction.java @@ -170,8 +170,11 @@ public class IssueAssetTransaction extends Transaction { Asset asset = new Asset(this.repository, issueAssetTransactionData.getAssetId()); asset.deissue(); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(issueAssetTransactionData); + // Remove assigned asset ID from transaction info + issueAssetTransactionData.setAssetId(null); + + // Save this transaction, with removed assetId + this.repository.getTransactionRepository().save(issueAssetTransactionData); // Update issuer's balance Account issuer = getIssuer(); diff --git a/src/main/java/org/qora/transaction/JoinGroupTransaction.java b/src/main/java/org/qora/transaction/JoinGroupTransaction.java index 7cf0c4cd..c63f17d1 100644 --- a/src/main/java/org/qora/transaction/JoinGroupTransaction.java +++ b/src/main/java/org/qora/transaction/JoinGroupTransaction.java @@ -104,7 +104,7 @@ public class JoinGroupTransaction extends Transaction { Group group = new Group(this.repository, joinGroupTransactionData.getGroupId()); group.join(joinGroupTransactionData); - // Save this transaction + // Save this transaction with cached references to transactions that can help restore state this.repository.getTransactionRepository().save(joinGroupTransactionData); // Update joiner's balance @@ -122,8 +122,8 @@ public class JoinGroupTransaction extends Transaction { Group group = new Group(this.repository, joinGroupTransactionData.getGroupId()); group.unjoin(joinGroupTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(joinGroupTransactionData); + // Save this transaction with removed references + this.repository.getTransactionRepository().save(joinGroupTransactionData); // Update joiner's balance Account joiner = getJoiner(); diff --git a/src/main/java/org/qora/transaction/LeaveGroupTransaction.java b/src/main/java/org/qora/transaction/LeaveGroupTransaction.java index 6f79e42c..d708dad3 100644 --- a/src/main/java/org/qora/transaction/LeaveGroupTransaction.java +++ b/src/main/java/org/qora/transaction/LeaveGroupTransaction.java @@ -120,8 +120,8 @@ public class LeaveGroupTransaction extends Transaction { Group group = new Group(this.repository, leaveGroupTransactionData.getGroupId()); group.unleave(leaveGroupTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(leaveGroupTransactionData); + // Save this transaction with removed member/admin references + this.repository.getTransactionRepository().save(leaveGroupTransactionData); // Update leaver's balance Account leaver = getLeaver(); diff --git a/src/main/java/org/qora/transaction/MessageTransaction.java b/src/main/java/org/qora/transaction/MessageTransaction.java index bce108dc..0c919ef1 100644 --- a/src/main/java/org/qora/transaction/MessageTransaction.java +++ b/src/main/java/org/qora/transaction/MessageTransaction.java @@ -116,8 +116,7 @@ public class MessageTransaction extends Transaction { @Override public void process() throws DataException { - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Wrap and delegate payment processing to Payment class. Only update recipient's last reference if transferring QORA. new Payment(this.repository).process(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(), @@ -126,12 +125,11 @@ public class MessageTransaction extends Transaction { @Override public void orphan() throws DataException { - // Delete this transaction itself - this.repository.getTransactionRepository().delete(this.transactionData); - // Wrap and delegate payment processing to Payment class. Only revert recipient's last reference if transferring QORA. new Payment(this.repository).orphan(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(), messageTransactionData.getSignature(), messageTransactionData.getReference(), false); + + // We would save updated transaction at this point, but it hasn't been modified } } diff --git a/src/main/java/org/qora/transaction/MultiPaymentTransaction.java b/src/main/java/org/qora/transaction/MultiPaymentTransaction.java index 3db33de4..aa858d8d 100644 --- a/src/main/java/org/qora/transaction/MultiPaymentTransaction.java +++ b/src/main/java/org/qora/transaction/MultiPaymentTransaction.java @@ -116,8 +116,7 @@ public class MultiPaymentTransaction extends Transaction { @Override public void process() throws DataException { - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Wrap and delegate payment processing to Payment class. Always update recipients' last references regardless of asset. new Payment(this.repository).process(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(), @@ -126,12 +125,11 @@ public class MultiPaymentTransaction extends Transaction { @Override public void orphan() throws DataException { - // Delete this transaction itself - this.repository.getTransactionRepository().delete(this.transactionData); - // Wrap and delegate payment processing to Payment class. Always revert recipients' last references regardless of asset. new Payment(this.repository).orphan(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(), multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature(), multiPaymentTransactionData.getReference(), true); + + // We would save updated transaction at this point, but it hasn't been modified } } diff --git a/src/main/java/org/qora/transaction/PaymentTransaction.java b/src/main/java/org/qora/transaction/PaymentTransaction.java index 2772b5db..ce1c1f54 100644 --- a/src/main/java/org/qora/transaction/PaymentTransaction.java +++ b/src/main/java/org/qora/transaction/PaymentTransaction.java @@ -88,8 +88,7 @@ public class PaymentTransaction extends Transaction { @Override public void process() throws DataException { - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Wrap and delegate payment processing to Payment class. Only update recipient's last reference if transferring QORA. new Payment(this.repository).process(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee(), @@ -98,12 +97,11 @@ public class PaymentTransaction extends Transaction { @Override public void orphan() throws DataException { - // Delete this transaction - this.repository.getTransactionRepository().delete(this.transactionData); - // Wrap and delegate payment processing to Payment class. Only revert recipient's last reference if transferring QORA. new Payment(this.repository).orphan(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee(), paymentTransactionData.getSignature(), paymentTransactionData.getReference(), false); + + // We would save updated transaction at this point, but it hasn't been modified } } diff --git a/src/main/java/org/qora/transaction/ProxyForgingTransaction.java b/src/main/java/org/qora/transaction/ProxyForgingTransaction.java index 4f66285a..17ec5071 100644 --- a/src/main/java/org/qora/transaction/ProxyForgingTransaction.java +++ b/src/main/java/org/qora/transaction/ProxyForgingTransaction.java @@ -163,8 +163,9 @@ public class ProxyForgingTransaction extends Transaction { this.repository.getAccountRepository().delete(forger.getPublicKey(), proxyForgingTransactionData.getRecipient()); } - // Delete this transaction itself - this.repository.getTransactionRepository().delete(proxyForgingTransactionData); + // Save this transaction, with removed previous share info + proxyForgingTransactionData.setPreviousShare(null); + this.repository.getTransactionRepository().save(proxyForgingTransactionData); // Update forger's balance forger.setConfirmedBalance(Asset.QORA, forger.getConfirmedBalance(Asset.QORA).add(proxyForgingTransactionData.getFee())); diff --git a/src/main/java/org/qora/transaction/RegisterNameTransaction.java b/src/main/java/org/qora/transaction/RegisterNameTransaction.java index cd2e8d93..eb7d065e 100644 --- a/src/main/java/org/qora/transaction/RegisterNameTransaction.java +++ b/src/main/java/org/qora/transaction/RegisterNameTransaction.java @@ -125,8 +125,7 @@ public class RegisterNameTransaction extends Transaction { Name name = new Name(this.repository, registerNameTransactionData); name.register(); - // Save this transaction - this.repository.getTransactionRepository().save(registerNameTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update registrant's balance Account registrant = getRegistrant(); @@ -142,8 +141,7 @@ public class RegisterNameTransaction extends Transaction { Name name = new Name(this.repository, registerNameTransactionData.getName()); name.unregister(); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(registerNameTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update registrant's balance Account registrant = getRegistrant(); diff --git a/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java b/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java index 412c1969..ec848352 100644 --- a/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java +++ b/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java @@ -117,7 +117,7 @@ public class RemoveGroupAdminTransaction extends Transaction { Group group = new Group(this.repository, removeGroupAdminTransactionData.getGroupId()); group.demoteFromAdmin(removeGroupAdminTransactionData); - // Save this transaction + // Save this transaction with cached references to transactions that can help restore state this.repository.getTransactionRepository().save(removeGroupAdminTransactionData); // Update owner's balance @@ -134,8 +134,8 @@ public class RemoveGroupAdminTransaction extends Transaction { Group group = new Group(this.repository, removeGroupAdminTransactionData.getGroupId()); group.undemoteFromAdmin(removeGroupAdminTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(removeGroupAdminTransactionData); + // Save this transaction with removed group references + this.repository.getTransactionRepository().save(removeGroupAdminTransactionData); // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/SellNameTransaction.java b/src/main/java/org/qora/transaction/SellNameTransaction.java index ac3b01b3..43a21df7 100644 --- a/src/main/java/org/qora/transaction/SellNameTransaction.java +++ b/src/main/java/org/qora/transaction/SellNameTransaction.java @@ -118,12 +118,11 @@ public class SellNameTransaction extends Transaction { @Override public void process() throws DataException { - // Update Name + // Sell Name Name name = new Name(this.repository, sellNameTransactionData.getName()); name.sell(sellNameTransactionData); - // Save this transaction, now with updated "name reference" to previous transaction that updated name - this.repository.getTransactionRepository().save(sellNameTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update owner's balance Account owner = getOwner(); @@ -139,8 +138,7 @@ public class SellNameTransaction extends Transaction { Name name = new Name(this.repository, sellNameTransactionData.getName()); name.unsell(sellNameTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(sellNameTransactionData); + // We would save updated transaction at this point, but it hasn't been modified // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/SetGroupTransaction.java b/src/main/java/org/qora/transaction/SetGroupTransaction.java index d9412134..ba89dd55 100644 --- a/src/main/java/org/qora/transaction/SetGroupTransaction.java +++ b/src/main/java/org/qora/transaction/SetGroupTransaction.java @@ -119,8 +119,9 @@ public class SetGroupTransaction extends Transaction { creator.setDefaultGroupId(previousDefaultGroupId); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(setGroupTransactionData); + // Save this transaction with removed previous defaultGroupId value + setGroupTransactionData.setPreviousDefaultGroupId(null); + this.repository.getTransactionRepository().save(setGroupTransactionData); // Update creator's balance creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(setGroupTransactionData.getFee())); diff --git a/src/main/java/org/qora/transaction/TransferAssetTransaction.java b/src/main/java/org/qora/transaction/TransferAssetTransaction.java index 031e4d61..2612d510 100644 --- a/src/main/java/org/qora/transaction/TransferAssetTransaction.java +++ b/src/main/java/org/qora/transaction/TransferAssetTransaction.java @@ -101,8 +101,7 @@ public class TransferAssetTransaction extends Transaction { @Override public void process() throws DataException { - // Save this transaction itself - this.repository.getTransactionRepository().save(this.transactionData); + // We would save updated transaction at this point, but it hasn't been modified // Wrap asset transfer as a payment and delegate processing to Payment class. Only update recipient's last reference if transferring QORA. new Payment(this.repository).process(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee(), @@ -111,12 +110,11 @@ public class TransferAssetTransaction extends Transaction { @Override public void orphan() throws DataException { - // Delete this transaction itself - this.repository.getTransactionRepository().delete(this.transactionData); - // Wrap asset transfer as a payment and delegate processing to Payment class. Only revert recipient's last reference if transferring QORA. new Payment(this.repository).orphan(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee(), transferAssetTransactionData.getSignature(), transferAssetTransactionData.getReference(), false); + + // We would save updated transaction at this point, but it hasn't been modified } } diff --git a/src/main/java/org/qora/transaction/UpdateAssetTransaction.java b/src/main/java/org/qora/transaction/UpdateAssetTransaction.java index 701bbfdd..b9fbe909 100644 --- a/src/main/java/org/qora/transaction/UpdateAssetTransaction.java +++ b/src/main/java/org/qora/transaction/UpdateAssetTransaction.java @@ -130,8 +130,7 @@ public class UpdateAssetTransaction extends Transaction { Asset asset = new Asset(this.repository, updateAssetTransactionData.getAssetId()); asset.update(updateAssetTransactionData); - // Save this transaction, now with updated "name reference" to previous - // transaction that updated name + // Save this transaction, with updated "name reference" to previous transaction that updated name this.repository.getTransactionRepository().save(updateAssetTransactionData); // Update old owner's balance @@ -149,8 +148,8 @@ public class UpdateAssetTransaction extends Transaction { Asset asset = new Asset(this.repository, updateAssetTransactionData.getAssetId()); asset.revert(updateAssetTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(updateAssetTransactionData); + // Save this transaction, with removed "name reference" to previous transaction that updated name + this.repository.getTransactionRepository().save(updateAssetTransactionData); // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/UpdateGroupTransaction.java b/src/main/java/org/qora/transaction/UpdateGroupTransaction.java index 483c54a9..9e56c327 100644 --- a/src/main/java/org/qora/transaction/UpdateGroupTransaction.java +++ b/src/main/java/org/qora/transaction/UpdateGroupTransaction.java @@ -149,8 +149,8 @@ public class UpdateGroupTransaction extends Transaction { Group group = new Group(this.repository, updateGroupTransactionData.getGroupId()); group.unupdateGroup(updateGroupTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(updateGroupTransactionData); + // Save this transaction, now with removed "group reference" + this.repository.getTransactionRepository().save(updateGroupTransactionData); // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/UpdateNameTransaction.java b/src/main/java/org/qora/transaction/UpdateNameTransaction.java index fe258d35..25b4de87 100644 --- a/src/main/java/org/qora/transaction/UpdateNameTransaction.java +++ b/src/main/java/org/qora/transaction/UpdateNameTransaction.java @@ -151,8 +151,8 @@ public class UpdateNameTransaction extends Transaction { Name name = new Name(this.repository, updateNameTransactionData.getName()); name.revert(updateNameTransactionData); - // Delete this transaction itself - this.repository.getTransactionRepository().delete(updateNameTransactionData); + // Save this transaction, now with removed "name reference" + this.repository.getTransactionRepository().save(updateNameTransactionData); // Update owner's balance Account owner = getOwner(); diff --git a/src/main/java/org/qora/transaction/VoteOnPollTransaction.java b/src/main/java/org/qora/transaction/VoteOnPollTransaction.java index faef2d23..773ae40f 100644 --- a/src/main/java/org/qora/transaction/VoteOnPollTransaction.java +++ b/src/main/java/org/qora/transaction/VoteOnPollTransaction.java @@ -177,8 +177,9 @@ public class VoteOnPollTransaction extends Transaction { votingRepository.delete(voteOnPollTransactionData.getPollName(), voteOnPollTransactionData.getVoterPublicKey()); } - // Delete this transaction itself - this.repository.getTransactionRepository().delete(voteOnPollTransactionData); + // Save this transaction, with removed previous vote info + voteOnPollTransactionData.setPreviousOptionIndex(null); + this.repository.getTransactionRepository().save(voteOnPollTransactionData); } } diff --git a/src/test/java/org/qora/test/BlockTests.java b/src/test/java/org/qora/test/BlockTests.java index b228feca..c5fc1e39 100644 --- a/src/test/java/org/qora/test/BlockTests.java +++ b/src/test/java/org/qora/test/BlockTests.java @@ -3,23 +3,37 @@ package org.qora.test; import java.math.BigDecimal; import java.util.List; +import org.junit.Before; import org.junit.Test; +import org.qora.account.PrivateKeyAccount; import org.qora.block.Block; +import org.qora.block.BlockGenerator; import org.qora.block.GenesisBlock; +import org.qora.data.at.ATStateData; import org.qora.data.block.BlockData; import org.qora.data.transaction.TransactionData; import org.qora.repository.DataException; import org.qora.repository.Repository; import org.qora.repository.RepositoryManager; import org.qora.test.common.Common; +import org.qora.test.common.TransactionUtils; import org.qora.transaction.Transaction; +import org.qora.transaction.Transaction.TransactionType; import org.qora.transform.TransformationException; import org.qora.transform.block.BlockTransformer; +import org.qora.transform.transaction.TransactionTransformer; +import org.qora.utils.Base58; +import org.qora.utils.Triple; import static org.junit.Assert.*; public class BlockTests extends Common { + @Before + public void beforeTest() throws DataException { + Common.useDefaultSettings(); + } + @Test public void testGenesisBlockTransactions() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { @@ -33,20 +47,24 @@ public class BlockTests extends Common { List transactions = block.getTransactions(); assertNotNull(transactions); + byte[] lastGenesisSignature = null; for (Transaction transaction : transactions) { assertNotNull(transaction); TransactionData transactionData = transaction.getTransactionData(); - assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType()); + if (transactionData.getType() != Transaction.TransactionType.GENESIS) + continue; + assertTrue(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0); - assertNull(transactionData.getReference()); assertTrue(transaction.isSignatureValid()); assertEquals(Transaction.ValidationResult.OK, transaction.isValid()); + + lastGenesisSignature = transactionData.getSignature(); } - // Attempt to load first transaction directly from database - TransactionData transactionData = repository.getTransactionRepository().fromSignature(transactions.get(0).getTransactionData().getSignature()); + // Attempt to load last GENESIS transaction directly from database + TransactionData transactionData = repository.getTransactionRepository().fromSignature(lastGenesisSignature); assertNotNull(transactionData); assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType()); @@ -61,61 +79,59 @@ public class BlockTests extends Common { } } - @Test - public void testBlockPaymentTransactions() throws DataException { - try (final Repository repository = RepositoryManager.getRepository()) { - // Block 949 has lots of varied transactions - // Blocks 390 & 754 have only payment transactions - BlockData blockData = repository.getBlockRepository().fromHeight(754); - assertNotNull("Block 754 is required for this test", blockData); - - Block block = new Block(repository, blockData); - assertTrue(block.isSignatureValid()); - - List transactions = block.getTransactions(); - assertNotNull(transactions); - - for (Transaction transaction : transactions) { - assertNotNull(transaction); - - TransactionData transactionData = transaction.getTransactionData(); - - assertEquals(Transaction.TransactionType.PAYMENT, transactionData.getType()); - assertFalse(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0); - assertNotNull(transactionData.getReference()); - - assertTrue(transaction.isSignatureValid()); - } - - // Attempt to load first transaction directly from database - TransactionData transactionData = repository.getTransactionRepository().fromSignature(transactions.get(0).getTransactionData().getSignature()); - assertNotNull(transactionData); - - assertEquals(Transaction.TransactionType.PAYMENT, transactionData.getType()); - assertFalse(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0); - assertNotNull(transactionData.getReference()); - - Transaction transaction = Transaction.fromData(repository, transactionData); - assertNotNull(transaction); - - assertTrue(transaction.isSignatureValid()); - } - } - @Test public void testBlockSerialization() throws DataException, TransformationException { try (final Repository repository = RepositoryManager.getRepository()) { - // Block 949 has lots of varied transactions - // Blocks 390 & 754 have only payment transactions - BlockData blockData = repository.getBlockRepository().fromHeight(754); - assertNotNull("Block 754 is required for this test", blockData); + PrivateKeyAccount signingAccount = Common.getTestAccount(repository, "alice"); + // TODO: Fill block with random, valid transactions of every type (except GENESIS or AT) + for (Transaction.TransactionType txType : Transaction.TransactionType.values()) { + if (txType == TransactionType.GENESIS || txType == TransactionType.AT) + continue; + + TransactionData transactionData = TransactionUtils.randomTransaction(repository, signingAccount, txType, true); + Transaction transaction = Transaction.fromData(repository, transactionData); + transaction.sign(signingAccount); + + repository.getTransactionRepository().save(transactionData); + repository.getTransactionRepository().unconfirmTransaction(transactionData); + repository.saveChanges(); + + // TODO: more transactions + break; + } + + // We might need to wait until transactions' timestamps are valid for the block we're about to generate + try { + Thread.sleep(1L); + } catch (InterruptedException e) { + } + + BlockGenerator.generateTestingBlock(repository, signingAccount); + + BlockData blockData = repository.getBlockRepository().getLastBlock(); Block block = new Block(repository, blockData); assertTrue(block.isSignatureValid()); byte[] bytes = BlockTransformer.toBytes(block); assertEquals(BlockTransformer.getDataLength(block), bytes.length); + + Triple, List> blockInfo = BlockTransformer.fromBytes(bytes); + + // Compare transactions + List deserializedTransactions = blockInfo.getB(); + assertEquals("Transaction count differs", blockData.getTransactionCount(), deserializedTransactions.size()); + + for (int i = 0; i < blockData.getTransactionCount(); ++i) { + TransactionData deserializedTransactionData = deserializedTransactions.get(i); + Transaction originalTransaction = block.getTransactions().get(i); + TransactionData originalTransactionData = originalTransaction.getTransactionData(); + + assertEquals("Transaction signature differs", Base58.encode(originalTransactionData.getSignature()), Base58.encode(deserializedTransactionData.getSignature())); + assertEquals("Transaction declared length differs", TransactionTransformer.getDataLength(originalTransactionData), TransactionTransformer.getDataLength(deserializedTransactionData)); + assertEquals("Transaction serialized length differs", TransactionTransformer.toBytes(originalTransactionData).length, TransactionTransformer.toBytes(deserializedTransactionData).length); + } } } diff --git a/src/test/java/org/qora/test/BlockchainTests.java b/src/test/java/org/qora/test/BlockchainTests.java deleted file mode 100644 index c6e45138..00000000 --- a/src/test/java/org/qora/test/BlockchainTests.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.qora.test; - -import org.junit.Test; -import org.qora.block.BlockChain; -import org.qora.repository.DataException; -import org.qora.test.common.Common; - -public class BlockchainTests extends Common { - - @Test - public void testValidateOrRebuild() throws DataException { - BlockChain.validate(); - } - -} diff --git a/src/test/java/org/qora/test/GenesisTests.java b/src/test/java/org/qora/test/GenesisTests.java deleted file mode 100644 index 65c1d8b5..00000000 --- a/src/test/java/org/qora/test/GenesisTests.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.qora.test; - -import java.math.BigDecimal; -import java.util.List; - -import org.junit.Test; -import org.qora.block.Block; -import org.qora.block.GenesisBlock; -import org.qora.data.transaction.TransactionData; -import org.qora.repository.DataException; -import org.qora.repository.Repository; -import org.qora.repository.RepositoryManager; -import org.qora.test.common.Common; -import org.qora.transaction.Transaction; - -import static org.junit.Assert.*; - -public class GenesisTests extends Common { - - @Test - public void testGenesisBlockTransactions() throws DataException { - try (final Repository repository = RepositoryManager.getRepository()) { - assertEquals("Blockchain should be empty for this test", 0, repository.getBlockRepository().getBlockchainHeight()); - - GenesisBlock block = GenesisBlock.getInstance(repository); - - assertNotNull("No genesis block?", block); - assertTrue(block.isSignatureValid()); - // Note: only true if blockchain is empty - assertEquals("Block invalid", Block.ValidationResult.OK, block.isValid()); - - List transactions = block.getTransactions(); - assertNotNull("No transactions?", transactions); - - for (Transaction transaction : transactions) { - assertNotNull(transaction); - - TransactionData transactionData = transaction.getTransactionData(); - - assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType()); - assertTrue(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0); - assertNull(transactionData.getReference()); - assertNotNull(transactionData.getSignature()); - assertTrue(transaction.isSignatureValid()); - assertEquals(Transaction.ValidationResult.OK, transaction.isValid()); - } - - // Actually try to process genesis block onto empty blockchain - block.process(); - repository.saveChanges(); - } - } - -} diff --git a/src/test/java/org/qora/test/LoadTests.java b/src/test/java/org/qora/test/LoadTests.java deleted file mode 100644 index c911aa6d..00000000 --- a/src/test/java/org/qora/test/LoadTests.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.qora.test; - -import org.junit.Test; -import org.qora.account.PublicKeyAccount; -import org.qora.data.transaction.PaymentTransactionData; -import org.qora.data.transaction.TransactionData; -import org.qora.repository.DataException; -import org.qora.repository.Repository; -import org.qora.repository.RepositoryManager; -import org.qora.repository.TransactionRepository; -import org.qora.test.common.Common; -import org.qora.transaction.Transaction.TransactionType; -import org.qora.utils.Base58; - -import static org.junit.Assert.*; - -public class LoadTests extends Common { - - @Test - public void testLoadPaymentTransaction() throws DataException { - try (final Repository repository = RepositoryManager.getRepository()) { - TransactionRepository transactionRepository = repository.getTransactionRepository(); - - assertTrue("Migrate from old database to at least block 49778 before running this test", repository.getBlockRepository().getBlockchainHeight() >= 49778); - - String signature58 = "1211ZPwG3hk5evWzXCZi9hMDRpwumWmkENjwWkeTCik9xA5uoYnxzF7rwR5hmHH3kG2RXo7ToCAaRc7dvnynByJt"; - byte[] signature = Base58.decode(signature58); - - TransactionData transactionData = transactionRepository.fromSignature(signature); - assertNotNull("Transaction data not loaded from repository", transactionData); - assertEquals("Transaction data not PAYMENT type", TransactionType.PAYMENT, transactionData.getType()); - assertEquals("QXwu8924WdgPoRmtiWQBUMF6eedmp1Hu2E", PublicKeyAccount.getAddress(transactionData.getCreatorPublicKey())); - - PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData; - - assertNotNull(paymentTransactionData); - assertEquals("QXwu8924WdgPoRmtiWQBUMF6eedmp1Hu2E", PublicKeyAccount.getAddress(paymentTransactionData.getSenderPublicKey())); - assertEquals("QZsv8vbJ6QfrBNba4LMp5UtHhAzhrxvVUU", paymentTransactionData.getRecipient()); - assertEquals(1416209264000L, paymentTransactionData.getTimestamp()); - assertEquals("31dC6kHHBeG5vYb8LMaZDjLEmhc9kQB2VUApVd8xWncSRiXu7yMejdprjYFMP2rUnzZxWd4KJhkq6LsV7rQvU1kY", - Base58.encode(paymentTransactionData.getReference())); - } - } - - @Test - public void testLoadFactory() throws DataException { - try (final Repository repository = RepositoryManager.getRepository()) { - TransactionRepository transactionRepository = repository.getTransactionRepository(); - - assertTrue("Migrate from old database to at least block 49778 before running this test", repository.getBlockRepository().getBlockchainHeight() >= 49778); - - String signature58 = "1211ZPwG3hk5evWzXCZi9hMDRpwumWmkENjwWkeTCik9xA5uoYnxzF7rwR5hmHH3kG2RXo7ToCAaRc7dvnynByJt"; - byte[] signature = Base58.decode(signature58); - - while (true) { - TransactionData transactionData = transactionRepository.fromSignature(signature); - if (transactionData == null) - break; - - if (transactionData.getType() != TransactionType.PAYMENT) - break; - - PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData; - System.out.println(PublicKeyAccount.getAddress(paymentTransactionData.getSenderPublicKey()) + " sent " + paymentTransactionData.getAmount() - + " QORA to " + paymentTransactionData.getRecipient()); - - signature = transactionData.getReference(); - } - } - } - - @Test - public void testLoadNonexistentTransaction() throws DataException { - try (final Repository repository = RepositoryManager.getRepository()) { - TransactionRepository transactionRepository = repository.getTransactionRepository(); - - String signature58 = "1111222233334444"; - byte[] signature = Base58.decode(signature58); - - TransactionData transactionData = transactionRepository.fromSignature(signature); - - if (transactionData != null) { - PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData; - - System.out.println(PublicKeyAccount.getAddress(paymentTransactionData.getSenderPublicKey()) + " sent " + paymentTransactionData.getAmount() - + " QORA to " + paymentTransactionData.getRecipient()); - - fail(); - } - } - } - -} diff --git a/src/test/java/org/qora/test/NavigationTests.java b/src/test/java/org/qora/test/NavigationTests.java deleted file mode 100644 index fba2ecf6..00000000 --- a/src/test/java/org/qora/test/NavigationTests.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.qora.test; - -import org.junit.Test; -import org.qora.data.block.BlockData; -import org.qora.data.transaction.TransactionData; -import org.qora.repository.DataException; -import org.qora.repository.Repository; -import org.qora.repository.RepositoryManager; -import org.qora.repository.TransactionRepository; -import org.qora.test.common.Common; -import org.qora.transaction.Transaction.TransactionType; -import org.qora.utils.Base58; - -import static org.junit.Assert.*; - -public class NavigationTests extends Common { - - @Test - public void testNavigateFromTransactionToBlock() throws DataException { - try (final Repository repository = RepositoryManager.getRepository()) { - TransactionRepository transactionRepository = repository.getTransactionRepository(); - - assertTrue("Migrate from old database to at least block 49778 before running this test", repository.getBlockRepository().getBlockchainHeight() >= 49778); - - String signature58 = "1211ZPwG3hk5evWzXCZi9hMDRpwumWmkENjwWkeTCik9xA5uoYnxzF7rwR5hmHH3kG2RXo7ToCAaRc7dvnynByJt"; - byte[] signature = Base58.decode(signature58); - - System.out.println("Navigating to Block from transaction " + signature58); - - TransactionData transactionData = transactionRepository.fromSignature(signature); - assertNotNull("Transaction data not loaded from repository", transactionData); - assertEquals("Transaction data not PAYMENT type", TransactionType.PAYMENT, transactionData.getType()); - - int transactionHeight = transactionRepository.getHeightFromSignature(signature); - assertFalse("Transaction not found or transaction's block not found", transactionHeight == 0); - assertEquals("Transaction's block height expected to be 49778", 49778, transactionHeight); - - BlockData blockData = repository.getBlockRepository().fromHeight(transactionHeight); - assertNotNull("Block 49778 not loaded from database", blockData); - System.out.println("Block " + blockData.getHeight() + ", signature: " + Base58.encode(blockData.getSignature())); - - assertEquals((Integer) 49778, blockData.getHeight()); - } - } - -} diff --git a/src/test/java/org/qora/test/RepositoryTests.java b/src/test/java/org/qora/test/RepositoryTests.java index 74d93c59..42653d9a 100644 --- a/src/test/java/org/qora/test/RepositoryTests.java +++ b/src/test/java/org/qora/test/RepositoryTests.java @@ -1,5 +1,6 @@ package org.qora.test; +import org.junit.Before; import org.junit.Test; import org.qora.account.Account; import org.qora.asset.Asset; @@ -19,6 +20,11 @@ public class RepositoryTests extends Common { private static final Logger LOGGER = LogManager.getLogger(RepositoryTests.class); + @Before + public void beforeTest() throws DataException { + Common.useDefaultSettings(); + } + @Test public void testGetRepository() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { @@ -44,7 +50,7 @@ public class RepositoryTests extends Common { @Test public void testAccessAfterClose() throws DataException { - try (Repository repository = RepositoryManager.getRepository()) { + try (final Repository repository = RepositoryManager.getRepository()) { assertNotNull(repository); repository.close(); @@ -61,17 +67,15 @@ public class RepositoryTests extends Common { @Test public void testDeadlock() throws DataException { - Common.useDefaultSettings(); - // Open connection 1 - try (Repository repository1 = RepositoryManager.getRepository()) { + try (final Repository repository1 = RepositoryManager.getRepository()) { // Do a database 'read' Account account1 = Common.getTestAccount(repository1, "alice"); account1.getLastReference(); // Open connection 2 - try (Repository repository2 = RepositoryManager.getRepository()) { + try (final Repository repository2 = RepositoryManager.getRepository()) { // Update account in 2 Account account2 = Common.getTestAccount(repository2, "alice"); account2.setConfirmedBalance(Asset.QORA, BigDecimal.valueOf(1234L)); diff --git a/src/test/java/org/qora/test/common/TransactionUtils.java b/src/test/java/org/qora/test/common/TransactionUtils.java index 6cc197f1..31f99975 100644 --- a/src/test/java/org/qora/test/common/TransactionUtils.java +++ b/src/test/java/org/qora/test/common/TransactionUtils.java @@ -3,17 +3,21 @@ package org.qora.test.common; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import org.qora.account.PrivateKeyAccount; import org.qora.block.BlockGenerator; import org.qora.data.transaction.TransactionData; import org.qora.repository.DataException; import org.qora.repository.Repository; import org.qora.transaction.Transaction; +import org.qora.transaction.Transaction.TransactionType; import org.qora.transaction.Transaction.ValidationResult; public class TransactionUtils { - public static void signAndForge(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException { + public static void signAsUnconfirmed(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException { Transaction transaction = Transaction.fromData(repository, transactionData); transaction.sign(signingAccount); @@ -32,10 +36,29 @@ public class TransactionUtils { repository.getTransactionRepository().save(transactionData); repository.getTransactionRepository().unconfirmTransaction(transactionData); repository.saveChanges(); + } + + public static void signAndForge(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException { + signAsUnconfirmed(repository, transactionData, signingAccount); // Generate block PrivateKeyAccount generatorAccount = Common.getTestAccount(repository, "alice"); BlockGenerator.generateTestingBlock(repository, generatorAccount); } + public static TransactionData randomTransaction(Repository repository, PrivateKeyAccount account, TransactionType txType, boolean wantValid) throws DataException { + try { + Class clazz = Class.forName(String.join("", org.qora.test.common.transaction.Transaction.class.getPackage().getName(), ".", txType.className, "Transaction")); + + try { + Method method = clazz.getDeclaredMethod("randomTransaction", Repository.class, PrivateKeyAccount.class, boolean.class); + return (TransactionData) method.invoke(null, repository, account, wantValid); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(String.format("Transaction subclass constructor not found for transaction type \"%s\"", txType.name()), e); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(String.format("Transaction subclass not found for transaction type \"%s\"", txType.name()), e); + } + } + } diff --git a/src/test/java/org/qora/test/common/transaction/PaymentTransaction.java b/src/test/java/org/qora/test/common/transaction/PaymentTransaction.java new file mode 100644 index 00000000..69d0f976 --- /dev/null +++ b/src/test/java/org/qora/test/common/transaction/PaymentTransaction.java @@ -0,0 +1,18 @@ +package org.qora.test.common.transaction; + +import java.math.BigDecimal; + +import org.qora.account.PrivateKeyAccount; +import org.qora.data.transaction.PaymentTransactionData; +import org.qora.data.transaction.TransactionData; +import org.qora.group.Group; +import org.qora.repository.Repository; +import org.qora.utils.NTP; + +public class PaymentTransaction { + + public static TransactionData randomTransaction(Repository repository, PrivateKeyAccount account, boolean wantValid) { + return new PaymentTransactionData(NTP.getTime(), Group.NO_GROUP, new byte[32], account.getPublicKey(), account.getAddress(), BigDecimal.valueOf(123L), BigDecimal.ONE); + } + +} diff --git a/src/test/java/org/qora/test/common/transaction/Transaction.java b/src/test/java/org/qora/test/common/transaction/Transaction.java new file mode 100644 index 00000000..3d7ce65b --- /dev/null +++ b/src/test/java/org/qora/test/common/transaction/Transaction.java @@ -0,0 +1,4 @@ +package org.qora.test.common.transaction; + +public abstract class Transaction { +} diff --git a/src/test/java/org/qora/test/forging/GrantForgingTests.java b/src/test/java/org/qora/test/forging/GrantForgingTests.java index 03a58b22..76b91b37 100644 --- a/src/test/java/org/qora/test/forging/GrantForgingTests.java +++ b/src/test/java/org/qora/test/forging/GrantForgingTests.java @@ -22,7 +22,6 @@ import org.qora.transaction.Transaction.ValidationResult; public class GrantForgingTests extends Common { - @Before public void beforeTest() throws DataException { Common.useDefaultSettings();