multi-bls key support (#2249)

refactoring to multibls package to avoid cyclic dependency and better structure

fixing import issue

fixing more imports

fixing a bug that causes nil pointer for explorer node

fixing a bug in the super majority vote

changing config to have same epoch for cross link and staking

fixing the compilation error

addressing PR comments

leaving todo for assuming order between pub/pri keys pairs

fixing goimports

removing unwanted warning message
pull/2372/head
Ganesha Upadhyaya 5 years ago committed by GitHub
parent b7a8c506eb
commit ae362c24c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 154
      cmd/harmony/main.go
  2. 33
      consensus/consensus.go
  3. 34
      consensus/consensus_service.go
  4. 17
      consensus/consensus_service_test.go
  5. 3
      consensus/consensus_test.go
  6. 22
      consensus/consensus_v2.go
  7. 17
      consensus/consensus_viewchange_msg.go
  8. 14
      consensus/construct.go
  9. 11
      consensus/construct_test.go
  10. 6
      consensus/fbft_log_test.go
  11. 35
      consensus/leader.go
  12. 10
      consensus/quorum/one-node-one-vote.go
  13. 13
      consensus/quorum/one-node-staked-vote.go
  14. 11
      consensus/quorum/quorum.go
  15. 31
      consensus/threshold.go
  16. 84
      consensus/validator.go
  17. 73
      consensus/view_change.go
  18. 5
      internal/chain/engine.go
  19. 9
      internal/configs/node/config.go
  20. 3
      internal/configs/node/config_test.go
  21. 73
      multibls/multibls.go
  22. 4
      node/node.go
  23. 3
      node/node_cross_link.go
  24. 2
      node/node_handler.go
  25. 5
      node/node_handler_test.go
  26. 12
      node/node_metrics.go
  27. 4
      node/node_newblock.go
  28. 7
      node/node_test.go

@ -1,7 +1,6 @@
package main package main
import ( import (
"encoding/hex"
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -10,6 +9,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"path" "path"
"path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@ -32,6 +32,7 @@ import (
"github.com/harmony-one/harmony/internal/memprofiling" "github.com/harmony-one/harmony/internal/memprofiling"
"github.com/harmony-one/harmony/internal/shardchain" "github.com/harmony-one/harmony/internal/shardchain"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/node" "github.com/harmony-one/harmony/node"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
@ -101,6 +102,7 @@ var (
enableMemProfiling = flag.Bool("enableMemProfiling", false, "Enable memsize logging.") enableMemProfiling = flag.Bool("enableMemProfiling", false, "Enable memsize logging.")
enableGC = flag.Bool("enableGC", true, "Enable calling garbage collector manually .") enableGC = flag.Bool("enableGC", true, "Enable calling garbage collector manually .")
blsKeyFile = flag.String("blskey_file", "", "The encrypted file of bls serialized private key by passphrase.") blsKeyFile = flag.String("blskey_file", "", "The encrypted file of bls serialized private key by passphrase.")
blsFolder = flag.String("blsfolder", ".hmy/blskeys", "The folder that stores the bls keys; same blspass is used to decrypt all bls keys; all bls keys mapped to same shard")
blsPass = flag.String("blspass", "", "The file containing passphrase to decrypt the encrypted bls file.") blsPass = flag.String("blspass", "", "The file containing passphrase to decrypt the encrypted bls file.")
blsPassphrase string blsPassphrase string
// Sharding configuration parameters for devnet // Sharding configuration parameters for devnet
@ -114,7 +116,7 @@ var (
// Use a separate log file to log libp2p traces // Use a separate log file to log libp2p traces
logP2P = flag.Bool("log_p2p", false, "log libp2p debug info") logP2P = flag.Bool("log_p2p", false, "log libp2p debug info")
initialAccount = &genesis.DeployAccount{} initialAccounts = []*genesis.DeployAccount{}
// logging verbosity // logging verbosity
verbosity = flag.Int("verbosity", 5, "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 5)") verbosity = flag.Int("verbosity", 5, "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 5)")
// dbDir is the database directory. // dbDir is the database directory.
@ -188,8 +190,12 @@ func passphraseForBls() {
return return
} }
if *blsKeyFile == "" || *blsPass == "" { if *blsKeyFile == "" && *blsFolder == "" {
fmt.Println("Internal nodes need to have pass to decrypt blskey") fmt.Println("blskey_file or blsfolder option must be provided")
os.Exit(101)
}
if *blsPass == "" {
fmt.Println("Internal nodes need to have blspass to decrypt blskey")
os.Exit(101) os.Exit(101)
} }
passphrase, err := utils.GetPassphraseFromSource(*blsPass) passphrase, err := utils.GetPassphraseFromSource(*blsPass)
@ -200,27 +206,41 @@ func passphraseForBls() {
blsPassphrase = passphrase blsPassphrase = passphrase
} }
func findAccountsByPubKeys(config shardingconfig.Instance, pubKeys []*bls.PublicKey) {
for _, key := range pubKeys {
keyStr := key.SerializeToHexStr()
_, account := config.FindAccount(keyStr)
if account != nil {
initialAccounts = append(initialAccounts, account)
}
}
}
func setupLegacyNodeAccount() error { func setupLegacyNodeAccount() error {
genesisShardingConfig := shard.Schedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch)) genesisShardingConfig := shard.Schedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch))
pubKey := setupConsensusKey(nodeconfig.GetDefaultConfig()) multiBlsPubKey := setupConsensusKey(nodeconfig.GetDefaultConfig())
reshardingEpoch := genesisShardingConfig.ReshardingEpoch() reshardingEpoch := genesisShardingConfig.ReshardingEpoch()
if reshardingEpoch != nil && len(reshardingEpoch) > 0 { if reshardingEpoch != nil && len(reshardingEpoch) > 0 {
for _, epoch := range reshardingEpoch { for _, epoch := range reshardingEpoch {
config := shard.Schedule.InstanceForEpoch(epoch) config := shard.Schedule.InstanceForEpoch(epoch)
_, initialAccount = config.FindAccount(pubKey.SerializeToHexStr()) findAccountsByPubKeys(config, multiBlsPubKey.PublicKey)
if initialAccount != nil { if len(initialAccounts) != 0 {
break break
} }
} }
} else { } else {
_, initialAccount = genesisShardingConfig.FindAccount(pubKey.SerializeToHexStr()) findAccountsByPubKeys(genesisShardingConfig, multiBlsPubKey.PublicKey)
}
if len(initialAccounts) == 0 {
fmt.Fprintf(os.Stderr, "ERROR cannot find your BLS key in the genesis/FN tables: %s\n", multiBlsPubKey.SerializeToHexStr())
os.Exit(100)
} }
if initialAccount == nil { for _, account := range initialAccounts {
return errors.Errorf("cannot find key %s in table", pubKey.SerializeToHexStr()) fmt.Printf("My Genesis Account: %v\n", *account)
} }
fmt.Printf("My Genesis Account: %v\n", *initialAccount)
return nil return nil
} }
@ -230,39 +250,82 @@ func setupStakingNodeAccount() error {
if err != nil { if err != nil {
return errors.Wrap(err, "cannot determine shard to join") return errors.Wrap(err, "cannot determine shard to join")
} }
initialAccount = &genesis.DeployAccount{} for _, blsKey := range pubKey.PublicKey {
initialAccount.ShardID = shardID initialAccount := &genesis.DeployAccount{}
initialAccount.BlsPublicKey = pubKey.SerializeToHexStr() initialAccount.ShardID = shardID
initialAccount.Address = "" initialAccount.BlsPublicKey = blsKey.SerializeToHexStr()
initialAccount.Address = ""
initialAccounts = append(initialAccounts, initialAccount)
}
return nil return nil
} }
func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) *bls.PublicKey { func readMultiBlsKeys(consensusMultiBlsPriKey *multibls.PrivateKey, consensusMultiBlsPubKey *multibls.PublicKey) error {
consensusPriKey, err := blsgen.LoadBlsKeyWithPassPhrase(*blsKeyFile, blsPassphrase) multiBlsKeyDir := blsFolder
blsKeyFiles, err := ioutil.ReadDir(*multiBlsKeyDir)
if err != nil { if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ERROR when loading bls key, err :%v\n", err) return err
os.Exit(100)
} }
pubKey := consensusPriKey.GetPublicKey()
// Consensus keys are the BLS12-381 keys used to sign consensus messages for _, blsKeyFile := range blsKeyFiles {
nodeConfig.ConsensusPriKey, nodeConfig.ConsensusPubKey = consensusPriKey, consensusPriKey.GetPublicKey() if filepath.Ext(blsKeyFile.Name()) != ".key" {
if nodeConfig.ConsensusPriKey == nil || nodeConfig.ConsensusPubKey == nil { fmt.Println("BLS key file should have .key file extension, found", blsKeyFile.Name())
fmt.Println("error to get consensus keys.") continue
os.Exit(100) }
blsKeyFilePath := path.Join(*multiBlsKeyDir, blsKeyFile.Name())
consensusPriKey, err := blsgen.LoadBlsKeyWithPassPhrase(blsKeyFilePath, blsPassphrase) // uses the same bls passphrase for multiple bls keys
if err != nil {
return err
}
// TODO: assumes order between public/private key pairs
multibls.AppendPriKey(consensusMultiBlsPriKey, consensusPriKey)
multibls.AppendPubKey(consensusMultiBlsPubKey, consensusPriKey.GetPublicKey())
} }
return pubKey
return nil
}
func setupConsensusKey(nodeConfig *nodeconfig.ConfigType) multibls.PublicKey {
consensusMultiPriKey := &multibls.PrivateKey{}
consensusMultiPubKey := &multibls.PublicKey{}
if *blsKeyFile != "" {
consensusPriKey, err := blsgen.LoadBlsKeyWithPassPhrase(*blsKeyFile, blsPassphrase)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ERROR when loading bls key, err :%v\n", err)
os.Exit(100)
}
multibls.AppendPriKey(consensusMultiPriKey, consensusPriKey)
multibls.AppendPubKey(consensusMultiPubKey, consensusPriKey.GetPublicKey())
} else {
err := readMultiBlsKeys(consensusMultiPriKey, consensusMultiPubKey)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ERROR when loading bls keys, err :%v\n", err)
os.Exit(100)
}
}
// Consensus keys are the BLS12-381 keys used to sign consensus messages
nodeConfig.ConsensusPriKey = consensusMultiPriKey
nodeConfig.ConsensusPubKey = consensusMultiPubKey
return *consensusMultiPubKey
} }
func createGlobalConfig() (*nodeconfig.ConfigType, error) { func createGlobalConfig() (*nodeconfig.ConfigType, error) {
var err error var err error
nodeConfig := nodeconfig.GetShardConfig(initialAccount.ShardID) if len(initialAccounts) == 0 {
initialAccounts = append(initialAccounts, &genesis.DeployAccount{ShardID: uint32(*shardID)})
}
nodeConfig := nodeconfig.GetShardConfig(initialAccounts[0].ShardID)
if *nodeType == "validator" { if *nodeType == "validator" {
// Set up consensus keys. // Set up consensus keys.
setupConsensusKey(nodeConfig) setupConsensusKey(nodeConfig)
} else { } else {
nodeConfig.ConsensusPriKey = &bls.SecretKey{} // set dummy bls key for consensus object // set dummy bls key for consensus object
nodeConfig.ConsensusPriKey = multibls.GetPrivateKey(&bls.SecretKey{})
nodeConfig.ConsensusPubKey = multibls.GetPublicKey(&bls.PublicKey{})
} }
// Set network type // Set network type
@ -279,7 +342,7 @@ func createGlobalConfig() (*nodeconfig.ConfigType, error) {
*keyFile) *keyFile)
} }
selfPeer := p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: nodeConfig.ConsensusPubKey} selfPeer := p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: nodeConfig.ConsensusPubKey.PublicKey[0]}
myHost, err = p2pimpl.NewHost(&selfPeer, nodeConfig.P2pPriKey) myHost, err = p2pimpl.NewHost(&selfPeer, nodeConfig.P2pPriKey)
if err != nil { if err != nil {
@ -317,12 +380,14 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
currentConsensus.Decider.SetShardIDProvider(func() (uint32, error) { currentConsensus.Decider.SetShardIDProvider(func() (uint32, error) {
return currentConsensus.ShardID, nil return currentConsensus.ShardID, nil
}) })
currentConsensus.Decider.SetMyPublicKeyProvider(func() (*bls.PublicKey, error) { currentConsensus.Decider.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) {
return currentConsensus.PubKey, nil return currentConsensus.PubKey, nil
}) })
if initialAccount.Address != "" { // staking validator doesn't have to specify ECDSA address // staking validator doesn't have to specify ECDSA address
currentConsensus.SelfAddress = common.ParseAddr(initialAccount.Address) currentConsensus.SelfAddresses = map[string]ethCommon.Address{}
for _, initialAccount := range initialAccounts {
currentConsensus.SelfAddresses[initialAccount.BlsPublicKey] = common.ParseAddr(initialAccount.Address)
} }
if err != nil { if err != nil {
@ -540,17 +605,20 @@ func main() {
os.Exit(1) os.Exit(1)
} }
} }
fmt.Printf("%s mode; node key %s -> shard %d\n", if *nodeType == "validator" {
map[bool]string{false: "Legacy", true: "Staking"}[*stakingFlag], fmt.Printf("%s mode; node key %s -> shard %d\n",
nodeconfig.GetDefaultConfig().ConsensusPubKey.SerializeToHexStr(), map[bool]string{false: "Legacy", true: "Staking"}[*stakingFlag],
initialAccount.ShardID) nodeconfig.GetDefaultConfig().ConsensusPubKey.SerializeToHexStr(),
initialAccounts[0].ShardID)
}
if *nodeType != "validator" && *shardID >= 0 { if *nodeType != "validator" && *shardID >= 0 {
utils.Logger().Info(). for _, initialAccount := range initialAccounts {
Uint32("original", initialAccount.ShardID). utils.Logger().Info().
Int("override", *shardID). Uint32("original", initialAccount.ShardID).
Msg("ShardID Override") Int("override", *shardID).
initialAccount.ShardID = uint32(*shardID) Msg("ShardID Override")
initialAccount.ShardID = uint32(*shardID)
}
} }
nodeConfig, err := createGlobalConfig() nodeConfig, err := createGlobalConfig()
@ -614,7 +682,7 @@ func main() {
} }
utils.Logger().Info(). utils.Logger().Info().
Str("BlsPubKey", hex.EncodeToString(nodeConfig.ConsensusPubKey.Serialize())). Str("BlsPubKey", nodeConfig.ConsensusPubKey.SerializeToHexStr()).
Uint32("ShardID", nodeConfig.ShardID). Uint32("ShardID", nodeConfig.ShardID).
Str("ShardGroupID", nodeConfig.GetShardGroupID().String()). Str("ShardGroupID", nodeConfig.GetShardGroupID().String()).
Str("BeaconGroupID", nodeConfig.GetBeaconGroupID().String()). Str("BeaconGroupID", nodeConfig.GetBeaconGroupID().String()).

