From d65864397d6940870ec5c55b7f34fd24c454ec86 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 11 Oct 2019 11:39:09 +0900 Subject: [PATCH] Access only blocks to related to render --- CHANGES.md | 5 ++ Libplanet/Blockchain/BlockChain.cs | 86 +++++++++++++++++++----------- 2 files changed, 61 insertions(+), 30 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index dc0a7446c10..ec5bc888642 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,6 +20,8 @@ To be released. ### Added interfaces + - Added `BlockChain.LongCount()` method. [[#575]] + ### Behavioral changes - Improved performance of `StoreExtension.LookupStateReference()` method. @@ -32,6 +34,8 @@ To be released. already received when blockchain is empty. [[#550], [#562]] - Fixed a bug that `Swarm` had thrown `SocketException` with a message `Operation on non-blocking socket would block`. [[#405], [#485]] + - Fixed a bug that accessed all blocks from the genesis block when a swap + occurred. [[#575]] [#405]: https://github.com/planetarium/libplanet/issues/405 [#447]: https://github.com/planetarium/libplanet/issues/447 @@ -47,6 +51,7 @@ To be released. [#563]: https://github.com/planetarium/libplanet/pull/563 [#209]: https://github.com/planetarium/libplanet/issues/209 [#561]: https://github.com/planetarium/libplanet/pull/561 +[#575]: https://github.com/planetarium/libplanet/pull/575 Version 0.6.0 diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index e9c51ad80c0..17e1aac647f 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -114,30 +114,7 @@ public Block Tip /// All es in the current index. The genesis block's hash goes /// first, and the tip goes last. /// - public IEnumerable> BlockHashes - { - get - { - try - { - _rwlock.EnterUpgradeableReadLock(); - - IEnumerable> indices = Store.IterateIndexes(Id); - - // NOTE: The reason why this does not simply return indices, but iterates over - // indices and yields hashes step by step instead, is that we need to ensure - // the read lock held until the whole iteration completes. - foreach (HashDigest hash in indices) - { - yield return hash; - } - } - finally - { - _rwlock.ExitUpgradeableReadLock(); - } - } - } + public IEnumerable> BlockHashes => IterateBlockHashes(); /// int IReadOnlyCollection>.Count => @@ -171,6 +148,14 @@ public IEnumerable> BlockHashes } } + /// + /// Returns a integer that represents the number of elements in the + /// . + /// + /// A number that represents how many elements in the . + /// + public long LongCount() => Store.CountIndex(Id); + public void Validate( IReadOnlyList> blocks, DateTimeOffset currentTime @@ -956,7 +941,7 @@ internal void Swap(BlockChain other, bool render) if (render && !(Tip is null || other.Tip is null)) { long shorterHeight = - Math.Min(this.LongCount(), other.LongCount()) - 1; + Math.Min(LongCount(), other.LongCount()) - 1; for ( Block t = this[shorterHeight], o = other[shorterHeight]; t.PreviousHash is HashDigest tp && @@ -1030,11 +1015,12 @@ internal void Swap(BlockChain other, bool render) if (render) { // Render actions that had been behind. - IEnumerable> blocksToRender = - topmostCommon is Block branchPoint - ? this.SkipWhile(b => b.Index <= branchPoint.Index) - : this; - foreach (Block b in blocksToRender) + long startToRenderIndex = topmostCommon is Block branchPoint + ? branchPoint.Index + 1 + : 0; + + // FIXME: We should consider the case where block count is larger than int.MaxSize. + foreach (Block b in IterateBlocks(offset: (int)startToRenderIndex)) { List evaluations = b.EvaluateActionsPerTx(a => GetState(a, b.PreviousHash).GetValueOrDefault(a)) @@ -1106,6 +1092,46 @@ bool buildStateReferences } } + private IEnumerable> IterateBlocks(int offset = 0, int? limit = null) + { + _rwlock.EnterUpgradeableReadLock(); + + try + { + foreach (HashDigest hash in IterateBlockHashes(offset, limit)) + { + yield return Blocks[hash]; + } + } + finally + { + _rwlock.ExitUpgradeableReadLock(); + } + } + + private IEnumerable> + IterateBlockHashes(int offset = 0, int? limit = null) + { + _rwlock.EnterUpgradeableReadLock(); + + try + { + IEnumerable> indices = Store.IterateIndexes(Id, offset, limit); + + // NOTE: The reason why this does not simply return indices, but iterates over + // indices and yields hashes step by step instead, is that we need to ensure + // the read lock held until the whole iteration completes. + foreach (HashDigest hash in indices) + { + yield return hash; + } + } + finally + { + _rwlock.ExitUpgradeableReadLock(); + } + } + /// /// Provides data for the event. ///