diff --git a/CHANGES.md b/CHANGES.md index 15b233a975f..c766a99fbf8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,13 @@ To be released. ### Backward-incompatible interface changes + - `IStore.StoreStateReference(string, IImmutableSet
, Block)` + method became replaced by + `StoreStateReference(string, IImmutableSet
, HashDigest, long)` + method so that it takes hash and index of a block instead of an entire + block. [[#420]] + - Added `IStore.ForkBlockIndexes()` method. [[#420]] + ### Added interfaces ### Behavioral changes @@ -17,6 +24,7 @@ To be released. - Fixed a bug that `Swarm` hadn't released its TURN releated resources on `Swarm.StopAsync()`. [[#450]] +[#420]: https://github.com/planetarium/libplanet/pull/420 [#450]: https://github.com/planetarium/libplanet/pull/450 diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 8d19e32b34c..be498747a2c 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -1392,7 +1392,8 @@ void BuildIndex(Guid id, Block block) store.StoreStateReference( chainId.ToString(), dirty.Keys.ToImmutableHashSet(), - b + b.Hash, + b.Index ); BuildIndex(chainId, b); } diff --git a/Libplanet.Tests/Store/StoreExtensionTest.cs b/Libplanet.Tests/Store/StoreExtensionTest.cs index fe8ab81ef8f..3425ab0a201 100644 --- a/Libplanet.Tests/Store/StoreExtensionTest.cs +++ b/Libplanet.Tests/Store/StoreExtensionTest.cs @@ -47,7 +47,12 @@ public void LookupStateReference(StoreFixture fx) Assert.Null(fx.Store.LookupStateReference(fx.StoreNamespace, address, block5)); Assert.Null(fx.Store.LookupStateReference(fx.StoreNamespace, address, block6)); - fx.Store.StoreStateReference(fx.StoreNamespace, tx4.UpdatedAddresses, block4); + fx.Store.StoreStateReference( + fx.StoreNamespace, + tx4.UpdatedAddresses, + block4.Hash, + block4.Index + ); Assert.Null(fx.Store.LookupStateReference(fx.StoreNamespace, address, fx.Block3)); Assert.Equal( Tuple.Create(block4.Hash, block4.Index), @@ -62,7 +67,12 @@ public void LookupStateReference(StoreFixture fx) fx.Store.LookupStateReference(fx.StoreNamespace, address, block6) ); - fx.Store.StoreStateReference(fx.StoreNamespace, tx5.UpdatedAddresses, block5); + fx.Store.StoreStateReference( + fx.StoreNamespace, + tx5.UpdatedAddresses, + block5.Hash, + block5.Index + ); Assert.Null(fx.Store.LookupStateReference( fx.StoreNamespace, address, fx.Block3)); Assert.Equal( diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index fb4c8f95f84..ac2336d8dbb 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -51,7 +51,8 @@ public void DeleteNamespace() Fx.Store.StoreStateReference( Fx.StoreNamespace, addresses.Take(3).ToImmutableHashSet(), - block1 + block1.Hash, + block1.Index ); Fx.Store.IncreaseTxNonce(Fx.StoreNamespace, Fx.Transaction1.Signer); @@ -87,7 +88,8 @@ public void ListAddresses() Fx.Store.StoreStateReference( Fx.StoreNamespace, addresses.Take(3).ToImmutableHashSet(), - Fx.Block1 + Fx.Block1.Hash, + Fx.Block1.Index ); Assert.Equal( addresses.Take(3).ToImmutableHashSet(), @@ -96,7 +98,8 @@ public void ListAddresses() Fx.Store.StoreStateReference( Fx.StoreNamespace, addresses.Skip(2).Take(3).ToImmutableHashSet(), - Fx.Block2 + Fx.Block2.Hash, + Fx.Block2.Index ); Assert.Equal( addresses.Take(5).ToImmutableHashSet(), @@ -105,7 +108,8 @@ public void ListAddresses() Fx.Store.StoreStateReference( Fx.StoreNamespace, addresses.Skip(5).Take(3).ToImmutableHashSet(), - Fx.Block3 + Fx.Block3.Hash, + Fx.Block3.Index ); Assert.Equal( addresses.ToImmutableHashSet(), @@ -343,13 +347,23 @@ public void IterateStateReferences() Assert.Empty(this.Fx.Store.IterateStateReferences(this.Fx.StoreNamespace, address)); - Fx.Store.StoreStateReference(Fx.StoreNamespace, tx4.UpdatedAddresses, block4); + Fx.Store.StoreStateReference( + Fx.StoreNamespace, + tx4.UpdatedAddresses, + block4.Hash, + block4.Index + ); Assert.Equal( new[] { Tuple.Create(block4.Hash, block4.Index) }, this.Fx.Store.IterateStateReferences(this.Fx.StoreNamespace, address) ); - Fx.Store.StoreStateReference(Fx.StoreNamespace, tx5.UpdatedAddresses, block5); + Fx.Store.StoreStateReference( + Fx.StoreNamespace, + tx5.UpdatedAddresses, + block5.Hash, + block5.Index + ); Assert.Equal( new[] { @@ -392,7 +406,11 @@ public void ForkStateReferences(int branchPointIndex) { updatedAddresses = new HashSet
{ address1 }; Fx.Store.StoreStateReference( - Fx.StoreNamespace, updatedAddresses.ToImmutableHashSet(), block); + Fx.StoreNamespace, + updatedAddresses.ToImmutableHashSet(), + block.Hash, + block.Index + ); } var txs2 = new[] { tx2 }; @@ -400,7 +418,11 @@ public void ForkStateReferences(int branchPointIndex) updatedAddresses = new HashSet
{ address2 }; Fx.Store.StoreStateReference( - Fx.StoreNamespace, updatedAddresses.ToImmutableHashSet(), blocks[3]); + Fx.StoreNamespace, + updatedAddresses.ToImmutableHashSet(), + blocks[3].Hash, + blocks[3].Index + ); var branchPoint = blocks[branchPointIndex]; var addressesToStrip = new[] { address1, address2 }.ToImmutableHashSet(); diff --git a/Libplanet.Tests/Store/StoreTracker.cs b/Libplanet.Tests/Store/StoreTracker.cs index eb9ae6473e1..fd08e170063 100644 --- a/Libplanet.Tests/Store/StoreTracker.cs +++ b/Libplanet.Tests/Store/StoreTracker.cs @@ -176,15 +176,15 @@ AddressStateMap states return _store.IterateStateReferences(@namespace, address); } - public void StoreStateReference( + public void StoreStateReference( string @namespace, IImmutableSet
addresses, - Block block) - where T : IAction, new() + HashDigest blockHash, + long blockIndex) { // FIXME: Log arguments properly (including @namespace). - _logs.Add((nameof(StoreStateReference), block.Hash, null)); - _store.StoreStateReference(@namespace, addresses, block); + _logs.Add((nameof(StoreStateReference), blockHash, null)); + _store.StoreStateReference(@namespace, addresses, blockHash, blockIndex); } public void ForkStateReferences( @@ -200,6 +200,15 @@ AddressStateMap states sourceNamespace, destinationNamespace, branchPoint, addressesToStrip); } + public void ForkBlockIndexes( + string sourceNamespace, + string destinationNamespace, + HashDigest branchPoint) + { + _logs.Add((nameof(ForkBlockIndexes), null, null)); + _store.ForkBlockIndexes(sourceNamespace, destinationNamespace, branchPoint); + } + public IEnumerable> ListTxNonces(string @namespace) { _logs.Add((nameof(ListTxNonces), @namespace, null)); diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 717ab06cc83..e2ba71aaa37 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -815,15 +815,8 @@ internal BlockChain Fork(HashDigest point) try { _rwlock.EnterReadLock(); - foreach (var index in Store.IterateIndex(id)) - { - Store.AppendIndex(forkedId, index); - if (index.Equals(point)) - { - break; - } - } + Store.ForkBlockIndexes(id, forkedId, point); Block pointBlock = Blocks[point]; var addressesToStrip = new HashSet
(); @@ -1080,7 +1073,12 @@ bool buildStateReferences if (buildStateReferences) { - Store.StoreStateReference(Id.ToString(), updatedAddresses, block); + Store.StoreStateReference( + Id.ToString(), + updatedAddresses, + block.Hash, + block.Index + ); } } } diff --git a/Libplanet/Net/StateReferenceDownloadState.cs b/Libplanet/Net/StateReferenceDownloadState.cs index e8ce5951d29..34db933c8cb 100644 --- a/Libplanet/Net/StateReferenceDownloadState.cs +++ b/Libplanet/Net/StateReferenceDownloadState.cs @@ -17,11 +17,6 @@ public class StateReferenceDownloadState : PreloadState /// public int ReceivedStateReferenceCount { get; internal set; } - /// - /// The address of the state references just received. - /// - public Address ReceivedAddress { get; internal set; } - /// public override int CurrentPhase => 2; } diff --git a/Libplanet/Net/Swarm.cs b/Libplanet/Net/Swarm.cs index 4281f63972e..3923d6b8637 100644 --- a/Libplanet/Net/Swarm.cs +++ b/Libplanet/Net/Swarm.cs @@ -1042,21 +1042,37 @@ bool render int count = 0, totalCount = recentStates.StateReferences.Count; _logger.Debug("Starts to store state refs received from {0}.", peer); + + var d = new Dictionary, ISet
>(); foreach (var pair in recentStates.StateReferences) { cancellationToken.ThrowIfCancellationRequested(); IImmutableSet
address = ImmutableHashSet.Create(pair.Key); foreach (HashDigest bHash in pair.Value) { - Block block = store.GetBlock(bHash); - store.StoreStateReference(ns, address, block); + if (!d.ContainsKey(bHash)) + { + d[bHash] = new HashSet
(); + } + + d[bHash].UnionWith(address); + } + } + + totalCount = d.Count; + foreach (KeyValuePair, ISet
> pair in d) + { + HashDigest hash = pair.Key; + IImmutableSet
addresses = pair.Value.ToImmutableHashSet(); + if (store.GetBlockIndex(hash) is long index) + { + store.StoreStateReference(ns, addresses, hash, index); } progress?.Report(new StateReferenceDownloadState() { TotalStateReferenceCount = totalCount, ReceivedStateReferenceCount = ++count, - ReceivedAddress = pair.Key, }); } diff --git a/Libplanet/Store/BaseStore.cs b/Libplanet/Store/BaseStore.cs index cf452c12e11..ce9b0752cf5 100644 --- a/Libplanet/Store/BaseStore.cs +++ b/Libplanet/Store/BaseStore.cs @@ -38,6 +38,12 @@ long index HashDigest hash ); + /// + public abstract void ForkBlockIndexes( + string sourceNamespace, + string destinationNamespace, + HashDigest branchPoint); + /// public abstract IEnumerable
ListAddresses(string @namespace); @@ -119,12 +125,11 @@ AddressStateMap states public abstract IEnumerable, long>> IterateStateReferences( string @namespace, Address address); - /// - public abstract void StoreStateReference( + public abstract void StoreStateReference( string @namespace, IImmutableSet
addresses, - Block block) - where T : IAction, new(); + HashDigest hashDigest, + long index); /// public abstract void ForkStateReferences( diff --git a/Libplanet/Store/IStore.cs b/Libplanet/Store/IStore.cs index 29ae069329c..986ecfa231e 100644 --- a/Libplanet/Store/IStore.cs +++ b/Libplanet/Store/IStore.cs @@ -53,6 +53,26 @@ public interface IStore bool DeleteIndex(string @namespace, HashDigest hash); + /// + /// Forks block indexes from + /// to + /// . + /// + /// The namespace of block indexes to + /// fork. + /// The namespace of destination + /// block indexes. + /// The branch point + /// to fork. + /// Thrown when the given + /// does not exist. + /// + /// + void ForkBlockIndexes( + string sourceNamespace, + string destinationNamespace, + HashDigest branchPoint); + /// /// Deletes an index, tx nonces, and state references in the given /// . @@ -175,6 +195,7 @@ void PutBlock(Block block) AddressStateMap states ); + #pragma warning disable MEN002 /// /// Gets pairs of a state reference and a corresponding of /// the requested in the specified . @@ -184,7 +205,8 @@ AddressStateMap states /// Ordered pairs of a state reference and a corresponding /// . The highest index (i.e., the closest to the tip) goes /// first and the lowest index (i.e., the closest to the genesis) goes last. - /// + /// + #pragma warning restore MEN002 // Line is too long IEnumerable, long>> IterateStateReferences( string @namespace, Address address); @@ -193,25 +215,24 @@ AddressStateMap states /// Stores a state reference, which is a /// that has the state of the for each updated /// es by the s in the - /// . + /// . /// The namespace to store a state reference. /// /// The es to store state /// reference. - /// The which has the state + /// The which has the state /// of the . - /// An class used with - /// . - /// State reference must be stored in the same order as the blocks. For now, - /// it is assumed that this is only called by - /// method. + /// The which has the state + /// of the . This must refer to the same block + /// that refers to. /// - void StoreStateReference( + void StoreStateReference( string @namespace, IImmutableSet
addresses, - Block block) - where T : IAction, new(); + HashDigest blockHash, + long blockIndex); + #pragma warning disable MEN002 /// /// Forks state references, which are es that /// have the state of the es, from @@ -236,7 +257,8 @@ AddressStateMap states /// Thrown when the given /// does not exist. /// - /// + /// + #pragma warning restore MEN002 void ForkStateReferences( string sourceNamespace, string destinationNamespace, diff --git a/Libplanet/Store/LiteDBStore.cs b/Libplanet/Store/LiteDBStore.cs index 92e4d54d4d6..ff758ab6afc 100644 --- a/Libplanet/Store/LiteDBStore.cs +++ b/Libplanet/Store/LiteDBStore.cs @@ -191,6 +191,19 @@ public override bool DeleteIndex(string @namespace, HashDigest hash) return deleted > 0; } + /// + public override void ForkBlockIndexes( + string sourceNamespace, + string destinationNamespace, + HashDigest branchPoint) + { + LiteCollection srcColl = IndexCollection(sourceNamespace); + LiteCollection destColl = IndexCollection(destinationNamespace); + + destColl.InsertBulk(srcColl.FindAll().TakeWhile(i => !i.Hash.Equals(branchPoint))); + AppendIndex(destinationNamespace, branchPoint); + } + /// public override IEnumerable
ListAddresses(string @namespace) { @@ -432,10 +445,11 @@ public override AddressStateMap GetBlockStates(HashDigest blockHash) } /// - public override void StoreStateReference( + public override void StoreStateReference( string @namespace, IImmutableSet
addresses, - Block block) + HashDigest hash, + long index) { string collId = StateRefId(@namespace); LiteCollection coll = _db.GetCollection(collId); @@ -443,8 +457,8 @@ public override AddressStateMap GetBlockStates(HashDigest blockHash) addresses.Select(addr => new StateRefDoc { Address = addr, - BlockIndex = block.Index, - BlockHash = block.Hash, + BlockIndex = index, + BlockHash = hash, }) ); coll.EnsureIndex("AddressString"); diff --git a/Libplanet/Store/StoreExtension.cs b/Libplanet/Store/StoreExtension.cs index fd7f496d441..ffb45c4ee41 100644 --- a/Libplanet/Store/StoreExtension.cs +++ b/Libplanet/Store/StoreExtension.cs @@ -10,6 +10,7 @@ namespace Libplanet.Store { public static class StoreExtension { + #pragma warning disable MEN002 /// /// Looks up a state reference, which is a block's that contains /// an action mutating the ' state. @@ -24,9 +25,9 @@ public static class StoreExtension /// address. /// An class used with /// . - /// + /// /// + #pragma warning restore MEN002 public static Tuple, long> LookupStateReference( this IStore store, string @namespace,