From 1ea4cb457d284285a30d31291a3b229c2e533081 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 14 Jan 2013 12:29:54 -0500 Subject: [PATCH] Add the new nFlags BloomFilter fields to control auto-updating. --- .../com/google/bitcoin/core/BloomFilter.java | 25 ++++++++++++++++++- .../google/bitcoin/core/BloomFilterTest.java | 8 +++--- ...ilteredBlockAndPartialMerkelTreeTests.java | 2 +- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/core/BloomFilter.java b/core/src/main/java/com/google/bitcoin/core/BloomFilter.java index 904c5a34..8ee3bc2d 100644 --- a/core/src/main/java/com/google/bitcoin/core/BloomFilter.java +++ b/core/src/main/java/com/google/bitcoin/core/BloomFilter.java @@ -37,9 +37,19 @@ import com.google.common.base.Preconditions; * which match the filter but are not actually ours.

*/ public class BloomFilter extends Message { + /** The BLOOM_UPDATE_* constants control when the bloom filter is auto-updated by the peer using + it as a filter, either never, for all outputs or only for pay-2-pubkey outputs (default) */ + public enum bloomUpdate { + UPDATE_NONE, // 0 + UPDATE_ALL, // 1 + /** Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script */ + UPDATE_P2PUBKEY_ONLY //2 + } + private byte[] data; private long hashFuncs; private long nTweak; + private byte nFlags; // Same value as the reference client // A filter of 20,000 items and a false positive rate of 0.1% or one of 10,000 items and 0.0001% is just under 36,000 bytes @@ -54,6 +64,13 @@ public class BloomFilter extends Message { super(params, payloadBytes, 0); } + /** + * Constructs a filter with the given parameters which is updated on pay2pubkey outputs only. + */ + public BloomFilter(int elements, double falsePositiveRate, long randomNonce) { + this(elements, falsePositiveRate, randomNonce, bloomUpdate.UPDATE_P2PUBKEY_ONLY); + } + /** *

Constructs a new Bloom Filter which will provide approximately the given false positive * rate when the given number of elements have been inserted.

@@ -82,8 +99,10 @@ public class BloomFilter extends Message { * *

randomNonce is a tweak for the hash function used to prevent some theoretical DoS attacks. * It should be a random value, however secureness of the random value is of no great consequence.

+ * + *

updateFlag is used to control filter behavior

*/ - public BloomFilter(int elements, double falsePositiveRate, long randomNonce) { + public BloomFilter(int elements, double falsePositiveRate, long randomNonce, bloomUpdate updateFlag) { // The following formulas were stolen from Wikipedia's page on Bloom Filters (with the addition of min(..., MAX_...)) // Size required for a given number of elements and false-positive rate int size = Math.min((int)(-1 / (Math.pow(Math.log(2), 2)) * elements * Math.log(falsePositiveRate)), @@ -92,6 +111,7 @@ public class BloomFilter extends Message { // Optimal number of hash functions for a given filter size and element count. hashFuncs = Math.min((int)(data.length * 8 / elements * Math.log(2)), MAX_HASH_FUNCS); this.nTweak = randomNonce; + this.nFlags = (byte)(0xff & updateFlag.ordinal()); } /** @@ -117,6 +137,8 @@ public class BloomFilter extends Message { throw new ProtocolException("Bloom filter hash function count out of range"); nTweak = readUint32(); + + nFlags = readBytes(1)[0]; length = cursor - offset; } @@ -129,6 +151,7 @@ public class BloomFilter extends Message { stream.write(data); Utils.uint32ToByteStreamLE(hashFuncs, stream); Utils.uint32ToByteStreamLE(nTweak, stream); + stream.write(nFlags); } @Override diff --git a/core/src/test/java/com/google/bitcoin/core/BloomFilterTest.java b/core/src/test/java/com/google/bitcoin/core/BloomFilterTest.java index f946bf29..a2dedcfa 100644 --- a/core/src/test/java/com/google/bitcoin/core/BloomFilterTest.java +++ b/core/src/test/java/com/google/bitcoin/core/BloomFilterTest.java @@ -9,7 +9,7 @@ import org.spongycastle.util.encoders.Hex; public class BloomFilterTest { @Test public void insertSerializeTest() { - BloomFilter filter = new BloomFilter(3, 0.01, 0); + BloomFilter filter = new BloomFilter(3, 0.01, 0, BloomFilter.bloomUpdate.UPDATE_ALL); filter.insert(Hex.decode("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); assertTrue (filter.contains(Hex.decode("99108ad8ed9bb6274d3980bab5a85c048f0950c8"))); @@ -23,7 +23,7 @@ public class BloomFilterTest { assertTrue(filter.contains(Hex.decode("b9300670b4c5366e95b2699e8b18bc75e5f729c5"))); // Value generated by the reference client - assertTrue(Arrays.equals(Hex.decode("03614e9b0500000000000000"), filter.bitcoinSerialize())); + assertTrue(Arrays.equals(Hex.decode("03614e9b050000000000000001"), filter.bitcoinSerialize())); } @Test @@ -42,7 +42,7 @@ public class BloomFilterTest { assertTrue(filter.contains(Hex.decode("b9300670b4c5366e95b2699e8b18bc75e5f729c5"))); // Value generated by the reference client - assertTrue(Arrays.equals(Hex.decode("03ce42990500000001000080"), filter.bitcoinSerialize())); + assertTrue(Arrays.equals(Hex.decode("03ce4299050000000100008002"), filter.bitcoinSerialize())); } @Test @@ -70,6 +70,6 @@ public class BloomFilterTest { BloomFilter filter = wallet.getBloomFilter(wallet.getBloomFilterElementCount(), 0.001, 0); // Value generated by the reference client - assertTrue(Arrays.equals(Hex.decode("082ae5edc8e51d4a030800000000000000"), filter.bitcoinSerialize())); + assertTrue(Arrays.equals(Hex.decode("082ae5edc8e51d4a03080000000000000002"), filter.bitcoinSerialize())); } } diff --git a/core/src/test/java/com/google/bitcoin/core/FilteredBlockAndPartialMerkelTreeTests.java b/core/src/test/java/com/google/bitcoin/core/FilteredBlockAndPartialMerkelTreeTests.java index 1fecb76e..3e4d8820 100644 --- a/core/src/test/java/com/google/bitcoin/core/FilteredBlockAndPartialMerkelTreeTests.java +++ b/core/src/test/java/com/google/bitcoin/core/FilteredBlockAndPartialMerkelTreeTests.java @@ -87,7 +87,7 @@ public class FilteredBlockAndPartialMerkelTreeTests extends TestWithPeerGroup { BloomFilter filter = wallet.getBloomFilter(wallet.getKeychainSize()*2, 0.001, 0xDEADBEEF); // Compare the serialized bloom filter to a known-good value - assertTrue(Arrays.equals(filter.bitcoinSerialize(), Hex.decode("0e1b091ca195e45a9164889b6bc46a09000000efbeadde"))); + assertTrue(Arrays.equals(filter.bitcoinSerialize(), Hex.decode("0e1b091ca195e45a9164889b6bc46a09000000efbeadde02"))); // Cheat and place the previous block (block 100000) at the head of the block store without supporting blocks blockStore = new MemoryBlockStore(NetworkParameters.unitTests());