From b26362372f29f2b51277b2815f3010f41d4b2a7c Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Tue, 18 Jun 2024 16:45:55 +0900 Subject: [PATCH 01/11] Changed to always store next state root hash --- Libplanet/Blockchain/BlockChain.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 49d387bf934..1bbdab67537 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -185,18 +185,19 @@ private BlockChain( if (Tip.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { - return; + Store.PutNextStateRootHash(Tip.Hash, Tip.StateRootHash); } + else + { + HashDigest nextStateRootHash = + DetermineNextBlockStateRootHash(Tip, out var actionEvaluations); - HashDigest nextStateRootHash = - DetermineNextBlockStateRootHash(Tip, out var actionEvaluations); - - Store.DeleteNextStateRootHash(Tip.Hash); - Store.PutNextStateRootHash(Tip.Hash, nextStateRootHash); + Store.DeleteNextStateRootHash(Tip.Hash); + Store.PutNextStateRootHash(Tip.Hash, nextStateRootHash); - IEnumerable txExecutions = - MakeTxExecutions(Tip, actionEvaluations); - UpdateTxExecutions(txExecutions); + IEnumerable txExecutions = MakeTxExecutions(Tip, actionEvaluations); + UpdateTxExecutions(txExecutions); + } } ~BlockChain() @@ -1159,6 +1160,7 @@ internal void AppendStateRootHashPreceded( TimestampFormat, CultureInfo.InvariantCulture)); _blocks[block.Hash] = block; + Store.PutNextStateRootHash(block.Hash, block.StateRootHash); IEnumerable txExecutions = MakeTxExecutions(block, actionEvaluations); UpdateTxExecutions(txExecutions); From fd99513f4d93d7f069d57722baaa8b1e3f049480 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Tue, 18 Jun 2024 19:36:05 +0900 Subject: [PATCH 02/11] Added extension methods for test codes --- Libplanet.Tests/BlockChainExtensions.cs | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Libplanet.Tests/BlockChainExtensions.cs diff --git a/Libplanet.Tests/BlockChainExtensions.cs b/Libplanet.Tests/BlockChainExtensions.cs new file mode 100644 index 00000000000..da010032987 --- /dev/null +++ b/Libplanet.Tests/BlockChainExtensions.cs @@ -0,0 +1,73 @@ +using System.Security.Cryptography; +using Libplanet.Action.State; +using Libplanet.Blockchain; +using Libplanet.Common; +using Libplanet.Types.Blocks; + +namespace Libplanet.Tests +{ + public static class BlockChainExtensions + { + public static Block GetNextBlock(this BlockChain blockChain, BlockHash blockHash) => + blockChain[blockChain[blockHash].Index + 1]; + + /// + /// Returns an resulting from the execution of + /// the tip of . + /// + /// The to search. + /// An resulting from the execution of + /// the tip of . + public static IWorldState GetResultWorldState(this BlockChain blockChain) => + GetResultWorldState(blockChain, blockChain.Tip); + + /// + /// Returns an resulting from the execution of + /// a associated with given + /// from . + /// + /// The to search. + /// The index of a to search. + /// An resulting from the execution of + /// a associated with given . + public static IWorldState GetResultWorldState(this BlockChain blockChain, long index) => + GetResultWorldState(blockChain, blockChain[index]); + + /// + /// Returns an resulting from the execution of + /// a associated with given + /// from . + /// + /// The to search. + /// The to search. + /// An resulting from the execution of + /// a associated with given . + public static IWorldState GetResultWorldState( + this BlockChain blockChain, + BlockHash blockHash) => + GetResultWorldState(blockChain, blockChain[blockHash]); + + private static IWorldState GetResultWorldState(BlockChain blockChain, Block block) + { + if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion) + { + return blockChain.GetWorldState(block.StateRootHash); + } + else + { + // Since block is fetched from blockChain, its index will be at most tip's index. + if (block.Index < blockChain.Tip.Index) + { + return blockChain.GetWorldState(blockChain[block.Index + 1].StateRootHash); + } + else + { + return blockChain.GetNextStateRootHash(block.Hash) is + HashDigest stateRootHash + ? blockChain.GetWorldState(stateRootHash) + : null; + } + } + } + } +} From 8e1306cc9839a5ad2812b1ba888e1035042b1de9 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Tue, 18 Jun 2024 20:01:14 +0900 Subject: [PATCH 03/11] Rerouted calls to extension methods --- Libplanet.Net.Tests/Consensus/ContextTest.cs | 5 ++-- Libplanet.Net.Tests/TestUtils.cs | 3 ++- .../Blockchain/BlockChainTest.Append.cs | 4 +-- Libplanet.Tests/Blockchain/BlockChainTest.cs | 4 +-- Libplanet/Blockchain/BlockChain.States.cs | 27 ++++--------------- 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/Libplanet.Net.Tests/Consensus/ContextTest.cs b/Libplanet.Net.Tests/Consensus/ContextTest.cs index d66f03c7ee9..d701322a276 100644 --- a/Libplanet.Net.Tests/Consensus/ContextTest.cs +++ b/Libplanet.Net.Tests/Consensus/ContextTest.cs @@ -16,6 +16,7 @@ using Libplanet.Net.Messages; using Libplanet.Store; using Libplanet.Store.Trie; +using Libplanet.Tests; using Libplanet.Tests.Store; using Libplanet.Types.Blocks; using Libplanet.Types.Consensus; @@ -321,7 +322,7 @@ void BroadcastMessage(ConsensusMsg message) => 1L, TestUtils.PrivateKeys[0], blockChain - .GetNextWorldState(blockChain[0L].Hash)! + .GetResultWorldState(0) .GetValidatorSet(), contextTimeoutOptions: new ContextTimeoutOption()); @@ -623,7 +624,7 @@ void BroadcastMessage(ConsensusMsg message) => 1L, TestUtils.PrivateKeys[0], blockChain - .GetNextWorldState(blockChain[0L].Hash)! + .GetResultWorldState(0L) .GetValidatorSet(), contextTimeoutOptions: new ContextTimeoutOption()); diff --git a/Libplanet.Net.Tests/TestUtils.cs b/Libplanet.Net.Tests/TestUtils.cs index ffe72a2c1a6..a83c00fea82 100644 --- a/Libplanet.Net.Tests/TestUtils.cs +++ b/Libplanet.Net.Tests/TestUtils.cs @@ -19,6 +19,7 @@ using Libplanet.Net.Transports; using Libplanet.Store; using Libplanet.Store.Trie; +using Libplanet.Tests; using Libplanet.Tests.Store; using Libplanet.Types.Blocks; using Libplanet.Types.Consensus; @@ -288,7 +289,7 @@ void BroadcastMessage(ConsensusMsg message) => height, privateKey, validatorSet ?? blockChain - .GetNextWorldState(blockChain[height - 1].Hash)! + .GetResultWorldState(height - 1) .GetValidatorSet(), contextTimeoutOptions: contextTimeoutOptions ?? new ContextTimeoutOption()); diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index 333ac0b00e6..a731556927d 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -786,10 +786,10 @@ public void DoesNotMigrateStateWithoutAction() ImmutableList.Empty, TestUtils.CreateBlockCommit(blockChain.Tip)); blockChain.Append(emptyBlock, TestUtils.CreateBlockCommit(emptyBlock)); - Assert.True(blockChain.GetNextWorldState(emptyBlock.Hash).Legacy); + Assert.True(blockChain.GetResultWorldState(emptyBlock.Hash).Legacy); Assert.Equal( blockChain.GetWorldState(genesis.StateRootHash).Trie.Hash.ByteArray, - blockChain.GetNextWorldState(emptyBlock.Hash).Trie.Hash.ByteArray); + blockChain.GetResultWorldState(emptyBlock.Hash).Trie.Hash.ByteArray); } [Fact] diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 781103239c3..a7d4e511af0 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -2316,7 +2316,7 @@ private void ValidateNextBlockCommitOnValidatorSetChange() Assert.Equal( blockChain - .GetNextWorldState(blockChain[0].Hash) + .GetResultWorldState(0) .GetValidatorSet(), new ValidatorSet( ValidatorPrivateKeys.Select( @@ -2324,7 +2324,7 @@ private void ValidateNextBlockCommitOnValidatorSetChange() Assert.Equal( blockChain - .GetNextWorldState(blockChain[1].Hash) + .GetResultWorldState(1) .GetValidatorSet(), new ValidatorSet( newValidators.Select( diff --git a/Libplanet/Blockchain/BlockChain.States.cs b/Libplanet/Blockchain/BlockChain.States.cs index efa27efbec7..1879dd712d5 100644 --- a/Libplanet/Blockchain/BlockChain.States.cs +++ b/Libplanet/Blockchain/BlockChain.States.cs @@ -2,7 +2,6 @@ using System.Security.Cryptography; using Libplanet.Action.State; using Libplanet.Common; -using Libplanet.Store; using Libplanet.Types.Blocks; namespace Libplanet.Blockchain @@ -27,33 +26,17 @@ public IWorldState GetWorldState(HashDigest? stateRootHash) /// Gets the next world state in the . /// /// The next world state. If it does not exist, returns null. - public IWorldState? GetNextWorldState() => GetNextWorldState(Tip.Hash); - - /// - /// Returns the next in the BlockChain - /// at . - /// - /// The of the to create - /// for which to create an . - /// - /// The next at . - /// Returns if next state root hash does not exists. - /// - /// Thrown when next state root hash exists, - /// but corresponding state root is not found in the . - /// - /// - public IWorldState? GetNextWorldState(BlockHash offset) + public IWorldState? GetNextWorldState() { - var nextSrh = Store.GetNextStateRootHash(offset); + var nextSrh = Store.GetNextStateRootHash(Tip.Hash); if (nextSrh is { } srh) { var trie = StateStore.GetStateRoot(srh); return trie.Recorded ? new WorldBaseState(StateStore.GetStateRoot(nextSrh), StateStore) - : throw new ArgumentException( - $"Could not find state root {srh} in {nameof(StateStore)}.", - nameof(offset)); + : throw new InvalidOperationException( + $"Could not find state root {srh} in {nameof(StateStore)} for " + + $"the current tip."); } else { From fe1726b22245ce2bb3431141e783ceb633a54430 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Wed, 19 Jun 2024 11:17:33 +0900 Subject: [PATCH 04/11] Changed validation and proposal to throw an exception instead of blocking --- Libplanet/Blockchain/BlockChain.ProposeBlock.cs | 5 ++++- Libplanet/Blockchain/BlockChain.Validate.cs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Libplanet/Blockchain/BlockChain.ProposeBlock.cs b/Libplanet/Blockchain/BlockChain.ProposeBlock.cs index e831b2f55bb..1b665fdfad3 100644 --- a/Libplanet/Blockchain/BlockChain.ProposeBlock.cs +++ b/Libplanet/Blockchain/BlockChain.ProposeBlock.cs @@ -149,7 +149,10 @@ internal Block ProposeBlock( _blocks[prevHash].ProtocolVersion < BlockMetadata.SlothProtocolVersion ? _blocks[prevHash].StateRootHash - : (HashDigest)GetNextStateRootHash(prevHash, TimeSpan.Zero); + : GetNextStateRootHash(prevHash) ?? + throw new InvalidOperationException( + $"Cannot propose a block as the next state root hash " + + $"for block {prevHash} is missing."); // FIXME: Should use automated public constructor. // Manual internal constructor is used purely for testing custom timestamps. diff --git a/Libplanet/Blockchain/BlockChain.Validate.cs b/Libplanet/Blockchain/BlockChain.Validate.cs index 803c5bdd468..f39a10318b8 100644 --- a/Libplanet/Blockchain/BlockChain.Validate.cs +++ b/Libplanet/Blockchain/BlockChain.Validate.cs @@ -343,7 +343,10 @@ internal void ValidateBlockStateRootHash(Block block, TimeSpan validationInterva _blocks[previousHash].ProtocolVersion < BlockMetadata.SlothProtocolVersion ? _blocks[previousHash].StateRootHash - : (HashDigest)GetNextStateRootHash(previousHash, validationInterval); + : GetNextStateRootHash(previousHash) ?? + throw new InvalidOperationException( + $"Cannot validate a block' state root hash as the next " + + $"state root hash for block {previousHash} is missing."); if (!stateRootHash.Equals(block.StateRootHash)) { From 91478ceccfbfa6c507d962aae938ccbd3ce085c5 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Wed, 19 Jun 2024 13:48:12 +0900 Subject: [PATCH 05/11] Refactor GetNextStateRootHash --- Libplanet.Net/Consensus/ConsensusContext.cs | 19 +++++++--- Libplanet.Net/Consensus/Context.cs | 2 +- .../Blockchain/BlockChain.ProposeBlock.cs | 12 +++---- Libplanet/Blockchain/BlockChain.States.cs | 2 +- Libplanet/Blockchain/BlockChain.Validate.cs | 22 ++++++------ Libplanet/Blockchain/BlockChain.cs | 35 ++++++++++--------- 6 files changed, 48 insertions(+), 44 deletions(-) diff --git a/Libplanet.Net/Consensus/ConsensusContext.cs b/Libplanet.Net/Consensus/ConsensusContext.cs index cb70301f067..f695fd365ba 100644 --- a/Libplanet.Net/Consensus/ConsensusContext.cs +++ b/Libplanet.Net/Consensus/ConsensusContext.cs @@ -461,11 +461,20 @@ private Context CreateContext(long height) } else { - validatorSet = _blockChain - .GetWorldState( - _blockChain.GetNextStateRootHash( - _blockChain[Height - 1].Hash, TimeSpan.Zero)) - .GetValidatorSet(); + while (true) + { + var nextStateRootHash = _blockChain.GetNextStateRootHash(Height - 1); + if (nextStateRootHash is { } nsrh) + { + validatorSet = _blockChain + .GetWorldState(nsrh) + .GetValidatorSet(); + break; + } + + // FIXME: Maybe this should be adjustable? + Thread.Sleep(100); + } } Context context = new Context( diff --git a/Libplanet.Net/Consensus/Context.cs b/Libplanet.Net/Consensus/Context.cs index f1698b2a6dc..cb6b1b47cb0 100644 --- a/Libplanet.Net/Consensus/Context.cs +++ b/Libplanet.Net/Consensus/Context.cs @@ -491,7 +491,7 @@ private bool IsValid(Block block) } } - _blockChain.ValidateBlockStateRootHash(block, TimeSpan.Zero); + _blockChain.ValidateBlockStateRootHash(block); } catch (Exception e) when ( e is InvalidBlockException || diff --git a/Libplanet/Blockchain/BlockChain.ProposeBlock.cs b/Libplanet/Blockchain/BlockChain.ProposeBlock.cs index 1b665fdfad3..09ef70d94be 100644 --- a/Libplanet/Blockchain/BlockChain.ProposeBlock.cs +++ b/Libplanet/Blockchain/BlockChain.ProposeBlock.cs @@ -145,14 +145,10 @@ internal Block ProposeBlock( BlockHash prevHash = Store.IndexBlockHash(Id, index - 1) ?? throw new NullReferenceException($"Chain {Id} is missing block #{index - 1}"); - HashDigest stateRootHash = - _blocks[prevHash].ProtocolVersion < - BlockMetadata.SlothProtocolVersion - ? _blocks[prevHash].StateRootHash - : GetNextStateRootHash(prevHash) ?? - throw new InvalidOperationException( - $"Cannot propose a block as the next state root hash " + - $"for block {prevHash} is missing."); + HashDigest stateRootHash = GetNextStateRootHash(prevHash) ?? + throw new InvalidOperationException( + $"Cannot propose a block as the next state root hash " + + $"for block {prevHash} is missing."); // FIXME: Should use automated public constructor. // Manual internal constructor is used purely for testing custom timestamps. diff --git a/Libplanet/Blockchain/BlockChain.States.cs b/Libplanet/Blockchain/BlockChain.States.cs index 1879dd712d5..c0725cca2f4 100644 --- a/Libplanet/Blockchain/BlockChain.States.cs +++ b/Libplanet/Blockchain/BlockChain.States.cs @@ -28,7 +28,7 @@ public IWorldState GetWorldState(HashDigest? stateRootHash) /// The next world state. If it does not exist, returns null. public IWorldState? GetNextWorldState() { - var nextSrh = Store.GetNextStateRootHash(Tip.Hash); + var nextSrh = GetNextStateRootHash(); if (nextSrh is { } srh) { var trie = StateStore.GetStateRoot(srh); diff --git a/Libplanet/Blockchain/BlockChain.Validate.cs b/Libplanet/Blockchain/BlockChain.Validate.cs index f39a10318b8..a66adfaaffb 100644 --- a/Libplanet/Blockchain/BlockChain.Validate.cs +++ b/Libplanet/Blockchain/BlockChain.Validate.cs @@ -318,19 +318,21 @@ internal void ValidateBlock(Block block) /// /// Validates a result obtained from by - /// comparing the state root hash from + /// comparing the state root hash from /// which stores state root hash from , /// to the one in . /// /// The to validate against. - /// The interval for fetching calculated state root hash - /// from . + /// If this method is called + /// when the result of + /// is . This can happen if + /// is an index higher than the tip but its result is not ready yet. /// If the state root hash /// calculated by committing to the does not match /// the 's . /// /// - internal void ValidateBlockStateRootHash(Block block, TimeSpan validationInterval = default) + internal void ValidateBlockStateRootHash(Block block) { // NOTE: Since previous hash validation is on block validation, // assume block is genesis if previous hash is null. @@ -339,14 +341,10 @@ internal void ValidateBlockStateRootHash(Block block, TimeSpan validationInterva return; } - HashDigest stateRootHash = - _blocks[previousHash].ProtocolVersion < - BlockMetadata.SlothProtocolVersion - ? _blocks[previousHash].StateRootHash - : GetNextStateRootHash(previousHash) ?? - throw new InvalidOperationException( - $"Cannot validate a block' state root hash as the next " + - $"state root hash for block {previousHash} is missing."); + HashDigest stateRootHash = GetNextStateRootHash(previousHash) ?? + throw new InvalidOperationException( + $"Cannot validate a block' state root hash as the next " + + $"state root hash for block {previousHash} is missing."); if (!stateRootHash.Equals(block.StateRootHash)) { diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 1bbdab67537..c99f5fad400 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -1405,26 +1405,27 @@ internal void CleanupBlockCommitStore(long limit) } } - internal HashDigest? GetNextStateRootHash( - BlockHash blockHash, - TimeSpan? fetchInterval = null) + internal HashDigest? GetNextStateRootHash() => + GetNextStateRootHash(Tip); + + internal HashDigest? GetNextStateRootHash(long index) => + GetNextStateRootHash(this[index]); + + internal HashDigest? GetNextStateRootHash(BlockHash blockHash) => + GetNextStateRootHash(this[blockHash]); + + private HashDigest? GetNextStateRootHash(Block block) { - while (true) + if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { - if (Store.GetNextStateRootHash(blockHash) is HashDigest srh) - { - return srh; - } - - if (fetchInterval is TimeSpan interval) - { - Thread.Sleep(interval); - } - else - { - return null; - } + return block.StateRootHash; } + else if (block.Index < Tip.Index) + { + return this[block.Index + 1].StateRootHash; + } + + return Store.GetNextStateRootHash(block.Hash); } } } From 3c0c630310609bc2cfff3d0f33251c22de1c179d Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Wed, 19 Jun 2024 16:35:27 +0900 Subject: [PATCH 06/11] Removed next state root hash from storage --- Libplanet.Net.Tests/Consensus/ContextTest.cs | 2 + Libplanet.Store/IStore.cs | 28 ---------- Libplanet.Store/MemoryStore.cs | 14 ----- .../Action/ActionEvaluatorTest.Migration.cs | 2 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 4 +- .../Blockchain/BlockChainTest.Internals.cs | 5 +- Libplanet.Tests/Blockchain/BlockChainTest.cs | 2 - Libplanet.Tests/Store/ProxyStore.cs | 14 ----- Libplanet.Tests/Store/StoreTest.cs | 31 ----------- Libplanet.Tests/Store/StoreTracker.cs | 20 ------- Libplanet/Blockchain/BlockChain.Next.cs | 12 +++++ Libplanet/Blockchain/BlockChain.States.cs | 5 +- Libplanet/Blockchain/BlockChain.Swap.cs | 1 + Libplanet/Blockchain/BlockChain.cs | 52 +++++++++---------- 14 files changed, 48 insertions(+), 144 deletions(-) create mode 100644 Libplanet/Blockchain/BlockChain.Next.cs diff --git a/Libplanet.Net.Tests/Consensus/ContextTest.cs b/Libplanet.Net.Tests/Consensus/ContextTest.cs index d701322a276..a3a464ef807 100644 --- a/Libplanet.Net.Tests/Consensus/ContextTest.cs +++ b/Libplanet.Net.Tests/Consensus/ContextTest.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Linq; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Bencodex; using Bencodex.Types; @@ -688,6 +689,7 @@ void BroadcastMessage(ConsensusMsg message) => var watch = Stopwatch.StartNew(); await onTipChanged.WaitAsync(); Assert.True(watch.ElapsedMilliseconds < (actionDelay * 0.5)); + Thread.Sleep(100); // Wait for votes to get collected. Assert.Equal( 4, diff --git a/Libplanet.Store/IStore.cs b/Libplanet.Store/IStore.cs index 7edd7d4e318..d273a4bd18e 100644 --- a/Libplanet.Store/IStore.cs +++ b/Libplanet.Store/IStore.cs @@ -348,33 +348,5 @@ public interface IStore : IDisposable /// Returns an of es /// of all s. IEnumerable GetBlockCommitHashes(); - - /// - /// Gets the next state root hash for given from the store. - /// - /// The of the - /// to retrieve next state root hash. - /// Returns if next state root hash of given - /// is stored and available, - /// otherwise returns . - HashDigest? GetNextStateRootHash(BlockHash blockHash); - - /// - /// Puts a next state root hash of corresponding to the - /// to the store. - /// - /// The of the - /// where evaluated. - /// The that represents - /// state root hash of the next state. - void PutNextStateRootHash(BlockHash blockHash, HashDigest nextStateRootHash); - - /// - /// Deletes the next state root hash of corresponding to the given - /// from the store. - /// - /// The of a next state root hash - /// to delete. - void DeleteNextStateRootHash(BlockHash blockHash); } } diff --git a/Libplanet.Store/MemoryStore.cs b/Libplanet.Store/MemoryStore.cs index e394b0e266d..43b3a7b916b 100644 --- a/Libplanet.Store/MemoryStore.cs +++ b/Libplanet.Store/MemoryStore.cs @@ -301,20 +301,6 @@ public void DeleteBlockCommit(BlockHash blockHash) => public IEnumerable GetBlockCommitHashes() => _blockCommits.Keys; - /// - public HashDigest? GetNextStateRootHash(BlockHash blockHash) - => _nextStateRootHashes.TryGetValue(blockHash, out var nextStateRootHash) - ? (HashDigest?)nextStateRootHash - : null; - - /// - public void PutNextStateRootHash(BlockHash blockHash, HashDigest nextStateRootHash) - => _nextStateRootHashes[blockHash] = nextStateRootHash; - - /// - public void DeleteNextStateRootHash(BlockHash blockHash) - => _nextStateRootHashes.TryRemove(blockHash, out _); - [StoreLoader("memory")] private static (IStore Store, IStateStore StateStore) Loader(Uri storeUri) { diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.Migration.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.Migration.cs index 08035590b2c..0cbec15057a 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.Migration.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.Migration.cs @@ -332,7 +332,7 @@ public void MigrateThroughBlockWorldState() var block3 = chain.ProposeBlock(miner, blockCommit); chain.Append(block3, CreateBlockCommit(block3)); Assert.Equal(BlockMetadata.CurrentProtocolVersion, chain.GetNextWorldState().Version); - var accountStateRoot = stateStore.GetStateRoot(store.GetNextStateRootHash(block3.Hash)) + var accountStateRoot = stateStore.GetStateRoot(chain.GetNextStateRootHash(block3.Hash)) .Get(KeyConverters.ToStateKey(ModernAction.AccountAddress)); Assert.NotNull(accountStateRoot); var accountTrie = stateStore.GetStateRoot(new HashDigest(accountStateRoot)); diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 22fc632c1fa..acb72c551d7 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -1009,7 +1009,7 @@ public void EvaluateActionAndCollectFee() Block block = chain.ProposeBlock(miner); var evaluations = chain.ActionEvaluator.Evaluate( - block, chain.Store.GetNextStateRootHash((BlockHash)block.PreviousHash)); + block, chain.GetNextStateRootHash((BlockHash)block.PreviousHash)); Assert.False(evaluations[0].InputContext.BlockAction); Assert.Single(evaluations); @@ -1079,7 +1079,7 @@ public void EvaluateThrowingExceedGasLimit() var evaluations = chain.ActionEvaluator.Evaluate( block, - chain.Store.GetNextStateRootHash((BlockHash)block.PreviousHash)); + chain.GetNextStateRootHash((BlockHash)block.PreviousHash)); Assert.False(evaluations[0].InputContext.BlockAction); Assert.Single(evaluations); diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs index 60d0427fd87..caa940dc057 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs @@ -105,8 +105,7 @@ Transaction MkTx(PrivateKey key, long nonce, DateTimeOffset? ts = null) => [SkippableFact] public void ExecuteActions() { - (var addresses, Transaction[] txs) = - MakeFixturesForAppendTests(); + (var addresses, Transaction[] txs) = MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; Block block1 = _blockChain.ProposeBlock( @@ -126,7 +125,7 @@ public void ExecuteActions() }; IValue legacyStateRootRaw = - _fx.StateStore.GetStateRoot(_fx.Store.GetNextStateRootHash(block1.Hash)) + _fx.StateStore.GetStateRoot(_blockChain.GetNextStateRootHash()) .Get(ToStateKey(ReservedAddresses.LegacyAccount)); Assert.NotNull(legacyStateRootRaw); var legacyStateRoot = diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index a7d4e511af0..4c6561c9b9c 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -1862,8 +1862,6 @@ void BuildIndex(Guid id, Block block) .ToList(); Assert.NotEmpty(dirty); store.PutBlock(b); - store.PutNextStateRootHash( - b.Hash, evals.Last().OutputState.Trie.Hash); BuildIndex(chain.Id, b); Assert.Equal(b, chain[b.Hash]); if (presentIndices.Contains((int)b.Index)) diff --git a/Libplanet.Tests/Store/ProxyStore.cs b/Libplanet.Tests/Store/ProxyStore.cs index cd384d6adb2..dde51f23d54 100644 --- a/Libplanet.Tests/Store/ProxyStore.cs +++ b/Libplanet.Tests/Store/ProxyStore.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Security.Cryptography; -using Libplanet.Common; using Libplanet.Crypto; using Libplanet.Store; using Libplanet.Types.Blocks; @@ -191,17 +189,5 @@ public void DeleteBlockCommit(BlockHash blockHash) => /// public IEnumerable GetBlockCommitHashes() => Store.GetBlockCommitHashes(); - - /// - public HashDigest? GetNextStateRootHash(BlockHash blockHash) => - Store.GetNextStateRootHash(blockHash); - - /// - public void PutNextStateRootHash(BlockHash blockHash, HashDigest nextStateRootHash) - => Store.PutNextStateRootHash(blockHash, nextStateRootHash); - - /// - public void DeleteNextStateRootHash(BlockHash blockHash) => - Store.DeleteNextStateRootHash(blockHash); } } diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index 3adb0d9fd72..1e8f114749e 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -1169,37 +1169,6 @@ public void DeleteLastCommit() } } - [SkippableFact] - public void GetNextStateRootHash() - { - using (StoreFixture fx = FxConstructor()) - { - HashDigest nextStateRootHash - = HashDigest.DeriveFrom(new byte[] { 0, 1, 2 }); - fx.Store.PutNextStateRootHash(fx.Block2.Hash, nextStateRootHash); - HashDigest? storedNextStateRootHash = - fx.Store.GetNextStateRootHash(fx.Block2.Hash); - - Assert.Equal(nextStateRootHash, storedNextStateRootHash); - } - } - - [SkippableFact] - public void DeleteNextStateRootHash() - { - using (StoreFixture fx = FxConstructor()) - { - HashDigest nextStateRootHash - = HashDigest.DeriveFrom(new byte[] { 0, 1, 2 }); - fx.Store.PutNextStateRootHash(fx.Block2.Hash, nextStateRootHash); - - Assert.NotNull(fx.Store.GetNextStateRootHash(fx.Block2.Hash)); - - fx.Store.DeleteNextStateRootHash(fx.Block2.Hash); - Assert.Null(fx.Store.GetNextStateRootHash(fx.Block2.Hash)); - } - } - [SkippableFact] public void ForkTxNonces() { diff --git a/Libplanet.Tests/Store/StoreTracker.cs b/Libplanet.Tests/Store/StoreTracker.cs index f6df855f1c1..c2faff600b1 100644 --- a/Libplanet.Tests/Store/StoreTracker.cs +++ b/Libplanet.Tests/Store/StoreTracker.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Security.Cryptography; -using Libplanet.Common; using Libplanet.Crypto; using Libplanet.Store; using Libplanet.Types.Blocks; @@ -232,24 +230,6 @@ public IEnumerable GetBlockCommitHashes() return _store.GetBlockCommitHashes(); } - public HashDigest? GetNextStateRootHash(BlockHash blockHash) - { - Log(nameof(GetNextStateRootHash)); - return _store.GetNextStateRootHash(blockHash); - } - - public void PutNextStateRootHash(BlockHash blockHash, HashDigest nextStateRootHash) - { - Log(nameof(PutNextStateRootHash)); - _store.PutNextStateRootHash(blockHash, nextStateRootHash); - } - - public void DeleteNextStateRootHash(BlockHash blockHash) - { - Log(nameof(DeleteNextStateRootHash)); - _store.DeleteNextStateRootHash(blockHash); - } - public Guid? GetCanonicalChainId() { Log(nameof(GetCanonicalChainId)); diff --git a/Libplanet/Blockchain/BlockChain.Next.cs b/Libplanet/Blockchain/BlockChain.Next.cs new file mode 100644 index 00000000000..e12c70d6c12 --- /dev/null +++ b/Libplanet/Blockchain/BlockChain.Next.cs @@ -0,0 +1,12 @@ +using System.Security.Cryptography; +using Libplanet.Common; + +namespace Libplanet.Blockchain +{ + public partial class BlockChain + { + private HashDigest? _nextStateRootHash; + + public HashDigest? NextStateRootHash => _nextStateRootHash; + } +} diff --git a/Libplanet/Blockchain/BlockChain.States.cs b/Libplanet/Blockchain/BlockChain.States.cs index c0725cca2f4..56738617d13 100644 --- a/Libplanet/Blockchain/BlockChain.States.cs +++ b/Libplanet/Blockchain/BlockChain.States.cs @@ -28,12 +28,11 @@ public IWorldState GetWorldState(HashDigest? stateRootHash) /// The next world state. If it does not exist, returns null. public IWorldState? GetNextWorldState() { - var nextSrh = GetNextStateRootHash(); - if (nextSrh is { } srh) + if (GetNextStateRootHash() is { } srh) { var trie = StateStore.GetStateRoot(srh); return trie.Recorded - ? new WorldBaseState(StateStore.GetStateRoot(nextSrh), StateStore) + ? new WorldBaseState(trie, StateStore) : throw new InvalidOperationException( $"Could not find state root {srh} in {nameof(StateStore)} for " + $"the current tip."); diff --git a/Libplanet/Blockchain/BlockChain.Swap.cs b/Libplanet/Blockchain/BlockChain.Swap.cs index 0643a519044..c6783b05bc2 100644 --- a/Libplanet/Blockchain/BlockChain.Swap.cs +++ b/Libplanet/Blockchain/BlockChain.Swap.cs @@ -109,6 +109,7 @@ HashSet GetTxIdsWithRange( TipChanged?.Invoke(this, (oldTip, newTip)); Store.DeleteChainId(obsoleteId); + _nextStateRootHash = other.NextStateRootHash; } finally { diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index c99f5fad400..e0d336ccf09 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -185,15 +185,13 @@ private BlockChain( if (Tip.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { - Store.PutNextStateRootHash(Tip.Hash, Tip.StateRootHash); + _nextStateRootHash = Tip.StateRootHash; } else { HashDigest nextStateRootHash = DetermineNextBlockStateRootHash(Tip, out var actionEvaluations); - - Store.DeleteNextStateRootHash(Tip.Hash); - Store.PutNextStateRootHash(Tip.Hash, nextStateRootHash); + _nextStateRootHash = nextStateRootHash; IEnumerable txExecutions = MakeTxExecutions(Tip, actionEvaluations); UpdateTxExecutions(txExecutions); @@ -758,23 +756,13 @@ public BlockChain Fork(BlockHash point, bool inheritRenderers = true) _rwlock.EnterReadLock(); Store.AppendIndex(forkedId, Genesis.Hash); - var forked = new BlockChain( - Policy, - StagePolicy, - Store, - StateStore, - forkedId, - Genesis, - _blockChainStates, - ActionEvaluator, - renderers); Store.ForkBlockIndexes(Id, forkedId, point); if (GetBlockCommit(point) is { } p) { Store.PutChainBlockCommit(forkedId, GetBlockCommit(point)); } - Store.ForkTxNonces(Id, forked.Id); + Store.ForkTxNonces(Id, forkedId); for (Block block = Tip; block.PreviousHash is { } hash && !block.Hash.Equals(point); block = _blocks[hash]) @@ -786,10 +774,21 @@ public BlockChain Fork(BlockHash point, bool inheritRenderers = true) foreach ((Address address, int txCount) in signers) { - Store.IncreaseTxNonce(forked.Id, address, -txCount); + Store.IncreaseTxNonce(forkedId, address, -txCount); } } + var forked = new BlockChain( + Policy, + StagePolicy, + Store, + StateStore, + forkedId, + Genesis, + _blockChainStates, + ActionEvaluator, + renderers); + _logger.Information( "Forked chain at #{Index} {Hash} from id {PreviousId} to id {ForkedId}", pointBlock.Index, @@ -985,6 +984,7 @@ internal void Append( } Store.AppendIndex(Id, block.Hash); + _nextStateRootHash = null; } finally { @@ -1027,8 +1027,7 @@ internal void Append( HashDigest nextStateRootHash = DetermineNextBlockStateRootHash(block, out var actionEvaluations); - - Store.PutNextStateRootHash(block.Hash, nextStateRootHash); + _nextStateRootHash = nextStateRootHash; IEnumerable txExecutions = MakeTxExecutions(block, actionEvaluations); @@ -1160,10 +1159,6 @@ internal void AppendStateRootHashPreceded( TimestampFormat, CultureInfo.InvariantCulture)); _blocks[block.Hash] = block; - Store.PutNextStateRootHash(block.Hash, block.StateRootHash); - IEnumerable txExecutions = - MakeTxExecutions(block, actionEvaluations); - UpdateTxExecutions(txExecutions); foreach (KeyValuePair pair in nonceDeltas) { @@ -1181,6 +1176,10 @@ internal void AppendStateRootHashPreceded( } Store.AppendIndex(Id, block.Hash); + _nextStateRootHash = block.StateRootHash; + IEnumerable txExecutions = + MakeTxExecutions(block, actionEvaluations); + UpdateTxExecutions(txExecutions); } finally { @@ -1405,8 +1404,7 @@ internal void CleanupBlockCommitStore(long limit) } } - internal HashDigest? GetNextStateRootHash() => - GetNextStateRootHash(Tip); + internal HashDigest? GetNextStateRootHash() => NextStateRootHash; internal HashDigest? GetNextStateRootHash(long index) => GetNextStateRootHash(this[index]); @@ -1424,8 +1422,10 @@ internal void CleanupBlockCommitStore(long limit) { return this[block.Index + 1].StateRootHash; } - - return Store.GetNextStateRootHash(block.Hash); + else + { + return GetNextStateRootHash(); + } } } } From 9fb3413e16e2b41fcb978459865f02311f6f4a40 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 20 Jun 2024 16:51:54 +0900 Subject: [PATCH 07/11] Cleanup --- Libplanet/Blockchain/BlockChain.Next.cs | 12 ------------ Libplanet/Blockchain/BlockChain.Swap.cs | 2 +- Libplanet/Blockchain/BlockChain.cs | 4 +++- 3 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 Libplanet/Blockchain/BlockChain.Next.cs diff --git a/Libplanet/Blockchain/BlockChain.Next.cs b/Libplanet/Blockchain/BlockChain.Next.cs deleted file mode 100644 index e12c70d6c12..00000000000 --- a/Libplanet/Blockchain/BlockChain.Next.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Security.Cryptography; -using Libplanet.Common; - -namespace Libplanet.Blockchain -{ - public partial class BlockChain - { - private HashDigest? _nextStateRootHash; - - public HashDigest? NextStateRootHash => _nextStateRootHash; - } -} diff --git a/Libplanet/Blockchain/BlockChain.Swap.cs b/Libplanet/Blockchain/BlockChain.Swap.cs index c6783b05bc2..ca35491bb9f 100644 --- a/Libplanet/Blockchain/BlockChain.Swap.cs +++ b/Libplanet/Blockchain/BlockChain.Swap.cs @@ -109,7 +109,7 @@ HashSet GetTxIdsWithRange( TipChanged?.Invoke(this, (oldTip, newTip)); Store.DeleteChainId(obsoleteId); - _nextStateRootHash = other.NextStateRootHash; + _nextStateRootHash = other._nextStateRootHash; } finally { diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index e0d336ccf09..56b1c782cb9 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -64,6 +64,8 @@ public partial class BlockChain : IBlockChainStates /// private Block _genesis; + private HashDigest? _nextStateRootHash; + /// /// Initializes a new instance of the class by loading /// the canonical chain from given . @@ -1404,7 +1406,7 @@ internal void CleanupBlockCommitStore(long limit) } } - internal HashDigest? GetNextStateRootHash() => NextStateRootHash; + internal HashDigest? GetNextStateRootHash() => _nextStateRootHash; internal HashDigest? GetNextStateRootHash(long index) => GetNextStateRootHash(this[index]); From d1a0544711487948a256deb333db843418f5fb25 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 20 Jun 2024 18:19:09 +0900 Subject: [PATCH 08/11] Cleanup unnecessary code --- Libplanet.Net/Consensus/ConsensusContext.cs | 3 +- Libplanet.Tests/Action/WorldTest.cs | 4 +- Libplanet.Tests/TestUtils.cs | 6 +- Libplanet/Blockchain/BlockChain.Evaluate.cs | 66 +++++++++------------ Libplanet/Blockchain/BlockChain.Validate.cs | 8 +-- Libplanet/Blockchain/BlockChain.cs | 14 ++--- 6 files changed, 42 insertions(+), 59 deletions(-) diff --git a/Libplanet.Net/Consensus/ConsensusContext.cs b/Libplanet.Net/Consensus/ConsensusContext.cs index f695fd365ba..762c0bae8e6 100644 --- a/Libplanet.Net/Consensus/ConsensusContext.cs +++ b/Libplanet.Net/Consensus/ConsensusContext.cs @@ -452,8 +452,7 @@ private Context CreateContext(long height) { // blockchain may not contain block of Height - 1? ValidatorSet validatorSet; - if (_blockChain.Tip.ProtocolVersion - < BlockMetadata.SlothProtocolVersion) + if (_blockChain.Tip.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { validatorSet = _blockChain .GetWorldState(_blockChain[Height - 1].StateRootHash) diff --git a/Libplanet.Tests/Action/WorldTest.cs b/Libplanet.Tests/Action/WorldTest.cs index 1598fcb52d0..27f1210d9e1 100644 --- a/Libplanet.Tests/Action/WorldTest.cs +++ b/Libplanet.Tests/Action/WorldTest.cs @@ -505,9 +505,7 @@ public virtual void TotalSupplyTracking() } protected static IWorldState GetLatestWorldState(BlockChain blockChain) => - blockChain.Tip.ProtocolVersion < BlockMetadata.SlothProtocolVersion - ? blockChain.GetWorldState() - : blockChain.GetNextWorldState(); + blockChain.GetNextWorldState(); protected FungibleAssetValue Value(int currencyIndex, BigInteger quantity) => new FungibleAssetValue(_currencies[currencyIndex], quantity, 0); diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 933f9476d2e..2f8186d85df 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -626,7 +626,7 @@ public static (BlockChain BlockChain, ActionEvaluator ActionEvaluator) timestamp, protocolVersion); var evaluatedSrh = actionEvaluator.Evaluate(preEval, null).Last().OutputState; - genesisBlock = protocolVersion < 2 + genesisBlock = protocolVersion < BlockMetadata.SignatureProtocolVersion ? new Block( preEval, ( @@ -635,8 +635,8 @@ public static (BlockChain BlockChain, ActionEvaluator ActionEvaluator) preEval.Header.DeriveBlockHash(evaluatedSrh, null) )) : protocolVersion < BlockMetadata.SlothProtocolVersion - ? preEval.Sign(GenesisProposer, evaluatedSrh) - : preEval.Sign(GenesisProposer, MerkleTrie.EmptyRootHash); + ? preEval.Sign(GenesisProposer, evaluatedSrh) + : preEval.Sign(GenesisProposer, MerkleTrie.EmptyRootHash); } ValidatingActionRenderer validator = null; diff --git a/Libplanet/Blockchain/BlockChain.Evaluate.cs b/Libplanet/Blockchain/BlockChain.Evaluate.cs index 7dc56aea34a..3abb563cc6c 100644 --- a/Libplanet/Blockchain/BlockChain.Evaluate.cs +++ b/Libplanet/Blockchain/BlockChain.Evaluate.cs @@ -113,48 +113,38 @@ public IReadOnlyList EvaluateBlock(Block block) => internal Block EvaluateAndSign( PreEvaluationBlock preEvaluationBlock, PrivateKey privateKey) { - if (preEvaluationBlock.Index < 1) + if (preEvaluationBlock.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { - throw new ArgumentException( - $"Given {nameof(preEvaluationBlock)} must have block index " + - $"higher than 0"); - } - - if (preEvaluationBlock.ProtocolVersion < BlockMetadata.SignatureProtocolVersion) - { - throw new ArgumentException( - $"Given {nameof(preEvaluationBlock)} must have protocol version " + - $"2 or greater: {preEvaluationBlock.ProtocolVersion}"); - } - - if (preEvaluationBlock.ProtocolVersion < - BlockMetadata.SlothProtocolVersion) - { - return preEvaluationBlock.Sign( - privateKey, - DetermineBlockPrecededStateRootHash(preEvaluationBlock, out _)); - } - - if (!(preEvaluationBlock.PreviousHash is BlockHash previousHash)) - { - throw new ArgumentException( - $"Given {nameof(preEvaluationBlock)} must have non-null previous hash " + - $"If it isn't genesis"); - } - - if (_blocks[previousHash].ProtocolVersion - < BlockMetadata.SlothProtocolVersion) - { - return preEvaluationBlock.Sign(privateKey, _blocks[previousHash].StateRootHash); + if (preEvaluationBlock.ProtocolVersion < BlockMetadata.SignatureProtocolVersion) + { + throw new ArgumentException( + $"Given {nameof(preEvaluationBlock)} must have protocol version " + + $"2 or greater: {preEvaluationBlock.ProtocolVersion}"); + } + else + { + return preEvaluationBlock.Sign( + privateKey, + DetermineBlockPrecededStateRootHash(preEvaluationBlock, out _)); + } } - - if (!(GetNextStateRootHash(previousHash) is HashDigest stateRootHash)) + else { - throw new NullReferenceException( - $"State root hash of block is not prepared"); + if (preEvaluationBlock.Index < 1) + { + throw new ArgumentException( + $"Given {nameof(preEvaluationBlock)} must have block index " + + $"higher than 0"); + } + else + { + var prevBlock = _blocks[(BlockHash)preEvaluationBlock.PreviousHash]; + var stateRootHash = GetNextStateRootHash(prevBlock.Hash) + ?? throw new NullReferenceException( + $"State root hash of block is not prepared"); + return preEvaluationBlock.Sign(privateKey, stateRootHash); + } } - - return preEvaluationBlock.Sign(privateKey, stateRootHash); } /// diff --git a/Libplanet/Blockchain/BlockChain.Validate.cs b/Libplanet/Blockchain/BlockChain.Validate.cs index a66adfaaffb..eb3d1dc6e87 100644 --- a/Libplanet/Blockchain/BlockChain.Validate.cs +++ b/Libplanet/Blockchain/BlockChain.Validate.cs @@ -140,11 +140,9 @@ internal void ValidateBlockCommit( // FIXME: When the dynamic validator set is possible, the functionality of this // condition should be checked once more. - var validators = - block.ProtocolVersion < - BlockMetadata.SlothProtocolVersion - ? GetWorldState(block.PreviousHash ?? Genesis.Hash).GetValidatorSet() - : GetWorldState(block.StateRootHash).GetValidatorSet(); + var validators = block.ProtocolVersion < BlockMetadata.SlothProtocolVersion + ? GetWorldState(block.PreviousHash ?? Genesis.Hash).GetValidatorSet() + : GetWorldState(block.StateRootHash).GetValidatorSet(); if (!validators.ValidateBlockCommitValidators(blockCommit)) { throw new InvalidBlockCommitException( diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 56b1c782cb9..50b69331eba 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -191,10 +191,8 @@ private BlockChain( } else { - HashDigest nextStateRootHash = + _nextStateRootHash = DetermineNextBlockStateRootHash(Tip, out var actionEvaluations); - _nextStateRootHash = nextStateRootHash; - IEnumerable txExecutions = MakeTxExecutions(Tip, actionEvaluations); UpdateTxExecutions(txExecutions); } @@ -391,8 +389,7 @@ public static BlockChain Create( var id = Guid.NewGuid(); - if (genesisBlock.ProtocolVersion < - BlockMetadata.SlothProtocolVersion) + if (genesisBlock.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { var preEval = new PreEvaluationBlock( genesisBlock.Header, genesisBlock.Transactions); @@ -546,10 +543,11 @@ public void Append( if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion) { AppendStateRootHashPreceded(block, blockCommit, render: true); - return; } - - Append(block, blockCommit, render: true); + else + { + Append(block, blockCommit, render: true); + } } /// From 9952b6db2641d7f749261ad53b988bd17b1e98c4 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 20 Jun 2024 19:00:17 +0900 Subject: [PATCH 09/11] Renamed extension methods --- Libplanet.Net.Tests/Consensus/ContextTest.cs | 4 +- Libplanet.Net.Tests/TestUtils.cs | 2 +- Libplanet.Tests/BlockChainExtensions.cs | 44 +++++-------------- .../Blockchain/BlockChainTest.Append.cs | 4 +- Libplanet.Tests/Blockchain/BlockChainTest.cs | 4 +- 5 files changed, 19 insertions(+), 39 deletions(-) diff --git a/Libplanet.Net.Tests/Consensus/ContextTest.cs b/Libplanet.Net.Tests/Consensus/ContextTest.cs index a3a464ef807..caeca6a5f59 100644 --- a/Libplanet.Net.Tests/Consensus/ContextTest.cs +++ b/Libplanet.Net.Tests/Consensus/ContextTest.cs @@ -323,7 +323,7 @@ void BroadcastMessage(ConsensusMsg message) => 1L, TestUtils.PrivateKeys[0], blockChain - .GetResultWorldState(0) + .GetNextWorldState(0) .GetValidatorSet(), contextTimeoutOptions: new ContextTimeoutOption()); @@ -625,7 +625,7 @@ void BroadcastMessage(ConsensusMsg message) => 1L, TestUtils.PrivateKeys[0], blockChain - .GetResultWorldState(0L) + .GetNextWorldState(0L) .GetValidatorSet(), contextTimeoutOptions: new ContextTimeoutOption()); diff --git a/Libplanet.Net.Tests/TestUtils.cs b/Libplanet.Net.Tests/TestUtils.cs index a83c00fea82..1c72f6f1fb9 100644 --- a/Libplanet.Net.Tests/TestUtils.cs +++ b/Libplanet.Net.Tests/TestUtils.cs @@ -289,7 +289,7 @@ void BroadcastMessage(ConsensusMsg message) => height, privateKey, validatorSet ?? blockChain - .GetResultWorldState(height - 1) + .GetNextWorldState(height - 1) .GetValidatorSet(), contextTimeoutOptions: contextTimeoutOptions ?? new ContextTimeoutOption()); diff --git a/Libplanet.Tests/BlockChainExtensions.cs b/Libplanet.Tests/BlockChainExtensions.cs index da010032987..a434832f9c6 100644 --- a/Libplanet.Tests/BlockChainExtensions.cs +++ b/Libplanet.Tests/BlockChainExtensions.cs @@ -8,9 +8,6 @@ namespace Libplanet.Tests { public static class BlockChainExtensions { - public static Block GetNextBlock(this BlockChain blockChain, BlockHash blockHash) => - blockChain[blockChain[blockHash].Index + 1]; - /// /// Returns an resulting from the execution of /// the tip of . @@ -18,8 +15,10 @@ public static Block GetNextBlock(this BlockChain blockChain, BlockHash blockHash /// The to search. /// An resulting from the execution of /// the tip of . - public static IWorldState GetResultWorldState(this BlockChain blockChain) => - GetResultWorldState(blockChain, blockChain.Tip); + public static IWorldState GetNextWorldState(this BlockChain blockChain) => + blockChain.GetNextStateRootHash() is HashDigest stateRootHash + ? blockChain.GetWorldState(stateRootHash) + : null; /// /// Returns an resulting from the execution of @@ -30,8 +29,10 @@ public static IWorldState GetResultWorldState(this BlockChain blockChain) => /// The index of a to search. /// An resulting from the execution of /// a associated with given . - public static IWorldState GetResultWorldState(this BlockChain blockChain, long index) => - GetResultWorldState(blockChain, blockChain[index]); + public static IWorldState GetNextWorldState(this BlockChain blockChain, long index) => + blockChain.GetNextStateRootHash(index) is HashDigest stateRootHash + ? blockChain.GetWorldState(stateRootHash) + : null; /// /// Returns an resulting from the execution of @@ -42,32 +43,11 @@ public static IWorldState GetResultWorldState(this BlockChain blockChain, long i /// The to search. /// An resulting from the execution of /// a associated with given . - public static IWorldState GetResultWorldState( + public static IWorldState GetNextWorldState( this BlockChain blockChain, BlockHash blockHash) => - GetResultWorldState(blockChain, blockChain[blockHash]); - - private static IWorldState GetResultWorldState(BlockChain blockChain, Block block) - { - if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion) - { - return blockChain.GetWorldState(block.StateRootHash); - } - else - { - // Since block is fetched from blockChain, its index will be at most tip's index. - if (block.Index < blockChain.Tip.Index) - { - return blockChain.GetWorldState(blockChain[block.Index + 1].StateRootHash); - } - else - { - return blockChain.GetNextStateRootHash(block.Hash) is - HashDigest stateRootHash - ? blockChain.GetWorldState(stateRootHash) - : null; - } - } - } + blockChain.GetNextStateRootHash(blockHash) is HashDigest stateRootHash + ? blockChain.GetWorldState(stateRootHash) + : null; } } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index a731556927d..333ac0b00e6 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -786,10 +786,10 @@ public void DoesNotMigrateStateWithoutAction() ImmutableList.Empty, TestUtils.CreateBlockCommit(blockChain.Tip)); blockChain.Append(emptyBlock, TestUtils.CreateBlockCommit(emptyBlock)); - Assert.True(blockChain.GetResultWorldState(emptyBlock.Hash).Legacy); + Assert.True(blockChain.GetNextWorldState(emptyBlock.Hash).Legacy); Assert.Equal( blockChain.GetWorldState(genesis.StateRootHash).Trie.Hash.ByteArray, - blockChain.GetResultWorldState(emptyBlock.Hash).Trie.Hash.ByteArray); + blockChain.GetNextWorldState(emptyBlock.Hash).Trie.Hash.ByteArray); } [Fact] diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 4c6561c9b9c..ebe3079bb93 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -2314,7 +2314,7 @@ private void ValidateNextBlockCommitOnValidatorSetChange() Assert.Equal( blockChain - .GetResultWorldState(0) + .GetNextWorldState(0) .GetValidatorSet(), new ValidatorSet( ValidatorPrivateKeys.Select( @@ -2322,7 +2322,7 @@ private void ValidateNextBlockCommitOnValidatorSetChange() Assert.Equal( blockChain - .GetResultWorldState(1) + .GetNextWorldState(1) .GetValidatorSet(), new ValidatorSet( newValidators.Select( From 0b86001f0d4d003d0eab7542b5ea5b680557305f Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 20 Jun 2024 19:32:12 +0900 Subject: [PATCH 10/11] Changelog --- CHANGES.md | 10 ---------- Libplanet.Action/State/IBlockChainStates.cs | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b388556b429..780857939bd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,8 +28,6 @@ To be released. parameter `IActionEvaluator actionEvaluator` any more. [[#3811]] - (Libplanet) `BlockChain.ProposeBlock()` receives parameter `HashDigest stateRootHash`. [[#3811]] - - (Libplanet) Added `BlockChain.GetNextWorldState()` and - `BlockChain.GetNextWorldState(BlockHash?)` methods. [[#3821]] ### Backward-incompatible network protocol changes @@ -37,12 +35,6 @@ To be released. ### Added APIs - - (Libplanet.Store) Added `IStore.GetNextStateRootHash()` method. - [[#3811]] - - (Libplanet.Store) Added `IStore.PutNextStateRootHash()` method. - [[#3811]] - - (Libplanet.Store) Added `IStore.DeleteNextStateRootHash()` method. - [[#3811]] - (Libplanet) Added `BlockChain.DetermineNextBlockStateRootHash()` method. [[#3811]] @@ -51,8 +43,6 @@ To be released. - `BlockHeader.StateRootHash` now means state root hash calculated by `BlockChain.DetermineNextBlockStateRootHash(previousBlockHash)`. [[#Sloth]] - - `IBlockChainStates.GetWorldState(BlockHash)` now means the `IWorldState` - before state transition from the `Block`. [[#3811]] - `Context.ProcessHeightOrRoundUponRules()` now appends block asynchronously, as a manner of fire-and-forget. [[#3808]] diff --git a/Libplanet.Action/State/IBlockChainStates.cs b/Libplanet.Action/State/IBlockChainStates.cs index 005c32eee3c..f7dbdd62929 100644 --- a/Libplanet.Action/State/IBlockChainStates.cs +++ b/Libplanet.Action/State/IBlockChainStates.cs @@ -22,8 +22,8 @@ public interface IBlockChainStates /// The at , which is the identical /// to what of indicates. /// - /// Thrown when - /// one of the following is true. + /// Thrown when one of the following is true + /// for . /// /// /// Corresponding is not found in the . @@ -46,7 +46,7 @@ public interface IBlockChainStates /// /// The with . /// If is , - /// returns the hash of the empty state root. + /// returns an empty . /// /// Thrown when no with /// as its state root hash is found. From 48e13a97d9b16330c40f07f67aa2eb9003a8d0af Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Fri, 21 Jun 2024 11:09:27 +0900 Subject: [PATCH 11/11] Added suggested changes Co-authored-by: ilgyu --- Libplanet.Net.Tests/Consensus/ContextTest.cs | 2 +- Libplanet.Tests/Action/WorldTest.cs | 15 ++++++++------- Libplanet.Tests/Blockchain/BlockChainTest.cs | 4 ++-- Libplanet/Blockchain/BlockChain.States.cs | 6 +++--- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Libplanet.Net.Tests/Consensus/ContextTest.cs b/Libplanet.Net.Tests/Consensus/ContextTest.cs index caeca6a5f59..61e7cb78c36 100644 --- a/Libplanet.Net.Tests/Consensus/ContextTest.cs +++ b/Libplanet.Net.Tests/Consensus/ContextTest.cs @@ -323,7 +323,7 @@ void BroadcastMessage(ConsensusMsg message) => 1L, TestUtils.PrivateKeys[0], blockChain - .GetNextWorldState(0) + .GetNextWorldState(0L) .GetValidatorSet(), contextTimeoutOptions: new ContextTimeoutOption()); diff --git a/Libplanet.Tests/Action/WorldTest.cs b/Libplanet.Tests/Action/WorldTest.cs index 27f1210d9e1..a1a58018fb2 100644 --- a/Libplanet.Tests/Action/WorldTest.cs +++ b/Libplanet.Tests/Action/WorldTest.cs @@ -260,11 +260,13 @@ public virtual void TransferAssetInBlock() chain.Append(block1, TestUtils.CreateBlockCommit(block1)); Assert.Equal( DumbAction.DumbCurrency * 0, - GetLatestWorldState(chain) + chain + .GetNextWorldState() .GetBalance(_addr[0], DumbAction.DumbCurrency)); Assert.Equal( DumbAction.DumbCurrency * 20, - GetLatestWorldState(chain) + chain + .GetNextWorldState() .GetBalance(_addr[1], DumbAction.DumbCurrency)); // Transfer @@ -288,11 +290,13 @@ public virtual void TransferAssetInBlock() chain.Append(block2, TestUtils.CreateBlockCommit(block2)); Assert.Equal( DumbAction.DumbCurrency * 5, - GetLatestWorldState(chain) + chain + .GetNextWorldState() .GetBalance(_addr[0], DumbAction.DumbCurrency)); Assert.Equal( DumbAction.DumbCurrency * 15, - GetLatestWorldState(chain) + chain + .GetNextWorldState() .GetBalance(_addr[1], DumbAction.DumbCurrency)); // Transfer bugged @@ -504,9 +508,6 @@ public virtual void TotalSupplyTracking() world.GetTotalSupply(_currencies[4])); } - protected static IWorldState GetLatestWorldState(BlockChain blockChain) => - blockChain.GetNextWorldState(); - protected FungibleAssetValue Value(int currencyIndex, BigInteger quantity) => new FungibleAssetValue(_currencies[currencyIndex], quantity, 0); } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index ebe3079bb93..819eeef1b4d 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -2314,7 +2314,7 @@ private void ValidateNextBlockCommitOnValidatorSetChange() Assert.Equal( blockChain - .GetNextWorldState(0) + .GetNextWorldState(0L) .GetValidatorSet(), new ValidatorSet( ValidatorPrivateKeys.Select( @@ -2322,7 +2322,7 @@ private void ValidateNextBlockCommitOnValidatorSetChange() Assert.Equal( blockChain - .GetNextWorldState(1) + .GetNextWorldState(1L) .GetValidatorSet(), new ValidatorSet( newValidators.Select( diff --git a/Libplanet/Blockchain/BlockChain.States.cs b/Libplanet/Blockchain/BlockChain.States.cs index 56738617d13..e55a4d35cc1 100644 --- a/Libplanet/Blockchain/BlockChain.States.cs +++ b/Libplanet/Blockchain/BlockChain.States.cs @@ -28,13 +28,13 @@ public IWorldState GetWorldState(HashDigest? stateRootHash) /// The next world state. If it does not exist, returns null. public IWorldState? GetNextWorldState() { - if (GetNextStateRootHash() is { } srh) + if (GetNextStateRootHash() is { } nsrh) { - var trie = StateStore.GetStateRoot(srh); + var trie = StateStore.GetStateRoot(nsrh); return trie.Recorded ? new WorldBaseState(trie, StateStore) : throw new InvalidOperationException( - $"Could not find state root {srh} in {nameof(StateStore)} for " + + $"Could not find state root {nsrh} in {nameof(StateStore)} for " + $"the current tip."); } else