From d7c3a8f682d2acdcdce859d86e732d33db1c9d1e Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 24 Aug 2021 11:43:13 -0400 Subject: [PATCH] time: make median time library type private (#6853) This is a very minor change, but I was looking through the code, and this seems like it shouldn't be exported or used more broadly, so I've moved it out. --- libs/time/time.go | 41 --------------------------- state/state.go | 7 ++--- state/time.go | 46 +++++++++++++++++++++++++++++++ {libs/time => state}/time_test.go | 39 +++++++++++++------------- 4 files changed, 69 insertions(+), 64 deletions(-) create mode 100644 state/time.go rename {libs/time => state}/time_test.go (50%) diff --git a/libs/time/time.go b/libs/time/time.go index 022bdf574..786f9bbb4 100644 --- a/libs/time/time.go +++ b/libs/time/time.go @@ -1,7 +1,6 @@ package time import ( - "sort" "time" ) @@ -16,43 +15,3 @@ func Now() time.Time { func Canonical(t time.Time) time.Time { return t.Round(0).UTC() } - -// WeightedTime for computing a median. -type WeightedTime struct { - Time time.Time - Weight int64 -} - -// NewWeightedTime with time and weight. -func NewWeightedTime(time time.Time, weight int64) *WeightedTime { - return &WeightedTime{ - Time: time, - Weight: weight, - } -} - -// WeightedMedian computes weighted median time for a given array of WeightedTime and the total voting power. -func WeightedMedian(weightedTimes []*WeightedTime, totalVotingPower int64) (res time.Time) { - median := totalVotingPower / 2 - - sort.Slice(weightedTimes, func(i, j int) bool { - if weightedTimes[i] == nil { - return false - } - if weightedTimes[j] == nil { - return true - } - return weightedTimes[i].Time.UnixNano() < weightedTimes[j].Time.UnixNano() - }) - - for _, weightedTime := range weightedTimes { - if weightedTime != nil { - if median <= weightedTime.Weight { - res = weightedTime.Time - break - } - median -= weightedTime.Weight - } - } - return -} diff --git a/state/state.go b/state/state.go index 132a86fda..5862162d1 100644 --- a/state/state.go +++ b/state/state.go @@ -9,7 +9,6 @@ import ( "github.com/gogo/protobuf/proto" - tmtime "github.com/tendermint/tendermint/libs/time" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" "github.com/tendermint/tendermint/types" @@ -287,7 +286,7 @@ func (state State) MakeBlock( // the votes sent by honest processes, i.e., a faulty processes can not arbitrarily increase or decrease the // computed value. func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time { - weightedTimes := make([]*tmtime.WeightedTime, len(commit.Signatures)) + weightedTimes := make([]*weightedTime, len(commit.Signatures)) totalVotingPower := int64(0) for i, commitSig := range commit.Signatures { @@ -298,11 +297,11 @@ func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time // If there's no condition, TestValidateBlockCommit panics; not needed normally. if validator != nil { totalVotingPower += validator.VotingPower - weightedTimes[i] = tmtime.NewWeightedTime(commitSig.Timestamp, validator.VotingPower) + weightedTimes[i] = newWeightedTime(commitSig.Timestamp, validator.VotingPower) } } - return tmtime.WeightedMedian(weightedTimes, totalVotingPower) + return weightedMedian(weightedTimes, totalVotingPower) } //------------------------------------------------------------------------ diff --git a/state/time.go b/state/time.go new file mode 100644 index 000000000..c0770b3af --- /dev/null +++ b/state/time.go @@ -0,0 +1,46 @@ +package state + +import ( + "sort" + "time" +) + +// weightedTime for computing a median. +type weightedTime struct { + Time time.Time + Weight int64 +} + +// newWeightedTime with time and weight. +func newWeightedTime(time time.Time, weight int64) *weightedTime { + return &weightedTime{ + Time: time, + Weight: weight, + } +} + +// weightedMedian computes weighted median time for a given array of WeightedTime and the total voting power. +func weightedMedian(weightedTimes []*weightedTime, totalVotingPower int64) (res time.Time) { + median := totalVotingPower / 2 + + sort.Slice(weightedTimes, func(i, j int) bool { + if weightedTimes[i] == nil { + return false + } + if weightedTimes[j] == nil { + return true + } + return weightedTimes[i].Time.UnixNano() < weightedTimes[j].Time.UnixNano() + }) + + for _, weightedTime := range weightedTimes { + if weightedTime != nil { + if median <= weightedTime.Weight { + res = weightedTime.Time + break + } + median -= weightedTime.Weight + } + } + return +} diff --git a/libs/time/time_test.go b/state/time_test.go similarity index 50% rename from libs/time/time_test.go rename to state/time_test.go index 1b1a30e50..893ade7ea 100644 --- a/libs/time/time_test.go +++ b/state/time_test.go @@ -1,54 +1,55 @@ -package time +package state import ( "testing" "time" "github.com/stretchr/testify/assert" + tmtime "github.com/tendermint/tendermint/libs/time" ) func TestWeightedMedian(t *testing.T) { - m := make([]*WeightedTime, 3) + m := make([]*weightedTime, 3) - t1 := Now() + t1 := tmtime.Now() t2 := t1.Add(5 * time.Second) t3 := t1.Add(10 * time.Second) - m[2] = NewWeightedTime(t1, 33) // faulty processes - m[0] = NewWeightedTime(t2, 40) // correct processes - m[1] = NewWeightedTime(t3, 27) // correct processes + m[2] = newWeightedTime(t1, 33) // faulty processes + m[0] = newWeightedTime(t2, 40) // correct processes + m[1] = newWeightedTime(t3, 27) // correct processes totalVotingPower := int64(100) - median := WeightedMedian(m, totalVotingPower) + median := weightedMedian(m, totalVotingPower) assert.Equal(t, t2, median) // median always returns value between values of correct processes assert.Equal(t, true, (median.After(t1) || median.Equal(t1)) && (median.Before(t3) || median.Equal(t3))) - m[1] = NewWeightedTime(t1, 40) // correct processes - m[2] = NewWeightedTime(t2, 27) // correct processes - m[0] = NewWeightedTime(t3, 33) // faulty processes + m[1] = newWeightedTime(t1, 40) // correct processes + m[2] = newWeightedTime(t2, 27) // correct processes + m[0] = newWeightedTime(t3, 33) // faulty processes totalVotingPower = int64(100) - median = WeightedMedian(m, totalVotingPower) + median = weightedMedian(m, totalVotingPower) assert.Equal(t, t2, median) // median always returns value between values of correct processes assert.Equal(t, true, (median.After(t1) || median.Equal(t1)) && (median.Before(t2) || median.Equal(t2))) - m = make([]*WeightedTime, 8) + m = make([]*weightedTime, 8) t4 := t1.Add(15 * time.Second) t5 := t1.Add(60 * time.Second) - m[3] = NewWeightedTime(t1, 10) // correct processes - m[1] = NewWeightedTime(t2, 10) // correct processes - m[5] = NewWeightedTime(t2, 10) // correct processes - m[4] = NewWeightedTime(t3, 23) // faulty processes - m[0] = NewWeightedTime(t4, 20) // correct processes - m[7] = NewWeightedTime(t5, 10) // faulty processes + m[3] = newWeightedTime(t1, 10) // correct processes + m[1] = newWeightedTime(t2, 10) // correct processes + m[5] = newWeightedTime(t2, 10) // correct processes + m[4] = newWeightedTime(t3, 23) // faulty processes + m[0] = newWeightedTime(t4, 20) // correct processes + m[7] = newWeightedTime(t5, 10) // faulty processes totalVotingPower = int64(83) - median = WeightedMedian(m, totalVotingPower) + median = weightedMedian(m, totalVotingPower) assert.Equal(t, t3, median) // median always returns value between values of correct processes assert.Equal(t, true, (median.After(t1) || median.Equal(t1)) &&