forked from Qortal/qortal
Updated orphaning code of Block and Transaction subclasses
This commit is contained in:
parent
4b3f877dc0
commit
8af761c1c3
@ -31,6 +31,7 @@ import org.qora.repository.ATRepository;
|
||||
import org.qora.repository.BlockRepository;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
import org.qora.repository.TransactionRepository;
|
||||
import org.qora.transaction.AtTransaction;
|
||||
import org.qora.transaction.Transaction;
|
||||
import org.qora.transaction.Transaction.ApprovalStatus;
|
||||
@ -1064,21 +1065,7 @@ public class Block {
|
||||
processBlockRewards();
|
||||
|
||||
// Process transactions (we'll link them to this block after saving the block itself)
|
||||
// AT-generated transactions are already prepended to our transactions at this point.
|
||||
List<Transaction> transactions = this.getTransactions();
|
||||
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());
|
||||
|
||||
// Only process transactions that don't require group-approval.
|
||||
// Group-approval transactions are dealt with later.
|
||||
if (transaction.getTransactionData().getApprovalStatus() == ApprovalStatus.NOT_REQUIRED)
|
||||
transaction.process();
|
||||
|
||||
// Regardless of group-approval, update relevant info for creator (e.g. lastReference)
|
||||
transaction.processReferencesAndFees();
|
||||
}
|
||||
processTransactions();
|
||||
|
||||
// Group-approval transactions
|
||||
processGroupApprovalTransactions();
|
||||
@ -1087,86 +1074,19 @@ public class Block {
|
||||
rewardTransactionFees();
|
||||
|
||||
// Process AT fees and save AT states into repository
|
||||
ATRepository atRepository = this.repository.getATRepository();
|
||||
for (ATStateData atState : this.getATStates()) {
|
||||
Account atAccount = new Account(this.repository, atState.getATAddress());
|
||||
|
||||
// Subtract AT-generated fees from AT accounts
|
||||
atAccount.setConfirmedBalance(Asset.QORA, atAccount.getConfirmedBalance(Asset.QORA).subtract(atState.getFees()));
|
||||
|
||||
atRepository.save(atState);
|
||||
}
|
||||
processAtFeesAndStates();
|
||||
|
||||
// Link block into blockchain by fetching signature of highest block and setting that as our reference
|
||||
BlockData latestBlockData = this.repository.getBlockRepository().fromHeight(blockchainHeight);
|
||||
if (latestBlockData != null)
|
||||
this.blockData.setReference(latestBlockData.getSignature());
|
||||
|
||||
// Save block
|
||||
this.repository.getBlockRepository().save(this.blockData);
|
||||
|
||||
// Link transactions to this block, thus removing them from unconfirmed transactions list.
|
||||
// Also update "transaction participants" in repository for "transactions involving X" support in API
|
||||
for (int sequence = 0; sequence < transactions.size(); ++sequence) {
|
||||
Transaction transaction = transactions.get(sequence);
|
||||
|
||||
// Link transaction to this block
|
||||
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
||||
transaction.getTransactionData().getSignature());
|
||||
this.repository.getBlockRepository().save(blockTransactionData);
|
||||
|
||||
// Update transaction's height in repository
|
||||
this.repository.getTransactionRepository().updateBlockHeight(transaction.getTransactionData().getSignature(), this.blockData.getHeight());
|
||||
// Update local transactionData's height too
|
||||
transaction.getTransactionData().setBlockHeight(this.blockData.getHeight());
|
||||
|
||||
// No longer unconfirmed
|
||||
this.repository.getTransactionRepository().confirmTransaction(transaction.getTransactionData().getSignature());
|
||||
|
||||
List<Account> participants = transaction.getInvolvedAccounts();
|
||||
List<String> participantAddresses = participants.stream().map(account -> account.getAddress()).collect(Collectors.toList());
|
||||
this.repository.getTransactionRepository().saveParticipants(transaction.getTransactionData(), participantAddresses);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processGroupApprovalTransactions() throws DataException {
|
||||
// Search for pending transactions that have now expired
|
||||
List<TransactionData> approvalExpiringTransactions = this.repository.getTransactionRepository().getApprovalExpiringTransactions(this.blockData.getHeight());
|
||||
for (TransactionData transactionData : approvalExpiringTransactions) {
|
||||
transactionData.setApprovalStatus(ApprovalStatus.EXPIRED);
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
}
|
||||
|
||||
// Search for pending transactions within min/max block delay range
|
||||
List<TransactionData> approvalPendingTransactions = this.repository.getTransactionRepository().getApprovalPendingTransactions(this.blockData.getHeight());
|
||||
for (TransactionData transactionData : approvalPendingTransactions) {
|
||||
Transaction transaction = Transaction.fromData(this.repository, transactionData);
|
||||
|
||||
// something like:
|
||||
Boolean isApproved = transaction.getApprovalDecision();
|
||||
|
||||
if (isApproved == null)
|
||||
continue; // approve/reject threshold not yet met
|
||||
|
||||
if (!isApproved) {
|
||||
// REJECT
|
||||
transactionData.setApprovalStatus(ApprovalStatus.REJECTED);
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Approved, but check transaction can still be processed
|
||||
if (transaction.isProcessable() != Transaction.ValidationResult.OK) {
|
||||
transactionData.setApprovalStatus(ApprovalStatus.INVALID);
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
continue;
|
||||
}
|
||||
|
||||
// APPROVED, in which case do transaction.process();
|
||||
transactionData.setApprovalStatus(ApprovalStatus.APPROVED);
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
|
||||
transaction.process();
|
||||
}
|
||||
linkTransactionsToBlock();
|
||||
}
|
||||
|
||||
protected void processBlockRewards() throws DataException {
|
||||
@ -1194,6 +1114,76 @@ public class Block {
|
||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(reward));
|
||||
}
|
||||
|
||||
protected void processTransactions() throws DataException {
|
||||
// Process transactions (we'll link them to this block after saving the block itself)
|
||||
// AT-generated transactions are already prepended to our transactions at this point.
|
||||
List<Transaction> transactions = this.getTransactions();
|
||||
|
||||
for (Transaction transaction : transactions) {
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
// AT_TRANSACTIONs are created locally and need saving into repository before processing
|
||||
if (transactionData.getType() == TransactionType.AT)
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
|
||||
// Only process transactions that don't require group-approval.
|
||||
// Group-approval transactions are dealt with later.
|
||||
if (transactionData.getApprovalStatus() == ApprovalStatus.NOT_REQUIRED)
|
||||
transaction.process();
|
||||
|
||||
// Regardless of group-approval, update relevant info for creator (e.g. lastReference)
|
||||
transaction.processReferencesAndFees();
|
||||
}
|
||||
}
|
||||
|
||||
protected void processGroupApprovalTransactions() throws DataException {
|
||||
TransactionRepository transactionRepository = this.repository.getTransactionRepository();
|
||||
|
||||
// Search for pending transactions that have now expired
|
||||
List<TransactionData> approvalExpiringTransactions = transactionRepository.getApprovalExpiringTransactions(this.blockData.getHeight());
|
||||
|
||||
for (TransactionData transactionData : approvalExpiringTransactions) {
|
||||
transactionData.setApprovalStatus(ApprovalStatus.EXPIRED);
|
||||
transactionRepository.save(transactionData);
|
||||
}
|
||||
|
||||
// Search for pending transactions within min/max block delay range
|
||||
List<TransactionData> approvalPendingTransactions = transactionRepository.getApprovalPendingTransactions(this.blockData.getHeight());
|
||||
|
||||
for (TransactionData transactionData : approvalPendingTransactions) {
|
||||
Transaction transaction = Transaction.fromData(this.repository, transactionData);
|
||||
|
||||
// something like:
|
||||
Boolean isApproved = transaction.getApprovalDecision();
|
||||
|
||||
if (isApproved == null)
|
||||
continue; // approve/reject threshold not yet met
|
||||
|
||||
// Update approval height for transaction in repository
|
||||
transactionRepository.updateApprovalHeight(transactionData.getSignature(), this.blockData.getHeight());
|
||||
|
||||
if (!isApproved) {
|
||||
// REJECT
|
||||
transactionData.setApprovalStatus(ApprovalStatus.REJECTED);
|
||||
transactionRepository.save(transactionData);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Approved, but check transaction can still be processed
|
||||
if (transaction.isProcessable() != Transaction.ValidationResult.OK) {
|
||||
transactionData.setApprovalStatus(ApprovalStatus.INVALID);
|
||||
transactionRepository.save(transactionData);
|
||||
continue;
|
||||
}
|
||||
|
||||
// APPROVED, in which case do transaction.process();
|
||||
transactionData.setApprovalStatus(ApprovalStatus.APPROVED);
|
||||
transactionRepository.save(transactionData);
|
||||
|
||||
transaction.process();
|
||||
}
|
||||
}
|
||||
|
||||
protected void rewardTransactionFees() throws DataException {
|
||||
BigDecimal blockFees = this.blockData.getTotalFees();
|
||||
|
||||
@ -1219,32 +1209,57 @@ public class Block {
|
||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(blockFees));
|
||||
}
|
||||
|
||||
protected void processAtFeesAndStates() throws DataException {
|
||||
ATRepository atRepository = this.repository.getATRepository();
|
||||
|
||||
for (ATStateData atState : this.getATStates()) {
|
||||
Account atAccount = new Account(this.repository, atState.getATAddress());
|
||||
|
||||
// Subtract AT-generated fees from AT accounts
|
||||
atAccount.setConfirmedBalance(Asset.QORA, atAccount.getConfirmedBalance(Asset.QORA).subtract(atState.getFees()));
|
||||
|
||||
atRepository.save(atState);
|
||||
}
|
||||
}
|
||||
|
||||
protected void linkTransactionsToBlock() throws DataException {
|
||||
TransactionRepository transactionRepository = this.repository.getTransactionRepository();
|
||||
|
||||
for (int sequence = 0; sequence < transactions.size(); ++sequence) {
|
||||
Transaction transaction = transactions.get(sequence);
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
// Link transaction to this block
|
||||
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
||||
transactionData.getSignature());
|
||||
this.repository.getBlockRepository().save(blockTransactionData);
|
||||
|
||||
// Update transaction's height in repository
|
||||
transactionRepository.updateBlockHeight(transactionData.getSignature(), this.blockData.getHeight());
|
||||
|
||||
// Update local transactionData's height too
|
||||
transaction.getTransactionData().setBlockHeight(this.blockData.getHeight());
|
||||
|
||||
// No longer unconfirmed
|
||||
transactionRepository.confirmTransaction(transactionData.getSignature());
|
||||
|
||||
List<Account> participants = transaction.getInvolvedAccounts();
|
||||
List<String> participantAddresses = participants.stream().map(account -> account.getAddress()).collect(Collectors.toList());
|
||||
transactionRepository.saveParticipants(transactionData, participantAddresses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes block from blockchain undoing transactions and adding them to unconfirmed pile.
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public void orphan() throws DataException {
|
||||
// Orphan transactions in reverse order, and unlink them from this block
|
||||
// AT-generated transactions are already added to our transactions so no special handling is needed here.
|
||||
List<Transaction> transactions = this.getTransactions();
|
||||
for (int sequence = transactions.size() - 1; sequence >= 0; --sequence) {
|
||||
Transaction transaction = transactions.get(sequence);
|
||||
transaction.orphan();
|
||||
// Orphan, and unlink, transactions from this block
|
||||
orphanTransactionsFromBlock();
|
||||
|
||||
// Unlink transaction from this block
|
||||
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
||||
transaction.getTransactionData().getSignature());
|
||||
this.repository.getBlockRepository().delete(blockTransactionData);
|
||||
|
||||
// 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());
|
||||
}
|
||||
// Undo any group-approval decisions that happen at this block
|
||||
orphanGroupApprovalTransactions();
|
||||
|
||||
// Block rewards removed after transactions undone
|
||||
orphanBlockRewards();
|
||||
@ -1253,18 +1268,70 @@ public class Block {
|
||||
deductTransactionFees();
|
||||
|
||||
// Return AT fees and delete AT states from repository
|
||||
ATRepository atRepository = this.repository.getATRepository();
|
||||
for (ATStateData atState : this.getATStates()) {
|
||||
Account atAccount = new Account(this.repository, atState.getATAddress());
|
||||
|
||||
// Return AT-generated fees to AT accounts
|
||||
atAccount.setConfirmedBalance(Asset.QORA, atAccount.getConfirmedBalance(Asset.QORA).add(atState.getFees()));
|
||||
}
|
||||
// Delete ATStateData for this height
|
||||
atRepository.deleteATStates(this.blockData.getHeight());
|
||||
orphanAtFeesAndStates();
|
||||
|
||||
// Delete block from blockchain
|
||||
this.repository.getBlockRepository().delete(this.blockData);
|
||||
this.blockData.setHeight(null);
|
||||
}
|
||||
|
||||
protected void orphanTransactionsFromBlock() throws DataException {
|
||||
TransactionRepository transactionRepository = this.repository.getTransactionRepository();
|
||||
|
||||
// AT-generated transactions are already added to our transactions so no special handling is needed here.
|
||||
List<Transaction> transactions = this.getTransactions();
|
||||
|
||||
for (int sequence = transactions.size() - 1; sequence >= 0; --sequence) {
|
||||
Transaction transaction = transactions.get(sequence);
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
// Orphan transaction
|
||||
// Only orphan transactions that didn't require group-approval.
|
||||
// Group-approval transactions are dealt with later.
|
||||
if (transactionData.getApprovalStatus() == ApprovalStatus.NOT_REQUIRED)
|
||||
transaction.orphan();
|
||||
|
||||
// Regardless of group-approval, update relevant info for creator (e.g. lastReference)
|
||||
transaction.orphanReferencesAndFees();
|
||||
|
||||
// Unlink transaction from this block
|
||||
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
||||
transactionData.getSignature());
|
||||
this.repository.getBlockRepository().delete(blockTransactionData);
|
||||
|
||||
// Add to unconfirmed pile and remove height, or delete if AT_TRANSACTION
|
||||
if (transaction.getTransactionData().getType() == TransactionType.AT) {
|
||||
transactionRepository.delete(transactionData);
|
||||
} else {
|
||||
// Add to unconfirmed pile
|
||||
transactionRepository.unconfirmTransaction(transactionData);
|
||||
|
||||
// Unset height
|
||||
transactionRepository.updateBlockHeight(transactionData.getSignature(), null);
|
||||
}
|
||||
|
||||
transactionRepository.deleteParticipants(transactionData);
|
||||
}
|
||||
}
|
||||
|
||||
protected void orphanGroupApprovalTransactions() throws DataException {
|
||||
TransactionRepository transactionRepository = this.repository.getTransactionRepository();
|
||||
|
||||
// Find all transactions where decision happened at this block height
|
||||
List<TransactionData> transactions = transactionRepository.getApprovalTransactionDecidedAtHeight(this.blockData.getHeight());
|
||||
|
||||
for (TransactionData transactionData : transactions) {
|
||||
// Orphan/un-process transaction
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.orphan();
|
||||
|
||||
// Revert back to PENDING
|
||||
transactionData.setApprovalStatus(ApprovalStatus.PENDING);
|
||||
transactionRepository.save(transactionData);
|
||||
|
||||
// Undo approval decision height
|
||||
transactionRepository.updateApprovalHeight(transactionData.getSignature(), null);
|
||||
}
|
||||
}
|
||||
|
||||
protected void orphanBlockRewards() throws DataException {
|
||||
@ -1317,6 +1384,19 @@ public class Block {
|
||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(blockFees));
|
||||
}
|
||||
|
||||
protected void orphanAtFeesAndStates() throws DataException {
|
||||
ATRepository atRepository = this.repository.getATRepository();
|
||||
for (ATStateData atState : this.getATStates()) {
|
||||
Account atAccount = new Account(this.repository, atState.getATAddress());
|
||||
|
||||
// Return AT-generated fees to AT accounts
|
||||
atAccount.setConfirmedBalance(Asset.QORA, atAccount.getConfirmedBalance(Asset.QORA).add(atState.getFees()));
|
||||
}
|
||||
|
||||
// Delete ATStateData for this height
|
||||
atRepository.deleteATStates(this.blockData.getHeight());
|
||||
}
|
||||
|
||||
protected BigDecimal getRewardAtHeight(int ourHeight) {
|
||||
List<RewardByHeight> rewardsByHeight = BlockChain.getInstance().getBlockRewardsByHeight();
|
||||
|
||||
|
@ -33,6 +33,9 @@ public class Payment {
|
||||
|
||||
// Processing
|
||||
|
||||
|
||||
// isValid
|
||||
|
||||
/** Are payments valid? */
|
||||
public ValidationResult isValid(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, boolean isZeroAmountValid) throws DataException {
|
||||
AssetRepository assetRepository = this.repository.getAssetRepository();
|
||||
@ -115,6 +118,8 @@ public class Payment {
|
||||
return isValid(senderPublicKey, paymentData, fee, false);
|
||||
}
|
||||
|
||||
// isProcessable
|
||||
|
||||
/** Are multiple payments processable? */
|
||||
public ValidationResult isProcessable(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, boolean isZeroAmountValid) throws DataException {
|
||||
// Essentially the same as isValid...
|
||||
@ -136,6 +141,8 @@ public class Payment {
|
||||
return isProcessable(senderPublicKey, paymentData, fee, false);
|
||||
}
|
||||
|
||||
// process
|
||||
|
||||
/** Multiple payment processing */
|
||||
public void process(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature)
|
||||
throws DataException {
|
||||
@ -162,6 +169,8 @@ public class Payment {
|
||||
process(senderPublicKey, Collections.singletonList(paymentData), fee, signature);
|
||||
}
|
||||
|
||||
// processReferenceAndFees
|
||||
|
||||
/** Multiple payment reference processing */
|
||||
public void processReferencesAndFees(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, boolean alwaysInitializeRecipientReference)
|
||||
throws DataException {
|
||||
@ -173,7 +182,7 @@ public class Payment {
|
||||
// Update sender's reference
|
||||
sender.setLastReference(signature);
|
||||
|
||||
// Process all payments
|
||||
// Process all recipients
|
||||
for (PaymentData paymentData : payments) {
|
||||
Account recipient = new Account(this.repository, paymentData.getRecipient());
|
||||
|
||||
@ -191,16 +200,11 @@ public class Payment {
|
||||
processReferencesAndFees(senderPublicKey, Collections.singletonList(payment), fee, signature, alwaysInitializeRecipientReference);
|
||||
}
|
||||
|
||||
public void orphan(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, byte[] reference,
|
||||
boolean alwaysUninitializeRecipientReference) throws DataException {
|
||||
// orphan
|
||||
|
||||
public void orphan(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, byte[] reference) throws DataException {
|
||||
Account sender = new PublicKeyAccount(this.repository, senderPublicKey);
|
||||
|
||||
// Update sender's balance due to fee
|
||||
sender.setConfirmedBalance(Asset.QORA, sender.getConfirmedBalance(Asset.QORA).add(fee));
|
||||
|
||||
// Update sender's reference
|
||||
sender.setLastReference(reference);
|
||||
|
||||
// Orphan all payments
|
||||
for (PaymentData paymentData : payments) {
|
||||
Account recipient = new Account(this.repository, paymentData.getRecipient());
|
||||
@ -212,6 +216,29 @@ public class Payment {
|
||||
|
||||
// Update recipient's balance
|
||||
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).subtract(amount));
|
||||
}
|
||||
}
|
||||
|
||||
public void orphan(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature, byte[] reference) throws DataException {
|
||||
orphan(senderPublicKey, Collections.singletonList(paymentData), fee, signature, reference);
|
||||
}
|
||||
|
||||
// orphanReferencesAndFees
|
||||
|
||||
public void orphanReferencesAndFees(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, byte[] reference,
|
||||
boolean alwaysUninitializeRecipientReference) throws DataException {
|
||||
Account sender = new PublicKeyAccount(this.repository, senderPublicKey);
|
||||
|
||||
// Update sender's balance due to fee
|
||||
sender.setConfirmedBalance(Asset.QORA, sender.getConfirmedBalance(Asset.QORA).add(fee));
|
||||
|
||||
// Update sender's reference
|
||||
sender.setLastReference(reference);
|
||||
|
||||
// Orphan all recipients
|
||||
for (PaymentData paymentData : payments) {
|
||||
Account recipient = new Account(this.repository, paymentData.getRecipient());
|
||||
long assetId = paymentData.getAssetId();
|
||||
|
||||
/*
|
||||
* For QORA amounts only: If recipient's last reference is this transaction's signature, then they can't have made any transactions of their own
|
||||
@ -222,9 +249,9 @@ public class Payment {
|
||||
}
|
||||
}
|
||||
|
||||
public void orphan(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature, byte[] reference,
|
||||
public void orphanReferencesAndFees(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature, byte[] reference,
|
||||
boolean alwaysUninitializeRecipientReference) throws DataException {
|
||||
orphan(senderPublicKey, Collections.singletonList(paymentData), fee, signature, reference, alwaysUninitializeRecipientReference);
|
||||
orphanReferencesAndFees(senderPublicKey, Collections.singletonList(paymentData), fee, signature, reference, alwaysUninitializeRecipientReference);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -113,6 +113,9 @@ public interface TransactionRepository {
|
||||
*/
|
||||
public List<TransactionData> getApprovalExpiringTransactions(int blockHeight) throws DataException;
|
||||
|
||||
/** Returns list of transactions that had group-approval decided at passed block height. */
|
||||
public List<TransactionData> getApprovalTransactionDecidedAtHeight(int approvalHeight) throws DataException;
|
||||
|
||||
/** Returns latest approval decision by given admin for given pending transaction signature. */
|
||||
public GroupApprovalTransactionData getLatestApproval(byte[] pendingSignature, byte[] adminPublicKey) throws DataException;
|
||||
|
||||
|
@ -25,9 +25,9 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
|
||||
@Override
|
||||
public ATData fromATAddress(String atAddress) throws DataException {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(
|
||||
"SELECT creator, creation, version, asset_id, code_bytes, is_sleeping, sleep_until_height, is_finished, had_fatal_error, is_frozen, frozen_balance FROM ATs WHERE AT_address = ?",
|
||||
atAddress)) {
|
||||
final String sql = "SELECT creator, creation, version, asset_id, code_bytes, is_sleeping, sleep_until_height, is_finished, had_fatal_error, is_frozen, frozen_balance FROM ATs WHERE AT_address = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, atAddress)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
@ -39,7 +39,7 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
boolean isSleeping = resultSet.getBoolean(6);
|
||||
|
||||
Integer sleepUntilHeight = resultSet.getInt(7);
|
||||
if (resultSet.wasNull())
|
||||
if (sleepUntilHeight == 0 && resultSet.wasNull())
|
||||
sleepUntilHeight = null;
|
||||
|
||||
boolean isFinished = resultSet.getBoolean(8);
|
||||
@ -47,8 +47,6 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
boolean isFrozen = resultSet.getBoolean(10);
|
||||
|
||||
BigDecimal frozenBalance = resultSet.getBigDecimal(11);
|
||||
if (resultSet.wasNull())
|
||||
frozenBalance = null;
|
||||
|
||||
return new ATData(atAddress, creatorPublicKey, creation, version, assetId, codeBytes, isSleeping, sleepUntilHeight, isFinished, hadFatalError,
|
||||
isFrozen, frozenBalance);
|
||||
@ -68,10 +66,11 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
|
||||
@Override
|
||||
public List<ATData> getAllExecutableATs() throws DataException {
|
||||
final String sql = "SELECT AT_address, creator, creation, version, asset_id, code_bytes, is_sleeping, sleep_until_height, had_fatal_error, is_frozen, frozen_balance FROM ATs WHERE is_finished = false ORDER BY creation ASC";
|
||||
|
||||
List<ATData> executableATs = new ArrayList<ATData>();
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(
|
||||
"SELECT AT_address, creator, creation, version, asset_id, code_bytes, is_sleeping, sleep_until_height, had_fatal_error, is_frozen, frozen_balance FROM ATs WHERE is_finished = false ORDER BY creation ASC")) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql)) {
|
||||
if (resultSet == null)
|
||||
return executableATs;
|
||||
|
||||
@ -87,15 +86,13 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
boolean isSleeping = resultSet.getBoolean(7);
|
||||
|
||||
Integer sleepUntilHeight = resultSet.getInt(8);
|
||||
if (resultSet.wasNull())
|
||||
if (sleepUntilHeight == 0 && resultSet.wasNull())
|
||||
sleepUntilHeight = null;
|
||||
|
||||
boolean hadFatalError = resultSet.getBoolean(9);
|
||||
boolean isFrozen = resultSet.getBoolean(10);
|
||||
|
||||
BigDecimal frozenBalance = resultSet.getBigDecimal(11);
|
||||
if (resultSet.wasNull())
|
||||
frozenBalance = null;
|
||||
|
||||
ATData atData = new ATData(atAddress, creatorPublicKey, creation, version, assetId, codeBytes, isSleeping, sleepUntilHeight, isFinished,
|
||||
hadFatalError, isFrozen, frozenBalance);
|
||||
@ -111,9 +108,9 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
|
||||
@Override
|
||||
public Integer getATCreationBlockHeight(String atAddress) throws DataException {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(
|
||||
"SELECT height from DeployATTransactions JOIN BlockTransactions ON transaction_signature = signature JOIN Blocks ON Blocks.signature = block_signature WHERE AT_address = ?",
|
||||
atAddress)) {
|
||||
final String sql = "SELECT height from DeployATTransactions JOIN BlockTransactions ON transaction_signature = signature JOIN Blocks ON Blocks.signature = block_signature WHERE AT_address = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, atAddress)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
|
@ -29,8 +29,9 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
@Override
|
||||
public GroupData fromGroupId(int groupId) throws DataException {
|
||||
try (ResultSet resultSet = this.repository
|
||||
.checkedExecute("SELECT group_name, owner, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay, creation_group_id FROM Groups WHERE group_id = ?", groupId)) {
|
||||
final String sql = "SELECT group_name, owner, description, created, updated, reference, is_open, approval_threshold, min_block_delay, max_block_delay, creation_group_id FROM Groups WHERE group_id = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, groupId)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
@ -41,7 +42,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
// Special handling for possibly-NULL "updated" column
|
||||
Timestamp updatedTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC));
|
||||
Long updated = resultSet.wasNull() ? null : updatedTimestamp.getTime();
|
||||
Long updated = updatedTimestamp == null ? null : updatedTimestamp.getTime();
|
||||
|
||||
byte[] reference = resultSet.getBytes(6);
|
||||
boolean isOpen = resultSet.getBoolean(7);
|
||||
@ -73,7 +74,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
// Special handling for possibly-NULL "updated" column
|
||||
Timestamp updatedTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC));
|
||||
Long updated = resultSet.wasNull() ? null : updatedTimestamp.getTime();
|
||||
Long updated = updatedTimestamp == null ? null : updatedTimestamp.getTime();
|
||||
|
||||
byte[] reference = resultSet.getBytes(6);
|
||||
boolean isOpen = resultSet.getBoolean(7);
|
||||
@ -131,7 +132,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
// Special handling for possibly-NULL "updated" column
|
||||
Timestamp updatedTimestamp = resultSet.getTimestamp(6, Calendar.getInstance(HSQLDBRepository.UTC));
|
||||
Long updated = resultSet.wasNull() ? null : updatedTimestamp.getTime();
|
||||
Long updated = updatedTimestamp == null ? null : updatedTimestamp.getTime();
|
||||
|
||||
byte[] reference = resultSet.getBytes(7);
|
||||
boolean isOpen = resultSet.getBoolean(8);
|
||||
|
@ -38,7 +38,7 @@ public class HSQLDBNetworkRepository implements NetworkRepository {
|
||||
Long lastAttempted = HSQLDBRepository.getZonedTimestampMilli(resultSet, 3);
|
||||
|
||||
Integer lastHeight = resultSet.getInt(4);
|
||||
if (resultSet.wasNull())
|
||||
if (lastHeight == 0 && resultSet.wasNull())
|
||||
lastHeight = null;
|
||||
|
||||
byte[] lastBlockSignature = resultSet.getBytes(5);
|
||||
|
@ -736,6 +736,34 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TransactionData> getApprovalTransactionDecidedAtHeight(int approvalHeight) throws DataException {
|
||||
final String sql = "SELECT signature from Transactions WHERE approval_height = ?";
|
||||
|
||||
List<TransactionData> transactions = new ArrayList<>();
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, approvalHeight)) {
|
||||
if (resultSet == null)
|
||||
return transactions;
|
||||
|
||||
do {
|
||||
byte[] signature = resultSet.getBytes(1);
|
||||
|
||||
TransactionData transactionData = this.fromSignature(signature);
|
||||
|
||||
if (transactionData == null)
|
||||
// Something inconsistent with the repository
|
||||
throw new DataException("Unable to fetch approval-decided transaction from repository?");
|
||||
|
||||
transactions.add(transactionData);
|
||||
} while (resultSet.next());
|
||||
|
||||
return transactions;
|
||||
} catch (SQLException | DataException e) {
|
||||
throw new DataException("Unable to fetch approval-decided transactions from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupApprovalTransactionData getLatestApproval(byte[] pendingSignature, byte[] adminPublicKey) throws DataException {
|
||||
String sql = "SELECT signature FROM GroupApprovalTransactions "
|
||||
|
@ -20,7 +20,7 @@ public class HSQLDBTransferAssetTransactionRepository extends HSQLDBTransactionR
|
||||
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
||||
String sql = "SELECT recipient, asset_id, amount, asset_name FROM TransferAssetTransactions JOIN Assets USING (asset_id) WHERE signature = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql)) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
|
@ -120,14 +120,6 @@ public class AccountFlagsTransaction extends Transaction {
|
||||
// Remove previous flags from transaction itself
|
||||
accountFlagsTransactionData.setPreviousFlags(null);
|
||||
this.repository.getTransactionRepository().save(accountFlagsTransactionData);
|
||||
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update creator's balance
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(accountFlagsTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(accountFlagsTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -113,8 +113,6 @@ public class AddGroupAdminTransaction extends Transaction {
|
||||
// Update Group adminship
|
||||
Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupId());
|
||||
group.promoteToAdmin(addGroupAdminTransactionData);
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -122,15 +120,6 @@ public class AddGroupAdminTransaction extends Transaction {
|
||||
// Revert group adminship
|
||||
Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupId());
|
||||
group.unpromoteToAdmin(addGroupAdminTransactionData);
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(addGroupAdminTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(addGroupAdminTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
@ -116,8 +116,6 @@ public class ArbitraryTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature());
|
||||
@ -132,11 +130,16 @@ public class ArbitraryTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Wrap and delegate payment processing to Payment class. Always revert recipients' last references regardless of asset.
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).orphan(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature(), arbitraryTransactionData.getReference(), true);
|
||||
arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature(), arbitraryTransactionData.getReference());
|
||||
}
|
||||
|
||||
// We would save transaction in orphaned form at this point, but it hasn't been modified
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate reference and fee processing to Payment class. Always revert recipients' last references regardless of asset.
|
||||
new Payment(this.repository).orphanReferencesAndFees(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature(), arbitraryTransactionData.getReference(), true);
|
||||
}
|
||||
|
||||
// Data access
|
||||
|
@ -161,8 +161,6 @@ public class AtTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
if (this.atTransactionData.getAmount() != null) {
|
||||
Account sender = getATAccount();
|
||||
Account recipient = getRecipient();
|
||||
@ -206,6 +204,17 @@ public class AtTransaction extends Transaction {
|
||||
|
||||
// Update recipient's balance
|
||||
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).subtract(amount));
|
||||
}
|
||||
|
||||
// As AT_TRANSACTIONs are really part of a block, the caller (Block) will probably delete this transaction after orphaning
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
if (this.atTransactionData.getAmount() != null) {
|
||||
Account recipient = getRecipient();
|
||||
|
||||
long assetId = this.atTransactionData.getAssetId();
|
||||
|
||||
/*
|
||||
* For QORA amounts only: If recipient's last reference is this transaction's signature, then they can't have made any transactions of their own
|
||||
@ -214,10 +223,6 @@ 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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -134,13 +134,6 @@ public class BuyNameTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, with removed "name reference"
|
||||
this.repository.getTransactionRepository().save(buyNameTransactionData);
|
||||
|
||||
// Update buyer's balance
|
||||
Account buyer = getBuyer();
|
||||
buyer.setConfirmedBalance(Asset.QORA, buyer.getConfirmedBalance(Asset.QORA).add(buyNameTransactionData.getFee()));
|
||||
|
||||
// Update buyer's reference
|
||||
buyer.setLastReference(buyNameTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -94,8 +94,6 @@ public class CancelAssetOrderTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Mark Order as completed so no more trades can happen
|
||||
OrderData orderData = this.repository.getAssetRepository().fromOrderId(cancelOrderTransactionData.getOrderId());
|
||||
Order order = new Order(this.repository, orderData);
|
||||
@ -104,16 +102,6 @@ public class CancelAssetOrderTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
// 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()));
|
||||
|
||||
// Update creator's last reference
|
||||
creator.setLastReference(cancelOrderTransactionData.getReference());
|
||||
|
||||
// Unmark Order as completed so trades can happen again
|
||||
OrderData orderData = this.repository.getAssetRepository().fromOrderId(cancelOrderTransactionData.getOrderId());
|
||||
Order order = new Order(this.repository, orderData);
|
||||
|
@ -124,13 +124,6 @@ public class CancelGroupBanTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed member/admin references
|
||||
this.repository.getTransactionRepository().save(groupUnbanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupUnbanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupUnbanTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -124,13 +124,6 @@ public class CancelGroupInviteTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed member/admin references
|
||||
this.repository.getTransactionRepository().save(cancelGroupInviteTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(cancelGroupInviteTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(cancelGroupInviteTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -121,13 +121,6 @@ public class CancelSellNameTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, with removed "name reference"
|
||||
this.repository.getTransactionRepository().save(cancelSellNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(cancelSellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(cancelSellNameTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -178,16 +178,6 @@ public class CreateAssetOrderTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update creator's balance due to fee
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createOrderTransactionData.getFee()));
|
||||
|
||||
// Update creator's last reference
|
||||
creator.setLastReference(createOrderTransactionData.getSignature());
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Order Id is transaction's signature
|
||||
byte[] orderId = createOrderTransactionData.getSignature();
|
||||
|
||||
@ -201,22 +191,12 @@ public class CreateAssetOrderTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update creator's balance due to fee
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createOrderTransactionData.getFee()));
|
||||
|
||||
// Update creator's last reference
|
||||
creator.setLastReference(createOrderTransactionData.getReference());
|
||||
|
||||
// Order Id is transaction's signature
|
||||
byte[] orderId = createOrderTransactionData.getSignature();
|
||||
|
||||
// Orphan the order itself
|
||||
OrderData orderData = this.repository.getAssetRepository().fromOrderId(orderId);
|
||||
new Order(this.repository, orderData).orphan();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public class CreateGroupTransaction extends Transaction {
|
||||
// Note newly assigned group ID in our transaction record
|
||||
createGroupTransactionData.setGroupId(group.getGroupData().getGroupId());
|
||||
|
||||
// Save this transaction
|
||||
// Save this transaction with newly assigned group ID
|
||||
this.repository.getTransactionRepository().save(createGroupTransactionData);
|
||||
}
|
||||
|
||||
@ -137,13 +137,6 @@ public class CreateGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed group ID
|
||||
this.repository.getTransactionRepository().save(createGroupTransactionData);
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createGroupTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(createGroupTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -153,8 +153,6 @@ public class CreatePollTransaction extends Transaction {
|
||||
// Publish poll to allow voting
|
||||
Poll poll = new Poll(this.repository, createPollTransactionData);
|
||||
poll.publish();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -162,15 +160,6 @@ public class CreatePollTransaction extends Transaction {
|
||||
// Unpublish poll
|
||||
Poll poll = new Poll(this.repository, createPollTransactionData.getPollName());
|
||||
poll.unpublish();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createPollTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(createPollTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -238,8 +238,6 @@ public class DeployAtTransaction extends Transaction {
|
||||
AT at = new AT(this.repository, this.deployATTransactionData);
|
||||
at.deploy();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
long assetId = deployATTransactionData.getAssetId();
|
||||
|
||||
// Update creator's balance regarding initial payment to AT
|
||||
@ -260,17 +258,11 @@ public class DeployAtTransaction extends Transaction {
|
||||
AT at = new AT(this.repository, this.deployATTransactionData);
|
||||
at.undeploy();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
long assetId = deployATTransactionData.getAssetId();
|
||||
|
||||
// Update creator's balance
|
||||
// Update creator's balance regarding initial payment to AT
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(assetId, creator.getConfirmedBalance(assetId).add(deployATTransactionData.getAmount()));
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(deployATTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(deployATTransactionData.getReference());
|
||||
|
||||
// Delete AT's account (and hence its balance)
|
||||
this.repository.getAccountRepository().delete(this.deployATTransactionData.getAtAddress());
|
||||
|
@ -146,8 +146,6 @@ public class EnableForgingTransaction extends Transaction {
|
||||
|
||||
target.setFlags(targetFlags);
|
||||
target.setForgingEnabler(creator.getAddress());
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -169,14 +167,6 @@ public class EnableForgingTransaction extends Transaction {
|
||||
|
||||
target.setFlags(targetFlags);
|
||||
target.setForgingEnabler(null);
|
||||
|
||||
// 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()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(enableForgingTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -136,8 +136,6 @@ public class GenesisTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
Account recipient = new Account(repository, genesisTransactionData.getRecipient());
|
||||
|
||||
// Update recipient's balance
|
||||
@ -156,10 +154,13 @@ public class GenesisTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// 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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// Recipient's last reference removed thanks to delete() called by orphan() above.
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -106,13 +106,6 @@ public class GroupApprovalTransaction extends Transaction {
|
||||
// Save this transaction with removed prior reference
|
||||
groupApprovalTransactionData.setPriorReference(null);
|
||||
this.repository.getTransactionRepository().save(groupApprovalTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupApprovalTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupApprovalTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -125,13 +125,6 @@ public class GroupBanTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed member/admin references
|
||||
this.repository.getTransactionRepository().save(groupBanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupBanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupBanTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -131,13 +131,6 @@ public class GroupInviteTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed member/admin references
|
||||
this.repository.getTransactionRepository().save(groupInviteTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupInviteTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupInviteTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -131,13 +131,6 @@ public class GroupKickTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed member/admin references
|
||||
this.repository.getTransactionRepository().save(groupKickTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupKickTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupKickTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -142,15 +142,15 @@ public class IssueAssetTransaction extends Transaction {
|
||||
Asset asset = new Asset(this.repository, issueAssetTransactionData);
|
||||
asset.issue();
|
||||
|
||||
// Add asset to owner
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(asset.getAssetData().getAssetId(), BigDecimal.valueOf(issueAssetTransactionData.getQuantity()).setScale(8));
|
||||
|
||||
// Note newly assigned asset ID in our transaction record
|
||||
issueAssetTransactionData.setAssetId(asset.getAssetData().getAssetId());
|
||||
|
||||
// Save this transaction, now with corresponding assetId
|
||||
// Save this transaction with newly assigned assetId
|
||||
this.repository.getTransactionRepository().save(issueAssetTransactionData);
|
||||
|
||||
// Add asset to owner
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(issueAssetTransactionData.getAssetId(), BigDecimal.valueOf(issueAssetTransactionData.getQuantity()).setScale(8));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,13 +168,6 @@ public class IssueAssetTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, with removed assetId
|
||||
this.repository.getTransactionRepository().save(issueAssetTransactionData);
|
||||
|
||||
// Update issuer's balance
|
||||
Account issuer = getIssuer();
|
||||
issuer.setConfirmedBalance(Asset.QORA, issuer.getConfirmedBalance(Asset.QORA).add(issueAssetTransactionData.getFee()));
|
||||
|
||||
// Update issuer's reference
|
||||
issuer.setLastReference(issueAssetTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,13 +111,6 @@ public class JoinGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed references
|
||||
this.repository.getTransactionRepository().save(joinGroupTransactionData);
|
||||
|
||||
// Update joiner's balance
|
||||
Account joiner = getJoiner();
|
||||
joiner.setConfirmedBalance(Asset.QORA, joiner.getConfirmedBalance(Asset.QORA).add(joinGroupTransactionData.getFee()));
|
||||
|
||||
// Update joiner's reference
|
||||
joiner.setLastReference(joinGroupTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -110,13 +110,6 @@ public class LeaveGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed member/admin references
|
||||
this.repository.getTransactionRepository().save(leaveGroupTransactionData);
|
||||
|
||||
// Update leaver's balance
|
||||
Account leaver = getLeaver();
|
||||
leaver.setConfirmedBalance(Asset.QORA, leaver.getConfirmedBalance(Asset.QORA).add(leaveGroupTransactionData.getFee()));
|
||||
|
||||
// Update leaver's reference
|
||||
leaver.setLastReference(leaveGroupTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -120,8 +120,6 @@ public class MessageTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(),
|
||||
messageTransactionData.getSignature());
|
||||
@ -136,11 +134,16 @@ public class MessageTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Wrap and delegate payment processing to Payment class. Only revert recipient's last reference if transferring QORA.
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).orphan(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(),
|
||||
messageTransactionData.getSignature(), messageTransactionData.getReference(), false);
|
||||
messageTransactionData.getSignature(), messageTransactionData.getReference());
|
||||
}
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate references processing to Payment class. Only revert recipient's last reference if transferring QORA.
|
||||
new Payment(this.repository).orphanReferencesAndFees(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(),
|
||||
messageTransactionData.getSignature(), messageTransactionData.getReference(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -119,8 +119,6 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(),
|
||||
multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature());
|
||||
@ -128,8 +126,6 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate reference processing to Payment class. Always update recipients' last references regardless of asset.
|
||||
new Payment(this.repository).processReferencesAndFees(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(),
|
||||
multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature(), true);
|
||||
@ -139,9 +135,14 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
public void orphan() throws DataException {
|
||||
// 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);
|
||||
multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature(), multiPaymentTransactionData.getReference());
|
||||
}
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate reference processing to Payment class. Always revert recipients' last references regardless of asset.
|
||||
new Payment(this.repository).orphanReferencesAndFees(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(),
|
||||
multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature(), multiPaymentTransactionData.getReference(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -88,8 +88,6 @@ public class PaymentTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee(),
|
||||
paymentTransactionData.getSignature());
|
||||
@ -106,9 +104,14 @@ public class PaymentTransaction extends Transaction {
|
||||
public void orphan() throws DataException {
|
||||
// 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);
|
||||
paymentTransactionData.getSignature(), paymentTransactionData.getReference());
|
||||
}
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate payment processing to Payment class. Only revert recipient's last reference if transferring QORA.
|
||||
new Payment(this.repository).orphanReferencesAndFees(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee(),
|
||||
paymentTransactionData.getSignature(), paymentTransactionData.getReference(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -161,12 +161,11 @@ public class ProxyForgingTransaction extends Transaction {
|
||||
// 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()));
|
||||
|
||||
// Update forger's reference
|
||||
forger.setLastReference(proxyForgingTransactionData.getReference());
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
super.orphanReferencesAndFees();
|
||||
|
||||
// If recipient didn't have a last-reference prior to this transaction then remove it
|
||||
Account recipient = new Account(this.repository, proxyForgingTransactionData.getRecipient());
|
||||
|
@ -126,8 +126,6 @@ public class RegisterNameTransaction extends Transaction {
|
||||
// Register Name
|
||||
Name name = new Name(this.repository, registerNameTransactionData);
|
||||
name.register();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,15 +133,6 @@ public class RegisterNameTransaction extends Transaction {
|
||||
// Unregister name
|
||||
Name name = new Name(this.repository, registerNameTransactionData.getName());
|
||||
name.unregister();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update registrant's balance
|
||||
Account registrant = getRegistrant();
|
||||
registrant.setConfirmedBalance(Asset.QORA, registrant.getConfirmedBalance(Asset.QORA).add(registerNameTransactionData.getFee()));
|
||||
|
||||
// Update registrant's reference
|
||||
registrant.setLastReference(registerNameTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -124,13 +124,6 @@ public class RemoveGroupAdminTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with removed group references
|
||||
this.repository.getTransactionRepository().save(removeGroupAdminTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(removeGroupAdminTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(removeGroupAdminTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
@ -116,8 +116,6 @@ public class SellNameTransaction extends Transaction {
|
||||
// Sell Name
|
||||
Name name = new Name(this.repository, sellNameTransactionData.getName());
|
||||
name.sell(sellNameTransactionData);
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -125,15 +123,6 @@ public class SellNameTransaction extends Transaction {
|
||||
// Revert name
|
||||
Name name = new Name(this.repository, sellNameTransactionData.getName());
|
||||
name.unsell(sellNameTransactionData);
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(sellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(sellNameTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,12 +111,6 @@ public class SetGroupTransaction extends Transaction {
|
||||
// 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()));
|
||||
|
||||
// Update admin's reference
|
||||
creator.setLastReference(setGroupTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -909,6 +909,22 @@ public abstract class Transaction {
|
||||
*/
|
||||
public abstract void orphan() throws DataException;
|
||||
|
||||
/**
|
||||
* Update last references, subtract transaction fees, etc.
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update transaction creator's balance
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(transactionData.getFee()));
|
||||
|
||||
// Update transaction creator's reference
|
||||
creator.setLastReference(transactionData.getReference());
|
||||
}
|
||||
|
||||
|
||||
// Comparison
|
||||
|
||||
/** Returns comparator that sorts ATTransactions first, then by timestamp, then by signature */
|
||||
|
@ -100,8 +100,6 @@ public class TransferAssetTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// 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(),
|
||||
transferAssetTransactionData.getSignature());
|
||||
@ -118,9 +116,14 @@ public class TransferAssetTransaction extends Transaction {
|
||||
public void orphan() throws DataException {
|
||||
// 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);
|
||||
transferAssetTransactionData.getSignature(), transferAssetTransactionData.getReference());
|
||||
}
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
@Override
|
||||
public void orphanReferencesAndFees() throws DataException {
|
||||
// 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).orphanReferencesAndFees(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee(),
|
||||
transferAssetTransactionData.getSignature(), transferAssetTransactionData.getReference(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -146,14 +146,6 @@ public class UpdateAssetTransaction extends Transaction {
|
||||
|
||||
// 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();
|
||||
owner.setConfirmedBalance(Asset.QORA,
|
||||
owner.getConfirmedBalance(Asset.QORA).add(updateAssetTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(updateAssetTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -148,13 +148,6 @@ public class UpdateGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, now with removed "group reference"
|
||||
this.repository.getTransactionRepository().save(updateGroupTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(updateGroupTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(updateGroupTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -151,13 +151,6 @@ public class UpdateNameTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, now with removed "name reference"
|
||||
this.repository.getTransactionRepository().save(updateNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(updateNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(updateNameTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -144,12 +144,7 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Update voter's balance
|
||||
Account voter = getVoter();
|
||||
voter.setConfirmedBalance(Asset.QORA, voter.getConfirmedBalance(Asset.QORA).add(voteOnPollTransactionData.getFee()));
|
||||
|
||||
// Update voter's reference
|
||||
voter.setLastReference(voteOnPollTransactionData.getReference());
|
||||
|
||||
// Does this transaction have previous vote info?
|
||||
VotingRepository votingRepository = this.repository.getVotingRepository();
|
||||
|
Loading…
Reference in New Issue
Block a user