forked from Qortal/qortal
Synchronizer asks for approval-pending transaction from peer if needed
This commit is contained in:
parent
c83d888a7d
commit
041773cf41
@ -37,6 +37,7 @@ 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.GetTransactionMessage;
|
||||
import org.qora.network.message.HeightMessage;
|
||||
import org.qora.network.message.HeightV2Message;
|
||||
import org.qora.network.message.Message;
|
||||
@ -500,7 +501,7 @@ public class Controller extends Thread {
|
||||
break;
|
||||
}
|
||||
|
||||
case GET_BLOCK:
|
||||
case GET_BLOCK: {
|
||||
GetBlockMessage getBlockMessage = (GetBlockMessage) message;
|
||||
byte[] signature = getBlockMessage.getSignature();
|
||||
|
||||
@ -522,6 +523,29 @@ public class Controller extends Thread {
|
||||
LOGGER.error(String.format("Repository issue while send block %s to peer %s", Base58.encode(signature), peer), e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GET_TRANSACTION: {
|
||||
GetTransactionMessage getTransactionMessage = (GetTransactionMessage) message;
|
||||
byte[] signature = getTransactionMessage.getSignature();
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
|
||||
if (transactionData == null) {
|
||||
LOGGER.debug(String.format("Ignoring GET_TRANSACTION request from peer %s for unknown transaction %s", peer, Base58.encode(signature)));
|
||||
// Send no response at all???
|
||||
break;
|
||||
}
|
||||
|
||||
Message transactionMessage = new TransactionMessage(transactionData);
|
||||
transactionMessage.setId(message.getId());
|
||||
if (!peer.sendMessage(transactionMessage))
|
||||
peer.disconnect("failed to send transaction");
|
||||
} catch (DataException e) {
|
||||
LOGGER.error(String.format("Repository issue while send transaction %s to peer %s", Base58.encode(signature), peer), e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TRANSACTION:
|
||||
TransactionMessage transactionMessage = (TransactionMessage) message;
|
||||
|
@ -13,6 +13,8 @@ import org.qora.block.BlockChain;
|
||||
import org.qora.block.GenesisBlock;
|
||||
import org.qora.data.block.BlockData;
|
||||
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.message.BlockMessage;
|
||||
import org.qora.network.message.BlockSummariesMessage;
|
||||
@ -20,13 +22,17 @@ 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.GetTransactionMessage;
|
||||
import org.qora.network.message.Message;
|
||||
import org.qora.network.message.Message.MessageType;
|
||||
import org.qora.network.message.SignaturesMessage;
|
||||
import org.qora.network.message.TransactionMessage;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
import org.qora.repository.RepositoryManager;
|
||||
import org.qora.transaction.Transaction;
|
||||
import org.qora.transaction.Transaction.TransactionType;
|
||||
import org.qora.utils.Base58;
|
||||
import org.qora.utils.NTP;
|
||||
|
||||
public class Synchronizer {
|
||||
@ -231,6 +237,46 @@ public class Synchronizer {
|
||||
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()) {
|
||||
LOGGER.info(String.format("Peer %s sent block with invalid signature for height %d", peer, ourHeight));
|
||||
return SynchronizationResult.INVALID_DATA;
|
||||
@ -391,4 +437,16 @@ 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
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;
|
||||
|
||||
public class GetTransactionMessage extends Message {
|
||||
|
||||
private static final int TRANSACTION_SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
||||
|
||||
private byte[] signature;
|
||||
|
||||
public GetTransactionMessage(byte[] signature) {
|
||||
this(-1, signature);
|
||||
}
|
||||
|
||||
private GetTransactionMessage(int id, byte[] signature) {
|
||||
super(id, MessageType.GET_TRANSACTION);
|
||||
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return this.signature;
|
||||
}
|
||||
|
||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
||||
if (bytes.remaining() != TRANSACTION_SIGNATURE_LENGTH)
|
||||
return null;
|
||||
|
||||
byte[] signature = new byte[TRANSACTION_SIGNATURE_LENGTH];
|
||||
|
||||
bytes.get(signature);
|
||||
|
||||
return new GetTransactionMessage(id, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] toData() {
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(this.signature);
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -64,7 +64,8 @@ public abstract class Message {
|
||||
GET_SIGNATURES_V2(16),
|
||||
PEER_VERIFY(17),
|
||||
VERIFICATION_CODES(18),
|
||||
HEIGHT_V2(19);
|
||||
HEIGHT_V2(19),
|
||||
GET_TRANSACTION(20);
|
||||
|
||||
public final int value;
|
||||
public final Method fromByteBuffer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user