Browse Source

Minor integration progress

Remove fetching unconfirmed from Synchronizer

Add extra validity/reference/processable checks to
Transaction.isValidUnconfirmed

Update TransactionUtils to use Transaction.importAsUnconfirmed
for unit tests.
pull/67/head
catbref 5 years ago
parent
commit
da1bd82c19
  1. 58
      src/main/java/org/qora/controller/Synchronizer.java
  2. 19
      src/main/java/org/qora/transaction/Transaction.java
  3. 4
      src/test/java/org/qora/test/common/TransactionUtils.java

58
src/main/java/org/qora/controller/Synchronizer.java

@ -13,8 +13,6 @@ import org.qora.block.BlockChain;
import org.qora.block.GenesisBlock; import org.qora.block.GenesisBlock;
import org.qora.data.block.BlockData; import org.qora.data.block.BlockData;
import org.qora.data.network.BlockSummaryData; import org.qora.data.network.BlockSummaryData;
import org.qora.data.transaction.GroupApprovalTransactionData;
import org.qora.data.transaction.TransactionData;
import org.qora.network.Peer; import org.qora.network.Peer;
import org.qora.network.message.BlockMessage; import org.qora.network.message.BlockMessage;
import org.qora.network.message.BlockSummariesMessage; import org.qora.network.message.BlockSummariesMessage;
@ -22,17 +20,13 @@ import org.qora.network.message.GetBlockMessage;
import org.qora.network.message.GetBlockSummariesMessage; import org.qora.network.message.GetBlockSummariesMessage;
import org.qora.network.message.GetSignaturesMessage; import org.qora.network.message.GetSignaturesMessage;
import org.qora.network.message.GetSignaturesV2Message; import org.qora.network.message.GetSignaturesV2Message;
import org.qora.network.message.GetTransactionMessage;
import org.qora.network.message.Message; import org.qora.network.message.Message;
import org.qora.network.message.Message.MessageType; import org.qora.network.message.Message.MessageType;
import org.qora.network.message.SignaturesMessage; import org.qora.network.message.SignaturesMessage;
import org.qora.network.message.TransactionMessage;
import org.qora.repository.DataException; import org.qora.repository.DataException;
import org.qora.repository.Repository; import org.qora.repository.Repository;
import org.qora.repository.RepositoryManager; import org.qora.repository.RepositoryManager;
import org.qora.transaction.Transaction; import org.qora.transaction.Transaction;
import org.qora.transaction.Transaction.TransactionType;
import org.qora.utils.Base58;
import org.qora.utils.NTP; import org.qora.utils.NTP;
public class Synchronizer { public class Synchronizer {
@ -237,46 +231,6 @@ public class Synchronizer {
return SynchronizationResult.NO_REPLY; return SynchronizationResult.NO_REPLY;
} }
// If block contains GROUP_APPROVAL transactions then we need to make sure we have the relevant pending transactions too
for (Transaction transaction : newBlock.getTransactions()) {
TransactionData transactionData = transaction.getTransactionData();
if (transactionData.getType() != TransactionType.GROUP_APPROVAL)
continue;
GroupApprovalTransactionData groupApprovalTransactionData = (GroupApprovalTransactionData) transactionData;
byte[] pendingSignature = groupApprovalTransactionData.getPendingSignature();
if (repository.getTransactionRepository().exists(pendingSignature))
continue;
LOGGER.debug(String.format("Fetching unknown approval-pending transaction %s from peer %s, needed for block at height %d", Base58.encode(pendingSignature), peer, ourHeight));
TransactionData pendingTransactionData = this.fetchTransaction(peer, pendingSignature);
if (pendingTransactionData == null) {
LOGGER.info(String.format("Peer %s failed to respond with pending transaction %s", peer, Base58.encode(pendingSignature)));
return SynchronizationResult.NO_REPLY;
}
// Check the signature is valid at least!
Transaction pendingTransaction = Transaction.fromData(repository, pendingTransactionData);
if (!pendingTransaction.isSignatureValid()) {
LOGGER.info(String.format("Peer %s sent pending transaction %s with invalid signature", peer, Base58.encode(pendingSignature)));
return SynchronizationResult.INVALID_DATA;
}
Transaction.ValidationResult transactionResult = pendingTransaction.isValidUnconfirmed();
if (transactionResult != Transaction.ValidationResult.OK) {
LOGGER.info(String.format("Peer %s sent invalid (%s) pending transaction %s", peer, transactionResult.name(), Base58.encode(pendingSignature)));
return SynchronizationResult.INVALID_DATA;
}
// Add to our unconfirmed pile
this.repository.getTransactionRepository().save(pendingTransactionData);
this.repository.getTransactionRepository().unconfirmTransaction(pendingTransactionData);
}
if (!newBlock.isSignatureValid()) { if (!newBlock.isSignatureValid()) {
LOGGER.info(String.format("Peer %s sent block with invalid signature for height %d", peer, ourHeight)); LOGGER.info(String.format("Peer %s sent block with invalid signature for height %d", peer, ourHeight));
return SynchronizationResult.INVALID_DATA; return SynchronizationResult.INVALID_DATA;
@ -437,16 +391,4 @@ public class Synchronizer {
} }
} }
private TransactionData fetchTransaction(Peer peer, byte[] signature) {
Message getTransactionMessage = new GetTransactionMessage(signature);
Message message = peer.getResponse(getTransactionMessage);
if (message == null || message.getType() != MessageType.TRANSACTION)
return null;
TransactionMessage transactionMessage = (TransactionMessage) message;
return transactionMessage.getTransactionData();
}
} }

