-
Notifications
You must be signed in to change notification settings - Fork 264
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #389 from AElfProject/feature/bloom-filter-for-event
Bloom filter for event
- Loading branch information
Showing
7 changed files
with
354 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using AElf.Common.ByteArrayHelpers; | ||
using Google.Protobuf; | ||
using Google.Protobuf.WellKnownTypes; | ||
using QuickGraph; | ||
using Xunit; | ||
|
||
namespace AElf.Kernel.Tests | ||
{ | ||
public class BloomTests | ||
{ | ||
[Fact] | ||
public void LengthTest() | ||
{ | ||
var bloom = new Bloom(); | ||
Assert.Equal(256, bloom.Data.Length); | ||
} | ||
|
||
[Fact] | ||
public void AddHashAddValueTest() | ||
{ | ||
var empty = BytesValue.Parser.ParseFrom(ByteString.Empty); | ||
var elf = new StringValue() | ||
{ | ||
Value = "ELF" | ||
}; // Serialized: 0a03454c46 | ||
// sha256 of empty string: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 | ||
// sha256 of 0a03454c46: 782330156f8c9403758ed30270a3e2d59e50b8f04c6779d819b72eee02addb13 | ||
var expected = string.Concat( | ||
"0000000000000000000000000000100000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000040000000000000000", | ||
"0000000000000000000100000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000800200000" | ||
); | ||
var bloom = new Bloom(); | ||
bloom.AddSha256Hash( | ||
ByteArrayHelpers.FromHexString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); | ||
bloom.AddSha256Hash( | ||
ByteArrayHelpers.FromHexString("782330156f8c9403758ed30270a3e2d59e50b8f04c6779d819b72eee02addb13")); | ||
Assert.Equal(expected, bloom.Data.ToHex().Replace("0x", "")); | ||
|
||
// add value | ||
var bloom1 = new Bloom(); | ||
bloom1.AddValue(empty); | ||
bloom1.AddValue(elf); | ||
Assert.Equal(expected, bloom1.Data.ToHex().Replace("0x", "")); | ||
|
||
// Take only 12 characters (2 * 3 = 6 bytes) | ||
var bloom2 = new Bloom(); | ||
var fiftyTwoZeros = string.Join("", Enumerable.Repeat("0", 52)); | ||
|
||
// Too short | ||
Assert.ThrowsAny<Exception>(() => bloom2.AddSha256Hash(ByteArrayHelpers.FromHexString("e3b0c44298fc"))); | ||
Assert.ThrowsAny<Exception>(() => bloom2.AddSha256Hash(ByteArrayHelpers.FromHexString("782330156f8c"))); | ||
|
||
// Too long | ||
|
||
Assert.ThrowsAny<Exception>(() => | ||
bloom2.AddSha256Hash(ByteArrayHelpers.FromHexString("e3b0c44298fc" + "00" + fiftyTwoZeros))); | ||
Assert.ThrowsAny<Exception>(() => | ||
bloom2.AddSha256Hash(ByteArrayHelpers.FromHexString("782330156f8c" + "00" + fiftyTwoZeros))); | ||
|
||
// Right size | ||
bloom2.AddSha256Hash(ByteArrayHelpers.FromHexString("e3b0c44298fc" + fiftyTwoZeros)); | ||
bloom2.AddSha256Hash(ByteArrayHelpers.FromHexString("782330156f8c" + fiftyTwoZeros)); | ||
Assert.Equal(expected, bloom2.Data.ToHex().Replace("0x", "")); | ||
|
||
// Incorrect value | ||
var bloom3 = new Bloom(); | ||
bloom3.AddSha256Hash(ByteArrayHelpers.FromHexString("e3b0c44298f0" + fiftyTwoZeros)); | ||
bloom3.AddSha256Hash(ByteArrayHelpers.FromHexString("782330156f80" + fiftyTwoZeros)); | ||
Assert.NotEqual(expected, bloom3.Data.ToHex().Replace("0x", "")); | ||
} | ||
|
||
[Fact] | ||
public void MultiMergeTest() | ||
{ | ||
var a = ByteArrayHelpers.FromHexString(string.Concat( | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000" | ||
)); | ||
|
||
var b = ByteArrayHelpers.FromHexString(string.Concat( | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000", | ||
"0100000000000000000000000000000000000000000000000000000000000000" | ||
)); | ||
|
||
var c = ByteArrayHelpers.FromHexString(string.Concat( | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000", | ||
"1100000000000000000000000000000000000000000000000000000000000000" | ||
)); | ||
|
||
var res = Bloom.AndMultipleBloomBytes(new List<byte[]>(){a, b}); | ||
Assert.Equal(c, res); | ||
} | ||
|
||
[Fact] | ||
public void IsInTest() | ||
{ | ||
var target = new Bloom(ByteArrayHelpers.FromHexString(string.Concat( | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000" | ||
))); | ||
var source = new Bloom(ByteArrayHelpers.FromHexString(string.Concat( | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"1000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000" | ||
))); | ||
Assert.True(source.IsIn(target)); | ||
|
||
var wrongSource = new Bloom(ByteArrayHelpers.FromHexString(string.Concat( | ||
"1110000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000", | ||
"0000000000000000000000000000000000000000000000000000000000000000" | ||
))); | ||
|
||
Assert.False(wrongSource.IsIn(target)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using Google.Protobuf; | ||
using System.Security.Cryptography; | ||
|
||
namespace AElf.Kernel | ||
{ | ||
public class Bloom | ||
{ | ||
private static byte[] GetNewEmptyBytes() | ||
{ | ||
var bytes = new byte[256]; | ||
for (int i = 0; i < 256; i++) | ||
{ | ||
bytes[i] = 0x00; | ||
} | ||
|
||
return bytes; | ||
} | ||
|
||
public static byte[] AndMultipleBloomBytes(IEnumerable<byte[]> multipleBytes) | ||
{ | ||
var res = GetNewEmptyBytes(); | ||
foreach (var bytes in multipleBytes) | ||
{ | ||
if (bytes.Length != 256) | ||
{ | ||
throw new InvalidOperationException("Bloom data has to be 256 bytes long."); | ||
} | ||
|
||
for (int i = 0; i < 256; i++) | ||
{ | ||
res[i] |= bytes[i]; | ||
} | ||
} | ||
|
||
return res; | ||
} | ||
|
||
private const uint BucketPerVal = 3; // number of hash functions | ||
private byte[] _data; | ||
|
||
public byte[] Data => _data; | ||
|
||
public Bloom() | ||
{ | ||
_data = GetNewEmptyBytes(); | ||
} | ||
|
||
public Bloom(byte[] data) | ||
{ | ||
if (data.Length != 256) | ||
{ | ||
throw new InvalidOperationException("Bloom data has to be 256 bytes long."); | ||
} | ||
|
||
_data = (byte[]) data.Clone(); | ||
} | ||
|
||
public Bloom(Bloom bloom) : this(bloom.Data) | ||
{ | ||
} | ||
|
||
public void AddValue(byte[] bytes) | ||
{ | ||
var hash = SHA256.Create().ComputeHash(bytes); | ||
AddSha256Hash(hash); | ||
} | ||
|
||
public void AddValue(IMessage message) | ||
{ | ||
var bytes = message.ToByteArray(); | ||
AddValue(bytes); | ||
} | ||
|
||
public void AddValue(ISerializable serializable) | ||
{ | ||
var bytes = serializable.Serialize(); | ||
AddValue(bytes); | ||
} | ||
|
||
public void AddSha256Hash(byte[] hash256) | ||
{ | ||
if (hash256.Length != 32) | ||
{ | ||
throw new InvalidOperationException("Invalid input."); | ||
} | ||
|
||
for (uint i = 0; i < BucketPerVal * 2; i += 2) | ||
{ | ||
var index = ((hash256[i] << 8) | hash256[i + 1]) & 2047; | ||
var byteToSet = (byte) (((uint) 1) << (index % 8)); | ||
_data[255 - index / 8] |= byteToSet; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Combines some other blooms into current bloom. | ||
/// </summary> | ||
/// <param name="blooms">Other blooms</param> | ||
public void Combine(IEnumerable<Bloom> blooms) | ||
{ | ||
foreach (var bloom in blooms) | ||
{ | ||
for (int i = 0; i < 256; i++) | ||
{ | ||
_data[i] |= bloom.Data[i]; | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Checks if current bloom is contained in the input bloom. | ||
/// </summary> | ||
/// <param name="bloom">Other bloom</param> | ||
/// <returns></returns> | ||
public bool IsIn(Bloom bloom) | ||
{ | ||
for (int i = 0; i < 256; i++) | ||
{ | ||
var curByte = _data[i]; | ||
if ((curByte & bloom.Data[i]) != curByte) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.