Skip to content

Commit ecc7e5f

Browse files
committed
feat: add vote power verification
1 parent 99ad048 commit ecc7e5f

File tree

5 files changed

+48
-5
lines changed

5 files changed

+48
-5
lines changed

Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ public void CannotAddUnknownValidator()
6464
Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));
6565
}
6666

67+
[Fact]
68+
public void CannotAddValidatorWithInvalidPower()
69+
{
70+
var preVote = new VoteMetadata(
71+
2,
72+
0,
73+
default,
74+
DateTimeOffset.UtcNow,
75+
TestUtils.ValidatorSet[0].PublicKey,
76+
TestUtils.ValidatorSet[0].Power + 1,
77+
VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);
78+
79+
Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));
80+
}
81+
6782
[Fact]
6883
public void CannotAddMultipleVotesPerRoundPerValidator()
6984
{

Libplanet.Net/Consensus/HeightVoteSet.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ public void AddVote(Vote vote)
132132
vote);
133133
}
134134

135+
if (_validatorSet.GetValidator(validatorKey).Power != vote.ValidatorPower)
136+
{
137+
const string msg = "ValidatorPower of the vote is not the same " +
138+
"with the one in the validator set";
139+
throw new InvalidVoteException(msg, vote);
140+
}
141+
135142
if (!vote.Flag.Equals(VoteFlag.PreVote) &&
136143
!vote.Flag.Equals(VoteFlag.PreCommit))
137144
{

Libplanet.Tests/Consensus/ValidatorSetTest.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,30 @@ public void ValidateBlockCommitValidators()
152152
BigInteger.One,
153153
VoteFlag.PreCommit).Sign(key))
154154
.ToImmutableArray();
155+
var invalidPowerVotes = orderedPrivateKeys
156+
.Select(
157+
key => new VoteMetadata(
158+
height,
159+
round,
160+
hash,
161+
DateTimeOffset.UtcNow,
162+
key.PublicKey,
163+
2,
164+
VoteFlag.PreCommit).Sign(key))
165+
.ToImmutableArray();
155166

156167
var blockCommitWithUnorderedVotes =
157168
new BlockCommit(height, round, hash, unorderedVotes);
169+
var blockCommitWithInvalidPowerVotes =
170+
new BlockCommit(height, round, hash, unorderedVotes);
158171
var blockCommitWithInsufficientVotes =
159172
new BlockCommit(height, round, hash, orderedVotes.Take(5).ToImmutableArray());
160173
var validBlockCommit = new BlockCommit(height, round, hash, orderedVotes);
161174

162175
Assert.False(
163176
validatorSet.ValidateBlockCommitValidators(blockCommitWithUnorderedVotes));
177+
Assert.False(
178+
validatorSet.ValidateBlockCommitValidators(blockCommitWithInvalidPowerVotes));
164179
Assert.False(
165180
validatorSet.ValidateBlockCommitValidators(blockCommitWithInsufficientVotes));
166181
Assert.True(validatorSet.ValidateBlockCommitValidators(validBlockCommit));

Libplanet.Types/Blocks/BlockCommit.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,14 @@ public BlockCommit(
9393
vote.Height != height ||
9494
vote.Round != round ||
9595
!blockHash.Equals(vote.BlockHash) ||
96-
(vote.Flag != VoteFlag.Null && vote.Flag != VoteFlag.PreCommit)))
96+
(vote.Flag != VoteFlag.Null && vote.Flag != VoteFlag.PreCommit) ||
97+
(vote.Flag == VoteFlag.PreCommit && !vote.Verify())))
9798
{
9899
throw new ArgumentException(
99100
$"Every vote must have the same height as {height}, the same round " +
100101
$"as {round}, the same hash as {blockHash}, and must have flag value of " +
101-
$"either {VoteFlag.Null} or {VoteFlag.PreCommit}.",
102+
$"either {VoteFlag.Null} or {VoteFlag.PreCommit}, " +
103+
$"and must be signed if the vote's flag is {VoteFlag.PreCommit}.",
102104
nameof(votes));
103105
}
104106

Libplanet.Types/Consensus/ValidatorSet.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,15 +249,19 @@ public Validator GetProposer(long height, int round)
249249

250250
/// <summary>
251251
/// Checks whether <see cref="BlockCommit.Votes"/> is ordered
252-
/// by <see cref="Address"/> of each <see cref="Vote.ValidatorPublicKey"/>.
252+
/// by <see cref="Address"/> of each <see cref="Vote.ValidatorPublicKey"/>,
253+
/// and <see cref="Vote.ValidatorPower"/> equals to the one recorded in the chain states.
253254
/// </summary>
254255
/// <param name="blockCommit">The <see cref="BlockCommit"/> to check.</param>
255256
/// <returns><see langword="true"/> if the <see cref="BlockCommit.Votes"/> is
256257
/// ordered, <see langword="false"/> otherwise.</returns>
257258
public bool ValidateBlockCommitValidators(BlockCommit blockCommit)
258259
{
259-
return Validators.Select(validator => validator.PublicKey).SequenceEqual(
260-
blockCommit.Votes.Select(vote => vote.ValidatorPublicKey).ToList());
260+
return Validators.Select(validator => validator.PublicKey)
261+
.SequenceEqual(
262+
blockCommit.Votes.Select(vote => vote.ValidatorPublicKey).ToList()) &&
263+
blockCommit.Votes.All(
264+
v => v.ValidatorPower == GetValidator(v.ValidatorPublicKey).Power);
261265
}
262266
}
263267
}

0 commit comments

Comments
 (0)