Skip to content

Commit

Permalink
Merge pull request #389 from AElfProject/feature/bloom-filter-for-event
Browse files Browse the repository at this point in the history
Bloom filter for event
  • Loading branch information
rosona authored Aug 10, 2018
2 parents 192037c + e4b87af commit 0da66be
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 33 deletions.
8 changes: 8 additions & 0 deletions AElf.ChainControllerImpl/Miner/Miner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public async Task<IBlock> Mine()
res.Logs.AddRange(trace.FlattenedLogs);
res.Status = Status.Mined;
res.RetVal = ByteString.CopyFrom(trace.RetVal.ToFriendlyBytes());
res.Logs.AddRange(trace.FlattenedLogs);
res.UpdateBloom();
}
else
{
Expand All @@ -134,6 +136,12 @@ public async Task<IBlock> Mine()
_logger?.Log(LogLevel.Debug, "Generating block..");
// generate block
var block = await GenerateBlockAsync(Config.ChainId, results);

block.Header.Bloom =ByteString.CopyFrom(
Bloom.AndMultipleBloomBytes(
results.Where(x=>!x.Bloom.IsEmpty).Select(x=>x.Bloom.ToByteArray())
)
);
_logger?.Log(LogLevel.Debug, "Generating block End..");

// sign block
Expand Down
5 changes: 3 additions & 2 deletions AElf.Contracts.Genesis/BasicContractZero.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ namespace AElf.Contracts.Genesis
public class ContractHasBeenDeployed : Event
{
[Indexed] public Hash Creator;

[Indexed] public Hash Address;
[Indexed] public Hash CodeHash;
}

public class OwnerHasBeenChanged : Event
Expand Down Expand Up @@ -108,7 +108,8 @@ public async Task<byte[]> DeploySmartContract(int category, byte[] code)
new ContractHasBeenDeployed()
{
Creator = creator,
Address = address
Address = address,
CodeHash = SHA256.Create().ComputeHash(code)
}.Fire();
*/

Expand Down
161 changes: 161 additions & 0 deletions AElf.Kernel.Tests/BloomTests.cs
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));
}
}
}
132 changes: 132 additions & 0 deletions AElf.Kernel.Types/Bloom.cs
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;
}
}
}
26 changes: 11 additions & 15 deletions AElf.Kernel.Types/Protobuf/Proto/kernel.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ message TransactionResult{
Hash TransactionId = 1;
Status status = 2;
repeated LogEvent Logs = 3;
bytes RetVal = 4;
bytes Bloom = 4;
bytes RetVal = 5;
}

message StateValueChange{
Expand All @@ -45,17 +46,11 @@ message StateValueChange{
bytes AfterValue = 3;
}

message EventField
{
string Name = 1;
google.protobuf.Any Value = 2;
}

message LogEvent
{
Hash Address = 1;
Hash Topic = 2;
repeated EventField Details = 3;
repeated bytes Topics = 2;
bytes Data = 3;
}

message RetVal {
Expand All @@ -80,12 +75,13 @@ message BlockHeader{
Hash PreviousBlockHash = 2;
Hash MerkleTreeRootOfTransactions = 3;
Hash MerkleTreeRootOfWorldState = 4;
uint64 Index = 5;
bytes R = 6;
bytes S = 7;
bytes P = 8;
google.protobuf.Timestamp Time = 9;
Hash ChainId = 10;
bytes Bloom = 5;
uint64 Index = 6;
bytes R = 7;
bytes S = 8;
bytes P = 9;
google.protobuf.Timestamp Time = 10;
Hash ChainId = 11;
}

message BlockBody{
Expand Down
Loading

0 comments on commit 0da66be

Please sign in to comment.