diff --git a/consensus/quorum/one-node-one-vote.go b/consensus/quorum/one-node-one-vote.go index 524312f7a..494a015d7 100644 --- a/consensus/quorum/one-node-one-vote.go +++ b/consensus/quorum/one-node-one-vote.go @@ -4,6 +4,8 @@ import ( "encoding/json" "math/big" + "github.com/pkg/errors" + bls_core "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/crypto/bls" @@ -20,6 +22,9 @@ type uniformVoteWeight struct { DependencyInjectionWriter DependencyInjectionReader SignatureReader + + lastPowerSignersCountCache map[Phase]int64 + lastParticipantsCount int64 } // Policy .. @@ -123,9 +128,29 @@ func (v *uniformVoteWeight) AmIMemberOfCommitee() bool { } func (v *uniformVoteWeight) ResetPrepareAndCommitVotes() { + v.lastPowerSignersCountCache[Prepare] = v.SignersCount(Prepare) + v.lastPowerSignersCountCache[Commit] = v.SignersCount(Commit) + v.lastParticipantsCount = v.ParticipantsCount() + v.reset([]Phase{Prepare, Commit}) } func (v *uniformVoteWeight) ResetViewChangeVotes() { + v.lastPowerSignersCountCache[ViewChange] = v.SignersCount(ViewChange) + v.lastParticipantsCount = v.ParticipantsCount() + v.reset([]Phase{ViewChange}) } + +func (v *uniformVoteWeight) CurrentTotalPower(p Phase) (*numeric.Dec, error) { + if v.lastParticipantsCount == 0 { + return nil, errors.New("uniformVoteWeight not cache last participants count") + } + + if lastPowerSignersCount, ok := v.lastPowerSignersCountCache[p]; ok { + power := numeric.NewDec(lastPowerSignersCount).Quo(numeric.NewDec(v.lastParticipantsCount)) + return &power, nil + } else { + return nil, errors.New("uniformVoteWeight not cache this phase") + } +} diff --git a/consensus/quorum/one-node-staked-vote.go b/consensus/quorum/one-node-staked-vote.go index 797cb02d3..49dc5519f 100644 --- a/consensus/quorum/one-node-staked-vote.go +++ b/consensus/quorum/one-node-staked-vote.go @@ -49,6 +49,7 @@ type stakedVoteWeight struct { DependencyInjectionReader roster votepower.Roster voteTally VoteTally + lastPower map[Phase]numeric.Dec } // Policy .. @@ -323,12 +324,25 @@ func newVoteTally() VoteTally { } func (v *stakedVoteWeight) ResetPrepareAndCommitVotes() { + v.lastPower[Prepare] = v.voteTally.Prepare.tally + v.lastPower[Commit] = v.voteTally.Commit.tally + v.reset([]Phase{Prepare, Commit}) v.voteTally.Prepare = &tallyAndQuorum{numeric.NewDec(0), false} v.voteTally.Commit = &tallyAndQuorum{numeric.NewDec(0), false} } func (v *stakedVoteWeight) ResetViewChangeVotes() { + v.lastPower[ViewChange] = v.voteTally.ViewChange.tally + v.reset([]Phase{ViewChange}) v.voteTally.ViewChange = &tallyAndQuorum{numeric.NewDec(0), false} } + +func (v *stakedVoteWeight) CurrentTotalPower(p Phase) (*numeric.Dec, error) { + if power, ok := v.lastPower[p]; ok { + return &power, nil + } else { + return nil, errors.New("stakedVoteWeight not cache this phase") + } +} diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index 128cde267..a341a77ad 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -132,6 +132,7 @@ type Decider interface { IsAllSigsCollected() bool ResetPrepareAndCommitVotes() ResetViewChangeVotes() + CurrentTotalPower(p Phase) (*numeric.Dec, error) } // Registry .. @@ -408,15 +409,19 @@ func NewDecider(p Policy, shardID uint32) Decider { switch p { case SuperMajorityVote: return &uniformVoteWeight{ - c.DependencyInjectionWriter, c.DependencyInjectionReader, c, + DependencyInjectionWriter: c.DependencyInjectionWriter, + DependencyInjectionReader: c.DependencyInjectionReader, + SignatureReader: c, + lastPowerSignersCountCache: make(map[Phase]int64), } case SuperMajorityStake: return &stakedVoteWeight{ - c.SignatureReader, - c.DependencyInjectionWriter, - c.DependencyInjectionWriter.(DependencyInjectionReader), - *votepower.NewRoster(shardID), - newVoteTally(), + SignatureReader: c.SignatureReader, + DependencyInjectionWriter: c.DependencyInjectionWriter, + DependencyInjectionReader: c.DependencyInjectionWriter.(DependencyInjectionReader), + roster: *votepower.NewRoster(shardID), + voteTally: newVoteTally(), + lastPower: make(map[Phase]numeric.Dec), } default: // Should not be possible diff --git a/hmy/hmy.go b/hmy/hmy.go index 7501882b5..71ac9e7b3 100644 --- a/hmy/hmy.go +++ b/hmy/hmy.go @@ -110,6 +110,7 @@ type NodeAPI interface { GetConsensusCurViewID() uint64 GetConfig() commonRPC.Config ShutDown() + GetLastSigningPower() (float64, error) } // New creates a new Harmony object (including the diff --git a/node/api.go b/node/api.go index dbd80f3f8..bc053de1e 100644 --- a/node/api.go +++ b/node/api.go @@ -2,6 +2,7 @@ package node import ( "github.com/ethereum/go-ethereum/rpc" + "github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/hmy" "github.com/harmony-one/harmony/rosetta" @@ -166,3 +167,14 @@ func (node *Node) GetConfig() rpc_common.Config { ChainConfig: node.chainConfig, } } + +// GetLastSigningPower get last signed power +func (node *Node) GetLastSigningPower() (float64, error) { + power, err := node.Consensus.Decider.CurrentTotalPower(quorum.Commit) + if err != nil { + return 0, err + } + + round := float64(power.MulInt64(10000).RoundInt64()) / 10000 + return round, nil +} diff --git a/rpc/private_debug.go b/rpc/private_debug.go index 17fc86344..af79f58fb 100644 --- a/rpc/private_debug.go +++ b/rpc/private_debug.go @@ -58,3 +58,10 @@ func (s *PrivateDebugService) GetConfig( ) (StructuredResponse, error) { return NewStructuredResponse(s.hmy.NodeAPI.GetConfig()) } + +// GetLastSigningPower get last signed power +func (s *PrivateDebugService) GetLastSigningPower( + ctx context.Context, +) (float64, error) { + return s.hmy.NodeAPI.GetLastSigningPower() +}