3
0
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:
Matt Corallo 2012-07-21 16:36:39 +02:00
parent 394d0b788d
commit 7c03eefefd
2 changed files with 41 additions and 3 deletions

View File

@ -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);

View File

@ -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);