3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 15:22:16 +00:00

TransactionBroadcast: refactor

This commit is contained in:
Mike Hearn 2013-11-10 18:08:50 +01:00
parent 8b8266f9d6
commit a68bc627ee

View File

@ -55,7 +55,11 @@ public class TransactionBroadcast {
public ListenableFuture<Transaction> broadcast() {
log.info("Waiting for {} peers required for broadcast ...", minConnections);
ListenableFuture<PeerGroup> peerAvailabilityFuture = peerGroup.waitForPeers(minConnections);
peerAvailabilityFuture.addListener(new Runnable() {
peerAvailabilityFuture.addListener(new EnoughAvailablePeers(), Threading.SAME_THREAD);
return future;
}
private class EnoughAvailablePeers implements Runnable {
public void run() {
// We now have enough connected peers to send the transaction.
// This can be called immediately if we already have enough. Otherwise it'll be called from a peer
@ -68,8 +72,38 @@ public class TransactionBroadcast {
final Transaction pinnedTx = peerGroup.getMemoryPool().seen(tx, somePeer.getAddress());
// Prepare to send the transaction by adding a listener that'll be called when confidence changes.
// Only bother with this if we might actually hear back:
if (minConnections > 1) pinnedTx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
public void onConfidenceChanged(Transaction tx, TransactionConfidence.Listener.ChangeReason reason) {
if (minConnections > 1)
pinnedTx.getConfidence().addEventListener(new ConfidenceChange(pinnedTx));
// Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
// blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
// just a single connection we don't have to wait for getdata to be received and handled before
// completing the future in the code immediately below. Secondly, it's faster. The reason the
// Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
// transaction or not. However, we are not a fully validating node and this is advertised in
// our version message, as SPV nodes cannot relay it doesn't give away any additional information
// to skip the inv here - we wouldn't send invs anyway.
//
// TODO: The peer we picked might be dead by now. If we can't write the message, pick again and retry.
somePeer.sendMessage(pinnedTx);
// If we've been limited to talk to only one peer, we can't wait to hear back because the
// remote peer won't tell us about transactions we just announced to it for obvious reasons.
// So we just have to assume we're done, at that point. This happens when we're not given
// any peer discovery source and the user just calls connectTo() once.
if (minConnections == 1) {
future.set(pinnedTx);
}
}
}
private class ConfidenceChange implements TransactionConfidence.Listener {
private final Transaction pinnedTx;
public ConfidenceChange(Transaction pinnedTx) {
this.pinnedTx = pinnedTx;
}
public void onConfidenceChanged(Transaction tx, ChangeReason reason) {
// The number of peers that announced this tx has gone up.
final TransactionConfidence conf = tx.getConfidence();
int numSeenPeers = conf.numBroadcastPeers();
@ -95,28 +129,5 @@ public class TransactionBroadcast {
tx.getConfidence().removeEventListener(this);
future.set(pinnedTx); // RE-ENTRANCY POINT
}
});
// Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
// blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
// just a single connection we don't have to wait for getdata to be received and handled before
// completing the future in the code immediately below. Secondly, it's faster. The reason the
// Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
// transaction or not. However, we are not a fully validating node and this is advertised in
// our version message, as SPV nodes cannot relay it doesn't give away any additional information
// to skip the inv here - we wouldn't send invs anyway.
//
// TODO: The peer we picked might be dead by now. If we can't write the message, pick again and retry.
somePeer.sendMessage(pinnedTx);
// If we've been limited to talk to only one peer, we can't wait to hear back because the
// remote peer won't tell us about transactions we just announced to it for obvious reasons.
// So we just have to assume we're done, at that point. This happens when we're not given
// any peer discovery source and the user just calls connectTo() once.
if (minConnections == 1) {
future.set(pinnedTx);
}
}
}, Threading.SAME_THREAD);
return future;
}
}