mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-30 23:02:15 +00:00
Send peers a bloom filter from our wallet(s).
This commit is contained in:
parent
394d0b788d
commit
7c03eefefd
@ -129,6 +129,9 @@ public class PeerGroup extends AbstractIdleService {
|
||||
// Visible for testing
|
||||
Peer.PeerLifecycleListener startupListener = new PeerStartupListener();
|
||||
|
||||
// A bloom filter generated from all connected wallets that is given to new peers
|
||||
private BloomFilter bloomFilter;
|
||||
|
||||
/**
|
||||
* Creates a PeerGroup with the given parameters. No chain is provided so this node will report its chain height
|
||||
* as zero to other peers. This constructor is useful if you just want to explore the network but aren't interested
|
||||
@ -523,20 +526,36 @@ public class PeerGroup extends AbstractIdleService {
|
||||
wallet.addEventListener(new AbstractWalletEventListener() {
|
||||
@Override
|
||||
public void onKeyAdded(ECKey key) {
|
||||
recalculateFastCatchupTime();
|
||||
recalculateFastCatchupAndFilter();
|
||||
}
|
||||
});
|
||||
recalculateFastCatchupTime();
|
||||
recalculateFastCatchupAndFilter();
|
||||
}
|
||||
|
||||
private synchronized void recalculateFastCatchupTime() {
|
||||
private synchronized void recalculateFastCatchupAndFilter() {
|
||||
// Fully verifying mode doesn't use this optimization (it can't as it needs to see all transactions).
|
||||
if (chain != null && chain.shouldVerifyTransactions()) return;
|
||||
long earliestKeyTime = Long.MAX_VALUE;
|
||||
int elements = 0;
|
||||
for (Wallet w : wallets) {
|
||||
earliestKeyTime = Math.min(earliestKeyTime, w.getEarliestKeyCreationTime());
|
||||
elements += w.getBloomFilterElementCount();
|
||||
}
|
||||
setFastCatchupTimeSecs(earliestKeyTime);
|
||||
|
||||
if (chain == null || !chain.shouldVerifyTransactions()) {
|
||||
long nTweak = new Random().nextLong();
|
||||
BloomFilter filter = new BloomFilter(elements, 0.001, nTweak);
|
||||
for (Wallet w : wallets)
|
||||
filter.merge(w.getBloomFilter(elements, 0.001, nTweak));
|
||||
bloomFilter = filter;
|
||||
log.info("Sending all peers an updated Bloom Filter.");
|
||||
for (Peer peer : peers)
|
||||
try {
|
||||
// peers of a low version will simply ignore filterload messages
|
||||
peer.sendMessage(filter);
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -647,6 +666,13 @@ public class PeerGroup extends AbstractIdleService {
|
||||
protected synchronized void handleNewPeer(final Peer peer) {
|
||||
// Runs on a netty worker thread for every peer that is newly connected. Peer is not locked at this point.
|
||||
log.info("{}: New peer", peer);
|
||||
// Give the peer a filter that can be used to probabilistically drop transactions that
|
||||
// aren't relevant to our wallet. We may still receive some false positives, which is
|
||||
// OK because it helps improve wallet privacy.
|
||||
try {
|
||||
if (bloomFilter != null)
|
||||
peer.sendMessage(bloomFilter);
|
||||
} catch (IOException e) { } // That was quick...already disconnected
|
||||
// Link the peer to the memory pool so broadcast transactions have their confidence levels updated.
|
||||
peer.setMemoryPool(memoryPool);
|
||||
peer.setDownloadData(false);
|
||||
|
@ -137,8 +137,10 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
inv.addTransaction(t1);
|
||||
|
||||
inbound(p1, inv);
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
inbound(p2, inv);
|
||||
assertTrue(outbound(p2) instanceof BloomFilter);
|
||||
assertNull(outbound(p2)); // Only one peer is used to download.
|
||||
inbound(p1, t1);
|
||||
assertNull(outbound(p2));
|
||||
@ -181,7 +183,9 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
// Only peer 1 tries to download it.
|
||||
inbound(p1, inv);
|
||||
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
assertTrue(outbound(p2) instanceof BloomFilter);
|
||||
assertNull(outbound(p2));
|
||||
// Peer 1 goes away.
|
||||
closePeer(peerOf(p1));
|
||||
@ -209,6 +213,7 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
// Expect a zero hash getblocks on p1. This is how the process starts.
|
||||
peerGroup.startBlockChainDownload(new AbstractPeerEventListener() {
|
||||
});
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
GetBlocksMessage getblocks = (GetBlocksMessage) outbound(p1);
|
||||
assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
|
||||
// We give back an inv with some blocks in it.
|
||||
@ -223,6 +228,7 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
inbound(p1, b1);
|
||||
// Now we successfully connect to another peer. There should be no messages sent.
|
||||
FakeChannel p2 = connectPeer(2);
|
||||
assertTrue(outbound(p2) instanceof BloomFilter);
|
||||
Message message = (Message)outbound(p2);
|
||||
assertNull(message == null ? "" : message.toString(), message);
|
||||
peerGroup.stop();
|
||||
@ -250,12 +256,14 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
|
||||
// Peer 2 advertises the tx but does not download it.
|
||||
inbound(p2, inv);
|
||||
assertTrue(outbound(p2) instanceof BloomFilter);
|
||||
assertTrue(outbound(p2) instanceof GetDataMessage);
|
||||
assertEquals(0, tx.getConfidence().numBroadcastPeers());
|
||||
assertTrue(peerGroup.getMemoryPool().maybeWasSeen(tx.getHash()));
|
||||
assertNull(event[0]);
|
||||
// Peer 1 advertises the tx, we don't do anything as it's already been requested.
|
||||
inbound(p1, inv);
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
assertNull(outbound(p1));
|
||||
inbound(p2, tx);
|
||||
assertNull(outbound(p2));
|
||||
@ -300,6 +308,7 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
// Send ourselves a bit of money.
|
||||
Block b1 = TestUtils.makeSolvedTestBlock(params, blockStore, address);
|
||||
inbound(p1, b1);
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
assertNull(outbound(p1));
|
||||
|
||||
assertEquals(Utils.toNanoCoins(50, 0), wallet.getBalance());
|
||||
@ -350,10 +359,12 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
GetDataMessage getdata = new GetDataMessage(params);
|
||||
getdata.addItem(inv1.getItems().get(0));
|
||||
inbound(p1, getdata);
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
Transaction t4 = (Transaction) outbound(p1);
|
||||
assertEquals(t3, t4);
|
||||
|
||||
FakeChannel p3 = connectPeer(3);
|
||||
assertTrue(outbound(p3) instanceof BloomFilter);
|
||||
assertTrue(outbound(p3) instanceof InventoryMessage);
|
||||
control.verify();
|
||||
}
|
||||
@ -394,6 +405,7 @@ public class PeerGroupTest extends TestWithNetworkConnections {
|
||||
VersionMessage versionMessage = new VersionMessage(params, 2);
|
||||
versionMessage.clientVersion = Pong.MIN_PROTOCOL_VERSION;
|
||||
FakeChannel p1 = connectPeer(1, versionMessage);
|
||||
assertTrue(outbound(p1) instanceof BloomFilter);
|
||||
Ping ping = (Ping) outbound(p1);
|
||||
inbound(p1, new Pong(ping.getNonce()));
|
||||
assertTrue(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE);
|
||||
|
Loading…
Reference in New Issue
Block a user