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.
This commit is contained in:
catbref
2019-05-22 14:50:37 +01:00
parent 07e8e01865
commit a3d4cf2900
56 changed files with 410 additions and 444 deletions

View File

@@ -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);
}
}

View File

@@ -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<Transaction> 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());
}

View File

@@ -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();
}

View File

@@ -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<byte[]> 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;

View File

@@ -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<byte[]> 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)

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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()));

View File

@@ -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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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();

View File

@@ -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()));

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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
}
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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()));

View File

@@ -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());

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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()));

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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()));

View File

@@ -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
}
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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);
}
}