Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: broadcast vote power #4683

Merged
merged 1 commit into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,6 @@ debug_external: clean

build_localnet_validator:
bash test/build-localnet-validator.sh

generate:
bash ./scripts/gogenerate.sh
413 changes: 270 additions & 143 deletions api/proto/message/message.pb.go

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions api/proto/message/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ enum MessageType {
DRAND_INIT = 10 [deprecated=true];
DRAND_COMMIT = 11 [deprecated=true];
LOTTERY_REQUEST = 12 [deprecated=true]; // it should be either ENTER or GETPLAYERS but it will be removed later.
LAST_SIGN_POWER = 13;
}

// This is universal message for all communication protocols.
Expand All @@ -47,6 +48,7 @@ message Message {
ViewChangeRequest viewchange = 7;
// Refactor this later after demo.
LotteryRequest lottery_request = 8 [deprecated=true];
LastSignPowerRequest last_sign_power = 9;
}
}

Expand Down Expand Up @@ -98,6 +100,14 @@ message DrandRequest {
bytes payload = 4 [deprecated=true];
}

message LastSignPowerRequest {
int64 prepare = 1;
int64 commit = 2;
int64 change = 3;
bytes sender_pubkey = 4;
uint32 shard_id = 5;
}

message ViewChangeRequest {
uint64 view_id = 1;
uint64 block_num = 2;
Expand Down
15 changes: 15 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ type Consensus struct {
// Both flags only for initialization state.
start bool
isInitialLeader bool

// value receives from
lastKnownSignPower int64
}

// Blockchain returns the blockchain.
Expand Down Expand Up @@ -399,6 +402,18 @@ func (consensus *Consensus) InitConsensusWithValidators() (err error) {
return nil
}

func (consensus *Consensus) SetLastKnownSignPower(i int64) {
consensus.mutex.Lock()
defer consensus.mutex.Unlock()
consensus.lastKnownSignPower = i
}

func (consensus *Consensus) GetLastKnownSignPower() int64 {
consensus.mutex.RLock()
defer consensus.mutex.RUnlock()
return consensus.lastKnownSignPower
}

type downloadAsync struct {
}

Expand Down
46 changes: 46 additions & 0 deletions consensus/consensus_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/ethereum/go-ethereum/common"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/api/proto"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/quorum"
Expand All @@ -17,8 +18,10 @@ import (
bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/crypto/hash"
"github.com/harmony-one/harmony/internal/chain"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/webhooks"
Expand Down Expand Up @@ -153,13 +156,56 @@ func (consensus *Consensus) updateBitmaps() {

}

func (consensus *Consensus) sendLastSignPower() {
if consensus.isLeader() {
k, err := consensus.getLeaderPrivateKey(consensus.LeaderPubKey.Object)
if err != nil {
consensus.getLogger().Err(err).Msg("Leader not found in the committee")
return
}
comm, _ := consensus.decider.CurrentTotalPower(quorum.Commit)
prep, _ := consensus.decider.CurrentTotalPower(quorum.Prepare)
view, _ := consensus.decider.CurrentTotalPower(quorum.ViewChange)
msg := &msg_pb.Message{
ServiceType: msg_pb.ServiceType_CONSENSUS,
Type: msg_pb.MessageType_LAST_SIGN_POWER,
Request: &msg_pb.Message_LastSignPower{
LastSignPower: &msg_pb.LastSignPowerRequest{
Prepare: getOrZero(prep),
Commit: getOrZero(comm),
Change: getOrZero(view),
SenderPubkey: k.Pub.Bytes[:],
ShardId: consensus.ShardID,
},
},
}
marshaledMessage, err := consensus.signAndMarshalConsensusMessage(msg, k.Pri)
if err != nil {
consensus.getLogger().Err(err).
Msg("[constructNewViewMessage] failed to sign and marshal the new view message")
return
}
msgToSend := proto.ConstructConsensusMessage(marshaledMessage)
if err := consensus.msgSender.SendWithoutRetry(
[]nodeconfig.GroupID{
nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))},
p2p.ConstructMessage(msgToSend),
); err != nil {
consensus.getLogger().Err(err).
Msg("[LastSignPower] could not send out the ViewChange message")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update the log message here

}
}
}