@ -14,8 +14,10 @@ import (
bls_cosi "github.com/harmony-one/harmony/crypto/bls" bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/memprofiling" "github.com/harmony-one/harmony/internal/memprofiling"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/staking/slash" "github.com/harmony-one/harmony/staking/slash"
"github.com/pkg/errors"
) )
const ( const (
@ -23,6 +25,8 @@ const (
vdfAndSeedSize = 548 // size of VDF/Proof and Seed vdfAndSeedSize = 548 // size of VDF/Proof and Seed
) )
var errLeaderPriKeyNotFound = errors.New("getting leader private key from consensus public keys failed")
// Consensus is the main struct with all states and data related to consensus process. // Consensus is the main struct with all states and data related to consensus process.
type Consensus struct { type Consensus struct {
Decider quorum.Decider Decider quorum.Decider
@ -75,9 +79,9 @@ type Consensus struct {
MinPeers int MinPeers int
pubKeyLock sync.Mutex pubKeyLock sync.Mutex
// private/public keys of current node // private/public keys of current node
priKey *bls.SecretKey priKey *multibls.PrivateKey
PubKey *bls.PublicKey PubKey *multibls.PublicKey
SelfAddress common.Address SelfAddresses map[string]common.Address
// the publickey of leader // the publickey of leader
LeaderPubKey *bls.PublicKey LeaderPubKey *bls.PublicKey
viewID uint64 viewID uint64
@ -173,11 +177,26 @@ func (consensus *Consensus) GetBlockReward() *big.Int {
return consensus.lastBlockReward return consensus.lastBlockReward
} }
// 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) {
return consensus.priKey.PrivateKey[i], nil
}
}
return nil, errors.Wrapf(errLeaderPriKeyNotFound, leaderKey.SerializeToHexStr())
}
// GetConsensusLeaderPrivateKey returns consensus leader private key if node is the leader
func (consensus *Consensus) GetConsensusLeaderPrivateKey() (*bls.SecretKey, error) {
return consensus.GetLeaderPrivateKey(consensus.LeaderPubKey)
}
// TODO: put shardId into chain reader's chain config // TODO: put shardId into chain reader's chain config
// New create a new Consensus record // New create a new Consensus record
func New( func New(
host p2p.Host, shard uint32, leader p2p.Peer, blsPriKey *bls.SecretKey, host p2p.Host, shard uint32, leader p2p.Peer, multiBlsPriKey *multibls.PrivateKey,
Decider quorum.Decider, Decider quorum.Decider,
) (*Consensus, error) { ) (*Consensus, error) {
consensus := Consensus{} consensus := Consensus{}
@ -194,9 +213,9 @@ func New(
consensus.consensusTimeout = createTimeout() consensus.consensusTimeout = createTimeout()
consensus.validators.Store(leader.ConsensusPubKey.SerializeToHexStr(), leader) consensus.validators.Store(leader.ConsensusPubKey.SerializeToHexStr(), leader)
if blsPriKey != nil { if multiBlsPriKey != nil {
consensus.priKey = blsPriKey consensus.priKey = multiBlsPriKey
consensus.PubKey = blsPriKey.GetPublicKey() consensus.PubKey = multiBlsPriKey.GetPublicKey()
utils.Logger().Info(). utils.Logger().Info().
Str("publicKey", consensus.PubKey.SerializeToHexStr()).Msg("My Public Key") Str("publicKey", consensus.PubKey.SerializeToHexStr()).Msg("My Public Key")
} else { } else {

@ -20,6 +20,7 @@ import (
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/profiler" "github.com/harmony-one/harmony/internal/profiler"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee" "github.com/harmony-one/harmony/shard/committee"
@ -61,13 +62,11 @@ var (
) )
// Signs the consensus message and returns the marshaled message. // Signs the consensus message and returns the marshaled message.
func (consensus *Consensus) signAndMarshalConsensusMessage( func (consensus *Consensus) signAndMarshalConsensusMessage(message *msg_pb.Message,
message *msg_pb.Message, priKey *bls.SecretKey) ([]byte, error) {
) ([]byte, error) { if err := consensus.signConsensusMessage(message, priKey); err != nil {
if err := consensus.signConsensusMessage(message); err != nil {
return empty, err return empty, err
} }
marshaledMessage, err := protobuf.Marshal(message) marshaledMessage, err := protobuf.Marshal(message)
if err != nil { if err != nil {
return empty, err return empty, err
@ -121,14 +120,15 @@ func NewFaker() *Consensus {
} }
// Sign on the hash of the message // Sign on the hash of the message
func (consensus *Consensus) signMessage(message []byte) []byte { func (consensus *Consensus) signMessage(message []byte, priKey *bls.SecretKey) []byte {
hash := hash.Keccak256(message) hash := hash.Keccak256(message)
signature := consensus.priKey.SignHash(hash[:]) signature := priKey.SignHash(hash[:])
return signature.Serialize() return signature.Serialize()
} }
// Sign on the consensus message signature field. // Sign on the consensus message signature field.
func (consensus *Consensus) signConsensusMessage(message *msg_pb.Message) error { func (consensus *Consensus) signConsensusMessage(message *msg_pb.Message,
priKey *bls.SecretKey) error {
message.Signature = nil message.Signature = nil
// TODO: use custom serialization method rather than protobuf // TODO: use custom serialization method rather than protobuf
marshaledMessage, err := protobuf.Marshal(message) marshaledMessage, err := protobuf.Marshal(message)
@ -136,7 +136,7 @@ func (consensus *Consensus) signConsensusMessage(message *msg_pb.Message) error
return err return err
} }
// 64 byte of signature on previous data // 64 byte of signature on previous data
signature := consensus.signMessage(marshaledMessage) signature := consensus.signMessage(marshaledMessage, priKey)
message.Signature = signature message.Signature = signature
return nil return nil
} }
@ -381,7 +381,7 @@ func (consensus *Consensus) reportMetrics(block types.Block) {
txHashes = append(txHashes, hex.EncodeToString(txHash[:])) txHashes = append(txHashes, hex.EncodeToString(txHash[:]))
} }
metrics := map[string]interface{}{ metrics := map[string]interface{}{
"key": hex.EncodeToString(consensus.PubKey.Serialize()), "key": hex.EncodeToString(consensus.LeaderPubKey.Serialize()),
"tps": tps, "tps": tps,
"txCount": numOfTxs, "txCount": numOfTxs,
"nodeCount": consensus.Decider.ParticipantsCount() + 1, "nodeCount": consensus.Decider.ParticipantsCount() + 1,
@ -480,7 +480,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode {
decider.SetShardIDProvider(func() (uint32, error) { decider.SetShardIDProvider(func() (uint32, error) {
return consensus.ShardID, nil return consensus.ShardID, nil
}) })
decider.SetMyPublicKeyProvider(func() (*bls.PublicKey, error) { decider.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) {
return consensus.PubKey, nil return consensus.PubKey, nil
}) })
consensus.Decider = decider consensus.Decider = decider
@ -577,15 +577,15 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode {
} }
} }
for i := range pubKeys { for _, key := range pubKeys {
// in committee // in committee
if pubKeys[i].IsEqual(consensus.PubKey) { if consensus.PubKey.Contains(key) {
if hasError { if hasError {
return Syncing return Syncing
} }
// If the leader changed and I myself become the leader // If the leader changed and I myself become the leader
if !consensus.LeaderPubKey.IsEqual(oldLeader) && consensus.LeaderPubKey.IsEqual(consensus.PubKey) { if !consensus.LeaderPubKey.IsEqual(oldLeader) && consensus.IsLeader() {
go func() { go func() {
utils.Logger().Debug(). utils.Logger().Debug().
Str("myKey", consensus.PubKey.SerializeToHexStr()). Str("myKey", consensus.PubKey.SerializeToHexStr()).
@ -605,8 +605,10 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode {
// IsLeader check if the node is a leader or not by comparing the public key of // IsLeader check if the node is a leader or not by comparing the public key of
// the node with the leader public key // the node with the leader public key
func (consensus *Consensus) IsLeader() bool { func (consensus *Consensus) IsLeader() bool {
if consensus.PubKey != nil && consensus.LeaderPubKey != nil { for _, key := range consensus.PubKey.PublicKey {
return consensus.PubKey.IsEqual(consensus.LeaderPubKey) if key.IsEqual(consensus.LeaderPubKey) {
return true
}
} }
return false return false
} }

@ -8,6 +8,7 @@ import (
"github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
@ -23,7 +24,7 @@ func TestPopulateMessageFields(t *testing.T) {
blsPriKey := bls.RandPrivateKey() blsPriKey := bls.RandPrivateKey()
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, blsPriKey, decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsPriKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)
@ -37,9 +38,9 @@ func TestPopulateMessageFields(t *testing.T) {
Consensus: &msg_pb.ConsensusRequest{}, Consensus: &msg_pb.ConsensusRequest{},
}, },
} }
consensusMsg := consensus.populateMessageFields(
msg.GetConsensus(), consensus.blockHash[:], consensusMsg := consensus.populateMessageFields(msg.GetConsensus(), consensus.blockHash[:],
) blsPriKey.GetPublicKey())
if consensusMsg.ViewId != 2 { if consensusMsg.ViewId != 2 {
t.Errorf("Consensus ID is not populated correctly") t.Errorf("Consensus ID is not populated correctly")
@ -60,8 +61,9 @@ func TestSignAndMarshalConsensusMessage(t *testing.T) {
t.Fatalf("newhost failure: %v", err) t.Fatalf("newhost failure: %v", err)
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
blsPriKey := bls.RandPrivateKey()
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, bls.RandPrivateKey(), decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsPriKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)
@ -70,7 +72,7 @@ func TestSignAndMarshalConsensusMessage(t *testing.T) {
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
msg := &msg_pb.Message{} msg := &msg_pb.Message{}
marshaledMessage, err := consensus.signAndMarshalConsensusMessage(msg) marshaledMessage, err := consensus.signAndMarshalConsensusMessage(msg, blsPriKey)
if err != nil || len(marshaledMessage) == 0 { if err != nil || len(marshaledMessage) == 0 {
t.Errorf("Failed to sign and marshal the message: %s", err) t.Errorf("Failed to sign and marshal the message: %s", err)
@ -88,8 +90,9 @@ func TestSetViewID(t *testing.T) {
t.Fatalf("newhost failure: %v", err) t.Fatalf("newhost failure: %v", err)
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
blsPriKey := bls.RandPrivateKey()
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, bls.RandPrivateKey(), decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsPriKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)

@ -6,6 +6,7 @@ import (
"github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
@ -20,7 +21,7 @@ func TestNew(test *testing.T) {
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, bls.RandPrivateKey(), decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(bls.RandPrivateKey()), decider,
) )
if err != nil { if err != nil {
test.Fatalf("Cannot craeate consensus: %v", err) test.Fatalf("Cannot craeate consensus: %v", err)

@ -109,8 +109,13 @@ func (consensus *Consensus) finalizeCommits() {
Int64("NumCommits", consensus.Decider.SignersCount(quorum.Commit)). Int64("NumCommits", consensus.Decider.SignersCount(quorum.Commit)).
Msg("[Finalizing] Finalizing Block") Msg("[Finalizing] Finalizing Block")
beforeCatchupNum := consensus.blockNum beforeCatchupNum := consensus.blockNum
leaderPriKey, err := consensus.GetConsensusLeaderPrivateKey()
if err != nil {
consensus.getLogger().Error().Err(err).Msg("[FinalizeCommits] leader not found")
return
}
// Construct committed message // Construct committed message
network, err := consensus.construct(msg_pb.MessageType_COMMITTED, nil) network, err := consensus.construct(msg_pb.MessageType_COMMITTED, nil, leaderPriKey.GetPublicKey(), leaderPriKey)
if err != nil { if err != nil {
consensus.getLogger().Warn().Err(err). consensus.getLogger().Warn().Err(err).
Msg("[FinalizeCommits] Unable to construct Committed message") Msg("[FinalizeCommits] Unable to construct Committed message")
@ -182,7 +187,7 @@ func (consensus *Consensus) finalizeCommits() {
Uint64("epochNum", block.Epoch().Uint64()). Uint64("epochNum", block.Epoch().Uint64()).
Uint64("ViewId", block.Header().ViewID().Uint64()). Uint64("ViewId", block.Header().ViewID().Uint64()).
Str("blockHash", block.Hash().String()). Str("blockHash", block.Hash().String()).
Int("index", consensus.Decider.IndexOf(consensus.PubKey)). Int("index", consensus.Decider.IndexOf(consensus.LeaderPubKey)).
Int("numTxns", len(block.Transactions())). Int("numTxns", len(block.Transactions())).
Int("numStakingTxns", len(block.StakingTransactions())). Int("numStakingTxns", len(block.StakingTransactions())).
Msg("HOORAY!!!!!!! CONSENSUS REACHED!!!!!!!") Msg("HOORAY!!!!!!! CONSENSUS REACHED!!!!!!!")
@ -491,10 +496,15 @@ func (consensus *Consensus) Start(
} }
// GenerateVrfAndProof generates new VRF/Proof from hash of previous block // GenerateVrfAndProof generates new VRF/Proof from hash of previous block
func (consensus *Consensus) GenerateVrfAndProof( func (consensus *Consensus) GenerateVrfAndProof(newBlock *types.Block, vrfBlockNumbers []uint64) []uint64 {
newBlock *types.Block, vrfBlockNumbers []uint64, key, err := consensus.GetConsensusLeaderPrivateKey()
) []uint64 { if err != nil {
sk := vrf_bls.NewVRFSigner(consensus.priKey) consensus.getLogger().Error().
Err(err).
Msg("[GenerateVrfAndProof] VRF generation error")
return vrfBlockNumbers
}
sk := vrf_bls.NewVRFSigner(key)
blockHash := [32]byte{} blockHash := [32]byte{}
previousHeader := consensus.ChainReader.GetHeaderByNumber( previousHeader := consensus.ChainReader.GetHeaderByNumber(
newBlock.NumberU64() - 1, newBlock.NumberU64() - 1,

@ -3,6 +3,7 @@ package consensus
import ( import (
"encoding/binary" "encoding/binary"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/api/proto" "github.com/harmony-one/harmony/api/proto"
msg_pb "github.com/harmony-one/harmony/api/proto/message" msg_pb "github.com/harmony-one/harmony/api/proto/message"
bls_cosi "github.com/harmony-one/harmony/crypto/bls" bls_cosi "github.com/harmony-one/harmony/crypto/bls"
@ -10,7 +11,7 @@ import (
) )
// construct the view change message // construct the view change message
func (consensus *Consensus) constructViewChangeMessage() []byte { func (consensus *Consensus) constructViewChangeMessage(pubKey *bls.PublicKey, priKey *bls.SecretKey) []byte {
message := &msg_pb.Message{ message := &msg_pb.Message{
ServiceType: msg_pb.ServiceType_CONSENSUS, ServiceType: msg_pb.ServiceType_CONSENSUS,
Type: msg_pb.MessageType_VIEWCHANGE, Type: msg_pb.MessageType_VIEWCHANGE,
@ -24,7 +25,7 @@ func (consensus *Consensus) constructViewChangeMessage() []byte {
vcMsg.BlockNum = consensus.blockNum vcMsg.BlockNum = consensus.blockNum
vcMsg.ShardId = consensus.ShardID vcMsg.ShardId = consensus.ShardID
// sender address // sender address
vcMsg.SenderPubkey = consensus.PubKey.Serialize() vcMsg.SenderPubkey = pubKey.Serialize()
// next leader key already updated // next leader key already updated
vcMsg.LeaderPubkey = consensus.LeaderPubKey.Serialize() vcMsg.LeaderPubkey = consensus.LeaderPubKey.Serialize()
@ -49,7 +50,7 @@ func (consensus *Consensus) constructViewChangeMessage() []byte {
Str("pubKey", consensus.PubKey.SerializeToHexStr()). Str("pubKey", consensus.PubKey.SerializeToHexStr()).
Msg("[constructViewChangeMessage]") Msg("[constructViewChangeMessage]")
sign := consensus.priKey.SignHash(msgToSign) sign := priKey.SignHash(msgToSign)
if sign != nil { if sign != nil {
vcMsg.ViewchangeSig = sign.Serialize() vcMsg.ViewchangeSig = sign.Serialize()
} else { } else {
@ -58,14 +59,14 @@ func (consensus *Consensus) constructViewChangeMessage() []byte {
viewIDBytes := make([]byte, 8) viewIDBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(viewIDBytes, consensus.current.ViewID()) binary.LittleEndian.PutUint64(viewIDBytes, consensus.current.ViewID())
sign1 := consensus.priKey.SignHash(viewIDBytes) sign1 := priKey.SignHash(viewIDBytes)
if sign1 != nil { if sign1 != nil {
vcMsg.ViewidSig = sign1.Serialize() vcMsg.ViewidSig = sign1.Serialize()
} else { } else {
utils.Logger().Error().Msg("unable to serialize viewID signature") utils.Logger().Error().Msg("unable to serialize viewID signature")
} }
marshaledMessage, err := consensus.signAndMarshalConsensusMessage(message) marshaledMessage, err := consensus.signAndMarshalConsensusMessage(message, priKey)
if err != nil { if err != nil {
utils.Logger().Error().Err(err). utils.Logger().Error().Err(err).
Msg("[constructViewChangeMessage] failed to sign and marshal the viewchange message") Msg("[constructViewChangeMessage] failed to sign and marshal the viewchange message")
@ -74,7 +75,7 @@ func (consensus *Consensus) constructViewChangeMessage() []byte {
} }
// new leader construct newview message // new leader construct newview message
func (consensus *Consensus) constructNewViewMessage(viewID uint64) []byte { func (consensus *Consensus) constructNewViewMessage(viewID uint64, pubKey *bls.PublicKey, priKey *bls.SecretKey) []byte {
message := &msg_pb.Message{ message := &msg_pb.Message{
ServiceType: msg_pb.ServiceType_CONSENSUS, ServiceType: msg_pb.ServiceType_CONSENSUS,
Type: msg_pb.MessageType_NEWVIEW, Type: msg_pb.MessageType_NEWVIEW,
@ -88,7 +89,7 @@ func (consensus *Consensus) constructNewViewMessage(viewID uint64) []byte {
vcMsg.BlockNum = consensus.blockNum vcMsg.BlockNum = consensus.blockNum
vcMsg.ShardId = consensus.ShardID vcMsg.ShardId = consensus.ShardID
// sender address // sender address
vcMsg.SenderPubkey = consensus.PubKey.Serialize() vcMsg.SenderPubkey = pubKey.Serialize()
vcMsg.Payload = consensus.m1Payload vcMsg.Payload = consensus.m1Payload
sig2arr := consensus.GetNilSigsArray(viewID) sig2arr := consensus.GetNilSigsArray(viewID)
@ -108,7 +109,7 @@ func (consensus *Consensus) constructNewViewMessage(viewID uint64) []byte {
vcMsg.M3Bitmap = consensus.viewIDBitmap[viewID].Bitmap vcMsg.M3Bitmap = consensus.viewIDBitmap[viewID].Bitmap
} }
marshaledMessage, err := consensus.signAndMarshalConsensusMessage(message) marshaledMessage, err := consensus.signAndMarshalConsensusMessage(message, priKey)
if err != nil { if err != nil {
utils.Logger().Error().Err(err). utils.Logger().Error().Err(err).
Msg("[constructNewViewMessage] failed to sign and marshal the new view message") Msg("[constructNewViewMessage] failed to sign and marshal the new view message")

@ -22,7 +22,7 @@ type NetworkMessage struct {
// Populates the common basic fields for all consensus message. // Populates the common basic fields for all consensus message.
func (consensus *Consensus) populateMessageFields( func (consensus *Consensus) populateMessageFields(
request *msg_pb.ConsensusRequest, blockHash []byte, request *msg_pb.ConsensusRequest, blockHash []byte, pubKey *bls.PublicKey,
) *msg_pb.ConsensusRequest { ) *msg_pb.ConsensusRequest {
request.ViewId = consensus.viewID request.ViewId = consensus.viewID
request.BlockNum = consensus.blockNum request.BlockNum = consensus.blockNum
@ -30,13 +30,13 @@ func (consensus *Consensus) populateMessageFields(
// 32 byte block hash // 32 byte block hash
request.BlockHash = blockHash request.BlockHash = blockHash
// sender address // sender address
request.SenderPubkey = consensus.PubKey.Serialize() request.SenderPubkey = pubKey.Serialize()
return request return request
} }
// construct is the single creation point of messages intended for the wire. // construct is the single creation point of messages intended for the wire.
func (consensus *Consensus) construct( func (consensus *Consensus) construct(
p msg_pb.MessageType, payloadForSign []byte, p msg_pb.MessageType, payloadForSign []byte, pubKey *bls.PublicKey, priKey *bls.SecretKey,
) (*NetworkMessage, error) { ) (*NetworkMessage, error) {
message := &msg_pb.Message{ message := &msg_pb.Message{
ServiceType: msg_pb.ServiceType_CONSENSUS, ServiceType: msg_pb.ServiceType_CONSENSUS,
@ -51,7 +51,7 @@ func (consensus *Consensus) construct(
) )
consensusMsg = consensus.populateMessageFields( consensusMsg = consensus.populateMessageFields(
message.GetConsensus(), consensus.blockHash[:], message.GetConsensus(), consensus.blockHash[:], pubKey,
) )
// Do the signing, 96 byte of bls signature // Do the signing, 96 byte of bls signature
@ -67,11 +67,11 @@ func (consensus *Consensus) construct(
buffer.Write(consensus.prepareBitmap.Bitmap) buffer.Write(consensus.prepareBitmap.Bitmap)
consensusMsg.Payload = buffer.Bytes() consensusMsg.Payload = buffer.Bytes()
case msg_pb.MessageType_PREPARE: case msg_pb.MessageType_PREPARE:
if s := consensus.priKey.SignHash(consensusMsg.BlockHash); s != nil { if s := priKey.SignHash(consensusMsg.BlockHash); s != nil {
consensusMsg.Payload = s.Serialize() consensusMsg.Payload = s.Serialize()
} }
case msg_pb.MessageType_COMMIT: case msg_pb.MessageType_COMMIT:
if s := consensus.priKey.SignHash(payloadForSign); s != nil { if s := priKey.SignHash(payloadForSign); s != nil {
consensusMsg.Payload = s.Serialize() consensusMsg.Payload = s.Serialize()
} }
case msg_pb.MessageType_COMMITTED: case msg_pb.MessageType_COMMITTED:
@ -86,7 +86,7 @@ func (consensus *Consensus) construct(
consensusMsg.Payload = consensus.blockHash[:] consensusMsg.Payload = consensus.blockHash[:]
} }
marshaledMessage, err := consensus.signAndMarshalConsensusMessage(message) marshaledMessage, err := consensus.signAndMarshalConsensusMessage(message, priKey)
if err != nil { if err != nil {
utils.Logger().Error().Err(err). utils.Logger().Error().Err(err).
Str("phase", p.String()). Str("phase", p.String()).

@ -9,6 +9,7 @@ import (
"github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
@ -22,14 +23,15 @@ func TestConstructAnnounceMessage(test *testing.T) {
test.Fatalf("newhost failure: %v", err) test.Fatalf("newhost failure: %v", err)
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
blsPriKey := bls.RandPrivateKey()
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, bls.RandPrivateKey(), decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsPriKey), decider,
) )
if err != nil { if err != nil {
test.Fatalf("Cannot create consensus: %v", err) test.Fatalf("Cannot create consensus: %v", err)
} }
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
if _, err = consensus.construct(msg_pb.MessageType_ANNOUNCE, nil); err != nil { if _, err = consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, blsPriKey.GetPublicKey(), blsPriKey); err != nil {
test.Fatalf("could not construct announce: %v", err) test.Fatalf("could not construct announce: %v", err)
} }
} }
@ -47,8 +49,9 @@ func TestConstructPreparedMessage(test *testing.T) {
test.Fatalf("newhost failure: %v", err) test.Fatalf("newhost failure: %v", err)
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
blsPriKey := bls.RandPrivateKey()
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, bls.RandPrivateKey(), decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsPriKey), decider,
) )
if err != nil { if err != nil {
test.Fatalf("Cannot craeate consensus: %v", err) test.Fatalf("Cannot craeate consensus: %v", err)
@ -78,7 +81,7 @@ func TestConstructPreparedMessage(test *testing.T) {
test.Log(ctxerror.New("prepareBitmap.SetKey").WithCause(err)) test.Log(ctxerror.New("prepareBitmap.SetKey").WithCause(err))
} }
network, err := consensus.construct(msg_pb.MessageType_PREPARED, nil) network, err := consensus.construct(msg_pb.MessageType_PREPARED, nil, blsPriKey.GetPublicKey(), blsPriKey)
if err != nil { if err != nil {
test.Errorf("Error when creating prepared message") test.Errorf("Error when creating prepared message")
} }

@ -8,6 +8,7 @@ import (
"github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
@ -21,14 +22,15 @@ func constructAnnounceMessage(t *testing.T) (*NetworkMessage, error) {
t.Fatalf("newhost failure: %v", err) t.Fatalf("newhost failure: %v", err)
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
blsPriKey := bls.RandPrivateKey()
consensus, err := New( consensus, err := New(
host, shard.BeaconChainShardID, leader, bls.RandPrivateKey(), decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsPriKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot create consensus: %v", err) t.Fatalf("Cannot create consensus: %v", err)
} }
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
return consensus.construct(msg_pb.MessageType_ANNOUNCE, nil) return consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, blsPriKey.GetPublicKey(), blsPriKey)
} }
func getConsensusMessage(payload []byte) (*msg_pb.Message, error) { func getConsensusMessage(payload []byte) (*msg_pb.Message, error) {

@ -36,7 +36,13 @@ func (consensus *Consensus) announce(block *types.Block) {
consensus.block = encodedBlock consensus.block = encodedBlock
consensus.blockHeader = encodedBlockHeader consensus.blockHeader = encodedBlockHeader
networkMessage, err := consensus.construct(msg_pb.MessageType_ANNOUNCE, nil)
key, err := consensus.GetConsensusLeaderPrivateKey()
if err != nil {
consensus.getLogger().Warn().Err(err).Msg("[Announce] Node not a leader")
return
}
networkMessage, err := consensus.construct(msg_pb.MessageType_ANNOUNCE, nil, key.GetPublicKey(), key)
if err != nil { if err != nil {
consensus.getLogger().Err(err). consensus.getLogger().Err(err).
Str("message-type", msg_pb.MessageType_ANNOUNCE.String()). Str("message-type", msg_pb.MessageType_ANNOUNCE.String()).
@ -55,21 +61,20 @@ func (consensus *Consensus) announce(block *types.Block) {
consensus.FBFTLog.AddBlock(block) consensus.FBFTLog.AddBlock(block)
// Leader sign the block hash itself // Leader sign the block hash itself
consensus.Decider.SubmitVote( for i, key := range consensus.PubKey.PublicKey {
quorum.Prepare, consensus.Decider.SubmitVote(
consensus.PubKey, quorum.Prepare,
consensus.priKey.SignHash(consensus.blockHash[:]), key,
common.BytesToHash(consensus.blockHash[:]), consensus.priKey.PrivateKey[i].SignHash(consensus.blockHash[:]),
) common.BytesToHash(consensus.blockHash[:]),
if err := consensus.prepareBitmap.SetKey(
consensus.PubKey, true,
); err != nil {
consensus.getLogger().Warn().Err(err).Msg(
"[Announce] Leader prepareBitmap SetKey failed",
) )
return if err := consensus.prepareBitmap.SetKey(key, true); err != nil {
consensus.getLogger().Warn().Err(err).Msg(
"[Announce] Leader prepareBitmap SetKey failed",
)
return
}
} }
// Construct broadcast p2p message // Construct broadcast p2p message
if err := consensus.msgSender.SendWithRetry( if err := consensus.msgSender.SendWithRetry(
consensus.blockNum, msg_pb.MessageType_ANNOUNCE, []nodeconfig.GroupID{ consensus.blockNum, msg_pb.MessageType_ANNOUNCE, []nodeconfig.GroupID{
@ -268,7 +273,7 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) {
Offender: *addr, Offender: *addr,
} }
consensus.SlashChan <- proof consensus.SlashChan <- proof
}(consensus.SelfAddress) }(consensus.SelfAddresses[consensus.LeaderPubKey.SerializeToHexStr()])
return return
} }
} }

@ -120,10 +120,12 @@ func (v *uniformVoteWeight) AmIMemberOfCommitee() bool {
} }
identity, _ := pubKeyFunc() identity, _ := pubKeyFunc()
everyone := v.DumpParticipants() everyone := v.DumpParticipants()
myVoterID := identity.SerializeToHexStr() for _, key := range identity.PublicKey {
for i := range everyone { myVoterID := key.SerializeToHexStr()
if everyone[i] == myVoterID { for i := range everyone {
return true if everyone[i] == myVoterID {
return true
}
} }
} }
return false return false

@ -244,10 +244,15 @@ func (v *stakedVoteWeight) AmIMemberOfCommitee() bool {
return false return false
} }
identity, _ := pubKeyFunc() identity, _ := pubKeyFunc()
w := shard.BlsPublicKey{} for _, key := range identity.PublicKey {
w.FromLibBLSPublicKey(identity) w := shard.BlsPublicKey{}
_, ok := v.roster.Voters[w] w.FromLibBLSPublicKey(key)
return ok _, ok := v.roster.Voters[w]
if ok {
return true
}
}
return false
} }
func newBox() *voteBox { func newBox() *voteBox {

@ -8,6 +8,7 @@ import (
"github.com/harmony-one/harmony/consensus/votepower" "github.com/harmony-one/harmony/consensus/votepower"
bls_cosi "github.com/harmony-one/harmony/crypto/bls" bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -95,13 +96,13 @@ type SignatureReader interface {
// DependencyInjectionWriter .. // DependencyInjectionWriter ..
type DependencyInjectionWriter interface { type DependencyInjectionWriter interface {
SetShardIDProvider(func() (uint32, error)) SetShardIDProvider(func() (uint32, error))
SetMyPublicKeyProvider(func() (*bls.PublicKey, error)) SetMyPublicKeyProvider(func() (*multibls.PublicKey, error))
} }
// DependencyInjectionReader .. // DependencyInjectionReader ..
type DependencyInjectionReader interface { type DependencyInjectionReader interface {
ShardIDProvider() func() (uint32, error) ShardIDProvider() func() (uint32, error)
MyPublicKey() func() (*bls.PublicKey, error) MyPublicKey() func() (*multibls.PublicKey, error)
} }
// Decider .. // Decider ..
@ -151,7 +152,7 @@ type cIdentities struct {
type depInject struct { type depInject struct {
shardIDProvider func() (uint32, error) shardIDProvider func() (uint32, error)
publicKeyProvider func() (*bls.PublicKey, error) publicKeyProvider func() (*multibls.PublicKey, error)
} }
func (s *cIdentities) AggregateVotes(p Phase) *bls.Sign { func (s *cIdentities) AggregateVotes(p Phase) *bls.Sign {
@ -323,11 +324,11 @@ func (d *depInject) ShardIDProvider() func() (uint32, error) {
return d.shardIDProvider return d.shardIDProvider
} }
func (d *depInject) SetMyPublicKeyProvider(p func() (*bls.PublicKey, error)) { func (d *depInject) SetMyPublicKeyProvider(p func() (*multibls.PublicKey, error)) {
d.publicKeyProvider = p d.publicKeyProvider = p
} }
func (d *depInject) MyPublicKey() func() (*bls.PublicKey, error) { func (d *depInject) MyPublicKey() func() (*multibls.PublicKey, error) {
return d.publicKeyProvider return d.publicKeyProvider
} }

@ -14,8 +14,13 @@ import (
func (consensus *Consensus) didReachPrepareQuorum() error { func (consensus *Consensus) didReachPrepareQuorum() error {
logger := utils.Logger() logger := utils.Logger()
logger.Debug().Msg("[OnPrepare] Received Enough Prepare Signatures") logger.Debug().Msg("[OnPrepare] Received Enough Prepare Signatures")
leaderPriKey, err := consensus.GetConsensusLeaderPrivateKey()
if err != nil {
utils.Logger().Warn().Err(err).Msg("[OnPrepare] leader not found")
return err
}
// Construct and broadcast prepared message // Construct and broadcast prepared message
networkMessage, err := consensus.construct(msg_pb.MessageType_PREPARED, nil) networkMessage, err := consensus.construct(msg_pb.MessageType_PREPARED, nil, consensus.LeaderPubKey, leaderPriKey)
if err != nil { if err != nil {
consensus.getLogger().Err(err). consensus.getLogger().Err(err).
Str("message-type", msg_pb.MessageType_PREPARED.String()). Str("message-type", msg_pb.MessageType_PREPARED.String()).
@ -33,18 +38,22 @@ func (consensus *Consensus) didReachPrepareQuorum() error {
blockNumHash := [8]byte{} blockNumHash := [8]byte{}
binary.LittleEndian.PutUint64(blockNumHash[:], consensus.blockNum) binary.LittleEndian.PutUint64(blockNumHash[:], consensus.blockNum)
commitPayload := append(blockNumHash[:], consensus.blockHash[:]...) commitPayload := append(blockNumHash[:], consensus.blockHash[:]...)
consensus.Decider.SubmitVote(
quorum.Commit,
consensus.PubKey,
consensus.priKey.SignHash(commitPayload),
common.BytesToHash(consensus.blockHash[:]),
)
if err := consensus.commitBitmap.SetKey(consensus.PubKey, true); err != nil { // so by this point, everyone has committed to the blockhash of this block
consensus.getLogger().Debug().Msg("[OnPrepare] Leader commit bitmap set failed") // in prepare and so this is the actual block.
return err for i, key := range consensus.PubKey.PublicKey {
} consensus.Decider.SubmitVote(
quorum.Commit,
key,
consensus.priKey.PrivateKey[i].SignHash(commitPayload),
common.BytesToHash(consensus.blockHash[:]),
)
if err := consensus.commitBitmap.SetKey(key, true); err != nil {
consensus.getLogger().Debug().Msg("[OnPrepare] Leader commit bitmap set failed")
return err
}
}
if err := consensus.msgSender.SendWithRetry( if err := consensus.msgSender.SendWithRetry(
consensus.blockNum, consensus.blockNum,
msg_pb.MessageType_PREPARED, []nodeconfig.GroupID{ msg_pb.MessageType_PREPARED, []nodeconfig.GroupID{

@ -58,26 +58,27 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) {
} }
func (consensus *Consensus) prepare() { func (consensus *Consensus) prepare() {
networkMessage, err := consensus.construct(msg_pb.MessageType_PREPARE, nil) groupID := []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}
if err != nil { for i, key := range consensus.PubKey.PublicKey {
consensus.getLogger().Err(err). networkMessage, err := consensus.construct(msg_pb.MessageType_PREPARE, nil, key, consensus.priKey.PrivateKey[i])
Str("message-type", msg_pb.MessageType_PREPARE.String()). if err != nil {
Msg("could not construct message") consensus.getLogger().Err(err).
return Str("message-type", msg_pb.MessageType_PREPARE.String()).
} Msg("could not construct message")
return
}
// TODO: this will not return immediatey, may block // TODO: this will not return immediatey, may block
if err := consensus.msgSender.SendWithoutRetry( if err := consensus.msgSender.SendWithoutRetry(
[]nodeconfig.GroupID{ groupID,
nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)), host.ConstructP2pMessage(byte(17), networkMessage.Bytes),
}, ); err != nil {
host.ConstructP2pMessage(byte(17), networkMessage.Bytes), consensus.getLogger().Warn().Err(err).Msg("[OnAnnounce] Cannot send prepare message")
); err != nil { } else {
consensus.getLogger().Warn().Err(err).Msg("[OnAnnounce] Cannot send prepare message") consensus.getLogger().Info().
} else { Str("blockHash", hex.EncodeToString(consensus.blockHash[:])).
consensus.getLogger().Info(). Msg("[OnAnnounce] Sent Prepare Message!!")
Str("blockHash", hex.EncodeToString(consensus.blockHash[:])). }
Msg("[OnAnnounce] Sent Prepare Message!!")
} }
consensus.getLogger().Debug(). consensus.getLogger().Debug().
Str("From", consensus.phase.String()). Str("From", consensus.phase.String()).
@ -192,29 +193,32 @@ func (consensus *Consensus) onPrepared(msg *msg_pb.Message) {
} }
blockNumBytes := make([]byte, 8) blockNumBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(blockNumBytes, consensus.blockNum) binary.LittleEndian.PutUint64(blockNumBytes, consensus.blockNum)
networkMessage, _ := consensus.construct( groupID := []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}
msg_pb.MessageType_COMMIT, for i, key := range consensus.PubKey.PublicKey {
append(blockNumBytes, consensus.blockHash[:]...), networkMessage, _ := consensus.construct(
) // TODO: should only sign on block hash
// TODO: genesis account node delay for 1 second, msg_pb.MessageType_COMMIT,
// this is a temp fix for allows FN nodes to earning reward append(blockNumBytes, consensus.blockHash[:]...),
if consensus.delayCommit > 0 { key, consensus.priKey.PrivateKey[i],
time.Sleep(consensus.delayCommit) )
} // TODO: genesis account node delay for 1 second,
// this is a temp fix for allows FN nodes to earning reward
if consensus.delayCommit > 0 {
time.Sleep(consensus.delayCommit)
}
if err := consensus.msgSender.SendWithoutRetry( if err := consensus.msgSender.SendWithoutRetry(
[]nodeconfig.GroupID{ groupID,
nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), networkMessage.Bytes),
host.ConstructP2pMessage(byte(17), networkMessage.Bytes), ); err != nil {
); err != nil { consensus.getLogger().Warn().Msg("[OnPrepared] Cannot send commit message!!")
consensus.getLogger().Warn().Msg("[OnPrepared] Cannot send commit message!!") } else {
} else { consensus.getLogger().Info().
consensus.getLogger().Info(). Uint64("blockNum", consensus.blockNum).
Uint64("blockNum", consensus.blockNum). Hex("blockHash", consensus.blockHash[:]).
Hex("blockHash", consensus.blockHash[:]). Msg("[OnPrepared] Sent Commit Message!!")
Msg("[OnPrepared] Sent Commit Message!!") }
} }
consensus.getLogger().Debug(). consensus.getLogger().Debug().
Str("From", consensus.phase.String()). Str("From", consensus.phase.String()).
Str("To", FBFTCommit.String()). Str("To", FBFTCommit.String()).

@ -127,12 +127,14 @@ func (consensus *Consensus) startViewChange(viewID uint64) {
Str("NextLeader", consensus.LeaderPubKey.SerializeToHexStr()). Str("NextLeader", consensus.LeaderPubKey.SerializeToHexStr()).
Msg("[startViewChange]") Msg("[startViewChange]")
msgToSend := consensus.constructViewChangeMessage() for i, key := range consensus.PubKey.PublicKey {
consensus.host.SendMessageToGroups([]nodeconfig.GroupID{ msgToSend := consensus.constructViewChangeMessage(key, consensus.priKey.PrivateKey[i])
nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)), consensus.host.SendMessageToGroups([]nodeconfig.GroupID{
}, nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)),
host.ConstructP2pMessage(byte(17), msgToSend), },
) host.ConstructP2pMessage(byte(17), msgToSend),
)
}
consensus.consensusTimeout[timeoutViewChange].SetDuration(duration) consensus.consensusTimeout[timeoutViewChange].SetDuration(duration)
consensus.consensusTimeout[timeoutViewChange].Start() consensus.consensusTimeout[timeoutViewChange].Start()
@ -148,7 +150,8 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
return return
} }
newLeaderKey := recvMsg.LeaderPubkey newLeaderKey := recvMsg.LeaderPubkey
if !consensus.PubKey.IsEqual(newLeaderKey) { newLeaderPriKey, err := consensus.GetLeaderPrivateKey(newLeaderKey)
if err != nil {
return return
} }
@ -214,13 +217,13 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
preparedMsg := consensus.FBFTLog.FindMessageByMaxViewID(preparedMsgs) preparedMsg := consensus.FBFTLog.FindMessageByMaxViewID(preparedMsgs)
if preparedMsg == nil { if preparedMsg == nil {
consensus.getLogger().Debug().Msg("[onViewChange] add my M2(NIL) type messaage") consensus.getLogger().Debug().Msg("[onViewChange] add my M2(NIL) type messaage")
consensus.nilSigs[recvMsg.ViewID][consensus.PubKey.SerializeToHexStr()] = consensus.priKey.SignHash(NIL) consensus.nilSigs[recvMsg.ViewID][consensus.PubKey.SerializeToHexStr()] = newLeaderPriKey.SignHash(NIL)
consensus.nilBitmap[recvMsg.ViewID].SetKey(consensus.PubKey, true) consensus.nilBitmap[recvMsg.ViewID].SetKey(newLeaderKey, true)
} else { } else {
consensus.getLogger().Debug().Msg("[onViewChange] add my M1 type messaage") consensus.getLogger().Debug().Msg("[onViewChange] add my M1 type messaage")
msgToSign := append(preparedMsg.BlockHash[:], preparedMsg.Payload...) msgToSign := append(preparedMsg.BlockHash[:], preparedMsg.Payload...)
consensus.bhpSigs[recvMsg.ViewID][consensus.PubKey.SerializeToHexStr()] = consensus.priKey.SignHash(msgToSign) consensus.bhpSigs[recvMsg.ViewID][consensus.PubKey.SerializeToHexStr()] = newLeaderPriKey.SignHash(msgToSign)
consensus.bhpBitmap[recvMsg.ViewID].SetKey(consensus.PubKey, true) consensus.bhpBitmap[recvMsg.ViewID].SetKey(newLeaderKey, true)
} }
} }
// add self m3 type message signature and bitmap // add self m3 type message signature and bitmap
@ -228,8 +231,8 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
if !ok3 { if !ok3 {
viewIDBytes := make([]byte, 8) viewIDBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(viewIDBytes, recvMsg.ViewID) binary.LittleEndian.PutUint64(viewIDBytes, recvMsg.ViewID)
consensus.viewIDSigs[recvMsg.ViewID][consensus.PubKey.SerializeToHexStr()] = consensus.priKey.SignHash(viewIDBytes) consensus.viewIDSigs[recvMsg.ViewID][consensus.PubKey.SerializeToHexStr()] = newLeaderPriKey.SignHash(viewIDBytes)
consensus.viewIDBitmap[recvMsg.ViewID].SetKey(consensus.PubKey, true) consensus.viewIDBitmap[recvMsg.ViewID].SetKey(newLeaderKey, true)
} }
// m2 type message // m2 type message
@ -307,7 +310,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
copy(preparedMsg.BlockHash[:], recvMsg.Payload[:32]) copy(preparedMsg.BlockHash[:], recvMsg.Payload[:32])
preparedMsg.Payload = make([]byte, len(recvMsg.Payload)-32) preparedMsg.Payload = make([]byte, len(recvMsg.Payload)-32)
copy(preparedMsg.Payload[:], recvMsg.Payload[32:]) copy(preparedMsg.Payload[:], recvMsg.Payload[32:])
preparedMsg.SenderPubkey = consensus.PubKey preparedMsg.SenderPubkey = newLeaderKey
consensus.getLogger().Info().Msg("[onViewChange] New Leader Prepared Message Added") consensus.getLogger().Info().Msg("[onViewChange] New Leader Prepared Message Added")
consensus.FBFTLog.AddMessage(&preparedMsg) consensus.FBFTLog.AddMessage(&preparedMsg)
} }
@ -349,7 +352,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
// received enough view change messages, change state to normal consensus // received enough view change messages, change state to normal consensus
if consensus.Decider.IsQuorumAchievedByMask(consensus.viewIDBitmap[recvMsg.ViewID]) { if consensus.Decider.IsQuorumAchievedByMask(consensus.viewIDBitmap[recvMsg.ViewID]) {
consensus.current.SetMode(Normal) consensus.current.SetMode(Normal)
consensus.LeaderPubKey = consensus.PubKey consensus.LeaderPubKey = newLeaderKey
consensus.ResetState() consensus.ResetState()
if len(consensus.m1Payload) == 0 { if len(consensus.m1Payload) == 0 {
// TODO(Chao): explain why ReadySignal is sent only in this case but not the other case. // TODO(Chao): explain why ReadySignal is sent only in this case but not the other case.
@ -379,12 +382,12 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
commitPayload := append(blockNumBytes[:], consensus.blockHash[:]...) commitPayload := append(blockNumBytes[:], consensus.blockHash[:]...)
consensus.Decider.SubmitVote( consensus.Decider.SubmitVote(
quorum.Commit, quorum.Commit,
consensus.PubKey, newLeaderKey,
consensus.priKey.SignHash(commitPayload), newLeaderPriKey.SignHash(commitPayload),
common.BytesToHash(consensus.blockHash[:]), common.BytesToHash(consensus.blockHash[:]),
) )
if err = consensus.commitBitmap.SetKey(consensus.PubKey, true); err != nil { if err = consensus.commitBitmap.SetKey(newLeaderKey, true); err != nil {
consensus.getLogger().Debug(). consensus.getLogger().Debug().
Msg("[OnViewChange] New Leader commit bitmap set failed") Msg("[OnViewChange] New Leader commit bitmap set failed")
return return
@ -392,7 +395,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
} }
consensus.current.SetViewID(recvMsg.ViewID) consensus.current.SetViewID(recvMsg.ViewID)
msgToSend := consensus.constructNewViewMessage(recvMsg.ViewID) msgToSend := consensus.constructNewViewMessage(recvMsg.ViewID, newLeaderKey, newLeaderPriKey)
consensus.getLogger().Warn(). consensus.getLogger().Warn().
Int("payloadSize", len(consensus.m1Payload)). Int("payloadSize", len(consensus.m1Payload)).
@ -541,21 +544,25 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) {
// Construct and send the commit message // Construct and send the commit message
blockNumHash := make([]byte, 8) blockNumHash := make([]byte, 8)
binary.LittleEndian.PutUint64(blockNumHash, consensus.blockNum) binary.LittleEndian.PutUint64(blockNumHash, consensus.blockNum)
network, err := consensus.construct( groupID := []nodeconfig.GroupID{
msg_pb.MessageType_COMMIT, nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}
append(blockNumHash, consensus.blockHash[:]...), for i, key := range consensus.PubKey.PublicKey {
) network, err := consensus.construct(
if err != nil { msg_pb.MessageType_COMMIT,
consensus.getLogger().Err(err).Msg("could not create commit message") append(blockNumHash, consensus.blockHash[:]...),
return key, consensus.priKey.PrivateKey[i],
)
if err != nil {
consensus.getLogger().Err(err).Msg("could not create commit message")
return
}
msgToSend := network.Bytes
consensus.getLogger().Info().Msg("onNewView === commit")
consensus.host.SendMessageToGroups(
groupID,
host.ConstructP2pMessage(byte(17), msgToSend),
)
} }
msgToSend := network.Bytes
consensus.getLogger().Info().Msg("onNewView === commit")
consensus.host.SendMessageToGroups(
[]nodeconfig.GroupID{
nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))},
host.ConstructP2pMessage(byte(17), msgToSend),
)
consensus.getLogger().Debug(). consensus.getLogger().Debug().
Str("From", consensus.phase.String()). Str("From", consensus.phase.String()).
Str("To", FBFTCommit.String()). Str("To", FBFTCommit.String()).

@ -17,6 +17,7 @@ import (
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee" "github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/staking/availability" "github.com/harmony-one/harmony/staking/availability"
@ -212,7 +213,7 @@ func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header)
d.SetShardIDProvider(func() (uint32, error) { d.SetShardIDProvider(func() (uint32, error) {
return parentHeader.ShardID(), nil return parentHeader.ShardID(), nil
}) })
d.SetMyPublicKeyProvider(func() (*bls.PublicKey, error) { d.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) {
return nil, nil return nil, nil
}) })
d.SetVoters(slotList.FindCommitteeByID(parentHeader.ShardID()).Slots) d.SetVoters(slotList.FindCommitteeByID(parentHeader.ShardID()).Slots)
@ -444,7 +445,7 @@ func (e *engineImpl) VerifyHeaderWithSignature(chain engine.ChainReader, header
d.SetShardIDProvider(func() (uint32, error) { d.SetShardIDProvider(func() (uint32, error) {
return header.ShardID(), nil return header.ShardID(), nil
}) })
d.SetMyPublicKeyProvider(func() (*bls.PublicKey, error) { d.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) {
return nil, nil return nil, nil
}) })
d.SetVoters(slotList.FindCommitteeByID(header.ShardID()).Slots) d.SetVoters(slotList.FindCommitteeByID(header.ShardID()).Slots)

@ -8,9 +8,9 @@ import (
"math/big" "math/big"
"sync" "sync"
"github.com/harmony-one/bls/ffi/go/bls"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding" shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/staking/slash" "github.com/harmony-one/harmony/staking/slash"
p2p_crypto "github.com/libp2p/go-libp2p-crypto" p2p_crypto "github.com/libp2p/go-libp2p-crypto"
@ -83,8 +83,8 @@ type ConfigType struct {
PushgatewayPort string // metrics pushgateway prometheus port PushgatewayPort string // metrics pushgateway prometheus port
StringRole string StringRole string
P2pPriKey p2p_crypto.PrivKey P2pPriKey p2p_crypto.PrivKey
ConsensusPriKey *bls.SecretKey ConsensusPriKey *multibls.PrivateKey
ConsensusPubKey *bls.PublicKey ConsensusPubKey *multibls.PublicKey
// Database directory // Database directory
DBDir string DBDir string
networkType NetworkType networkType NetworkType
@ -280,7 +280,8 @@ func SetShardingSchedule(schedule shardingconfig.Schedule) {
// consensus key. // consensus key.
func (conf *ConfigType) ShardIDFromConsensusKey() (uint32, error) { func (conf *ConfigType) ShardIDFromConsensusKey() (uint32, error) {
var pubKey shard.BlsPublicKey var pubKey shard.BlsPublicKey
if err := pubKey.FromLibBLSPublicKey(conf.ConsensusPubKey); err != nil { // all keys belong to same shard
if err := pubKey.FromLibBLSPublicKey(conf.ConsensusPubKey.PublicKey[0]); err != nil {
return 0, errors.Wrapf(err, return 0, errors.Wrapf(err,
"cannot convert libbls public key %s to internal form", "cannot convert libbls public key %s to internal form",
conf.ConsensusPubKey.SerializeToHexStr()) conf.ConsensusPubKey.SerializeToHexStr())

@ -9,6 +9,7 @@ import (
mock_shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding/mock" mock_shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding/mock"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/multibls"
) )
func TestNodeConfigSingleton(t *testing.T) { func TestNodeConfigSingleton(t *testing.T) {
@ -115,7 +116,7 @@ func TestConfigType_ShardIDFromConsensusKey(t *testing.T) {
schedule := mock_shardingconfig.NewMockSchedule(mc) schedule := mock_shardingconfig.NewMockSchedule(mc)
schedule.EXPECT().InstanceForEpoch(tt.epoch).Return(instance) schedule.EXPECT().InstanceForEpoch(tt.epoch).Return(instance)
conf := &ConfigType{ conf := &ConfigType{
ConsensusPubKey: tt.fields.ConsensusPubKey, ConsensusPubKey: multibls.GetPublicKey(tt.fields.ConsensusPubKey),
networkType: tt.fields.networkType, networkType: tt.fields.networkType,
shardingSchedule: schedule, shardingSchedule: schedule,
} }

@ -0,0 +1,73 @@
package multibls
import (
"strings"
"github.com/harmony-one/bls/ffi/go/bls"
)
// PrivateKey stores the bls secret keys that belongs to the node
type PrivateKey struct {
PrivateKey []*bls.SecretKey
}
// PublicKey stores the bls public keys that belongs to the node
type PublicKey struct {
PublicKey []*bls.PublicKey
}
// SerializeToHexStr wrapper
func (multiKey PublicKey) SerializeToHexStr() string {
var builder strings.Builder
for _, pubKey := range multiKey.PublicKey {
builder.WriteString(pubKey.SerializeToHexStr())
}
return builder.String()
}
// Contains wrapper
func (multiKey PublicKey) Contains(pubKey *bls.PublicKey) bool {
for _, key := range multiKey.PublicKey {
if key.IsEqual(pubKey) {
return true
}
}
return false
}
// GetPublicKey wrapper
func (multiKey PrivateKey) GetPublicKey() *PublicKey {
pubKeys := make([]*bls.PublicKey, len(multiKey.PrivateKey))
for i, key := range multiKey.PrivateKey {
pubKeys[i] = key.GetPublicKey()
}
return &PublicKey{PublicKey: pubKeys}
}
// GetPrivateKey creates a multibls PrivateKey using bls.SecretKey
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}}
}
}
// AppendPriKey appends a SecretKey to multibls PrivateKey
func AppendPriKey(multiKey *PrivateKey, key *bls.SecretKey) {
if multiKey != nil {
multiKey.PrivateKey = append(multiKey.PrivateKey, key)
} else {
multiKey = &PrivateKey{PrivateKey: []*bls.SecretKey{key}}
}
}

@ -652,8 +652,8 @@ func (node *Node) InitConsensusWithValidators() (err error) {
"blockNum", blockNum) "blockNum", blockNum)
} }
for i := range pubKeys { for _, key := range pubKeys {
if pubKeys[i].IsEqual(node.Consensus.PubKey) { if node.Consensus.PubKey.Contains(key) {
utils.Logger().Info(). utils.Logger().Info().
Uint64("blockNum", blockNum). Uint64("blockNum", blockNum).
Int("numPubKeys", len(pubKeys)). Int("numPubKeys", len(pubKeys)).

@ -10,6 +10,7 @@ import (
bls_cosi "github.com/harmony-one/harmony/crypto/bls" bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
) )
@ -163,7 +164,7 @@ func (node *Node) VerifyCrossLink(cl types.CrossLink) error {
decider.SetShardIDProvider(func() (uint32, error) { decider.SetShardIDProvider(func() (uint32, error) {
return cl.ShardID(), nil return cl.ShardID(), nil
}) })
decider.SetMyPublicKeyProvider(func() (*bls.PublicKey, error) { decider.SetMyPublicKeyProvider(func() (*multibls.PublicKey, error) {
return nil, nil return nil, nil
}) })
if _, err := decider.SetVoters(committee.Slots); err != nil { if _, err := decider.SetVoters(committee.Slots); err != nil {

@ -417,7 +417,7 @@ func (node *Node) PostConsensusProcessing(
// TODO: randomly selected a few validators to broadcast messages instead of only leader broadcast // TODO: randomly selected a few validators to broadcast messages instead of only leader broadcast
// TODO: refactor the asynchronous calls to separate go routine. // TODO: refactor the asynchronous calls to separate go routine.
node.lastConsensusTime = time.Now().Unix() node.lastConsensusTime = time.Now().Unix()
if node.Consensus.PubKey.IsEqual(node.Consensus.LeaderPubKey) { if node.Consensus.IsLeader() {
if node.NodeConfig.ShardID == shard.BeaconChainShardID { if node.NodeConfig.ShardID == shard.BeaconChainShardID {
node.BroadcastNewBlock(newBlock) node.BroadcastNewBlock(newBlock)
} }

@ -10,6 +10,7 @@ import (
"github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/crypto/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node" nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
@ -27,7 +28,7 @@ func TestAddNewBlock(t *testing.T) {
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := consensus.New( consensus, err := consensus.New(
host, shard.BeaconChainShardID, leader, blsKey, decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)
@ -65,7 +66,7 @@ func TestVerifyNewBlock(t *testing.T) {
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := consensus.New( consensus, err := consensus.New(
host, shard.BeaconChainShardID, leader, blsKey, decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)

@ -43,12 +43,14 @@ func (node *Node) UpdateTxPoolSizeForMetrics(txPoolSize uint64) {
// UpdateBalanceForMetrics uppdates node balance for metrics service. // UpdateBalanceForMetrics uppdates node balance for metrics service.
func (node *Node) UpdateBalanceForMetrics() { func (node *Node) UpdateBalanceForMetrics() {
curBalance, err := node.GetBalanceOfAddress(node.Consensus.SelfAddress) for _, addr := range node.Consensus.SelfAddresses {
if err != nil { curBalance, err := node.GetBalanceOfAddress(addr)
return if err != nil {
return
}
utils.Logger().Info().Msgf("Updating metrics node balance %d", curBalance.Uint64())
metrics.UpdateNodeBalance(curBalance)
} }
utils.Logger().Info().Msgf("Updating metrics node balance %d", curBalance.Uint64())
metrics.UpdateNodeBalance(curBalance)
} }
// UpdateLastConsensusTimeForMetrics uppdates last consensus reached time for metrics service. // UpdateLastConsensusTimeForMetrics uppdates last consensus reached time for metrics service.

@ -84,7 +84,7 @@ func (node *Node) proposeNewBlock() (*types.Block, error) {
// Update worker's current header and state data in preparation to propose/process new transactions // Update worker's current header and state data in preparation to propose/process new transactions
var ( var (
coinbase = node.Consensus.SelfAddress coinbase = node.Consensus.SelfAddresses[node.Consensus.LeaderPubKey.SerializeToHexStr()]
beneficiary = coinbase beneficiary = coinbase
err error err error
) )
@ -94,7 +94,7 @@ func (node *Node) proposeNewBlock() (*types.Block, error) {
// After staking, all coinbase will be the address of bls pub key // After staking, all coinbase will be the address of bls pub key
if header := node.Worker.GetCurrentHeader(); node.Blockchain().Config().IsStaking(header.Epoch()) { if header := node.Worker.GetCurrentHeader(); node.Blockchain().Config().IsStaking(header.Epoch()) {
addr := common.Address{} addr := common.Address{}
blsPubKeyBytes := node.Consensus.PubKey.GetAddress() blsPubKeyBytes := node.Consensus.LeaderPubKey.GetAddress()
addr.SetBytes(blsPubKeyBytes[:]) addr.SetBytes(blsPubKeyBytes[:])
coinbase = addr // coinbase will be the bls address coinbase = addr // coinbase will be the bls address
header.SetCoinbase(coinbase) header.SetCoinbase(coinbase)

@ -16,6 +16,7 @@ import (
"github.com/harmony-one/harmony/drand" "github.com/harmony-one/harmony/drand"
"github.com/harmony-one/harmony/internal/shardchain" "github.com/harmony-one/harmony/internal/shardchain"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl" "github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
@ -35,7 +36,7 @@ func TestNewNode(t *testing.T) {
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := consensus.New( consensus, err := consensus.New(
host, shard.BeaconChainShardID, leader, blsKey, decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)
@ -202,7 +203,7 @@ func TestAddPeers(t *testing.T) {
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := consensus.New( consensus, err := consensus.New(
host, shard.BeaconChainShardID, leader, blsKey, decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)
@ -252,7 +253,7 @@ func TestAddBeaconPeer(t *testing.T) {
} }
decider := quorum.NewDecider(quorum.SuperMajorityVote) decider := quorum.NewDecider(quorum.SuperMajorityVote)
consensus, err := consensus.New( consensus, err := consensus.New(
host, shard.BeaconChainShardID, leader, blsKey, decider, host, shard.BeaconChainShardID, leader, multibls.GetPrivateKey(blsKey), decider,
) )
if err != nil { if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err) t.Fatalf("Cannot craeate consensus: %v", err)

Loading…
Cancel
Save