@@ -16,6 +16,10 @@
Loading
16 16
                = new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size));
17 17
            var merkleTrie = new MerkleTrie(new MemoryKeyValueStore(), hashDigest);
18 18
            Assert.Equal(hashDigest, merkleTrie.Hash);
19 +
20 +
            // See https://github.com/planetarium/libplanet/pull/1091
21 +
            merkleTrie = new MerkleTrie(new MemoryKeyValueStore(), MerkleTrie.EmptyRootHash);
22 +
            Assert.Null(merkleTrie.Root);
19 23
        }
20 24
21 25
        [Fact]

@@ -63,13 +63,15 @@
Loading
63 63
        internal MerkleTrie(IKeyValueStore keyValueStore, INode? root = null, bool secure = false)
64 64
        {
65 65
            KeyValueStore = keyValueStore;
66 -
            Root = root;
66 +
            Root = root is HashNode hashNode && hashNode.HashDigest.Equals(EmptyRootHash)
67 +
                ? null
68 +
                : root;
67 69
            _secure = secure;
68 70
        }
69 71
70 72
        public HashDigest<SHA256> Hash => Root?.Hash() ?? EmptyRootHash;
71 73
72 -
        private INode? Root { get; }
74 +
        internal INode? Root { get; }
73 75
74 76
        private IKeyValueStore KeyValueStore { get; }
75 77

@@ -172,21 +172,24 @@
Loading
172 172
                GetBalance,
173 173
                trieGetter);
174 174
175 -
            if (inFork && !(StateStore is IBlockStatesStore))
175 +
            if (Count == 0)
176 176
            {
177 -
                // If the store is BlockStateStore, have to fork state reference too so
178 -
                // should use Append().
179 -
                Store.AppendIndex(Id, genesisBlock.Hash);
180 -
            }
181 -
            else if (Count == 0)
182 -
            {
183 -
                Append(
184 -
                    genesisBlock,
185 -
                    currentTime: genesisBlock.Timestamp,
186 -
                    renderBlocks: !inFork,
187 -
                    renderActions: !inFork,
188 -
                    evaluateActions: !inFork
189 -
                );
177 +
                if (StateStore is TrieStateStore tss && tss.ContainsBlockStates(genesisBlock.Hash))
178 +
                {
179 +
                    // If the store is BlockStateStore, have to fork state reference too so
180 +
                    // should use Append().
181 +
                    Store.AppendIndex(Id, genesisBlock.Hash);
182 +
                }
183 +
                else
184 +
                {
185 +
                    Append(
186 +
                        genesisBlock,
187 +
                        currentTime: genesisBlock.Timestamp,
188 +
                        renderBlocks: !inFork,
189 +
                        renderActions: !inFork,
190 +
                        evaluateActions: !inFork
191 +
                    );
192 +
                }
190 193
            }
191 194
            else if (!Genesis.Equals(genesisBlock))
192 195
            {
@@ -903,7 +906,16 @@
Loading
903 906
904 907
            if (StateStore is TrieStateStore trieStateStore)
905 908
            {
906 -
                SetStates(block, actionEvaluations, false);
909 +
                _rwlock.EnterWriteLock();
910 +
                try
911 +
                {
912 +
                    SetStates(block, actionEvaluations, false);
913 +
                }
914 +
                finally
915 +
                {
916 +
                    _rwlock.ExitWriteLock();
917 +
                }
918 +
907 919
                block = new Block<T>(block, trieStateStore.GetRootHash(block.Hash));
908 920
            }
909 921
@@ -1260,15 +1272,27 @@
Loading
1260 1272
                block
1261 1273
            );
1262 1274
            IReadOnlyList<ActionEvaluation> evaluations = null;
1275 +
            DateTimeOffset evaluateActionStarted = DateTimeOffset.Now;
1263 1276
            evaluations = BlockEvaluator.EvaluateActions(
1264 1277
                block,
1265 1278
                stateCompleters ?? StateCompleterSet<T>.Recalculate
1266 1279
            );
1280 +
            _logger.Verbose(
1281 +
                $"[#{{0}} {{1}}] {nameof(BlockEvaluator.EvaluateActions)} spent {{2}} ms.",
1282 +
                block.Index,
1283 +
                block.Hash,
1284 +
                (DateTimeOffset.Now - evaluateActionStarted).TotalMilliseconds);
1267 1285
1268 1286
            _rwlock.EnterWriteLock();
1269 1287
            try
1270 1288
            {
1289 +
                DateTimeOffset setStatesStarted = DateTimeOffset.Now;
1271 1290
                SetStates(block, evaluations, buildStateReferences: true);
1291 +
                _logger.Verbose(
1292 +
                    $"[#{{0}} {{1}}] {nameof(SetStates)} spent {{2}} ms.",
1293 +
                    block.Index,
1294 +
                    block.Hash,
1295 +
                    (DateTimeOffset.Now - setStatesStarted).TotalMilliseconds);
1272 1296
            }
1273 1297
            finally
1274 1298
            {

@@ -1596,6 +1596,8 @@
Loading
1596 1596
            }
1597 1597
1598 1598
            int count = 0, totalCount = (int)(workspace.Count - initHeight);
1599 +
            long actionsCount = 0, txsCount = 0;
