Skip to content

Commit

Permalink
Merge pull request #3610 from greymistcube/fix/state-store-commit
Browse files Browse the repository at this point in the history
🐛 Fixed `IStateStore.Commit()`
  • Loading branch information
greymistcube authored Jan 18, 2024
2 parents b4bde80 + 82760cb commit ccef9c5
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Version 3.9.5

To be released.

- (Libplanet.Store) Changed `IStateStore.Commit()` to return an `ITrie`
with either its `Root` as `null` or a `HashNode`. [[#3610]]


Version 3.9.4
-------------
Expand Down
5 changes: 4 additions & 1 deletion Libplanet.Store/IStateStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Security.Cryptography;
using Libplanet.Common;
using Libplanet.Store.Trie;
using Libplanet.Store.Trie.Nodes;

namespace Libplanet.Store
{
Expand Down Expand Up @@ -34,7 +35,9 @@ public interface IStateStore : IDisposable
/// <see cref="ITrie.Hash"/>.
/// </summary>
/// <param name="trie">The <see cref="ITrie"/> to commit.</param>
/// <returns>The committed <see cref="ITrie"/>.</returns>
/// <returns>The committed <see cref="ITrie"/>. The committed <see cref="ITrie"/>'s
/// <see cref="ITrie.Root"/> is guaranteed to be either <see langword="null"/>
/// or a <see cref="HashNode"/>.</returns>
/// <remarks>
/// Given <paramref name="trie"/> must have originated from the same instance
/// (or with an instance with the same reference to an <see cref="IKeyValueStore"/>).
Expand Down
4 changes: 2 additions & 2 deletions Libplanet.Store/Trie/MerkleTrie.Diff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public partial class MerkleTrie : ITrie
}

case ShortNode shortNode:
queue.Enqueue((shortNode.Value!, path.AddRange(shortNode.Key)));
queue.Enqueue((shortNode.Value, path.AddRange(shortNode.Key)));
continue;

case FullNode fullNode:
Expand Down Expand Up @@ -104,7 +104,7 @@ int i in Enumerable.Range(0, FullNode.ChildrenCount - 1))
continue;

case ShortNode shortNode:
queue.Enqueue((shortNode.Value!, path.AddRange(shortNode.Key)));
queue.Enqueue((shortNode.Value, path.AddRange(shortNode.Key)));
continue;

case FullNode fullNode:
Expand Down
2 changes: 1 addition & 1 deletion Libplanet.Store/Trie/MerkleTrie.Insert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private INode InsertToShortNode(ShortNode shortNode, in PathCursor cursor, Value
? fullNode.SetChild(
newChildIndex,
new ShortNode(newShortNodeKey, shortNode.Value))
: fullNode.SetChild(newChildIndex, shortNode.Value!);
: fullNode.SetChild(newChildIndex, shortNode.Value);

// Handles value node.
// Assumes next cursor nibble (including non-remaining case)
Expand Down
5 changes: 3 additions & 2 deletions Libplanet.Store/TrieStateStore.Commit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ public ITrie Commit(ITrie trie)
{
IValue bencoded = newRoot.ToBencodex();
byte[] serialized = _codec.Encode(bencoded);
byte[] hash = SHA256.Create().ComputeHash(serialized);
HashDigest<SHA256> hashDigest = HashDigest<SHA256>.DeriveFrom(serialized);

writeBatch.Add(new KeyBytes(hash), serialized);
writeBatch.Add(new KeyBytes(hashDigest.ByteArray), serialized);
newRoot = new HashNode(hashDigest);
}

writeBatch.Flush();
Expand Down
17 changes: 17 additions & 0 deletions Libplanet.Tests/Store/TrieStateStoreCommitTest.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using Bencodex.Types;
using Libplanet.Common;
using Libplanet.Store;
using Libplanet.Store.Trie;
using Libplanet.Store.Trie.Nodes;
using Xunit;

namespace Libplanet.Tests.Store
Expand All @@ -20,6 +22,7 @@ public void CommitEmptyDoesNotWrite()

Assert.Null(emptyTrie.Root);
Assert.True(stateStore.GetStateRoot(emptyRootHash).Recorded);
Assert.Null(stateStore.GetStateRoot(emptyRootHash).Root);
Assert.False(keyValueStore.Exists(new KeyBytes(emptyRootHash.ByteArray)));

emptyTrie = stateStore.Commit(emptyTrie);
Expand Down Expand Up @@ -57,5 +60,19 @@ public void Commit()
Assert.Equal(new Text("2c73"), trie.Get(new KeyBytes(new byte[] { 0x2c, 0x73 })));
Assert.Equal(new Text("234f"), trie.Get(new KeyBytes(new byte[] { 0x23, 0x4f })));
}

[Fact]
public void CommittedNonEmptyTrieRootIsHashNode()
{
IKeyValueStore keyValueStore = new MemoryKeyValueStore();
IStateStore stateStore = new TrieStateStore(keyValueStore);
ITrie trie = stateStore.GetStateRoot(null);
trie = trie.Set(new KeyBytes(Array.Empty<byte>()), new Integer(1));
trie = stateStore.Commit(trie);
HashNode root = Assert.IsType<HashNode>(trie.Root);
trie = stateStore.GetStateRoot(trie.Hash);
Assert.IsType<HashNode>(trie.Root);
Assert.Equal(root, trie.Root);
}
}
}

0 comments on commit ccef9c5

Please sign in to comment.