diff --git a/CHANGES.md b/CHANGES.md index ec4fd2caaeb..ff6e43773ea 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ To be released. ### Backward-incompatible API changes + - Added `IBencodable` interface to `HashDigest`. [[#3455]] + ### Backward-incompatible network protocol changes ### Backward-incompatible storage format changes @@ -27,6 +29,7 @@ To be released. ### CLI tools [#3454]: https://github.com/planetarium/libplanet/pull/3454 +[#3455]: https://github.com/planetarium/libplanet/pull/3455 Version 3.6.0 diff --git a/Libplanet.Common/HashDigest.cs b/Libplanet.Common/HashDigest.cs index e22122b5ca6..ca0b2143a0e 100644 --- a/Libplanet.Common/HashDigest.cs +++ b/Libplanet.Common/HashDigest.cs @@ -15,6 +15,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; +using Bencodex; +using Bencodex.Types; using Libplanet.Common.Serialization; namespace Libplanet.Common @@ -36,7 +38,7 @@ namespace Libplanet.Common [TypeConverter(typeof(HashDigestTypeConverter))] [JsonConverter(typeof(HashDigestJsonConverter))] [Serializable] - public readonly struct HashDigest : ISerializable, IEquatable> + public readonly struct HashDigest : ISerializable, IEquatable>, IBencodable where T : HashAlgorithm { /// @@ -114,6 +116,21 @@ public HashDigest(in ImmutableArray hashDigest) _byteArray = hashDigest; } + public HashDigest(IValue bencoded) + : this(bencoded is Binary binary + ? binary + : throw new ArgumentException( + $"Given {nameof(bencoded)} must be of type " + + $"{typeof(Binary)}: {bencoded.GetType()}", + nameof(bencoded))) + { + } + + private HashDigest(Binary binary) + : this(binary.ByteArray) + { + } + private HashDigest( SerializationInfo info, StreamingContext context) @@ -130,6 +147,9 @@ private HashDigest( public ImmutableArray ByteArray => _byteArray.IsDefault ? DefaultByteArray : _byteArray; + /// + public IValue Bencoded => new Binary(ByteArray); + /// /// Converts a given hexadecimal representation of a digest into /// a object. diff --git a/Libplanet.Common/Libplanet.Common.csproj b/Libplanet.Common/Libplanet.Common.csproj index a297d48461b..601c9994491 100644 --- a/Libplanet.Common/Libplanet.Common.csproj +++ b/Libplanet.Common/Libplanet.Common.csproj @@ -1,5 +1,5 @@ - + Libplanet.Common Libplanet.Common @@ -18,7 +18,7 @@ false ..\Libplanet.ruleset - + @@ -34,6 +34,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + all @@ -42,5 +43,5 @@ - + diff --git a/Libplanet.Tests/HashDigestTest.cs b/Libplanet.Tests/HashDigestTest.cs index bf37bff984b..b822530764b 100644 --- a/Libplanet.Tests/HashDigestTest.cs +++ b/Libplanet.Tests/HashDigestTest.cs @@ -26,11 +26,20 @@ public void DefaultConstructor() public void DisallowNull() { Assert.Throws( - () => new HashDigest(null) - ); + () => new HashDigest((byte[])null)); Assert.Throws( - () => new HashDigest(null) - ); + () => new HashDigest((byte[])null)); + } + + [Fact] + public void Bencoded() + { + Assert.NotEqual(HashDigest.Size, HashDigest.Size); + var digest = new HashDigest(TestUtils.GetRandomBytes(HashDigest.Size)); + var bencoded = digest.Bencoded; + var decoded = new HashDigest(bencoded); + Assert.Equal(digest, decoded); + Assert.Throws(() => new HashDigest(bencoded)); } [Fact] diff --git a/Libplanet.Types/Blocks/BlockMarshaler.cs b/Libplanet.Types/Blocks/BlockMarshaler.cs index f731804df38..b6c5595b72e 100644 --- a/Libplanet.Types/Blocks/BlockMarshaler.cs +++ b/Libplanet.Types/Blocks/BlockMarshaler.cs @@ -88,7 +88,7 @@ public static Dictionary MarshalBlockMetadata(IBlockMetadata metadata) if (metadata.TxHash is { } th) { - dict = dict.Add(TxHashKey, th.ByteArray); + dict = dict.Add(TxHashKey, th.Bencoded); } dict = metadata.PublicKey is { } pubKey @@ -109,13 +109,7 @@ HashDigest preEvaluationHash ) { Dictionary dict = marshaledMetadata; - ImmutableArray preEvaluationHashBytes = preEvaluationHash.ByteArray; - - if (!preEvaluationHashBytes.IsDefaultOrEmpty) - { - dict = dict.Add(PreEvaluationHashKey, preEvaluationHashBytes); - } - + dict = dict.Add(PreEvaluationHashKey, preEvaluationHash.Bencoded); return dict; } @@ -135,8 +129,8 @@ BlockHash hash ) { Dictionary dict = marshaledPreEvaluatedBlockHeader - .Add(StateRootHashKey, stateRootHash.ByteArray) - .Add(HashKey, hash.ByteArray); + .Add(StateRootHashKey, stateRootHash.Bencoded) + .Add(HashKey, hash.Bencoded); if (signature is { } sig) { dict = dict.Add(SignatureKey, sig); @@ -207,11 +201,11 @@ public static BlockMetadata UnmarshalBlockMetadata(Dictionary marshaled) CultureInfo.InvariantCulture), miner: miner, publicKey: publicKey, - previousHash: marshaled.ContainsKey(PreviousHashKey) - ? new BlockHash(marshaled[PreviousHashKey]) + previousHash: marshaled.TryGetValue(PreviousHashKey, out IValue phv) + ? new BlockHash(phv) : (BlockHash?)null, - txHash: marshaled.ContainsKey(TxHashKey) - ? new HashDigest(((Binary)marshaled[TxHashKey]).ByteArray) + txHash: marshaled.TryGetValue(TxHashKey, out IValue thv) + ? new HashDigest(thv) : (HashDigest?)null, lastCommit: marshaled.ContainsKey(LastCommitKey) ? new BlockCommit(marshaled[LastCommitKey]) @@ -220,7 +214,7 @@ public static BlockMetadata UnmarshalBlockMetadata(Dictionary marshaled) } public static HashDigest UnmarshalPreEvaluationHash(Dictionary marshaled) => - new HashDigest(((Binary)marshaled[PreEvaluationHashKey]).ByteArray); + new HashDigest(marshaled[PreEvaluationHashKey]); public static PreEvaluationBlockHeader UnmarshalPreEvaluationBlockHeader( Dictionary marshaled) @@ -242,8 +236,7 @@ public static BlockHash UnmarshalBlockHeaderHash(Dictionary marshaledBlockHeader public static HashDigest UnmarshalBlockHeaderStateRootHash( Dictionary marshaledBlockHeader ) => - new HashDigest( - ((Binary)marshaledBlockHeader[StateRootHashKey]).ByteArray); + new HashDigest(marshaledBlockHeader[StateRootHashKey]); public static ImmutableArray? UnmarshalBlockHeaderSignature( Dictionary marshaledBlockHeader diff --git a/Libplanet.Types/Tx/TxExecution.cs b/Libplanet.Types/Tx/TxExecution.cs index 5d98cc0b35b..7b9f7cbcccc 100644 --- a/Libplanet.Types/Tx/TxExecution.cs +++ b/Libplanet.Types/Tx/TxExecution.cs @@ -197,12 +197,12 @@ public IValue ToBencodex() if (InputState is { } inputState) { - dict = dict.Add(InputStateKey, inputState.ByteArray); + dict = dict.Add(InputStateKey, inputState.Bencoded); } if (OutputState is { } outputState) { - dict = dict.Add(OutputStateKey, outputState.ByteArray); + dict = dict.Add(OutputStateKey, outputState.Bencoded); } if (ExceptionNames is { } exceptionNames)