1600 +
            DateTimeOffset executionStarted = DateTimeOffset.Now;
1599 1601
            _logger.Debug("Starts to execute actions of {0} blocks.", totalCount);
1600 1602
            var blockHashes = workspace.IterateBlockHashes((int)initHeight);
1601 1603
            foreach (HashDigest<SHA256> hash in blockHashes)
@@ -1609,6 +1611,12 @@
Loading
1609 1611
                }
1610 1612
1611 1613
                workspace.ExecuteActions(block);
1614 +
                IEnumerable<Transaction<T>>
1615 +
                    transactions = block.Transactions.ToImmutableArray();
1616 +
                txsCount += transactions.Count();
1617 +
                actionsCount +=
1618 +
                    transactions.Sum(tx => tx.Actions.Count);
1619 +
1612 1620
                _logger.Debug("Executed actions in the block {0}.", block.Hash);
1613 1621
                progress?.Report(new ActionExecutionState()
1614 1622
                {
@@ -1619,6 +1627,14 @@
Loading
1619 1627
            }
1620 1628
1621 1629
            _logger.Debug("Finished to execute actions.");
1630 +
1631 +
            TimeSpan spent = DateTimeOffset.Now - executionStarted;
1632 +
            _logger.Verbose(
1633 +
                "Executed totally {0} blocks, {1} txs, {2} actions during {3}",
1634 +
                totalCount,
1635 +
                actionsCount,
1636 +
                txsCount,
1637 +
                spent);
1622 1638
        }
1623 1639
1624 1640
        private async Task BroadcastTxAsync(

@@ -87,6 +87,21 @@
Loading
87 87
            );
88 88
        }
89 89
90 +
        [Fact]
91 +
        public void PolymorphicActionToString()
92 +
        {
93 +
            Assert.Equal(
94 +
                "Libplanet.Action.PolymorphicAction`1[Libplanet.Tests.Common.Action.Sleep]",
95 +
                new PolymorphicAction<BaseAction>(new Sleep()).ToString());
96 +
            Assert.Equal(
97 +
                "Libplanet.Action.PolymorphicAction`1[Libplanet.Tests.Common.Action.Attack]",
98 +
                new PolymorphicAction<BaseAction>(new Attack()).ToString());
99 +
            Assert.Equal(
100 +
                "Libplanet.Action.PolymorphicAction`1" +
101 +
                "[Libplanet.Tests.Common.Action.DetectRehearsal]",
102 +
                new PolymorphicAction<BaseAction>(new DetectRehearsal()).ToString());
103 +
        }
104 +
90 105
        private class ActionNotAttributeAnnotated : IAction
91 106
        {
92 107
            public ActionNotAttributeAnnotated()

@@ -249,5 +249,10 @@
Loading
249 249
        /// <inheritdoc/>
250 250
        public IAccountStateDelta Execute(IActionContext context) =>
251 251
            InnerAction.Execute(context);
252 +
253 +
        public override string ToString()
254 +
        {
255 +
            return $"{GetType().Namespace}.{GetType().Name}[{_innerAction}]";
256 +
        }
252 257
    }
253 258
}

@@ -7,6 +7,7 @@
Loading
7 7
using Libplanet.Blocks;
8 8
using Libplanet.Store.Trie;
9 9
using Libplanet.Tx;
10 +
using Serilog;
10 11
11 12
namespace Libplanet.Action
12 13
{
@@ -136,7 +137,11 @@
Loading
136 137
                IAccountStateDelta nextStates = context.PreviousStates;
137 138
                try
138 139
                {
140 +
                    DateTimeOffset actionExecutionStarted = DateTimeOffset.Now;
139 141
                    nextStates = action.Execute(context);
142 +
                    TimeSpan spent = DateTimeOffset.Now - actionExecutionStarted;
143 +
144 +
                    Log.Verbose($"{action} execution spent {spent.TotalMilliseconds} ms.");
140 145
                }
141 146
                catch (Exception e)
142 147
                {

@@ -279,6 +279,7 @@
Loading
279 279
                    try
280 280
                    {
281 281
                        message = await StunMessage.Parse(stream);
282 +
                        Log.Debug("Stun Message is: {message}", message);
282 283
                    }
283 284
                    catch (TurnClientException e)
284 285
                    {
@@ -319,6 +320,8 @@
Loading
319 320
                    );
320 321
                }
321 322
            }
323 +
324 +
            Log.Debug($"{nameof(ProcessMessage)} is ended. Connected: {_control.Connected}");
322 325
        }
323 326
324 327
        private void EnsureConnection()
Files Coverage
Libplanet 86.44%
Libplanet.Analyzers.Tests 84.07%
Libplanet.RocksDBStore 95.77%
Libplanet.RocksDBStore.Tests 77.46%
Libplanet.Stun.Tests/Stun 99.56%
Libplanet.Stun/Stun 77.93%
Libplanet.Tests 89.60%
Libplanet.Analyzers/ActionAnalyzer.cs 82.58%
Project Totals (345 files) 88.33%
1
coverage:
2
  range: 70..95
3
  status:
4
    project:
5
      default:
6
        target: auto
7
        threshold: "1"
8
        base: auto
9

10
comment:
11
  require_changes: true
12
  layout: "diff, files"
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading