Skip to content

Commit

Permalink
feat(mpt): list all states in a tree
Browse files Browse the repository at this point in the history
  • Loading branch information
moreal committed Oct 8, 2020
1 parent 26b8eb5 commit 1e465ae
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Libplanet.Tests/ImmutableArrayEqualityComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace Libplanet.Tests
{
public class ImmutableArrayEqualityComparer<T> : IEqualityComparer<ImmutableArray<T>>
{
public bool Equals(ImmutableArray<T> x, ImmutableArray<T> y)
=> x.Length == y.Length && x.SequenceEqual(y);

public int GetHashCode(ImmutableArray<T> obj)
{
int code = 0;
unchecked
{
foreach (T el in obj)
{
code = (code * 397) ^ el.GetHashCode();
}
}

return code;
}
}
}
34 changes: 34 additions & 0 deletions Libplanet.Tests/Store/Trie/MerkleTrieExtensionsTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Security.Cryptography;
using Bencodex.Types;
Expand Down Expand Up @@ -39,5 +40,38 @@ public void DifferentNodes()
Assert.Equal(trieA.Hash, differentNodes["03"][0].Root);
Assert.Equal(trieB.Hash, differentNodes["04"][0].Root);
}

[Fact]
public void ListAllStates()
{
IKeyValueStore keyValueStore = new MemoryKeyValueStore();
MerkleTrie trie = new MerkleTrie(keyValueStore);

trie.Set(new byte[] { 0x01, }, default(Null));
trie.Set(new byte[] { 0x02, }, default(Null));
trie.Set(new byte[] { 0x03, }, default(Null));
trie.Set(new byte[] { 0x04, }, default(Null));
trie.Set(new byte[] { 0xbe, 0xef }, Dictionary.Empty);

Dictionary<ImmutableArray<byte>, IValue> states =
new Dictionary<ImmutableArray<byte>, IValue>(
trie.ListAllStates(), new ImmutableArrayEqualityComparer<byte>());
Assert.Equal(5, states.Count);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x01)]);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x02)]);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x03)]);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x04)]);
Assert.Equal(Dictionary.Empty, states[ImmutableArray<byte>.Empty.Add(0xbe).Add(0xef)]);

trie = (MerkleTrie)trie.Commit();
states = new Dictionary<ImmutableArray<byte>, IValue>(
trie.ListAllStates(), new ImmutableArrayEqualityComparer<byte>());
Assert.Equal(5, states.Count);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x01)]);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x02)]);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x03)]);
Assert.Equal(default(Null), states[ImmutableArray<byte>.Empty.Add(0x04)]);
Assert.Equal(Dictionary.Empty, states[ImmutableArray<byte>.Empty.Add(0xbe).Add(0xef)]);
}
}
}
14 changes: 14 additions & 0 deletions Libplanet/Store/Trie/MerkleTrieExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ public static class MerkleTrieExtensions
group.Count() == 1 || !group.All(v => v.Value.Equals(group.First().Value)));
}

/// <summary>
/// Lists the all states key and the all states in the given <paramref name="merkleTrie"/>.
/// </summary>
/// <param name="merkleTrie">A trie to discover.</param>
/// <returns>All state keys and the all states.</returns>
public static IEnumerable<KeyValuePair<ImmutableArray<byte>, IValue>> ListAllStates(
this MerkleTrie merkleTrie)
{
return merkleTrie.IterateNodes().Where(pair => pair.Node is ValueNode).Select(pair =>
new KeyValuePair<ImmutableArray<byte>, IValue>(
FromKey(pair.Path),
((ValueNode)pair.Node).Value));
}

private static ImmutableArray<byte> FromKey(ImmutableArray<byte> bytes)
{
if (bytes.Length % 2 == 1)
Expand Down

0 comments on commit 1e465ae

Please sign in to comment.