diff --git a/src/Libplanet.Action/AssemblyInfo.cs b/src/Libplanet.Action/AssemblyInfo.cs
index 3b64ad1989d..d32db2c362f 100644
--- a/src/Libplanet.Action/AssemblyInfo.cs
+++ b/src/Libplanet.Action/AssemblyInfo.cs
@@ -1,6 +1,7 @@
using System.Runtime.CompilerServices;
-[assembly: InternalsVisibleTo("Libplanet.Tests")]
+[assembly: InternalsVisibleTo("Libplanet")]
[assembly: InternalsVisibleTo("Libplanet.Action.Tests")]
[assembly: InternalsVisibleTo("Libplanet.Explorer.Tests")]
[assembly: InternalsVisibleTo("Libplanet.Mocks")]
+[assembly: InternalsVisibleTo("Libplanet.Tests")]
diff --git a/src/Libplanet/Blockchain/StateStoreExtensions.cs b/src/Libplanet/Blockchain/StateStoreExtensions.cs
new file mode 100644
index 00000000000..333b3d1fdaf
--- /dev/null
+++ b/src/Libplanet/Blockchain/StateStoreExtensions.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Security.Cryptography;
+using Bencodex.Types;
+using Libplanet.Action.State;
+using Libplanet.Common;
+using Libplanet.Crypto;
+using Libplanet.Store.Trie;
+using Libplanet.Types.Blocks;
+
+namespace Libplanet.Store
+{
+ ///
+ /// Convenient extension methods for .
+ ///
+ public static class IStateStoreExtensions
+ {
+ ///
+ /// Commits representing a world state directly
+ /// to and returns its state root hash.
+ /// The world state created is set to .
+ ///
+ /// The to commit to.
+ /// The data representing a world state to commit.
+ ///
+ /// Thrown if given
+ /// is not in the right format.
+ ///
+ /// -
+ /// Every key in must be a of length
+ /// .
+ ///
+ /// -
+ /// Every value in must be a with
+ /// each key in the being a of length
+ /// .
+ ///
+ ///
+ ///
+ public static HashDigest CommitWorld(this IStateStore stateStore, Dictionary data)
+ {
+ var stateRoot = stateStore.GetStateRoot(null);
+ stateRoot = stateRoot.SetMetadata(
+ new TrieMetadata(BlockMetadata.CurrentProtocolVersion));
+ foreach((var key, var value) in data)
+ {
+ if (key is not Binary binary)
+ {
+ throw new ArgumentException(
+ $"Given {data} contains a key that is of invalid type: {key.GetType()}",
+ nameof(data));
+ }
+
+ if (binary.ByteArray.Length != Address.Size)
+ {
+ throw new ArgumentException(
+ $"Given {data} contains a key that is of invalid length that is " +
+ $"not {Address.Size}: {binary.ByteArray.Length}",
+ nameof(data));
+ }
+
+ if (value is not Dictionary dict)
+ {
+ throw new ArgumentException(
+ $"Given {data} contains a value that is of invalid type: {value.GetType()}",
+ nameof(data));
+ }
+
+ stateRoot = stateRoot.Set(
+ KeyConverters.ToStateKey(new Address(binary.ByteArray)),
+ new Binary(stateStore.CommitAccount(dict).ByteArray));
+ }
+
+ return stateStore.Commit(stateRoot).Hash;
+ }
+
+ private static HashDigest CommitAccount(this IStateStore stateStore, Dictionary data)
+ {
+ var stateRoot = stateStore.GetStateRoot(null);
+ foreach((var key, var value) in data)
+ {
+ if (key is not Binary binary)
+ {
+ throw new ArgumentException(
+ $"Given {data} contains a key that is of invalid type: {key.GetType()}",
+ nameof(data));
+ }
+
+ if (binary.ByteArray.Length != Address.Size)
+ {
+ throw new ArgumentException(
+ $"Given {data} contains a key that is of invalid length that is " +
+ $"not {Address.Size}: {binary.ByteArray.Length}",
+ nameof(data));
+ }
+
+ stateRoot = stateRoot.Set(
+ KeyConverters.ToStateKey(new Address(binary.ByteArray)),
+ value);
+ }
+
+ return stateStore.Commit(stateRoot).Hash;
+ }
+ }
+}