3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-30 23:02:15 +00:00

Add the new nFlags BloomFilter fields to control auto-updating.

This commit is contained in:
Matt Corallo 2013-01-14 12:29:54 -05:00
parent 3906aa62d9
commit 1ea4cb457d
3 changed files with 29 additions and 6 deletions

View File

@ -37,9 +37,19 @@ import com.google.common.base.Preconditions;
* which match the filter but are not actually ours.</p>
*/
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);
}
/**
* <p>Constructs a new Bloom Filter which will provide approximately the given false positive
* rate when the given number of elements have been inserted.</p>
@ -82,8 +99,10 @@ public class BloomFilter extends Message {
*
* <p>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.</p>
*
* <p>updateFlag is used to control filter behavior</p>
*/
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

View File

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

View File

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