// ResetState resets the state of the consensus
func (consensus *Consensus) resetState() {
consensus.switchPhase("ResetState", FBFTAnnounce)

consensus.blockHash = [32]byte{}
consensus.block = []byte{}
consensus.decider.ResetPrepareAndCommitVotes()
consensus.sendLastSignPower()

if consensus.prepareBitmap != nil {
consensus.prepareBitmap.Clear()
}
Expand Down
10 changes: 10 additions & 0 deletions consensus/consensus_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
vrf_bls "github.com/harmony-one/harmony/crypto/vrf/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/vdf/src/vdf_go"
Expand Down Expand Up @@ -93,6 +94,8 @@ func (consensus *Consensus) HandleMessageUpdate(ctx context.Context, peer libp2p
case t == msg_pb.MessageType_NEWVIEW:
members := consensus.decider.Participants()
fbftMsg, err = ParseNewViewMessage(msg, members)
case t == msg_pb.MessageType_LAST_SIGN_POWER:
return nil
default:
fbftMsg, err = consensus.parseFBFTMessage(msg)
}
Expand Down Expand Up @@ -968,3 +971,10 @@ func (consensus *Consensus) DeleteMessagesLessThan(number uint64) {
defer consensus.mutex.Unlock()
consensus.fBFTLog.deleteMessagesLessThan(number)
}

func getOrZero(n *numeric.Dec) int64 {
if n == nil {
return 0
}
return (*n).Mul(numeric.NewDec(100)).TruncateInt64()
}
1 change: 1 addition & 0 deletions consensus/fbft_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type FBFTMessage struct {
M3AggSig *bls_core.Sign
M3Bitmap *bls_cosi.Mask
Verified bool
LastVotePower int64
}

func (m *FBFTMessage) Hash() []byte {
Expand Down
26 changes: 2 additions & 24 deletions node/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package node

import (
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/consensus/votepower"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/eth/rpc"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/internal/tikv"
Expand Down Expand Up @@ -187,27 +185,7 @@ func (node *Node) GetLastSigningPower() (float64, error) {
}

func (node *Node) GetLastSigningPower2() (float64, error) {
bc := node.Consensus.Blockchain()
cur := bc.CurrentBlock()
ss, err := bc.ReadShardState(cur.Epoch())
if err != nil {
return 0, err
}
roster, err := votepower.Compute(&ss.Shards[bc.ShardID()], cur.Epoch())
if err != nil {
return 0, err
}
blsPubKeys, err := ss.Shards[bc.ShardID()].BLSPublicKeys()
if err != nil {
return 0, err
}

mask := bls.NewMask(blsPubKeys)
err = mask.SetMask(cur.Header().LastCommitBitmap())
if err != nil {
return 0, err
}
power := roster.VotePowerByMask(mask)
round := float64(power.MulInt64(10000).RoundInt64()) / 10000
p := node.Consensus.GetLastKnownSignPower()
round := float64(p) / 10000
return round, nil
}
28 changes: 21 additions & 7 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,12 +534,14 @@ func (node *Node) validateNodeMessage(ctx context.Context, payload []byte) (
return payload[p2pNodeMsgPrefixSize:], msgType, nil
}

type ignore = bool

// validateShardBoundMessage validate consensus message
// validate shardID
// validate public key size
// verify message signature
func validateShardBoundMessage(consensus *consensus.Consensus, peer libp2p_peer.ID, nodeConfig *nodeconfig.ConfigType, payload []byte,
) (*msg_pb.Message, *bls.SerializedPublicKey, bool, error) {
) (*msg_pb.Message, *bls.SerializedPublicKey, ignore, error) {
var (
m msg_pb.Message
//consensus = registry.GetConsensus()
Expand Down Expand Up @@ -591,11 +593,16 @@ func validateShardBoundMessage(consensus *consensus.Consensus, peer libp2p_peer.
}
}

maybeCon, maybeVC := m.GetConsensus(), m.GetViewchange()
senderKey := []byte{}
senderBitmap := []byte{}
var (
maybeCon = m.GetConsensus()
maybeVC = m.GetViewchange()
maybeSP = m.GetLastSignPower()
senderKey []byte
senderBitmap []byte
)

if maybeCon != nil {
switch {
case maybeCon != nil:
if maybeCon.ShardId != consensus.ShardID {
nodeConsensusMessageCounterVec.With(prometheus.Labels{"type": "invalid_shard"}).Inc()
return nil, nil, true, errors.WithStack(errWrongShardID)
Expand All @@ -609,7 +616,7 @@ func validateShardBoundMessage(consensus *consensus.Consensus, peer libp2p_peer.
if maybeCon.ViewId+5 < consensus.GetCurBlockViewID() {
return nil, nil, true, errors.WithStack(errViewIDTooOld)
}
} else if maybeVC != nil {
case maybeVC != nil:
if maybeVC.ShardId != consensus.ShardID {
nodeConsensusMessageCounterVec.With(prometheus.Labels{"type": "invalid_shard"}).Inc()
return nil, nil, true, errors.WithStack(errWrongShardID)
Expand All @@ -619,7 +626,14 @@ func validateShardBoundMessage(consensus *consensus.Consensus, peer libp2p_peer.
if maybeVC.ViewId+5 < consensus.GetViewChangingID() {
return nil, nil, true, errors.WithStack(errViewIDTooOld)
}
} else {
case maybeSP != nil:
if maybeSP.ShardId != consensus.ShardID {
nodeConsensusMessageCounterVec.With(prometheus.Labels{"type": "invalid_shard"}).Inc()
return nil, nil, true, errors.WithStack(errWrongShardID)
}
senderKey = maybeSP.SenderPubkey
consensus.SetLastKnownSignPower(maybeSP.Commit)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to capture all 3 VP :
Prepare: getOrZero(prep),
Commit: getOrZero(comm),
Change: getOrZero(view),

during an outage, most likely we won't even hit the commit phase, and during that time only view change VP will be seen.

default:
nodeConsensusMessageCounterVec.With(prometheus.Labels{"type": "invalid"}).Inc()
return nil, nil, true, errors.WithStack(errNoSenderPubKey)
}
Expand Down