From 67d77c3965867aabec23227618b277ceafa0a21a Mon Sep 17 00:00:00 2001 From: Rongjian Lan Date: Thu, 2 Jul 2020 16:33:38 -0700 Subject: [PATCH] Refactor bls public key into a wrapper (#3203) * Refactor bls public key into a wrapper * Fix build * Fix --- cmd/harmony/main.go | 32 ++++---- consensus/checks.go | 22 +++-- consensus/consensus.go | 11 +-- consensus/consensus_service.go | 75 ++++++++++------- consensus/consensus_service_test.go | 4 +- consensus/consensus_v2.go | 7 +- consensus/consensus_viewchange_msg.go | 8 +- consensus/construct.go | 8 +- consensus/construct_test.go | 8 +- consensus/double_sign.go | 26 ++---- consensus/fbft_log.go | 59 +++++++------ consensus/leader.go | 34 ++++---- consensus/quorum/one-node-one-vote.go | 6 +- consensus/quorum/one-node-staked-vote.go | 29 +++---- consensus/quorum/quorum.go | 62 ++++++-------- consensus/threshold.go | 8 +- consensus/validator.go | 12 +-- consensus/view_change.go | 100 +++++++++++------------ hmy/api_backend.go | 4 +- internal/chain/engine.go | 4 +- internal/configs/node/config.go | 10 +-- internal/configs/node/config_test.go | 18 ++-- multibls/multibls.go | 48 +++++------ node/node.go | 6 +- node/node_cross_link.go | 2 +- node/node_handler.go | 15 +++- node/node_newblock.go | 4 +- shard/shard_state.go | 10 ++- 28 files changed, 333 insertions(+), 299 deletions(-) diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index 111f8183c..33b7364c6 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -185,9 +185,9 @@ func passphraseForBLS() { blsPassphrase = passphrase } -func findAccountsByPubKeys(config shardingconfig.Instance, pubKeys []*bls.PublicKey) { +func findAccountsByPubKeys(config shardingconfig.Instance, pubKeys multibls.PublicKeys) { for _, key := range pubKeys { - keyStr := key.SerializeToHexStr() + keyStr := key.Bytes.Hex() _, account := config.FindAccount(keyStr) if account != nil { initialAccounts = append(initialAccounts, account) @@ -202,13 +202,13 @@ func setupLegacyNodeAccount() error { if len(reshardingEpoch) > 0 { for _, epoch := range reshardingEpoch { config := shard.Schedule.InstanceForEpoch(epoch) - findAccountsByPubKeys(config, multiBLSPubKey.PublicKey) + findAccountsByPubKeys(config, multiBLSPubKey) if len(initialAccounts) != 0 { break } } } else { - findAccountsByPubKeys(genesisShardingConfig, multiBLSPubKey.PublicKey) + findAccountsByPubKeys(genesisShardingConfig, multiBLSPubKey) } if len(initialAccounts) == 0 { @@ -233,21 +233,21 @@ func setupStakingNodeAccount() error { return errors.Wrap(err, "cannot determine shard to join") } if err := nodeconfig.GetDefaultConfig().ValidateConsensusKeysForSameShard( - pubKey.PublicKey, shardID, + pubKey, shardID, ); err != nil { return err } - for _, blsKey := range pubKey.PublicKey { + for _, blsKey := range pubKey { initialAccount := &genesis.DeployAccount{} initialAccount.ShardID = shardID - initialAccount.BLSPublicKey = blsKey.SerializeToHexStr() + initialAccount.BLSPublicKey = blsKey.Bytes.Hex() initialAccount.Address = "" initialAccounts = append(initialAccounts, initialAccount) } return nil } -func readMultiBLSKeys(consensusMultiBLSPriKey *multibls.PrivateKey, consensusMultiBLSPubKey *multibls.PublicKey) error { +func readMultiBLSKeys(consensusMultiBLSPriKey *multibls.PrivateKey, consensusMultiBLSPubKey multibls.PublicKeys) error { keyPasses := map[string]string{} blsKeyFiles := []os.FileInfo{} awsEncryptedBLSKeyFiles := []os.FileInfo{} @@ -325,15 +325,15 @@ func readMultiBLSKeys(consensusMultiBLSPriKey *multibls.PrivateKey, consensusMul } // TODO: assumes order between public/private key pairs multibls.AppendPriKey(consensusMultiBLSPriKey, consensusPriKey) - multibls.AppendPubKey(consensusMultiBLSPubKey, consensusPriKey.GetPublicKey()) + consensusMultiBLSPubKey = append(consensusMultiBLSPubKey, multibls.GetPublicKey(consensusPriKey.GetPublicKey())...) } return nil } -func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) multibls.PublicKey { +func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) multibls.PublicKeys { consensusMultiPriKey := &multibls.PrivateKey{} - consensusMultiPubKey := &multibls.PublicKey{} + consensusMultiPubKey := multibls.PublicKeys{} if *blsKeyFile != "" { consensusPriKey, err := blsgen.LoadBLSKeyWithPassPhrase(*blsKeyFile, blsPassphrase) @@ -342,7 +342,7 @@ func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) multibls.PublicKey { os.Exit(100) } multibls.AppendPriKey(consensusMultiPriKey, consensusPriKey) - multibls.AppendPubKey(consensusMultiPubKey, consensusPriKey.GetPublicKey()) + consensusMultiPubKey = append(consensusMultiPubKey, multibls.GetPublicKey(consensusPriKey.GetPublicKey())...) } else if *cmkEncryptedBLSKey != "" { consensusPriKey, err := blsgen.LoadAwsCMKEncryptedBLSKey(*cmkEncryptedBLSKey, awsSettingString) if err != nil { @@ -351,7 +351,7 @@ func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) multibls.PublicKey { } multibls.AppendPriKey(consensusMultiPriKey, consensusPriKey) - multibls.AppendPubKey(consensusMultiPubKey, consensusPriKey.GetPublicKey()) + consensusMultiPubKey = append(consensusMultiPubKey, multibls.GetPublicKey(consensusPriKey.GetPublicKey())...) } else { err := readMultiBLSKeys(consensusMultiPriKey, consensusMultiPubKey) if err != nil { @@ -364,7 +364,7 @@ func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) multibls.PublicKey { nodeConfig.ConsensusPriKey = consensusMultiPriKey nodeConfig.ConsensusPubKey = consensusMultiPubKey - return *consensusMultiPubKey + return consensusMultiPubKey } func createGlobalConfig() (*nodeconfig.ConfigType, error) { @@ -398,7 +398,7 @@ func createGlobalConfig() (*nodeconfig.ConfigType, error) { selfPeer := p2p.Peer{ IP: *ip, Port: *port, - ConsensusPubKey: nodeConfig.ConsensusPubKey.PublicKey[0], + ConsensusPubKey: nodeConfig.ConsensusPubKey[0].Object, } myHost, err = p2p.NewHost(&selfPeer, nodeConfig.P2PPriKey) @@ -431,7 +431,7 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node { currentConsensus, err := consensus.New( myHost, nodeConfig.ShardID, p2p.Peer{}, nodeConfig.ConsensusPriKey, decider, ) - currentConsensus.Decider.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) { + currentConsensus.Decider.SetMyPublicKeyProvider(func() (multibls.PublicKeys, error) { return currentConsensus.PubKey, nil }) diff --git a/consensus/checks.go b/consensus/checks.go index 7cd738ce2..12203513f 100644 --- a/consensus/checks.go +++ b/consensus/checks.go @@ -1,6 +1,8 @@ package consensus import ( + "bytes" + msg_pb "github.com/harmony-one/harmony/api/proto/message" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/crypto/bls" @@ -37,7 +39,7 @@ func (consensus *Consensus) validatorSanityChecks(msg *msg_pb.Message) bool { if err != nil { return false } - if !senderKey.IsEqual(consensus.LeaderPubKey) && + if !senderKey.IsEqual(consensus.LeaderPubKey.Object) && consensus.current.Mode() == Normal && !consensus.IgnoreViewIDCheck.IsSet() { consensus.getLogger().Warn().Msgf( "[%s] SenderKey not match leader PubKey", @@ -104,7 +106,7 @@ func (consensus *Consensus) isRightBlockNumAndViewID(recvMsg *FBFTMessage, Uint64("MsgViewID", recvMsg.ViewID). Uint64("MsgBlockNum", recvMsg.BlockNum). Uint64("blockNum", consensus.blockNum). - Str("ValidatorPubKey", recvMsg.SenderPubkey.SerializeToHexStr()). + Str("ValidatorPubKey", recvMsg.SenderPubkey.Bytes.Hex()). Msg("[OnCommit] BlockNum/viewID not match") return false } @@ -117,15 +119,15 @@ func (consensus *Consensus) onAnnounceSanityChecks(recvMsg *FBFTMessage) bool { ) if len(logMsgs) > 0 { if logMsgs[0].BlockHash != recvMsg.BlockHash && - logMsgs[0].SenderPubkey.IsEqual(recvMsg.SenderPubkey) { + bytes.Equal(logMsgs[0].SenderPubkey.Bytes[:], recvMsg.SenderPubkey.Bytes[:]) { consensus.getLogger().Debug(). - Str("logMsgSenderKey", logMsgs[0].SenderPubkey.SerializeToHexStr()). + Str("logMsgSenderKey", logMsgs[0].SenderPubkey.Bytes.Hex()). Str("logMsgBlockHash", logMsgs[0].BlockHash.Hex()). - Str("recvMsg.SenderPubkey", recvMsg.SenderPubkey.SerializeToHexStr()). + Str("recvMsg.SenderPubkey", recvMsg.SenderPubkey.Bytes.Hex()). Uint64("recvMsg.BlockNum", recvMsg.BlockNum). Uint64("recvMsg.ViewID", recvMsg.ViewID). Str("recvMsgBlockHash", recvMsg.BlockHash.Hex()). - Str("LeaderKey", consensus.LeaderPubKey.SerializeToHexStr()). + Str("LeaderKey", consensus.LeaderPubKey.Bytes.Hex()). Msg("[OnAnnounce] Leader is malicious") if consensus.current.Mode() == ViewChanging { consensus.getLogger().Debug().Msg( @@ -136,7 +138,7 @@ func (consensus *Consensus) onAnnounceSanityChecks(recvMsg *FBFTMessage) bool { } } consensus.getLogger().Debug(). - Str("leaderKey", consensus.LeaderPubKey.SerializeToHexStr()). + Str("leaderKey", consensus.LeaderPubKey.Bytes.Hex()). Msg("[OnAnnounce] Announce message received again") } return consensus.isRightBlockNumCheck(recvMsg) @@ -205,7 +207,7 @@ func (consensus *Consensus) viewChangeSanityCheck(msg *msg_pb.Message) bool { } consensus.getLogger().Debug(). Msg("[viewChangeSanityCheck] Checking new message") - senderKey, err := consensus.verifyViewChangeSenderKey(msg) + err := consensus.verifyViewChangeSenderKey(msg) if err != nil { if err == shard.ErrValidNotInCommittee { consensus.getLogger().Info(). @@ -221,6 +223,10 @@ func (consensus *Consensus) viewChangeSanityCheck(msg *msg_pb.Message) bool { } return false } + senderKey, err := bls.BytesToBLSPublicKey(msg.GetViewchange().SenderPubkey) + if err != nil { + return false + } if err := verifyMessageSig(senderKey, msg); err != nil { consensus.getLogger().Error().Err(err).Msgf( "[%s] Failed To Verify Sender's Signature", diff --git a/consensus/consensus.go b/consensus/consensus.go index ee4480683..a1457d6bf 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -14,6 +14,7 @@ import ( "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/staking/slash" "github.com/pkg/errors" ) @@ -76,9 +77,9 @@ type Consensus struct { pubKeyLock sync.Mutex // private/public keys of current node priKey *multibls.PrivateKey - PubKey *multibls.PublicKey + PubKey multibls.PublicKeys // the publickey of leader - LeaderPubKey *bls.PublicKey + LeaderPubKey *shard.BLSPublicKeyWrapper viewID uint64 // Blockhash - 32 byte blockHash [32]byte @@ -153,8 +154,8 @@ func (consensus *Consensus) VdfSeedSize() int { // GetLeaderPrivateKey returns leader private key if node is the leader func (consensus *Consensus) GetLeaderPrivateKey(leaderKey *bls.PublicKey) (*bls.SecretKey, error) { - for i, key := range consensus.PubKey.PublicKey { - if key.IsEqual(leaderKey) { + for i, key := range consensus.PubKey { + if key.Object.IsEqual(leaderKey) { return consensus.priKey.PrivateKey[i], nil } } @@ -163,7 +164,7 @@ func (consensus *Consensus) GetLeaderPrivateKey(leaderKey *bls.PublicKey) (*bls. // GetConsensusLeaderPrivateKey returns consensus leader private key if node is the leader func (consensus *Consensus) GetConsensusLeaderPrivateKey() (*bls.SecretKey, error) { - return consensus.GetLeaderPrivateKey(consensus.LeaderPubKey) + return consensus.GetLeaderPrivateKey(consensus.LeaderPubKey.Object) } // TODO: put shardId into chain reader's chain config diff --git a/consensus/consensus_service.go b/consensus/consensus_service.go index 3e26fec4f..dea4fd2f0 100644 --- a/consensus/consensus_service.go +++ b/consensus/consensus_service.go @@ -84,9 +84,13 @@ func (consensus *Consensus) UpdatePublicKeys(pubKeys []*bls.PublicKey) int64 { Str("BLSPubKey", pubKeys[i].SerializeToHexStr()). Msg("Member") } - consensus.LeaderPubKey = pubKeys[0] - utils.Logger().Info(). - Str("info", consensus.LeaderPubKey.SerializeToHexStr()).Msg("My Leader") + + allKeys := consensus.Decider.Participants() + if len(allKeys) != 0 { + consensus.LeaderPubKey = &allKeys[0] + utils.Logger().Info(). + Str("info", consensus.LeaderPubKey.Bytes.Hex()).Msg("My Leader") + } consensus.pubKeyLock.Unlock() // reset states after update public keys consensus.ResetState() @@ -150,8 +154,12 @@ func (consensus *Consensus) ResetState() { consensus.block = []byte{} consensus.Decider.ResetPrepareAndCommitVotes() members := consensus.Decider.Participants() - prepareBitmap, _ := bls_cosi.NewMask(members, nil) - commitBitmap, _ := bls_cosi.NewMask(members, nil) + publicKeys := []*bls.PublicKey{} + for _, key := range members { + publicKeys = append(publicKeys, key.Object) + } + prepareBitmap, _ := bls_cosi.NewMask(publicKeys, nil) + commitBitmap, _ := bls_cosi.NewMask(publicKeys, nil) consensus.prepareBitmap = prepareBitmap consensus.commitBitmap = commitBitmap consensus.aggregatedPrepareSig = nil @@ -164,12 +172,8 @@ func (consensus *Consensus) ToggleConsensusCheck() { } // IsValidatorInCommittee returns whether the given validator BLS address is part of my committee -func (consensus *Consensus) IsValidatorInCommittee(pubKey *bls.PublicKey) bool { - pubKeyBytes := shard.FromLibBLSPublicKeyUnsafe(pubKey) - if pubKeyBytes == nil { - return false - } - return consensus.Decider.IndexOf(*pubKeyBytes) != -1 +func (consensus *Consensus) IsValidatorInCommittee(pubKey shard.BLSPublicKey) bool { + return consensus.Decider.IndexOf(pubKey) != -1 } // IsValidatorInCommitteeBytes returns whether the given validator BLS address is part of my committee @@ -210,17 +214,15 @@ func (consensus *Consensus) verifySenderKey(msg *msg_pb.Message) error { return nil } -func (consensus *Consensus) verifyViewChangeSenderKey(msg *msg_pb.Message) (*bls.PublicKey, error) { +func (consensus *Consensus) verifyViewChangeSenderKey(msg *msg_pb.Message) error { vcMsg := msg.GetViewchange() - senderKey, err := bls_cosi.BytesToBLSPublicKey(vcMsg.SenderPubkey) - if err != nil { - return nil, err - } + senderKey := shard.BLSPublicKey{} + copy(senderKey[:], vcMsg.SenderPubkey) if !consensus.IsValidatorInCommittee(senderKey) { - return nil, shard.ErrValidNotInCommittee + return shard.ErrValidNotInCommittee } - return senderKey, nil + return nil } // SetViewID set the viewID to the height of the blockchain @@ -263,7 +265,7 @@ func (consensus *Consensus) checkViewID(msg *FBFTMessage) error { consensus.consensusTimeout[timeoutConsensus].Start() utils.Logger().Debug(). Uint64("viewID", consensus.viewID). - Str("leaderKey", consensus.LeaderPubKey.SerializeToHexStr()[:20]). + Str("leaderKey", consensus.LeaderPubKey.Bytes.Hex()). Msg("viewID and leaderKey override") utils.Logger().Debug(). Uint64("viewID", consensus.viewID). @@ -291,8 +293,15 @@ func (consensus *Consensus) ReadSignatureBitmapPayload( return nil, nil, errors.New("payload not have enough length") } sigAndBitmapPayload := recvPayload[offset:] + + // TODO(audit): keep a Mask in the Decider so it won't be reconstructed on the fly. + members := consensus.Decider.Participants() + publicKeys := []*bls.PublicKey{} + for _, key := range members { + publicKeys = append(publicKeys, key.Object) + } return chain.ReadSignatureBitmapByPublicKeys( - sigAndBitmapPayload, consensus.Decider.Participants(), + sigAndBitmapPayload, publicKeys, ) } @@ -310,7 +319,7 @@ func (consensus *Consensus) getLogger() *zerolog.Logger { // retrieve corresponding blsPublicKey from Coinbase Address func (consensus *Consensus) getLeaderPubKeyFromCoinbase( header *block.Header, -) (*bls.PublicKey, error) { +) (*shard.BLSPublicKeyWrapper, error) { shardState, err := consensus.ChainReader.ReadShardState(header.Epoch()) if err != nil { return nil, errors.Wrapf(err, "cannot read shard state %v %s", @@ -333,14 +342,14 @@ func (consensus *Consensus) getLeaderPubKeyFromCoinbase( if err := member.BLSPublicKey.ToLibBLSPublicKey(committerKey); err != nil { return nil, err } - return committerKey, nil + return &shard.BLSPublicKeyWrapper{Object: committerKey, Bytes: member.BLSPublicKey}, nil } } else { if member.EcdsaAddress == header.Coinbase() { if err := member.BLSPublicKey.ToLibBLSPublicKey(committerKey); err != nil { return nil, err } - return committerKey, nil + return &shard.BLSPublicKeyWrapper{Object: committerKey, Bytes: member.BLSPublicKey}, nil } } } @@ -385,7 +394,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { // Only happens once, the flip-over to a new Decider policy if isFirstTimeStaking || haventUpdatedDecider { decider := quorum.NewDecider(quorum.SuperMajorityStake, consensus.ShardID) - decider.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) { + decider.SetMyPublicKeyProvider(func() (multibls.PublicKeys, error) { return consensus.PubKey, nil }) consensus.Decider = decider @@ -487,7 +496,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { hasError = true } else { consensus.getLogger().Debug(). - Str("leaderPubKey", leaderPubKey.SerializeToHexStr()). + Str("leaderPubKey", leaderPubKey.Bytes.Hex()). Msg("[UpdateConsensusInformation] Most Recent LeaderPubKey Updated Based on BlockChain") consensus.LeaderPubKey = leaderPubKey } @@ -501,7 +510,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { } // If the leader changed and I myself become the leader - if !consensus.LeaderPubKey.IsEqual(oldLeader) && consensus.IsLeader() { + if !consensus.LeaderPubKey.Object.IsEqual(oldLeader.Object) && consensus.IsLeader() { go func() { utils.Logger().Debug(). Str("myKey", consensus.PubKey.SerializeToHexStr()). @@ -521,8 +530,8 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { // IsLeader check if the node is a leader or not by comparing the public key of // the node with the leader public key func (consensus *Consensus) IsLeader() bool { - for _, key := range consensus.PubKey.PublicKey { - if key.IsEqual(consensus.LeaderPubKey) { + for _, key := range consensus.PubKey { + if key.Object.IsEqual(consensus.LeaderPubKey.Object) { return true } } @@ -540,6 +549,10 @@ func (consensus *Consensus) NeedsRandomNumberGeneration(epoch *big.Int) bool { func (consensus *Consensus) addViewIDKeyIfNotExist(viewID uint64) { members := consensus.Decider.Participants() + publicKeys := []*bls.PublicKey{} + for _, key := range members { + publicKeys = append(publicKeys, key.Object) + } if _, ok := consensus.bhpSigs[viewID]; !ok { consensus.bhpSigs[viewID] = map[string]*bls.Sign{} } @@ -550,15 +563,15 @@ func (consensus *Consensus) addViewIDKeyIfNotExist(viewID uint64) { consensus.viewIDSigs[viewID] = map[string]*bls.Sign{} } if _, ok := consensus.bhpBitmap[viewID]; !ok { - bhpBitmap, _ := bls_cosi.NewMask(members, nil) + bhpBitmap, _ := bls_cosi.NewMask(publicKeys, nil) consensus.bhpBitmap[viewID] = bhpBitmap } if _, ok := consensus.nilBitmap[viewID]; !ok { - nilBitmap, _ := bls_cosi.NewMask(members, nil) + nilBitmap, _ := bls_cosi.NewMask(publicKeys, nil) consensus.nilBitmap[viewID] = nilBitmap } if _, ok := consensus.viewIDBitmap[viewID]; !ok { - viewIDBitmap, _ := bls_cosi.NewMask(members, nil) + viewIDBitmap, _ := bls_cosi.NewMask(publicKeys, nil) consensus.viewIDBitmap[viewID] = viewIDBitmap } } diff --git a/consensus/consensus_service_test.go b/consensus/consensus_service_test.go index f619ab40e..aaf4c0192 100644 --- a/consensus/consensus_service_test.go +++ b/consensus/consensus_service_test.go @@ -40,8 +40,10 @@ func TestPopulateMessageFields(t *testing.T) { }, } + keyBytes := shard.BLSPublicKey{} + keyBytes.FromLibBLSPublicKey(blsPriKey.GetPublicKey()) consensusMsg := consensus.populateMessageFields(msg.GetConsensus(), consensus.blockHash[:], - blsPriKey.GetPublicKey()) + keyBytes) if consensusMsg.ViewId != 2 { t.Errorf("Consensus ID is not populated correctly") diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index 9707b97a6..7455da7ff 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -107,7 +107,10 @@ func (consensus *Consensus) finalizeCommits() { return } // Construct committed message - network, err := consensus.construct(msg_pb.MessageType_COMMITTED, nil, leaderPriKey.GetPublicKey(), leaderPriKey) + // TODO(audit): wrap bls private key with public key + leaderPubKeyBytes := shard.BLSPublicKey{} + leaderPubKeyBytes.FromLibBLSPublicKey(leaderPriKey.GetPublicKey()) + network, err := consensus.construct(msg_pb.MessageType_COMMITTED, nil, leaderPubKeyBytes, leaderPriKey) if err != nil { consensus.getLogger().Warn().Err(err). Msg("[FinalizeCommits] Unable to construct Committed message") @@ -544,7 +547,7 @@ func (consensus *Consensus) GenerateVrfAndProof(newBlock *types.Block, vrfBlockN // ValidateVrfAndProof validates a VRF/Proof from hash of previous block func (consensus *Consensus) ValidateVrfAndProof(headerObj *block.Header) bool { - vrfPk := vrf_bls.NewVRFVerifier(consensus.LeaderPubKey) + vrfPk := vrf_bls.NewVRFVerifier(consensus.LeaderPubKey.Object) var blockHash [32]byte previousHeader := consensus.ChainReader.GetHeaderByNumber( headerObj.Number().Uint64() - 1, diff --git a/consensus/consensus_viewchange_msg.go b/consensus/consensus_viewchange_msg.go index 7cdeac987..6ab1f0621 100644 --- a/consensus/consensus_viewchange_msg.go +++ b/consensus/consensus_viewchange_msg.go @@ -3,6 +3,8 @@ package consensus import ( "encoding/binary" + "github.com/harmony-one/harmony/shard" + "github.com/ethereum/go-ethereum/rlp" "github.com/harmony-one/bls/ffi/go/bls" @@ -30,7 +32,7 @@ func (consensus *Consensus) constructViewChangeMessage(pubKey *bls.PublicKey, pr vcMsg.SenderPubkey = pubKey.Serialize() // next leader key already updated - vcMsg.LeaderPubkey = consensus.LeaderPubKey.Serialize() + vcMsg.LeaderPubkey = consensus.LeaderPubKey.Bytes[:] preparedMsgs := consensus.FBFTLog.GetMessagesByTypeSeq( msg_pb.MessageType_PREPARED, consensus.blockNum, @@ -98,7 +100,7 @@ func (consensus *Consensus) constructViewChangeMessage(pubKey *bls.PublicKey, pr } // new leader construct newview message -func (consensus *Consensus) constructNewViewMessage(viewID uint64, pubKey *bls.PublicKey, priKey *bls.SecretKey) []byte { +func (consensus *Consensus) constructNewViewMessage(viewID uint64, pubKey shard.BLSPublicKey, priKey *bls.SecretKey) []byte { message := &msg_pb.Message{ ServiceType: msg_pb.ServiceType_CONSENSUS, Type: msg_pb.MessageType_NEWVIEW, @@ -112,7 +114,7 @@ func (consensus *Consensus) constructNewViewMessage(viewID uint64, pubKey *bls.P vcMsg.BlockNum = consensus.blockNum vcMsg.ShardId = consensus.ShardID // sender address - vcMsg.SenderPubkey = pubKey.Serialize() + vcMsg.SenderPubkey = pubKey[:] vcMsg.Payload = consensus.m1Payload if len(consensus.m1Payload) != 0 { block := consensus.FBFTLog.GetBlockByHash(consensus.blockHash) diff --git a/consensus/construct.go b/consensus/construct.go index 5565f336d..dd4235881 100644 --- a/consensus/construct.go +++ b/consensus/construct.go @@ -3,6 +3,8 @@ package consensus import ( "bytes" + "github.com/harmony-one/harmony/shard" + "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" @@ -22,7 +24,7 @@ type NetworkMessage struct { // Populates the common basic fields for all consensus message. func (consensus *Consensus) populateMessageFields( - request *msg_pb.ConsensusRequest, blockHash []byte, pubKey *bls.PublicKey, + request *msg_pb.ConsensusRequest, blockHash []byte, pubKey shard.BLSPublicKey, ) *msg_pb.ConsensusRequest { request.ViewId = consensus.viewID request.BlockNum = consensus.blockNum @@ -30,13 +32,13 @@ func (consensus *Consensus) populateMessageFields( // 32 byte block hash request.BlockHash = blockHash // sender address - request.SenderPubkey = pubKey.Serialize() + request.SenderPubkey = pubKey[:] return request } // construct is the single creation point of messages intended for the wire. func (consensus *Consensus) construct( - p msg_pb.MessageType, payloadForSign []byte, pubKey *bls.PublicKey, priKey *bls.SecretKey, + p msg_pb.MessageType, payloadForSign []byte, pubKey shard.BLSPublicKey, priKey *bls.SecretKey, ) (*NetworkMessage, error) { message := &msg_pb.Message{ ServiceType: msg_pb.ServiceType_CONSENSUS, diff --git a/consensus/construct_test.go b/consensus/construct_test.go index aa3391a26..6cd6549bf 100644 --- a/consensus/construct_test.go +++ b/consensus/construct_test.go @@ -32,7 +32,9 @@ func TestConstructAnnounceMessage(test *testing.T) { test.Fatalf("Cannot create consensus: %v", err) } consensus.blockHash = [32]byte{} - if _, err = consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, blsPriKey.GetPublicKey(), blsPriKey); err != nil { + keyBytes := shard.BLSPublicKey{} + keyBytes.FromLibBLSPublicKey(blsPriKey.GetPublicKey()) + if _, err = consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, keyBytes, blsPriKey); err != nil { test.Fatalf("could not construct announce: %v", err) } } @@ -94,7 +96,9 @@ func TestConstructPreparedMessage(test *testing.T) { test.Log(errors.New("prepareBitmap.SetKey")) } - network, err := consensus.construct(msg_pb.MessageType_PREPARED, nil, blsPriKey.GetPublicKey(), blsPriKey) + keyBytes := shard.BLSPublicKey{} + keyBytes.FromLibBLSPublicKey(blsPriKey.GetPublicKey()) + network, err := consensus.construct(msg_pb.MessageType_PREPARED, nil, keyBytes, blsPriKey) if err != nil { test.Errorf("Error when creating prepared message") } diff --git a/consensus/double_sign.go b/consensus/double_sign.go index 2a43a4240..31322ffc4 100644 --- a/consensus/double_sign.go +++ b/consensus/double_sign.go @@ -4,7 +4,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/consensus/quorum" - "github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/staking/slash" ) @@ -13,11 +12,11 @@ import ( func (consensus *Consensus) checkDoubleSign(recvMsg *FBFTMessage) bool { if consensus.couldThisBeADoubleSigner(recvMsg) { if alreadyCastBallot := consensus.Decider.ReadBallot( - quorum.Commit, recvMsg.SenderPubkeyBytes, + quorum.Commit, recvMsg.SenderPubkey.Bytes, ); alreadyCastBallot != nil { firstPubKey := bls.PublicKey{} alreadyCastBallot.SignerPubKey.ToLibBLSPublicKey(&firstPubKey) - if recvMsg.SenderPubkey.IsEqual(&firstPubKey) { + if recvMsg.SenderPubkey.Object.IsEqual(&firstPubKey) { for _, blk := range consensus.FBFTLog.GetBlocksByNumber(recvMsg.BlockNum) { firstSignedBlock := blk.Header() areHeightsEqual := firstSignedBlock.Number().Uint64() == recvMsg.BlockNum @@ -45,13 +44,7 @@ func (consensus *Consensus) checkDoubleSign(recvMsg *FBFTMessage) bool { Msg("could not read shard state") return true } - offender := shard.FromLibBLSPublicKeyUnsafe(recvMsg.SenderPubkey) - if offender == nil { - consensus.getLogger().Error(). - Str("msg", recvMsg.String()). - Msg("could not get shard key from sender's key") - return true - } + subComm, err := committee.FindCommitteeByID( consensus.ShardID, ) @@ -62,21 +55,14 @@ func (consensus *Consensus) checkDoubleSign(recvMsg *FBFTMessage) bool { return true } - addr, err := subComm.AddressForBLSKey(*offender) + addr, err := subComm.AddressForBLSKey(recvMsg.SenderPubkey.Bytes) if err != nil { consensus.getLogger().Err(err).Str("msg", recvMsg.String()). Msg("could not find address for bls key") return true } - leaderShardKey := shard.FromLibBLSPublicKeyUnsafe(consensus.LeaderPubKey) - if leaderShardKey == nil { - consensus.getLogger().Error(). - Str("msg", recvMsg.String()). - Msg("could not get shard key from leader's key") - return true - } - leaderAddr, err := subComm.AddressForBLSKey(*leaderShardKey) + leaderAddr, err := subComm.AddressForBLSKey(consensus.LeaderPubKey.Bytes) if err != nil { consensus.getLogger().Err(err).Str("msg", recvMsg.String()). Msg("could not find address for leader bls key") @@ -92,7 +78,7 @@ func (consensus *Consensus) checkDoubleSign(recvMsg *FBFTMessage) bool { alreadyCastBallot.Signature, }, SecondVote: slash.Vote{ - *offender, + recvMsg.SenderPubkey.Bytes, recvMsg.BlockHash, common.Hex2Bytes(doubleSign.SerializeToHexStr()), }}, diff --git a/consensus/fbft_log.go b/consensus/fbft_log.go index 17ac7fce9..6c7d0fad6 100644 --- a/consensus/fbft_log.go +++ b/consensus/fbft_log.go @@ -23,21 +23,20 @@ type FBFTLog struct { // FBFTMessage is the record of pbft messages received by a node during FBFT process type FBFTMessage struct { - MessageType msg_pb.MessageType - ViewID uint64 - BlockNum uint64 - BlockHash common.Hash - Block []byte - SenderPubkey *bls.PublicKey - SenderPubkeyBytes shard.BLSPublicKey - LeaderPubkey *bls.PublicKey - Payload []byte - ViewchangeSig *bls.Sign - ViewidSig *bls.Sign - M2AggSig *bls.Sign - M2Bitmap *bls_cosi.Mask - M3AggSig *bls.Sign - M3Bitmap *bls_cosi.Mask + MessageType msg_pb.MessageType + ViewID uint64 + BlockNum uint64 + BlockHash common.Hash + Block []byte + SenderPubkey *shard.BLSPublicKeyWrapper + LeaderPubkey *shard.BLSPublicKeyWrapper + Payload []byte + ViewchangeSig *bls.Sign + ViewidSig *bls.Sign + M2AggSig *bls.Sign + M2Bitmap *bls_cosi.Mask + M3AggSig *bls.Sign + M3Bitmap *bls_cosi.Mask } // String .. @@ -48,8 +47,8 @@ func (m *FBFTMessage) String() string { m.ViewID, m.BlockNum, m.BlockHash.Hex(), - m.SenderPubkeyBytes.Hex(), - m.LeaderPubkey.SerializeToHexStr(), + m.SenderPubkey.Bytes.Hex(), + m.LeaderPubkey.Bytes.Hex(), ) } @@ -250,8 +249,8 @@ func ParseFBFTMessage(msg *msg_pb.Message) (*FBFTMessage, error) { if err != nil { return nil, err } - pbftMsg.SenderPubkey = pubKey - copy(pbftMsg.SenderPubkeyBytes[:], consensusMsg.SenderPubkey[:]) + pbftMsg.SenderPubkey = &shard.BLSPublicKeyWrapper{Object: pubKey} + copy(pbftMsg.SenderPubkey.Bytes[:], consensusMsg.SenderPubkey[:]) return &pbftMsg, nil } @@ -296,9 +295,11 @@ func ParseViewChangeMessage(msg *msg_pb.Message) (*FBFTMessage, error) { utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to deserialize the viewid signature") return nil, err } - pbftMsg.SenderPubkey = pubKey - copy(pbftMsg.SenderPubkeyBytes[:], vcMsg.SenderPubkey[:]) - pbftMsg.LeaderPubkey = leaderKey + + pbftMsg.SenderPubkey = &shard.BLSPublicKeyWrapper{Object: pubKey} + copy(pbftMsg.SenderPubkey.Bytes[:], vcMsg.SenderPubkey[:]) + pbftMsg.LeaderPubkey = &shard.BLSPublicKeyWrapper{Object: leaderKey} + copy(pbftMsg.LeaderPubkey.Bytes[:], vcMsg.LeaderPubkey[:]) pbftMsg.ViewchangeSig = &vcSig pbftMsg.ViewidSig = &vcSig1 return &pbftMsg, nil @@ -326,9 +327,15 @@ func (consensus *Consensus) ParseNewViewMessage(msg *msg_pb.Message) (*FBFTMessa utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to parse senderpubkey") return nil, err } - FBFTMsg.SenderPubkey = pubKey - copy(FBFTMsg.SenderPubkeyBytes[:], vcMsg.SenderPubkey[:]) + FBFTMsg.SenderPubkey = &shard.BLSPublicKeyWrapper{Object: pubKey} + copy(FBFTMsg.SenderPubkey.Bytes[:], vcMsg.SenderPubkey[:]) + + members := consensus.Decider.Participants() + publicKeys := []*bls.PublicKey{} + for _, key := range members { + publicKeys = append(publicKeys, key.Object) + } if len(vcMsg.M3Aggsigs) > 0 { m3Sig := bls.Sign{} err = m3Sig.Deserialize(vcMsg.M3Aggsigs) @@ -336,7 +343,7 @@ func (consensus *Consensus) ParseNewViewMessage(msg *msg_pb.Message) (*FBFTMessa utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to deserialize the multi signature for M3 viewID signature") return nil, err } - m3mask, err := bls_cosi.NewMask(consensus.Decider.Participants(), nil) + m3mask, err := bls_cosi.NewMask(publicKeys, nil) if err != nil { utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to create mask for multi signature") return nil, err @@ -353,7 +360,7 @@ func (consensus *Consensus) ParseNewViewMessage(msg *msg_pb.Message) (*FBFTMessa utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to deserialize the multi signature for M2 aggregated signature") return nil, err } - m2mask, err := bls_cosi.NewMask(consensus.Decider.Participants(), nil) + m2mask, err := bls_cosi.NewMask(publicKeys, nil) if err != nil { utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to create mask for multi signature") return nil, err diff --git a/consensus/leader.go b/consensus/leader.go index 1ab144ac9..e655bebf7 100644 --- a/consensus/leader.go +++ b/consensus/leader.go @@ -3,6 +3,8 @@ package consensus import ( "time" + "github.com/harmony-one/harmony/shard" + "github.com/ethereum/go-ethereum/rlp" "github.com/harmony-one/bls/ffi/go/bls" msg_pb "github.com/harmony-one/harmony/api/proto/message" @@ -37,7 +39,11 @@ func (consensus *Consensus) announce(block *types.Block) { consensus.getLogger().Warn().Err(err).Msg("[Announce] Node not a leader") return } - networkMessage, err := consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, key.GetPublicKey(), key) + + // TODO(audit): wrap bls private key with public key + leaderPubKeyBytes := shard.BLSPublicKey{} + leaderPubKeyBytes.FromLibBLSPublicKey(key.GetPublicKey()) + networkMessage, err := consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, leaderPubKeyBytes, key) if err != nil { consensus.getLogger().Err(err). Str("message-type", msg_pb.MessageType_ANNOUNCE.String()). @@ -56,8 +62,8 @@ func (consensus *Consensus) announce(block *types.Block) { consensus.FBFTLog.AddBlock(block) // Leader sign the block hash itself - for i, key := range consensus.PubKey.PublicKey { - if err := consensus.prepareBitmap.SetKey(key, true); err != nil { + for i, key := range consensus.PubKey { + if err := consensus.prepareBitmap.SetKey(key.Object, true); err != nil { consensus.getLogger().Warn().Err(err).Msgf( "[Announce] Leader prepareBitmap SetKey failed for key at index %d", i, ) @@ -66,7 +72,7 @@ func (consensus *Consensus) announce(block *types.Block) { if _, err := consensus.Decider.AddNewVote( quorum.Prepare, - consensus.PubKey.PublicKeyBytes[i], + key.Bytes, consensus.priKey.PrivateKey[i].SignHash(consensus.blockHash[:]), block.Hash(), block.NumberU64(), @@ -132,10 +138,10 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) { consensus.mutex.Lock() defer consensus.mutex.Unlock() // proceed only when the message is not received before - signed := consensus.Decider.ReadBallot(quorum.Prepare, recvMsg.SenderPubkeyBytes) + signed := consensus.Decider.ReadBallot(quorum.Prepare, recvMsg.SenderPubkey.Bytes) if signed != nil { consensus.getLogger().Debug(). - Str("validatorPubKey", recvMsg.SenderPubkeyBytes.Hex()). + Str("validatorPubKey", recvMsg.SenderPubkey.Bytes.Hex()). Msg("[OnPrepare] Already Received prepare message from the validator") return } @@ -143,7 +149,7 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) { if consensus.Decider.IsQuorumAchieved(quorum.Prepare) { // already have enough signatures consensus.getLogger().Debug(). - Str("validatorPubKey", recvMsg.SenderPubkeyBytes.Hex()). + Str("validatorPubKey", recvMsg.SenderPubkey.Bytes.Hex()). Msg("[OnPrepare] Received Additional Prepare Message") return } @@ -156,7 +162,7 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) { Msg("[OnPrepare] Failed to deserialize bls signature") return } - if !sign.VerifyHash(recvMsg.SenderPubkey, consensus.blockHash[:]) { + if !sign.VerifyHash(recvMsg.SenderPubkey.Object, consensus.blockHash[:]) { consensus.getLogger().Error().Msg("[OnPrepare] Received invalid BLS signature") return } @@ -166,7 +172,7 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) { Int64("PublicKeys", consensus.Decider.ParticipantsCount()). Msg("[OnPrepare] Received New Prepare Signature") if _, err := consensus.Decider.AddNewVote( - quorum.Prepare, recvMsg.SenderPubkeyBytes, + quorum.Prepare, recvMsg.SenderPubkey.Bytes, &sign, recvMsg.BlockHash, recvMsg.BlockNum, recvMsg.ViewID, ); err != nil { @@ -174,7 +180,7 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) { return } // Set the bitmap indicating that this validator signed. - if err := prepareBitmap.SetKey(recvMsg.SenderPubkey, true); err != nil { + if err := prepareBitmap.SetKey(recvMsg.SenderPubkey.Object, true); err != nil { consensus.getLogger().Warn().Err(err).Msg("[OnPrepare] prepareBitmap.SetKey failed") return } @@ -211,7 +217,7 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) { validatorPubKey, commitSig, commitBitmap := recvMsg.SenderPubkey, recvMsg.Payload, consensus.commitBitmap logger := consensus.getLogger().With(). - Str("validatorPubKey", validatorPubKey.SerializeToHexStr()).Logger() + Str("validatorPubKey", validatorPubKey.Bytes.Hex()).Logger() // has to be called before verifying signature quorumWasMet := consensus.Decider.IsQuorumAchieved(quorum.Commit) @@ -238,7 +244,7 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) { Uint64("MsgBlockNum", recvMsg.BlockNum). Logger() - if !sign.VerifyHash(recvMsg.SenderPubkey, commitPayload) { + if !sign.VerifyHash(recvMsg.SenderPubkey.Object, commitPayload) { logger.Error().Msg("[OnCommit] Cannot verify commit message") return } @@ -249,14 +255,14 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) { logger.Debug().Msg("[OnCommit] Received new commit message") if _, err := consensus.Decider.AddNewVote( - quorum.Commit, recvMsg.SenderPubkeyBytes, + quorum.Commit, recvMsg.SenderPubkey.Bytes, &sign, recvMsg.BlockHash, recvMsg.BlockNum, recvMsg.ViewID, ); err != nil { return } // Set the bitmap indicating that this validator signed. - if err := commitBitmap.SetKey(recvMsg.SenderPubkey, true); err != nil { + if err := commitBitmap.SetKey(recvMsg.SenderPubkey.Object, true); err != nil { consensus.getLogger().Warn().Err(err). Msg("[OnCommit] commitBitmap.SetKey failed") return diff --git a/consensus/quorum/one-node-one-vote.go b/consensus/quorum/one-node-one-vote.go index 7a59d23a4..7468e7aa0 100644 --- a/consensus/quorum/one-node-one-vote.go +++ b/consensus/quorum/one-node-one-vote.go @@ -91,7 +91,7 @@ func (v *uniformVoteWeight) MarshalJSON() ([]byte, error) { keysDump := v.Participants() keys := make([]string, len(keysDump)) for i := range keysDump { - keys[i] = keysDump[i].SerializeToHexStr() + keys[i] = keysDump[i].Bytes.Hex() } return json.Marshal(t{v.Policy().String(), len(keys), keys}) @@ -104,9 +104,9 @@ func (v *uniformVoteWeight) AmIMemberOfCommitee() bool { } identity, _ := pubKeyFunc() everyone := v.Participants() - for _, key := range identity.PublicKey { + for _, key := range identity { for i := range everyone { - if key.IsEqual(everyone[i]) { + if key.Object.IsEqual(everyone[i].Object) { return true } } diff --git a/consensus/quorum/one-node-staked-vote.go b/consensus/quorum/one-node-staked-vote.go index 9333e6e67..e8d6101dc 100644 --- a/consensus/quorum/one-node-staked-vote.go +++ b/consensus/quorum/one-node-staked-vote.go @@ -84,16 +84,19 @@ func (v *stakedVoteWeight) AddNewVote( tallyQuorum.tally = tallyQuorum.tally.Add(additionalVotePower) t := v.QuorumThreshold() - tallyQuorum.quorumAchieved = tallyQuorum.tally.GT(t) - msg := "Attempt to reach quorum" - if tallyQuorum.quorumAchieved { - msg = "Quorum Achieved!" + if !tallyQuorum.quorumAchieved { + tallyQuorum.quorumAchieved = tallyQuorum.tally.GT(t) + + msg := "Attempt to reach quorum" + if tallyQuorum.quorumAchieved { + msg = "Quorum Achieved!" + } + utils.Logger().Info(). + Str("phase", p.String()). + Str("total-power-of-signers", tallyQuorum.tally.String()). + Msg(msg) } - utils.Logger().Info(). - Str("phase", p.String()). - Str("total-power-of-signers", tallyQuorum.tally.String()). - Msg(msg) return ballet, nil } @@ -262,12 +265,10 @@ func (v *stakedVoteWeight) AmIMemberOfCommitee() bool { return false } identity, _ := pubKeyFunc() - for _, key := range identity.PublicKey { - if w := (shard.BLSPublicKey{}); w.FromLibBLSPublicKey(key) != nil { - _, ok := v.roster.Voters[w] - if ok { - return true - } + for _, key := range identity { + _, ok := v.roster.Voters[key.Bytes] + if ok { + return true } } return false diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index 8c0fafbd6..202a29cd2 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -67,11 +67,10 @@ func (p Policy) String() string { // ParticipantTracker .. type ParticipantTracker interface { - Participants() []*bls.PublicKey - ParticipantsKeyBytes() []shard.BLSPublicKey + Participants() multibls.PublicKeys IndexOf(shard.BLSPublicKey) int ParticipantsCount() int64 - NextAfter(*bls.PublicKey) (bool, *bls.PublicKey) + NextAfter(*shard.BLSPublicKeyWrapper) (bool, *shard.BLSPublicKeyWrapper) UpdateParticipants(pubKeys []*bls.PublicKey) } @@ -100,12 +99,12 @@ type SignatureReader interface { // DependencyInjectionWriter .. type DependencyInjectionWriter interface { - SetMyPublicKeyProvider(func() (*multibls.PublicKey, error)) + SetMyPublicKeyProvider(func() (multibls.PublicKeys, error)) } // DependencyInjectionReader .. type DependencyInjectionReader interface { - MyPublicKey() func() (*multibls.PublicKey, error) + MyPublicKey() func() (multibls.PublicKeys, error) } // Decider .. @@ -151,18 +150,17 @@ type Transition struct { // and values are BLS private key signed signatures type cIdentities struct { // Public keys of the committee including leader and validators - publicKeys []*bls.PublicKey - publicKeysByte []shard.BLSPublicKey - keyIndexMap map[shard.BLSPublicKey]int - prepare *votepower.Round - commit *votepower.Round + publicKeys []shard.BLSPublicKeyWrapper + keyIndexMap map[shard.BLSPublicKey]int + prepare *votepower.Round + commit *votepower.Round // viewIDSigs: every validator // sign on |viewID|blockHash| in view changing message viewChange *votepower.Round } type depInject struct { - publicKeyProvider func() (*multibls.PublicKey, error) + publicKeyProvider func() (multibls.PublicKeys, error) } func (s *cIdentities) AggregateVotes(p Phase) *bls.Sign { @@ -187,39 +185,32 @@ func (s *cIdentities) IndexOf(pubKey shard.BLSPublicKey) int { return -1 } -func (s *cIdentities) NextAfter(pubKey *bls.PublicKey) (bool, *bls.PublicKey) { +func (s *cIdentities) NextAfter(pubKey *shard.BLSPublicKeyWrapper) (bool, *shard.BLSPublicKeyWrapper) { found := false - pubKeyByte := shard.BLSPublicKey{} - pubKeyByte.FromLibBLSPublicKey(pubKey) - idx := s.IndexOf(pubKeyByte) + idx := s.IndexOf(pubKey.Bytes) if idx != -1 { found = true } idx = (idx + 1) % int(s.ParticipantsCount()) - return found, s.publicKeys[idx] + return found, &s.publicKeys[idx] } -func (s *cIdentities) Participants() []*bls.PublicKey { +func (s *cIdentities) Participants() multibls.PublicKeys { return s.publicKeys } -func (s *cIdentities) ParticipantsKeyBytes() []shard.BLSPublicKey { - return s.publicKeysByte -} - func (s *cIdentities) UpdateParticipants(pubKeys []*bls.PublicKey) { - keyBytes := []shard.BLSPublicKey{} + keys := make([]shard.BLSPublicKeyWrapper, len(pubKeys)) keyIndexMap := map[shard.BLSPublicKey]int{} for i := range pubKeys { - k := shard.BLSPublicKey{} - k.FromLibBLSPublicKey(pubKeys[i]) + kBytes := shard.BLSPublicKey{} + kBytes.FromLibBLSPublicKey(pubKeys[i]) - keyBytes = append(keyBytes, k) - keyIndexMap[k] = i + keys[i] = shard.BLSPublicKeyWrapper{Object: pubKeys[i], Bytes: kBytes} + keyIndexMap[kBytes] = i } - s.publicKeys = append(pubKeys[:0:0], pubKeys...) - s.publicKeysByte = keyBytes + s.publicKeys = keys s.keyIndexMap = keyIndexMap } @@ -325,12 +316,11 @@ func (s *cIdentities) ReadAllBallots(p Phase) []*votepower.Ballot { func newBallotsBackedSignatureReader() *cIdentities { return &cIdentities{ - publicKeys: []*bls.PublicKey{}, - publicKeysByte: []shard.BLSPublicKey{}, - keyIndexMap: map[shard.BLSPublicKey]int{}, - prepare: votepower.NewRound(), - commit: votepower.NewRound(), - viewChange: votepower.NewRound(), + publicKeys: []shard.BLSPublicKeyWrapper{}, + keyIndexMap: map[shard.BLSPublicKey]int{}, + prepare: votepower.NewRound(), + commit: votepower.NewRound(), + viewChange: votepower.NewRound(), } } @@ -340,11 +330,11 @@ type composite struct { SignatureReader } -func (d *depInject) SetMyPublicKeyProvider(p func() (*multibls.PublicKey, error)) { +func (d *depInject) SetMyPublicKeyProvider(p func() (multibls.PublicKeys, error)) { d.publicKeyProvider = p } -func (d *depInject) MyPublicKey() func() (*multibls.PublicKey, error) { +func (d *depInject) MyPublicKey() func() (multibls.PublicKeys, error) { return d.publicKeyProvider } diff --git a/consensus/threshold.go b/consensus/threshold.go index 2ff652072..ea6933cc9 100644 --- a/consensus/threshold.go +++ b/consensus/threshold.go @@ -21,7 +21,7 @@ func (consensus *Consensus) didReachPrepareQuorum() error { } // Construct and broadcast prepared message networkMessage, err := consensus.construct( - msg_pb.MessageType_PREPARED, nil, consensus.LeaderPubKey, leaderPriKey, + msg_pb.MessageType_PREPARED, nil, consensus.LeaderPubKey.Bytes, leaderPriKey, ) if err != nil { consensus.getLogger().Err(err). @@ -50,15 +50,15 @@ func (consensus *Consensus) didReachPrepareQuorum() error { // so by this point, everyone has committed to the blockhash of this block // in prepare and so this is the actual block. - for i, key := range consensus.PubKey.PublicKey { - if err := consensus.commitBitmap.SetKey(key, true); err != nil { + for i, key := range consensus.PubKey { + if err := consensus.commitBitmap.SetKey(key.Object, true); err != nil { consensus.getLogger().Warn().Msgf("[OnPrepare] Leader commit bitmap set failed for key at index %d", i) continue } if _, err := consensus.Decider.AddNewVote( quorum.Commit, - consensus.PubKey.PublicKeyBytes[i], + key.Bytes, consensus.priKey.PrivateKey[i].SignHash(commitPayload), blockObj.Hash(), blockObj.NumberU64(), diff --git a/consensus/validator.go b/consensus/validator.go index e2e1fdb74..a793a84be 100644 --- a/consensus/validator.go +++ b/consensus/validator.go @@ -59,11 +59,11 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) { func (consensus *Consensus) prepare() { groupID := []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))} - for i, key := range consensus.PubKey.PublicKey { - if !consensus.IsValidatorInCommittee(key) { + for i, key := range consensus.PubKey { + if !consensus.IsValidatorInCommittee(key.Bytes) { continue } - networkMessage, err := consensus.construct(msg_pb.MessageType_PREPARE, nil, key, consensus.priKey.PrivateKey[i]) + networkMessage, err := consensus.construct(msg_pb.MessageType_PREPARE, nil, key.Bytes, consensus.priKey.PrivateKey[i]) if err != nil { consensus.getLogger().Err(err). Str("message-type", msg_pb.MessageType_PREPARE.String()). @@ -210,15 +210,15 @@ func (consensus *Consensus) onPrepared(msg *msg_pb.Message) { groupID := []nodeconfig.GroupID{ nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)), } - for i, key := range consensus.PubKey.PublicKey { - if !consensus.IsValidatorInCommittee(key) { + for i, key := range consensus.PubKey { + if !consensus.IsValidatorInCommittee(key.Bytes) { continue } networkMessage, _ := consensus.construct( msg_pb.MessageType_COMMIT, commitPayload, - key, consensus.priKey.PrivateKey[i], + key.Bytes, consensus.priKey.PrivateKey[i], ) if consensus.current.Mode() != Listening { diff --git a/consensus/view_change.go b/consensus/view_change.go index 8338bfb7f..40cb95b0a 100644 --- a/consensus/view_change.go +++ b/consensus/view_change.go @@ -7,6 +7,8 @@ import ( "sync" "time" + "github.com/harmony-one/harmony/shard" + "github.com/ethereum/go-ethereum/rlp" "github.com/harmony-one/harmony/core/types" @@ -82,11 +84,11 @@ func (consensus *Consensus) switchPhase(desired FBFTPhase, override bool) { } // GetNextLeaderKey uniquely determine who is the leader for given viewID -func (consensus *Consensus) GetNextLeaderKey() *bls.PublicKey { +func (consensus *Consensus) GetNextLeaderKey() *shard.BLSPublicKeyWrapper { wasFound, next := consensus.Decider.NextAfter(consensus.LeaderPubKey) if !wasFound { consensus.getLogger().Warn(). - Str("key", consensus.LeaderPubKey.SerializeToHexStr()). + Str("key", consensus.LeaderPubKey.Bytes.Hex()). Msg("GetNextLeaderKey: currentLeaderKey not found") } return next @@ -132,14 +134,14 @@ func (consensus *Consensus) startViewChange(viewID uint64) { consensus.getLogger().Info(). Uint64("ViewChangingID", viewID). Dur("timeoutDuration", duration). - Str("NextLeader", consensus.LeaderPubKey.SerializeToHexStr()). + Str("NextLeader", consensus.LeaderPubKey.Bytes.Hex()). Msg("[startViewChange]") - for i, key := range consensus.PubKey.PublicKey { - if !consensus.IsValidatorInCommittee(key) { + for i, key := range consensus.PubKey { + if !consensus.IsValidatorInCommittee(key.Bytes) { continue } - msgToSend := consensus.constructViewChangeMessage(key, consensus.priKey.PrivateKey[i]) + msgToSend := consensus.constructViewChangeMessage(key.Object, consensus.priKey.PrivateKey[i]) consensus.host.SendMessageToGroups([]nodeconfig.GroupID{ nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)), }, @@ -162,7 +164,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { } // if not leader, noop newLeaderKey := recvMsg.LeaderPubkey - newLeaderPriKey, err := consensus.GetLeaderPrivateKey(newLeaderKey) + newLeaderPriKey, err := consensus.GetLeaderPrivateKey(newLeaderKey.Object) if err != nil { return } @@ -171,7 +173,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { consensus.getLogger().Debug(). Int64("have", consensus.Decider.SignersCount(quorum.ViewChange)). Int64("need", consensus.Decider.TwoThirdsSignersCount()). - Str("validatorPubKey", recvMsg.SenderPubkey.SerializeToHexStr()). + Str("validatorPubKey", recvMsg.SenderPubkey.Bytes.Hex()). Msg("[onViewChange] Received Enough View Change Messages") return } @@ -190,8 +192,8 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { // TODO: remove NIL type message // add self m1 or m2 type message signature and bitmap - _, ok1 := consensus.nilSigs[recvMsg.ViewID][newLeaderKey.SerializeToHexStr()] - _, ok2 := consensus.bhpSigs[recvMsg.ViewID][newLeaderKey.SerializeToHexStr()] + _, ok1 := consensus.nilSigs[recvMsg.ViewID][newLeaderKey.Bytes.Hex()] + _, ok2 := consensus.bhpSigs[recvMsg.ViewID][newLeaderKey.Bytes.Hex()] if !(ok1 || ok2) { // add own signature for newview message preparedMsgs := consensus.FBFTLog.GetMessagesByTypeSeq( @@ -213,13 +215,13 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { if hasBlock { consensus.getLogger().Debug().Msg("[onViewChange] add my M1 type messaage") msgToSign := append(preparedMsg.BlockHash[:], preparedMsg.Payload...) - for i, key := range consensus.PubKey.PublicKey { - if err := consensus.bhpBitmap[recvMsg.ViewID].SetKey(key, true); err != nil { + for i, key := range consensus.PubKey { + if err := consensus.bhpBitmap[recvMsg.ViewID].SetKey(key.Object, true); err != nil { consensus.getLogger().Warn().Msgf("[onViewChange] bhpBitmap setkey failed for key at index %d", i) continue } priKey := consensus.priKey.PrivateKey[i] - consensus.bhpSigs[recvMsg.ViewID][key.SerializeToHexStr()] = priKey.SignHash(msgToSign) + consensus.bhpSigs[recvMsg.ViewID][key.Bytes.Hex()] = priKey.SignHash(msgToSign) } // if m1Payload is empty, we just add one if len(consensus.m1Payload) == 0 { @@ -227,28 +229,28 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { } } else { consensus.getLogger().Debug().Msg("[onViewChange] add my M2(NIL) type messaage") - for i, key := range consensus.PubKey.PublicKey { - if err := consensus.nilBitmap[recvMsg.ViewID].SetKey(key, true); err != nil { + for i, key := range consensus.PubKey { + if err := consensus.nilBitmap[recvMsg.ViewID].SetKey(key.Object, true); err != nil { consensus.getLogger().Warn().Msgf("[onViewChange] nilBitmap setkey failed for key at index %d", i) continue } priKey := consensus.priKey.PrivateKey[i] - consensus.nilSigs[recvMsg.ViewID][key.SerializeToHexStr()] = priKey.SignHash(NIL) + consensus.nilSigs[recvMsg.ViewID][key.Bytes.Hex()] = priKey.SignHash(NIL) } } } // add self m3 type message signature and bitmap - _, ok3 := consensus.viewIDSigs[recvMsg.ViewID][newLeaderKey.SerializeToHexStr()] + _, ok3 := consensus.viewIDSigs[recvMsg.ViewID][newLeaderKey.Bytes.Hex()] if !ok3 { viewIDBytes := make([]byte, 8) binary.LittleEndian.PutUint64(viewIDBytes, recvMsg.ViewID) - for i, key := range consensus.PubKey.PublicKey { - if err := consensus.viewIDBitmap[recvMsg.ViewID].SetKey(key, true); err != nil { + for i, key := range consensus.PubKey { + if err := consensus.viewIDBitmap[recvMsg.ViewID].SetKey(key.Object, true); err != nil { consensus.getLogger().Warn().Msgf("[onViewChange] viewIDBitmap setkey failed for key at index %d", i) continue } priKey := consensus.priKey.PrivateKey[i] - consensus.viewIDSigs[recvMsg.ViewID][key.SerializeToHexStr()] = priKey.SignHash(viewIDBytes) + consensus.viewIDSigs[recvMsg.ViewID][key.Bytes.Hex()] = priKey.SignHash(viewIDBytes) } } @@ -267,37 +269,37 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { // m2 type message if !hasBlock { - _, ok := consensus.nilSigs[recvMsg.ViewID][senderKey.SerializeToHexStr()] + _, ok := consensus.nilSigs[recvMsg.ViewID][senderKey.Bytes.Hex()] if ok { consensus.getLogger().Debug(). - Str("validatorPubKey", senderKey.SerializeToHexStr()). + Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Already Received M2 message from validator") return } - if !recvMsg.ViewchangeSig.VerifyHash(senderKey, NIL) { + if !recvMsg.ViewchangeSig.VerifyHash(senderKey.Object, NIL) { consensus.getLogger().Warn().Msg("[onViewChange] Failed To Verify Signature For M2 Type Viewchange Message") return } consensus.getLogger().Debug(). - Str("validatorPubKey", senderKey.SerializeToHexStr()). + Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Add M2 (NIL) type message") - consensus.nilSigs[recvMsg.ViewID][senderKey.SerializeToHexStr()] = recvMsg.ViewchangeSig - consensus.nilBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey, true) // Set the bitmap indicating that this validator signed. + consensus.nilSigs[recvMsg.ViewID][senderKey.Bytes.Hex()] = recvMsg.ViewchangeSig + consensus.nilBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Object, true) // Set the bitmap indicating that this validator signed. } else { // m1 type message if consensus.BlockVerifier(preparedBlock); err != nil { consensus.getLogger().Error().Err(err).Msg("[onViewChange] Prepared block verification failed") return } - _, ok := consensus.bhpSigs[recvMsg.ViewID][senderKey.SerializeToHexStr()] + _, ok := consensus.bhpSigs[recvMsg.ViewID][senderKey.Bytes.Hex()] if ok { consensus.getLogger().Debug(). - Str("validatorPubKey", senderKey.SerializeToHexStr()). + Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Already Received M1 Message From the Validator") return } - if !recvMsg.ViewchangeSig.VerifyHash(recvMsg.SenderPubkey, recvMsg.Payload) { + if !recvMsg.ViewchangeSig.VerifyHash(recvMsg.SenderPubkey.Object, recvMsg.Payload) { consensus.getLogger().Warn().Msg("[onViewChange] Failed to Verify Signature for M1 Type Viewchange Message") return } @@ -345,7 +347,6 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { preparedMsg.Payload = make([]byte, len(recvMsg.Payload)-32) copy(preparedMsg.Payload[:], recvMsg.Payload[32:]) preparedMsg.SenderPubkey = newLeaderKey - copy(preparedMsg.SenderPubkeyBytes[:], newLeaderKey.Serialize()) consensus.getLogger().Info().Msg("[onViewChange] New Leader Prepared Message Added") consensus.FBFTLog.AddMessage(&preparedMsg) @@ -353,34 +354,34 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { } } consensus.getLogger().Debug(). - Str("validatorPubKey", senderKey.SerializeToHexStr()). + Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Add M1 (prepared) type message") - consensus.bhpSigs[recvMsg.ViewID][senderKey.SerializeToHexStr()] = recvMsg.ViewchangeSig - consensus.bhpBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey, true) // Set the bitmap indicating that this validator signed. + consensus.bhpSigs[recvMsg.ViewID][senderKey.Bytes.Hex()] = recvMsg.ViewchangeSig + consensus.bhpBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Object, true) // Set the bitmap indicating that this validator signed. } // check and add viewID (m3 type) message signature - if _, ok := consensus.viewIDSigs[recvMsg.ViewID][senderKey.SerializeToHexStr()]; ok { + if _, ok := consensus.viewIDSigs[recvMsg.ViewID][senderKey.Bytes.Hex()]; ok { consensus.getLogger().Debug(). - Str("validatorPubKey", senderKey.SerializeToHexStr()). + Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Already Received M3(ViewID) message from the validator") return } viewIDHash := make([]byte, 8) binary.LittleEndian.PutUint64(viewIDHash, recvMsg.ViewID) - if !recvMsg.ViewidSig.VerifyHash(recvMsg.SenderPubkey, viewIDHash) { + if !recvMsg.ViewidSig.VerifyHash(recvMsg.SenderPubkey.Object, viewIDHash) { consensus.getLogger().Warn(). Uint64("MsgViewID", recvMsg.ViewID). Msg("[onViewChange] Failed to Verify M3 Message Signature") return } consensus.getLogger().Debug(). - Str("validatorPubKey", senderKey.SerializeToHexStr()). + Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Add M3 (ViewID) type message") - consensus.viewIDSigs[recvMsg.ViewID][senderKey.SerializeToHexStr()] = recvMsg.ViewidSig + consensus.viewIDSigs[recvMsg.ViewID][senderKey.Bytes.Hex()] = recvMsg.ViewidSig // Set the bitmap indicating that this validator signed. - consensus.viewIDBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey, true) + consensus.viewIDBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Object, true) consensus.getLogger().Debug(). Int("have", len(consensus.viewIDSigs[recvMsg.ViewID])). Int64("total", consensus.Decider.ParticipantsCount()). @@ -423,8 +424,8 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { } commitPayload := signature.ConstructCommitPayload(consensus.ChainReader, block.Epoch(), block.Hash(), block.NumberU64(), block.Header().ViewID().Uint64()) - for i, key := range consensus.PubKey.PublicKey { - if err := consensus.commitBitmap.SetKey(key, true); err != nil { + for i, key := range consensus.PubKey { + if err := consensus.commitBitmap.SetKey(key.Object, true); err != nil { consensus.getLogger().Warn(). Msgf("[OnViewChange] New Leader commit bitmap set failed for key at index %d", i) continue @@ -433,7 +434,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { priKey := consensus.priKey.PrivateKey[i] if _, err := consensus.Decider.SubmitVote( quorum.Commit, - consensus.PubKey.PublicKeyBytes[i], + consensus.PubKey[i].Bytes, priKey.SignHash(commitPayload), common.BytesToHash(consensus.blockHash[:]), block.NumberU64(), @@ -448,7 +449,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { consensus.current.SetViewID(recvMsg.ViewID) msgToSend := consensus.constructNewViewMessage( - recvMsg.ViewID, newLeaderKey, newLeaderPriKey, + recvMsg.ViewID, newLeaderKey.Bytes, newLeaderPriKey, ) consensus.getLogger().Warn(). @@ -474,7 +475,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { Uint64("viewChangingID", consensus.current.ViewID()). Msg("[onViewChange] New Leader Start Consensus Timer and Stop View Change Timer") consensus.getLogger().Debug(). - Str("myKey", newLeaderKey.SerializeToHexStr()). + Str("myKey", newLeaderKey.Bytes.Hex()). Uint64("viewID", consensus.viewID). Uint64("block", consensus.blockNum). Msg("[onViewChange] I am the New Leader") @@ -598,7 +599,6 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) { preparedMsg.Payload = make([]byte, len(recvMsg.Payload)-32) copy(preparedMsg.Payload[:], recvMsg.Payload[32:]) preparedMsg.SenderPubkey = senderKey - preparedMsg.SenderPubkeyBytes = recvMsg.SenderPubkeyBytes consensus.FBFTLog.AddMessage(&preparedMsg) if hasBlock { @@ -615,7 +615,7 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) { // change view and leaderKey to keep in sync with network if consensus.blockNum != recvMsg.BlockNum { consensus.getLogger().Debug(). - Str("newLeaderKey", consensus.LeaderPubKey.SerializeToHexStr()). + Str("newLeaderKey", consensus.LeaderPubKey.Bytes.Hex()). Uint64("MsgBlockNum", recvMsg.BlockNum). Msg("[onNewView] New Leader Changed") return @@ -628,14 +628,14 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) { preparedBlock.Epoch(), preparedBlock.Hash(), preparedBlock.NumberU64(), preparedBlock.Header().ViewID().Uint64()) groupID := []nodeconfig.GroupID{ nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))} - for i, key := range consensus.PubKey.PublicKey { - if !consensus.IsValidatorInCommittee(key) { + for i, key := range consensus.PubKey { + if !consensus.IsValidatorInCommittee(key.Bytes) { continue } network, err := consensus.construct( msg_pb.MessageType_COMMIT, commitPayload, - key, consensus.priKey.PrivateKey[i], + key.Bytes, consensus.priKey.PrivateKey[i], ) if err != nil { consensus.getLogger().Err(err).Msg("could not create commit message") @@ -658,7 +658,7 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) { consensus.getLogger().Info().Msg("onNewView === announce") } consensus.getLogger().Debug(). - Str("newLeaderKey", consensus.LeaderPubKey.SerializeToHexStr()). + Str("newLeaderKey", consensus.LeaderPubKey.Bytes.Hex()). Msg("new leader changed") consensus.getLogger().Debug(). Msg("validator start consensus timer and stop view change timer") diff --git a/hmy/api_backend.go b/hmy/api_backend.go index 799209db1..24c000d34 100644 --- a/hmy/api_backend.go +++ b/hmy/api_backend.go @@ -836,8 +836,8 @@ func (b *APIBackend) GetNodeMetadata() commonRPC.NodeMetadata { blsKeys := []string{} if cfg.ConsensusPubKey != nil { - for _, key := range cfg.ConsensusPubKey.PublicKey { - blsKeys = append(blsKeys, key.SerializeToHexStr()) + for _, key := range cfg.ConsensusPubKey { + blsKeys = append(blsKeys, key.Bytes.Hex()) } } c := commonRPC.C{} diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 69283e12a..8353a6c46 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -209,7 +209,7 @@ func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header) d := quorum.NewDecider( quorum.SuperMajorityStake, subComm.ShardID, ) - d.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) { + d.SetMyPublicKeyProvider(func() (multibls.PublicKeys, error) { return nil, nil }) @@ -524,7 +524,7 @@ func (e *engineImpl) VerifyHeaderWithSignature(chain engine.ChainReader, header } // TODO(audit): reuse a singleton decider and not recreate it for every single block d := quorum.NewDecider(quorum.SuperMajorityStake, subComm.ShardID) - d.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) { + d.SetMyPublicKeyProvider(func() (multibls.PublicKeys, error) { return nil, nil }) diff --git a/internal/configs/node/config.go b/internal/configs/node/config.go index 7c5fd83a3..547f362e8 100644 --- a/internal/configs/node/config.go +++ b/internal/configs/node/config.go @@ -77,7 +77,7 @@ type ConfigType struct { StringRole string P2PPriKey p2p_crypto.PrivKey ConsensusPriKey *multibls.PrivateKey - ConsensusPubKey *multibls.PublicKey + ConsensusPubKey multibls.PublicKeys // Database directory DBDir string networkType NetworkType @@ -268,15 +268,15 @@ func (conf *ConfigType) ShardIDFromKey(key *bls.PublicKey) (uint32, error) { // ShardIDFromConsensusKey returns the shard ID statically determined from the // consensus key. func (conf *ConfigType) ShardIDFromConsensusKey() (uint32, error) { - return conf.ShardIDFromKey(conf.ConsensusPubKey.PublicKey[0]) + return conf.ShardIDFromKey(conf.ConsensusPubKey[0].Object) } // ValidateConsensusKeysForSameShard checks if all consensus public keys belong to the same shard -func (conf *ConfigType) ValidateConsensusKeysForSameShard(pubkeys []*bls.PublicKey, sID uint32) error { +func (conf *ConfigType) ValidateConsensusKeysForSameShard(pubkeys multibls.PublicKeys, sID uint32) error { keyShardStrs := []string{} isSameShard := true for _, key := range pubkeys { - shardID, err := conf.ShardIDFromKey(key) + shardID, err := conf.ShardIDFromKey(key.Object) if err != nil { return err } @@ -285,7 +285,7 @@ func (conf *ConfigType) ValidateConsensusKeysForSameShard(pubkeys []*bls.PublicK } keyShardStrs = append( keyShardStrs, - fmt.Sprintf("key: %s, shard id: %d", key.SerializeToHexStr(), shardID), + fmt.Sprintf("key: %s, shard id: %d", key.Bytes.Hex(), shardID), ) } if !isSameShard { diff --git a/internal/configs/node/config_test.go b/internal/configs/node/config_test.go index 4c9d95407..537e7d8f9 100644 --- a/internal/configs/node/config_test.go +++ b/internal/configs/node/config_test.go @@ -3,7 +3,9 @@ package nodeconfig import ( "testing" - "github.com/harmony-one/bls/ffi/go/bls" + "github.com/harmony-one/harmony/multibls" + "github.com/harmony-one/harmony/shard" + "github.com/harmony-one/harmony/internal/blsgen" shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding" "github.com/pkg/errors" @@ -69,9 +71,13 @@ func TestValidateConsensusKeysForSameShard(t *testing.T) { if err != nil { t.Error(err) } - keys := []*bls.PublicKey{} - keys = append(keys, pubKey1) - keys = append(keys, pubKey2) + keys := multibls.PublicKeys{} + dummyKey := shard.BLSPublicKey{} + dummyKey.FromLibBLSPublicKey(pubKey1) + keys = append(keys, shard.BLSPublicKeyWrapper{Object: pubKey1, Bytes: dummyKey}) + dummyKey = shard.BLSPublicKey{} + dummyKey.FromLibBLSPublicKey(pubKey2) + keys = append(keys, shard.BLSPublicKeyWrapper{Object: pubKey2, Bytes: dummyKey}) if err := GetDefaultConfig().ValidateConsensusKeysForSameShard(keys, 0); err != nil { t.Error("expected", nil, "got", err) } @@ -82,7 +88,9 @@ func TestValidateConsensusKeysForSameShard(t *testing.T) { if err != nil { t.Error(err) } - keys = append(keys, pubKey3) + dummyKey = shard.BLSPublicKey{} + dummyKey.FromLibBLSPublicKey(pubKey3) + keys = append(keys, shard.BLSPublicKeyWrapper{Object: pubKey3, Bytes: dummyKey}) if err := GetDefaultConfig().ValidateConsensusKeysForSameShard(keys, 0); err == nil { e := errors.New("bls keys do not belong to the same shard") t.Error("expected", e, "got", nil) diff --git a/multibls/multibls.go b/multibls/multibls.go index 77afbaa62..693ed8d3a 100644 --- a/multibls/multibls.go +++ b/multibls/multibls.go @@ -13,28 +13,25 @@ type PrivateKey struct { PrivateKey []*bls.SecretKey } -// PublicKey stores the bls public keys that belongs to the node -type PublicKey struct { - PublicKey []*bls.PublicKey - PublicKeyBytes []shard.BLSPublicKey -} +// PublicKeys stores the bls public keys that belongs to the node +type PublicKeys []shard.BLSPublicKeyWrapper // SerializeToHexStr wrapper -func (multiKey *PublicKey) SerializeToHexStr() string { +func (multiKey PublicKeys) SerializeToHexStr() string { if multiKey == nil { return "" } var builder strings.Builder - for _, pubKey := range multiKey.PublicKey { - builder.WriteString(pubKey.SerializeToHexStr() + ";") + for _, pubKey := range multiKey { + builder.WriteString(pubKey.Bytes.Hex() + ";") } return builder.String() } // Contains wrapper -func (multiKey PublicKey) Contains(pubKey *bls.PublicKey) bool { - for _, key := range multiKey.PublicKey { - if key.IsEqual(pubKey) { +func (multiKey PublicKeys) Contains(pubKey *bls.PublicKey) bool { + for _, key := range multiKey { + if key.Object.IsEqual(pubKey) { return true } } @@ -42,15 +39,15 @@ func (multiKey PublicKey) Contains(pubKey *bls.PublicKey) bool { } // GetPublicKey wrapper -func (multiKey PrivateKey) GetPublicKey() *PublicKey { - pubKeys := make([]*bls.PublicKey, len(multiKey.PrivateKey)) - pubKeysBytes := make([]shard.BLSPublicKey, len(multiKey.PrivateKey)) +func (multiKey PrivateKey) GetPublicKey() PublicKeys { + pubKeys := make([]shard.BLSPublicKeyWrapper, len(multiKey.PrivateKey)) for i, key := range multiKey.PrivateKey { - pubKeys[i] = key.GetPublicKey() - pubKeysBytes[i].FromLibBLSPublicKey(pubKeys[i]) + wrapper := shard.BLSPublicKeyWrapper{Object: key.GetPublicKey()} + wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object) + pubKeys[i] = wrapper } - return &PublicKey{PublicKey: pubKeys, PublicKeyBytes: pubKeysBytes} + return pubKeys } // GetPrivateKey creates a multibls PrivateKey using bls.SecretKey @@ -58,18 +55,11 @@ func GetPrivateKey(key *bls.SecretKey) *PrivateKey { return &PrivateKey{PrivateKey: []*bls.SecretKey{key}} } -// GetPublicKey creates a multibls PublicKey using bls.PublicKey -func GetPublicKey(key *bls.PublicKey) *PublicKey { - return &PublicKey{PublicKey: []*bls.PublicKey{key}} -} - -// AppendPubKey appends a PublicKey to multibls PublicKey -func AppendPubKey(multiKey *PublicKey, key *bls.PublicKey) { - if multiKey != nil { - multiKey.PublicKey = append(multiKey.PublicKey, key) - } else { - multiKey = &PublicKey{PublicKey: []*bls.PublicKey{key}} - } +// GetPublicKey creates a multibls PublicKeys using bls.PublicKeys +func GetPublicKey(key *bls.PublicKey) PublicKeys { + keyBytes := shard.BLSPublicKey{} + keyBytes.FromLibBLSPublicKey(key) + return PublicKeys{shard.BLSPublicKeyWrapper{Object: key, Bytes: keyBytes}} } // AppendPriKey appends a SecretKey to multibls PrivateKey diff --git a/node/node.go b/node/node.go index bed430d3e..29c999ed1 100644 --- a/node/node.go +++ b/node/node.go @@ -683,9 +683,9 @@ func (node *Node) populateSelfAddresses(epoch *big.Int) { return } - for _, blskey := range node.Consensus.PubKey.PublicKey { - blsStr := blskey.SerializeToHexStr() - shardkey := shard.FromLibBLSPublicKeyUnsafe(blskey) + for _, blskey := range node.Consensus.PubKey { + blsStr := blskey.Bytes.Hex() + shardkey := shard.FromLibBLSPublicKeyUnsafe(blskey.Object) if shardkey == nil { utils.Logger().Error(). Int64("epoch", epoch.Int64()). diff --git a/node/node_cross_link.go b/node/node_cross_link.go index 55e274117..5f752b563 100644 --- a/node/node_cross_link.go +++ b/node/node_cross_link.go @@ -185,7 +185,7 @@ func (node *Node) lookupDecider( quorum.SuperMajorityStake, committee.ShardID, ) - decider.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) { + decider.SetMyPublicKeyProvider(func() (multibls.PublicKeys, error) { return nil, nil }) diff --git a/node/node_handler.go b/node/node_handler.go index fc161e845..effb7764a 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -6,6 +6,8 @@ import ( "math/rand" "time" + "github.com/harmony-one/bls/ffi/go/bls" + "github.com/ethereum/go-ethereum/rlp" "github.com/harmony-one/harmony/api/proto" proto_node "github.com/harmony-one/harmony/api/proto/node" @@ -397,8 +399,13 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) error { func (node *Node) numSignaturesIncludedInBlock(block *types.Block) uint32 { count := uint32(0) - pubkeys := node.Consensus.Decider.Participants() - mask, err := internal_bls.NewMask(pubkeys, nil) + members := node.Consensus.Decider.Participants() + publicKeys := []*bls.PublicKey{} + for _, key := range members { + publicKeys = append(publicKeys, key.Object) + } + // TODO(audit): do not reconstruct the Mask + mask, err := internal_bls.NewMask(publicKeys, nil) if err != nil { return count } @@ -406,8 +413,8 @@ func (node *Node) numSignaturesIncludedInBlock(block *types.Block) uint32 { if err != nil { return count } - for _, key := range node.Consensus.PubKey.PublicKey { - if ok, err := mask.KeyEnabled(key); err == nil && ok { + for _, key := range node.Consensus.PubKey { + if ok, err := mask.KeyEnabled(key.Object); err == nil && ok { count++ } } diff --git a/node/node_newblock.go b/node/node_newblock.go index 61668822b..fc196968e 100644 --- a/node/node_newblock.go +++ b/node/node_newblock.go @@ -89,14 +89,14 @@ func (node *Node) proposeNewBlock() (*types.Block, error) { // Update worker's current header and // state data in preparation to propose/process new transactions var ( - coinbase = node.GetAddressForBLSKey(node.Consensus.LeaderPubKey, header.Epoch()) + coinbase = node.GetAddressForBLSKey(node.Consensus.LeaderPubKey.Object, header.Epoch()) beneficiary = coinbase err error ) // After staking, all coinbase will be the address of bls pub key if node.Blockchain().Config().IsStaking(header.Epoch()) { - blsPubKeyBytes := node.Consensus.LeaderPubKey.GetAddress() + blsPubKeyBytes := node.Consensus.LeaderPubKey.Object.GetAddress() coinbase.SetBytes(blsPubKeyBytes[:]) } diff --git a/shard/shard_state.go b/shard/shard_state.go index adf47749a..bc5f1dfe4 100644 --- a/shard/shard_state.go +++ b/shard/shard_state.go @@ -37,8 +37,14 @@ type State struct { Shards []Committee `json:"shards"` } -// BLSPublicKey defines the bls public key -// TODO(audit): wrap c bls key object with the raw bytes +// BLSPublicKeyWrapper defines the bls public key in both serialized and +// deserialized form. +type BLSPublicKeyWrapper struct { + Bytes BLSPublicKey + Object *bls.PublicKey +} + +// BLSPublicKey defines the serialized bls public key type BLSPublicKey [PublicKeySizeInBytes]byte // BLSSignature defines the bls signature