diff --git a/CHANGES.md b/CHANGES.md index aa01e26f0cc..ec68f3504dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,9 +29,10 @@ Version DPoS and its implementations. [[#3730]] - (Libplanet.Action) Added `MaxGasPrice` property to `IActionContext` interface and its implementations. [[#3762]] - - (Libplanet.Explorer) Added `ValidatorPower` field to `VoteType`. [[#3737]] + - (Libplanet.Explorer) Added `ValidatorPower` field to `VoteType`. + [[#3737], [#3813]] - (Libplanet.Types) Added `ValidatorPower` property to `IVoteMetadata` - interface and its implementations. [[#3737]] + interface and its implementations. [[#3737], [#3813]] ### Backward-incompatible network protocol changes @@ -55,6 +56,7 @@ Version DPoS [#3748]: https://github.com/planetarium/libplanet/pull/3748 [#3762]: https://github.com/planetarium/libplanet/pull/3762 [#3764]: https://github.com/planetarium/libplanet/pull/3764 +[#3813]: https://github.com/planetarium/libplanet/pull/3813 Version Sloth diff --git a/Libplanet.Explorer/GraphTypes/VoteType.cs b/Libplanet.Explorer/GraphTypes/VoteType.cs index cc0fede8e59..2171c4717c6 100644 --- a/Libplanet.Explorer/GraphTypes/VoteType.cs +++ b/Libplanet.Explorer/GraphTypes/VoteType.cs @@ -30,7 +30,7 @@ public VoteType() "ValidatorPublicKey", description: "Public key of the validator which is subject of the vote.", resolve: ctx => ctx.Source.ValidatorPublicKey); - Field>( + Field( "ValidatorPower", description: "Power of the validator which is subject of the vote.", resolve: ctx => ctx.Source.ValidatorPower); diff --git a/Libplanet.Net/Consensus/HeightVoteSet.cs b/Libplanet.Net/Consensus/HeightVoteSet.cs index e67f8b4d235..a6eef27c7b5 100644 --- a/Libplanet.Net/Consensus/HeightVoteSet.cs +++ b/Libplanet.Net/Consensus/HeightVoteSet.cs @@ -132,10 +132,11 @@ public void AddVote(Vote vote) vote); } - if (_validatorSet.GetValidator(validatorKey).Power != vote.ValidatorPower) + if (vote.ValidatorPower is { } power && + _validatorSet.GetValidator(validatorKey).Power != power) { - const string msg = "ValidatorPower of the vote is not the same " + - "with the one in the validator set"; + const string msg = "ValidatorPower of the vote is given and the value is " + + "not the same with the one in the validator set"; throw new InvalidVoteException(msg, vote); } diff --git a/Libplanet.Tests/Blocks/BlockCommitTest.cs b/Libplanet.Tests/Blocks/BlockCommitTest.cs index 4f94e460504..474f0c6bcdc 100644 --- a/Libplanet.Tests/Blocks/BlockCommitTest.cs +++ b/Libplanet.Tests/Blocks/BlockCommitTest.cs @@ -28,14 +28,14 @@ public void ToHash() { var randomHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)); var keys = Enumerable.Range(0, 4).Select(_ => new PrivateKey()).ToList(); - var votes = keys.Select(key => + var votes = keys.Select((key, index) => new VoteMetadata( 1, 0, randomHash, DateTimeOffset.UtcNow, key.PublicKey, - BigInteger.One, + index == 0 ? (BigInteger?)null : BigInteger.One, VoteFlag.PreCommit).Sign(key)) .ToImmutableArray(); var blockCommit = new BlockCommit(1, 0, randomHash, votes); diff --git a/Libplanet.Tests/Consensus/VoteMetadataTest.cs b/Libplanet.Tests/Consensus/VoteMetadataTest.cs index af25df1bbe8..29335fb2c51 100644 --- a/Libplanet.Tests/Consensus/VoteMetadataTest.cs +++ b/Libplanet.Tests/Consensus/VoteMetadataTest.cs @@ -68,6 +68,17 @@ public void Bencoded() VoteFlag.PreCommit); var decoded = new VoteMetadata(expected.Bencoded); Assert.Equal(expected, decoded); + + expected = new VoteMetadata( + 1, + 2, + hash, + DateTimeOffset.UtcNow, + key.PublicKey, + null, + VoteFlag.PreCommit); + decoded = new VoteMetadata(expected.Bencoded); + Assert.Equal(expected, decoded); } } } diff --git a/Libplanet.Tests/Consensus/VoteTest.cs b/Libplanet.Tests/Consensus/VoteTest.cs index 092b3c2663d..a56136cbd2f 100644 --- a/Libplanet.Tests/Consensus/VoteTest.cs +++ b/Libplanet.Tests/Consensus/VoteTest.cs @@ -28,6 +28,20 @@ public void Sign() Vote vote = voteMetadata.Sign(privateKey); Assert.True( privateKey.PublicKey.Verify(_codec.Encode(voteMetadata.Bencoded), vote.Signature)); + + var nullPowerVoteMetadata = new VoteMetadata( + 1, + 2, + hash, + DateTimeOffset.UtcNow, + privateKey.PublicKey, + null, + VoteFlag.PreCommit); + Vote nullPowerVote = nullPowerVoteMetadata.Sign(privateKey); + Assert.True( + privateKey.PublicKey.Verify( + _codec.Encode(nullPowerVoteMetadata.Bencoded), + nullPowerVote.Signature)); } [Fact] diff --git a/Libplanet.Types/Consensus/IVoteMetadata.cs b/Libplanet.Types/Consensus/IVoteMetadata.cs index 6e9b4dfb895..d6d4f45cb62 100644 --- a/Libplanet.Types/Consensus/IVoteMetadata.cs +++ b/Libplanet.Types/Consensus/IVoteMetadata.cs @@ -39,7 +39,7 @@ public interface IVoteMetadata /// /// The voting power of the validator that voted. /// - BigInteger ValidatorPower { get; } + BigInteger? ValidatorPower { get; } /// /// The indicating the type of a . diff --git a/Libplanet.Types/Consensus/Vote.cs b/Libplanet.Types/Consensus/Vote.cs index 0b2b8deb139..ee8deebe89b 100644 --- a/Libplanet.Types/Consensus/Vote.cs +++ b/Libplanet.Types/Consensus/Vote.cs @@ -103,7 +103,7 @@ private Vote(Bencodex.Types.Dictionary encoded) public PublicKey ValidatorPublicKey => _metadata.ValidatorPublicKey; /// - public BigInteger ValidatorPower => _metadata.ValidatorPower; + public BigInteger? ValidatorPower => _metadata.ValidatorPower; /// public VoteFlag Flag => _metadata.Flag; @@ -166,6 +166,7 @@ public override string ToString() var dict = new Dictionary { { "validator_public_key", ValidatorPublicKey.ToString() }, + { "validator_power", ValidatorPower.ToString() }, { "vote_flag", Flag.ToString() }, { "block_hash", BlockHash.ToString() }, { "height", Height }, diff --git a/Libplanet.Types/Consensus/VoteMetadata.cs b/Libplanet.Types/Consensus/VoteMetadata.cs index 6db9b6343c4..3e8f95c62d1 100644 --- a/Libplanet.Types/Consensus/VoteMetadata.cs +++ b/Libplanet.Types/Consensus/VoteMetadata.cs @@ -69,7 +69,7 @@ public VoteMetadata( BlockHash blockHash, DateTimeOffset timestamp, PublicKey validatorPublicKey, - BigInteger validatorPower, + BigInteger? validatorPower, VoteFlag flag) { if (height < 0) @@ -82,7 +82,7 @@ public VoteMetadata( throw new ArgumentException( $"Given {nameof(round)} cannot be negative: {round}"); } - else if (validatorPower <= 0) + else if (validatorPower is { } power && power <= 0) { var msg = $"Given {nameof(validatorPower)} cannot be negative " + $"or equal to zero: {validatorPower}"; @@ -127,7 +127,9 @@ private VoteMetadata(Bencodex.Types.Dictionary bencoded) CultureInfo.InvariantCulture), validatorPublicKey: new PublicKey( ((Binary)bencoded[ValidatorPublicKeyKey]).ByteArray), - validatorPower: (Integer)bencoded[ValidatorPowerKey], + validatorPower: bencoded.ContainsKey(ValidatorPowerKey) + ? (Integer)bencoded[ValidatorPowerKey] + : (Integer?)null, flag: (VoteFlag)(int)(Integer)bencoded[FlagKey]) { } @@ -149,7 +151,7 @@ private VoteMetadata(Bencodex.Types.Dictionary bencoded) public PublicKey ValidatorPublicKey { get; } /// - public BigInteger ValidatorPower { get; } + public BigInteger? ValidatorPower { get; } /// public VoteFlag Flag { get; } @@ -167,7 +169,6 @@ public Bencodex.Types.IValue Bencoded TimestampKey, Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture)) .Add(ValidatorPublicKeyKey, ValidatorPublicKey.Format(compress: true)) - .Add(ValidatorPowerKey, ValidatorPower) .Add(FlagKey, (long)Flag); if (BlockHash is { } blockHash) @@ -175,6 +176,11 @@ public Bencodex.Types.IValue Bencoded encoded = encoded.Add(BlockHashKey, blockHash.ByteArray); } + if (ValidatorPower is { } power) + { + encoded = encoded.Add(ValidatorPowerKey, power); + } + return encoded; } }