19
src/main/java/org/qora/transaction/Transaction.java

@ -548,7 +548,17 @@ public abstract class Transaction {
if (unconfirmedLastReference != null) if (unconfirmedLastReference != null)
creator.setLastReference(unconfirmedLastReference); creator.setLastReference(unconfirmedLastReference);
// Check transaction is valid
ValidationResult result = this.isValid(); ValidationResult result = this.isValid();
if (result != ValidationResult.OK)
return result;
// Check transaction references
if (!this.hasValidReference())
return ValidationResult.INVALID_REFERENCE;
// Check transction is processable
result = this.isProcessable();
return result; return result;
} finally { } finally {
@ -807,7 +817,13 @@ public abstract class Transaction {
return null; return null;
} }
/** Import into our repository as a new, unconfirmed transaction. */ /**
* Import into our repository as a new, unconfirmed transaction.
* <p>
* Calls <tt>repository.saveChanges()</tt>
*
* @throws DataException
*/
public void importAsUnconfirmed() throws DataException { public void importAsUnconfirmed() throws DataException {
// Fix up approval status // Fix up approval status
if (this.needsGroupApproval()) { if (this.needsGroupApproval()) {
@ -829,6 +845,7 @@ public abstract class Transaction {
* Transactions that have already been processed will return false. * Transactions that have already been processed will return false.
* *
* @return true if transaction can be processed, false otherwise * @return true if transaction can be processed, false otherwise
* @throws DataException
*/ */
public abstract ValidationResult isValid() throws DataException; public abstract ValidationResult isValid() throws DataException;

4
src/test/java/org/qora/test/common/TransactionUtils.java

@ -33,9 +33,7 @@ public class TransactionUtils {
ValidationResult result = transaction.isValidUnconfirmed(); ValidationResult result = transaction.isValidUnconfirmed();
assertEquals("Transaction invalid", ValidationResult.OK, result); assertEquals("Transaction invalid", ValidationResult.OK, result);
repository.getTransactionRepository().save(transactionData); transaction.importAsUnconfirmed();
repository.getTransactionRepository().unconfirmTransaction(transactionData);
repository.saveChanges();
} }
public static void signAndForge(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException { public static void signAndForge(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException {

Loading…
Cancel
Save