Skip to content

Commit

Permalink
Merge pull request #1026 from moreal/feature/export-trie-states
Browse files Browse the repository at this point in the history
Export all states as JSON
  • Loading branch information
moreal committed Oct 14, 2020
2 parents 9253899 + 2aa5a6c commit 2f6e94d
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 2 deletions.
5 changes: 3 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,8 @@ To be released.
- The `planet` command became installable using `npm`. [[#923], [#982]]
- Fixed a bug that <kbd>^H</kbd> had not removed the rightmost character
in passphrase prompts. [[#983], [#984]]
- Added a new sub-command `planet mpt`. [[#1023]]
- Introduced a configuration file. It's placed in: [[#1023]]
- Added a new sub-command `planet mpt`. [[#1023], [#1026]]
- Introduced a configuration file. It's placed in: [[#1023], [#1026]]
- Linux/macOS: *<var>$XDG_CONFIG_HOME</var>/planetarium/cli.json*
- Windows: *<var>%AppData%</var>\planetarium\cli.json*

Expand Down Expand Up @@ -377,6 +377,7 @@ To be released.
[#1021]: https://github.com/planetarium/libplanet/pull/1021
[#1022]: https://github.com/planetarium/libplanet/pull/1022
[#1023]: https://github.com/planetarium/libplanet/pull/1023
[#1026]: https://github.com/planetarium/libplanet/pull/1026
[sleep mode]: https://en.wikipedia.org/wiki/Sleep_mode


Expand Down
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;
}
}
}
38 changes: 38 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,42 @@ 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 =
trie.ListAllStates().ToDictionary(
pair => pair.Key,
pair => pair.Value,
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 = trie.ListAllStates().ToDictionary(
pair => pair.Key,
pair => pair.Value,
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)]);
}
}
}
47 changes: 47 additions & 0 deletions Libplanet.Tools/Mpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Bencodex;
using Cocona;
using Cocona.Help;
using Libplanet.RocksDBStore;
Expand Down Expand Up @@ -89,6 +91,51 @@ public class Mpt
}
}

[Command(Description = "Export all states of the state root hash as JSON.")]
public void Export(
[Argument(
Name = "KEY-VALUE-STORE",
Description = "The path where IKeyValueStore implementation was used at.")]
string kvStoreUri,
[Argument(
Name = "STATE-ROOT-HASH",
Description = "The state root hash to compare.")]
string stateRootHashHex,
[FromService] IConfigurationService<ToolConfiguration> configurationService)
{
// If it is not Uri format,
// try to get uri from configuration service by using it as alias.
if (!Uri.IsWellFormedUriString(kvStoreUri, UriKind.Absolute))
{
try
{
var configuration = configurationService.Load();
kvStoreUri = configuration.Mpt.Aliases[kvStoreUri];
}
catch (KeyNotFoundException)
{
var exceptionMessage =
$"The alias, '{kvStoreUri}' doesn't exist. " +
$"Please pass correct uri or alias.";
throw new CommandExitedException(
exceptionMessage,
-1);
}
}

IKeyValueStore keyValueStore = LoadKVStoreFromURI(kvStoreUri);
var trie = new MerkleTrie(
keyValueStore,
HashDigest<SHA256>.FromString(stateRootHashHex));
var codec = new Codec();
ImmutableDictionary<string, byte[]> decoratedStates = trie.ListAllStates()
.ToImmutableDictionary(
pair => Encoding.UTF8.GetString(pair.Key.ToArray()),
pair => codec.Encode(pair.Value));

Console.WriteLine(JsonSerializer.Serialize(decoratedStates));
}

// FIXME: Now, it works like `set` not `add`. It allows override.
[Command(Description="Add a new mpt store alias.")]
public void Add(
Expand Down
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 2f6e94d

Please sign in to comment.