mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-07 04:20:44 +00:00
base synchrony on amount of voting power observed on the network from proposals
This commit is contained in:
@@ -4,7 +4,9 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
|
||||
@@ -43,6 +45,21 @@ func (lb LightBlock) ValidateBasic(chainID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lb LightBlock) CalculateSynchronyVotingPower(t types.TimingParams) time.Duration {
|
||||
// Synchrony calculated as a function of the amount of voting power that has been seen since
|
||||
// since the beginning of the height exclusive of the round in which the proposal succeeded.
|
||||
votingPowerSeen := lb.ValidatorSet.VotingPowerBeforeRound(lb.SignedHeader.Commit.Round)
|
||||
nonFaultyThreshold := lb.ValidatorSet.TotalVotingPower()*1/3 + 1
|
||||
|
||||
thresholdsObserved := (votingPowerSeen / nonFaultyThreshold)
|
||||
return t.Precision + t.MessageDelay + t.MessageDelay*time.Duration(thresholdsObserved)
|
||||
}
|
||||
|
||||
func (lb LightBlock) CalculateSynchronyRounds(t types.TimingParams) time.Duration {
|
||||
// hard coded value of '10' used in this example
|
||||
return t.Precision + t.MessageDelay + t.MessageDelay*time.Duration(lb.Commit.Round/10)
|
||||
}
|
||||
|
||||
// String returns a string representation of the LightBlock
|
||||
func (lb LightBlock) String() string {
|
||||
return lb.StringIndented("")
|
||||
|
||||
@@ -6,8 +6,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
@@ -163,3 +165,45 @@ func TestSignedHeaderValidateBasic(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateSynchronyVotingPower(t *testing.T) {
|
||||
vals, _ := randValidatorPrivValSet(5, 10)
|
||||
sh := &SignedHeader{
|
||||
Commit: &Commit{
|
||||
Round: 4,
|
||||
},
|
||||
}
|
||||
lb := LightBlock{
|
||||
ValidatorSet: vals,
|
||||
SignedHeader: sh,
|
||||
}
|
||||
|
||||
tp := types.TimingParams{
|
||||
MessageDelay: 100 * time.Millisecond,
|
||||
Precision: 10 * time.Millisecond,
|
||||
}
|
||||
|
||||
s := lb.CalculateSynchronyVotingPower(tp)
|
||||
require.Equal(t, s, tp.Precision+tp.MessageDelay+tp.MessageDelay*2)
|
||||
}
|
||||
|
||||
func TestCalculateSynchronyRound(t *testing.T) {
|
||||
vals, _ := randValidatorPrivValSet(5, 10)
|
||||
sh := &SignedHeader{
|
||||
Commit: &Commit{
|
||||
Round: 11,
|
||||
},
|
||||
}
|
||||
lb := LightBlock{
|
||||
ValidatorSet: vals,
|
||||
SignedHeader: sh,
|
||||
}
|
||||
|
||||
tp := types.TimingParams{
|
||||
MessageDelay: 100 * time.Millisecond,
|
||||
Precision: 10 * time.Millisecond,
|
||||
}
|
||||
|
||||
s := lb.CalculateSynchronyRounds(tp)
|
||||
require.Equal(t, s, tp.Precision+tp.MessageDelay+tp.MessageDelay*1)
|
||||
}
|
||||
|
||||
@@ -88,10 +88,11 @@ func (p *Proposal) ValidateBasic() error {
|
||||
//
|
||||
// For more information on the meaning of 'timely', see the proposer-based timestamp specification:
|
||||
// https://github.com/tendermint/spec/tree/master/spec/consensus/proposer-based-timestamp
|
||||
func (p *Proposal) IsTimely(clock tmtime.Source, tp TimingParams) bool {
|
||||
func (p *Proposal) IsTimely(clock tmtime.Source, tp TimingParams, vs *ValidatorSet) bool {
|
||||
thirdsSeen := vs.VotingPowerBeforeRound(p.Round) / (vs.TotalVotingPower()*1/3 + 1)
|
||||
lt := clock.Now()
|
||||
lhs := lt.Add(-tp.Precision)
|
||||
rhs := lt.Add(tp.Precision).Add(tp.MessageDelay)
|
||||
rhs := lt.Add(tp.Precision)
|
||||
lhs := lt.Add(-tp.Precision).Add(-tp.MessageDelay - tp.MessageDelay*time.Duration(thirdsSeen))
|
||||
if lhs.Before(p.Timestamp) && rhs.After(p.Timestamp) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ func TestIsTimely(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
proposalTime time.Time
|
||||
round int32
|
||||
localTime time.Time
|
||||
precision time.Duration
|
||||
msgDelay time.Duration
|
||||
@@ -235,11 +236,30 @@ func TestIsTimely(t *testing.T) {
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: false,
|
||||
},
|
||||
{
|
||||
name: "long proposal in later round",
|
||||
proposalTime: genesisTime,
|
||||
round: 2, // should see 1/3 +1 of the network power
|
||||
localTime: genesisTime.Add(3 * time.Nanosecond),
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: true,
|
||||
},
|
||||
{
|
||||
name: "long proposal in earlier round",
|
||||
proposalTime: genesisTime,
|
||||
round: 1, // should see 1/3 +1 of the network power
|
||||
localTime: genesisTime.Add(3 * time.Nanosecond),
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: false,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
p := Proposal{
|
||||
Timestamp: testCase.proposalTime,
|
||||
Round: testCase.round,
|
||||
}
|
||||
|
||||
tp := TimingParams{
|
||||
@@ -250,7 +270,8 @@ func TestIsTimely(t *testing.T) {
|
||||
mockSource := new(tmtimemocks.Source)
|
||||
mockSource.On("Now").Return(testCase.localTime)
|
||||
|
||||
ti := p.IsTimely(mockSource, tp)
|
||||
vals, _ := randValidatorPrivValSet(5, 15)
|
||||
ti := p.IsTimely(mockSource, tp, vals)
|
||||
assert.Equal(t, testCase.expectTimely, ti)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -342,6 +342,17 @@ func (vals *ValidatorSet) findProposer() *Validator {
|
||||
return proposer
|
||||
}
|
||||
|
||||
// VotingPowerSeenBeforeRound calculates the amount of voting power seen on the network
|
||||
// from proposals before round r.
|
||||
func (vals *ValidatorSet) VotingPowerBeforeRound(r int32) int64 {
|
||||
var votingPowerSeen int64
|
||||
for i := int32(0); i < r; i++ {
|
||||
vals.IncrementProposerPriority(1)
|
||||
votingPowerSeen += vals.GetProposer().VotingPower
|
||||
}
|
||||
return votingPowerSeen
|
||||
}
|
||||
|
||||
// Hash returns the Merkle root hash build using validators (as leaves) in the
|
||||
// set.
|
||||
func (vals *ValidatorSet) Hash() []byte {
|
||||
|
||||
Reference in New Issue
Block a user