From 0a3eb0efa83564ec1d8226c0533aedba5139b828 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Fri, 18 Jun 2021 14:38:46 +0900 Subject: [PATCH 01/22] HashAlgorithmType class --- CHANGES.md | 3 + Libplanet.Tests/HashAlgorithmTypeTest.cs | 76 +++++++++++++ Libplanet/HashAlgorithmType.cs | 133 +++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 Libplanet.Tests/HashAlgorithmTypeTest.cs create mode 100644 Libplanet/HashAlgorithmType.cs diff --git a/CHANGES.md b/CHANGES.md index a50de4f299..1663b6e7d7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -173,6 +173,7 @@ To be released. - Added `ActionEvaluator` class. [[#1301], [#1305]] - Added `BlockHash` struct. [[#1192], [#1197]] - Added `HashDigest.DeriveFrom()` method. [[#1197]] + - Added `HashAlgorithmType` class. [[#1314], [#1352]] - Added `BlockChain.GetTxExecution()` method. [[#1156], [#1289]] - Added `StunMessage.ParseAsync(Stream, CancellationToken)` method. [[#1228]] @@ -313,6 +314,7 @@ To be released. [#1298]: https://github.com/planetarium/libplanet/pull/1298 [#1301]: https://github.com/planetarium/libplanet/issues/1301 [#1305]: https://github.com/planetarium/libplanet/pull/1305 +[#1314]: https://github.com/planetarium/libplanet/issues/1314 [#1315]: https://github.com/planetarium/libplanet/issues/1315 [#1316]: https://github.com/planetarium/libplanet/issues/1316 [#1320]: https://github.com/planetarium/libplanet/issues/1320 @@ -328,6 +330,7 @@ To be released. [#1349]: https://github.com/planetarium/libplanet/issues/1349 [#1350]: https://github.com/planetarium/libplanet/pull/1350 [#1351]: https://github.com/planetarium/libplanet/pull/1351 +[#1352]: https://github.com/planetarium/libplanet/pull/1352 [#1353]: https://github.com/planetarium/libplanet/pull/1353 [#1360]: https://github.com/planetarium/libplanet/pull/1360 diff --git a/Libplanet.Tests/HashAlgorithmTypeTest.cs b/Libplanet.Tests/HashAlgorithmTypeTest.cs new file mode 100644 index 0000000000..a248991b22 --- /dev/null +++ b/Libplanet.Tests/HashAlgorithmTypeTest.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Immutable; +using System.Security.Cryptography; +using System.Text; +using Xunit; +using static Libplanet.Tests.TestUtils; + +namespace Libplanet.Tests +{ + public class HashAlgorithmTypeTest + { + [Fact] + public void Of() + { + HashAlgorithmType md5 = HashAlgorithmType.Of(); + Assert.Same(typeof(MD5), md5.Type); + Assert.Equal(16, md5.DigestSize); + + HashAlgorithmType sha1 = HashAlgorithmType.Of(); + Assert.Same(typeof(SHA1), sha1.Type); + Assert.Equal(20, sha1.DigestSize); + + HashAlgorithmType sha256 = HashAlgorithmType.Of(SHA256.Create()); + Assert.Same(typeof(SHA256), sha256.Type); + Assert.Equal(32, sha256.DigestSize); + } + + [Fact] + public void Digest() + { + HashAlgorithmType md5 = HashAlgorithmType.Of(); + byte[] digest = md5.Digest(Encoding.ASCII.GetBytes("hello")); + byte[] expected = + { + 0x5d, 0x41, 0x40, 0x2a, 0xbc, 0x4b, 0x2a, 0x76, + 0xb9, 0x71, 0x9d, 0x91, 0x10, 0x17, 0xc5, 0x92, + }; + AssertBytesEqual(expected, digest); + + ImmutableArray immutableDigest = + md5.Digest(Encoding.ASCII.GetBytes("hello").ToImmutableArray()); + AssertBytesEqual(expected.ToImmutableArray(), immutableDigest); + } + + [Fact] + public void Equality() + { + HashAlgorithmType md5 = HashAlgorithmType.Of(); + HashAlgorithmType md5a = HashAlgorithmType.Of(MD5.Create()); + HashAlgorithmType sha1 = HashAlgorithmType.Of(); + + Assert.Equal(md5, md5a); + Assert.True(((IEquatable)md5).Equals(md5a)); + Assert.True(md5.Equals((object)md5a)); + Assert.Equal(md5.GetHashCode(), md5a.GetHashCode()); + Assert.True(md5 == md5a); + Assert.False(md5 != md5a); + + Assert.NotEqual(md5, sha1); + Assert.True(!((IEquatable)md5).Equals(sha1)); + Assert.True(!md5.Equals((object)sha1)); + Assert.NotEqual(md5.GetHashCode(), sha1.GetHashCode()); + Assert.False(md5 == sha1); + Assert.True(md5 != sha1); + } + + [Fact] + public void String() + { + HashAlgorithmType md5 = HashAlgorithmType.Of(); + HashAlgorithmType sha1 = HashAlgorithmType.Of(); + Assert.Equal("System.Security.Cryptography.MD5", md5.ToString()); + Assert.Equal("System.Security.Cryptography.SHA1", sha1.ToString()); + } + } +} diff --git a/Libplanet/HashAlgorithmType.cs b/Libplanet/HashAlgorithmType.cs new file mode 100644 index 0000000000..cfe6dae091 --- /dev/null +++ b/Libplanet/HashAlgorithmType.cs @@ -0,0 +1,133 @@ +#nullable enable +using System; +using System.Collections.Concurrent; +using System.Collections.Immutable; +using System.Diagnostics.Contracts; +using System.Reflection; +using System.Security.Cryptography; + +namespace Libplanet +{ + /// + /// Represents the type of . + /// It is guaranteed that only one instance is created for the same subclass of + /// . + /// + [Pure] + public sealed class HashAlgorithmType : IEquatable + { + private static readonly ConcurrentDictionary _internedObjects + = new ConcurrentDictionary(); + + private readonly HashAlgorithm _instance; + + private HashAlgorithmType(Type type) + { + Type = type; + MethodInfo method = type.GetMethod(nameof(HashAlgorithm.Create), new Type[0])!; + string excMsg = + $"Failed to invoke {type.FullName}.{nameof(HashAlgorithm.Create)}() static method."; + _instance = method?.Invoke(null, new object[0]) as HashAlgorithm + ?? throw new InvalidCastException(excMsg); + } + + /// + /// The object which refers to a subclass of + /// . + /// + [Pure] + public Type Type { get; } + + /// + /// The length of bytes of every digest that the makes. + /// + [Pure] + public int DigestSize => _instance.HashSize / 8; + + /// + /// Checks if two s refers to the same + /// class. + /// + /// An instance. + /// Another instance. + /// true iff two operands refers to the same + /// class. + [Pure] + public static bool operator ==(HashAlgorithmType left, HashAlgorithmType right) => + left is IEquatable l && l.Equals(right); + + /// + /// Checks if two s do not refer to the different + /// class. + /// + /// An instance. + /// Another instance. + /// false iff two operands refers to the same + /// class. + public static bool operator !=(HashAlgorithmType left, HashAlgorithmType right) => + !(left == right); + + /// + /// Creates a which refers to . + /// + /// An optional object to make the compiler infers the + /// type parameter from this. + /// A subclass of . + /// A which refers to . + /// + [Pure] + public static HashAlgorithmType Of(T? objectToInferType = null) + where T : HashAlgorithm => + Of(typeof(T)); + + /// + /// Computes a hash digest of the hash algorithm from the given + /// bytes. + /// + /// The bytes to compute its hash. + /// The hash digest derived from . + [Pure] + public byte[] Digest(byte[] input) => + _instance.ComputeHash(input); + + /// + /// Computes a hash digest of the hash algorithm from the given + /// bytes. + /// + /// The bytes to compute its hash. + /// The hash digest derived from . + [Pure] + public ImmutableArray Digest(ImmutableArray input) => + Digest(input.ToBuilder().ToArray()).ToImmutableArray(); + + /// + [Pure] + public bool Equals(HashAlgorithmType? other) => + other is { } o && Type == o.Type; + + /// + [Pure] + public override bool Equals(object? obj) => + obj is IEquatable e && e.Equals(this); + + /// + [Pure] + public override int GetHashCode() => + Type.GetHashCode(); + + /// + [Pure] + public override string ToString() => + Type.FullName ?? "(Unknown)"; + + private static HashAlgorithmType Of(Type type) + { + if (!_internedObjects.TryGetValue(type, out HashAlgorithmType? v)) + { + v = new HashAlgorithmType(type); + } + + return v; + } + } +} From 0def61d5e6e4b97ca4677012372c35df9214d46e Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Fri, 18 Jun 2021 16:39:32 +0900 Subject: [PATCH 02/22] ByteUtil.TimingSafelyCompare() method --- CHANGES.md | 1 + Libplanet.Tests/ByteUtilTest.cs | 17 +++++++++++++++++ Libplanet/ByteUtil.cs | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 1663b6e7d7..8e74a93e17 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -194,6 +194,7 @@ To be released. - Added `Address(Binary)` overloaded constructor. [[#1289]] - Added `Currency(IValue)` overloaded constructor. [[#1289]] - Added `Currency.Serialize()` method. [[#1289]] + - Added `ByteUtil.TimingSafelyCompare()` method. [[#1314], [#1352]] ### Behavioral changes diff --git a/Libplanet.Tests/ByteUtilTest.cs b/Libplanet.Tests/ByteUtilTest.cs index 08dacdd8cf..5d00feca57 100644 --- a/Libplanet.Tests/ByteUtilTest.cs +++ b/Libplanet.Tests/ByteUtilTest.cs @@ -60,5 +60,22 @@ public void CanCalculateHashCode() ByteUtil.CalculateHashCode(otherBytes) ); } + + [Fact] + public void TimingSafelyCompare() + { + Assert.True(ByteUtil.TimingSafelyCompare(new byte[0], new byte[0])); + Assert.False(ByteUtil.TimingSafelyCompare(new byte[] { 0 }, new byte[] { 1 })); + Assert.True(ByteUtil.TimingSafelyCompare(new byte[] { 1 }, new byte[] { 1 })); + Assert.True( + ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3, 4 }) + ); + Assert.False( + ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3, 5 }) + ); + Assert.False( + ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3 }) + ); + } } } diff --git a/Libplanet/ByteUtil.cs b/Libplanet/ByteUtil.cs index 7a1b1730e3..5f7f7d516f 100644 --- a/Libplanet/ByteUtil.cs +++ b/Libplanet/ByteUtil.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.Contracts; using System.Globalization; @@ -118,5 +119,25 @@ public static int CalculateHashCode(byte[] bytes) (current, t) => unchecked(current * (bytes.Length + 1) + t) ); } + + /// + /// Timing safe comparision of two byte arrays. + /// + /// In case of two byte arrays do not have the same length, it tries to keep + /// the timing dependent on the length of the shorter one. + /// A byte array. + /// Another byte array. + /// true iff two byte arrays have the exactly same contents. + [Pure] + public static bool TimingSafelyCompare(IReadOnlyList left, IReadOnlyList right) + { + bool differ = left.Count != right.Count; + for (int i = 0, len = Math.Min(left.Count, right.Count); i < len; i++) + { + differ = differ || (left[i] ^ right[i]) != 0; + } + + return !differ; + } } } From 2b63bd50d2c6943de7f82a3e254c8f84c5600751 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Fri, 18 Jun 2021 19:19:37 +0900 Subject: [PATCH 03/22] Overload Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken) --- CHANGES.md | 2 + Libplanet.Tests/Blocks/BlockHeaderTest.cs | 2 + Libplanet.Tests/HashcashTest.cs | 16 +++++-- Libplanet/Blockchain/BlockChain.cs | 2 + Libplanet/Blocks/Block.cs | 8 ++++ Libplanet/Blocks/BlockHeader.cs | 2 + Libplanet/Hashcash.cs | 53 +++++++++++++++++++---- Libplanet/Store/Trie/MerkleTrie.cs | 2 + 8 files changed, 75 insertions(+), 12 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 8e74a93e17..50064d85e3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -195,6 +195,8 @@ To be released. - Added `Currency(IValue)` overloaded constructor. [[#1289]] - Added `Currency.Serialize()` method. [[#1289]] - Added `ByteUtil.TimingSafelyCompare()` method. [[#1314], [#1352]] + - Added `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` + overloaded method. [[#1314], [#1352]] ### Behavioral changes diff --git a/Libplanet.Tests/Blocks/BlockHeaderTest.cs b/Libplanet.Tests/Blocks/BlockHeaderTest.cs index 464653658f..db0969bcd6 100644 --- a/Libplanet.Tests/Blocks/BlockHeaderTest.cs +++ b/Libplanet.Tests/Blocks/BlockHeaderTest.cs @@ -371,7 +371,9 @@ private BlockHeader MakeBlockHeader( ImmutableArray stateRootHash ) { +#pragma warning disable CS0612 ImmutableArray hash = Hashcash.Hash( +#pragma warning restore CS0612 BlockHeader.SerializeForHash( protocolVersion, index, diff --git a/Libplanet.Tests/HashcashTest.cs b/Libplanet.Tests/HashcashTest.cs index af06f36248..c944d1bb95 100644 --- a/Libplanet.Tests/HashcashTest.cs +++ b/Libplanet.Tests/HashcashTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Security.Cryptography; using Libplanet.Blocks; @@ -15,9 +16,18 @@ public class HashcashTest public void AnswerSatisfiesDifficulty(byte[] challenge, long difficulty) { byte[] Stamp(Nonce nonce) => challenge.Concat(nonce.ToByteArray()).ToArray(); - var answer = Hashcash.Answer(Stamp, difficulty); - var digest = Hashcash.Hash(Stamp(answer)); - Assert.True(digest.Satisfies(difficulty)); + (Nonce answer, ImmutableArray digest) = + Hashcash.Answer(Stamp, HashAlgorithmType.Of(), difficulty); + Assert.True(Satisfies(digest.ToArray(), difficulty)); + TestUtils.AssertBytesEqual( + digest.ToArray(), + SHA256.Create().ComputeHash(Stamp(answer)) + ); +#pragma warning disable CS0612 + Nonce answer2 = Hashcash.Answer(Stamp, difficulty); + BlockHash digest2 = Hashcash.Hash(Stamp(answer2)); +#pragma warning restore CS0612 + Assert.True(digest2.Satisfies(difficulty)); } [Fact] diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 965de57906..afacd0dc70 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -2003,7 +2003,9 @@ internal IEnumerable IterateBlockHashes(int offset = 0, int? limit = dict.Add(address.ToHex(), actionEvaluation.OutputStates.GetState(address)); } +#pragma warning disable CS0612 return Hashcash.Hash(new Codec().Encode(dict)); +#pragma warning restore CS0612 } /// diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index 51fc39ae2a..12fa1563ba 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -82,11 +82,15 @@ public Block( Transactions = transactions.OrderBy(tx => tx.Id).ToArray(); TxHash = CalculateTxHashes(Transactions); +#pragma warning disable CS0612 PreEvaluationHash = preEvaluationHash ?? Hashcash.Hash(Header.SerializeForHash()); +#pragma warning restore CS0612 StateRootHash = stateRootHash; // FIXME: This does not need to be computed every time? +#pragma warning disable CS0612 Hash = Hashcash.Hash(Header.SerializeForHash()); +#pragma warning restore CS0612 // As the order of transactions should be unpredictable until a block is mined, // the sorter key should be derived from both a block hash and a txid. @@ -399,7 +403,9 @@ public static Block Mine( byte[] stampSuffix = new byte[emptyNonce.Length - offset - nonceLength]; Array.Copy(emptyNonce, offset + nonceLength, stampSuffix, 0, stampSuffix.Length); +#pragma warning disable CS0612 Nonce nonce = Hashcash.Answer( +#pragma warning restore CS0612 n => { int nLen = n.ByteArray.Length; @@ -514,7 +520,9 @@ internal void Validate(DateTimeOffset currentTime) if (ProtocolVersion > 0) { BlockHash expectedPreEvaluationHash = +#pragma warning disable CS0612 Hashcash.Hash(Header.SerializeForHash(includeStateRootHash: false)); +#pragma warning restore CS0612 if (!expectedPreEvaluationHash.Equals(PreEvaluationHash)) { string message = diff --git a/Libplanet/Blocks/BlockHeader.cs b/Libplanet/Blocks/BlockHeader.cs index 98a8b78948..60ce7a6068 100644 --- a/Libplanet/Blocks/BlockHeader.cs +++ b/Libplanet/Blocks/BlockHeader.cs @@ -403,7 +403,9 @@ internal void Validate(DateTimeOffset currentTime) ); } +#pragma warning disable CS0612 BlockHash calculatedHash = Hashcash.Hash(SerializeForHash()); +#pragma warning restore CS0612 if (!hash.Equals(calculatedHash)) { throw new InvalidBlockHashException( diff --git a/Libplanet/Hashcash.cs b/Libplanet/Hashcash.cs index 829b8d20e4..847ebf19e1 100644 --- a/Libplanet/Hashcash.cs +++ b/Libplanet/Hashcash.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Collections.Immutable; using System.Security.Cryptography; using System.Threading; using Libplanet.Blocks; @@ -23,13 +24,14 @@ public static class Hashcash /// >proof-of-work system, the total time an implementation elapses /// should not vary for different s. /// - /// An arbitrary nonce for an attempt, provided - /// by method. + /// An arbitrary nonce for an attempt, provided by + /// method. + /// /// A array determined from the given /// . It should return consistently /// an equivalent array for equivalent /// values. - /// + /// /// public delegate byte[] Stamp(Nonce nonce); @@ -43,19 +45,23 @@ public static class Hashcash /// A callback to get a “stamp” /// which is a array determined from a given /// value. + /// The hash algorithm to use. /// A number to calculate the target number /// for which the returned answer should be less than. /// /// A cancellation token used to propagate notification that this /// operation should be canceled. /// - /// A value which satisfies the given - /// . + /// A pair of value which satisfies the + /// given , and the succeeded hash + /// digest. /// - public static Nonce Answer( + public static (Nonce Nonce, ImmutableArray Digest) Answer( Stamp stamp, + HashAlgorithmType hashAlgorithmType, long difficulty, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default + ) { var nonceBytes = new byte[10]; var random = new Random(); @@ -63,17 +69,45 @@ public static Nonce Answer( { random.NextBytes(nonceBytes); var nonce = new Nonce(nonceBytes); - var digest = Hash(stamp(nonce)); + // FIXME: .Satisfies() method should be moved to other class. + var digest = new BlockHash(hashAlgorithmType.Digest(stamp(nonce))); if (digest.Satisfies(difficulty)) { - return nonce; + return (nonce, digest.ByteArray); } } throw new OperationCanceledException(cancellationToken); } + /// + /// Finds a that satisfies the given + /// . This process is so-called + /// “mining”. + /// + /// A callback to get a “stamp” + /// which is a array determined from a given + /// value. + /// A number to calculate the target number + /// for which the returned answer should be less than. + /// + /// A cancellation token used to propagate notification that this + /// operation should be canceled. + /// + /// A value which satisfies the given + /// . + /// + [Obsolete] + public static Nonce Answer( + Stamp stamp, + long difficulty, + CancellationToken cancellationToken = default + ) => + Answer(stamp, HashAlgorithmType.Of(), difficulty, cancellationToken).Nonce; + /// /// Calculates a SHA-256 digest from the given . /// @@ -81,6 +115,7 @@ public static Nonce Answer( /// its hash digest. /// A deterministic digest of the given /// . + [Obsolete] public static BlockHash Hash(byte[] bytes) => BlockHash.FromHashDigest(HashDigest.DeriveFrom(bytes)); } diff --git a/Libplanet/Store/Trie/MerkleTrie.cs b/Libplanet/Store/Trie/MerkleTrie.cs index b76d657d33..b5f9ee3096 100644 --- a/Libplanet/Store/Trie/MerkleTrie.cs +++ b/Libplanet/Store/Trie/MerkleTrie.cs @@ -448,7 +448,9 @@ private byte[] ToKey(byte[] key) { if (_secure) { +#pragma warning disable CS0612 key = Hashcash.Hash(key).ToByteArray(); +#pragma warning restore CS0612 } var res = new byte[key.Length * 2]; From 344e46765392fa707765cfb49ede4e7c6d593ae0 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Fri, 18 Jun 2021 19:40:14 +0900 Subject: [PATCH 04/22] Remove unused internal methods --- Libplanet.Tests/TestUtils.cs | 26 -------------------------- Libplanet/Blockchain/BlockChain.cs | 26 -------------------------- 2 files changed, 52 deletions(-) diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 52b45d346e..83661e93c8 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Security.Cryptography; using System.Text; -using Bencodex; using Bencodex.Types; using Libplanet.Action; using Libplanet.Assets; @@ -375,31 +374,6 @@ public static BlockChain MakeBlockChain( return chain; } - public static HashDigest? ActionEvaluationsToHash( - IEnumerable actionEvaluations) - { - ActionEvaluation actionEvaluation; - var evaluations = actionEvaluations.ToList(); - if (evaluations.Any()) - { - actionEvaluation = evaluations.Last(); - } - else - { - return (HashDigest?)null; - } - - IImmutableSet
updatedAddresses = - actionEvaluation.OutputStates.UpdatedAddresses; - var dict = Bencodex.Types.Dictionary.Empty; - foreach (Address address in updatedAddresses) - { - dict.Add(address.ToHex(), actionEvaluation.OutputStates.GetState(address)); - } - - return HashDigest.DeriveFrom(new Codec().Encode(dict)); - } - public static PrivateKey GeneratePrivateKeyOfBucketIndex(Address tableAddress, int target) { var table = new RoutingTable(tableAddress); diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index afacd0dc70..4169e5f03a 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -1982,32 +1982,6 @@ internal IEnumerable IterateBlockHashes(int offset = 0, int? limit = } } - internal BlockHash? ActionEvaluationsToHash(IEnumerable actionEvaluations) - { - ActionEvaluation actionEvaluation; - var evaluations = actionEvaluations.ToList(); - if (evaluations.Any()) - { - actionEvaluation = evaluations.Last(); - } - else - { - return null; - } - - IImmutableSet
updatedAddresses = - actionEvaluation.OutputStates.UpdatedAddresses; - var dict = Bencodex.Types.Dictionary.Empty; - foreach (Address address in updatedAddresses) - { - dict.Add(address.ToHex(), actionEvaluation.OutputStates.GetState(address)); - } - -#pragma warning disable CS0612 - return Hashcash.Hash(new Codec().Encode(dict)); -#pragma warning restore CS0612 - } - /// /// Calculates and complements a block's incomplete states on the fly. /// From cd5f23a47f6704a6a0dcae66d5ae2b6449a2f2df Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Fri, 18 Jun 2021 19:42:15 +0900 Subject: [PATCH 05/22] Remove Hashcash.Hash() method --- CHANGES.md | 4 ++-- Libplanet.Tests/Blocks/BlockHeaderTest.cs | 7 +++---- Libplanet.Tests/HashcashTest.cs | 4 ++-- Libplanet/Blocks/Block.cs | 23 +++++++++++------------ Libplanet/Blocks/BlockHeader.cs | 6 +++--- Libplanet/Hashcash.cs | 11 ----------- Libplanet/Store/Trie/MerkleTrie.cs | 10 ++++------ 7 files changed, 25 insertions(+), 40 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 50064d85e3..d2b9e10627 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -159,10 +159,10 @@ To be released. [[#1294], [#1328]] - Added `IStore.DeleteTxIdBlockHashIndex(TxId, BlockHash)` method. [[#1294], [#1328]] - - Added `IStore.IterateTxIdBlockHashIndex(TxId)` method. - [[#1294], [#1328]] + - Added `IStore.IterateTxIdBlockHashIndex(TxId)` method. [[#1294], [#1328]] - `Swarm.StartAsync()` method became to receive `broadcastBlockInterval` (or `millisecondsBroadcastBlockInterval`) parameter. [[#1351]] + - Removed `Hashcash.Hash()` method. [[#1314], [#1352]] ### Backward-incompatible network protocol changes diff --git a/Libplanet.Tests/Blocks/BlockHeaderTest.cs b/Libplanet.Tests/Blocks/BlockHeaderTest.cs index db0969bcd6..1d173540d6 100644 --- a/Libplanet.Tests/Blocks/BlockHeaderTest.cs +++ b/Libplanet.Tests/Blocks/BlockHeaderTest.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using Bencodex.Types; using Libplanet.Blocks; using Libplanet.Tests.Common.Action; @@ -371,9 +372,7 @@ private BlockHeader MakeBlockHeader( ImmutableArray stateRootHash ) { -#pragma warning disable CS0612 - ImmutableArray hash = Hashcash.Hash( -#pragma warning restore CS0612 + ImmutableArray hash = HashAlgorithmType.Of().Digest( BlockHeader.SerializeForHash( protocolVersion, index, @@ -385,7 +384,7 @@ ImmutableArray stateRootHash txHash, stateRootHash ) - ).ByteArray; + ).ToImmutableArray(); return new BlockHeader( protocolVersion, index, diff --git a/Libplanet.Tests/HashcashTest.cs b/Libplanet.Tests/HashcashTest.cs index c944d1bb95..c5b85822fa 100644 --- a/Libplanet.Tests/HashcashTest.cs +++ b/Libplanet.Tests/HashcashTest.cs @@ -25,9 +25,9 @@ public void AnswerSatisfiesDifficulty(byte[] challenge, long difficulty) ); #pragma warning disable CS0612 Nonce answer2 = Hashcash.Answer(Stamp, difficulty); - BlockHash digest2 = Hashcash.Hash(Stamp(answer2)); #pragma warning restore CS0612 - Assert.True(digest2.Satisfies(difficulty)); + byte[] digest2 = SHA256.Create().ComputeHash(Stamp(answer2)); + Assert.True(Satisfies(digest2, difficulty)); } [Fact] diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index 12fa1563ba..0cbc172b78 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -82,15 +82,13 @@ public Block( Transactions = transactions.OrderBy(tx => tx.Id).ToArray(); TxHash = CalculateTxHashes(Transactions); -#pragma warning disable CS0612 - PreEvaluationHash = preEvaluationHash ?? Hashcash.Hash(Header.SerializeForHash()); -#pragma warning restore CS0612 + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + PreEvaluationHash = preEvaluationHash ?? + new BlockHash(hashAlgorithm.Digest(Header.SerializeForHash())); StateRootHash = stateRootHash; // FIXME: This does not need to be computed every time? -#pragma warning disable CS0612 - Hash = Hashcash.Hash(Header.SerializeForHash()); -#pragma warning restore CS0612 + Hash = new BlockHash(hashAlgorithm.Digest(Header.SerializeForHash())); // As the order of transactions should be unpredictable until a block is mined, // the sorter key should be derived from both a block hash and a txid. @@ -519,11 +517,12 @@ internal void Validate(DateTimeOffset currentTime) if (ProtocolVersion > 0) { - BlockHash expectedPreEvaluationHash = -#pragma warning disable CS0612 - Hashcash.Hash(Header.SerializeForHash(includeStateRootHash: false)); -#pragma warning restore CS0612 - if (!expectedPreEvaluationHash.Equals(PreEvaluationHash)) + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + byte[] expectedPreEvaluationHash = + hashAlgorithm.Digest(Header.SerializeForHash(includeStateRootHash: false)); + if (!ByteUtil.TimingSafelyCompare( + expectedPreEvaluationHash, + PreEvaluationHash.ByteArray)) { string message = $"The expected pre evaluation hash of block {Hash} is " + @@ -531,7 +530,7 @@ internal void Validate(DateTimeOffset currentTime) $"{PreEvaluationHash}."; throw new InvalidBlockPreEvaluationHashException( PreEvaluationHash, - expectedPreEvaluationHash, + new BlockHash(expectedPreEvaluationHash), message); } } diff --git a/Libplanet/Blocks/BlockHeader.cs b/Libplanet/Blocks/BlockHeader.cs index 60ce7a6068..49dffaa40a 100644 --- a/Libplanet/Blocks/BlockHeader.cs +++ b/Libplanet/Blocks/BlockHeader.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using Bencodex; using Bencodex.Types; using Libplanet.Store.Trie; @@ -403,9 +404,8 @@ internal void Validate(DateTimeOffset currentTime) ); } -#pragma warning disable CS0612 - BlockHash calculatedHash = Hashcash.Hash(SerializeForHash()); -#pragma warning restore CS0612 + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + BlockHash calculatedHash = new BlockHash(hashAlgorithm.Digest(SerializeForHash())); if (!hash.Equals(calculatedHash)) { throw new InvalidBlockHashException( diff --git a/Libplanet/Hashcash.cs b/Libplanet/Hashcash.cs index 847ebf19e1..2a0a82613a 100644 --- a/Libplanet/Hashcash.cs +++ b/Libplanet/Hashcash.cs @@ -107,16 +107,5 @@ public static Nonce Answer( CancellationToken cancellationToken = default ) => Answer(stamp, HashAlgorithmType.Of(), difficulty, cancellationToken).Nonce; - - /// - /// Calculates a SHA-256 digest from the given . - /// - /// A array to calculate - /// its hash digest. - /// A deterministic digest of the given - /// . - [Obsolete] - public static BlockHash Hash(byte[] bytes) => - BlockHash.FromHashDigest(HashDigest.DeriveFrom(bytes)); } } diff --git a/Libplanet/Store/Trie/MerkleTrie.cs b/Libplanet/Store/Trie/MerkleTrie.cs index b5f9ee3096..007577f0b6 100644 --- a/Libplanet/Store/Trie/MerkleTrie.cs +++ b/Libplanet/Store/Trie/MerkleTrie.cs @@ -40,7 +40,7 @@ static MerkleTrie() /// . /// Whether to use in /// secure mode. If it is turned on, internally stores hashed keys - /// instead of bare keys. is used to hash them. + /// instead of bare keys. Keys will be hashed with SHA-256. public MerkleTrie( IKeyValueStore keyValueStore, HashDigest rootHash, @@ -58,8 +58,7 @@ public MerkleTrie( /// it will be treated like empty trie. /// Whether to use in secure /// mode. If it is true, will stores the value with the hashed - /// result from the given key as the key. It will hash with - /// . + /// result from the given key as the key. Keys will be hashed with SHA-256. internal MerkleTrie(IKeyValueStore keyValueStore, INode? root = null, bool secure = false) { KeyValueStore = keyValueStore; @@ -448,9 +447,8 @@ private byte[] ToKey(byte[] key) { if (_secure) { -#pragma warning disable CS0612 - key = Hashcash.Hash(key).ToByteArray(); -#pragma warning restore CS0612 + SHA256 hasher = SHA256.Create(); + key = hasher.ComputeHash(key); } var res = new byte[key.Length * 2]; From b82b7446c455a93f28d6ea04ddf996872837a57c Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Fri, 18 Jun 2021 19:50:49 +0900 Subject: [PATCH 06/22] Completely remove the existing HashCash.Answer() overload --- CHANGES.md | 5 +++-- Libplanet.Tests/HashcashTest.cs | 5 ----- Libplanet/Blocks/Block.cs | 6 +++--- Libplanet/Hashcash.cs | 28 ---------------------------- 4 files changed, 6 insertions(+), 38 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d2b9e10627..da3cd8c174 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -162,6 +162,9 @@ To be released. - Added `IStore.IterateTxIdBlockHashIndex(TxId)` method. [[#1294], [#1328]] - `Swarm.StartAsync()` method became to receive `broadcastBlockInterval` (or `millisecondsBroadcastBlockInterval`) parameter. [[#1351]] + - Replaced `Hashcash.Answer(Stamp, long, CancellationToken)` method with + `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` method. + [[#1314], [#1352]] - Removed `Hashcash.Hash()` method. [[#1314], [#1352]] ### Backward-incompatible network protocol changes @@ -195,8 +198,6 @@ To be released. - Added `Currency(IValue)` overloaded constructor. [[#1289]] - Added `Currency.Serialize()` method. [[#1289]] - Added `ByteUtil.TimingSafelyCompare()` method. [[#1314], [#1352]] - - Added `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` - overloaded method. [[#1314], [#1352]] ### Behavioral changes diff --git a/Libplanet.Tests/HashcashTest.cs b/Libplanet.Tests/HashcashTest.cs index c5b85822fa..490c0d23fe 100644 --- a/Libplanet.Tests/HashcashTest.cs +++ b/Libplanet.Tests/HashcashTest.cs @@ -23,11 +23,6 @@ public void AnswerSatisfiesDifficulty(byte[] challenge, long difficulty) digest.ToArray(), SHA256.Create().ComputeHash(Stamp(answer)) ); -#pragma warning disable CS0612 - Nonce answer2 = Hashcash.Answer(Stamp, difficulty); -#pragma warning restore CS0612 - byte[] digest2 = SHA256.Create().ComputeHash(Stamp(answer2)); - Assert.True(Satisfies(digest2, difficulty)); } [Fact] diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index 0cbc172b78..69be0ed7bc 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -401,9 +401,8 @@ public static Block Mine( byte[] stampSuffix = new byte[emptyNonce.Length - offset - nonceLength]; Array.Copy(emptyNonce, offset + nonceLength, stampSuffix, 0, stampSuffix.Length); -#pragma warning disable CS0612 - Nonce nonce = Hashcash.Answer( -#pragma warning restore CS0612 + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + (Nonce nonce, _) = Hashcash.Answer( n => { int nLen = n.ByteArray.Length; @@ -423,6 +422,7 @@ public static Block Mine( Array.Copy(stampSuffix, 0, stamp, pos, stampSuffix.Length); return stamp; }, + hashAlgorithm, difficulty, cancellationToken ); diff --git a/Libplanet/Hashcash.cs b/Libplanet/Hashcash.cs index 2a0a82613a..3f67929f21 100644 --- a/Libplanet/Hashcash.cs +++ b/Libplanet/Hashcash.cs @@ -1,7 +1,6 @@ #nullable enable using System; using System.Collections.Immutable; -using System.Security.Cryptography; using System.Threading; using Libplanet.Blocks; @@ -80,32 +79,5 @@ public static (Nonce Nonce, ImmutableArray Digest) Answer( throw new OperationCanceledException(cancellationToken); } - - /// - /// Finds a that satisfies the given - /// . This process is so-called - /// “mining”. - /// - /// A callback to get a “stamp” - /// which is a array determined from a given - /// value. - /// A number to calculate the target number - /// for which the returned answer should be less than. - /// - /// A cancellation token used to propagate notification that this - /// operation should be canceled. - /// - /// A value which satisfies the given - /// . - /// - [Obsolete] - public static Nonce Answer( - Stamp stamp, - long difficulty, - CancellationToken cancellationToken = default - ) => - Answer(stamp, HashAlgorithmType.Of(), difficulty, cancellationToken).Nonce; } } From 86d14abcc465d48df4fa6a4ae20346b30c04a623 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Mon, 21 Jun 2021 16:24:19 +0900 Subject: [PATCH 07/22] Add hashAlgorithm param to Block.MineBlock() method --- CHANGES.md | 2 ++ Libplanet.Tests/Action/ActionEvaluatorTest.cs | 2 ++ .../Blockchain/BlockChainTest.ValidateNextBlock.cs | 12 ++++++++++++ Libplanet.Tests/Blockchain/BlockChainTest.cs | 2 ++ Libplanet.Tests/Blocks/BlockTest.cs | 4 ++++ Libplanet.Tests/Fixtures/IntegerSet.cs | 3 ++- Libplanet.Tests/TestUtils.cs | 2 ++ Libplanet/Blockchain/BlockChain.cs | 3 +++ Libplanet/Blocks/Block.cs | 4 +++- Libplanet/HashAlgorithmType.cs | 3 ++- 10 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index da3cd8c174..611a6cb31f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -118,6 +118,8 @@ To be released. - The type of `TrieStateStore.PruneStates()` method's `excludeBlockHashes` parameter became `IImmutableSet` (was `ImmutableHashSet>`). + - Added `HashAlgorithmType hashAlgorithm` parameter to `Block.MineBlock()` + method. [[#1314], [#1352]] - Added `IActionContext.TxId` property. [[#1275]] - Added `IStore.PutTxExecution(TxSuccess)` method. [[#1156], [#1289]] - Added `IStore.PutTxExecution(TxFailure)` method. [[#1156], [#1289]] diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 32f87675a0..27e0c0f94b 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using System.Threading.Tasks; using Bencodex.Types; using Libplanet.Action; @@ -207,6 +208,7 @@ public void EvaluateWithCriticalException() actions: new[] { action }); var block = Block.Mine( index: 1, + hashAlgorithm: HashAlgorithmType.Of(), difficulty: 1, previousTotalDifficulty: genesis.TotalDifficulty, miner: _storeFx.Address1, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index fc5294e094..e9e4ef9b5b 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -18,6 +18,7 @@ public void ValidateNextBlock() { Block validNextBlock = Block.Mine( 1, + HashAlgorithmType.Of(), 1024, _fx.GenesisBlock.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -34,6 +35,7 @@ private void ValidateNextBlockProtocolVersion() { Block block1 = Block.Mine( 1, + HashAlgorithmType.Of(), 1024, _fx.GenesisBlock.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -46,6 +48,7 @@ private void ValidateNextBlockProtocolVersion() Block block2 = Block.Mine( 2, + HashAlgorithmType.Of(), 1024, block1.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -60,6 +63,7 @@ private void ValidateNextBlockProtocolVersion() { Block block3 = Block.Mine( 2, + HashAlgorithmType.Of(), 1024, block1.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -80,6 +84,7 @@ private void ValidateNextBlockInvalidIndex() Block prev = _blockChain.Tip; Block blockWithAlreadyUsedIndex = Block.Mine( prev.Index, + HashAlgorithmType.Of(), 1, prev.TotalDifficulty, prev.Miner.Value, @@ -93,6 +98,7 @@ private void ValidateNextBlockInvalidIndex() Block blockWithIndexAfterNonexistentIndex = Block.Mine( prev.Index + 2, + HashAlgorithmType.Of(), 1, prev.TotalDifficulty, prev.Miner.Value, @@ -112,6 +118,7 @@ private void ValidateNextBlockInvalidDifficulty() var invalidDifficultyBlock = Block.Mine( 2, + HashAlgorithmType.Of(), 1, _validNext.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -129,6 +136,7 @@ private void ValidateNextBlockInvalidTotalDifficulty() var invalidTotalDifficultyBlock = Block.Mine( 2, + HashAlgorithmType.Of(), _policy.GetNextBlockDifficulty(_blockChain), _validNext.TotalDifficulty - 1, _fx.GenesisBlock.Miner.Value, @@ -146,6 +154,7 @@ private void ValidateNextBlockInvalidPreviousHash() var invalidPreviousHashBlock = Block.Mine( 2, + HashAlgorithmType.Of(), 1032, _validNext.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -163,6 +172,7 @@ private void ValidateNextBlockInvalidTimestamp() var invalidPreviousTimestamp = Block.Mine( 2, + HashAlgorithmType.Of(), 1032, _validNext.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -196,6 +206,7 @@ private void ValidateNextBlockInvalidStateRootHash() var validNext = Block.Mine( 1, + HashAlgorithmType.Of(), 1024, genesisBlock.TotalDifficulty, genesisBlock.Miner.Value, @@ -207,6 +218,7 @@ private void ValidateNextBlockInvalidStateRootHash() var invalidStateRootHash = Block.Mine( 2, + HashAlgorithmType.Of(), 1032, validNext.TotalDifficulty, genesisBlock.Miner.Value, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 4bb12b15d7..43b5de153c 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using System.Threading.Tasks; using Bencodex.Types; using Libplanet.Action; @@ -65,6 +66,7 @@ public BlockChainTest(ITestOutputHelper output) _emptyTransaction = new List>(); _validNext = Block.Mine( 1, + HashAlgorithmType.Of(), 1024, _fx.GenesisBlock.TotalDifficulty, _fx.GenesisBlock.Miner.Value, diff --git a/Libplanet.Tests/Blocks/BlockTest.cs b/Libplanet.Tests/Blocks/BlockTest.cs index b7feee6e82..e60294c024 100644 --- a/Libplanet.Tests/Blocks/BlockTest.cs +++ b/Libplanet.Tests/Blocks/BlockTest.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Globalization; using System.Linq; +using System.Security.Cryptography; using Bencodex; using Bencodex.Types; using Libplanet.Action; @@ -203,6 +204,7 @@ public void DetectInvalidProtocolVersion() DateTimeOffset now = DateTimeOffset.UtcNow; Block block = Block.Mine( _fx.Next.Index, + HashAlgorithmType.Of(), _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -215,6 +217,7 @@ public void DetectInvalidProtocolVersion() block = Block.Mine( _fx.Next.Index, + HashAlgorithmType.Of(), _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -232,6 +235,7 @@ public void CanDetectInvalidTimestamp() DateTimeOffset now = DateTimeOffset.UtcNow; var block = Block.Mine( _fx.Next.Index, + HashAlgorithmType.Of(), _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, diff --git a/Libplanet.Tests/Fixtures/IntegerSet.cs b/Libplanet.Tests/Fixtures/IntegerSet.cs index 8f4591d549..60696c7a2d 100644 --- a/Libplanet.Tests/Fixtures/IntegerSet.cs +++ b/Libplanet.Tests/Fixtures/IntegerSet.cs @@ -66,7 +66,8 @@ public IntegerSet( Store = new DefaultStore(null); KVStore = new MemoryKeyValueStore(); StateStore = new TrieStateStore(KVStore, KVStore); - Genesis = Block.Mine(0, 0, 0, Miner, null, DateTimeOffset.UtcNow, Txs) + HashAlgorithmType algo = HashAlgorithmType.Of(); + Genesis = Block.Mine(0, algo, 0, 0, Miner, null, DateTimeOffset.UtcNow, Txs) .AttachStateRootHash(StateStore, policy.BlockAction); Chain = new BlockChain( policy, diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 83661e93c8..a8defc9288 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -228,11 +228,13 @@ public static Block MineNext( DateTimeOffset timestamp = previousBlock.Timestamp.Add(blockInterval ?? TimeSpan.FromSeconds(15)); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block; if (nonce == null) { block = Block.Mine( index: index, + hashAlgorithm: hashAlgorithm, difficulty: difficulty, previousTotalDifficulty: previousBlock.TotalDifficulty, miner: miner ?? previousBlock.Miner.Value, diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 4169e5f03a..3c594613f0 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -384,6 +384,7 @@ public static Block MakeGenesisBlock( Block block = Block.Mine( 0, + HashAlgorithmType.Of(), 0, 0, privateKey.ToAddress(), @@ -949,12 +950,14 @@ public async Task> MineBlock( stagedTransactions.Length ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block; try { block = await Task.Run( () => Block.Mine( index: index, + hashAlgorithm: hashAlgorithm, difficulty: difficulty, previousTotalDifficulty: Tip.TotalDifficulty, miner: miner, diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index 69be0ed7bc..bba943d4e0 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -346,6 +346,8 @@ public BlockHeader Header /// Generate a block with given . /// /// Index of the block. + /// The hash algorithm to use for calculating + /// . /// Difficulty to find the /// . /// The total difficulty until the previous @@ -364,6 +366,7 @@ public BlockHeader Header /// A that mined. public static Block Mine( long index, + HashAlgorithmType hashAlgorithm, long difficulty, BigInteger previousTotalDifficulty, Address miner, @@ -401,7 +404,6 @@ public static Block Mine( byte[] stampSuffix = new byte[emptyNonce.Length - offset - nonceLength]; Array.Copy(emptyNonce, offset + nonceLength, stampSuffix, 0, stampSuffix.Length); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); (Nonce nonce, _) = Hashcash.Answer( n => { diff --git a/Libplanet/HashAlgorithmType.cs b/Libplanet/HashAlgorithmType.cs index cfe6dae091..c2749d0bb0 100644 --- a/Libplanet/HashAlgorithmType.cs +++ b/Libplanet/HashAlgorithmType.cs @@ -71,7 +71,8 @@ private HashAlgorithmType(Type type) /// Creates a which refers to . /// /// An optional object to make the compiler infers the - /// type parameter from this. + /// type parameter from this. Note that the value in itself is + /// never used at runtime. /// A subclass of . /// A which refers to . /// From 1caa503b5d72b6cffce8918ea58de37698400a88 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Tue, 22 Jun 2021 22:02:32 +0900 Subject: [PATCH 08/22] ByteUtil.Satisfies() method --- CHANGES.md | 1 + Libplanet.Tests/ByteUtilTest.cs | 40 +++++++++++++++++++++++++++++++ Libplanet.Tests/HashcashTest.cs | 3 +-- Libplanet/Blocks/BlockHash.cs | 11 +-------- Libplanet/Blocks/BlockHeader.cs | 2 +- Libplanet/ByteUtil.cs | 42 +++++++++++++++++++++++++++++++++ Libplanet/Hashcash.cs | 8 +++---- 7 files changed, 89 insertions(+), 18 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 611a6cb31f..2c85eca869 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -200,6 +200,7 @@ To be released. - Added `Currency(IValue)` overloaded constructor. [[#1289]] - Added `Currency.Serialize()` method. [[#1289]] - Added `ByteUtil.TimingSafelyCompare()` method. [[#1314], [#1352]] + - Added `ByteUtil.Satisfies()` method. [[#1314], [#1352]] ### Behavioral changes diff --git a/Libplanet.Tests/ByteUtilTest.cs b/Libplanet.Tests/ByteUtilTest.cs index 5d00feca57..60e93072e2 100644 --- a/Libplanet.Tests/ByteUtilTest.cs +++ b/Libplanet.Tests/ByteUtilTest.cs @@ -77,5 +77,45 @@ public void TimingSafelyCompare() ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3 }) ); } + + [Fact] + public void Satisfies() + { + Func hash = ByteUtil.ParseHex; + var emp = new byte[0]; + var dl1 = hash("8ec2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8f00"); + var dl2 = hash("e94a399c4fd6d508f022bbee8781a9c44754408bb92ca5b509fa824b00000000"); + var dl4 = hash("a85f4662e531e44d161346dcaa256af7923c87291b5408b109fa820000000000"); + + Assert.True(ByteUtil.Satisfies(emp, 0)); + Assert.True(ByteUtil.Satisfies(dl1, 0)); + Assert.True(ByteUtil.Satisfies(dl2, 0)); + Assert.True(ByteUtil.Satisfies(dl4, 0)); + + Assert.False(ByteUtil.Satisfies(emp, 1)); + Assert.True(ByteUtil.Satisfies(dl1, 1)); + Assert.True(ByteUtil.Satisfies(dl2, 1)); + Assert.True(ByteUtil.Satisfies(dl4, 1)); + + Assert.False(ByteUtil.Satisfies(emp, 457)); + Assert.True(ByteUtil.Satisfies(dl1, 457)); + Assert.True(ByteUtil.Satisfies(dl2, 457)); + Assert.True(ByteUtil.Satisfies(dl4, 457)); + + Assert.False(ByteUtil.Satisfies(emp, 458)); + Assert.False(ByteUtil.Satisfies(dl1, 458)); + Assert.True(ByteUtil.Satisfies(dl2, 458)); + Assert.True(ByteUtil.Satisfies(dl4, 458)); + + Assert.False(ByteUtil.Satisfies(emp, 14560825400)); + Assert.False(ByteUtil.Satisfies(dl1, 14560825400)); + Assert.True(ByteUtil.Satisfies(dl2, 14560825400)); + Assert.True(ByteUtil.Satisfies(dl4, 14560825400)); + + Assert.False(ByteUtil.Satisfies(emp, 14560825401)); + Assert.False(ByteUtil.Satisfies(dl1, 14560825401)); + Assert.False(ByteUtil.Satisfies(dl2, 14560825401)); + Assert.True(ByteUtil.Satisfies(dl4, 14560825401)); + } } } diff --git a/Libplanet.Tests/HashcashTest.cs b/Libplanet.Tests/HashcashTest.cs index 490c0d23fe..9d2092cf37 100644 --- a/Libplanet.Tests/HashcashTest.cs +++ b/Libplanet.Tests/HashcashTest.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Linq; using System.Security.Cryptography; -using Libplanet.Blocks; using Xunit; namespace Libplanet.Tests @@ -60,7 +59,7 @@ private bool Satisfies(byte[] bytes, long difficulty) digest = bytes; } - return new BlockHash(digest).Satisfies(difficulty); + return ByteUtil.Satisfies(digest, difficulty); } } diff --git a/Libplanet/Blocks/BlockHash.cs b/Libplanet/Blocks/BlockHash.cs index e2b64c6fb3..fb79bc3fe9 100644 --- a/Libplanet/Blocks/BlockHash.cs +++ b/Libplanet/Blocks/BlockHash.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Immutable; using System.Diagnostics.Contracts; -using System.Numerics; using System.Runtime.Serialization; using System.Security.Cryptography; using Libplanet.Serialization; @@ -109,15 +108,7 @@ public bool Satisfies(long difficulty) return false; } - var maxTargetBytes = new byte[_byteArray.Length + 1]; - maxTargetBytes[_byteArray.Length] = 0x01; - var maxTarget = new BigInteger(maxTargetBytes); - BigInteger target = maxTarget / difficulty; - - // Add zero to convert unsigned BigInteger - var result = new BigInteger(_byteArray.Add(0).ToBuilder().ToArray()); - - return result < target; + return ByteUtil.Satisfies(this._byteArray, difficulty); } /// diff --git a/Libplanet/Blocks/BlockHeader.cs b/Libplanet/Blocks/BlockHeader.cs index 49dffaa40a..de90c402df 100644 --- a/Libplanet/Blocks/BlockHeader.cs +++ b/Libplanet/Blocks/BlockHeader.cs @@ -395,7 +395,7 @@ internal void Validate(DateTimeOffset currentTime) } } - if (!new BlockHash(PreEvaluationHash.ToArray()).Satisfies(Difficulty)) + if (!ByteUtil.Satisfies(PreEvaluationHash, Difficulty)) { throw new InvalidBlockNonceException( $"Block #{Index} {hash}'s pre-evaluation hash " + diff --git a/Libplanet/ByteUtil.cs b/Libplanet/ByteUtil.cs index 5f7f7d516f..a43eb424d8 100644 --- a/Libplanet/ByteUtil.cs +++ b/Libplanet/ByteUtil.cs @@ -5,6 +5,7 @@ using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; +using System.Numerics; namespace Libplanet { @@ -139,5 +140,46 @@ public static bool TimingSafelyCompare(IReadOnlyList left, IReadOnlyList + /// Tests if a hash digest is less than the target computed for the given + /// ). + /// + /// A hash digest to test. + /// The difficulty to compute target number. + /// true only if a digest is less than the target computed for the given + /// ). If is 0 it always + /// returns true. + [Pure] + public static bool Satisfies(IReadOnlyList hashDigest, long difficulty) + { + if (difficulty == 0) + { + return true; + } + else if (!hashDigest.Any()) + { + return false; + } + + var maxTargetBytes = new byte[hashDigest.Count + 1]; + maxTargetBytes[hashDigest.Count] = 0x01; + var maxTarget = new BigInteger(maxTargetBytes); + BigInteger target = maxTarget / difficulty; + + var digestArray = new byte[hashDigest.Count + 1]; + int i = 0; + foreach (byte b in hashDigest) + { + digestArray[i++] = b; + } + + // Append zero to convert unsigned BigInteger. Note that BigInteger(byte[]) assumes + // the input bytes are in little-endian order. + digestArray[i] = 0; + + var result = new BigInteger(digestArray); + return result < target; + } } } diff --git a/Libplanet/Hashcash.cs b/Libplanet/Hashcash.cs index 3f67929f21..d00a2ae981 100644 --- a/Libplanet/Hashcash.cs +++ b/Libplanet/Hashcash.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Immutable; using System.Threading; -using Libplanet.Blocks; namespace Libplanet { @@ -69,11 +68,10 @@ public static (Nonce Nonce, ImmutableArray Digest) Answer( random.NextBytes(nonceBytes); var nonce = new Nonce(nonceBytes); - // FIXME: .Satisfies() method should be moved to other class. - var digest = new BlockHash(hashAlgorithmType.Digest(stamp(nonce))); - if (digest.Satisfies(difficulty)) + var digest = hashAlgorithmType.Digest(stamp(nonce)); + if (ByteUtil.Satisfies(digest, difficulty)) { - return (nonce, digest.ByteArray); + return (nonce, ImmutableArray.Create(digest)); } } From 796eae0d9eb426f9d4046fc05a9e0d24aeab9d91 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Tue, 22 Jun 2021 22:54:01 +0900 Subject: [PATCH 09/22] Remove BlockHash.Satisfies() method --- CHANGES.md | 4 +-- Libplanet.Tests/Blocks/BlockHashTest.cs | 47 ------------------------- Libplanet/Blocks/BlockHash.cs | 23 ------------ 3 files changed, 2 insertions(+), 72 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2c85eca869..1540688d15 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,8 +11,6 @@ To be released. - Block hashes are now represented as `BlockHash`, which was introduced in this release, which has been done as `HashDigest`. [[#1192], [#1197]] - - Removed `HashDigest.Satisfies()` method. This was replaced by - `BlockHash.Satisfies()` method instead. - The type of `Block.Hash` property became `BlockHash` (was `HashDigest`). - The type of `Block.PreviousHash` property became `BlockHash?` @@ -168,6 +166,8 @@ To be released. `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` method. [[#1314], [#1352]] - Removed `Hashcash.Hash()` method. [[#1314], [#1352]] + - Removed `HashDigest.Satisfies()` method. This was replaced by + `ByteUtil.Satisfies()` method instead. [[#1192], [#1197], [#1314], [#1352]] ### Backward-incompatible network protocol changes diff --git a/Libplanet.Tests/Blocks/BlockHashTest.cs b/Libplanet.Tests/Blocks/BlockHashTest.cs index 411c36a47b..ee28517641 100644 --- a/Libplanet.Tests/Blocks/BlockHashTest.cs +++ b/Libplanet.Tests/Blocks/BlockHashTest.cs @@ -93,53 +93,6 @@ public void Length() Assert.Equal(20, new BlockHash(b20).BytesLength); } - [Fact] - public void Satisfies() - { - Func hash = BlockHash.FromString; - var def = default(BlockHash); - var emp = new BlockHash(new byte[0]); - var dl1 = hash("8ec2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8f00"); - var dl2 = hash("e94a399c4fd6d508f022bbee8781a9c44754408bb92ca5b509fa824b00000000"); - var dl4 = hash("a85f4662e531e44d161346dcaa256af7923c87291b5408b109fa820000000000"); - - Assert.True(def.Satisfies(0)); - Assert.True(emp.Satisfies(0)); - Assert.True(dl1.Satisfies(0)); - Assert.True(dl2.Satisfies(0)); - Assert.True(dl4.Satisfies(0)); - - Assert.False(def.Satisfies(1)); - Assert.False(emp.Satisfies(1)); - Assert.True(dl1.Satisfies(1)); - Assert.True(dl2.Satisfies(1)); - Assert.True(dl4.Satisfies(1)); - - Assert.False(def.Satisfies(457)); - Assert.False(emp.Satisfies(457)); - Assert.True(dl1.Satisfies(457)); - Assert.True(dl2.Satisfies(457)); - Assert.True(dl4.Satisfies(457)); - - Assert.False(def.Satisfies(458)); - Assert.False(emp.Satisfies(458)); - Assert.False(dl1.Satisfies(458)); - Assert.True(dl2.Satisfies(458)); - Assert.True(dl4.Satisfies(458)); - - Assert.False(def.Satisfies(14560825400)); - Assert.False(emp.Satisfies(14560825400)); - Assert.False(dl1.Satisfies(14560825400)); - Assert.True(dl2.Satisfies(14560825400)); - Assert.True(dl4.Satisfies(14560825400)); - - Assert.False(def.Satisfies(14560825401)); - Assert.False(emp.Satisfies(14560825401)); - Assert.False(dl1.Satisfies(14560825401)); - Assert.False(dl2.Satisfies(14560825401)); - Assert.True(dl4.Satisfies(14560825401)); - } - [Fact] public void SerializeAndDeserialize() { diff --git a/Libplanet/Blocks/BlockHash.cs b/Libplanet/Blocks/BlockHash.cs index fb79bc3fe9..9dbc3ca70d 100644 --- a/Libplanet/Blocks/BlockHash.cs +++ b/Libplanet/Blocks/BlockHash.cs @@ -88,29 +88,6 @@ public static BlockHash FromHashDigest(HashDigest hashDigest) where T : HashAlgorithm => new BlockHash(hashDigest.ByteArray); - /// - /// Tests if a block hash is less than the target computed for the given - /// ). - /// - /// The difficulty to compute target number. - /// true only if a digest is less than the target computed for the given - /// ). If is 0 it always - /// returns true. - [Pure] - public bool Satisfies(long difficulty) - { - if (difficulty == 0) - { - return true; - } - else if (_byteArray.IsDefaultOrEmpty) - { - return false; - } - - return ByteUtil.Satisfies(this._byteArray, difficulty); - } - /// /// Gets a bare mutable array of the block hash. /// From 06fead150d66f2c1c986dcc3dd81d882d403aa02 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Wed, 23 Jun 2021 00:34:14 +0900 Subject: [PATCH 10/22] Change PreEvaluationHash's type to ImmutableArray --- CHANGES.md | 29 ++++++++++++------- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 6 ++-- ...expectedlyTerminatedActionExceptionTest.cs | 9 +++--- Libplanet.Tests/Blocks/BlockHeaderTest.cs | 6 ++-- ...alidBlockPreEvaluationHashExceptionTest.cs | 5 ++-- Libplanet/Action/ActionEvaluator.cs | 4 +-- .../UnexpectedlyTerminatedActionException.cs | 25 ++++++++-------- Libplanet/Blocks/Block.cs | 25 ++++++++-------- .../InvalidBlockPreEvaluationHashException.cs | 20 ++++++++----- Libplanet/Store/BaseStore.cs | 6 ++-- 10 files changed, 75 insertions(+), 60 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1540688d15..1a450e74f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,14 +15,10 @@ To be released. (was `HashDigest`). - The type of `Block.PreviousHash` property became `BlockHash?` (was `HashDigest?`). - - The type of `Block.PreEvaluationHash` property became `BlockHash?` - (was `HashDigest?`). - The types of `Block()` constructors' `hash` parameter became `BlockHash` (were `HashDigest`). - The types of `Block()` constructors' `previousHash` parameter became `BlockHash?` (were `HashDigest?`). - - The types of `Block()` constructors' `preEvaluationHash` parameter - became `BlockHash?` (were `HashDigest?`). - The type of `Block.Mine()` method's `previousHash` parameter became `BlockHash?` (was `HashDigest?`). - The return type of `HashCash.Hash()` method became `BlockHash` @@ -60,12 +56,6 @@ To be released. `BlockHash` (was `HashDigest`). - The type of `BlockVerificationState.VerifiedBlockHash` property became `BlockHash` (was `HashDigest`). - - The type of `ActionEvaluation.EvaluateActionsGradually()` method's - `blockHash` parameter became `BlockHash` (was `HashDigest`). - - The type of `UnexpectedlyTerminatedActionException()` constructor's - `blockHash` parameter became `BlockHash?` (was `HashDigest?`). - - The type of `UnexpectedlyTerminatedActionException.BlockHash` property - became `BlockHash?` (was `HashDigest?`). - The type of `IncompleteBlockStatesException()` constructor's `blockHash` parameter became `BlockHash` (was `HashDigest`). - The type of `IncompleteBlockStatesException.BlockHash` property @@ -162,6 +152,25 @@ To be released. - Added `IStore.IterateTxIdBlockHashIndex(TxId)` method. [[#1294], [#1328]] - `Swarm.StartAsync()` method became to receive `broadcastBlockInterval` (or `millisecondsBroadcastBlockInterval`) parameter. [[#1351]] + - The type of `Block.PreEvaluationHash` property became + `ImmutableArray?` (was `HashDigest?`). + [[#1192], [#1197], [#1314], [#1352]] + - The types of `Block()` constructors' `preEvaluationHash` parameter + became `ImmutableArray?` (were `HashDigest?`). + [[#1192], [#1197], [#1314], [#1352]] + - The type of `InvalidBlockPreEvaluationHashException.ActualPreEvaluationHash` + and `ExpectedPreEvaluationHash` properties became `ImmutableArray` + (were `HashDigest`). [[#1192], [#1197], [#1314], [#1352]] + - The type of `InvalidBlockPreEvaluationHashException()` constructor's + `actualPreEvaluationHash` and and `expectedPreEvaluationHash` parameters + became `ImmutableArray` (were `HashDigest`). + [[#1192], [#1197], [#1314], [#1352]] + - Replaced `UnexpectedlyTerminatedActionException()` constructor's + `HashDigest? blockHash` parameter with + `ImmutableArray? preEvaluationHash`. + [[#1192], [#1197], [#1314], [#1352]] + - Replaced `UnexpectedlyTerminatedActionException.BlockHash` property with + `PreEvaluationHash.` [[#1192], [#1197], [#1314], [#1352]] - Replaced `Hashcash.Answer(Stamp, long, CancellationToken)` method with `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` method. [[#1314], [#1352]] diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 27e0c0f94b..d38aeff366 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -83,7 +83,7 @@ public void Idempotent() var generatedRandomNumbers = new List(); Assert.NotEqual(stateRootBlock.Hash, noStateRootBlock.Hash); - Assert.Equal(stateRootBlock.PreEvaluationHash, noStateRootBlock.PreEvaluationHash); + AssertBytesEqual(stateRootBlock.PreEvaluationHash, noStateRootBlock.PreEvaluationHash); for (int i = 0; i < repeatCount; ++i) { @@ -799,7 +799,7 @@ public async Task EvaluateActions(bool rehearsal) Block blockA = await fx.Mine(); ActionEvaluation[] evalsA = ActionEvaluator.EvaluateActions( - blockA.Hash, + blockA.PreEvaluationHash, blockIndex: blockA.Index, txid: txA.Id, previousStates: fx.CreateAccountStateDelta(0, blockA.PreviousHash), @@ -848,7 +848,7 @@ public async Task EvaluateActions(bool rehearsal) Block blockB = await fx.Mine(); ActionEvaluation[] evalsB = ActionEvaluator.EvaluateActions( - blockB.Hash, + blockB.PreEvaluationHash, blockIndex: blockB.Index, txid: txB.Id, previousStates: fx.CreateAccountStateDelta(0, blockB.PreviousHash), diff --git a/Libplanet.Tests/Action/UnexpectedlyTerminatedActionExceptionTest.cs b/Libplanet.Tests/Action/UnexpectedlyTerminatedActionExceptionTest.cs index 656d5f1083..6375217a87 100644 --- a/Libplanet.Tests/Action/UnexpectedlyTerminatedActionExceptionTest.cs +++ b/Libplanet.Tests/Action/UnexpectedlyTerminatedActionExceptionTest.cs @@ -1,9 +1,9 @@ using System; +using System.Collections.Immutable; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using Libplanet.Action; -using Libplanet.Blocks; using Libplanet.Tests.Common.Action; using Libplanet.Tx; using Xunit; @@ -16,7 +16,8 @@ public class UnexpectedlyTerminatedActionExceptionTest public void Serializable() { var innerExc = new Exception("inner"); - var blockHash = new BlockHash(TestUtils.GetRandomBytes(32)); + ImmutableArray preEvaluationHash = + TestUtils.GetRandomBytes(32).ToImmutableArray(); long blockIndex = 100; var txId = new TxId(TestUtils.GetRandomBytes(TxId.Size)); var previousStateRootHash = new HashDigest( @@ -28,7 +29,7 @@ public void Serializable() }; var exc = new UnexpectedlyTerminatedActionException( - blockHash, + preEvaluationHash, blockIndex, txId, previousStateRootHash, @@ -48,7 +49,7 @@ public void Serializable() Assert.IsType(deserialized.InnerException); Assert.Equal(innerExc.Message, deserialized.InnerException.Message); - Assert.Equal(blockHash, deserialized.BlockHash); + Assert.Equal(preEvaluationHash, deserialized.PreEvaluationHash); Assert.Equal(blockIndex, deserialized.BlockIndex); Assert.Equal(txId, deserialized.TxId); Assert.Equal(previousStateRootHash, deserialized.PreviousStateRootHash); diff --git a/Libplanet.Tests/Blocks/BlockHeaderTest.cs b/Libplanet.Tests/Blocks/BlockHeaderTest.cs index 1d173540d6..821f1ca194 100644 --- a/Libplanet.Tests/Blocks/BlockHeaderTest.cs +++ b/Libplanet.Tests/Blocks/BlockHeaderTest.cs @@ -34,7 +34,7 @@ public void ToBencodex() BlockHeader.TimestampFormat, CultureInfo.InvariantCulture ), - preEvaluationHash: _fx.Genesis.PreEvaluationHash.ByteArray, + preEvaluationHash: _fx.Genesis.PreEvaluationHash, stateRootHash: _fx.Genesis.StateRootHash?.ByteArray ?? ImmutableArray.Empty ); Bencodex.Types.Dictionary expected = Bencodex.Types.Dictionary.Empty @@ -54,7 +54,7 @@ public void ToBencodex() .Add(BlockHeader.NonceKey, _fx.Genesis.Nonce.ToByteArray()) .Add(BlockHeader.HashKey, _fx.Genesis.Hash.ToByteArray()) .Add(BlockHeader.MinerKey, _fx.Genesis.Miner?.ToByteArray() ?? new byte[0]) - .Add(BlockHeader.PreEvaluationHashKey, _fx.Genesis.PreEvaluationHash.ToByteArray()); + .Add(BlockHeader.PreEvaluationHashKey, _fx.Genesis.PreEvaluationHash.ToArray()); Assert.Equal(expected, header.ToBencodex()); Assert.Equal(expected, new BlockHeader(expected).ToBencodex()); @@ -125,7 +125,7 @@ public void ValidateHash() BlockHeader.TimestampFormat, CultureInfo.InvariantCulture ), - preEvaluationHash: _fx.Genesis.PreEvaluationHash.ByteArray, + preEvaluationHash: _fx.Genesis.PreEvaluationHash, stateRootHash: _fx.Genesis.StateRootHash?.ByteArray ?? ImmutableArray.Empty ); diff --git a/Libplanet.Tests/Blocks/InvalidBlockPreEvaluationHashExceptionTest.cs b/Libplanet.Tests/Blocks/InvalidBlockPreEvaluationHashExceptionTest.cs index b27467686c..4c588c9cf6 100644 --- a/Libplanet.Tests/Blocks/InvalidBlockPreEvaluationHashExceptionTest.cs +++ b/Libplanet.Tests/Blocks/InvalidBlockPreEvaluationHashExceptionTest.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using Libplanet.Blocks; @@ -10,8 +11,8 @@ public class InvalidBlockPreEvaluationHashExceptionTest [Fact] public void Serialize() { - var actual = new BlockHash(TestUtils.GetRandomBytes(32)); - var expected = new BlockHash(TestUtils.GetRandomBytes(32)); + var actual = TestUtils.GetRandomBytes(32).ToImmutableArray(); + var expected = TestUtils.GetRandomBytes(32).ToImmutableArray(); var exc = new InvalidBlockPreEvaluationHashException( actual, expected, diff --git a/Libplanet/Action/ActionEvaluator.cs b/Libplanet/Action/ActionEvaluator.cs index cac2c282cf..60f6e650c4 100644 --- a/Libplanet/Action/ActionEvaluator.cs +++ b/Libplanet/Action/ActionEvaluator.cs @@ -212,7 +212,7 @@ internal static IImmutableSet
GetUpdatedAddresses(Transaction tx) /// [Pure] internal static IEnumerable EvaluateActions( - BlockHash preEvaluationHash, + ImmutableArray preEvaluationHash, long blockIndex, TxId? txid, IAccountStateDelta previousStates, @@ -244,7 +244,7 @@ ActionContext CreateActionContext(IAccountStateDelta prevStates, int randomSeed) hashedSignature = hasher.ComputeHash(signature); } - byte[] preEvaluationHashBytes = preEvaluationHash.ToByteArray(); + byte[] preEvaluationHashBytes = preEvaluationHash.ToBuilder().ToArray(); int seed = (preEvaluationHashBytes.Length > 0 ? BitConverter.ToInt32(preEvaluationHashBytes, 0) : 0) diff --git a/Libplanet/Action/UnexpectedlyTerminatedActionException.cs b/Libplanet/Action/UnexpectedlyTerminatedActionException.cs index f709383b0f..fe6c723a31 100644 --- a/Libplanet/Action/UnexpectedlyTerminatedActionException.cs +++ b/Libplanet/Action/UnexpectedlyTerminatedActionException.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Collections.Immutable; using System.Runtime.Serialization; using System.Security.Cryptography; using Bencodex; @@ -24,9 +25,9 @@ public sealed class UnexpectedlyTerminatedActionException : Exception /// /// Creates a new object. /// - /// The of the - /// that belongs to. This can be null on rehearsal mode. - /// + /// The of the + /// that belongs to. + /// This can be null on rehearsal mode. /// The of the /// that belongs to. This can be null on rehearsal mode. /// @@ -43,7 +44,7 @@ public sealed class UnexpectedlyTerminatedActionException : Exception /// The actual exception that the threw. /// public UnexpectedlyTerminatedActionException( - BlockHash? blockHash, + ImmutableArray? preEvaluationHash, long? blockIndex, TxId? txid, HashDigest? previousStateRootHash, @@ -53,7 +54,7 @@ Exception innerException ) : base(message, innerException) { - BlockHash = blockHash; + PreEvaluationHash = preEvaluationHash; BlockIndex = blockIndex; TxId = txid; PreviousStateRootHash = previousStateRootHash; @@ -66,9 +67,9 @@ StreamingContext context ) : base(info, context) { - if (info.TryGetValue(nameof(BlockHash), out byte[] blockHash)) + if (info.TryGetValue(nameof(PreEvaluationHash), out byte[] blockHash)) { - BlockHash = new BlockHash(blockHash); + PreEvaluationHash = blockHash.ToImmutableArray(); } if (info.TryGetValue(nameof(BlockIndex), out long blockIndex)) @@ -123,10 +124,10 @@ StreamingContext context } /// - /// The of the that - /// belongs to. This can be null on rehearsal mode. + /// The of the that + /// belongs to. This can be null on rehearsal mode. /// - public BlockHash? BlockHash { get; } + public ImmutableArray? PreEvaluationHash { get; } /// /// The of the that @@ -152,9 +153,9 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont { base.GetObjectData(info, context); - if (BlockHash is { } blockHash) + if (PreEvaluationHash is { } preEvaluationHash) { - info.AddValue(nameof(BlockHash), blockHash.ToByteArray()); + info.AddValue(nameof(PreEvaluationHash), preEvaluationHash.ToBuilder().ToArray()); } if (BlockIndex is long blockIndex) diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index bba943d4e0..7f1667f583 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -67,7 +67,7 @@ public Block( BlockHash? previousHash, DateTimeOffset timestamp, IReadOnlyList> transactions, - BlockHash? preEvaluationHash = null, + ImmutableArray? preEvaluationHash = null, HashDigest? stateRootHash = null, int protocolVersion = CurrentProtocolVersion) { @@ -84,7 +84,7 @@ public Block( HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); PreEvaluationHash = preEvaluationHash ?? - new BlockHash(hashAlgorithm.Digest(Header.SerializeForHash())); + hashAlgorithm.Digest(Header.SerializeForHash()).ToImmutableArray(); StateRootHash = stateRootHash; // FIXME: This does not need to be computed every time? @@ -92,7 +92,7 @@ public Block( // As the order of transactions should be unpredictable until a block is mined, // the sorter key should be derived from both a block hash and a txid. - var hashInteger = new BigInteger(PreEvaluationHash.ToByteArray()); + var hashInteger = new BigInteger(PreEvaluationHash.ToBuilder().ToArray()); // If there are multiple transactions for the same signer these should be ordered by // their tx nonces. So transactions of the same signer should have the same sort key. @@ -182,8 +182,8 @@ private Block(RawBlock rb) .Select(tx => Transaction.Deserialize(tx.ToArray(), false)) .ToList(), rb.Header.PreEvaluationHash.Any() - ? new BlockHash(rb.Header.PreEvaluationHash) - : (BlockHash?)null, + ? rb.Header.PreEvaluationHash + : (ImmutableArray?)null, rb.Header.StateRootHash.Any() ? new HashDigest(rb.Header.StateRootHash) : (HashDigest?)null) @@ -203,7 +203,7 @@ private Block( DateTimeOffset timestamp, HashDigest? txHash, IReadOnlyList> transactions, - BlockHash? preEvaluationHash, + ImmutableArray? preEvaluationHash, HashDigest? stateRootHash ) { @@ -248,7 +248,7 @@ private Block( /// /// /// - public BlockHash PreEvaluationHash { get; } + public ImmutableArray PreEvaluationHash { get; } /// /// The of the states on the block. @@ -330,7 +330,7 @@ public BlockHeader Header previousHash: previousHashAsArray, txHash: TxHash?.ToByteArray().ToImmutableArray() ?? ImmutableArray.Empty, hash: Hash.ToByteArray().ToImmutableArray(), - preEvaluationHash: PreEvaluationHash.ToByteArray().ToImmutableArray(), + preEvaluationHash: PreEvaluationHash, stateRootHash: stateRootHashAsArray ); } @@ -522,9 +522,7 @@ internal void Validate(DateTimeOffset currentTime) HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); byte[] expectedPreEvaluationHash = hashAlgorithm.Digest(Header.SerializeForHash(includeStateRootHash: false)); - if (!ByteUtil.TimingSafelyCompare( - expectedPreEvaluationHash, - PreEvaluationHash.ByteArray)) + if (!ByteUtil.TimingSafelyCompare(expectedPreEvaluationHash, PreEvaluationHash)) { string message = $"The expected pre evaluation hash of block {Hash} is " + @@ -532,8 +530,9 @@ internal void Validate(DateTimeOffset currentTime) $"{PreEvaluationHash}."; throw new InvalidBlockPreEvaluationHashException( PreEvaluationHash, - new BlockHash(expectedPreEvaluationHash), - message); + expectedPreEvaluationHash.ToImmutableArray(), + message + ); } } diff --git a/Libplanet/Blocks/InvalidBlockPreEvaluationHashException.cs b/Libplanet/Blocks/InvalidBlockPreEvaluationHashException.cs index 4b3584475b..af83aa5fb1 100644 --- a/Libplanet/Blocks/InvalidBlockPreEvaluationHashException.cs +++ b/Libplanet/Blocks/InvalidBlockPreEvaluationHashException.cs @@ -1,6 +1,8 @@ #nullable enable using System; +using System.Collections.Immutable; using System.Diagnostics.Contracts; +using System.Linq; using System.Runtime.Serialization; using Libplanet.Serialization; @@ -24,8 +26,8 @@ public class InvalidBlockPreEvaluationHashException : InvalidBlockException /// . /// The message that describes the error. public InvalidBlockPreEvaluationHashException( - BlockHash actualPreEvaluationHash, - BlockHash expectedPreEvaluationHash, + ImmutableArray actualPreEvaluationHash, + ImmutableArray expectedPreEvaluationHash, string message) : base(message) { @@ -37,21 +39,23 @@ private InvalidBlockPreEvaluationHashException( SerializationInfo info, StreamingContext context) : base(info, context) { - ActualPreEvaluationHash = info.GetValue(nameof(ActualPreEvaluationHash)); - ExpectedPreEvaluationHash = info.GetValue(nameof(ExpectedPreEvaluationHash)); + ActualPreEvaluationHash = + info.GetValue(nameof(ActualPreEvaluationHash)).ToImmutableArray(); + ExpectedPreEvaluationHash = + info.GetValue(nameof(ExpectedPreEvaluationHash)).ToImmutableArray(); } /// /// The hash calculated from the block except . /// [Pure] - public BlockHash ActualPreEvaluationHash { get; } + public ImmutableArray ActualPreEvaluationHash { get; } /// /// The hash recorded as . /// [Pure] - public BlockHash ExpectedPreEvaluationHash { get; } + public ImmutableArray ExpectedPreEvaluationHash { get; } public static bool operator ==( InvalidBlockPreEvaluationHashException left, @@ -67,8 +71,8 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont { base.GetObjectData(info, context); - info.AddValue(nameof(ActualPreEvaluationHash), ActualPreEvaluationHash); - info.AddValue(nameof(ExpectedPreEvaluationHash), ExpectedPreEvaluationHash); + info.AddValue(nameof(ActualPreEvaluationHash), ActualPreEvaluationHash.ToArray()); + info.AddValue(nameof(ExpectedPreEvaluationHash), ExpectedPreEvaluationHash.ToArray()); } } } diff --git a/Libplanet/Store/BaseStore.cs b/Libplanet/Store/BaseStore.cs index b815830c45..4a029eddd0 100644 --- a/Libplanet/Store/BaseStore.cs +++ b/Libplanet/Store/BaseStore.cs @@ -79,9 +79,9 @@ public Block GetBlock(BlockHash blockHash) BlockHash? prevHash = blockDigest.Header.PreviousHash.Any() ? new BlockHash(blockDigest.Header.PreviousHash) : (BlockHash?)null; - BlockHash? preEvaluationHash = blockDigest.Header.PreEvaluationHash.Any() - ? new BlockHash(blockDigest.Header.PreEvaluationHash) - : (BlockHash?)null; + ImmutableArray? preEvaluationHash = blockDigest.Header.PreEvaluationHash.Any() + ? blockDigest.Header.PreEvaluationHash + : (ImmutableArray?)null; HashDigest? stateRootHash = blockDigest.Header.StateRootHash.Any() ? new HashDigest(blockDigest.Header.StateRootHash) : (HashDigest?)null; From 6b71a6cc77e6429873268ca546ae53cf0feb8f77 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Wed, 23 Jun 2021 01:33:46 +0900 Subject: [PATCH 11/22] Make BlockHash type fixed-size --- Libplanet.Tests/Blocks/BlockHashTest.cs | 76 +++++++++++++------------ Libplanet/Blocks/BlockHash.cs | 48 ++++++++++------ 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/Libplanet.Tests/Blocks/BlockHashTest.cs b/Libplanet.Tests/Blocks/BlockHashTest.cs index ee28517641..7906250680 100644 --- a/Libplanet.Tests/Blocks/BlockHashTest.cs +++ b/Libplanet.Tests/Blocks/BlockHashTest.cs @@ -14,10 +14,8 @@ public class BlockHashTest public void DefaultConstructor() { BlockHash def = default; - Assert.Equal(default, def); - Assert.Equal(new BlockHash(new byte[0]), def); - Assert.Equal(new BlockHash(default(ImmutableArray)), def); - Assert.Equal(new BlockHash(ImmutableArray.Empty), def); + TestUtils.AssertBytesEqual(new byte[32].ToImmutableArray(), def.ByteArray); + TestUtils.AssertBytesEqual(new byte[32], def.ToByteArray()); } [Fact] @@ -26,20 +24,44 @@ public void DisallowNull() Assert.Throws(() => new BlockHash(null)); } + [Fact] + public void LengthCheck() + { + Assert.Throws(() => new BlockHash(new byte[0])); + Assert.Throws(() => new BlockHash(new byte[1])); + Assert.Throws(() => new BlockHash(new byte[31])); + Assert.Throws(() => new BlockHash(new byte[33])); + } + [Fact] public void FromString() { byte[] b = { - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - 0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc, + 0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde, + 0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d, + 0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc, }; var expected = new BlockHash(b); - BlockHash actual = BlockHash.FromString("45a22187e2d8850bb357886958bc3e8560929ccc"); + BlockHash actual = BlockHash.FromString( + "2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cbfc" + ); Assert.Equal(expected, actual); Assert.Throws(() => BlockHash.FromString(null)); + Assert.Throws(() => BlockHash.FromString(string.Empty)); Assert.Throws(() => BlockHash.FromString("abc")); + Assert.Throws(() => BlockHash.FromString("ab")); + Assert.Throws(() => + BlockHash.FromString( + "2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cb" + ) + ); + Assert.Throws(() => + BlockHash.FromString( + "2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cbfc00" + ) + ); Assert.Throws(() => BlockHash.FromString("asdf")); } @@ -48,16 +70,17 @@ public void FromHashDigest() { byte[] b = { - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - 0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc, + 0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde, + 0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d, + 0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc, }; var expected = new BlockHash(b); - BlockHash actual = BlockHash.FromHashDigest(new HashDigest(b)); + BlockHash actual = BlockHash.FromHashDigest(new HashDigest(b)); Assert.Equal(expected, actual); Assert.Equal( - new BlockHash(new byte[HashDigest.Size]), - BlockHash.FromHashDigest(default(HashDigest)) + new BlockHash(new byte[32]), + BlockHash.FromHashDigest(default) ); } @@ -66,8 +89,9 @@ public void FromImmutableArrayConstructor() { byte[] b = { - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - 0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc, + 0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde, + 0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d, + 0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc, }; var bAsArray = b.ToImmutableArray(); @@ -76,32 +100,14 @@ public void FromImmutableArrayConstructor() Assert.Equal(expected, actual); } - [Fact] - public void Length() - { - byte[] b10 = - { - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - }; - Assert.Equal(10, new BlockHash(b10).BytesLength); - - byte[] b20 = - { - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - 0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc, - }; - Assert.Equal(20, new BlockHash(b20).BytesLength); - } - [Fact] public void SerializeAndDeserialize() { byte[] b = { - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - 0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc, - 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, - 0x88, 0x69, + 0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, 0x88, + 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc, 0x45, 0xa2, + 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57, 0x88, 0x69, }; var expected = new BlockHash(b); diff --git a/Libplanet/Blocks/BlockHash.cs b/Libplanet/Blocks/BlockHash.cs index 9dbc3ca70d..694dce5430 100644 --- a/Libplanet/Blocks/BlockHash.cs +++ b/Libplanet/Blocks/BlockHash.cs @@ -9,21 +9,41 @@ namespace Libplanet.Blocks { /// - /// A value type to represent block hash bytes which is derived data. + /// A value type to represent SHA-256 digest of data. /// /// [Serializable] public readonly struct BlockHash : ISerializable, IEquatable { + /// + /// The size of bytes that each consists of. + /// + public const int Size = 32; + + private static readonly ImmutableArray _defaultByteArray = + new byte[32].ToImmutableArray(); + private readonly ImmutableArray _byteArray; /// /// Converts an immutable array into a . /// /// An immutable array that encodes - /// a . - public BlockHash(ImmutableArray blockHash) => + /// a SHA-256 digest of a . + /// Thrown when the given + /// 's is not 32. + /// + public BlockHash(ImmutableArray blockHash) + { + if (blockHash.Length != Size) + { + string message = + $"{nameof(BlockHash)} must be {Size} bytes, but {blockHash.Length} was given."; + throw new ArgumentOutOfRangeException(nameof(blockHash), message); + } + _byteArray = blockHash; + } /// /// Converts a array into a . @@ -32,6 +52,9 @@ public BlockHash(ImmutableArray blockHash) => /// a . /// Thrown when the given /// is null. + /// Thrown when the given + /// 's is not 32. + /// public BlockHash(byte[] blockHash) : this((blockHash ?? throw new ArgumentNullException(nameof(blockHash))) .ToImmutableArray()) @@ -50,14 +73,7 @@ private BlockHash(SerializationInfo info, StreamingContext context) /// instead. /// public ImmutableArray ByteArray => - _byteArray.IsDefault ? ImmutableArray.Empty : _byteArray; - - /// - /// The length of the block hash in bytes. - /// - [Pure] - public int BytesLength => - _byteArray.IsDefault ? 0 : _byteArray.Length; + _byteArray.IsDefault ? _defaultByteArray : _byteArray; /// /// Converts a given hexadecimal representation of a block hash into @@ -72,20 +88,20 @@ private BlockHash(SerializationInfo info, StreamingContext context) /// string is an odd number. /// Thrown when the given string /// is not a valid hexadecimal string. + /// Thrown when the given + /// 's length is not 64. /// [Pure] public static BlockHash FromString(string hex) => new BlockHash(ByteUtil.ParseHex(hex ?? throw new ArgumentNullException(nameof(hex)))); /// - /// Converts a given value into a value. + /// Converts a given into a value. /// - /// A hash digest. - /// The hash algorithm. + /// A SHA-256 digest. /// A block hash corresponding to the . [Pure] - public static BlockHash FromHashDigest(HashDigest hashDigest) - where T : HashAlgorithm + public static BlockHash FromHashDigest(HashDigest hashDigest) => new BlockHash(hashDigest.ByteArray); /// From 58504bd0ffa28ac80b555273bd9da7737af43ed3 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Wed, 23 Jun 2021 22:32:05 +0900 Subject: [PATCH 12/22] Add hashAlgorithm param to Validate() method --- CHANGES.md | 57 ++++++++++--------- .../Blockchain/BlockChainTest.MineBlock.cs | 17 +++--- Libplanet.Tests/Blocks/BlockFixture.cs | 4 ++ Libplanet.Tests/Blocks/BlockHeaderTest.cs | 33 ++++++----- Libplanet.Tests/Blocks/BlockTest.cs | 37 ++++++------ Libplanet.Tests/TestUtils.cs | 2 +- Libplanet/Action/ActionEvaluator.cs | 4 +- Libplanet/Blocks/Block.cs | 7 ++- Libplanet/Blocks/BlockHeader.cs | 4 +- Libplanet/Net/Swarm.MessageHandlers.cs | 4 +- Libplanet/Net/Swarm.cs | 4 +- Libplanet/Store/BlockSet.cs | 4 +- 12 files changed, 101 insertions(+), 76 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1a450e74f4..8c9049d4bd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -106,8 +106,36 @@ To be released. - The type of `TrieStateStore.PruneStates()` method's `excludeBlockHashes` parameter became `IImmutableSet` (was `ImmutableHashSet>`). - - Added `HashAlgorithmType hashAlgorithm` parameter to `Block.MineBlock()` - method. [[#1314], [#1352]] + - Hash algorithm for PoW (Hashcash) became + configurable. [#1314], [#1352] + - Added `HashAlgorithmType hashAlgorithm` parameter to + `Block.MineBlock()` method. + - The type of `Block.PreEvaluationHash` property became + `ImmutableArray?` (was `HashDigest?`). + [[#1192], [#1197]] + - The types of `Block()` constructors' `preEvaluationHash` parameter + became `ImmutableArray?` (were `HashDigest?`). + [[#1192], [#1197]] + - The type of + `InvalidBlockPreEvaluationHashException.ActualPreEvaluationHash` and + `ExpectedPreEvaluationHash` properties became `ImmutableArray` + (were `HashDigest`). [[#1192], [#1197]] + - The type of `InvalidBlockPreEvaluationHashException()` constructor's + `actualPreEvaluationHash` and and `expectedPreEvaluationHash` parameters + became `ImmutableArray` (were `HashDigest`). + [[#1192], [#1197]] + - Replaced `UnexpectedlyTerminatedActionException()` constructor's + `HashDigest? blockHash` parameter with + `ImmutableArray? preEvaluationHash`. + [[#1192], [#1197]] + - Replaced `UnexpectedlyTerminatedActionException.BlockHash` property with + `PreEvaluationHash.` [[#1192], [#1197]] + - Replaced `Hashcash.Answer(Stamp, long, CancellationToken)` method with + `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` + method. + - Removed `Hashcash.Hash()` method. + - Removed `HashDigest.Satisfies()` method. This was replaced by + `ByteUtil.Satisfies()` method instead. [[#1192], [#1197]] - Added `IActionContext.TxId` property. [[#1275]] - Added `IStore.PutTxExecution(TxSuccess)` method. [[#1156], [#1289]] - Added `IStore.PutTxExecution(TxFailure)` method. [[#1156], [#1289]] @@ -152,31 +180,6 @@ To be released. - Added `IStore.IterateTxIdBlockHashIndex(TxId)` method. [[#1294], [#1328]] - `Swarm.StartAsync()` method became to receive `broadcastBlockInterval` (or `millisecondsBroadcastBlockInterval`) parameter. [[#1351]] - - The type of `Block.PreEvaluationHash` property became - `ImmutableArray?` (was `HashDigest?`). - [[#1192], [#1197], [#1314], [#1352]] - - The types of `Block()` constructors' `preEvaluationHash` parameter - became `ImmutableArray?` (were `HashDigest?`). - [[#1192], [#1197], [#1314], [#1352]] - - The type of `InvalidBlockPreEvaluationHashException.ActualPreEvaluationHash` - and `ExpectedPreEvaluationHash` properties became `ImmutableArray` - (were `HashDigest`). [[#1192], [#1197], [#1314], [#1352]] - - The type of `InvalidBlockPreEvaluationHashException()` constructor's - `actualPreEvaluationHash` and and `expectedPreEvaluationHash` parameters - became `ImmutableArray` (were `HashDigest`). - [[#1192], [#1197], [#1314], [#1352]] - - Replaced `UnexpectedlyTerminatedActionException()` constructor's - `HashDigest? blockHash` parameter with - `ImmutableArray? preEvaluationHash`. - [[#1192], [#1197], [#1314], [#1352]] - - Replaced `UnexpectedlyTerminatedActionException.BlockHash` property with - `PreEvaluationHash.` [[#1192], [#1197], [#1314], [#1352]] - - Replaced `Hashcash.Answer(Stamp, long, CancellationToken)` method with - `Hashcash.Answer(Stamp, HashAlgorithm, long, CancellationToken)` method. - [[#1314], [#1352]] - - Removed `Hashcash.Hash()` method. [[#1314], [#1352]] - - Removed `HashDigest.Satisfies()` method. This was replaced by - `ByteUtil.Satisfies()` method instead. [[#1192], [#1197], [#1314], [#1352]] ### Backward-incompatible network protocol changes diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.MineBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.MineBlock.cs index d979992754..6b8e73d3a8 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.MineBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.MineBlock.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using System.Threading.Tasks; using Bencodex.Types; using Libplanet.Blockchain; @@ -22,11 +23,12 @@ public partial class BlockChainTest public async void MineBlock() { Func getMaxBlockBytes = _blockChain.Policy.GetMaxBlockBytes; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Assert.Equal(1, _blockChain.Count); Assert.Equal((Text)$"{TestUtils.GenesisMinerAddress}", _blockChain.GetState(default)); Block block = await _blockChain.MineBlock(_fx.Address1); - block.Validate(DateTimeOffset.UtcNow); + block.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.True(_blockChain.ContainsBlock(block.Hash)); Assert.Equal(2, _blockChain.Count); Assert.True(block.BytesLength <= getMaxBlockBytes(block.Index)); @@ -36,7 +38,7 @@ public async void MineBlock() ); Block anotherBlock = await _blockChain.MineBlock(_fx.Address2); - anotherBlock.Validate(DateTimeOffset.UtcNow); + anotherBlock.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.True(_blockChain.ContainsBlock(anotherBlock.Hash)); Assert.Equal(3, _blockChain.Count); Assert.True(anotherBlock.BytesLength <= getMaxBlockBytes(anotherBlock.Index)); @@ -46,7 +48,7 @@ public async void MineBlock() ); Block block3 = await _blockChain.MineBlock(_fx.Address3, append: false); - block3.Validate(DateTimeOffset.UtcNow); + block3.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.False(_blockChain.ContainsBlock(block3.Hash)); Assert.Equal(3, _blockChain.Count); Assert.True(block3.BytesLength <= getMaxBlockBytes(block3.Index)); @@ -77,7 +79,7 @@ public async void MineBlock() } Block block4 = await _blockChain.MineBlock(_fx.Address3, append: false); - block4.Validate(DateTimeOffset.UtcNow); + block4.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.False(_blockChain.ContainsBlock(block4.Hash)); _logger.Debug( $"{nameof(block4)}.{nameof(block4.BytesLength)} = {0}", @@ -108,21 +110,22 @@ public async void MineBlockWithTxBatchSize() _blockChain.MakeTransaction(privateKeys[1], new DumbAction[0]); _blockChain.MakeTransaction(privateKeys[2], new DumbAction[0]); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = await _blockChain.MineBlock(_fx.Address1, maxTransactions: 1); - block.Validate(DateTimeOffset.UtcNow); + block.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.Single(block.Transactions); Assert.Equal(5, _blockChain.GetStagedTransactionIds().Count); Block block2 = await _blockChain.MineBlock( _fx.Address2, DateTimeOffset.UtcNow, maxTransactions: 2); - block2.Validate(DateTimeOffset.UtcNow); + block2.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.Equal(2, block2.Transactions.Count()); Assert.Equal(3, _blockChain.GetStagedTransactionIds().Count); Block block3 = await _blockChain.MineBlock( _fx.Address3, append: false, maxTransactions: 4); - block3.Validate(DateTimeOffset.UtcNow); + block3.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Assert.Equal(3, block3.Transactions.Count()); Assert.Equal(3, _blockChain.GetStagedTransactionIds().Count); diff --git a/Libplanet.Tests/Blocks/BlockFixture.cs b/Libplanet.Tests/Blocks/BlockFixture.cs index 3ac2715ed2..a52c91b0f4 100644 --- a/Libplanet.Tests/Blocks/BlockFixture.cs +++ b/Libplanet.Tests/Blocks/BlockFixture.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blocks; using Libplanet.Tests.Common.Action; @@ -14,6 +15,7 @@ public class BlockFixture public BlockFixture() { + HashAlgorithm = HashAlgorithmType.Of(); Genesis = TestUtils.MineGenesis>( protocolVersion: ProtocolVersion ); @@ -38,6 +40,8 @@ public BlockFixture() ); } + internal HashAlgorithmType HashAlgorithm { get; } + internal TxFixture TxFixture { get; } internal Block> Genesis { get; } diff --git a/Libplanet.Tests/Blocks/BlockHeaderTest.cs b/Libplanet.Tests/Blocks/BlockHeaderTest.cs index 821f1ca194..95cd255c19 100644 --- a/Libplanet.Tests/Blocks/BlockHeaderTest.cs +++ b/Libplanet.Tests/Blocks/BlockHeaderTest.cs @@ -104,8 +104,8 @@ public void ToBencodex() [Fact] public void ValidateValidHeader() { - _fx.Genesis.Header.Validate(DateTimeOffset.UtcNow); - _fx.Next.Header.Validate(DateTimeOffset.UtcNow); + _fx.Genesis.Header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow); + _fx.Next.Header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow); } [Fact] @@ -130,7 +130,7 @@ public void ValidateHash() ); Assert.Throws( - () => { header.Validate(DateTime.UtcNow); }); + () => { header.Validate(_fx.HashAlgorithm, DateTime.UtcNow); }); } [Fact] @@ -155,7 +155,7 @@ public void ValidateProtocolVersion() ); Assert.Throws(() => - header.Validate(DateTimeOffset.UtcNow) + header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); header = new BlockHeader( @@ -177,7 +177,7 @@ public void ValidateProtocolVersion() ); Assert.Throws(() => - header.Validate(DateTimeOffset.UtcNow) + header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); } @@ -187,7 +187,9 @@ public void ValidateTimestamp() DateTimeOffset now = DateTimeOffset.UtcNow; string future = (now + TimeSpan.FromSeconds(16)) .ToString(BlockHeader.TimestampFormat, CultureInfo.InvariantCulture); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); BlockHeader header = MakeBlockHeader( + hashAlgorithm: hashAlgorithm, protocolVersion: 0, index: 0, difficulty: 0, @@ -202,10 +204,10 @@ public void ValidateTimestamp() ); Assert.Throws( - () => { header.Validate(now); }); + () => { header.Validate(hashAlgorithm, now); }); // it's okay because 2 seconds later. - header.Validate(now + TimeSpan.FromSeconds(2)); + header.Validate(hashAlgorithm, now + TimeSpan.FromSeconds(2)); } [Fact] @@ -230,7 +232,7 @@ public void ValidateNonce() ); Assert.Throws(() => - header.Validate(DateTimeOffset.UtcNow)); + header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); } [Fact] @@ -255,7 +257,7 @@ public void ValidateIndex() ); Assert.Throws(() => - header.Validate(DateTimeOffset.UtcNow)); + header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); } [Fact] @@ -278,7 +280,7 @@ public void ValidateDifficulty() ); Assert.Throws(() => - genesisHeader.Validate(DateTimeOffset.UtcNow)); + genesisHeader.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); var header1 = new BlockHeader( protocolVersion: 0, @@ -296,7 +298,7 @@ public void ValidateDifficulty() ); Assert.Throws(() => - header1.Validate(DateTimeOffset.UtcNow)); + header1.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); var header2 = new BlockHeader( protocolVersion: 0, @@ -314,7 +316,7 @@ public void ValidateDifficulty() ); Assert.Throws(() => - header2.Validate(DateTimeOffset.UtcNow)); + header2.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); } [Fact] @@ -337,7 +339,7 @@ public void ValidatePreviousHash() ); Assert.Throws(() => - genesisHeader.Validate(DateTimeOffset.UtcNow)); + genesisHeader.Validate(HashAlgorithmType.Of(), DateTimeOffset.UtcNow)); var header = new BlockHeader( protocolVersion: 0, @@ -355,10 +357,11 @@ public void ValidatePreviousHash() ); Assert.Throws(() => - genesisHeader.Validate(DateTimeOffset.UtcNow)); + genesisHeader.Validate(HashAlgorithmType.Of(), DateTimeOffset.UtcNow)); } private BlockHeader MakeBlockHeader( + HashAlgorithmType hashAlgorithm, int protocolVersion, long index, long difficulty, @@ -372,7 +375,7 @@ private BlockHeader MakeBlockHeader( ImmutableArray stateRootHash ) { - ImmutableArray hash = HashAlgorithmType.Of().Digest( + ImmutableArray hash = hashAlgorithm.Digest( BlockHeader.SerializeForHash( protocolVersion, index, diff --git a/Libplanet.Tests/Blocks/BlockTest.cs b/Libplanet.Tests/Blocks/BlockTest.cs index e60294c024..fd2f90156a 100644 --- a/Libplanet.Tests/Blocks/BlockTest.cs +++ b/Libplanet.Tests/Blocks/BlockTest.cs @@ -213,7 +213,9 @@ public void DetectInvalidProtocolVersion() new Transaction[] { }, protocolVersion: -1 ); - Assert.Throws(() => block.Validate(now)); + Assert.Throws( + () => block.Validate(_fx.HashAlgorithm, now) + ); block = Block.Mine( _fx.Next.Index, @@ -226,11 +228,13 @@ public void DetectInvalidProtocolVersion() new Transaction[] { }, protocolVersion: Block.CurrentProtocolVersion + 1 ); - Assert.Throws(() => block.Validate(now)); + Assert.Throws( + () => block.Validate(_fx.HashAlgorithm, now) + ); } [Fact] - public void CanDetectInvalidTimestamp() + public void DetectInvalidTimestamp() { DateTimeOffset now = DateTimeOffset.UtcNow; var block = Block.Mine( @@ -245,10 +249,10 @@ public void CanDetectInvalidTimestamp() ); Assert.Throws( - () => { block.Validate(now); }); + () => { block.Validate(_fx.HashAlgorithm, now); }); // it's okay because 2 seconds later. - block.Validate(now + TimeSpan.FromSeconds(2)); + block.Validate(_fx.HashAlgorithm, now + TimeSpan.FromSeconds(2)); } [Fact] @@ -269,7 +273,7 @@ public void DetectInvalidNonce() ); Assert.Throws(() => - invalidBlock.Validate(DateTimeOffset.UtcNow)); + invalidBlock.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); } [Fact] @@ -286,7 +290,7 @@ public void DetectInvalidDifficulty() transactions: MineGenesis().Transactions ); Assert.Throws(() => - invalidDifficultyGenesis.Validate(DateTimeOffset.UtcNow) + invalidDifficultyGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); var invalidTotalDifficultyGenesis = new Block( @@ -300,7 +304,7 @@ public void DetectInvalidDifficulty() transactions: MineGenesis().Transactions ); Assert.Throws(() => - invalidTotalDifficultyGenesis.Validate(DateTimeOffset.UtcNow) + invalidTotalDifficultyGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); var invalidDifficultyNext = new Block>( @@ -314,7 +318,7 @@ public void DetectInvalidDifficulty() transactions: _fx.Next.Transactions ); Assert.Throws(() => - invalidDifficultyNext.Validate(DateTimeOffset.UtcNow) + invalidDifficultyNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); var invalidTotalDifficultyNext = new Block>( @@ -328,7 +332,7 @@ public void DetectInvalidDifficulty() transactions: _fx.Next.Transactions ); Assert.Throws(() => - invalidTotalDifficultyNext.Validate(DateTimeOffset.UtcNow) + invalidTotalDifficultyNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); } @@ -347,7 +351,7 @@ public void DetectInvalidPreviousHash() ); Assert.Throws(() => - invalidGenesis.Validate(DateTimeOffset.UtcNow) + invalidGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); var invalidNext = new Block>( @@ -362,7 +366,7 @@ public void DetectInvalidPreviousHash() ); Assert.Throws(() => - invalidNext.Validate(DateTimeOffset.UtcNow) + invalidNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) ); } @@ -536,6 +540,7 @@ public void ValidateTxHash() Transaction.Create(0, new PrivateKey(), null, new DumbAction[0]), Transaction.Create(0, new PrivateKey(), null, new DumbAction[0]), }; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block = new Block( index: 0, difficulty: 0, @@ -547,7 +552,7 @@ public void ValidateTxHash() transactions: txs ); - block.Validate(DateTimeOffset.UtcNow); + block.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Dictionary blockDict = block.ToBencodex(); var txList = (List)blockDict[RawBlock.TransactionsKey]; @@ -560,7 +565,7 @@ public void ValidateTxHash() ); var exc = Assert.Throws( - () => abnormalTxs.Validate(DateTimeOffset.UtcNow) + () => abnormalTxs.Validate(hashAlgorithm, DateTimeOffset.UtcNow) ); Assert.Equal(abnormalTxs.TxHash, exc.BlockTxHash); @@ -571,7 +576,7 @@ public void ValidateTxHash() ) ); Assert.Throws( - () => emptyTxs.Validate(DateTimeOffset.UtcNow) + () => emptyTxs.Validate(hashAlgorithm, DateTimeOffset.UtcNow) ); } @@ -590,7 +595,7 @@ public void DetectInvalidPreEvaluationHash() transactions: _fx.Next.Transactions); Assert.Throws(() => - invalidBlock.Validate(DateTimeOffset.UtcNow)); + invalidBlock.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); } [Fact] diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index a8defc9288..21d91285e6 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -259,7 +259,7 @@ public static Block MineNext( ); } - block.Validate(DateTimeOffset.Now); + block.Validate(hashAlgorithm, DateTimeOffset.Now); return block; } diff --git a/Libplanet/Action/ActionEvaluator.cs b/Libplanet/Action/ActionEvaluator.cs index 60f6e650c4..ed67a3e02d 100644 --- a/Libplanet/Action/ActionEvaluator.cs +++ b/Libplanet/Action/ActionEvaluator.cs @@ -381,8 +381,10 @@ internal IEnumerable EvaluateBlock( IAccountStateDelta previousStates, ITrie? previousBlockStatesTrie = null) { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + // FIXME: Probably not the best place to have Validate(). - block.Validate(currentTime); + block.Validate(hashAlgorithm, currentTime); return EvaluateTxs( block: block, diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index 7f1667f583..d5aff21d73 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -489,6 +489,8 @@ public override string ToString() /// Validates this and throws an appropriate exception /// if not valid. /// + /// The hash algorithm used to calculate + /// the . /// The current time to validate time-wise conditions. /// Thrown when /// is invalid. @@ -508,9 +510,9 @@ public override string ToString() /// Thrown when the value of /// is not consistent with . /// - internal void Validate(DateTimeOffset currentTime) + internal void Validate(HashAlgorithmType hashAlgorithm, DateTimeOffset currentTime) { - Header.Validate(currentTime); + Header.Validate(hashAlgorithm, currentTime); foreach (Transaction tx in Transactions) { @@ -519,7 +521,6 @@ internal void Validate(DateTimeOffset currentTime) if (ProtocolVersion > 0) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); byte[] expectedPreEvaluationHash = hashAlgorithm.Digest(Header.SerializeForHash(includeStateRootHash: false)); if (!ByteUtil.TimingSafelyCompare(expectedPreEvaluationHash, PreEvaluationHash)) diff --git a/Libplanet/Blocks/BlockHeader.cs b/Libplanet/Blocks/BlockHeader.cs index de90c402df..26eccafd14 100644 --- a/Libplanet/Blocks/BlockHeader.cs +++ b/Libplanet/Blocks/BlockHeader.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.Linq; using System.Numerics; -using System.Security.Cryptography; using Bencodex; using Bencodex.Types; using Libplanet.Store.Trie; @@ -295,7 +294,7 @@ ImmutableArray stateRootHash return new Codec().Encode(dict); } - internal void Validate(DateTimeOffset currentTime) + internal void Validate(HashAlgorithmType hashAlgorithm, DateTimeOffset currentTime) { if (ProtocolVersion < 0) { @@ -404,7 +403,6 @@ internal void Validate(DateTimeOffset currentTime) ); } - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); BlockHash calculatedHash = new BlockHash(hashAlgorithm.Digest(SerializeForHash())); if (!hash.Equals(calculatedHash)) { diff --git a/Libplanet/Net/Swarm.MessageHandlers.cs b/Libplanet/Net/Swarm.MessageHandlers.cs index 99865db2c5..013577136c 100644 --- a/Libplanet/Net/Swarm.MessageHandlers.cs +++ b/Libplanet/Net/Swarm.MessageHandlers.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Libplanet.Blockchain.Policies; @@ -134,9 +135,10 @@ private async Task ProcessBlockHeader( ByteUtil.Hex(header.Hash) ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); try { - header.Validate(DateTimeOffset.UtcNow); + header.Validate(hashAlgorithm, DateTimeOffset.UtcNow); } catch (InvalidBlockException ibe) { diff --git a/Libplanet/Net/Swarm.cs b/Libplanet/Net/Swarm.cs index 041bfd2c56..74895a23aa 100644 --- a/Libplanet/Net/Swarm.cs +++ b/Libplanet/Net/Swarm.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net; using System.Runtime.CompilerServices; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Libplanet.Action; @@ -692,7 +693,8 @@ var pair in completedBlocks.WithCancellation(blockDownloadCts.Token)) block.Index, block.Hash ); - block.Validate(DateTimeOffset.UtcNow); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + block.Validate(hashAlgorithm, DateTimeOffset.UtcNow); wStore.PutBlock(block); if (tempTip is null || block.Index > tempTip.Index) { diff --git a/Libplanet/Store/BlockSet.cs b/Libplanet/Store/BlockSet.cs index b615ba0e76..be436685c6 100644 --- a/Libplanet/Store/BlockSet.cs +++ b/Libplanet/Store/BlockSet.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blocks; using LruCacheNet; @@ -62,7 +63,8 @@ public override Block this[BlockHash key] $"{value}.hash does not match to {key}"); } - value.Validate(DateTimeOffset.UtcNow); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + value.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Store.PutBlock(value); _cache.AddOrUpdate(value.Hash, value); } From 8f558061d2b770f75af9f8b52d08bfefd5fcb7ca Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 00:22:19 +0900 Subject: [PATCH 13/22] Add hashAlgorithmGetter param to ActionEvaluator() ctor --- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 5 +++++ Libplanet.Tests/TestUtils.cs | 7 ++++++- Libplanet/Action/ActionEvaluator.cs | 7 ++++++- Libplanet/Blockchain/BlockChain.cs | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index d38aeff366..039fe405de 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -76,6 +76,7 @@ public void Idempotent() transactions: txs).AttachStateRootHash(stateStore, null); var actionEvaluator = new ActionEvaluator( + hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, stateGetter: ActionEvaluator.NullStateGetter, balanceGetter: ActionEvaluator.NullBalanceGetter, @@ -272,6 +273,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu }; Block genesis = MineGenesis(); ActionEvaluator actionEvaluator = new ActionEvaluator( + hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, stateGetter: ActionEvaluator.NullStateGetter, balanceGetter: ActionEvaluator.NullBalanceGetter, @@ -569,6 +571,7 @@ public void EvaluateTx() timestamp: DateTimeOffset.UtcNow, transactions: ImmutableArray.Create(tx)); var actionEvaluator = new ActionEvaluator( + hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, stateGetter: ActionEvaluator.NullStateGetter, balanceGetter: ActionEvaluator.NullBalanceGetter, @@ -721,6 +724,7 @@ public void EvaluateBlockWithInvalidTxUpdatedAddresses() txs: new List>> { invalidTx }); var actionEvaluator = new ActionEvaluator>( + hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, stateGetter: ActionEvaluator>.NullStateGetter, balanceGetter: ActionEvaluator>.NullBalanceGetter, @@ -758,6 +762,7 @@ public void EvaluateTxResultThrowingException() DateTimeOffset.UtcNow); var hash = new BlockHash(GetRandomBytes(32)); var actionEvaluator = new ActionEvaluator( + hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, stateGetter: ActionEvaluator.NullStateGetter, balanceGetter: ActionEvaluator.NullBalanceGetter, diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 21d91285e6..04cd8f97c0 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -293,7 +293,12 @@ FungibleAssetValue FungibleAssetValueGetter( } var actionEvaluator = new ActionEvaluator( - blockAction, StateGetter, FungibleAssetValueGetter, null); + hashAlgorithmGetter: _ => HashAlgorithmType.Of(), + policyBlockAction: blockAction, + stateGetter: StateGetter, + balanceGetter: FungibleAssetValueGetter, + trieGetter: null + ); var actionEvaluationResult = actionEvaluator .Evaluate(block, StateCompleterSet.Reject) .GetTotalDelta(ToStateKey, ToFungibleAssetKey); diff --git a/Libplanet/Action/ActionEvaluator.cs b/Libplanet/Action/ActionEvaluator.cs index ed67a3e02d..b75b8b9a09 100644 --- a/Libplanet/Action/ActionEvaluator.cs +++ b/Libplanet/Action/ActionEvaluator.cs @@ -46,6 +46,7 @@ public class ActionEvaluator transactions: ImmutableArray>.Empty); private static readonly ILogger _logger = Log.ForContext>(); + private readonly Func _hashAlgorithmGetter; private readonly IAction? _policyBlockAction; private readonly StateGetter _stateGetter; private readonly BalanceGetter _balanceGetter; @@ -54,6 +55,8 @@ public class ActionEvaluator /// /// Creates a new . /// + /// The function to determine a hash algorithm to use + /// for a block index. /// The provided by /// to evaluate at the end for each /// that gets evaluated. @@ -64,11 +67,13 @@ public class ActionEvaluator /// The function to retrieve a trie for /// a provided . public ActionEvaluator( + Func hashAlgorithmGetter, IAction? policyBlockAction, StateGetter stateGetter, BalanceGetter balanceGetter, Func? trieGetter) { + _hashAlgorithmGetter = hashAlgorithmGetter; _policyBlockAction = policyBlockAction; _stateGetter = stateGetter; _balanceGetter = balanceGetter; @@ -381,7 +386,7 @@ internal IEnumerable EvaluateBlock( IAccountStateDelta previousStates, ITrie? previousBlockStatesTrie = null) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmType hashAlgorithm = _hashAlgorithmGetter(block.Index); // FIXME: Probably not the best place to have Validate(). block.Validate(hashAlgorithm, currentTime); diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 3c594613f0..8c98167dd6 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -166,6 +166,7 @@ IEnumerable> renderers ? h => trieStateStore.GetTrie(h) : (Func)null; ActionEvaluator = new ActionEvaluator( + _ => HashAlgorithmType.Of(), policy.BlockAction, GetState, GetBalance, @@ -393,6 +394,7 @@ public static Block MakeGenesisBlock( transactions); var actionEvaluator = new ActionEvaluator( + _ => HashAlgorithmType.Of(), blockAction, (address, digest, stateCompleter) => null, (address, currency, hash, fungibleAssetStateCompleter) From 8f809fd39ff576c6e0f170c523b2d02075039c99 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 00:31:38 +0900 Subject: [PATCH 14/22] HashAlgorithmGetter delegate --- CHANGES.md | 1 + Libplanet/Action/ActionEvaluator.cs | 4 ++-- Libplanet/Blocks/HashAlgorithmGetter.cs | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Libplanet/Blocks/HashAlgorithmGetter.cs diff --git a/CHANGES.md b/CHANGES.md index 8c9049d4bd..96ff4f1784 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -191,6 +191,7 @@ To be released. - Added `BlockHash` struct. [[#1192], [#1197]] - Added `HashDigest.DeriveFrom()` method. [[#1197]] - Added `HashAlgorithmType` class. [[#1314], [#1352]] + - Added `HashAlgorithmGetter` delegate. [[#1314], [#1352]] - Added `BlockChain.GetTxExecution()` method. [[#1156], [#1289]] - Added `StunMessage.ParseAsync(Stream, CancellationToken)` method. [[#1228]] diff --git a/Libplanet/Action/ActionEvaluator.cs b/Libplanet/Action/ActionEvaluator.cs index b75b8b9a09..04719073bd 100644 --- a/Libplanet/Action/ActionEvaluator.cs +++ b/Libplanet/Action/ActionEvaluator.cs @@ -46,7 +46,7 @@ public class ActionEvaluator transactions: ImmutableArray>.Empty); private static readonly ILogger _logger = Log.ForContext>(); - private readonly Func _hashAlgorithmGetter; + private readonly HashAlgorithmGetter _hashAlgorithmGetter; private readonly IAction? _policyBlockAction; private readonly StateGetter _stateGetter; private readonly BalanceGetter _balanceGetter; @@ -67,7 +67,7 @@ public class ActionEvaluator /// The function to retrieve a trie for /// a provided . public ActionEvaluator( - Func hashAlgorithmGetter, + HashAlgorithmGetter hashAlgorithmGetter, IAction? policyBlockAction, StateGetter stateGetter, BalanceGetter balanceGetter, diff --git a/Libplanet/Blocks/HashAlgorithmGetter.cs b/Libplanet/Blocks/HashAlgorithmGetter.cs new file mode 100644 index 0000000000..15c517600e --- /dev/null +++ b/Libplanet/Blocks/HashAlgorithmGetter.cs @@ -0,0 +1,11 @@ +#nullable enable +namespace Libplanet.Blocks +{ + /// + /// The delegate to determine a hash algorithm to use for a . + /// + /// The of a block to determine its + /// hash algorithm. + /// The hash algorithm to be used for proof-of-work on the block. + public delegate HashAlgorithmType HashAlgorithmGetter(long blockIndex); +} From 34b256cba7b53dc08498c7b6dec270deb65bd9dd Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 01:26:22 +0900 Subject: [PATCH 15/22] Add hashAlgorithmGetter param to BlockSet() ctor --- CHANGES.md | 1 + Libplanet.Benchmarks/Store.cs | 3 +- Libplanet.Benchmarks/SwarmBenchmark.cs | 11 +-- .../Commands/StoreCommandTest.cs | 13 ++-- .../Action/AccountStateDeltaImplTest.cs | 5 +- .../Action/AccountStateDeltaImplV0Test.cs | 5 +- .../Action/AccountStateDeltaTest.cs | 5 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 17 +++-- .../Blockchain/BlockChainTest.Append.cs | 35 +++++++--- .../Blockchain/BlockChainTest.Internals.cs | 5 +- .../BlockChainTest.ValidateNextBlock.cs | 25 ++++--- Libplanet.Tests/Blockchain/BlockChainTest.cs | 67 +++++++++++++------ .../Renderers/AnonymousActionRendererTest.cs | 7 +- .../Renderers/AnonymousRendererTest.cs | 7 +- .../Renderers/DelayedRendererTest.cs | 12 +++- .../Renderers/LoggedActionRendererTest.cs | 7 +- .../Renderers/LoggedRendererTest.cs | 7 +- Libplanet.Tests/Blocks/BlockFixture.cs | 2 + Libplanet.Tests/Blocks/BlockTest.cs | 4 +- Libplanet.Tests/Fixtures/IntegerSet.cs | 5 +- Libplanet.Tests/Net/BlockCompletionTest.cs | 9 ++- Libplanet.Tests/Net/SwarmTest.Broadcast.cs | 9 ++- Libplanet.Tests/Net/SwarmTest.Consensus.cs | 10 ++- Libplanet.Tests/Net/SwarmTest.Preload.cs | 26 +++++-- Libplanet.Tests/Net/SwarmTest.cs | 21 ++++-- Libplanet.Tests/Store/BlockSetTest.cs | 2 +- Libplanet.Tests/Store/StoreFixture.cs | 15 +++-- Libplanet.Tests/Store/StoreTest.cs | 4 +- Libplanet.Tests/TestUtils.cs | 18 +++-- Libplanet/Blockchain/BlockChain.cs | 4 +- Libplanet/Store/BlockSet.cs | 7 +- 31 files changed, 262 insertions(+), 106 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 96ff4f1784..cd0da93683 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -136,6 +136,7 @@ To be released. - Removed `Hashcash.Hash()` method. - Removed `HashDigest.Satisfies()` method. This was replaced by `ByteUtil.Satisfies()` method instead. [[#1192], [#1197]] + - Added `hashAlgorithmGetter` parameter to `BlockSet()` constructor. - Added `IActionContext.TxId` property. [[#1275]] - Added `IStore.PutTxExecution(TxSuccess)` method. [[#1156], [#1289]] - Added `IStore.PutTxExecution(TxFailure)` method. [[#1156], [#1289]] diff --git a/Libplanet.Benchmarks/Store.cs b/Libplanet.Benchmarks/Store.cs index a1f0a37b2c..63960d9fbc 100644 --- a/Libplanet.Benchmarks/Store.cs +++ b/Libplanet.Benchmarks/Store.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Security.Cryptography; using BenchmarkDotNet.Attributes; using Libplanet.Blocks; using Libplanet.Crypto; @@ -36,7 +37,7 @@ public Store() { blockTxs.Add(Transaction.Create(nonce++, key, genesis.Hash, new DumbAction[0])); } - block = TestUtils.MineNext(block, blockTxs); + block = TestUtils.MineNext(block, HashAlgorithmType.Of(), blockTxs); blocks.Add(block); txs.AddRange(blockTxs); } diff --git a/Libplanet.Benchmarks/SwarmBenchmark.cs b/Libplanet.Benchmarks/SwarmBenchmark.cs index 03154a2a23..577bf3b2c6 100644 --- a/Libplanet.Benchmarks/SwarmBenchmark.cs +++ b/Libplanet.Benchmarks/SwarmBenchmark.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Net; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; @@ -27,6 +28,7 @@ public class SwarmBenchmark private readonly IStagePolicy _stagePolicy; private readonly List> _blocks; private readonly AppProtocolVersion _appProtocolVersion; + private readonly HashAlgorithmType _hashAlgorithm; private PrivateKey[] _keys; private DefaultStoreFixture[] _fxs; private BlockChain[] _blockChains; @@ -41,10 +43,11 @@ public SwarmBenchmark() TestUtils.MineGenesis(), }; _appProtocolVersion = AppProtocolVersion.Sign(new PrivateKey(), 1); - _blocks.Add(TestUtils.MineNext(_blocks[0])); - _blocks.Add(TestUtils.MineNext(_blocks[1])); - _blocks.Add(TestUtils.MineNext(_blocks[2])); - _blocks.Add(TestUtils.MineNext(_blocks[3])); + _hashAlgorithm = HashAlgorithmType.Of(); + _blocks.Add(TestUtils.MineNext(_blocks[0], _hashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[1], _hashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[2], _hashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[3], _hashAlgorithm)); } [IterationSetup(Targets = new[] {"BroadcastBlock", "BroadcastBlockWithoutFill"})] diff --git a/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs b/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs index 9e13113937..29adef5ee1 100644 --- a/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs +++ b/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Immutable; using System.IO; +using System.Security.Cryptography; using Cocona; using Libplanet.Blocks; using Libplanet.Crypto; @@ -17,6 +18,7 @@ public class StoreCommandTest : IDisposable { private readonly ImmutableArray _storeFixtures; private readonly TextWriter _originalWriter; + private readonly HashAlgorithmType _hashAlgorithm; private readonly Block _genesisBlock; private readonly Block _block1; private readonly Block _block2; @@ -51,11 +53,12 @@ public StoreCommandTest() _transaction3 = DummyTransaction(); _transaction4 = DummyTransaction(); - _block1 = TestUtils.MineNext(_genesisBlock, new[] { _transaction1 }); - _block2 = TestUtils.MineNext(_block1, new[] { _transaction2 }); - _block3 = TestUtils.MineNext(_block2, new[] { _transaction3 }); - _block4 = TestUtils.MineNext(_block3, new[] { _transaction3 }); - _block5 = TestUtils.MineNext(_block4); + _hashAlgorithm = HashAlgorithmType.Of(); + _block1 = TestUtils.MineNext(_genesisBlock, _hashAlgorithm, new[] { _transaction1 }); + _block2 = TestUtils.MineNext(_block1, _hashAlgorithm, new[] { _transaction2 }); + _block3 = TestUtils.MineNext(_block2, _hashAlgorithm, new[] { _transaction3 }); + _block4 = TestUtils.MineNext(_block3, _hashAlgorithm, new[] { _transaction3 }); + _block5 = TestUtils.MineNext(_block4, _hashAlgorithm); var guid = Guid.NewGuid(); foreach (var v in _storeFixtures) diff --git a/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs b/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs index 4be7beac7c..b823cd1cda 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Blocks; @@ -55,12 +56,14 @@ public override BlockChain TransferAssetInBlock() chain.Genesis.Hash, new[] { action } ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); chain.Append( TestUtils.MineNext( chain.Tip, + hashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash(chain.StateStore, chain.Policy.BlockAction) + ).AttachStateRootHash(hashAlgorithm, chain.StateStore, chain.Policy.BlockAction) ); Assert.Equal( DumbAction.DumbCurrency * 5, diff --git a/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs b/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs index 40e5d12010..7c42451632 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Tests.Common.Action; @@ -54,12 +55,14 @@ public override BlockChain TransferAssetInBlock() chain.Genesis.Hash, new[] { action } ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); chain.Append( TestUtils.MineNext( chain.Tip, + hashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash(chain.StateStore, chain.Policy.BlockAction) + ).AttachStateRootHash(hashAlgorithm, chain.StateStore, chain.Policy.BlockAction) ); Assert.Equal( DumbAction.DumbCurrency * 6, diff --git a/Libplanet.Tests/Action/AccountStateDeltaTest.cs b/Libplanet.Tests/Action/AccountStateDeltaTest.cs index bcdf410a54..b371c48cfc 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaTest.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaTest.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using Bencodex.Types; using Libplanet.Action; using Libplanet.Assets; @@ -208,6 +209,7 @@ public virtual BlockChain TransferAssetInBlock() protocolVersion: ProtocolVersion ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); DumbAction action = new DumbAction(_addr[0], "a", _addr[1], _addr[0], 5); Transaction tx = Transaction.Create( 0, @@ -218,9 +220,10 @@ public virtual BlockChain TransferAssetInBlock() chain.Append( TestUtils.MineNext( chain.Tip, + hashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash(stateStore, chain.Policy.BlockAction) + ).AttachStateRootHash(hashAlgorithm, stateStore, chain.Policy.BlockAction) ); Assert.Equal( DumbAction.DumbCurrency * 5, diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 039fe405de..629c879def 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -68,12 +68,13 @@ public void Idempotent() }; var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var noStateRootBlock = TestUtils.MineGenesis( timestamp: timestamp, transactions: txs); var stateRootBlock = TestUtils.MineGenesis( timestamp: timestamp, - transactions: txs).AttachStateRootHash(stateStore, null); + transactions: txs).AttachStateRootHash(hashAlgorithm, stateStore, null); var actionEvaluator = new ActionEvaluator( hashAlgorithmGetter: _ => HashAlgorithmType.Of(), @@ -271,6 +272,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _txFx.Address4, _txFx.Address5, }; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block genesis = MineGenesis(); ActionEvaluator actionEvaluator = new ActionEvaluator( hashAlgorithmGetter: _ => HashAlgorithmType.Of(), @@ -323,7 +325,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _logger.Debug("{0}[{1}] = {2}", nameof(block1Txs), i, tx.Id); } - Block block1 = MineNext(genesis, block1Txs, new byte[] { }); + Block block1 = MineNext(genesis, hashAlgorithm, block1Txs, new byte[] { }); previousStates = block1.ProtocolVersion > 0 ? new AccountStateDeltaImpl( ActionEvaluator.NullAccountStateGetter, @@ -442,7 +444,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _logger.Debug("{0}[{1}] = {2}", nameof(block2Txs), i, tx.Id); } - Block block2 = MineNext(block1, block2Txs, new byte[] { }); + Block block2 = MineNext(block1, hashAlgorithm, block2Txs, new byte[] { }); AccountStateGetter accountStateGetter = dirty1.GetValueOrDefault; AccountBalanceGetter accountBalanceGetter = (address, currency) => balances1.TryGetValue((address, currency), out FungibleAssetValue v) @@ -690,6 +692,7 @@ prevEval is null [Fact] public void EvaluateBlockWithInvalidTxUpdatedAddresses() { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); ImmutableArray rawActions = _txFx.TxWithActions .ToRawTransaction(false).Actions.ToImmutableArray(); @@ -721,6 +724,7 @@ public void EvaluateBlockWithInvalidTxUpdatedAddresses() sig.ToImmutableArray())); Block> invalidBlock = TestUtils.MineNext( previousBlock: genesis, + hashAlgorithm: hashAlgorithm, txs: new List>> { invalidTx }); var actionEvaluator = new ActionEvaluator>( @@ -914,15 +918,16 @@ public void EvaluatePolicyBlockAction() store: _storeFx.Store, stateStore: _storeFx.StateStore, genesisBlock: _storeFx.GenesisBlock); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); (var addresses, Transaction[] txs) = MakeFixturesForAppendTests(); var genesis = chain.Genesis; var block = TestUtils.MineNext( genesis, + hashAlgorithm, txs, - difficulty: chain.Policy.GetNextBlockDifficulty(chain)).AttachStateRootHash( - chain.StateStore, - _policy.BlockAction); + difficulty: chain.Policy.GetNextBlockDifficulty(chain) + ).AttachStateRootHash(hashAlgorithm, chain.StateStore, _policy.BlockAction); var stateCompleterSet = StateCompleterSet.Recalculate; AccountStateGetter accountStateGetter = diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index 7feb88862d..9cc117e092 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using System.Threading.Tasks; using Bencodex.Types; using Libplanet.Action; @@ -33,6 +34,8 @@ Func getTxExecution ? (Func)_blockChain.Store.GetTxExecution : _blockChain.GetTxExecution; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + (Address[] addresses, Transaction[] txs) = MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; @@ -42,17 +45,19 @@ Func getTxExecution Assert.Empty(_renderer.BlockRecords); var block1 = TestUtils.MineNext( genesis, + hashAlgorithm, miner: addresses[4], difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block1); Block block2 = TestUtils.MineNext( block1, + hashAlgorithm, txs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); foreach (Transaction tx in txs) { Assert.Null(getTxExecution(genesis.Hash, tx.Id)); @@ -200,9 +205,10 @@ Func getTxExecution ); Block block3 = TestUtils.MineNext( block2, + hashAlgorithm, new[] { tx1Transfer, tx2Error, tx3Transfer }, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block3); var txExecution1 = getTxExecution(block3.Hash, tx1Transfer.Id); _logger.Verbose(nameof(txExecution1) + " = {@TxExecution}", txExecution1); @@ -292,6 +298,7 @@ Func getTxExecution [Fact] public void AppendThrowsInvalidBlockBytesLengthException() { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); DumbAction[] manyActions = Enumerable.Repeat(new DumbAction(default, "_"), 200).ToArray(); PrivateKey signer = null; @@ -315,6 +322,7 @@ public void AppendThrowsInvalidBlockBytesLengthException() var block1 = TestUtils.MineNext( _blockChain.Genesis, + hashAlgorithm, heavyTxs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) @@ -332,6 +340,7 @@ public void AppendThrowsInvalidBlockBytesLengthException() [Fact] public void AppendThrowsBlockExceedingTransactionsException() { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); PrivateKey signer = null; int nonce = 0; int maxTxs = _blockChain.Policy.MaxTransactionsPerBlock; @@ -348,6 +357,7 @@ public void AppendThrowsBlockExceedingTransactionsException() var block1 = TestUtils.MineNext( _blockChain.Genesis, + hashAlgorithm, manyTxs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) @@ -367,10 +377,12 @@ public void AppendWithoutEvaluateActions() { (_, Transaction[] txs) = MakeFixturesForAppendTests(); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; var block = TestUtils.MineNext( genesis, + hashAlgorithm, difficulty: 1024, blockInterval: TimeSpan.FromSeconds(10)); Assert.Throws(() => @@ -439,6 +451,7 @@ bool IsSignerValid(Transaction tx, BlockChain chain) var policy = new BlockPolicy(doesTransactionFollowPolicy: IsSignerValid); using (var fx = new DefaultStoreFixture()) { + HashAlgorithmType hashAlgorithm = fx.HashAlgorithm; var blockChain = new BlockChain( policy, new VolatileStagePolicy(), @@ -453,21 +466,23 @@ bool IsSignerValid(Transaction tx, BlockChain chain) Block block1 = TestUtils.MineNext( fx.GenesisBlock, + hashAlgorithm, new[] { validTx }, miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(blockChain.StateStore, policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, blockChain.StateStore, policy.BlockAction); blockChain.Append(block1); Block block2 = TestUtils.MineNext( block1, + hashAlgorithm, new[] { invalidTx }, miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(blockChain.StateStore, policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, blockChain.StateStore, policy.BlockAction); Assert.Throws(() => blockChain.Append(block2)); } @@ -479,14 +494,16 @@ public void UnstageAfterAppendComplete() PrivateKey privateKey = new PrivateKey(); (Address[] addresses, Transaction[] txs) = MakeFixturesForAppendTests(privateKey, epoch: DateTimeOffset.UtcNow); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; Block block1 = TestUtils.MineNext( genesis, + hashAlgorithm, miner: addresses[4], difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block1); Assert.Empty(_blockChain.GetStagedTransactionIds()); @@ -496,10 +513,11 @@ public void UnstageAfterAppendComplete() Block block2 = TestUtils.MineNext( block1, + hashAlgorithm, ImmutableArray>.Empty.Add(txs[0]), difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block2); Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count); StageTransactions(txs); @@ -515,10 +533,11 @@ public void UnstageAfterAppendComplete() Block block3 = TestUtils.MineNext( block2, + hashAlgorithm, ImmutableArray>.Empty.Add(txs[1]), difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block3); Assert.Empty(_blockChain.GetStagedTransactionIds()); } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs index 8137a60ff6..27465ebf6c 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using Bencodex.Types; using Libplanet.Assets; using Libplanet.Blockchain; @@ -123,11 +124,13 @@ public void ExecuteActions() MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block1 = TestUtils.MineNext( genesis, + hashAlgorithm, txs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append( block1, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index e9e4ef9b5b..d1812af6db 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -25,7 +25,7 @@ public void ValidateNextBlock() _fx.GenesisBlock.Hash, _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(validNextBlock); Assert.Equal(_blockChain.Tip, validNextBlock); } @@ -43,7 +43,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: 1 - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block1); Block block2 = Block.Mine( @@ -56,7 +56,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: 0 - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(block2)); Assert.Throws(() => @@ -71,7 +71,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: Block.CurrentProtocolVersion + 1 - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block3); }); } @@ -91,7 +91,7 @@ private void ValidateNextBlockInvalidIndex() prev.Hash, prev.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws( () => _blockChain.Append(blockWithAlreadyUsedIndex) ); @@ -105,7 +105,7 @@ private void ValidateNextBlockInvalidIndex() prev.Hash, prev.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws( () => _blockChain.Append(blockWithIndexAfterNonexistentIndex) ); @@ -124,7 +124,8 @@ private void ValidateNextBlockInvalidDifficulty() _fx.GenesisBlock.Miner.Value, _validNext.Hash, _validNext.Timestamp.AddSeconds(1), - _emptyTransaction).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + _emptyTransaction + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(invalidDifficultyBlock)); } @@ -142,7 +143,8 @@ private void ValidateNextBlockInvalidTotalDifficulty() _fx.GenesisBlock.Miner.Value, _validNext.Hash, _validNext.Timestamp.AddSeconds(1), - _emptyTransaction).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + _emptyTransaction + ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(invalidTotalDifficultyBlock)); } @@ -195,7 +197,7 @@ private void ValidateNextBlockInvalidStateRootHash() // calculate state root hash. To resolve this problem, // it should be moved into StateStore. var genesisBlock = TestUtils.MineGenesis() - .AttachStateRootHash(_fx.StateStore, policy.BlockAction); + .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, policy.BlockAction); var store = new DefaultStore(null); var chain = new BlockChain( policy, @@ -212,8 +214,9 @@ private void ValidateNextBlockInvalidStateRootHash() genesisBlock.Miner.Value, genesisBlock.Hash, genesisBlock.Timestamp.AddSeconds(1), - _emptyTransaction).AttachStateRootHash(_fx.StateStore, _policy.BlockAction) - .AttachStateRootHash(chain.StateStore, policy.BlockAction); + _emptyTransaction) + .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction) + .AttachStateRootHash(_fx.HashAlgorithm, chain.StateStore, policy.BlockAction); chain.Append(validNext); var invalidStateRootHash = Block.Mine( diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 43b5de153c..e90e7f14e7 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -66,14 +66,14 @@ public BlockChainTest(ITestOutputHelper output) _emptyTransaction = new List>(); _validNext = Block.Mine( 1, - HashAlgorithmType.Of(), + _fx.HashAlgorithm, 1024, _fx.GenesisBlock.TotalDifficulty, _fx.GenesisBlock.Miner.Value, _fx.GenesisBlock.Hash, _fx.GenesisBlock.Timestamp.AddSeconds(1), _emptyTransaction) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); } public void Dispose() @@ -302,10 +302,11 @@ IEnumerable NonRehearsalExecutions() => var tx = chain.MakeTransaction(key, actions); var block = TestUtils.MineNext( chain.Genesis, + fx.HashAlgorithm, new[] { tx }, miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain)) - .AttachStateRootHash(fx.StateStore, policy.BlockAction); + .AttachStateRootHash(fx.HashAlgorithm, fx.StateStore, policy.BlockAction); chain.Append(block); var forked = chain.Fork(chain.Genesis.Hash); forked.Append(block); @@ -515,6 +516,7 @@ public async void Fork() [Fact] public async Task ForkWithBlockNotExistInChain() { + HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; var genesis = await _blockChain.MineBlock(_fx.Address1); for (var i = 0; i < 2; i++) @@ -522,7 +524,7 @@ public async Task ForkWithBlockNotExistInChain() await _blockChain.MineBlock(_fx.Address1); } - var newBlock = TestUtils.MineNext(genesis, difficulty: 1024); + var newBlock = TestUtils.MineNext(genesis, hashAlgorithm, difficulty: 1024); Assert.Throws(() => _blockChain.Fork(newBlock.Hash)); @@ -575,6 +577,7 @@ public async Task ForkShouldSkipExecuteAndRenderGenesis() Address miner = _fx.Address2; var action = new DumbAction(stateKey, "genesis"); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); using (var store = new DefaultStore(null)) using (var stateStore = new TrieStateStore( new MemoryKeyValueStore(), new MemoryKeyValueStore())) @@ -586,7 +589,7 @@ public async Task ForkShouldSkipExecuteAndRenderGenesis() new[] { action } ), } - ).AttachStateRootHash(stateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, stateStore, _policy.BlockAction); store.PutBlock(genesis); var renderer = new RecordingActionRenderer(); var blockChain = new BlockChain( @@ -623,6 +626,7 @@ public void DetectInvalidTxNonce() var privateKey = new PrivateKey(); var actions = new[] { new DumbAction(_fx.Address1, "foo") }; + HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; var genesis = _blockChain.Genesis; Transaction[] txsA = @@ -632,20 +636,22 @@ public void DetectInvalidTxNonce() Block b1 = TestUtils.MineNext( genesis, + hashAlgorithm, txsA, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b1); Block b2 = TestUtils.MineNext( b1, + hashAlgorithm, txsA, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(b2)); @@ -658,11 +664,12 @@ public void DetectInvalidTxNonce() }; b2 = TestUtils.MineNext( b1, + hashAlgorithm, txsB, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b2); } @@ -679,6 +686,7 @@ public void ForkTxNonce() Address lessActiveAddress = lessActivePrivateKey.ToAddress(); var actions = new[] { new DumbAction(address, "foo") }; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; @@ -692,11 +700,12 @@ public void ForkTxNonce() Block b1 = TestUtils.MineNext( genesis, + hashAlgorithm, txsA, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b1); @@ -711,11 +720,12 @@ public void ForkTxNonce() }; Block b2 = TestUtils.MineNext( b1, + hashAlgorithm, txsB, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b2); Assert.Equal(2, _blockChain.GetNextTxNonce(address)); @@ -761,14 +771,16 @@ public void Swap(bool render) MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; var minerAddress = addresses[4]; + HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; Block block1 = TestUtils.MineNext( genesis, + hashAlgorithm, txs1, miner: minerAddress, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block1); PrivateKey privateKey = new PrivateKey(new byte[] @@ -828,11 +840,12 @@ public void Swap(bool render) { Block b = TestUtils.MineNext( _blockChain.Tip, + hashAlgorithm, txs, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b); } @@ -859,11 +872,12 @@ public void Swap(bool render) Block forkTip = TestUtils.MineNext( fork.Tip, + hashAlgorithm, txsB, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); fork.Append( forkTip, DateTimeOffset.UtcNow, @@ -1001,9 +1015,10 @@ public async Task ReorgIsUnableToHeterogenousChain(bool render) using (var fx2 = new DefaultStoreFixture( memory: true, blockAction: _policy.BlockAction)) { + HashAlgorithmType hashAlgorithm = fx2.HashAlgorithm; Block genesis2 = TestUtils.MineGenesis(timestamp: DateTimeOffset.UtcNow) - .AttachStateRootHash(fx2.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, fx2.StateStore, _policy.BlockAction); var chain2 = new BlockChain( _blockChain.Policy, _blockChain.StagePolicy, @@ -1045,6 +1060,7 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() _fx.StateStore, _fx.GenesisBlock ); + HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; Block b = chain.Genesis; Address[] addresses = new Address[30]; @@ -1062,8 +1078,8 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() { Transaction.Create(0, privateKey, chain.Genesis.Hash, actions), }; - b = TestUtils.MineNext(b, txs) - .AttachStateRootHash(_fx.StateStore, policy.BlockAction); + b = TestUtils.MineNext(b, hashAlgorithm, txs) + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, policy.BlockAction); chain.Append(b); } @@ -1097,12 +1113,13 @@ public void GetStateReturnsEarlyForNonexistentAccount() _fx.StateStore, _fx.GenesisBlock ); + HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; Block b = chain.Genesis; for (int i = 0; i < 20; ++i) { - b = TestUtils.MineNext(b, blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, blockPolicy.BlockAction); + b = TestUtils.MineNext(b, hashAlgorithm, blockInterval: TimeSpan.FromSeconds(10)) + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, blockPolicy.BlockAction); chain.Append(b); } @@ -1261,6 +1278,7 @@ public void GetNextTxNonce() var privateKey = new PrivateKey(); Address address = privateKey.ToAddress(); var actions = new[] { new DumbAction(_fx.Address1, "foo") }; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; Assert.Equal(0, _blockChain.GetNextTxNonce(address)); @@ -1272,11 +1290,12 @@ public void GetNextTxNonce() Block b1 = TestUtils.MineNext( genesis, + hashAlgorithm, txsA, null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b1); Assert.Equal(1, _blockChain.GetNextTxNonce(address)); @@ -1366,16 +1385,18 @@ public void ValidateTxNonces() { var privateKey = new PrivateKey(); var actions = new[] { new DumbAction(_fx.Address1, string.Empty) }; + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; Block MineNext(Block block, IReadOnlyList> txs) where T : IAction, new() => TestUtils.MineNext( block, + hashAlgorithm, txs, difficulty: 1024, blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); Transaction[] txsA = { @@ -1529,10 +1550,11 @@ internal static (Address, Address[] Addresses, BlockChain Chain) ) { IBlockPolicy blockPolicy = new NullPolicy(); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); store = new StoreTracker(store); Guid chainId = Guid.NewGuid(); Block genesisBlock = TestUtils.MineGenesis() - .AttachStateRootHash(stateStore, blockPolicy.BlockAction); + .AttachStateRootHash(hashAlgorithm, stateStore, blockPolicy.BlockAction); var chain = new BlockChain( blockPolicy, new VolatileStagePolicy(), @@ -1593,9 +1615,10 @@ void BuildIndex(Guid id, Block block) ); b = TestUtils.MineNext( b, + hashAlgorithm, new[] { tx }, blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(stateStore, blockPolicy.BlockAction); + .AttachStateRootHash(hashAlgorithm, stateStore, blockPolicy.BlockAction); previousStates = b.ProtocolVersion > 0 ? new AccountStateDeltaImpl( dirty.GetValueOrDefault, diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs index 5ed7e236f6..21cc08a16e 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs @@ -1,4 +1,5 @@ using System; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain.Renderers; using Libplanet.Blocks; @@ -19,12 +20,14 @@ public class AnonymousActionRendererTest private static Exception _exception = new Exception(); + private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); + private static Block _genesis = TestUtils.MineGenesis(default(Address)); - private static Block _blockA = TestUtils.MineNext(_genesis); + private static Block _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); - private static Block _blockB = TestUtils.MineNext(_genesis); + private static Block _blockB = TestUtils.MineNext(_genesis, _hashAlgorithm); [Fact] public void ActionRenderer() diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs index aaf20d44b9..f3d7e6c9ef 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography; using Libplanet.Blockchain.Renderers; using Libplanet.Blocks; using Libplanet.Tests.Common.Action; @@ -7,12 +8,14 @@ namespace Libplanet.Tests.Blockchain.Renderers { public class AnonymousRendererTest { + private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); + private static Block _genesis = TestUtils.MineGenesis(default(Address)); - private static Block _blockA = TestUtils.MineNext(_genesis); + private static Block _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); - private static Block _blockB = TestUtils.MineNext(_genesis); + private static Block _blockB = TestUtils.MineNext(_genesis, _hashAlgorithm); [Fact] public void BlockRenderer() diff --git a/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs index 3693d1f970..cec23ed5d0 100644 --- a/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using Libplanet.Blockchain; using Libplanet.Blockchain.Renderers; using Libplanet.Blocks; @@ -25,20 +26,25 @@ public class DelayedRendererTest #pragma warning disable S3963 static DelayedRendererTest() { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var chainA = new Block[10]; var chainB = new Block[chainA.Length]; chainA[0] = chainB[0] = TestUtils.MineGenesis(); for (int i = 1; i < chainA.Length / 2; i++) { _branchpoint = chainA[i] = chainB[i] = - TestUtils.MineNext(chainA[i - 1]); + TestUtils.MineNext(chainA[i - 1], hashAlgorithm); } int extraDifficulty = 1; for (int i = chainA.Length / 2; i < chainA.Length; i++) { - chainA[i] = TestUtils.MineNext(chainA[i - 1], difficulty: 2); - chainB[i] = TestUtils.MineNext(chainB[i - 1], difficulty: 2 + extraDifficulty); + chainA[i] = TestUtils.MineNext(chainA[i - 1], hashAlgorithm, difficulty: 2); + chainB[i] = TestUtils.MineNext( + chainB[i - 1], + hashAlgorithm, + difficulty: 2 + extraDifficulty + ); // The block right next the branchpoint in the chainB has 1 more difficulty than // the block with the same index in the chainA, and then rest blocks have the diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs index 758d998a01..722fbacfa7 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain.Renderers; using Libplanet.Tests.Common.Action; @@ -23,11 +24,13 @@ public class LoggedActionRendererTest : IDisposable private static Exception _exception = new Exception(); + private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); + private static DumbBlock _genesis = TestUtils.MineGenesis(default(Address)); - private static DumbBlock _blockA = TestUtils.MineNext(_genesis); + private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); - private static DumbBlock _blockB = TestUtils.MineNext(_genesis); + private static DumbBlock _blockB = TestUtils.MineNext(_genesis, _hashAlgorithm); private ILogger _logger; diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs index c7ee57ac97..bb6b0d7f06 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security.Cryptography; using Libplanet.Blockchain.Renderers; using Libplanet.Tests.Common.Action; using Serilog; @@ -15,11 +16,13 @@ namespace Libplanet.Tests.Blockchain.Renderers { public class LoggedRendererTest : IDisposable { + private static HashAlgorithmType _hashAlgorithmType = HashAlgorithmType.Of(); + private static DumbBlock _genesis = TestUtils.MineGenesis(default(Address)); - private static DumbBlock _blockA = TestUtils.MineNext(_genesis); + private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _hashAlgorithmType); - private static DumbBlock _blockB = TestUtils.MineNext(_genesis); + private static DumbBlock _blockB = TestUtils.MineNext(_genesis, _hashAlgorithmType); private ILogger _logger; diff --git a/Libplanet.Tests/Blocks/BlockFixture.cs b/Libplanet.Tests/Blocks/BlockFixture.cs index a52c91b0f4..76fd70941f 100644 --- a/Libplanet.Tests/Blocks/BlockFixture.cs +++ b/Libplanet.Tests/Blocks/BlockFixture.cs @@ -22,6 +22,7 @@ public BlockFixture() TxFixture = new TxFixture(Genesis.Hash); Next = TestUtils.MineNext( Genesis, + HashAlgorithm, nonce: new byte[] { 0x02, 0x00, 0x00, 0x00 }, protocolVersion: ProtocolVersion ); @@ -31,6 +32,7 @@ public BlockFixture() }; HasTx = TestUtils.MineNext( Next, + HashAlgorithm, new List>> { TxFixture.TxWithActions, diff --git a/Libplanet.Tests/Blocks/BlockTest.cs b/Libplanet.Tests/Blocks/BlockTest.cs index fd2f90156a..13c4f2b2f5 100644 --- a/Libplanet.Tests/Blocks/BlockTest.cs +++ b/Libplanet.Tests/Blocks/BlockTest.cs @@ -94,7 +94,7 @@ public void Mine() _fx.Genesis.Hash ); - Block> next = MineNext(_fx.Genesis); + Block> next = MineNext(_fx.Genesis, _fx.HashAlgorithm); Assert.Equal(1, _fx.Next.Index); Assert.Equal(1, _fx.Next.Difficulty); @@ -618,6 +618,7 @@ public void DetectInvalidTxSignature() Assert.Throws(() => MineNext( MineGenesis(), + HashAlgorithmType.Of(), new List> { invalidTx, @@ -660,6 +661,7 @@ public void DetectInvalidTxPublicKey() Assert.Throws(() => MineNext( MineGenesis(), + HashAlgorithmType.Of(), new List> { invalidTx, diff --git a/Libplanet.Tests/Fixtures/IntegerSet.cs b/Libplanet.Tests/Fixtures/IntegerSet.cs index 60696c7a2d..a45f583bf6 100644 --- a/Libplanet.Tests/Fixtures/IntegerSet.cs +++ b/Libplanet.Tests/Fixtures/IntegerSet.cs @@ -68,7 +68,7 @@ public IntegerSet( StateStore = new TrieStateStore(KVStore, KVStore); HashAlgorithmType algo = HashAlgorithmType.Of(); Genesis = Block.Mine(0, algo, 0, 0, Miner, null, DateTimeOffset.UtcNow, Txs) - .AttachStateRootHash(StateStore, policy.BlockAction); + .AttachStateRootHash(algo, StateStore, policy.BlockAction); Chain = new BlockChain( policy, new VolatileStagePolicy(), @@ -142,12 +142,13 @@ public TxWithContext Sign(int signerIndex, params Arithmetic[] actions) => public async Task> Mine(CancellationToken cancellationToken = default) { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block draft = await Chain.MineBlock( Miner, DateTimeOffset.UtcNow, cancellationToken: cancellationToken ); - return draft.AttachStateRootHash(StateStore, Policy.BlockAction); + return draft.AttachStateRootHash(hashAlgorithm, StateStore, Policy.BlockAction); } public IAccountStateDelta CreateAccountStateDelta(Address signer, BlockHash? offset = null) diff --git a/Libplanet.Tests/Net/BlockCompletionTest.cs b/Libplanet.Tests/Net/BlockCompletionTest.cs index 790961b518..e9195467e3 100644 --- a/Libplanet.Tests/Net/BlockCompletionTest.cs +++ b/Libplanet.Tests/Net/BlockCompletionTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Dasync.Collections; @@ -288,9 +289,10 @@ await AsyncEnumerable.ForEachAsync(rv, pair => [Fact(Timeout = Timeout)] public async Task CompleteWithBlockFetcherGivingWrongBlocks() { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block genesis = TestUtils.MineGenesis(), - demand = TestUtils.MineNext(genesis), - wrong = TestUtils.MineNext(genesis); + demand = TestUtils.MineNext(genesis, hashAlgorithm), + wrong = TestUtils.MineNext(genesis, hashAlgorithm); _logger.Debug("Genesis: #{Index} {Hash}", genesis.Index, genesis.Hash); _logger.Debug("Demand: #{Index} {Hash}", demand.Index, demand.Hash); _logger.Debug("Wrong: #{Index} {Hash}", wrong.Index, wrong.Hash); @@ -395,12 +397,13 @@ private IEnumerable> GenerateBlocks(int count) { if (count >= 1) { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = TestUtils.MineGenesis(); yield return block; for (int i = 1; i < count; i++) { - block = TestUtils.MineNext(block); + block = TestUtils.MineNext(block, hashAlgorithm); yield return block; } } diff --git a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs index 6d49d56020..1f9ae958e6 100644 --- a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs +++ b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Libplanet.Blockchain; @@ -631,19 +632,23 @@ public async Task BroadcastBlockWithSkip() await BootstrapAsync(receiverSwarm, minerSwarm.AsPeer); + HashAlgorithmType hashAlgo1 = HashAlgorithmType.Of(); var block1 = TestUtils.MineNext( blockChain.Genesis, + hashAlgo1, new[] { transactions[0] }, null, policy.GetNextBlockDifficulty(blockChain)) - .AttachStateRootHash(blockChain.StateStore, policy.BlockAction); + .AttachStateRootHash(hashAlgo1, blockChain.StateStore, policy.BlockAction); blockChain.Append(block1, DateTimeOffset.MinValue.AddSeconds(3), true, true, false); + HashAlgorithmType hashAlgo2 = HashAlgorithmType.Of(); var block2 = TestUtils.MineNext( block1, + hashAlgo2, new[] { transactions[1] }, null, policy.GetNextBlockDifficulty(blockChain)) - .AttachStateRootHash(blockChain.StateStore, policy.BlockAction); + .AttachStateRootHash(hashAlgo2, blockChain.StateStore, policy.BlockAction); blockChain.Append(block2, DateTimeOffset.MinValue.AddSeconds(8), true, true, false); Log.Debug("Ready to broadcast blocks."); minerSwarm.BroadcastBlock(block2); diff --git a/Libplanet.Tests/Net/SwarmTest.Consensus.cs b/Libplanet.Tests/Net/SwarmTest.Consensus.cs index f368117a15..cf5759fe17 100644 --- a/Libplanet.Tests/Net/SwarmTest.Consensus.cs +++ b/Libplanet.Tests/Net/SwarmTest.Consensus.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Security.Cryptography; using System.Threading.Tasks; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -58,17 +59,20 @@ public async Task DetermineCanonicalChain(short canonComparerType) await chain1.MineBlock(miner1.Address); await chain1.MineBlock(miner2.Address); + HashAlgorithmType hashAlgorithm; Block bestBlock; switch (canonComparerType) { default: long nextDifficulty = (long)chain1.Tip.TotalDifficulty + policy.GetNextBlockDifficulty(chain2); + hashAlgorithm = HashAlgorithmType.Of(); bestBlock = TestUtils.MineNext( chain2.Tip, + hashAlgorithm, difficulty: nextDifficulty, blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash(chain2.StateStore, policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, chain2.StateStore, policy.BlockAction); _output.WriteLine("chain1's total difficulty: {0}", chain1.Tip.TotalDifficulty); _output.WriteLine("chain2's total difficulty: {0}", bestBlock.TotalDifficulty); break; @@ -78,11 +82,13 @@ public async Task DetermineCanonicalChain(short canonComparerType) string hashStr; do { + hashAlgorithm = HashAlgorithmType.Of(); bestBlock = TestUtils.MineNext( chain2.Tip, + hashAlgorithm, difficulty: policy.GetNextBlockDifficulty(chain2), blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash(chain2.StateStore, policy.BlockAction); + ).AttachStateRootHash(hashAlgorithm, chain2.StateStore, policy.BlockAction); hashStr = bestBlock.Hash.ToString(); _output.WriteLine("chain1's tip hash: {0}", chain1.Tip.Hash); _output.WriteLine("chain2's tip hash: {0}", bestBlock.Hash); diff --git a/Libplanet.Tests/Net/SwarmTest.Preload.cs b/Libplanet.Tests/Net/SwarmTest.Preload.cs index 3bd86267f2..5db02a489b 100644 --- a/Libplanet.Tests/Net/SwarmTest.Preload.cs +++ b/Libplanet.Tests/Net/SwarmTest.Preload.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Bencodex.Types; @@ -111,10 +112,13 @@ public async Task Preload() var blocks = new List>(); foreach (int i in Enumerable.Range(0, 11)) { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = TestUtils.MineNext( previousBlock: i == 0 ? minerChain.Genesis : blocks[i - 1], + hashAlgorithm: hashAlgorithm, difficulty: 1024) .AttachStateRootHash( + hashAlgorithm, minerChain.StateStore, minerChain.Policy.BlockAction); blocks.Add(block); @@ -323,12 +327,18 @@ public async Task PreloadWithFailedActions() DateTimeOffset.UtcNow ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block = TestUtils.MineNext( minerChain.Tip, + hashAlgorithm, new[] { tx }, difficulty: policy.GetNextBlockDifficulty(minerChain), - blockInterval: TimeSpan.FromSeconds(1)) - .AttachStateRootHash(minerChain.StateStore, minerChain.Policy.BlockAction); + blockInterval: TimeSpan.FromSeconds(1) + ).AttachStateRootHash( + hashAlgorithm, + minerChain.StateStore, + minerChain.Policy.BlockAction + ); minerSwarm.BlockChain.Append(block, DateTimeOffset.UtcNow, false, true, false); await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(1)); @@ -790,10 +800,18 @@ public async Task PreloadFromTheMostDifficultChain() await minerChain1.MineBlock(minerSwarm1.Address); await minerChain1.MineBlock(minerSwarm1.Address); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); long nextDifficulty = (long)minerChain1.Tip.TotalDifficulty + minerChain2.Policy.GetNextBlockDifficulty(minerChain2); - var block = TestUtils.MineNext(minerChain2.Tip, difficulty: nextDifficulty) - .AttachStateRootHash(minerChain2.StateStore, minerChain2.Policy.BlockAction); + var block = TestUtils.MineNext( + minerChain2.Tip, + hashAlgorithm, + difficulty: nextDifficulty + ).AttachStateRootHash( + hashAlgorithm, + minerChain2.StateStore, + minerChain2.Policy.BlockAction + ); minerChain2.Append(block); Assert.True(minerChain1.Count > minerChain2.Count); diff --git a/Libplanet.Tests/Net/SwarmTest.cs b/Libplanet.Tests/Net/SwarmTest.cs index 2c0167412f..0a59c351a1 100644 --- a/Libplanet.Tests/Net/SwarmTest.cs +++ b/Libplanet.Tests/Net/SwarmTest.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Bencodex.Types; @@ -713,11 +714,13 @@ public async Task RemoveForkedChainWhenFillBlocksAsyncFail() await chain2.MineBlock(swarm2.Address); // Creates a block that will make chain 2's total difficulty is higher than chain 1's. + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block3 = TestUtils.MineNext( chain2.Tip, + hashAlgorithm, difficulty: (long)chain1.Tip.TotalDifficulty + 1, blockInterval: TimeSpan.FromMilliseconds(1)) - .AttachStateRootHash(chain2.StateStore, chain2.Policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, chain2.StateStore, chain2.Policy.BlockAction); chain2.Append(block3); try { @@ -813,11 +816,13 @@ public async Task ForkByDifficulty() await chain1.MineBlock(miner2.Address); long nextDifficulty = (long)chain1.Tip.TotalDifficulty + policy.GetNextBlockDifficulty(chain2); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block = TestUtils.MineNext( chain2.Tip, + hashAlgorithm, difficulty: nextDifficulty, blockInterval: TimeSpan.FromMilliseconds(1)) - .AttachStateRootHash(chain2.StateStore, policy.BlockAction); + .AttachStateRootHash(hashAlgorithm, chain2.StateStore, policy.BlockAction); chain2.Append(block); Assert.True(chain1.Tip.Index > chain2.Tip.Index); @@ -1419,9 +1424,11 @@ public async Task DoNotFillWhenGetAllBlockAtFirstTimeFromSender() for (int i = 0; i < 6; i++) { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = - TestUtils.MineNext(sender.BlockChain.Tip, difficulty: 1024) + TestUtils.MineNext(sender.BlockChain.Tip, hashAlgorithm, difficulty: 1024) .AttachStateRootHash( + hashAlgorithm, sender.BlockChain.StateStore, sender.BlockChain.Policy.BlockAction); sender.BlockChain.Append(block); @@ -1460,9 +1467,11 @@ public async Task FillWhenGetAllBlocksFromSender() for (int i = 0; i < 6; i++) { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = - TestUtils.MineNext(sender.BlockChain.Tip, difficulty: 1024) + TestUtils.MineNext(sender.BlockChain.Tip, hashAlgorithm, difficulty: 1024) .AttachStateRootHash( + hashAlgorithm, sender.BlockChain.StateStore, sender.BlockChain.Policy.BlockAction); sender.BlockChain.Append(block); @@ -1499,9 +1508,11 @@ public async Task DoNotFillMultipleTimes() await StartAsync(sender1); await StartAsync(sender2); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block b1 = - TestUtils.MineNext(receiver.BlockChain.Genesis, difficulty: 1024) + TestUtils.MineNext(receiver.BlockChain.Genesis, hashAlgorithm, difficulty: 1024) .AttachStateRootHash( + hashAlgorithm, sender1.BlockChain.StateStore, sender1.BlockChain.Policy.BlockAction); diff --git a/Libplanet.Tests/Store/BlockSetTest.cs b/Libplanet.Tests/Store/BlockSetTest.cs index 60df6e07fb..006c23d092 100644 --- a/Libplanet.Tests/Store/BlockSetTest.cs +++ b/Libplanet.Tests/Store/BlockSetTest.cs @@ -15,7 +15,7 @@ public class BlockSetTest : IDisposable public BlockSetTest() { _fx = new DefaultStoreFixture(); - _set = new BlockSet(_fx.Store); + _set = new BlockSet(_ => _fx.HashAlgorithm, _fx.Store); } [Fact] diff --git a/Libplanet.Tests/Store/StoreFixture.cs b/Libplanet.Tests/Store/StoreFixture.cs index 6cd3ad74a9..67da0e9831 100644 --- a/Libplanet.Tests/Store/StoreFixture.cs +++ b/Libplanet.Tests/Store/StoreFixture.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blocks; using Libplanet.Crypto; @@ -92,11 +93,15 @@ protected StoreFixture(IAction blockAction = null) var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); + HashAlgorithm = HashAlgorithmType.Of(); GenesisBlock = TestUtils.MineGenesis() - .AttachStateRootHash(stateStore, blockAction); - Block1 = TestUtils.MineNext(GenesisBlock).AttachStateRootHash(stateStore, blockAction); - Block2 = TestUtils.MineNext(Block1).AttachStateRootHash(stateStore, blockAction); - Block3 = TestUtils.MineNext(Block2).AttachStateRootHash(stateStore, blockAction); + .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); + Block1 = TestUtils.MineNext(GenesisBlock, HashAlgorithm) + .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); + Block2 = TestUtils.MineNext(Block1, HashAlgorithm) + .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); + Block3 = TestUtils.MineNext(Block2, HashAlgorithm) + .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); Transaction1 = MakeTransaction(new List(), ImmutableHashSet
.Empty); Transaction2 = MakeTransaction(new List(), ImmutableHashSet
.Empty); @@ -131,6 +136,8 @@ protected StoreFixture(IAction blockAction = null) public BlockHash Hash3 { get; } + public HashAlgorithmType HashAlgorithm { get; set; } + public Block GenesisBlock { get; } public Block Block1 { get; } diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index 608f720cb1..30ac3c4e19 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -87,6 +87,7 @@ public void DeleteChainId() { Block block1 = TestUtils.MineNext( TestUtils.MineGenesis(), + Fx.HashAlgorithm, new[] { Fx.Transaction1 }); Fx.Store.AppendIndex(Fx.StoreChainId, block1.Hash); Guid arbitraryChainId = Guid.NewGuid(); @@ -995,7 +996,7 @@ public void ForkWithBranch() // We need `Block`s because `IStore` can't retrive index(long) by block hash without // actual block... - Block anotherBlock3 = TestUtils.MineNext(Fx.Block2); + Block anotherBlock3 = TestUtils.MineNext(Fx.Block2, Fx.HashAlgorithm); store.PutBlock(Fx.GenesisBlock); store.PutBlock(Fx.Block1); store.PutBlock(Fx.Block2); @@ -1095,6 +1096,7 @@ public void GetBlock() // NOTE: it depends on that Block.CurrentProtocolVersion is not 0. Block block = TestUtils.MineNext( genesisBlock, + fx.HashAlgorithm, protocolVersion: 0); fx.Store.PutBlock(block); diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 04cd8f97c0..eea60258c2 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -209,6 +209,7 @@ public static Block MineGenesis( public static Block MineNext( Block previousBlock, + HashAlgorithmType hashAlgorithm, IReadOnlyList> txs = null, byte[] nonce = null, long difficulty = 1, @@ -228,7 +229,6 @@ public static Block MineNext( DateTimeOffset timestamp = previousBlock.Timestamp.Add(blockInterval ?? TimeSpan.FromSeconds(15)); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block; if (nonce == null) { @@ -265,7 +265,11 @@ public static Block MineNext( } public static Block AttachStateRootHash( - this Block block, IStateStore stateStore, IAction blockAction) + this Block block, + HashAlgorithmType hashAlgorithm, + IStateStore stateStore, + IAction blockAction + ) where T : IAction, new() { IValue StateGetter( @@ -293,7 +297,7 @@ FungibleAssetValue FungibleAssetValueGetter( } var actionEvaluator = new ActionEvaluator( - hashAlgorithmGetter: _ => HashAlgorithmType.Of(), + hashAlgorithmGetter: _ => hashAlgorithm, policyBlockAction: blockAction, stateGetter: StateGetter, balanceGetter: FungibleAssetValueGetter, @@ -343,6 +347,8 @@ public static BlockChain MakeBlockChain( } ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + var tx = Transaction.Create( 0, privateKey, @@ -360,7 +366,11 @@ public static BlockChain MakeBlockChain( new[] { tx }, protocolVersion: protocolVersion ); - genesisBlock = genesisBlock.AttachStateRootHash(stateStore, policy.BlockAction); + genesisBlock = genesisBlock.AttachStateRootHash( + hashAlgorithm, + stateStore, + policy.BlockAction + ); ValidatingActionRenderer validator = null; #pragma warning disable S1121 var chain = new BlockChain( diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 8c98167dd6..73a28fdce0 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -147,7 +147,7 @@ IEnumerable> renderers throw new ArgumentNullException(nameof(stateStore)); } - _blocks = new BlockSet(store); + _blocks = new BlockSet(_ => HashAlgorithmType.Of(), store); Renderers = renderers is IEnumerable> r ? r.ToImmutableArray() : ImmutableArray>.Empty; @@ -1865,7 +1865,7 @@ internal void Swap( Guid obsoleteId = Id; Id = other.Id; Store.SetCanonicalChainId(Id); - _blocks = new BlockSet(Store); + _blocks = new BlockSet(_ => HashAlgorithmType.Of(), Store); TipChanged?.Invoke(this, (oldTip, newTip)); if (render) diff --git a/Libplanet/Store/BlockSet.cs b/Libplanet/Store/BlockSet.cs index be436685c6..de85ee3eb3 100644 --- a/Libplanet/Store/BlockSet.cs +++ b/Libplanet/Store/BlockSet.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blocks; using LruCacheNet; @@ -12,11 +11,13 @@ namespace Libplanet.Store public class BlockSet : BaseIndex> where T : IAction, new() { + private readonly HashAlgorithmGetter _hashAlgorithmGetter; private readonly LruCache> _cache; - public BlockSet(IStore store, int cacheSize = 4096) + public BlockSet(HashAlgorithmGetter hashAlgorithmGetter, IStore store, int cacheSize = 4096) : base(store) { + _hashAlgorithmGetter = hashAlgorithmGetter; _cache = new LruCache>(cacheSize); } @@ -63,7 +64,7 @@ public override Block this[BlockHash key] $"{value}.hash does not match to {key}"); } - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmType hashAlgorithm = _hashAlgorithmGetter(value.Index); value.Validate(hashAlgorithm, DateTimeOffset.UtcNow); Store.PutBlock(value); _cache.AddOrUpdate(value.Hash, value); From 136785fe37d91602362bf158f7fb9ce148bc6fb2 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 09:51:04 +0900 Subject: [PATCH 16/22] BlockHash.DeriveFrom() method --- Libplanet.Tests/Blocks/BlockHashTest.cs | 16 ++++++++++++++++ Libplanet/Blocks/Block.cs | 3 +-- Libplanet/Blocks/BlockHash.cs | 15 +++++++++++++++ Libplanet/Blocks/BlockHeader.cs | 2 +- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Libplanet.Tests/Blocks/BlockHashTest.cs b/Libplanet.Tests/Blocks/BlockHashTest.cs index 7906250680..984c14d548 100644 --- a/Libplanet.Tests/Blocks/BlockHashTest.cs +++ b/Libplanet.Tests/Blocks/BlockHashTest.cs @@ -84,6 +84,22 @@ public void FromHashDigest() ); } + [Fact] + public void DeriveFrom() + { + byte[] foo = { 0x66, 0x6f, 0x6f }, bar = { 0x62, 0x61, 0x72 }; + TestUtils.AssertBytesEqual( + BlockHash.FromString( + "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"), + BlockHash.DeriveFrom(foo) + ); + TestUtils.AssertBytesEqual( + BlockHash.FromString( + "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"), + BlockHash.DeriveFrom(bar) + ); + } + [Fact] public void FromImmutableArrayConstructor() { diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index d5aff21d73..a5af2a6f79 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -87,8 +87,7 @@ public Block( hashAlgorithm.Digest(Header.SerializeForHash()).ToImmutableArray(); StateRootHash = stateRootHash; - // FIXME: This does not need to be computed every time? - Hash = new BlockHash(hashAlgorithm.Digest(Header.SerializeForHash())); + Hash = BlockHash.DeriveFrom(Header.SerializeForHash()); // As the order of transactions should be unpredictable until a block is mined, // the sorter key should be derived from both a block hash and a txid. diff --git a/Libplanet/Blocks/BlockHash.cs b/Libplanet/Blocks/BlockHash.cs index 694dce5430..c5569ccba0 100644 --- a/Libplanet/Blocks/BlockHash.cs +++ b/Libplanet/Blocks/BlockHash.cs @@ -1,7 +1,9 @@ #nullable enable using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.Contracts; +using System.Linq; using System.Runtime.Serialization; using System.Security.Cryptography; using Libplanet.Serialization; @@ -104,6 +106,19 @@ public static BlockHash FromString(string hex) => public static BlockHash FromHashDigest(HashDigest hashDigest) => new BlockHash(hashDigest.ByteArray); + /// + /// Computes a SHA-256 digest from the given . + /// + /// The bytes serializing a block to compute its hash. + /// The SHA-256 hash digest derived from . + [Pure] + public static BlockHash DeriveFrom(IReadOnlyList blockBytes) + { + SHA256 sha256 = SHA256.Create(); + byte[] digest = sha256.ComputeHash(blockBytes is byte[] b ? b : blockBytes.ToArray()); + return new BlockHash(digest); + } + /// /// Gets a bare mutable array of the block hash. /// diff --git a/Libplanet/Blocks/BlockHeader.cs b/Libplanet/Blocks/BlockHeader.cs index 26eccafd14..2a107b2964 100644 --- a/Libplanet/Blocks/BlockHeader.cs +++ b/Libplanet/Blocks/BlockHeader.cs @@ -403,7 +403,7 @@ internal void Validate(HashAlgorithmType hashAlgorithm, DateTimeOffset currentTi ); } - BlockHash calculatedHash = new BlockHash(hashAlgorithm.Digest(SerializeForHash())); + BlockHash calculatedHash = BlockHash.DeriveFrom(SerializeForHash()); if (!hash.Equals(calculatedHash)) { throw new InvalidBlockHashException( From 563143eae5c5a8cb687f41d3587c92937fbbde3c Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 11:37:09 +0900 Subject: [PATCH 17/22] Add hashAlgorithm param to Block() ctor --- CHANGES.md | 4 ++ Libplanet.Benchmarks/Store.cs | 3 +- Libplanet.Benchmarks/SwarmBenchmark.cs | 4 +- .../GraphTypes/BlockTypeTest.cs | 1 + .../Commands/StoreCommandTest.cs | 4 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 14 ++++-- .../BlockChainTest.ValidateNextBlock.cs | 2 +- Libplanet.Tests/Blockchain/BlockChainTest.cs | 19 +++---- .../Renderers/AnonymousActionRendererTest.cs | 2 +- .../Renderers/AnonymousRendererTest.cs | 2 +- .../Renderers/DelayedRendererTest.cs | 2 +- .../Renderers/LoggedActionRendererTest.cs | 3 +- .../Renderers/LoggedRendererTest.cs | 3 +- Libplanet.Tests/Blocks/BlockFixture.cs | 1 + Libplanet.Tests/Blocks/BlockTest.cs | 43 ++++++++++------ Libplanet.Tests/Net/BlockCompletionTest.cs | 4 +- Libplanet.Tests/Net/Messages/MessageTest.cs | 3 +- Libplanet.Tests/Net/SwarmTest.Broadcast.cs | 4 +- Libplanet.Tests/Net/SwarmTest.Preload.cs | 9 +++- Libplanet.Tests/Store/StoreFixture.cs | 2 +- Libplanet.Tests/Store/StoreTest.cs | 2 +- Libplanet.Tests/TestUtils.cs | 4 ++ Libplanet/Action/ActionEvaluator.cs | 4 +- Libplanet/Blockchain/BlockChain.cs | 6 ++- Libplanet/Blocks/Block.cs | 49 ++++++++++++++++--- 25 files changed, 135 insertions(+), 59 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cd0da93683..7f029c518d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -108,6 +108,10 @@ To be released. (was `ImmutableHashSet>`). - Hash algorithm for PoW (Hashcash) became configurable. [#1314], [#1352] + - Added optional `HashAlgorithmType? hashAlgorithm` parameter to + `Block(long, long, BigInteger, Nonce, Address?, BlockHash?, + DateTimeOffset, IReadOnlyList>, ImmutableArray?, + HashDigest?, int protocolVersion)` constructor. - Added `HashAlgorithmType hashAlgorithm` parameter to `Block.MineBlock()` method. - The type of `Block.PreEvaluationHash` property became diff --git a/Libplanet.Benchmarks/Store.cs b/Libplanet.Benchmarks/Store.cs index 63960d9fbc..18b0a018c6 100644 --- a/Libplanet.Benchmarks/Store.cs +++ b/Libplanet.Benchmarks/Store.cs @@ -14,6 +14,7 @@ namespace Libplanet.Benchmarks { public class Store { + private readonly HashAlgorithmType HashAlgorithmType = HashAlgorithmType.Of(); private readonly ImmutableArray> Blocks = default; private readonly int BlocksCount = default; private readonly ImmutableArray> Txs = default; @@ -25,7 +26,7 @@ public Store() { var blocks = new List>(); var txs = new List>(); - Block genesis = TestUtils.MineGenesis(); + Block genesis = TestUtils.MineGenesis(HashAlgorithmType); blocks.Add(genesis); Block block = genesis; var key = new PrivateKey(); diff --git a/Libplanet.Benchmarks/SwarmBenchmark.cs b/Libplanet.Benchmarks/SwarmBenchmark.cs index 577bf3b2c6..0e9d34a13d 100644 --- a/Libplanet.Benchmarks/SwarmBenchmark.cs +++ b/Libplanet.Benchmarks/SwarmBenchmark.cs @@ -38,12 +38,12 @@ public SwarmBenchmark() { _policy = new NullPolicy(); _stagePolicy = new VolatileStagePolicy(); + _hashAlgorithm = HashAlgorithmType.Of(); _blocks = new List> { - TestUtils.MineGenesis(), + TestUtils.MineGenesis(_hashAlgorithm), }; _appProtocolVersion = AppProtocolVersion.Sign(new PrivateKey(), 1); - _hashAlgorithm = HashAlgorithmType.Of(); _blocks.Add(TestUtils.MineNext(_blocks[0], _hashAlgorithm)); _blocks.Add(TestUtils.MineNext(_blocks[1], _hashAlgorithm)); _blocks.Add(TestUtils.MineNext(_blocks[2], _hashAlgorithm)); diff --git a/Libplanet.Explorer.UnitTests/GraphTypes/BlockTypeTest.cs b/Libplanet.Explorer.UnitTests/GraphTypes/BlockTypeTest.cs index b5d7d2a5e6..b697702f5d 100644 --- a/Libplanet.Explorer.UnitTests/GraphTypes/BlockTypeTest.cs +++ b/Libplanet.Explorer.UnitTests/GraphTypes/BlockTypeTest.cs @@ -27,6 +27,7 @@ public async void Query() new BlockHash(TestUtils.GetRandomBytes(HashDigest.Size)), DateTimeOffset.UtcNow, ImmutableArray>.Empty, + HashAlgorithmType.Of(), stateRootHash: new HashDigest( TestUtils.GetRandomBytes(HashDigest.Size))); var query = diff --git a/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs b/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs index 29adef5ee1..b1a8c0cd22 100644 --- a/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs +++ b/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs @@ -47,13 +47,13 @@ public StoreCommandTest() throw new SkipException("RocksDB is not available."); } - _genesisBlock = TestUtils.MineGenesis(); + _hashAlgorithm = HashAlgorithmType.Of(); + _genesisBlock = TestUtils.MineGenesis(_hashAlgorithm); _transaction1 = DummyTransaction(); _transaction2 = DummyTransaction(); _transaction3 = DummyTransaction(); _transaction4 = DummyTransaction(); - _hashAlgorithm = HashAlgorithmType.Of(); _block1 = TestUtils.MineNext(_genesisBlock, _hashAlgorithm, new[] { _transaction1 }); _block2 = TestUtils.MineNext(_block1, _hashAlgorithm, new[] { _transaction2 }); _block3 = TestUtils.MineNext(_block2, _hashAlgorithm, new[] { _transaction3 }); diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 629c879def..0f399f085d 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -70,9 +70,11 @@ public void Idempotent() new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var noStateRootBlock = TestUtils.MineGenesis( + hashAlgorithm: hashAlgorithm, timestamp: timestamp, transactions: txs); var stateRootBlock = TestUtils.MineGenesis( + hashAlgorithm: hashAlgorithm, timestamp: timestamp, transactions: txs).AttachStateRootHash(hashAlgorithm, stateStore, null); var actionEvaluator = @@ -273,7 +275,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _txFx.Address5, }; HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - Block genesis = MineGenesis(); + Block genesis = MineGenesis(hashAlgorithm); ActionEvaluator actionEvaluator = new ActionEvaluator( hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, @@ -571,7 +573,9 @@ public void EvaluateTx() miner: addresses[0], previousHash: null, timestamp: DateTimeOffset.UtcNow, - transactions: ImmutableArray.Create(tx)); + transactions: ImmutableArray.Create(tx), + hashAlgorithm: HashAlgorithmType.Of() + ); var actionEvaluator = new ActionEvaluator( hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, @@ -697,7 +701,7 @@ public void EvaluateBlockWithInvalidTxUpdatedAddresses() _txFx.TxWithActions .ToRawTransaction(false).Actions.ToImmutableArray(); Block> genesis = - TestUtils.MineGenesis>(); + TestUtils.MineGenesis>(hashAlgorithm); RawTransaction rawTxWithoutSig = new RawTransaction( 0, _txFx.Address1.ByteArray, @@ -779,7 +783,9 @@ public void EvaluateTxResultThrowingException() miner: GenesisMinerAddress, previousHash: null, timestamp: DateTimeOffset.UtcNow, - transactions: ImmutableArray.Create(tx)); + transactions: ImmutableArray.Create(tx), + hashAlgorithm: HashAlgorithmType.Of() + ); var nextStates = actionEvaluator.EvaluateTxResult( block: block, tx: tx, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index d1812af6db..946e498acf 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -196,7 +196,7 @@ private void ValidateNextBlockInvalidStateRootHash() // Actually, it depends on BlockChain to update states and it makes hard to // calculate state root hash. To resolve this problem, // it should be moved into StateStore. - var genesisBlock = TestUtils.MineGenesis() + var genesisBlock = TestUtils.MineGenesis(_fx.HashAlgorithm) .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, policy.BlockAction); var store = new DefaultStore(null); var chain = new BlockChain( diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index e90e7f14e7..4aefaf4fbf 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -583,12 +583,8 @@ public async Task ForkShouldSkipExecuteAndRenderGenesis() new MemoryKeyValueStore(), new MemoryKeyValueStore())) { var genesis = TestUtils.MineGenesis( - transactions: new[] - { - _fx.MakeTransaction( - new[] { action } - ), - } + hashAlgorithm, + transactions: new[] { _fx.MakeTransaction(new[] { action }) } ).AttachStateRootHash(hashAlgorithm, stateStore, _policy.BlockAction); store.PutBlock(genesis); var renderer = new RecordingActionRenderer(); @@ -1016,9 +1012,10 @@ public async Task ReorgIsUnableToHeterogenousChain(bool render) memory: true, blockAction: _policy.BlockAction)) { HashAlgorithmType hashAlgorithm = fx2.HashAlgorithm; - Block genesis2 = - TestUtils.MineGenesis(timestamp: DateTimeOffset.UtcNow) - .AttachStateRootHash(hashAlgorithm, fx2.StateStore, _policy.BlockAction); + Block genesis2 = TestUtils.MineGenesis( + hashAlgorithm, + timestamp: DateTimeOffset.UtcNow + ).AttachStateRootHash(hashAlgorithm, fx2.StateStore, _policy.BlockAction); var chain2 = new BlockChain( _blockChain.Policy, _blockChain.StagePolicy, @@ -1553,7 +1550,7 @@ internal static (Address, Address[] Addresses, BlockChain Chain) HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); store = new StoreTracker(store); Guid chainId = Guid.NewGuid(); - Block genesisBlock = TestUtils.MineGenesis() + Block genesisBlock = TestUtils.MineGenesis(hashAlgorithm) .AttachStateRootHash(hashAlgorithm, stateStore, blockPolicy.BlockAction); var chain = new BlockChain( blockPolicy, @@ -1845,7 +1842,7 @@ private void ConstructBlockchainWithGenesisBlockHavingStateRootHash() var store = new DefaultStore(null); var stateStore = new TrieStateStore( new MemoryKeyValueStore(), new MemoryKeyValueStore()); - var genesisBlock = TestUtils.MineGenesis(); + var genesisBlock = TestUtils.MineGenesis(HashAlgorithmType.Of()); BlockChain blockChain = TestUtils.MakeBlockChain( _blockChain.Policy, store, stateStore, genesisBlock: genesisBlock); diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs index 21cc08a16e..dacd4d6582 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs @@ -23,7 +23,7 @@ public class AnonymousActionRendererTest private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); private static Block _genesis = - TestUtils.MineGenesis(default(Address)); + TestUtils.MineGenesis(_hashAlgorithm, default(Address)); private static Block _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs index f3d7e6c9ef..51f19ce424 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs @@ -11,7 +11,7 @@ public class AnonymousRendererTest private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); private static Block _genesis = - TestUtils.MineGenesis(default(Address)); + TestUtils.MineGenesis(_hashAlgorithm, default(Address)); private static Block _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); diff --git a/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs index cec23ed5d0..7505defcc7 100644 --- a/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs @@ -29,7 +29,7 @@ static DelayedRendererTest() HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var chainA = new Block[10]; var chainB = new Block[chainA.Length]; - chainA[0] = chainB[0] = TestUtils.MineGenesis(); + chainA[0] = chainB[0] = TestUtils.MineGenesis(hashAlgorithm); for (int i = 1; i < chainA.Length / 2; i++) { _branchpoint = chainA[i] = chainB[i] = diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs index 722fbacfa7..8ad8157078 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs @@ -26,7 +26,8 @@ public class LoggedActionRendererTest : IDisposable private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); - private static DumbBlock _genesis = TestUtils.MineGenesis(default(Address)); + private static DumbBlock _genesis = + TestUtils.MineGenesis(_hashAlgorithm, default(Address)); private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs index bb6b0d7f06..dd24e743ed 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs @@ -18,7 +18,8 @@ public class LoggedRendererTest : IDisposable { private static HashAlgorithmType _hashAlgorithmType = HashAlgorithmType.Of(); - private static DumbBlock _genesis = TestUtils.MineGenesis(default(Address)); + private static DumbBlock _genesis = + TestUtils.MineGenesis(_hashAlgorithmType, default(Address)); private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _hashAlgorithmType); diff --git a/Libplanet.Tests/Blocks/BlockFixture.cs b/Libplanet.Tests/Blocks/BlockFixture.cs index 76fd70941f..459558171e 100644 --- a/Libplanet.Tests/Blocks/BlockFixture.cs +++ b/Libplanet.Tests/Blocks/BlockFixture.cs @@ -17,6 +17,7 @@ public BlockFixture() { HashAlgorithm = HashAlgorithmType.Of(); Genesis = TestUtils.MineGenesis>( + hashAlgorithm: HashAlgorithm, protocolVersion: ProtocolVersion ); TxFixture = new TxFixture(Genesis.Hash); diff --git a/Libplanet.Tests/Blocks/BlockTest.cs b/Libplanet.Tests/Blocks/BlockTest.cs index 13c4f2b2f5..83e65a87e8 100644 --- a/Libplanet.Tests/Blocks/BlockTest.cs +++ b/Libplanet.Tests/Blocks/BlockTest.cs @@ -55,7 +55,8 @@ public void Transactions() miner: null, previousHash: null, timestamp: DateTimeOffset.UtcNow, - transactions: txs + transactions: txs, + hashAlgorithm: HashAlgorithmType.Of() ); // For transactions signed by the same signer, these should be ordered by its tx nonce. @@ -204,7 +205,7 @@ public void DetectInvalidProtocolVersion() DateTimeOffset now = DateTimeOffset.UtcNow; Block block = Block.Mine( _fx.Next.Index, - HashAlgorithmType.Of(), + _fx.HashAlgorithm, _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -219,7 +220,7 @@ public void DetectInvalidProtocolVersion() block = Block.Mine( _fx.Next.Index, - HashAlgorithmType.Of(), + _fx.HashAlgorithm, _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -287,7 +288,8 @@ public void DetectInvalidDifficulty() miner: _fx.Genesis.Miner, previousHash: _fx.Genesis.PreviousHash, timestamp: _fx.Genesis.Timestamp, - transactions: MineGenesis().Transactions + transactions: MineGenesis(_fx.HashAlgorithm).Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Assert.Throws(() => invalidDifficultyGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) @@ -301,7 +303,8 @@ public void DetectInvalidDifficulty() miner: _fx.Genesis.Miner, previousHash: _fx.Genesis.PreviousHash, timestamp: _fx.Genesis.Timestamp, - transactions: MineGenesis().Transactions + transactions: MineGenesis(_fx.HashAlgorithm).Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Assert.Throws(() => invalidTotalDifficultyGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) @@ -315,7 +318,8 @@ public void DetectInvalidDifficulty() miner: _fx.Next.Miner, previousHash: _fx.Next.PreviousHash, timestamp: _fx.Next.Timestamp, - transactions: _fx.Next.Transactions + transactions: _fx.Next.Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Assert.Throws(() => invalidDifficultyNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) @@ -329,7 +333,8 @@ public void DetectInvalidDifficulty() miner: _fx.Next.Miner, previousHash: _fx.Next.PreviousHash, timestamp: _fx.Next.Timestamp, - transactions: _fx.Next.Transactions + transactions: _fx.Next.Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Assert.Throws(() => invalidTotalDifficultyNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) @@ -347,7 +352,8 @@ public void DetectInvalidPreviousHash() miner: _fx.Genesis.Miner, previousHash: new BlockHash(GetRandomBytes(32)), // invalid timestamp: _fx.Genesis.Timestamp, - transactions: MineGenesis().Transactions + transactions: MineGenesis(_fx.HashAlgorithm).Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Assert.Throws(() => @@ -362,7 +368,8 @@ public void DetectInvalidPreviousHash() miner: _fx.Next.Miner, previousHash: null, timestamp: _fx.Next.Timestamp, - transactions: _fx.Next.Transactions + transactions: _fx.Next.Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Assert.Throws(() => @@ -463,7 +470,8 @@ public void CanCompareToOtherBlock() miner: sameBlock1.Miner, previousHash: null, timestamp: sameBlock1.Timestamp, - transactions: sameBlock1.Transactions + transactions: sameBlock1.Transactions, + hashAlgorithm: _fx.HashAlgorithm ); Block> differentBlock = _fx.Next; @@ -509,8 +517,9 @@ public void TransactionOrderIdempotent() new PrivateKey(), null, new[] { new RandomAction(signer.ToAddress()) })).ToImmutableArray(); - var blockA = MineGenesis(timestamp: timestamp, transactions: txs); - var blockB = MineGenesis(timestamp: timestamp, transactions: txs); + HashAlgorithmType algo = HashAlgorithmType.Of(); + var blockA = MineGenesis(algo, timestamp: timestamp, transactions: txs); + var blockB = MineGenesis(algo, timestamp: timestamp, transactions: txs); Assert.True(blockA.Transactions.SequenceEqual(blockB.Transactions)); } @@ -526,7 +535,8 @@ public void BytesLength() miner: null, previousHash: null, timestamp: DateTimeOffset.UtcNow, - transactions: new Transaction[0] + transactions: new Transaction[0], + hashAlgorithm: HashAlgorithmType.Of() ); Assert.Equal(146, block.BytesLength); } @@ -549,7 +559,8 @@ public void ValidateTxHash() miner: null, previousHash: null, timestamp: DateTimeOffset.UtcNow, - transactions: txs + transactions: txs, + hashAlgorithm: HashAlgorithmType.Of() ); block.Validate(hashAlgorithm, DateTimeOffset.UtcNow); @@ -617,7 +628,7 @@ public void DetectInvalidTxSignature() var invalidTx = new Transaction(rawTx); Assert.Throws(() => MineNext( - MineGenesis(), + MineGenesis(_fx.HashAlgorithm), HashAlgorithmType.Of(), new List> { @@ -660,7 +671,7 @@ public void DetectInvalidTxPublicKey() ); Assert.Throws(() => MineNext( - MineGenesis(), + MineGenesis(_fx.HashAlgorithm), HashAlgorithmType.Of(), new List> { diff --git a/Libplanet.Tests/Net/BlockCompletionTest.cs b/Libplanet.Tests/Net/BlockCompletionTest.cs index e9195467e3..1dcfc9be33 100644 --- a/Libplanet.Tests/Net/BlockCompletionTest.cs +++ b/Libplanet.Tests/Net/BlockCompletionTest.cs @@ -290,7 +290,7 @@ await AsyncEnumerable.ForEachAsync(rv, pair => public async Task CompleteWithBlockFetcherGivingWrongBlocks() { HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - Block genesis = TestUtils.MineGenesis(), + Block genesis = TestUtils.MineGenesis(hashAlgorithm), demand = TestUtils.MineNext(genesis, hashAlgorithm), wrong = TestUtils.MineNext(genesis, hashAlgorithm); _logger.Debug("Genesis: #{Index} {Hash}", genesis.Index, genesis.Hash); @@ -398,7 +398,7 @@ private IEnumerable> GenerateBlocks(int count) if (count >= 1) { HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - Block block = TestUtils.MineGenesis(); + Block block = TestUtils.MineGenesis(hashAlgorithm); yield return block; for (int i = 1; i < count; i++) diff --git a/Libplanet.Tests/Net/Messages/MessageTest.cs b/Libplanet.Tests/Net/Messages/MessageTest.cs index e9315c6bde..7f5b0a767d 100644 --- a/Libplanet.Tests/Net/Messages/MessageTest.cs +++ b/Libplanet.Tests/Net/Messages/MessageTest.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.Linq; using System.Net; +using System.Security.Cryptography; using Libplanet.Crypto; using Libplanet.Net; using Libplanet.Net.Messages; @@ -140,7 +141,7 @@ public void BlockHeaderMessage() ImmutableArray.Empty, default(Address)); var dateTimeOffset = DateTimeOffset.UtcNow; - var genesis = TestUtils.MineGenesis(); + var genesis = TestUtils.MineGenesis(HashAlgorithmType.Of()); var message = new BlockHeaderMessage(genesis.Hash, genesis.Header); NetMQMessage raw = message.ToNetMQMessage(privateKey, peer, dateTimeOffset, appProtocolVersion); diff --git a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs index 1f9ae958e6..cfa1741b62 100644 --- a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs +++ b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs @@ -99,7 +99,9 @@ public async Task BroadcastIgnoreFromDifferentGenesisHash() receiverSwarm.Address, null, DateTimeOffset.MinValue, - ImmutableArray>.Empty); + ImmutableArray>.Empty, + HashAlgorithmType.Of() + ); BlockChain seedChain = TestUtils.MakeBlockChain( receiverChain.Policy, new DefaultStore(path: null), diff --git a/Libplanet.Tests/Net/SwarmTest.Preload.cs b/Libplanet.Tests/Net/SwarmTest.Preload.cs index 5db02a489b..5565db5c45 100644 --- a/Libplanet.Tests/Net/SwarmTest.Preload.cs +++ b/Libplanet.Tests/Net/SwarmTest.Preload.cs @@ -842,6 +842,7 @@ public async Task PreloadIgnorePeerWithDifferentGenesisBlock() { var minerAddress = new PrivateKey().ToAddress(); var policy = new BlockPolicy(); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesisBlock1 = new Block( 0, 0, @@ -850,7 +851,9 @@ public async Task PreloadIgnorePeerWithDifferentGenesisBlock() minerAddress, null, DateTimeOffset.MinValue, - ImmutableArray>.Empty); + ImmutableArray>.Empty, + hashAlgorithm + ); var genesisBlock2 = new Block( 0, 0, @@ -859,7 +862,9 @@ public async Task PreloadIgnorePeerWithDifferentGenesisBlock() minerAddress, null, DateTimeOffset.MinValue, - ImmutableArray>.Empty); + ImmutableArray>.Empty, + hashAlgorithm + ); BlockChain MakeBlockChain(Block genesisBlock) => TestUtils.MakeBlockChain( diff --git a/Libplanet.Tests/Store/StoreFixture.cs b/Libplanet.Tests/Store/StoreFixture.cs index 67da0e9831..01ec5d39bd 100644 --- a/Libplanet.Tests/Store/StoreFixture.cs +++ b/Libplanet.Tests/Store/StoreFixture.cs @@ -94,7 +94,7 @@ protected StoreFixture(IAction blockAction = null) var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); HashAlgorithm = HashAlgorithmType.Of(); - GenesisBlock = TestUtils.MineGenesis() + GenesisBlock = TestUtils.MineGenesis(HashAlgorithm) .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); Block1 = TestUtils.MineNext(GenesisBlock, HashAlgorithm) .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index 30ac3c4e19..39e68fb09a 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -86,7 +86,7 @@ public void ListChainIdAfterForkAndDelete() public void DeleteChainId() { Block block1 = TestUtils.MineNext( - TestUtils.MineGenesis(), + TestUtils.MineGenesis(Fx.HashAlgorithm), Fx.HashAlgorithm, new[] { Fx.Transaction1 }); Fx.Store.AppendIndex(Fx.StoreChainId, block1.Hash); diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index eea60258c2..149f6344b3 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -180,6 +180,7 @@ public static byte[] GetRandomBytes(int size) } public static Block MineGenesis( + HashAlgorithmType hashAlgorithm, Address? miner = null, IReadOnlyList> transactions = null, DateTimeOffset? timestamp = null, @@ -201,6 +202,7 @@ public static Block MineGenesis( previousHash: null, timestamp: timestamp ?? new DateTimeOffset(2018, 11, 29, 0, 0, 0, TimeSpan.Zero), transactions: transactions, + hashAlgorithm: hashAlgorithm, protocolVersion: protocolVersion ); @@ -255,6 +257,7 @@ public static Block MineNext( previousHash: previousHash, timestamp: timestamp, transactions: txs, + hashAlgorithm: hashAlgorithm, protocolVersion: protocolVersion ); } @@ -364,6 +367,7 @@ public static BlockChain MakeBlockChain( null, timestamp ?? DateTimeOffset.MinValue, new[] { tx }, + hashAlgorithm: hashAlgorithm, protocolVersion: protocolVersion ); genesisBlock = genesisBlock.AttachStateRootHash( diff --git a/Libplanet/Action/ActionEvaluator.cs b/Libplanet/Action/ActionEvaluator.cs index 04719073bd..8aca659225 100644 --- a/Libplanet/Action/ActionEvaluator.cs +++ b/Libplanet/Action/ActionEvaluator.cs @@ -43,7 +43,9 @@ public class ActionEvaluator miner: null, previousHash: null, timestamp: DateTimeOffset.UtcNow, - transactions: ImmutableArray>.Empty); + transactions: ImmutableArray>.Empty, + hashAlgorithm: HashAlgorithmType.Of() + ); private static readonly ILogger _logger = Log.ForContext>(); private readonly HashAlgorithmGetter _hashAlgorithmGetter; diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 73a28fdce0..58c0d7e70c 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -803,6 +803,8 @@ public async Task> MineBlock( procId ); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + ImmutableArray> stagedTransactions = ListStagedTransactions(); _logger.Debug( "There are {Transactions} staged transactions.", @@ -824,7 +826,8 @@ public async Task> MineBlock( miner: miner, previousHash: prevHash, timestamp: currentTime, - transactions: new Transaction[0] + transactions: new Transaction[0], + hashAlgorithm: hashAlgorithm ).BytesLength; int maxBlockBytes = Math.Max(Policy.GetMaxBlockBytes(index), 1); var skippedSigners = new HashSet
(); @@ -952,7 +955,6 @@ public async Task> MineBlock( stagedTransactions.Length ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block; try { diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index a5af2a6f79..82820227b3 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -50,13 +50,22 @@ public class Block : IBlockExcerpt /// Transactions become sorted in an unpredicted-before-mined order and then go to /// the property. /// + /// The hash algorithm for proof-of-work, if and only if + /// is omitted. /// The hash derived from the block except of /// (i.e., without action evaluation). - /// Automatically determined if null is passed (which is default). + /// Automatically determined if null is passed, but + /// is needed in that case. /// The of the states on the block. /// /// The protocol version. /// by default. + /// Thrown when both + /// and are omitted. + /// + /// Thrown when both + /// and , which are mutually exclusive, are present. + /// /// public Block( long index, @@ -67,6 +76,7 @@ public Block( BlockHash? previousHash, DateTimeOffset timestamp, IReadOnlyList> transactions, + HashAlgorithmType hashAlgorithm = null, ImmutableArray? preEvaluationHash = null, HashDigest? stateRootHash = null, int protocolVersion = CurrentProtocolVersion) @@ -82,9 +92,34 @@ public Block( Transactions = transactions.OrderBy(tx => tx.Id).ToArray(); TxHash = CalculateTxHashes(Transactions); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - PreEvaluationHash = preEvaluationHash ?? - hashAlgorithm.Digest(Header.SerializeForHash()).ToImmutableArray(); + // FIXME: This constructor needs to be separated into two overloads, which are one + // taking only hashAlgorithm and other one taking only preEvaluationHash, so that + // the compiler can check whether two parameters are both omitted or both passed + // if any chance. + if (preEvaluationHash is { } hash) + { + if (hashAlgorithm is { }) + { + throw new ArgumentException( + $"The parameters {nameof(hashAlgorithm)} and {nameof(preEvaluationHash)} " + + "are mutually exclusive.", + paramName: nameof(preEvaluationHash) + ); + } + + PreEvaluationHash = hash; + } + else if (hashAlgorithm is { } algo) + { + PreEvaluationHash = algo.Digest(Header.SerializeForHash()).ToImmutableArray(); + } + else + { + string message = $"Either {nameof(hashAlgorithm)} or {nameof(preEvaluationHash)} " + + "must to be passed."; + throw new ArgumentNullException(nameof(preEvaluationHash), message); + } + StateRootHash = stateRootHash; Hash = BlockHash.DeriveFrom(Header.SerializeForHash()); @@ -150,8 +185,9 @@ public Block( block.PreviousHash, block.Timestamp, block.Transactions, - block.PreEvaluationHash, - stateRootHash, + hashAlgorithm: null, + preEvaluationHash: block.PreEvaluationHash, + stateRootHash: stateRootHash, protocolVersion: block.ProtocolVersion ) { @@ -385,6 +421,7 @@ public static Block Mine( previousHash, timestamp, txs, + hashAlgorithm: hashAlgorithm, protocolVersion: protocolVersion); // Poor man' way to optimize stamp... From 0a97720ca52848d407408ded012c986aee1a9825 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 12:02:21 +0900 Subject: [PATCH 18/22] Add hashAlgorithm param to BlockChain.MakeGenesisBlock() --- CHANGES.md | 4 ++- Libplanet.Benchmarks/SwarmBenchmark.cs | 2 +- Libplanet.Tests/Blockchain/BlockChainTest.cs | 25 +++++++++++-------- Libplanet.Tests/Net/SwarmTest.cs | 5 ++-- Libplanet/Blockchain/BlockChain.cs | 26 +++++++++++--------- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7f029c518d..307a69ac1d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -140,7 +140,9 @@ To be released. - Removed `Hashcash.Hash()` method. - Removed `HashDigest.Satisfies()` method. This was replaced by `ByteUtil.Satisfies()` method instead. [[#1192], [#1197]] - - Added `hashAlgorithmGetter` parameter to `BlockSet()` constructor. + - Added `hashAlgorithmGetter` parameter to `BlockSet()` constructor. + - Added `hashAlgorithm` parameter to `BlockChain.MakeGenesisBlock()` + method. - Added `IActionContext.TxId` property. [[#1275]] - Added `IStore.PutTxExecution(TxSuccess)` method. [[#1156], [#1289]] - Added `IStore.PutTxExecution(TxFailure)` method. [[#1156], [#1289]] diff --git a/Libplanet.Benchmarks/SwarmBenchmark.cs b/Libplanet.Benchmarks/SwarmBenchmark.cs index 0e9d34a13d..5aa189e76d 100644 --- a/Libplanet.Benchmarks/SwarmBenchmark.cs +++ b/Libplanet.Benchmarks/SwarmBenchmark.cs @@ -58,7 +58,7 @@ public void InitializeSwarms() _blockChains = new BlockChain[SwarmNumber]; _swarms = new Swarm[SwarmNumber]; - var genesisBlock = BlockChain.MakeGenesisBlock(); + var genesisBlock = BlockChain.MakeGenesisBlock(_hashAlgorithm); var tasks = new List(); for (int i = 0; i < SwarmNumber; i++) { diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 4aefaf4fbf..5c319ae900 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -181,7 +181,9 @@ public async void BlockHashes() [Fact] public async void ProcessActions() { - var genesisBlock = BlockChain>.MakeGenesisBlock(); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + Block> genesisBlock = + BlockChain>.MakeGenesisBlock(hashAlgorithm); var store = new DefaultStore(path: null); var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); @@ -1136,11 +1138,11 @@ public void GetStateReturnsEarlyForNonexistentAccount() [Fact] public async void GetStateReturnsValidStateAfterFork() { - var genesisBlock = BlockChain.MakeGenesisBlock( - new[] - { - new DumbAction(_fx.Address1, "item0.0", idempotent: true), - }); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + Block genesisBlock = BlockChain.MakeGenesisBlock( + hashAlgorithm, + new[] { new DumbAction(_fx.Address1, "item0.0", idempotent: true) } + ); var privateKey = new PrivateKey(); var store = new DefaultStore(path: null); var stateStore = @@ -1226,6 +1228,7 @@ public async void GetStateReturnsLatestStatesWhenMultipleAddresses() [Fact] public async void FindBranchPoint() { + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block b1 = await _blockChain.MineBlock(_fx.Address1); Block b2 = await _blockChain.MineBlock(_fx.Address1); Block b3 = await _blockChain.MineBlock(_fx.Address1); @@ -1241,7 +1244,7 @@ public async void FindBranchPoint() using (var forkFx = new DefaultStoreFixture( memory: true, blockAction: _policy.BlockAction)) { - var genesisBlock = BlockChain.MakeGenesisBlock(); + var genesisBlock = BlockChain.MakeGenesisBlock(hashAlgorithm); var emptyChain = new BlockChain( _blockChain.Policy, new VolatileStagePolicy(), @@ -1754,6 +1757,7 @@ private void ConstructWithGenesisBlock() { var storeFixture = new DefaultStoreFixture(); var policy = new NullPolicy(); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var addresses = ImmutableList
.Empty .Add(storeFixture.Address1) @@ -1770,7 +1774,7 @@ private void ConstructWithGenesisBlock() new VolatileStagePolicy(), storeFixture.Store, storeFixture.StateStore, - BlockChain.MakeGenesisBlock(actions)); + BlockChain.MakeGenesisBlock(hashAlgorithm, actions)); Assert.Equal(addresses, blockChain.Genesis.Transactions.First().UpdatedAddresses); @@ -1786,12 +1790,13 @@ private void ConstructWithGenesisBlock() private void ConstructWithUnexpectedGenesisBlock() { var policy = new NullPolicy(); + HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var stagePolicy = new VolatileStagePolicy(); var store = new DefaultStore(null); var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); - var genesisBlockA = BlockChain.MakeGenesisBlock(); - var genesisBlockB = BlockChain.MakeGenesisBlock(); + var genesisBlockA = BlockChain.MakeGenesisBlock(hashAlgorithm); + var genesisBlockB = BlockChain.MakeGenesisBlock(hashAlgorithm); var blockChain = new BlockChain( policy, diff --git a/Libplanet.Tests/Net/SwarmTest.cs b/Libplanet.Tests/Net/SwarmTest.cs index 0a59c351a1..1a8e1dc951 100644 --- a/Libplanet.Tests/Net/SwarmTest.cs +++ b/Libplanet.Tests/Net/SwarmTest.cs @@ -1216,8 +1216,9 @@ public async Task DoNotReceiveBlockFromNodeHavingDifferenceGenesisBlock() var actionsA = new[] { new DumbAction(signerAddress, "1") }; var actionsB = new[] { new DumbAction(signerAddress, "2") }; - var genesisBlockA = BlockChain.MakeGenesisBlock(actionsA, privateKeyA); - var genesisBlockB = BlockChain.MakeGenesisBlock(actionsB, privateKeyB); + HashAlgorithmType alg = HashAlgorithmType.Of(); + var genesisBlockA = BlockChain.MakeGenesisBlock(alg, actionsA, privateKeyA); + var genesisBlockB = BlockChain.MakeGenesisBlock(alg, actionsB, privateKeyB); BlockChain MakeGenesisChain( IStore store, IStateStore stateStore, Block genesisBlock) => diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 58c0d7e70c..f8670dc930 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -359,6 +359,8 @@ public Block this[in BlockHash blockHash] /// /// Mine the genesis block of the blockchain. /// + /// The hash algorithm for proof-of-work on the genesis block. + /// /// List of actions will be included in the genesis block. /// If it's null, it will be replaced with /// as default. @@ -371,6 +373,7 @@ public Block this[in BlockHash blockHash] /// /// The genesis block mined with parameters. public static Block MakeGenesisBlock( + HashAlgorithmType hashAlgorithm, IEnumerable actions = null, PrivateKey privateKey = null, DateTimeOffset? timestamp = null, @@ -384,17 +387,18 @@ public static Block MakeGenesisBlock( }; Block block = Block.Mine( - 0, - HashAlgorithmType.Of(), - 0, - 0, - privateKey.ToAddress(), - null, - timestamp ?? DateTimeOffset.UtcNow, - transactions); + index: 0, + hashAlgorithm: hashAlgorithm, + difficulty: 0, + previousTotalDifficulty: 0, + miner: privateKey.ToAddress(), + previousHash: null, + timestamp: timestamp ?? DateTimeOffset.UtcNow, + transactions: transactions + ); var actionEvaluator = new ActionEvaluator( - _ => HashAlgorithmType.Of(), + _ => hashAlgorithm, blockAction, (address, digest, stateCompleter) => null, (address, currency, hash, fungibleAssetStateCompleter) @@ -407,9 +411,7 @@ public static Block MakeGenesisBlock( trie = trie.Set(actionEvaluationResult); var stateRootHash = trie.Commit(rehearsal: true).Hash; - return new Block( - block, - stateRootHash); + return new Block(block, stateRootHash); } /// From af12db6c4673beddc890f58075b9d68d783cf2a2 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 13:54:55 +0900 Subject: [PATCH 19/22] Add IBlockPolicy.GetHashAlgorithm() method --- CHANGES.md | 1 + Libplanet.Benchmarks/Store.cs | 4 +- Libplanet.Benchmarks/SwarmBenchmark.cs | 16 +- Libplanet.Explorer.Executable/Program.cs | 3 + .../Commands/StoreCommandTest.cs | 17 +- .../Action/AccountStateDeltaImplTest.cs | 10 +- .../Action/AccountStateDeltaImplV0Test.cs | 10 +- .../Action/AccountStateDeltaTest.cs | 10 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 26 +- .../Blockchain/BlockChainTest.Append.cs | 91 ++++--- .../Blockchain/BlockChainTest.Internals.cs | 8 +- .../BlockChainTest.MultiAlgorithms.cs | 64 +++++ .../BlockChainTest.ValidateNextBlock.cs | 51 ++-- Libplanet.Tests/Blockchain/BlockChainTest.cs | 226 ++++++++++-------- Libplanet.Tests/Blockchain/NullPolicy.cs | 6 +- .../Renderers/AnonymousActionRendererTest.cs | 8 +- .../Renderers/AnonymousRendererTest.cs | 8 +- .../Renderers/DelayedRendererTest.cs | 9 +- .../Renderers/LoggedActionRendererTest.cs | 6 +- .../Renderers/LoggedRendererTest.cs | 6 +- Libplanet.Tests/Blocks/BlockFixture.cs | 15 +- Libplanet.Tests/Blocks/BlockHeaderTest.cs | 20 +- Libplanet.Tests/Blocks/BlockTest.cs | 76 +++--- Libplanet.Tests/Fixtures/IntegerSet.cs | 20 +- Libplanet.Tests/Net/BlockCompletionTest.cs | 19 +- Libplanet.Tests/Net/Messages/MessageTest.cs | 2 +- Libplanet.Tests/Net/SwarmTest.Broadcast.cs | 26 +- Libplanet.Tests/Net/SwarmTest.Consensus.cs | 16 +- Libplanet.Tests/Net/SwarmTest.Preload.cs | 15 +- Libplanet.Tests/Net/SwarmTest.cs | 56 ++--- Libplanet.Tests/Store/BlockSetTest.cs | 2 +- Libplanet.Tests/Store/StoreFixture.cs | 21 +- Libplanet.Tests/Store/StoreTest.cs | 8 +- Libplanet.Tests/TestUtils.cs | 22 +- Libplanet/Blockchain/BlockChain.cs | 10 +- Libplanet/Blockchain/Policies/BlockPolicy.cs | 5 + Libplanet/Blockchain/Policies/IBlockPolicy.cs | 8 + Libplanet/Blocks/Block.cs | 4 +- Libplanet/Net/Swarm.MessageHandlers.cs | 3 +- Libplanet/Net/Swarm.cs | 4 +- 40 files changed, 550 insertions(+), 382 deletions(-) create mode 100644 Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs diff --git a/CHANGES.md b/CHANGES.md index 307a69ac1d..6149914aa4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -108,6 +108,7 @@ To be released. (was `ImmutableHashSet>`). - Hash algorithm for PoW (Hashcash) became configurable. [#1314], [#1352] + - Added `IBlockPolicy.GetHashAlgorithm()` method. - Added optional `HashAlgorithmType? hashAlgorithm` parameter to `Block(long, long, BigInteger, Nonce, Address?, BlockHash?, DateTimeOffset, IReadOnlyList>, ImmutableArray?, diff --git a/Libplanet.Benchmarks/Store.cs b/Libplanet.Benchmarks/Store.cs index 18b0a018c6..a32c52642b 100644 --- a/Libplanet.Benchmarks/Store.cs +++ b/Libplanet.Benchmarks/Store.cs @@ -26,7 +26,7 @@ public Store() { var blocks = new List>(); var txs = new List>(); - Block genesis = TestUtils.MineGenesis(HashAlgorithmType); + Block genesis = TestUtils.MineGenesis(_ => HashAlgorithmType); blocks.Add(genesis); Block block = genesis; var key = new PrivateKey(); @@ -38,7 +38,7 @@ public Store() { blockTxs.Add(Transaction.Create(nonce++, key, genesis.Hash, new DumbAction[0])); } - block = TestUtils.MineNext(block, HashAlgorithmType.Of(), blockTxs); + block = TestUtils.MineNext(block, _ => HashAlgorithmType, blockTxs); blocks.Add(block); txs.AddRange(blockTxs); } diff --git a/Libplanet.Benchmarks/SwarmBenchmark.cs b/Libplanet.Benchmarks/SwarmBenchmark.cs index 5aa189e76d..4a656d389d 100644 --- a/Libplanet.Benchmarks/SwarmBenchmark.cs +++ b/Libplanet.Benchmarks/SwarmBenchmark.cs @@ -28,7 +28,6 @@ public class SwarmBenchmark private readonly IStagePolicy _stagePolicy; private readonly List> _blocks; private readonly AppProtocolVersion _appProtocolVersion; - private readonly HashAlgorithmType _hashAlgorithm; private PrivateKey[] _keys; private DefaultStoreFixture[] _fxs; private BlockChain[] _blockChains; @@ -38,16 +37,15 @@ public SwarmBenchmark() { _policy = new NullPolicy(); _stagePolicy = new VolatileStagePolicy(); - _hashAlgorithm = HashAlgorithmType.Of(); _blocks = new List> { - TestUtils.MineGenesis(_hashAlgorithm), + TestUtils.MineGenesis(_policy.GetHashAlgorithm), }; _appProtocolVersion = AppProtocolVersion.Sign(new PrivateKey(), 1); - _blocks.Add(TestUtils.MineNext(_blocks[0], _hashAlgorithm)); - _blocks.Add(TestUtils.MineNext(_blocks[1], _hashAlgorithm)); - _blocks.Add(TestUtils.MineNext(_blocks[2], _hashAlgorithm)); - _blocks.Add(TestUtils.MineNext(_blocks[3], _hashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[0], _policy.GetHashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[1], _policy.GetHashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[2], _policy.GetHashAlgorithm)); + _blocks.Add(TestUtils.MineNext(_blocks[3], _policy.GetHashAlgorithm)); } [IterationSetup(Targets = new[] {"BroadcastBlock", "BroadcastBlockWithoutFill"})] @@ -58,7 +56,9 @@ public void InitializeSwarms() _blockChains = new BlockChain[SwarmNumber]; _swarms = new Swarm[SwarmNumber]; - var genesisBlock = BlockChain.MakeGenesisBlock(_hashAlgorithm); + var genesisBlock = BlockChain.MakeGenesisBlock( + _blockChains[SwarmNumber].Policy.GetHashAlgorithm(0) + ); var tasks = new List(); for (int i = 0; i < SwarmNumber; i++) { diff --git a/Libplanet.Explorer.Executable/Program.cs b/Libplanet.Explorer.Executable/Program.cs index 2a733c0ee9..73d65934f3 100644 --- a/Libplanet.Explorer.Executable/Program.cs +++ b/Libplanet.Explorer.Executable/Program.cs @@ -433,6 +433,9 @@ BlockChain blocks, Block nextBlock { return _impl.ValidateNextBlock(blocks, nextBlock); } + + public HashAlgorithmType GetHashAlgorithm(long index) => + _impl.GetHashAlgorithm(index); } internal class AppAgnosticAction : IAction diff --git a/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs b/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs index b1a8c0cd22..afd23c931d 100644 --- a/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs +++ b/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs @@ -18,7 +18,6 @@ public class StoreCommandTest : IDisposable { private readonly ImmutableArray _storeFixtures; private readonly TextWriter _originalWriter; - private readonly HashAlgorithmType _hashAlgorithm; private readonly Block _genesisBlock; private readonly Block _block1; private readonly Block _block2; @@ -47,18 +46,17 @@ public StoreCommandTest() throw new SkipException("RocksDB is not available."); } - _hashAlgorithm = HashAlgorithmType.Of(); - _genesisBlock = TestUtils.MineGenesis(_hashAlgorithm); + _genesisBlock = TestUtils.MineGenesis(GetHashAlgorithm); _transaction1 = DummyTransaction(); _transaction2 = DummyTransaction(); _transaction3 = DummyTransaction(); _transaction4 = DummyTransaction(); - _block1 = TestUtils.MineNext(_genesisBlock, _hashAlgorithm, new[] { _transaction1 }); - _block2 = TestUtils.MineNext(_block1, _hashAlgorithm, new[] { _transaction2 }); - _block3 = TestUtils.MineNext(_block2, _hashAlgorithm, new[] { _transaction3 }); - _block4 = TestUtils.MineNext(_block3, _hashAlgorithm, new[] { _transaction3 }); - _block5 = TestUtils.MineNext(_block4, _hashAlgorithm); + _block1 = TestUtils.MineNext(_genesisBlock, GetHashAlgorithm, new[] { _transaction1 }); + _block2 = TestUtils.MineNext(_block1, GetHashAlgorithm, new[] { _transaction2 }); + _block3 = TestUtils.MineNext(_block2, GetHashAlgorithm, new[] { _transaction3 }); + _block4 = TestUtils.MineNext(_block3, GetHashAlgorithm, new[] { _transaction3 }); + _block5 = TestUtils.MineNext(_block4, GetHashAlgorithm); var guid = Guid.NewGuid(); foreach (var v in _storeFixtures) @@ -313,6 +311,9 @@ public void Dispose() Console.SetOut(_originalWriter); } + private HashAlgorithmType GetHashAlgorithm(long blockIndex) => + HashAlgorithmType.Of(); + private Transaction DummyTransaction() { return Transaction.Create( diff --git a/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs b/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs index b823cd1cda..afd84f83e6 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs @@ -1,4 +1,3 @@ -using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Blocks; @@ -56,14 +55,17 @@ public override BlockChain TransferAssetInBlock() chain.Genesis.Hash, new[] { action } ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); chain.Append( TestUtils.MineNext( chain.Tip, - hashAlgorithm, + chain.Policy.GetHashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash(hashAlgorithm, chain.StateStore, chain.Policy.BlockAction) + ).AttachStateRootHash( + chain.Policy.GetHashAlgorithm, + chain.StateStore, + chain.Policy.BlockAction + ) ); Assert.Equal( DumbAction.DumbCurrency * 5, diff --git a/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs b/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs index 7c42451632..3090d51b0e 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs @@ -1,4 +1,3 @@ -using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Tests.Common.Action; @@ -55,14 +54,17 @@ public override BlockChain TransferAssetInBlock() chain.Genesis.Hash, new[] { action } ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); chain.Append( TestUtils.MineNext( chain.Tip, - hashAlgorithm, + chain.Policy.GetHashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash(hashAlgorithm, chain.StateStore, chain.Policy.BlockAction) + ).AttachStateRootHash( + chain.Policy.GetHashAlgorithm, + chain.StateStore, + chain.Policy.BlockAction + ) ); Assert.Equal( DumbAction.DumbCurrency * 6, diff --git a/Libplanet.Tests/Action/AccountStateDeltaTest.cs b/Libplanet.Tests/Action/AccountStateDeltaTest.cs index b371c48cfc..f075ca3fd6 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaTest.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaTest.cs @@ -3,7 +3,6 @@ using System.Collections.Immutable; using System.Linq; using System.Numerics; -using System.Security.Cryptography; using Bencodex.Types; using Libplanet.Action; using Libplanet.Assets; @@ -209,7 +208,6 @@ public virtual BlockChain TransferAssetInBlock() protocolVersion: ProtocolVersion ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); DumbAction action = new DumbAction(_addr[0], "a", _addr[1], _addr[0], 5); Transaction tx = Transaction.Create( 0, @@ -220,10 +218,14 @@ public virtual BlockChain TransferAssetInBlock() chain.Append( TestUtils.MineNext( chain.Tip, - hashAlgorithm, + chain.Policy.GetHashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash(hashAlgorithm, stateStore, chain.Policy.BlockAction) + ).AttachStateRootHash( + chain.Policy.GetHashAlgorithm, + stateStore, + chain.Policy.BlockAction + ) ); Assert.Equal( DumbAction.DumbCurrency * 5, diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 0f399f085d..6210984e76 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -68,15 +68,15 @@ public void Idempotent() }; var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmGetter hashAlgorithmGetter = _ => HashAlgorithmType.Of(); var noStateRootBlock = TestUtils.MineGenesis( - hashAlgorithm: hashAlgorithm, + hashAlgorithmGetter: hashAlgorithmGetter, timestamp: timestamp, transactions: txs); var stateRootBlock = TestUtils.MineGenesis( - hashAlgorithm: hashAlgorithm, + hashAlgorithmGetter: hashAlgorithmGetter, timestamp: timestamp, - transactions: txs).AttachStateRootHash(hashAlgorithm, stateStore, null); + transactions: txs).AttachStateRootHash(hashAlgorithmGetter, stateStore, null); var actionEvaluator = new ActionEvaluator( hashAlgorithmGetter: _ => HashAlgorithmType.Of(), @@ -275,7 +275,8 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _txFx.Address5, }; HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - Block genesis = MineGenesis(hashAlgorithm); + HashAlgorithmGetter hashAlgoGetter = _ => hashAlgorithm; + Block genesis = MineGenesis(hashAlgoGetter); ActionEvaluator actionEvaluator = new ActionEvaluator( hashAlgorithmGetter: _ => HashAlgorithmType.Of(), policyBlockAction: null, @@ -327,7 +328,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _logger.Debug("{0}[{1}] = {2}", nameof(block1Txs), i, tx.Id); } - Block block1 = MineNext(genesis, hashAlgorithm, block1Txs, new byte[] { }); + Block block1 = MineNext(genesis, hashAlgoGetter, block1Txs, new byte[] { }); previousStates = block1.ProtocolVersion > 0 ? new AccountStateDeltaImpl( ActionEvaluator.NullAccountStateGetter, @@ -446,7 +447,7 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu _logger.Debug("{0}[{1}] = {2}", nameof(block2Txs), i, tx.Id); } - Block block2 = MineNext(block1, hashAlgorithm, block2Txs, new byte[] { }); + Block block2 = MineNext(block1, hashAlgoGetter, block2Txs, new byte[] { }); AccountStateGetter accountStateGetter = dirty1.GetValueOrDefault; AccountBalanceGetter accountBalanceGetter = (address, currency) => balances1.TryGetValue((address, currency), out FungibleAssetValue v) @@ -696,12 +697,12 @@ prevEval is null [Fact] public void EvaluateBlockWithInvalidTxUpdatedAddresses() { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmGetter hashAlgorithmGetter = _ => HashAlgorithmType.Of(); ImmutableArray rawActions = _txFx.TxWithActions .ToRawTransaction(false).Actions.ToImmutableArray(); Block> genesis = - TestUtils.MineGenesis>(hashAlgorithm); + TestUtils.MineGenesis>(hashAlgorithmGetter); RawTransaction rawTxWithoutSig = new RawTransaction( 0, _txFx.Address1.ByteArray, @@ -728,7 +729,7 @@ public void EvaluateBlockWithInvalidTxUpdatedAddresses() sig.ToImmutableArray())); Block> invalidBlock = TestUtils.MineNext( previousBlock: genesis, - hashAlgorithm: hashAlgorithm, + hashAlgorithmGetter: hashAlgorithmGetter, txs: new List>> { invalidTx }); var actionEvaluator = new ActionEvaluator>( @@ -924,16 +925,15 @@ public void EvaluatePolicyBlockAction() store: _storeFx.Store, stateStore: _storeFx.StateStore, genesisBlock: _storeFx.GenesisBlock); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); (var addresses, Transaction[] txs) = MakeFixturesForAppendTests(); var genesis = chain.Genesis; var block = TestUtils.MineNext( genesis, - hashAlgorithm, + _policy.GetHashAlgorithm, txs, difficulty: chain.Policy.GetNextBlockDifficulty(chain) - ).AttachStateRootHash(hashAlgorithm, chain.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_policy.GetHashAlgorithm, chain.StateStore, _policy.BlockAction); var stateCompleterSet = StateCompleterSet.Recalculate; AccountStateGetter accountStateGetter = diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index 9cc117e092..f441bb90f7 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -34,8 +34,6 @@ Func getTxExecution ? (Func)_blockChain.Store.GetTxExecution : _blockChain.GetTxExecution; - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - (Address[] addresses, Transaction[] txs) = MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; @@ -44,20 +42,28 @@ Func getTxExecution Assert.Empty(_renderer.ActionRecords); Assert.Empty(_renderer.BlockRecords); var block1 = TestUtils.MineNext( - genesis, - hashAlgorithm, - miner: addresses[4], - difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + genesis, + _blockChain.Policy.GetHashAlgorithm, + miner: addresses[4], + difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash( + _blockChain.Policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); _blockChain.Append(block1); Block block2 = TestUtils.MineNext( block1, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, txs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash( + _blockChain.Policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); foreach (Transaction tx in txs) { Assert.Null(getTxExecution(genesis.Hash, tx.Id)); @@ -205,10 +211,14 @@ Func getTxExecution ); Block block3 = TestUtils.MineNext( block2, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, new[] { tx1Transfer, tx2Error, tx3Transfer }, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash( + _blockChain.Policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); _blockChain.Append(block3); var txExecution1 = getTxExecution(block3.Hash, tx1Transfer.Id); _logger.Verbose(nameof(txExecution1) + " = {@TxExecution}", txExecution1); @@ -322,7 +332,7 @@ public void AppendThrowsInvalidBlockBytesLengthException() var block1 = TestUtils.MineNext( _blockChain.Genesis, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, heavyTxs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) @@ -357,7 +367,7 @@ public void AppendThrowsBlockExceedingTransactionsException() var block1 = TestUtils.MineNext( _blockChain.Genesis, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, manyTxs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) @@ -377,12 +387,11 @@ public void AppendWithoutEvaluateActions() { (_, Transaction[] txs) = MakeFixturesForAppendTests(); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; var block = TestUtils.MineNext( genesis, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, difficulty: 1024, blockInterval: TimeSpan.FromSeconds(10)); Assert.Throws(() => @@ -451,7 +460,6 @@ bool IsSignerValid(Transaction tx, BlockChain chain) var policy = new BlockPolicy(doesTransactionFollowPolicy: IsSignerValid); using (var fx = new DefaultStoreFixture()) { - HashAlgorithmType hashAlgorithm = fx.HashAlgorithm; var blockChain = new BlockChain( policy, new VolatileStagePolicy(), @@ -466,23 +474,31 @@ bool IsSignerValid(Transaction tx, BlockChain chain) Block block1 = TestUtils.MineNext( fx.GenesisBlock, - hashAlgorithm, + policy.GetHashAlgorithm, new[] { validTx }, miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, blockChain.StateStore, policy.BlockAction); + ).AttachStateRootHash( + policy.GetHashAlgorithm, + blockChain.StateStore, + policy.BlockAction + ); blockChain.Append(block1); Block block2 = TestUtils.MineNext( block1, - hashAlgorithm, + policy.GetHashAlgorithm, new[] { invalidTx }, miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, blockChain.StateStore, policy.BlockAction); + ).AttachStateRootHash( + policy.GetHashAlgorithm, + blockChain.StateStore, + policy.BlockAction + ); Assert.Throws(() => blockChain.Append(block2)); } @@ -494,16 +510,19 @@ public void UnstageAfterAppendComplete() PrivateKey privateKey = new PrivateKey(); (Address[] addresses, Transaction[] txs) = MakeFixturesForAppendTests(privateKey, epoch: DateTimeOffset.UtcNow); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; Block block1 = TestUtils.MineNext( - genesis, - hashAlgorithm, - miner: addresses[4], - difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + genesis, + _blockChain.Policy.GetHashAlgorithm, + miner: addresses[4], + difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10)) + .AttachStateRootHash( + _blockChain.Policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); _blockChain.Append(block1); Assert.Empty(_blockChain.GetStagedTransactionIds()); @@ -513,11 +532,15 @@ public void UnstageAfterAppendComplete() Block block2 = TestUtils.MineNext( block1, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, ImmutableArray>.Empty.Add(txs[0]), difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash( + _blockChain.Policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); _blockChain.Append(block2); Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count); StageTransactions(txs); @@ -533,11 +556,15 @@ public void UnstageAfterAppendComplete() Block block3 = TestUtils.MineNext( block2, - hashAlgorithm, + _blockChain.Policy.GetHashAlgorithm, ImmutableArray>.Empty.Add(txs[1]), difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash( + _blockChain.Policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); _blockChain.Append(block3); Assert.Empty(_blockChain.GetStagedTransactionIds()); } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs index 27465ebf6c..dacbb11b31 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Security.Cryptography; using Bencodex.Types; using Libplanet.Assets; using Libplanet.Blockchain; @@ -124,13 +123,12 @@ public void ExecuteActions() MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block1 = TestUtils.MineNext( genesis, - hashAlgorithm, + _policy.GetHashAlgorithm, txs, - difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + difficulty: _policy.GetNextBlockDifficulty(_blockChain) + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append( block1, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs b/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs new file mode 100644 index 0000000000..8cdb35c3bd --- /dev/null +++ b/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs @@ -0,0 +1,64 @@ +using System.Security.Cryptography; +using System.Threading.Tasks; +using Libplanet.Action; +using Libplanet.Blockchain; +using Libplanet.Blockchain.Policies; +using Libplanet.Blocks; +using Libplanet.Tests.Common.Action; +using Libplanet.Tests.Store; +using Xunit; + +namespace Libplanet.Tests.Blockchain +{ + public partial class BlockChainTest + { + [Fact] + public async Task MineBlockWithMultipleAlgorithms() + { + using (var fx = new DefaultStoreFixture()) + { + IBlockPolicy policy = new MultiAlgoPolicy(); + BlockChain chain = TestUtils.MakeBlockChain( + policy, + fx.Store, + fx.StateStore, + new DumbAction[0] + ); + Block block1 = await chain.MineBlock(default); + Assert.Equal(16, block1.PreEvaluationHash.Length); + Block block2 = await chain.MineBlock(default); + Assert.Equal(20, block2.PreEvaluationHash.Length); + } + } + + [Fact] + public void ValidateWithMultipleAlgorithms() + { + using (var fx = new DefaultStoreFixture()) + { + IBlockPolicy policy = new MultiAlgoPolicy(); + BlockChain chain = TestUtils.MakeBlockChain( + policy, + fx.Store, + fx.StateStore, + new DumbAction[0] + ); + HashAlgorithmGetter invalidAlgoGetter = _ => HashAlgorithmType.Of(); + Block invalid1 = TestUtils.MineNext(chain.Genesis, invalidAlgoGetter) + .AttachStateRootHash(invalidAlgoGetter, fx.StateStore, policy.BlockAction); + Assert.Throws(() => chain.Append(invalid1)); + HashAlgorithmGetter validAlgoGetter = _ => HashAlgorithmType.Of(); + Block valid1 = TestUtils.MineNext(chain.Genesis, validAlgoGetter) + .AttachStateRootHash(validAlgoGetter, fx.StateStore, policy.BlockAction); + chain.Append(valid1); + } + } + + private class MultiAlgoPolicy : NullPolicy + where T : IAction, new() + { + public override HashAlgorithmType GetHashAlgorithm(long index) => + index % 2 == 1 ? HashAlgorithmType.Of() : HashAlgorithmType.Of(); + } + } +} diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index 946e498acf..d83bd5d2e7 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -18,14 +18,14 @@ public void ValidateNextBlock() { Block validNextBlock = Block.Mine( 1, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(1), 1024, _fx.GenesisBlock.TotalDifficulty, _fx.GenesisBlock.Miner.Value, _fx.GenesisBlock.Hash, _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(validNextBlock); Assert.Equal(_blockChain.Tip, validNextBlock); } @@ -35,7 +35,7 @@ private void ValidateNextBlockProtocolVersion() { Block block1 = Block.Mine( 1, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(1), 1024, _fx.GenesisBlock.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -43,12 +43,12 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: 1 - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block1); Block block2 = Block.Mine( 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(2), 1024, block1.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -56,14 +56,14 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: 0 - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(block2)); Assert.Throws(() => { Block block3 = Block.Mine( 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(2), 1024, block1.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -71,7 +71,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: Block.CurrentProtocolVersion + 1 - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block3); }); } @@ -84,28 +84,28 @@ private void ValidateNextBlockInvalidIndex() Block prev = _blockChain.Tip; Block blockWithAlreadyUsedIndex = Block.Mine( prev.Index, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(prev.Index), 1, prev.TotalDifficulty, prev.Miner.Value, prev.Hash, prev.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws( () => _blockChain.Append(blockWithAlreadyUsedIndex) ); Block blockWithIndexAfterNonexistentIndex = Block.Mine( prev.Index + 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(prev.Index + 2), 1, prev.TotalDifficulty, prev.Miner.Value, prev.Hash, prev.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws( () => _blockChain.Append(blockWithIndexAfterNonexistentIndex) ); @@ -118,14 +118,14 @@ private void ValidateNextBlockInvalidDifficulty() var invalidDifficultyBlock = Block.Mine( 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(2), 1, _validNext.TotalDifficulty, _fx.GenesisBlock.Miner.Value, _validNext.Hash, _validNext.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(invalidDifficultyBlock)); } @@ -137,14 +137,14 @@ private void ValidateNextBlockInvalidTotalDifficulty() var invalidTotalDifficultyBlock = Block.Mine( 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(2), _policy.GetNextBlockDifficulty(_blockChain), _validNext.TotalDifficulty - 1, _fx.GenesisBlock.Miner.Value, _validNext.Hash, _validNext.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(invalidTotalDifficultyBlock)); } @@ -156,7 +156,7 @@ private void ValidateNextBlockInvalidPreviousHash() var invalidPreviousHashBlock = Block.Mine( 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(2), 1032, _validNext.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -174,7 +174,7 @@ private void ValidateNextBlockInvalidTimestamp() var invalidPreviousTimestamp = Block.Mine( 2, - HashAlgorithmType.Of(), + _fx.GetHashAlgorithm(2), 1032, _validNext.TotalDifficulty, _fx.GenesisBlock.Miner.Value, @@ -196,8 +196,8 @@ private void ValidateNextBlockInvalidStateRootHash() // Actually, it depends on BlockChain to update states and it makes hard to // calculate state root hash. To resolve this problem, // it should be moved into StateStore. - var genesisBlock = TestUtils.MineGenesis(_fx.HashAlgorithm) - .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, policy.BlockAction); + var genesisBlock = TestUtils.MineGenesis(_fx.GetHashAlgorithm) + .AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, policy.BlockAction); var store = new DefaultStore(null); var chain = new BlockChain( policy, @@ -208,20 +208,21 @@ private void ValidateNextBlockInvalidStateRootHash() var validNext = Block.Mine( 1, - HashAlgorithmType.Of(), + policy.GetHashAlgorithm(1), 1024, genesisBlock.TotalDifficulty, genesisBlock.Miner.Value, genesisBlock.Hash, genesisBlock.Timestamp.AddSeconds(1), - _emptyTransaction) - .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction) - .AttachStateRootHash(_fx.HashAlgorithm, chain.StateStore, policy.BlockAction); + _emptyTransaction + ) + .AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction) + .AttachStateRootHash(policy.GetHashAlgorithm, chain.StateStore, policy.BlockAction); chain.Append(validNext); var invalidStateRootHash = Block.Mine( 2, - HashAlgorithmType.Of(), + policy.GetHashAlgorithm(2), 1032, validNext.TotalDifficulty, genesisBlock.Miner.Value, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 5c319ae900..4dbd2be131 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -65,15 +65,15 @@ public BlockChainTest(ITestOutputHelper output) _emptyTransaction = new List>(); _validNext = Block.Mine( - 1, - _fx.HashAlgorithm, - 1024, - _fx.GenesisBlock.TotalDifficulty, - _fx.GenesisBlock.Miner.Value, - _fx.GenesisBlock.Hash, - _fx.GenesisBlock.Timestamp.AddSeconds(1), - _emptyTransaction) - .AttachStateRootHash(_fx.HashAlgorithm, _fx.StateStore, _policy.BlockAction); + 1, + _policy.GetHashAlgorithm(1), + 1024, + _fx.GenesisBlock.TotalDifficulty, + _fx.GenesisBlock.Miner.Value, + _fx.GenesisBlock.Hash, + _fx.GenesisBlock.Timestamp.AddSeconds(1), + _emptyTransaction + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); } public void Dispose() @@ -303,12 +303,12 @@ IEnumerable NonRehearsalExecutions() => var actions = new[] { new DumbAction(miner, "foo") }; var tx = chain.MakeTransaction(key, actions); var block = TestUtils.MineNext( - chain.Genesis, - fx.HashAlgorithm, - new[] { tx }, - miner: miner, - difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain)) - .AttachStateRootHash(fx.HashAlgorithm, fx.StateStore, policy.BlockAction); + chain.Genesis, + policy.GetHashAlgorithm, + new[] { tx }, + miner: miner, + difficulty: policy.GetNextBlockDifficulty(_blockChain) + ).AttachStateRootHash(policy.GetHashAlgorithm, fx.StateStore, policy.BlockAction); chain.Append(block); var forked = chain.Fork(chain.Genesis.Hash); forked.Append(block); @@ -518,7 +518,6 @@ public async void Fork() [Fact] public async Task ForkWithBlockNotExistInChain() { - HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; var genesis = await _blockChain.MineBlock(_fx.Address1); for (var i = 0; i < 2; i++) @@ -526,7 +525,7 @@ public async Task ForkWithBlockNotExistInChain() await _blockChain.MineBlock(_fx.Address1); } - var newBlock = TestUtils.MineNext(genesis, hashAlgorithm, difficulty: 1024); + var newBlock = TestUtils.MineNext(genesis, _policy.GetHashAlgorithm, difficulty: 1024); Assert.Throws(() => _blockChain.Fork(newBlock.Hash)); @@ -579,19 +578,18 @@ public async Task ForkShouldSkipExecuteAndRenderGenesis() Address miner = _fx.Address2; var action = new DumbAction(stateKey, "genesis"); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); using (var store = new DefaultStore(null)) using (var stateStore = new TrieStateStore( new MemoryKeyValueStore(), new MemoryKeyValueStore())) { var genesis = TestUtils.MineGenesis( - hashAlgorithm, + _policy.GetHashAlgorithm, transactions: new[] { _fx.MakeTransaction(new[] { action }) } - ).AttachStateRootHash(hashAlgorithm, stateStore, _policy.BlockAction); + ).AttachStateRootHash(_policy.GetHashAlgorithm, stateStore, _policy.BlockAction); store.PutBlock(genesis); var renderer = new RecordingActionRenderer(); var blockChain = new BlockChain( - _blockChain.Policy, + _policy, new VolatileStagePolicy(), store, stateStore, @@ -624,7 +622,6 @@ public void DetectInvalidTxNonce() var privateKey = new PrivateKey(); var actions = new[] { new DumbAction(_fx.Address1, "foo") }; - HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; var genesis = _blockChain.Genesis; Transaction[] txsA = @@ -633,23 +630,23 @@ public void DetectInvalidTxNonce() }; Block b1 = TestUtils.MineNext( - genesis, - hashAlgorithm, - txsA, - null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + genesis, + _policy.GetHashAlgorithm, + txsA, + null, + _policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10)) + .AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b1); Block b2 = TestUtils.MineNext( - b1, - hashAlgorithm, - txsA, - null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + b1, + _policy.GetHashAlgorithm, + txsA, + null, + _policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); Assert.Throws(() => _blockChain.Append(b2)); @@ -661,13 +658,13 @@ public void DetectInvalidTxNonce() privateKey: privateKey), }; b2 = TestUtils.MineNext( - b1, - hashAlgorithm, - txsB, - null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + b1, + _policy.GetHashAlgorithm, + txsB, + null, + _policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b2); } @@ -697,13 +694,13 @@ public void ForkTxNonce() Assert.Equal(0, _blockChain.GetNextTxNonce(address)); Block b1 = TestUtils.MineNext( - genesis, - hashAlgorithm, - txsA, - null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + genesis, + _policy.GetHashAlgorithm, + txsA, + null, + _blockChain.Policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b1); @@ -717,13 +714,13 @@ public void ForkTxNonce() privateKey: privateKey), }; Block b2 = TestUtils.MineNext( - b1, - hashAlgorithm, - txsB, - null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + b1, + _policy.GetHashAlgorithm, + txsB, + null, + _policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10)) + .AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b2); Assert.Equal(2, _blockChain.GetNextTxNonce(address)); @@ -769,16 +766,15 @@ public void Swap(bool render) MakeFixturesForAppendTests(); var genesis = _blockChain.Genesis; var minerAddress = addresses[4]; - HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; Block block1 = TestUtils.MineNext( genesis, - hashAlgorithm, + _policy.GetHashAlgorithm, txs1, miner: minerAddress, - difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), + difficulty: _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(block1); PrivateKey privateKey = new PrivateKey(new byte[] @@ -838,12 +834,16 @@ public void Swap(bool render) { Block b = TestUtils.MineNext( _blockChain.Tip, - hashAlgorithm, + _policy.GetHashAlgorithm, txs, null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), + _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash( + _policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); _blockChain.Append(b); } @@ -870,12 +870,12 @@ public void Swap(bool render) Block forkTip = TestUtils.MineNext( fork.Tip, - hashAlgorithm, + _policy.GetHashAlgorithm, txsB, null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), + _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); fork.Append( forkTip, DateTimeOffset.UtcNow, @@ -1013,14 +1013,17 @@ public async Task ReorgIsUnableToHeterogenousChain(bool render) using (var fx2 = new DefaultStoreFixture( memory: true, blockAction: _policy.BlockAction)) { - HashAlgorithmType hashAlgorithm = fx2.HashAlgorithm; Block genesis2 = TestUtils.MineGenesis( - hashAlgorithm, + _policy.GetHashAlgorithm, timestamp: DateTimeOffset.UtcNow - ).AttachStateRootHash(hashAlgorithm, fx2.StateStore, _policy.BlockAction); + ).AttachStateRootHash( + _policy.GetHashAlgorithm, + fx2.StateStore, + _policy.BlockAction + ); var chain2 = new BlockChain( - _blockChain.Policy, - _blockChain.StagePolicy, + _policy, + _stagePolicy, fx2.Store, fx2.StateStore, genesis2 @@ -1059,7 +1062,6 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() _fx.StateStore, _fx.GenesisBlock ); - HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; Block b = chain.Genesis; Address[] addresses = new Address[30]; @@ -1077,8 +1079,11 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() { Transaction.Create(0, privateKey, chain.Genesis.Hash, actions), }; - b = TestUtils.MineNext(b, hashAlgorithm, txs) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, policy.BlockAction); + b = TestUtils.MineNext( + b, + policy.GetHashAlgorithm, + txs + ).AttachStateRootHash(policy.GetHashAlgorithm, _fx.StateStore, policy.BlockAction); chain.Append(b); } @@ -1112,13 +1117,19 @@ public void GetStateReturnsEarlyForNonexistentAccount() _fx.StateStore, _fx.GenesisBlock ); - HashAlgorithmType hashAlgorithm = _fx.HashAlgorithm; Block b = chain.Genesis; for (int i = 0; i < 20; ++i) { - b = TestUtils.MineNext(b, hashAlgorithm, blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, blockPolicy.BlockAction); + b = TestUtils.MineNext( + b, + blockPolicy.GetHashAlgorithm, + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash( + blockPolicy.GetHashAlgorithm, + _fx.StateStore, + blockPolicy.BlockAction + ); chain.Append(b); } @@ -1278,7 +1289,6 @@ public void GetNextTxNonce() var privateKey = new PrivateKey(); Address address = privateKey.ToAddress(); var actions = new[] { new DumbAction(_fx.Address1, "foo") }; - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; Assert.Equal(0, _blockChain.GetNextTxNonce(address)); @@ -1289,13 +1299,13 @@ public void GetNextTxNonce() }; Block b1 = TestUtils.MineNext( - genesis, - hashAlgorithm, - txsA, - null, - _blockChain.Policy.GetNextBlockDifficulty(_blockChain), - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + genesis, + _policy.GetHashAlgorithm, + txsA, + null, + _policy.GetNextBlockDifficulty(_blockChain), + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); _blockChain.Append(b1); Assert.Equal(1, _blockChain.GetNextTxNonce(address)); @@ -1385,18 +1395,21 @@ public void ValidateTxNonces() { var privateKey = new PrivateKey(); var actions = new[] { new DumbAction(_fx.Address1, string.Empty) }; - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var genesis = _blockChain.Genesis; Block MineNext(Block block, IReadOnlyList> txs) where T : IAction, new() => TestUtils.MineNext( block, - hashAlgorithm, + _policy.GetHashAlgorithm, txs, difficulty: 1024, - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, _fx.StateStore, _policy.BlockAction); + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash( + _policy.GetHashAlgorithm, + _fx.StateStore, + _policy.BlockAction + ); Transaction[] txsA = { @@ -1550,11 +1563,15 @@ internal static (Address, Address[] Addresses, BlockChain Chain) ) { IBlockPolicy blockPolicy = new NullPolicy(); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); store = new StoreTracker(store); Guid chainId = Guid.NewGuid(); - Block genesisBlock = TestUtils.MineGenesis(hashAlgorithm) - .AttachStateRootHash(hashAlgorithm, stateStore, blockPolicy.BlockAction); + Block genesisBlock = TestUtils.MineGenesis( + blockPolicy.GetHashAlgorithm + ).AttachStateRootHash( + blockPolicy.GetHashAlgorithm, + stateStore, + blockPolicy.BlockAction + ); var chain = new BlockChain( blockPolicy, new VolatileStagePolicy(), @@ -1614,11 +1631,15 @@ void BuildIndex(Guid id, Block block) new[] { new DumbAction(addresses[j], index.ToString()) } ); b = TestUtils.MineNext( - b, - hashAlgorithm, - new[] { tx }, - blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(hashAlgorithm, stateStore, blockPolicy.BlockAction); + b, + blockPolicy.GetHashAlgorithm, + new[] { tx }, + blockInterval: TimeSpan.FromSeconds(10) + ).AttachStateRootHash( + blockPolicy.GetHashAlgorithm, + stateStore, + blockPolicy.BlockAction + ); previousStates = b.ProtocolVersion > 0 ? new AccountStateDeltaImpl( dirty.GetValueOrDefault, @@ -1757,7 +1778,6 @@ private void ConstructWithGenesisBlock() { var storeFixture = new DefaultStoreFixture(); var policy = new NullPolicy(); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var addresses = ImmutableList
.Empty .Add(storeFixture.Address1) @@ -1768,6 +1788,7 @@ private void ConstructWithGenesisBlock() addresses .Select((address, index) => new DumbAction(address, index.ToString())) .ToArray(); + HashAlgorithmType hashAlgorithm = policy.GetHashAlgorithm(0); BlockChain blockChain = new BlockChain( policy, @@ -1790,7 +1811,7 @@ private void ConstructWithGenesisBlock() private void ConstructWithUnexpectedGenesisBlock() { var policy = new NullPolicy(); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmType hashAlgorithm = policy.GetHashAlgorithm(0); var stagePolicy = new VolatileStagePolicy(); var store = new DefaultStore(null); var stateStore = @@ -1847,9 +1868,10 @@ private void ConstructBlockchainWithGenesisBlockHavingStateRootHash() var store = new DefaultStore(null); var stateStore = new TrieStateStore( new MemoryKeyValueStore(), new MemoryKeyValueStore()); - var genesisBlock = TestUtils.MineGenesis(HashAlgorithmType.Of()); + Block genesisBlock = + TestUtils.MineGenesis(_policy.GetHashAlgorithm); BlockChain blockChain = TestUtils.MakeBlockChain( - _blockChain.Policy, store, stateStore, genesisBlock: genesisBlock); + _policy, store, stateStore, genesisBlock: genesisBlock); Assert.NotNull(blockChain[0].StateRootHash); } diff --git a/Libplanet.Tests/Blockchain/NullPolicy.cs b/Libplanet.Tests/Blockchain/NullPolicy.cs index d6efe31065..886269b28e 100644 --- a/Libplanet.Tests/Blockchain/NullPolicy.cs +++ b/Libplanet.Tests/Blockchain/NullPolicy.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -8,7 +9,7 @@ namespace Libplanet.Tests.Blockchain { - public sealed class NullPolicy : IBlockPolicy + public class NullPolicy : IBlockPolicy where T : IAction, new() { private readonly InvalidBlockException _exceptionToThrow; @@ -39,5 +40,8 @@ public InvalidBlockException ValidateNextBlock(BlockChain blocks, Block ne _exceptionToThrow; public int GetMaxBlockBytes(long index) => 1024 * 1024; + + public virtual HashAlgorithmType GetHashAlgorithm(long index) => + HashAlgorithmType.Of(); } } diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs index dacd4d6582..31b52f1c74 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs @@ -23,11 +23,13 @@ public class AnonymousActionRendererTest private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); private static Block _genesis = - TestUtils.MineGenesis(_hashAlgorithm, default(Address)); + TestUtils.MineGenesis(_ => _hashAlgorithm, default(Address)); - private static Block _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); + private static Block _blockA = + TestUtils.MineNext(_genesis, _ => _hashAlgorithm); - private static Block _blockB = TestUtils.MineNext(_genesis, _hashAlgorithm); + private static Block _blockB = + TestUtils.MineNext(_genesis, _ => _hashAlgorithm); [Fact] public void ActionRenderer() diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs index 51f19ce424..292114da8d 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs @@ -11,11 +11,13 @@ public class AnonymousRendererTest private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); private static Block _genesis = - TestUtils.MineGenesis(_hashAlgorithm, default(Address)); + TestUtils.MineGenesis(_ => _hashAlgorithm, default(Address)); - private static Block _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); + private static Block _blockA = + TestUtils.MineNext(_genesis, _ => _hashAlgorithm); - private static Block _blockB = TestUtils.MineNext(_genesis, _hashAlgorithm); + private static Block _blockB = + TestUtils.MineNext(_genesis, _ => _hashAlgorithm); [Fact] public void BlockRenderer() diff --git a/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs index 7505defcc7..72f4428cc1 100644 --- a/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/DelayedRendererTest.cs @@ -27,22 +27,23 @@ public class DelayedRendererTest static DelayedRendererTest() { HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmGetter hashAlgorithmGetter = _ => hashAlgorithm; var chainA = new Block[10]; var chainB = new Block[chainA.Length]; - chainA[0] = chainB[0] = TestUtils.MineGenesis(hashAlgorithm); + chainA[0] = chainB[0] = TestUtils.MineGenesis(hashAlgorithmGetter); for (int i = 1; i < chainA.Length / 2; i++) { _branchpoint = chainA[i] = chainB[i] = - TestUtils.MineNext(chainA[i - 1], hashAlgorithm); + TestUtils.MineNext(chainA[i - 1], hashAlgorithmGetter); } int extraDifficulty = 1; for (int i = chainA.Length / 2; i < chainA.Length; i++) { - chainA[i] = TestUtils.MineNext(chainA[i - 1], hashAlgorithm, difficulty: 2); + chainA[i] = TestUtils.MineNext(chainA[i - 1], hashAlgorithmGetter, difficulty: 2); chainB[i] = TestUtils.MineNext( chainB[i - 1], - hashAlgorithm, + hashAlgorithmGetter, difficulty: 2 + extraDifficulty ); diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs index 8ad8157078..a1dcbbba77 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs @@ -27,11 +27,11 @@ public class LoggedActionRendererTest : IDisposable private static HashAlgorithmType _hashAlgorithm = HashAlgorithmType.Of(); private static DumbBlock _genesis = - TestUtils.MineGenesis(_hashAlgorithm, default(Address)); + TestUtils.MineGenesis(_ => _hashAlgorithm, default(Address)); - private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _hashAlgorithm); + private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _ => _hashAlgorithm); - private static DumbBlock _blockB = TestUtils.MineNext(_genesis, _hashAlgorithm); + private static DumbBlock _blockB = TestUtils.MineNext(_genesis, _ => _hashAlgorithm); private ILogger _logger; diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs index dd24e743ed..1fe8b79aec 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs @@ -19,11 +19,11 @@ public class LoggedRendererTest : IDisposable private static HashAlgorithmType _hashAlgorithmType = HashAlgorithmType.Of(); private static DumbBlock _genesis = - TestUtils.MineGenesis(_hashAlgorithmType, default(Address)); + TestUtils.MineGenesis(_ => _hashAlgorithmType, default(Address)); - private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _hashAlgorithmType); + private static DumbBlock _blockA = TestUtils.MineNext(_genesis, _ => _hashAlgorithmType); - private static DumbBlock _blockB = TestUtils.MineNext(_genesis, _hashAlgorithmType); + private static DumbBlock _blockB = TestUtils.MineNext(_genesis, _ => _hashAlgorithmType); private ILogger _logger; diff --git a/Libplanet.Tests/Blocks/BlockFixture.cs b/Libplanet.Tests/Blocks/BlockFixture.cs index 459558171e..6a2679de41 100644 --- a/Libplanet.Tests/Blocks/BlockFixture.cs +++ b/Libplanet.Tests/Blocks/BlockFixture.cs @@ -15,15 +15,14 @@ public class BlockFixture public BlockFixture() { - HashAlgorithm = HashAlgorithmType.Of(); Genesis = TestUtils.MineGenesis>( - hashAlgorithm: HashAlgorithm, + hashAlgorithmGetter: GetHashAlgorithm, protocolVersion: ProtocolVersion ); TxFixture = new TxFixture(Genesis.Hash); Next = TestUtils.MineNext( Genesis, - HashAlgorithm, + hashAlgorithmGetter: GetHashAlgorithm, nonce: new byte[] { 0x02, 0x00, 0x00, 0x00 }, protocolVersion: ProtocolVersion ); @@ -33,18 +32,16 @@ public BlockFixture() }; HasTx = TestUtils.MineNext( Next, - HashAlgorithm, - new List>> + hashAlgorithmGetter: GetHashAlgorithm, + txs: new List>> { TxFixture.TxWithActions, }, - hasTxNonce, + nonce: hasTxNonce, protocolVersion: ProtocolVersion ); } - internal HashAlgorithmType HashAlgorithm { get; } - internal TxFixture TxFixture { get; } internal Block> Genesis { get; } @@ -52,5 +49,7 @@ public BlockFixture() internal Block> Next { get; } internal Block> HasTx { get; } + + internal HashAlgorithmType GetHashAlgorithm(long index) => HashAlgorithmType.Of(); } } diff --git a/Libplanet.Tests/Blocks/BlockHeaderTest.cs b/Libplanet.Tests/Blocks/BlockHeaderTest.cs index 95cd255c19..58dae1855d 100644 --- a/Libplanet.Tests/Blocks/BlockHeaderTest.cs +++ b/Libplanet.Tests/Blocks/BlockHeaderTest.cs @@ -104,8 +104,8 @@ public void ToBencodex() [Fact] public void ValidateValidHeader() { - _fx.Genesis.Header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow); - _fx.Next.Header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow); + _fx.Genesis.Header.Validate(_fx.GetHashAlgorithm(0), DateTimeOffset.UtcNow); + _fx.Next.Header.Validate(_fx.GetHashAlgorithm(1), DateTimeOffset.UtcNow); } [Fact] @@ -130,7 +130,7 @@ public void ValidateHash() ); Assert.Throws( - () => { header.Validate(_fx.HashAlgorithm, DateTime.UtcNow); }); + () => { header.Validate(_fx.GetHashAlgorithm(0), DateTime.UtcNow); }); } [Fact] @@ -155,7 +155,7 @@ public void ValidateProtocolVersion() ); Assert.Throws(() => - header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + header.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), DateTimeOffset.UtcNow) ); header = new BlockHeader( @@ -177,7 +177,7 @@ public void ValidateProtocolVersion() ); Assert.Throws(() => - header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + header.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), DateTimeOffset.UtcNow) ); } @@ -232,7 +232,7 @@ public void ValidateNonce() ); Assert.Throws(() => - header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + header.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), DateTimeOffset.UtcNow)); } [Fact] @@ -257,7 +257,7 @@ public void ValidateIndex() ); Assert.Throws(() => - header.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + header.Validate(_fx.GetHashAlgorithm(-1), DateTimeOffset.UtcNow)); } [Fact] @@ -280,7 +280,7 @@ public void ValidateDifficulty() ); Assert.Throws(() => - genesisHeader.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + genesisHeader.Validate(_fx.GetHashAlgorithm(0), DateTimeOffset.UtcNow)); var header1 = new BlockHeader( protocolVersion: 0, @@ -298,7 +298,7 @@ public void ValidateDifficulty() ); Assert.Throws(() => - header1.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + header1.Validate(_fx.GetHashAlgorithm(10), DateTimeOffset.UtcNow)); var header2 = new BlockHeader( protocolVersion: 0, @@ -316,7 +316,7 @@ public void ValidateDifficulty() ); Assert.Throws(() => - header2.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + header2.Validate(_fx.GetHashAlgorithm(10), DateTimeOffset.UtcNow)); } [Fact] diff --git a/Libplanet.Tests/Blocks/BlockTest.cs b/Libplanet.Tests/Blocks/BlockTest.cs index 83e65a87e8..9d24393e1d 100644 --- a/Libplanet.Tests/Blocks/BlockTest.cs +++ b/Libplanet.Tests/Blocks/BlockTest.cs @@ -95,7 +95,7 @@ public void Mine() _fx.Genesis.Hash ); - Block> next = MineNext(_fx.Genesis, _fx.HashAlgorithm); + Block> next = MineNext(_fx.Genesis, _fx.GetHashAlgorithm); Assert.Equal(1, _fx.Next.Index); Assert.Equal(1, _fx.Next.Difficulty); @@ -205,7 +205,7 @@ public void DetectInvalidProtocolVersion() DateTimeOffset now = DateTimeOffset.UtcNow; Block block = Block.Mine( _fx.Next.Index, - _fx.HashAlgorithm, + _fx.GetHashAlgorithm(_fx.Next.Index), _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -215,12 +215,12 @@ public void DetectInvalidProtocolVersion() protocolVersion: -1 ); Assert.Throws( - () => block.Validate(_fx.HashAlgorithm, now) + () => block.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), now) ); block = Block.Mine( _fx.Next.Index, - _fx.HashAlgorithm, + _fx.GetHashAlgorithm(_fx.Next.Index), _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -230,7 +230,7 @@ public void DetectInvalidProtocolVersion() protocolVersion: Block.CurrentProtocolVersion + 1 ); Assert.Throws( - () => block.Validate(_fx.HashAlgorithm, now) + () => block.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), now) ); } @@ -238,9 +238,10 @@ public void DetectInvalidProtocolVersion() public void DetectInvalidTimestamp() { DateTimeOffset now = DateTimeOffset.UtcNow; + HashAlgorithmType hashAlgo = _fx.GetHashAlgorithm(_fx.Next.Index); var block = Block.Mine( _fx.Next.Index, - HashAlgorithmType.Of(), + hashAlgo, _fx.Next.Difficulty, _fx.Genesis.TotalDifficulty, _fx.Next.Miner.Value, @@ -250,10 +251,10 @@ public void DetectInvalidTimestamp() ); Assert.Throws( - () => { block.Validate(_fx.HashAlgorithm, now); }); + () => { block.Validate(hashAlgo, now); }); // it's okay because 2 seconds later. - block.Validate(_fx.HashAlgorithm, now + TimeSpan.FromSeconds(2)); + block.Validate(hashAlgo, now + TimeSpan.FromSeconds(2)); } [Fact] @@ -274,12 +275,13 @@ public void DetectInvalidNonce() ); Assert.Throws(() => - invalidBlock.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + invalidBlock.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), DateTimeOffset.UtcNow)); } [Fact] public void DetectInvalidDifficulty() { + HashAlgorithmType hashAlgo = _fx.GetHashAlgorithm(_fx.Genesis.Index); var invalidDifficultyGenesis = new Block( index: _fx.Genesis.Index, difficulty: 1, // invalid @@ -288,11 +290,11 @@ public void DetectInvalidDifficulty() miner: _fx.Genesis.Miner, previousHash: _fx.Genesis.PreviousHash, timestamp: _fx.Genesis.Timestamp, - transactions: MineGenesis(_fx.HashAlgorithm).Transactions, - hashAlgorithm: _fx.HashAlgorithm + transactions: MineGenesis(_fx.GetHashAlgorithm).Transactions, + hashAlgorithm: hashAlgo ); Assert.Throws(() => - invalidDifficultyGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + invalidDifficultyGenesis.Validate(hashAlgo, DateTimeOffset.UtcNow) ); var invalidTotalDifficultyGenesis = new Block( @@ -303,13 +305,14 @@ public void DetectInvalidDifficulty() miner: _fx.Genesis.Miner, previousHash: _fx.Genesis.PreviousHash, timestamp: _fx.Genesis.Timestamp, - transactions: MineGenesis(_fx.HashAlgorithm).Transactions, - hashAlgorithm: _fx.HashAlgorithm + transactions: MineGenesis(_fx.GetHashAlgorithm).Transactions, + hashAlgorithm: hashAlgo ); Assert.Throws(() => - invalidTotalDifficultyGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + invalidTotalDifficultyGenesis.Validate(hashAlgo, DateTimeOffset.UtcNow) ); + HashAlgorithmType hashAlgoNext = _fx.GetHashAlgorithm(_fx.Next.Index); var invalidDifficultyNext = new Block>( index: _fx.Next.Index, difficulty: 0, // invalid, @@ -319,10 +322,10 @@ public void DetectInvalidDifficulty() previousHash: _fx.Next.PreviousHash, timestamp: _fx.Next.Timestamp, transactions: _fx.Next.Transactions, - hashAlgorithm: _fx.HashAlgorithm + hashAlgorithm: hashAlgoNext ); Assert.Throws(() => - invalidDifficultyNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + invalidDifficultyNext.Validate(hashAlgoNext, DateTimeOffset.UtcNow) ); var invalidTotalDifficultyNext = new Block>( @@ -334,16 +337,17 @@ public void DetectInvalidDifficulty() previousHash: _fx.Next.PreviousHash, timestamp: _fx.Next.Timestamp, transactions: _fx.Next.Transactions, - hashAlgorithm: _fx.HashAlgorithm + hashAlgorithm: hashAlgoNext ); Assert.Throws(() => - invalidTotalDifficultyNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + invalidTotalDifficultyNext.Validate(hashAlgoNext, DateTimeOffset.UtcNow) ); } [Fact] public void DetectInvalidPreviousHash() { + HashAlgorithmType hashAlgo = _fx.GetHashAlgorithm(_fx.Genesis.Index); var invalidGenesis = new Block( index: _fx.Genesis.Index, difficulty: _fx.Genesis.Difficulty, @@ -352,14 +356,15 @@ public void DetectInvalidPreviousHash() miner: _fx.Genesis.Miner, previousHash: new BlockHash(GetRandomBytes(32)), // invalid timestamp: _fx.Genesis.Timestamp, - transactions: MineGenesis(_fx.HashAlgorithm).Transactions, - hashAlgorithm: _fx.HashAlgorithm + transactions: MineGenesis(_fx.GetHashAlgorithm).Transactions, + hashAlgorithm: hashAlgo ); Assert.Throws(() => - invalidGenesis.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + invalidGenesis.Validate(hashAlgo, DateTimeOffset.UtcNow) ); + HashAlgorithmType hashAlgoNext = _fx.GetHashAlgorithm(_fx.Next.Index); var invalidNext = new Block>( index: _fx.Next.Index, difficulty: _fx.Next.Difficulty, @@ -369,11 +374,11 @@ public void DetectInvalidPreviousHash() previousHash: null, timestamp: _fx.Next.Timestamp, transactions: _fx.Next.Transactions, - hashAlgorithm: _fx.HashAlgorithm + hashAlgorithm: hashAlgoNext ); Assert.Throws(() => - invalidNext.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow) + invalidNext.Validate(hashAlgoNext, DateTimeOffset.UtcNow) ); } @@ -471,7 +476,7 @@ public void CanCompareToOtherBlock() previousHash: null, timestamp: sameBlock1.Timestamp, transactions: sameBlock1.Transactions, - hashAlgorithm: _fx.HashAlgorithm + hashAlgorithm: _fx.GetHashAlgorithm(sameBlock1.Index) ); Block> differentBlock = _fx.Next; @@ -517,9 +522,9 @@ public void TransactionOrderIdempotent() new PrivateKey(), null, new[] { new RandomAction(signer.ToAddress()) })).ToImmutableArray(); - HashAlgorithmType algo = HashAlgorithmType.Of(); - var blockA = MineGenesis(algo, timestamp: timestamp, transactions: txs); - var blockB = MineGenesis(algo, timestamp: timestamp, transactions: txs); + HashAlgorithmGetter algoGetter = _ => HashAlgorithmType.Of(); + var blockA = MineGenesis(algoGetter, timestamp: timestamp, transactions: txs); + var blockB = MineGenesis(algoGetter, timestamp: timestamp, transactions: txs); Assert.True(blockA.Transactions.SequenceEqual(blockB.Transactions)); } @@ -606,7 +611,7 @@ public void DetectInvalidPreEvaluationHash() transactions: _fx.Next.Transactions); Assert.Throws(() => - invalidBlock.Validate(_fx.HashAlgorithm, DateTimeOffset.UtcNow)); + invalidBlock.Validate(_fx.GetHashAlgorithm(_fx.Next.Index), DateTimeOffset.UtcNow)); } [Fact] @@ -628,8 +633,8 @@ public void DetectInvalidTxSignature() var invalidTx = new Transaction(rawTx); Assert.Throws(() => MineNext( - MineGenesis(_fx.HashAlgorithm), - HashAlgorithmType.Of(), + MineGenesis(_fx.GetHashAlgorithm), + _fx.GetHashAlgorithm, new List> { invalidTx, @@ -671,12 +676,9 @@ public void DetectInvalidTxPublicKey() ); Assert.Throws(() => MineNext( - MineGenesis(_fx.HashAlgorithm), - HashAlgorithmType.Of(), - new List> - { - invalidTx, - } + MineGenesis(_fx.GetHashAlgorithm), + _fx.GetHashAlgorithm, + new List> { invalidTx } ) ); } diff --git a/Libplanet.Tests/Fixtures/IntegerSet.cs b/Libplanet.Tests/Fixtures/IntegerSet.cs index a45f583bf6..c5fb07ecbe 100644 --- a/Libplanet.Tests/Fixtures/IntegerSet.cs +++ b/Libplanet.Tests/Fixtures/IntegerSet.cs @@ -66,9 +66,16 @@ public IntegerSet( Store = new DefaultStore(null); KVStore = new MemoryKeyValueStore(); StateStore = new TrieStateStore(KVStore, KVStore); - HashAlgorithmType algo = HashAlgorithmType.Of(); - Genesis = Block.Mine(0, algo, 0, 0, Miner, null, DateTimeOffset.UtcNow, Txs) - .AttachStateRootHash(algo, StateStore, policy.BlockAction); + Genesis = Block.Mine( + index: 0, + hashAlgorithm: policy.GetHashAlgorithm(0), + difficulty: 0, + previousTotalDifficulty: 0, + miner: Miner, + previousHash: null, + timestamp: DateTimeOffset.UtcNow, + transactions: Txs + ).AttachStateRootHash(policy.GetHashAlgorithm, StateStore, policy.BlockAction); Chain = new BlockChain( policy, new VolatileStagePolicy(), @@ -142,13 +149,16 @@ public TxWithContext Sign(int signerIndex, params Arithmetic[] actions) => public async Task> Mine(CancellationToken cancellationToken = default) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block draft = await Chain.MineBlock( Miner, DateTimeOffset.UtcNow, cancellationToken: cancellationToken ); - return draft.AttachStateRootHash(hashAlgorithm, StateStore, Policy.BlockAction); + return draft.AttachStateRootHash( + Chain.Policy.GetHashAlgorithm, + StateStore, + Policy.BlockAction + ); } public IAccountStateDelta CreateAccountStateDelta(Address signer, BlockHash? offset = null) diff --git a/Libplanet.Tests/Net/BlockCompletionTest.cs b/Libplanet.Tests/Net/BlockCompletionTest.cs index 1dcfc9be33..9d1ba8eaf1 100644 --- a/Libplanet.Tests/Net/BlockCompletionTest.cs +++ b/Libplanet.Tests/Net/BlockCompletionTest.cs @@ -289,10 +289,10 @@ await AsyncEnumerable.ForEachAsync(rv, pair => [Fact(Timeout = Timeout)] public async Task CompleteWithBlockFetcherGivingWrongBlocks() { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - Block genesis = TestUtils.MineGenesis(hashAlgorithm), - demand = TestUtils.MineNext(genesis, hashAlgorithm), - wrong = TestUtils.MineNext(genesis, hashAlgorithm); + HashAlgorithmGetter hashAlgoGetter = _ => HashAlgorithmType.Of(); + Block genesis = TestUtils.MineGenesis(hashAlgoGetter), + demand = TestUtils.MineNext(genesis, hashAlgoGetter), + wrong = TestUtils.MineNext(genesis, hashAlgoGetter); _logger.Debug("Genesis: #{Index} {Hash}", genesis.Index, genesis.Hash); _logger.Debug("Demand: #{Index} {Hash}", demand.Index, demand.Hash); _logger.Debug("Wrong: #{Index} {Hash}", wrong.Index, wrong.Hash); @@ -392,18 +392,21 @@ public async Task CompleteWithCrashingPeers() ); } - private IEnumerable> GenerateBlocks(int count) + private IEnumerable> GenerateBlocks( + int count, + HashAlgorithmGetter hashAlgorithmGetter = null + ) where T : IAction, new() { + hashAlgorithmGetter = hashAlgorithmGetter ?? (_ => HashAlgorithmType.Of()); if (count >= 1) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - Block block = TestUtils.MineGenesis(hashAlgorithm); + Block block = TestUtils.MineGenesis(hashAlgorithmGetter); yield return block; for (int i = 1; i < count; i++) { - block = TestUtils.MineNext(block, hashAlgorithm); + block = TestUtils.MineNext(block, hashAlgorithmGetter); yield return block; } } diff --git a/Libplanet.Tests/Net/Messages/MessageTest.cs b/Libplanet.Tests/Net/Messages/MessageTest.cs index 7f5b0a767d..ce9f7c9f6a 100644 --- a/Libplanet.Tests/Net/Messages/MessageTest.cs +++ b/Libplanet.Tests/Net/Messages/MessageTest.cs @@ -141,7 +141,7 @@ public void BlockHeaderMessage() ImmutableArray.Empty, default(Address)); var dateTimeOffset = DateTimeOffset.UtcNow; - var genesis = TestUtils.MineGenesis(HashAlgorithmType.Of()); + var genesis = TestUtils.MineGenesis(_ => HashAlgorithmType.Of()); var message = new BlockHeaderMessage(genesis.Hash, genesis.Header); NetMQMessage raw = message.ToNetMQMessage(privateKey, peer, dateTimeOffset, appProtocolVersion); diff --git a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs index cfa1741b62..75b0bc44c0 100644 --- a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs +++ b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs @@ -634,23 +634,29 @@ public async Task BroadcastBlockWithSkip() await BootstrapAsync(receiverSwarm, minerSwarm.AsPeer); - HashAlgorithmType hashAlgo1 = HashAlgorithmType.Of(); var block1 = TestUtils.MineNext( blockChain.Genesis, - hashAlgo1, + policy.GetHashAlgorithm, new[] { transactions[0] }, null, policy.GetNextBlockDifficulty(blockChain)) - .AttachStateRootHash(hashAlgo1, blockChain.StateStore, policy.BlockAction); + .AttachStateRootHash( + policy.GetHashAlgorithm, + blockChain.StateStore, + policy.BlockAction + ); blockChain.Append(block1, DateTimeOffset.MinValue.AddSeconds(3), true, true, false); - HashAlgorithmType hashAlgo2 = HashAlgorithmType.Of(); var block2 = TestUtils.MineNext( - block1, - hashAlgo2, - new[] { transactions[1] }, - null, - policy.GetNextBlockDifficulty(blockChain)) - .AttachStateRootHash(hashAlgo2, blockChain.StateStore, policy.BlockAction); + block1, + policy.GetHashAlgorithm, + new[] { transactions[1] }, + null, + policy.GetNextBlockDifficulty(blockChain) + ).AttachStateRootHash( + policy.GetHashAlgorithm, + blockChain.StateStore, + policy.BlockAction + ); blockChain.Append(block2, DateTimeOffset.MinValue.AddSeconds(8), true, true, false); Log.Debug("Ready to broadcast blocks."); minerSwarm.BroadcastBlock(block2); diff --git a/Libplanet.Tests/Net/SwarmTest.Consensus.cs b/Libplanet.Tests/Net/SwarmTest.Consensus.cs index cf5759fe17..1ea72fbcf0 100644 --- a/Libplanet.Tests/Net/SwarmTest.Consensus.cs +++ b/Libplanet.Tests/Net/SwarmTest.Consensus.cs @@ -69,10 +69,14 @@ public async Task DetermineCanonicalChain(short canonComparerType) hashAlgorithm = HashAlgorithmType.Of(); bestBlock = TestUtils.MineNext( chain2.Tip, - hashAlgorithm, + policy.GetHashAlgorithm, difficulty: nextDifficulty, blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash(hashAlgorithm, chain2.StateStore, policy.BlockAction); + ).AttachStateRootHash( + policy.GetHashAlgorithm, + chain2.StateStore, + policy.BlockAction + ); _output.WriteLine("chain1's total difficulty: {0}", chain1.Tip.TotalDifficulty); _output.WriteLine("chain2's total difficulty: {0}", bestBlock.TotalDifficulty); break; @@ -85,10 +89,14 @@ public async Task DetermineCanonicalChain(short canonComparerType) hashAlgorithm = HashAlgorithmType.Of(); bestBlock = TestUtils.MineNext( chain2.Tip, - hashAlgorithm, + policy.GetHashAlgorithm, difficulty: policy.GetNextBlockDifficulty(chain2), blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash(hashAlgorithm, chain2.StateStore, policy.BlockAction); + ).AttachStateRootHash( + policy.GetHashAlgorithm, + chain2.StateStore, + policy.BlockAction + ); hashStr = bestBlock.Hash.ToString(); _output.WriteLine("chain1's tip hash: {0}", chain1.Tip.Hash); _output.WriteLine("chain2's tip hash: {0}", bestBlock.Hash); diff --git a/Libplanet.Tests/Net/SwarmTest.Preload.cs b/Libplanet.Tests/Net/SwarmTest.Preload.cs index 5565db5c45..4617dc2874 100644 --- a/Libplanet.Tests/Net/SwarmTest.Preload.cs +++ b/Libplanet.Tests/Net/SwarmTest.Preload.cs @@ -112,13 +112,12 @@ public async Task Preload() var blocks = new List>(); foreach (int i in Enumerable.Range(0, 11)) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = TestUtils.MineNext( previousBlock: i == 0 ? minerChain.Genesis : blocks[i - 1], - hashAlgorithm: hashAlgorithm, + hashAlgorithmGetter: minerChain.Policy.GetHashAlgorithm, difficulty: 1024) .AttachStateRootHash( - hashAlgorithm, + minerChain.Policy.GetHashAlgorithm, minerChain.StateStore, minerChain.Policy.BlockAction); blocks.Add(block); @@ -327,15 +326,14 @@ public async Task PreloadWithFailedActions() DateTimeOffset.UtcNow ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block = TestUtils.MineNext( minerChain.Tip, - hashAlgorithm, + minerChain.Policy.GetHashAlgorithm, new[] { tx }, difficulty: policy.GetNextBlockDifficulty(minerChain), blockInterval: TimeSpan.FromSeconds(1) ).AttachStateRootHash( - hashAlgorithm, + minerChain.Policy.GetHashAlgorithm, minerChain.StateStore, minerChain.Policy.BlockAction ); @@ -800,15 +798,14 @@ public async Task PreloadFromTheMostDifficultChain() await minerChain1.MineBlock(minerSwarm1.Address); await minerChain1.MineBlock(minerSwarm1.Address); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); long nextDifficulty = (long)minerChain1.Tip.TotalDifficulty + minerChain2.Policy.GetNextBlockDifficulty(minerChain2); var block = TestUtils.MineNext( minerChain2.Tip, - hashAlgorithm, + minerChain2.Policy.GetHashAlgorithm, difficulty: nextDifficulty ).AttachStateRootHash( - hashAlgorithm, + minerChain2.Policy.GetHashAlgorithm, minerChain2.StateStore, minerChain2.Policy.BlockAction ); diff --git a/Libplanet.Tests/Net/SwarmTest.cs b/Libplanet.Tests/Net/SwarmTest.cs index 1a8e1dc951..bf4ac9a1e3 100644 --- a/Libplanet.Tests/Net/SwarmTest.cs +++ b/Libplanet.Tests/Net/SwarmTest.cs @@ -714,13 +714,16 @@ public async Task RemoveForkedChainWhenFillBlocksAsyncFail() await chain2.MineBlock(swarm2.Address); // Creates a block that will make chain 2's total difficulty is higher than chain 1's. - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block3 = TestUtils.MineNext( - chain2.Tip, - hashAlgorithm, - difficulty: (long)chain1.Tip.TotalDifficulty + 1, - blockInterval: TimeSpan.FromMilliseconds(1)) - .AttachStateRootHash(hashAlgorithm, chain2.StateStore, chain2.Policy.BlockAction); + chain2.Tip, + policy2.GetHashAlgorithm, + difficulty: (long)chain1.Tip.TotalDifficulty + 1, + blockInterval: TimeSpan.FromMilliseconds(1) + ).AttachStateRootHash( + policy2.GetHashAlgorithm, + chain2.StateStore, + chain2.Policy.BlockAction + ); chain2.Append(block3); try { @@ -816,13 +819,12 @@ public async Task ForkByDifficulty() await chain1.MineBlock(miner2.Address); long nextDifficulty = (long)chain1.Tip.TotalDifficulty + policy.GetNextBlockDifficulty(chain2); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); var block = TestUtils.MineNext( - chain2.Tip, - hashAlgorithm, - difficulty: nextDifficulty, - blockInterval: TimeSpan.FromMilliseconds(1)) - .AttachStateRootHash(hashAlgorithm, chain2.StateStore, policy.BlockAction); + chain2.Tip, + policy.GetHashAlgorithm, + difficulty: nextDifficulty, + blockInterval: TimeSpan.FromMilliseconds(1) + ).AttachStateRootHash(policy.GetHashAlgorithm, chain2.StateStore, policy.BlockAction); chain2.Append(block); Assert.True(chain1.Tip.Index > chain2.Tip.Index); @@ -1422,17 +1424,17 @@ public async Task DoNotFillWhenGetAllBlockAtFirstTimeFromSender() receiver.FindNextHashesChunkSize = 8; sender.FindNextHashesChunkSize = 8; + BlockChain chain = sender.BlockChain; for (int i = 0; i < 6; i++) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = - TestUtils.MineNext(sender.BlockChain.Tip, hashAlgorithm, difficulty: 1024) + TestUtils.MineNext(chain.Tip, chain.Policy.GetHashAlgorithm, difficulty: 1024) .AttachStateRootHash( - hashAlgorithm, - sender.BlockChain.StateStore, - sender.BlockChain.Policy.BlockAction); - sender.BlockChain.Append(block); + chain.Policy.GetHashAlgorithm, + chain.StateStore, + chain.Policy.BlockAction); + chain.Append(block); } Log.Debug("Sender's BlockChain Tip index: #{index}", sender.BlockChain.Tip.Index); @@ -1465,17 +1467,17 @@ public async Task FillWhenGetAllBlocksFromSender() receiver.FindNextHashesChunkSize = 2; sender.FindNextHashesChunkSize = 2; + BlockChain chain = sender.BlockChain; for (int i = 0; i < 6; i++) { - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); Block block = - TestUtils.MineNext(sender.BlockChain.Tip, hashAlgorithm, difficulty: 1024) + TestUtils.MineNext(chain.Tip, chain.Policy.GetHashAlgorithm, difficulty: 1024) .AttachStateRootHash( - hashAlgorithm, - sender.BlockChain.StateStore, - sender.BlockChain.Policy.BlockAction); - sender.BlockChain.Append(block); + chain.Policy.GetHashAlgorithm, + chain.StateStore, + chain.Policy.BlockAction); + chain.Append(block); } Log.Debug("Sender's BlockChain Tip index: #{index}", sender.BlockChain.Tip.Index); @@ -1509,11 +1511,11 @@ public async Task DoNotFillMultipleTimes() await StartAsync(sender1); await StartAsync(sender2); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + BlockChain chain = receiver.BlockChain; Block b1 = - TestUtils.MineNext(receiver.BlockChain.Genesis, hashAlgorithm, difficulty: 1024) + TestUtils.MineNext(chain.Genesis, chain.Policy.GetHashAlgorithm, difficulty: 1024) .AttachStateRootHash( - hashAlgorithm, + chain.Policy.GetHashAlgorithm, sender1.BlockChain.StateStore, sender1.BlockChain.Policy.BlockAction); diff --git a/Libplanet.Tests/Store/BlockSetTest.cs b/Libplanet.Tests/Store/BlockSetTest.cs index 006c23d092..af3ee82743 100644 --- a/Libplanet.Tests/Store/BlockSetTest.cs +++ b/Libplanet.Tests/Store/BlockSetTest.cs @@ -15,7 +15,7 @@ public class BlockSetTest : IDisposable public BlockSetTest() { _fx = new DefaultStoreFixture(); - _set = new BlockSet(_ => _fx.HashAlgorithm, _fx.Store); + _set = new BlockSet(_fx.GetHashAlgorithm, _fx.Store); } [Fact] diff --git a/Libplanet.Tests/Store/StoreFixture.cs b/Libplanet.Tests/Store/StoreFixture.cs index 01ec5d39bd..ff473eaba2 100644 --- a/Libplanet.Tests/Store/StoreFixture.cs +++ b/Libplanet.Tests/Store/StoreFixture.cs @@ -93,15 +93,14 @@ protected StoreFixture(IAction blockAction = null) var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); - HashAlgorithm = HashAlgorithmType.Of(); - GenesisBlock = TestUtils.MineGenesis(HashAlgorithm) - .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); - Block1 = TestUtils.MineNext(GenesisBlock, HashAlgorithm) - .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); - Block2 = TestUtils.MineNext(Block1, HashAlgorithm) - .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); - Block3 = TestUtils.MineNext(Block2, HashAlgorithm) - .AttachStateRootHash(HashAlgorithm, stateStore, blockAction); + GenesisBlock = TestUtils.MineGenesis(GetHashAlgorithm) + .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + Block1 = TestUtils.MineNext(GenesisBlock, GetHashAlgorithm) + .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + Block2 = TestUtils.MineNext(Block1, GetHashAlgorithm) + .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + Block3 = TestUtils.MineNext(Block2, GetHashAlgorithm) + .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); Transaction1 = MakeTransaction(new List(), ImmutableHashSet
.Empty); Transaction2 = MakeTransaction(new List(), ImmutableHashSet
.Empty); @@ -136,8 +135,6 @@ protected StoreFixture(IAction blockAction = null) public BlockHash Hash3 { get; } - public HashAlgorithmType HashAlgorithm { get; set; } - public Block GenesisBlock { get; } public Block Block1 { get; } @@ -182,5 +179,7 @@ public Transaction MakeTransaction( timestamp ); } + + public HashAlgorithmType GetHashAlgorithm(long index) => HashAlgorithmType.Of(); } } diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index 39e68fb09a..fb27a3dae7 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -86,8 +86,8 @@ public void ListChainIdAfterForkAndDelete() public void DeleteChainId() { Block block1 = TestUtils.MineNext( - TestUtils.MineGenesis(Fx.HashAlgorithm), - Fx.HashAlgorithm, + TestUtils.MineGenesis(Fx.GetHashAlgorithm), + Fx.GetHashAlgorithm, new[] { Fx.Transaction1 }); Fx.Store.AppendIndex(Fx.StoreChainId, block1.Hash); Guid arbitraryChainId = Guid.NewGuid(); @@ -996,7 +996,7 @@ public void ForkWithBranch() // We need `Block`s because `IStore` can't retrive index(long) by block hash without // actual block... - Block anotherBlock3 = TestUtils.MineNext(Fx.Block2, Fx.HashAlgorithm); + Block anotherBlock3 = TestUtils.MineNext(Fx.Block2, Fx.GetHashAlgorithm); store.PutBlock(Fx.GenesisBlock); store.PutBlock(Fx.Block1); store.PutBlock(Fx.Block2); @@ -1096,7 +1096,7 @@ public void GetBlock() // NOTE: it depends on that Block.CurrentProtocolVersion is not 0. Block block = TestUtils.MineNext( genesisBlock, - fx.HashAlgorithm, + fx.GetHashAlgorithm, protocolVersion: 0); fx.Store.PutBlock(block); diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 149f6344b3..3f2bfee73a 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -180,7 +180,7 @@ public static byte[] GetRandomBytes(int size) } public static Block MineGenesis( - HashAlgorithmType hashAlgorithm, + HashAlgorithmGetter hashAlgorithmGetter, Address? miner = null, IReadOnlyList> transactions = null, DateTimeOffset? timestamp = null, @@ -202,7 +202,7 @@ public static Block MineGenesis( previousHash: null, timestamp: timestamp ?? new DateTimeOffset(2018, 11, 29, 0, 0, 0, TimeSpan.Zero), transactions: transactions, - hashAlgorithm: hashAlgorithm, + hashAlgorithm: hashAlgorithmGetter(0), protocolVersion: protocolVersion ); @@ -211,7 +211,7 @@ public static Block MineGenesis( public static Block MineNext( Block previousBlock, - HashAlgorithmType hashAlgorithm, + HashAlgorithmGetter hashAlgorithmGetter, IReadOnlyList> txs = null, byte[] nonce = null, long difficulty = 1, @@ -236,7 +236,7 @@ public static Block MineNext( { block = Block.Mine( index: index, - hashAlgorithm: hashAlgorithm, + hashAlgorithm: hashAlgorithmGetter(index), difficulty: difficulty, previousTotalDifficulty: previousBlock.TotalDifficulty, miner: miner ?? previousBlock.Miner.Value, @@ -257,19 +257,19 @@ public static Block MineNext( previousHash: previousHash, timestamp: timestamp, transactions: txs, - hashAlgorithm: hashAlgorithm, + hashAlgorithm: hashAlgorithmGetter(index), protocolVersion: protocolVersion ); } - block.Validate(hashAlgorithm, DateTimeOffset.Now); + block.Validate(hashAlgorithmGetter(index), DateTimeOffset.Now); return block; } public static Block AttachStateRootHash( this Block block, - HashAlgorithmType hashAlgorithm, + HashAlgorithmGetter hashAlgorithmGetter, IStateStore stateStore, IAction blockAction ) @@ -300,7 +300,7 @@ FungibleAssetValue FungibleAssetValueGetter( } var actionEvaluator = new ActionEvaluator( - hashAlgorithmGetter: _ => hashAlgorithm, + hashAlgorithmGetter: hashAlgorithmGetter, policyBlockAction: blockAction, stateGetter: StateGetter, balanceGetter: FungibleAssetValueGetter, @@ -350,8 +350,6 @@ public static BlockChain MakeBlockChain( } ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); - var tx = Transaction.Create( 0, privateKey, @@ -367,11 +365,11 @@ public static BlockChain MakeBlockChain( null, timestamp ?? DateTimeOffset.MinValue, new[] { tx }, - hashAlgorithm: hashAlgorithm, + hashAlgorithm: policy.GetHashAlgorithm(0), protocolVersion: protocolVersion ); genesisBlock = genesisBlock.AttachStateRootHash( - hashAlgorithm, + policy.GetHashAlgorithm, stateStore, policy.BlockAction ); diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index f8670dc930..a9248579ff 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -147,7 +147,7 @@ IEnumerable> renderers throw new ArgumentNullException(nameof(stateStore)); } - _blocks = new BlockSet(_ => HashAlgorithmType.Of(), store); + _blocks = new BlockSet(Policy.GetHashAlgorithm, store); Renderers = renderers is IEnumerable> r ? r.ToImmutableArray() : ImmutableArray>.Empty; @@ -166,8 +166,8 @@ IEnumerable> renderers ? h => trieStateStore.GetTrie(h) : (Func)null; ActionEvaluator = new ActionEvaluator( - _ => HashAlgorithmType.Of(), - policy.BlockAction, + Policy.GetHashAlgorithm, + Policy.BlockAction, GetState, GetBalance, trieGetter); @@ -805,7 +805,7 @@ public async Task> MineBlock( procId ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmType hashAlgorithm = Policy.GetHashAlgorithm(index); ImmutableArray> stagedTransactions = ListStagedTransactions(); _logger.Debug( @@ -1869,7 +1869,7 @@ internal void Swap( Guid obsoleteId = Id; Id = other.Id; Store.SetCanonicalChainId(Id); - _blocks = new BlockSet(_ => HashAlgorithmType.Of(), Store); + _blocks = new BlockSet(Policy.GetHashAlgorithm, Store); TipChanged?.Invoke(this, (oldTip, newTip)); if (render) diff --git a/Libplanet/Blockchain/Policies/BlockPolicy.cs b/Libplanet/Blockchain/Policies/BlockPolicy.cs index 25d70d7e4d..41a5c6b030 100644 --- a/Libplanet/Blockchain/Policies/BlockPolicy.cs +++ b/Libplanet/Blockchain/Policies/BlockPolicy.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blocks; using Libplanet.Tx; @@ -220,5 +221,9 @@ public virtual long GetNextBlockDifficulty(BlockChain blocks) /// public int GetMaxBlockBytes(long index) => index > 0 ? _maxBlockBytes : _maxGenesisBytes; + + /// + public HashAlgorithmType GetHashAlgorithm(long index) => + HashAlgorithmType.Of(); } } diff --git a/Libplanet/Blockchain/Policies/IBlockPolicy.cs b/Libplanet/Blockchain/Policies/IBlockPolicy.cs index 0b1692753b..58c7c33f1e 100644 --- a/Libplanet/Blockchain/Policies/IBlockPolicy.cs +++ b/Libplanet/Blockchain/Policies/IBlockPolicy.cs @@ -89,5 +89,13 @@ BlockChain blockChain /// If it returns less then 1, it is treated as 1, because there is no block /// taking 0 bytes or negative length of bytes. int GetMaxBlockBytes(long index); + + /// + /// Gets the to use for block's proof-of-work. + /// + /// The of the to + /// do proof-of-work. + /// The to use. + HashAlgorithmType GetHashAlgorithm(long index); } } diff --git a/Libplanet/Blocks/Block.cs b/Libplanet/Blocks/Block.cs index 82820227b3..6cc56169b2 100644 --- a/Libplanet/Blocks/Block.cs +++ b/Libplanet/Blocks/Block.cs @@ -563,8 +563,8 @@ internal void Validate(HashAlgorithmType hashAlgorithm, DateTimeOffset currentTi { string message = $"The expected pre evaluation hash of block {Hash} is " + - $"{expectedPreEvaluationHash}, but its pre evaluation hash is " + - $"{PreEvaluationHash}."; + $"{ByteUtil.Hex(expectedPreEvaluationHash)}, but its pre evaluation hash " + + $"is {ByteUtil.Hex(PreEvaluationHash)}."; throw new InvalidBlockPreEvaluationHashException( PreEvaluationHash, expectedPreEvaluationHash.ToImmutableArray(), diff --git a/Libplanet/Net/Swarm.MessageHandlers.cs b/Libplanet/Net/Swarm.MessageHandlers.cs index 013577136c..9ce3ba62f6 100644 --- a/Libplanet/Net/Swarm.MessageHandlers.cs +++ b/Libplanet/Net/Swarm.MessageHandlers.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Libplanet.Blockchain.Policies; @@ -135,7 +134,7 @@ private async Task ProcessBlockHeader( ByteUtil.Hex(header.Hash) ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmType hashAlgorithm = BlockChain.Policy.GetHashAlgorithm(header.Index); try { header.Validate(hashAlgorithm, DateTimeOffset.UtcNow); diff --git a/Libplanet/Net/Swarm.cs b/Libplanet/Net/Swarm.cs index 74895a23aa..3b79e2ee18 100644 --- a/Libplanet/Net/Swarm.cs +++ b/Libplanet/Net/Swarm.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Net; using System.Runtime.CompilerServices; -using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Libplanet.Action; @@ -693,7 +692,8 @@ var pair in completedBlocks.WithCancellation(blockDownloadCts.Token)) block.Index, block.Hash ); - HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of(); + HashAlgorithmType hashAlgorithm = + workspace.Policy.GetHashAlgorithm(block.Index); block.Validate(hashAlgorithm, DateTimeOffset.UtcNow); wStore.PutBlock(block); if (tempTip is null || block.Index > tempTip.Index) From ff07ecad7dce5133238736802f9a9c76e2feb0d2 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 15:34:53 +0900 Subject: [PATCH 20/22] Add a compacter AttachStateRootHash() overload --- .../Action/AccountStateDeltaImplTest.cs | 6 +- .../Action/AccountStateDeltaImplV0Test.cs | 6 +- .../Action/AccountStateDeltaTest.cs | 6 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 6 +- .../Blockchain/BlockChainTest.Append.cs | 48 ++------ .../Blockchain/BlockChainTest.Internals.cs | 2 +- .../BlockChainTest.MultiAlgorithms.cs | 12 +- .../BlockChainTest.ValidateNextBlock.cs | 22 ++-- Libplanet.Tests/Blockchain/BlockChainTest.cs | 67 ++++------- Libplanet.Tests/Fixtures/IntegerSet.cs | 8 +- Libplanet.Tests/Net/SwarmTest.Broadcast.cs | 12 +- Libplanet.Tests/Net/SwarmTest.Consensus.cs | 16 +-- Libplanet.Tests/Net/SwarmTest.Preload.cs | 17 +-- Libplanet.Tests/Net/SwarmTest.cs | 23 +--- Libplanet.Tests/Store/StoreFixture.cs | 8 +- Libplanet.Tests/TestUtils.cs | 109 ++++++++++-------- 16 files changed, 136 insertions(+), 232 deletions(-) diff --git a/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs b/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs index afd84f83e6..d1d9f34324 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaImplTest.cs @@ -61,11 +61,7 @@ public override BlockChain TransferAssetInBlock() chain.Policy.GetHashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash( - chain.Policy.GetHashAlgorithm, - chain.StateStore, - chain.Policy.BlockAction - ) + ).AttachStateRootHash(chain.StateStore, chain.Policy) ); Assert.Equal( DumbAction.DumbCurrency * 5, diff --git a/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs b/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs index 3090d51b0e..56a8530ca2 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaImplV0Test.cs @@ -60,11 +60,7 @@ public override BlockChain TransferAssetInBlock() chain.Policy.GetHashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash( - chain.Policy.GetHashAlgorithm, - chain.StateStore, - chain.Policy.BlockAction - ) + ).AttachStateRootHash(chain.StateStore, chain.Policy) ); Assert.Equal( DumbAction.DumbCurrency * 6, diff --git a/Libplanet.Tests/Action/AccountStateDeltaTest.cs b/Libplanet.Tests/Action/AccountStateDeltaTest.cs index f075ca3fd6..562a3e3e46 100644 --- a/Libplanet.Tests/Action/AccountStateDeltaTest.cs +++ b/Libplanet.Tests/Action/AccountStateDeltaTest.cs @@ -221,11 +221,7 @@ public virtual BlockChain TransferAssetInBlock() chain.Policy.GetHashAlgorithm, new[] { tx }, protocolVersion: ProtocolVersion - ).AttachStateRootHash( - chain.Policy.GetHashAlgorithm, - stateStore, - chain.Policy.BlockAction - ) + ).AttachStateRootHash(stateStore, chain.Policy) ); Assert.Equal( DumbAction.DumbCurrency * 5, diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 6210984e76..182a6335dd 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -76,10 +76,10 @@ public void Idempotent() var stateRootBlock = TestUtils.MineGenesis( hashAlgorithmGetter: hashAlgorithmGetter, timestamp: timestamp, - transactions: txs).AttachStateRootHash(hashAlgorithmGetter, stateStore, null); + transactions: txs).AttachStateRootHash(hashAlgorithmGetter(0), stateStore, null); var actionEvaluator = new ActionEvaluator( - hashAlgorithmGetter: _ => HashAlgorithmType.Of(), + hashAlgorithmGetter: hashAlgorithmGetter, policyBlockAction: null, stateGetter: ActionEvaluator.NullStateGetter, balanceGetter: ActionEvaluator.NullBalanceGetter, @@ -933,7 +933,7 @@ public void EvaluatePolicyBlockAction() _policy.GetHashAlgorithm, txs, difficulty: chain.Policy.GetNextBlockDifficulty(chain) - ).AttachStateRootHash(_policy.GetHashAlgorithm, chain.StateStore, _policy.BlockAction); + ).AttachStateRootHash(chain.StateStore, _policy); var stateCompleterSet = StateCompleterSet.Recalculate; AccountStateGetter accountStateGetter = diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index f441bb90f7..93a283c3ed 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -47,11 +47,7 @@ Func getTxExecution miner: addresses[4], difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - _blockChain.Policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block1); Block block2 = TestUtils.MineNext( block1, @@ -59,11 +55,7 @@ Func getTxExecution txs, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - _blockChain.Policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); foreach (Transaction tx in txs) { Assert.Null(getTxExecution(genesis.Hash, tx.Id)); @@ -214,11 +206,7 @@ Func getTxExecution _blockChain.Policy.GetHashAlgorithm, new[] { tx1Transfer, tx2Error, tx3Transfer }, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash( - _blockChain.Policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block3); var txExecution1 = getTxExecution(block3.Hash, tx1Transfer.Id); _logger.Verbose(nameof(txExecution1) + " = {@TxExecution}", txExecution1); @@ -479,11 +467,7 @@ bool IsSignerValid(Transaction tx, BlockChain chain) miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - policy.GetHashAlgorithm, - blockChain.StateStore, - policy.BlockAction - ); + ).AttachStateRootHash(blockChain.StateStore, policy); blockChain.Append(block1); @@ -494,11 +478,7 @@ bool IsSignerValid(Transaction tx, BlockChain chain) miner: miner, difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - policy.GetHashAlgorithm, - blockChain.StateStore, - policy.BlockAction - ); + ).AttachStateRootHash(blockChain.StateStore, policy); Assert.Throws(() => blockChain.Append(block2)); } @@ -518,11 +498,7 @@ public void UnstageAfterAppendComplete() miner: addresses[4], difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash( - _blockChain.Policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + .AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block1); Assert.Empty(_blockChain.GetStagedTransactionIds()); @@ -536,11 +512,7 @@ public void UnstageAfterAppendComplete() ImmutableArray>.Empty.Add(txs[0]), difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - _blockChain.Policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block2); Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count); StageTransactions(txs); @@ -560,11 +532,7 @@ public void UnstageAfterAppendComplete() ImmutableArray>.Empty.Add(txs[1]), difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - _blockChain.Policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block3); Assert.Empty(_blockChain.GetStagedTransactionIds()); } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs index dacbb11b31..0f0e14149c 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs @@ -128,7 +128,7 @@ public void ExecuteActions() _policy.GetHashAlgorithm, txs, difficulty: _policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append( block1, diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs b/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs index 8cdb35c3bd..85448c29ef 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.MultiAlgorithms.cs @@ -43,13 +43,13 @@ public void ValidateWithMultipleAlgorithms() fx.StateStore, new DumbAction[0] ); - HashAlgorithmGetter invalidAlgoGetter = _ => HashAlgorithmType.Of(); - Block invalid1 = TestUtils.MineNext(chain.Genesis, invalidAlgoGetter) - .AttachStateRootHash(invalidAlgoGetter, fx.StateStore, policy.BlockAction); + HashAlgorithmType invalidAlgo = HashAlgorithmType.Of(); + Block invalid1 = TestUtils.MineNext(chain.Genesis, _ => invalidAlgo) + .AttachStateRootHash(invalidAlgo, fx.StateStore, policy.BlockAction); Assert.Throws(() => chain.Append(invalid1)); - HashAlgorithmGetter validAlgoGetter = _ => HashAlgorithmType.Of(); - Block valid1 = TestUtils.MineNext(chain.Genesis, validAlgoGetter) - .AttachStateRootHash(validAlgoGetter, fx.StateStore, policy.BlockAction); + HashAlgorithmType validAlgo = HashAlgorithmType.Of(); + Block valid1 = TestUtils.MineNext(chain.Genesis, _ => validAlgo) + .AttachStateRootHash(validAlgo, fx.StateStore, policy.BlockAction); chain.Append(valid1); } } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index d83bd5d2e7..70fa947d59 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -25,7 +25,7 @@ public void ValidateNextBlock() _fx.GenesisBlock.Hash, _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(validNextBlock); Assert.Equal(_blockChain.Tip, validNextBlock); } @@ -43,7 +43,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: 1 - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block1); Block block2 = Block.Mine( @@ -56,7 +56,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: 0 - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); Assert.Throws(() => _blockChain.Append(block2)); Assert.Throws(() => @@ -71,7 +71,7 @@ private void ValidateNextBlockProtocolVersion() _fx.GenesisBlock.Timestamp.AddDays(1), _emptyTransaction, protocolVersion: Block.CurrentProtocolVersion + 1 - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block3); }); } @@ -91,7 +91,7 @@ private void ValidateNextBlockInvalidIndex() prev.Hash, prev.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); Assert.Throws( () => _blockChain.Append(blockWithAlreadyUsedIndex) ); @@ -105,7 +105,7 @@ private void ValidateNextBlockInvalidIndex() prev.Hash, prev.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); Assert.Throws( () => _blockChain.Append(blockWithIndexAfterNonexistentIndex) ); @@ -125,7 +125,7 @@ private void ValidateNextBlockInvalidDifficulty() _validNext.Hash, _validNext.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); Assert.Throws(() => _blockChain.Append(invalidDifficultyBlock)); } @@ -144,7 +144,7 @@ private void ValidateNextBlockInvalidTotalDifficulty() _validNext.Hash, _validNext.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); Assert.Throws(() => _blockChain.Append(invalidTotalDifficultyBlock)); } @@ -197,7 +197,7 @@ private void ValidateNextBlockInvalidStateRootHash() // calculate state root hash. To resolve this problem, // it should be moved into StateStore. var genesisBlock = TestUtils.MineGenesis(_fx.GetHashAlgorithm) - .AttachStateRootHash(_fx.GetHashAlgorithm, _fx.StateStore, policy.BlockAction); + .AttachStateRootHash(_fx.StateStore, policy); var store = new DefaultStore(null); var chain = new BlockChain( policy, @@ -216,8 +216,8 @@ private void ValidateNextBlockInvalidStateRootHash() genesisBlock.Timestamp.AddSeconds(1), _emptyTransaction ) - .AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction) - .AttachStateRootHash(policy.GetHashAlgorithm, chain.StateStore, policy.BlockAction); + .AttachStateRootHash(_fx.StateStore, _policy) + .AttachStateRootHash(chain.StateStore, policy); chain.Append(validNext); var invalidStateRootHash = Block.Mine( diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 4dbd2be131..142724edfd 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -73,7 +73,7 @@ public BlockChainTest(ITestOutputHelper output) _fx.GenesisBlock.Hash, _fx.GenesisBlock.Timestamp.AddSeconds(1), _emptyTransaction - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); } public void Dispose() @@ -308,7 +308,7 @@ IEnumerable NonRehearsalExecutions() => new[] { tx }, miner: miner, difficulty: policy.GetNextBlockDifficulty(_blockChain) - ).AttachStateRootHash(policy.GetHashAlgorithm, fx.StateStore, policy.BlockAction); + ).AttachStateRootHash(fx.StateStore, policy); chain.Append(block); var forked = chain.Fork(chain.Genesis.Hash); forked.Append(block); @@ -585,7 +585,7 @@ public async Task ForkShouldSkipExecuteAndRenderGenesis() var genesis = TestUtils.MineGenesis( _policy.GetHashAlgorithm, transactions: new[] { _fx.MakeTransaction(new[] { action }) } - ).AttachStateRootHash(_policy.GetHashAlgorithm, stateStore, _policy.BlockAction); + ).AttachStateRootHash(stateStore, _policy); store.PutBlock(genesis); var renderer = new RecordingActionRenderer(); var blockChain = new BlockChain( @@ -636,7 +636,7 @@ public void DetectInvalidTxNonce() null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(b1); Block b2 = TestUtils.MineNext( @@ -646,7 +646,7 @@ public void DetectInvalidTxNonce() null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); Assert.Throws(() => _blockChain.Append(b2)); @@ -664,7 +664,7 @@ public void DetectInvalidTxNonce() null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(b2); } @@ -700,7 +700,7 @@ public void ForkTxNonce() null, _blockChain.Policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(b1); @@ -720,7 +720,7 @@ public void ForkTxNonce() null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10)) - .AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + .AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(b2); Assert.Equal(2, _blockChain.GetNextTxNonce(address)); @@ -774,7 +774,7 @@ public void Swap(bool render) miner: minerAddress, difficulty: _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(block1); PrivateKey privateKey = new PrivateKey(new byte[] @@ -839,11 +839,7 @@ public void Swap(bool render) null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - _policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(b); } @@ -875,7 +871,7 @@ public void Swap(bool render) null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); fork.Append( forkTip, DateTimeOffset.UtcNow, @@ -1016,11 +1012,7 @@ public async Task ReorgIsUnableToHeterogenousChain(bool render) Block genesis2 = TestUtils.MineGenesis( _policy.GetHashAlgorithm, timestamp: DateTimeOffset.UtcNow - ).AttachStateRootHash( - _policy.GetHashAlgorithm, - fx2.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(fx2.StateStore, _policy); var chain2 = new BlockChain( _policy, _stagePolicy, @@ -1083,7 +1075,7 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() b, policy.GetHashAlgorithm, txs - ).AttachStateRootHash(policy.GetHashAlgorithm, _fx.StateStore, policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, policy); chain.Append(b); } @@ -1125,11 +1117,7 @@ public void GetStateReturnsEarlyForNonexistentAccount() b, blockPolicy.GetHashAlgorithm, blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - blockPolicy.GetHashAlgorithm, - _fx.StateStore, - blockPolicy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, blockPolicy); chain.Append(b); } @@ -1305,7 +1293,7 @@ public void GetNextTxNonce() null, _policy.GetNextBlockDifficulty(_blockChain), blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash(_policy.GetHashAlgorithm, _fx.StateStore, _policy.BlockAction); + ).AttachStateRootHash(_fx.StateStore, _policy); _blockChain.Append(b1); Assert.Equal(1, _blockChain.GetNextTxNonce(address)); @@ -1398,18 +1386,17 @@ public void ValidateTxNonces() var genesis = _blockChain.Genesis; - Block MineNext(Block block, IReadOnlyList> txs) - where T : IAction, new() => TestUtils.MineNext( + Block MineNext( + Block block, + IReadOnlyList> txs + ) => + TestUtils.MineNext( block, _policy.GetHashAlgorithm, txs, difficulty: 1024, blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - _policy.GetHashAlgorithm, - _fx.StateStore, - _policy.BlockAction - ); + ).AttachStateRootHash(_fx.StateStore, _policy); Transaction[] txsA = { @@ -1567,11 +1554,7 @@ internal static (Address, Address[] Addresses, BlockChain Chain) Guid chainId = Guid.NewGuid(); Block genesisBlock = TestUtils.MineGenesis( blockPolicy.GetHashAlgorithm - ).AttachStateRootHash( - blockPolicy.GetHashAlgorithm, - stateStore, - blockPolicy.BlockAction - ); + ).AttachStateRootHash(stateStore, blockPolicy); var chain = new BlockChain( blockPolicy, new VolatileStagePolicy(), @@ -1635,11 +1618,7 @@ void BuildIndex(Guid id, Block block) blockPolicy.GetHashAlgorithm, new[] { tx }, blockInterval: TimeSpan.FromSeconds(10) - ).AttachStateRootHash( - blockPolicy.GetHashAlgorithm, - stateStore, - blockPolicy.BlockAction - ); + ).AttachStateRootHash(stateStore, blockPolicy); previousStates = b.ProtocolVersion > 0 ? new AccountStateDeltaImpl( dirty.GetValueOrDefault, diff --git a/Libplanet.Tests/Fixtures/IntegerSet.cs b/Libplanet.Tests/Fixtures/IntegerSet.cs index c5fb07ecbe..6afe6499ae 100644 --- a/Libplanet.Tests/Fixtures/IntegerSet.cs +++ b/Libplanet.Tests/Fixtures/IntegerSet.cs @@ -75,7 +75,7 @@ public IntegerSet( previousHash: null, timestamp: DateTimeOffset.UtcNow, transactions: Txs - ).AttachStateRootHash(policy.GetHashAlgorithm, StateStore, policy.BlockAction); + ).AttachStateRootHash(StateStore, policy); Chain = new BlockChain( policy, new VolatileStagePolicy(), @@ -154,11 +154,7 @@ public async Task> Mine(CancellationToken cancellationToken = DateTimeOffset.UtcNow, cancellationToken: cancellationToken ); - return draft.AttachStateRootHash( - Chain.Policy.GetHashAlgorithm, - StateStore, - Policy.BlockAction - ); + return draft.AttachStateRootHash(StateStore, Policy); } public IAccountStateDelta CreateAccountStateDelta(Address signer, BlockHash? offset = null) diff --git a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs index 75b0bc44c0..ea77777b8f 100644 --- a/Libplanet.Tests/Net/SwarmTest.Broadcast.cs +++ b/Libplanet.Tests/Net/SwarmTest.Broadcast.cs @@ -640,11 +640,7 @@ public async Task BroadcastBlockWithSkip() new[] { transactions[0] }, null, policy.GetNextBlockDifficulty(blockChain)) - .AttachStateRootHash( - policy.GetHashAlgorithm, - blockChain.StateStore, - policy.BlockAction - ); + .AttachStateRootHash(blockChain.StateStore, policy); blockChain.Append(block1, DateTimeOffset.MinValue.AddSeconds(3), true, true, false); var block2 = TestUtils.MineNext( block1, @@ -652,11 +648,7 @@ public async Task BroadcastBlockWithSkip() new[] { transactions[1] }, null, policy.GetNextBlockDifficulty(blockChain) - ).AttachStateRootHash( - policy.GetHashAlgorithm, - blockChain.StateStore, - policy.BlockAction - ); + ).AttachStateRootHash(blockChain.StateStore, policy); blockChain.Append(block2, DateTimeOffset.MinValue.AddSeconds(8), true, true, false); Log.Debug("Ready to broadcast blocks."); minerSwarm.BroadcastBlock(block2); diff --git a/Libplanet.Tests/Net/SwarmTest.Consensus.cs b/Libplanet.Tests/Net/SwarmTest.Consensus.cs index 1ea72fbcf0..d8aa293c4d 100644 --- a/Libplanet.Tests/Net/SwarmTest.Consensus.cs +++ b/Libplanet.Tests/Net/SwarmTest.Consensus.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Security.Cryptography; using System.Threading.Tasks; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -59,24 +58,18 @@ public async Task DetermineCanonicalChain(short canonComparerType) await chain1.MineBlock(miner1.Address); await chain1.MineBlock(miner2.Address); - HashAlgorithmType hashAlgorithm; Block bestBlock; switch (canonComparerType) { default: long nextDifficulty = (long)chain1.Tip.TotalDifficulty + policy.GetNextBlockDifficulty(chain2); - hashAlgorithm = HashAlgorithmType.Of(); bestBlock = TestUtils.MineNext( chain2.Tip, policy.GetHashAlgorithm, difficulty: nextDifficulty, blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash( - policy.GetHashAlgorithm, - chain2.StateStore, - policy.BlockAction - ); + ).AttachStateRootHash(chain2.StateStore, policy); _output.WriteLine("chain1's total difficulty: {0}", chain1.Tip.TotalDifficulty); _output.WriteLine("chain2's total difficulty: {0}", bestBlock.TotalDifficulty); break; @@ -86,17 +79,12 @@ public async Task DetermineCanonicalChain(short canonComparerType) string hashStr; do { - hashAlgorithm = HashAlgorithmType.Of(); bestBlock = TestUtils.MineNext( chain2.Tip, policy.GetHashAlgorithm, difficulty: policy.GetNextBlockDifficulty(chain2), blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash( - policy.GetHashAlgorithm, - chain2.StateStore, - policy.BlockAction - ); + ).AttachStateRootHash(chain2.StateStore, policy); hashStr = bestBlock.Hash.ToString(); _output.WriteLine("chain1's tip hash: {0}", chain1.Tip.Hash); _output.WriteLine("chain2's tip hash: {0}", bestBlock.Hash); diff --git a/Libplanet.Tests/Net/SwarmTest.Preload.cs b/Libplanet.Tests/Net/SwarmTest.Preload.cs index 4617dc2874..266e43e310 100644 --- a/Libplanet.Tests/Net/SwarmTest.Preload.cs +++ b/Libplanet.Tests/Net/SwarmTest.Preload.cs @@ -116,10 +116,7 @@ public async Task Preload() previousBlock: i == 0 ? minerChain.Genesis : blocks[i - 1], hashAlgorithmGetter: minerChain.Policy.GetHashAlgorithm, difficulty: 1024) - .AttachStateRootHash( - minerChain.Policy.GetHashAlgorithm, - minerChain.StateStore, - minerChain.Policy.BlockAction); + .AttachStateRootHash(minerChain.StateStore, minerChain.Policy); blocks.Add(block); if (i != 10) { @@ -332,11 +329,7 @@ public async Task PreloadWithFailedActions() new[] { tx }, difficulty: policy.GetNextBlockDifficulty(minerChain), blockInterval: TimeSpan.FromSeconds(1) - ).AttachStateRootHash( - minerChain.Policy.GetHashAlgorithm, - minerChain.StateStore, - minerChain.Policy.BlockAction - ); + ).AttachStateRootHash(minerChain.StateStore, minerChain.Policy); minerSwarm.BlockChain.Append(block, DateTimeOffset.UtcNow, false, true, false); await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(1)); @@ -804,11 +797,7 @@ public async Task PreloadFromTheMostDifficultChain() minerChain2.Tip, minerChain2.Policy.GetHashAlgorithm, difficulty: nextDifficulty - ).AttachStateRootHash( - minerChain2.Policy.GetHashAlgorithm, - minerChain2.StateStore, - minerChain2.Policy.BlockAction - ); + ).AttachStateRootHash(minerChain2.StateStore, minerChain2.Policy); minerChain2.Append(block); Assert.True(minerChain1.Count > minerChain2.Count); diff --git a/Libplanet.Tests/Net/SwarmTest.cs b/Libplanet.Tests/Net/SwarmTest.cs index bf4ac9a1e3..dc6d715ad9 100644 --- a/Libplanet.Tests/Net/SwarmTest.cs +++ b/Libplanet.Tests/Net/SwarmTest.cs @@ -719,11 +719,7 @@ public async Task RemoveForkedChainWhenFillBlocksAsyncFail() policy2.GetHashAlgorithm, difficulty: (long)chain1.Tip.TotalDifficulty + 1, blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash( - policy2.GetHashAlgorithm, - chain2.StateStore, - chain2.Policy.BlockAction - ); + ).AttachStateRootHash(chain2.StateStore, policy2); chain2.Append(block3); try { @@ -824,7 +820,7 @@ public async Task ForkByDifficulty() policy.GetHashAlgorithm, difficulty: nextDifficulty, blockInterval: TimeSpan.FromMilliseconds(1) - ).AttachStateRootHash(policy.GetHashAlgorithm, chain2.StateStore, policy.BlockAction); + ).AttachStateRootHash(chain2.StateStore, policy); chain2.Append(block); Assert.True(chain1.Tip.Index > chain2.Tip.Index); @@ -1430,10 +1426,7 @@ public async Task DoNotFillWhenGetAllBlockAtFirstTimeFromSender() { Block block = TestUtils.MineNext(chain.Tip, chain.Policy.GetHashAlgorithm, difficulty: 1024) - .AttachStateRootHash( - chain.Policy.GetHashAlgorithm, - chain.StateStore, - chain.Policy.BlockAction); + .AttachStateRootHash(chain.StateStore, chain.Policy); chain.Append(block); } @@ -1473,10 +1466,7 @@ public async Task FillWhenGetAllBlocksFromSender() { Block block = TestUtils.MineNext(chain.Tip, chain.Policy.GetHashAlgorithm, difficulty: 1024) - .AttachStateRootHash( - chain.Policy.GetHashAlgorithm, - chain.StateStore, - chain.Policy.BlockAction); + .AttachStateRootHash(chain.StateStore, chain.Policy); chain.Append(block); } @@ -1514,10 +1504,7 @@ public async Task DoNotFillMultipleTimes() BlockChain chain = receiver.BlockChain; Block b1 = TestUtils.MineNext(chain.Genesis, chain.Policy.GetHashAlgorithm, difficulty: 1024) - .AttachStateRootHash( - chain.Policy.GetHashAlgorithm, - sender1.BlockChain.StateStore, - sender1.BlockChain.Policy.BlockAction); + .AttachStateRootHash(sender1.BlockChain.StateStore, chain.Policy); try { diff --git a/Libplanet.Tests/Store/StoreFixture.cs b/Libplanet.Tests/Store/StoreFixture.cs index ff473eaba2..b171319d4b 100644 --- a/Libplanet.Tests/Store/StoreFixture.cs +++ b/Libplanet.Tests/Store/StoreFixture.cs @@ -94,13 +94,13 @@ protected StoreFixture(IAction blockAction = null) var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); GenesisBlock = TestUtils.MineGenesis(GetHashAlgorithm) - .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + .AttachStateRootHash(GetHashAlgorithm(0), stateStore, blockAction); Block1 = TestUtils.MineNext(GenesisBlock, GetHashAlgorithm) - .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + .AttachStateRootHash(GetHashAlgorithm(1), stateStore, blockAction); Block2 = TestUtils.MineNext(Block1, GetHashAlgorithm) - .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + .AttachStateRootHash(GetHashAlgorithm(2), stateStore, blockAction); Block3 = TestUtils.MineNext(Block2, GetHashAlgorithm) - .AttachStateRootHash(GetHashAlgorithm, stateStore, blockAction); + .AttachStateRootHash(GetHashAlgorithm(3), stateStore, blockAction); Transaction1 = MakeTransaction(new List(), ImmutableHashSet
.Empty); Transaction2 = MakeTransaction(new List(), ImmutableHashSet
.Empty); diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 3f2bfee73a..4740cf3a8c 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -269,55 +269,20 @@ public static Block MineNext( public static Block AttachStateRootHash( this Block block, - HashAlgorithmGetter hashAlgorithmGetter, IStateStore stateStore, - IAction blockAction + IBlockPolicy policy ) - where T : IAction, new() - { - IValue StateGetter( - Address address, BlockHash? blockHash, StateCompleter stateCompleter) => - blockHash is null - ? null - : stateStore.GetState(ToStateKey(address), blockHash.Value); - - FungibleAssetValue FungibleAssetValueGetter( - Address address, - Currency currency, - BlockHash? blockHash, - FungibleAssetStateCompleter stateCompleter) - { - if (blockHash is null) - { - return FungibleAssetValue.FromRawValue(currency, 0); - } + where T : IAction, new() => + AttachStateRootHash(block, policy.GetHashAlgorithm, stateStore, policy.BlockAction); - IValue value = stateStore.GetState( - ToFungibleAssetKey(address, currency), blockHash.Value); - return FungibleAssetValue.FromRawValue( - currency, - value is Bencodex.Types.Integer i ? i.Value : 0); - } - - var actionEvaluator = new ActionEvaluator( - hashAlgorithmGetter: hashAlgorithmGetter, - policyBlockAction: blockAction, - stateGetter: StateGetter, - balanceGetter: FungibleAssetValueGetter, - trieGetter: null - ); - var actionEvaluationResult = actionEvaluator - .Evaluate(block, StateCompleterSet.Reject) - .GetTotalDelta(ToStateKey, ToFungibleAssetKey); - stateStore.SetStates(block, actionEvaluationResult); - if (stateStore is TrieStateStore trieStateStore) - { - block = new Block(block, trieStateStore.GetRootHash(block.Hash)); - stateStore.SetStates(block, actionEvaluationResult); - } - - return block; - } + public static Block AttachStateRootHash( + this Block block, + HashAlgorithmType hashAlgorithm, + IStateStore stateStore, + IAction blockAction + ) + where T : IAction, new() => + AttachStateRootHash(block, _ => hashAlgorithm, stateStore, blockAction); public static string ToString(BitArray bitArray) { @@ -405,5 +370,57 @@ public static PrivateKey GeneratePrivateKeyOfBucketIndex(Address tableAddress, i return privateKey; } + + private static Block AttachStateRootHash( + this Block block, + HashAlgorithmGetter hashAlgorithmGetter, + IStateStore stateStore, + IAction blockAction + ) + where T : IAction, new() + { + IValue StateGetter( + Address address, BlockHash? blockHash, StateCompleter stateCompleter) => + blockHash is null + ? null + : stateStore.GetState(ToStateKey(address), blockHash.Value); + + FungibleAssetValue FungibleAssetValueGetter( + Address address, + Currency currency, + BlockHash? blockHash, + FungibleAssetStateCompleter stateCompleter) + { + if (blockHash is null) + { + return FungibleAssetValue.FromRawValue(currency, 0); + } + + IValue value = stateStore.GetState( + ToFungibleAssetKey(address, currency), blockHash.Value); + return FungibleAssetValue.FromRawValue( + currency, + value is Bencodex.Types.Integer i ? i.Value : 0); + } + + var actionEvaluator = new ActionEvaluator( + hashAlgorithmGetter: hashAlgorithmGetter, + policyBlockAction: blockAction, + stateGetter: StateGetter, + balanceGetter: FungibleAssetValueGetter, + trieGetter: null + ); + var actionEvaluationResult = actionEvaluator + .Evaluate(block, StateCompleterSet.Reject) + .GetTotalDelta(ToStateKey, ToFungibleAssetKey); + stateStore.SetStates(block, actionEvaluationResult); + if (stateStore is TrieStateStore trieStateStore) + { + block = new Block(block, trieStateStore.GetRootHash(block.Hash)); + stateStore.SetStates(block, actionEvaluationResult); + } + + return block; + } } } From 38b79715098eec845ac12d5b09c7f111b0a4e0b2 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 15:51:21 +0900 Subject: [PATCH 21/22] Add hashAlgorithmGetter to BlockPolicy() ctor --- CHANGES.md | 4 +++- .../Blockchain/Policies/BlockPolicyTest.cs | 20 +++++++++++++++++++ Libplanet/Blockchain/Policies/BlockPolicy.cs | 17 ++++++++++++---- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6149914aa4..7c1e536218 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -109,7 +109,7 @@ To be released. - Hash algorithm for PoW (Hashcash) became configurable. [#1314], [#1352] - Added `IBlockPolicy.GetHashAlgorithm()` method. - - Added optional `HashAlgorithmType? hashAlgorithm` parameter to + - Added an optional `HashAlgorithmType? hashAlgorithm` parameter to `Block(long, long, BigInteger, Nonce, Address?, BlockHash?, DateTimeOffset, IReadOnlyList>, ImmutableArray?, HashDigest?, int protocolVersion)` constructor. @@ -144,6 +144,8 @@ To be released. - Added `hashAlgorithmGetter` parameter to `BlockSet()` constructor. - Added `hashAlgorithm` parameter to `BlockChain.MakeGenesisBlock()` method. + - Added an optional `hashAlgorithmGetter` parameter to `BlockPolicy()` + constructor. - Added `IActionContext.TxId` property. [[#1275]] - Added `IStore.PutTxExecution(TxSuccess)` method. [[#1156], [#1289]] - Added `IStore.PutTxExecution(TxFailure)` method. [[#1156], [#1289]] diff --git a/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs b/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs index b3b00e8c7a..290e1ddaf3 100644 --- a/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs +++ b/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs @@ -1,4 +1,5 @@ using System; +using System.Security.Cryptography; using System.Threading.Tasks; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -185,5 +186,24 @@ public async Task GetNextBlockDifficulty() _policy.GetNextBlockDifficulty(chain) ); } + + [Fact] + public void GetHashAlgorithm() + { + Assert.Equal(HashAlgorithmType.Of(), _policy.GetHashAlgorithm(0)); + Assert.Equal(HashAlgorithmType.Of(), _policy.GetHashAlgorithm(1)); + Assert.Equal(HashAlgorithmType.Of(), _policy.GetHashAlgorithm(2)); + Assert.Equal(HashAlgorithmType.Of(), _policy.GetHashAlgorithm(10)); + Assert.Equal(HashAlgorithmType.Of(), _policy.GetHashAlgorithm(15)); + + var p = new BlockPolicy(hashAlgorithmGetter: i => + i % 2 == 0 ? HashAlgorithmType.Of() : HashAlgorithmType.Of() + ); + Assert.Equal(HashAlgorithmType.Of(), p.GetHashAlgorithm(0)); + Assert.Equal(HashAlgorithmType.Of(), p.GetHashAlgorithm(1)); + Assert.Equal(HashAlgorithmType.Of(), p.GetHashAlgorithm(2)); + Assert.Equal(HashAlgorithmType.Of(), p.GetHashAlgorithm(10)); + Assert.Equal(HashAlgorithmType.Of(), p.GetHashAlgorithm(15)); + } } } diff --git a/Libplanet/Blockchain/Policies/BlockPolicy.cs b/Libplanet/Blockchain/Policies/BlockPolicy.cs index 41a5c6b030..c3c5661de8 100644 --- a/Libplanet/Blockchain/Policies/BlockPolicy.cs +++ b/Libplanet/Blockchain/Policies/BlockPolicy.cs @@ -18,6 +18,7 @@ public class BlockPolicy : IBlockPolicy private readonly int _maxBlockBytes; private readonly int _maxGenesisBytes; private readonly Func, BlockChain, bool> _doesTransactionFollowPolicy; + private readonly HashAlgorithmGetter _hashAlgorithmGetter; /// /// Creates a with configuring @@ -46,6 +47,8 @@ public class BlockPolicy : IBlockPolicy /// /// The custom rule to determine which is the canonical /// chain. If omitted, is used by default. + /// Configures . + /// If omitted, SHA-256 is used for every block. public BlockPolicy( IAction blockAction = null, int blockIntervalMilliseconds = 5000, @@ -55,7 +58,8 @@ public BlockPolicy( int maxBlockBytes = 100 * 1024, int maxGenesisBytes = 1024 * 1024, Func, BlockChain, bool> doesTransactionFollowPolicy = null, - IComparer canonicalChainComparer = null + IComparer canonicalChainComparer = null, + HashAlgorithmGetter hashAlgorithmGetter = null ) : this( blockAction, @@ -66,7 +70,8 @@ public BlockPolicy( maxBlockBytes, maxGenesisBytes, doesTransactionFollowPolicy, - canonicalChainComparer) + canonicalChainComparer, + hashAlgorithmGetter) { } @@ -96,6 +101,8 @@ public BlockPolicy( /// chain. If omitted, (having /// configured to triple of /// ) is used by default. + /// Configures . + /// If omitted, SHA-256 is used for every block. public BlockPolicy( IAction blockAction, TimeSpan blockInterval, @@ -105,7 +112,8 @@ public BlockPolicy( int maxBlockBytes, int maxGenesisBytes, Func, BlockChain, bool> doesTransactionFollowPolicy = null, - IComparer canonicalChainComparer = null + IComparer canonicalChainComparer = null, + HashAlgorithmGetter hashAlgorithmGetter = null ) { if (blockInterval < TimeSpan.Zero) @@ -143,6 +151,7 @@ public BlockPolicy( _doesTransactionFollowPolicy = doesTransactionFollowPolicy ?? ((_, __) => true); CanonicalChainComparer = canonicalChainComparer ?? new TotalDifficultyComparer(blockInterval + blockInterval + blockInterval); + _hashAlgorithmGetter = hashAlgorithmGetter ?? (_ => HashAlgorithmType.Of()); } /// @@ -224,6 +233,6 @@ public virtual long GetNextBlockDifficulty(BlockChain blocks) /// public HashAlgorithmType GetHashAlgorithm(long index) => - HashAlgorithmType.Of(); + _hashAlgorithmGetter(index); } } From 8dc9f89ca0860476a591647a10d504f8d1cad4eb Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 24 Jun 2021 17:28:44 +0900 Subject: [PATCH 22/22] HashAlgorithmTable.ToHashAlgorithmGetter() ext method --- CHANGES.md | 1 + .../Blocks/HashAlgorithmTableTest.cs | 46 +++++++++++++++ Libplanet/Blocks/HashAlgorithmTable.cs | 59 +++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 Libplanet.Tests/Blocks/HashAlgorithmTableTest.cs create mode 100644 Libplanet/Blocks/HashAlgorithmTable.cs diff --git a/CHANGES.md b/CHANGES.md index 7c1e536218..bd390a73d9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -202,6 +202,7 @@ To be released. - Added `HashDigest.DeriveFrom()` method. [[#1197]] - Added `HashAlgorithmType` class. [[#1314], [#1352]] - Added `HashAlgorithmGetter` delegate. [[#1314], [#1352]] + - Added `HashAlgorithmTable` static class. [[#1314], [#1352]] - Added `BlockChain.GetTxExecution()` method. [[#1156], [#1289]] - Added `StunMessage.ParseAsync(Stream, CancellationToken)` method. [[#1228]] diff --git a/Libplanet.Tests/Blocks/HashAlgorithmTableTest.cs b/Libplanet.Tests/Blocks/HashAlgorithmTableTest.cs new file mode 100644 index 0000000000..5f12e3d1c5 --- /dev/null +++ b/Libplanet.Tests/Blocks/HashAlgorithmTableTest.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using Libplanet.Blocks; +using Xunit; + +namespace Libplanet.Tests.Blocks +{ + public class HashAlgorithmTableTest + { + [Fact] + public void ToHashAlgorithmGetter() + { + Dictionary table = new Dictionary + { + [0] = HashAlgorithmType.Of(), + [10] = HashAlgorithmType.Of(), + [100] = HashAlgorithmType.Of(), + }; + HashAlgorithmGetter hashAlgorithmGetter = table.ToHashAlgorithmGetter(); + + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(0)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(1)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(9)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(10)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(11)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(50)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(99)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(100)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(101)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(200)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(500)); + Assert.Equal(HashAlgorithmType.Of(), hashAlgorithmGetter(long.MaxValue)); + + Assert.Throws( + () => new KeyValuePair[0].ToHashAlgorithmGetter() + ); + Assert.Throws(() => + table.Append( + new KeyValuePair(10, HashAlgorithmType.Of()) + ).ToHashAlgorithmGetter() + ); + } + } +} diff --git a/Libplanet/Blocks/HashAlgorithmTable.cs b/Libplanet/Blocks/HashAlgorithmTable.cs new file mode 100644 index 0000000000..05bd5c1679 --- /dev/null +++ b/Libplanet/Blocks/HashAlgorithmTable.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Libplanet.Blocks +{ + public static class HashAlgorithmTable + { + /// + /// Creates a delegate from a . + /// + /// A table with block index offsets and their corresponding + /// . For example, 0: SHA1, 10: SHA256, 100: SHA512 + /// means i => i >= 100 ? HashAlgorithmType.Of<SHA512>() : i >= 10 ? + /// HashAlgorithmType.Of<SHA256>() : HashAlgorithmType.Of<SHA1>(). + /// (Note that 0 means otherwise.) It must contain at least one entry with + /// index 0, because it is the last fallback. + /// A corresponding . + /// Thrown when has no + /// the last fallback entry with index 0, or there are entries with duplicate indices. + /// + public static HashAlgorithmGetter ToHashAlgorithmGetter( + this IEnumerable> table + ) + { + KeyValuePair[] indices = + table.OrderByDescending(kv => kv.Key).ToArray(); + + if (!indices.Any() || indices[indices.Length - 1].Key > 0) + { + throw new ArgumentException( + $"The {nameof(table)} must contain at least one entry with index 0.", + nameof(table) + ); + } + else if (indices.Select(kv => kv.Key).ToImmutableHashSet().Count < indices.Length) + { + throw new ArgumentException( + $"Entries with duplicate indices are disallowed.", + nameof(table) + ); + } + + return index => + { + foreach (KeyValuePair pair in indices) + { + if (index >= pair.Key) + { + return pair.Value; + } + } + + return indices[0].Value; + }; + } + } +}