From a354b93676e96a4a863d92ff3bfa6573484000a8 Mon Sep 17 00:00:00 2001 From: Rongjian Lan Date: Wed, 22 Jul 2020 10:08:29 -0700 Subject: [PATCH] Optimize bls Mask infra to avoid loops (#3243) --- consensus/consensus_service.go | 30 ++---- consensus/construct_test.go | 4 +- consensus/fbft_log.go | 8 +- consensus/leader.go | 6 +- consensus/quorum/one-node-staked-vote.go | 11 +- consensus/quorum/one-node-staked-vote_test.go | 12 ++- consensus/quorum/quorom_test.go | 7 +- consensus/quorum/quorum.go | 13 +-- consensus/threshold.go | 2 +- consensus/view_change.go | 14 +-- consensus/view_change_test.go | 10 +- crypto/bls/mask.go | 41 +++---- crypto/bls/mask_test.go | 100 +++++++++++------- hmy/api_backend.go | 8 +- internal/chain/engine.go | 7 +- internal/chain/sig.go | 2 +- internal/hmyapi/apiv1/blockchain.go | 21 +--- internal/hmyapi/apiv2/blockchain.go | 21 +--- node/node.go | 2 +- node/node_handler.go | 10 +- shard/shard_state.go | 7 +- 21 files changed, 152 insertions(+), 184 deletions(-) diff --git a/consensus/consensus_service.go b/consensus/consensus_service.go index 5824a66aa..f67ccd6ad 100644 --- a/consensus/consensus_service.go +++ b/consensus/consensus_service.go @@ -76,7 +76,7 @@ func (consensus *Consensus) GetViewID() uint64 { // UpdatePublicKeys updates the PublicKeys for // quorum on current subcommittee, protected by a mutex -func (consensus *Consensus) UpdatePublicKeys(pubKeys []*bls_core.PublicKey) int64 { +func (consensus *Consensus) UpdatePublicKeys(pubKeys []bls_cosi.PublicKeyWrapper) int64 { // TODO: use mutex for updating public keys pointer. No need to lock on all these logic. consensus.pubKeyLock.Lock() consensus.Decider.UpdateParticipants(pubKeys) @@ -84,7 +84,7 @@ func (consensus *Consensus) UpdatePublicKeys(pubKeys []*bls_core.PublicKey) int6 for i := range pubKeys { utils.Logger().Debug(). Int("index", i). - Str("BLSPubKey", pubKeys[i].SerializeToHexStr()). + Str("BLSPubKey", pubKeys[i].Bytes.Hex()). Msg("Member") } @@ -155,12 +155,8 @@ func (consensus *Consensus) UpdateBitmaps() { Str("Phase", consensus.phase.String()). Msg("[UpdateBitmaps] Updating consensus bitmaps") members := consensus.Decider.Participants() - publicKeys := []*bls_core.PublicKey{} - for _, key := range members { - publicKeys = append(publicKeys, key.Object) - } - prepareBitmap, _ := bls_cosi.NewMask(publicKeys, nil) - commitBitmap, _ := bls_cosi.NewMask(publicKeys, nil) + prepareBitmap, _ := bls_cosi.NewMask(members, nil) + commitBitmap, _ := bls_cosi.NewMask(members, nil) consensus.prepareBitmap = prepareBitmap consensus.commitBitmap = commitBitmap } @@ -265,12 +261,8 @@ func (consensus *Consensus) ReadSignatureBitmapPayload( // TODO(audit): keep a Mask in the Decider so it won't be reconstructed on the fly. members := consensus.Decider.Participants() - publicKeys := []*bls_core.PublicKey{} - for _, key := range members { - publicKeys = append(publicKeys, key.Object) - } return chain.ReadSignatureBitmapByPublicKeys( - sigAndBitmapPayload, publicKeys, + sigAndBitmapPayload, members, ) } @@ -474,7 +466,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { for _, key := range pubKeys { // in committee myPubKeys := consensus.GetPublicKeys() - if myPubKeys.Contains(key) { + if myPubKeys.Contains(key.Object) { if hasError { return Syncing } @@ -520,10 +512,6 @@ func (consensus *Consensus) NeedsRandomNumberGeneration(epoch *big.Int) bool { func (consensus *Consensus) addViewIDKeyIfNotExist(viewID uint64) { members := consensus.Decider.Participants() - publicKeys := []*bls_core.PublicKey{} - for _, key := range members { - publicKeys = append(publicKeys, key.Object) - } if _, ok := consensus.bhpSigs[viewID]; !ok { consensus.bhpSigs[viewID] = map[string]*bls_core.Sign{} } @@ -534,15 +522,15 @@ func (consensus *Consensus) addViewIDKeyIfNotExist(viewID uint64) { consensus.viewIDSigs[viewID] = map[string]*bls_core.Sign{} } if _, ok := consensus.bhpBitmap[viewID]; !ok { - bhpBitmap, _ := bls_cosi.NewMask(publicKeys, nil) + bhpBitmap, _ := bls_cosi.NewMask(members, nil) consensus.bhpBitmap[viewID] = bhpBitmap } if _, ok := consensus.nilBitmap[viewID]; !ok { - nilBitmap, _ := bls_cosi.NewMask(publicKeys, nil) + nilBitmap, _ := bls_cosi.NewMask(members, nil) consensus.nilBitmap[viewID] = nilBitmap } if _, ok := consensus.viewIDBitmap[viewID]; !ok { - viewIDBitmap, _ := bls_cosi.NewMask(publicKeys, nil) + viewIDBitmap, _ := bls_cosi.NewMask(members, nil) consensus.viewIDBitmap[viewID] = viewIDBitmap } } diff --git a/consensus/construct_test.go b/consensus/construct_test.go index edd91ad34..04c548f49 100644 --- a/consensus/construct_test.go +++ b/consensus/construct_test.go @@ -91,10 +91,10 @@ func TestConstructPreparedMessage(test *testing.T) { } // According to RJ these failures are benign. - if err := consensus.prepareBitmap.SetKey(leaderPubKey, true); err != nil { + if err := consensus.prepareBitmap.SetKey(leaderKey, true); err != nil { test.Log(errors.New("prepareBitmap.SetKey")) } - if err := consensus.prepareBitmap.SetKey(validatorPubKey, true); err != nil { + if err := consensus.prepareBitmap.SetKey(validatorKey, true); err != nil { test.Log(errors.New("prepareBitmap.SetKey")) } diff --git a/consensus/fbft_log.go b/consensus/fbft_log.go index eee852e82..23e1d87b4 100644 --- a/consensus/fbft_log.go +++ b/consensus/fbft_log.go @@ -340,10 +340,6 @@ func (consensus *Consensus) ParseNewViewMessage(msg *msg_pb.Message) (*FBFTMessa copy(FBFTMsg.SenderPubkey.Bytes[:], vcMsg.SenderPubkey[:]) members := consensus.Decider.Participants() - publicKeys := []*bls_core.PublicKey{} - for _, key := range members { - publicKeys = append(publicKeys, key.Object) - } if len(vcMsg.M3Aggsigs) > 0 { m3Sig := bls_core.Sign{} err = m3Sig.Deserialize(vcMsg.M3Aggsigs) @@ -351,7 +347,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(publicKeys, nil) + m3mask, err := bls_cosi.NewMask(members, nil) if err != nil { utils.Logger().Warn().Err(err).Msg("ParseViewChangeMessage failed to create mask for multi signature") return nil, err @@ -368,7 +364,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(publicKeys, nil) + m2mask, err := bls_cosi.NewMask(members, 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 cab43c7ad..0e520e98d 100644 --- a/consensus/leader.go +++ b/consensus/leader.go @@ -60,7 +60,7 @@ func (consensus *Consensus) announce(block *types.Block) { // Leader sign the block hash itself for i, key := range consensus.priKey { - if err := consensus.prepareBitmap.SetKey(key.Pub.Object, true); err != nil { + if err := consensus.prepareBitmap.SetKey(key.Pub.Bytes, true); err != nil { consensus.getLogger().Warn().Err(err).Msgf( "[Announce] Leader prepareBitmap SetKey failed for key at index %d", i, ) @@ -191,7 +191,7 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) { return } // Set the bitmap indicating that this validator signed. - if err := prepareBitmap.SetKey(recvMsg.SenderPubkey.Object, true); err != nil { + if err := prepareBitmap.SetKey(recvMsg.SenderPubkey.Bytes, true); err != nil { consensus.prepareMutex.Unlock() consensus.getLogger().Warn().Err(err).Msg("[OnPrepare] prepareBitmap.SetKey failed") return @@ -295,7 +295,7 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) { return } // Set the bitmap indicating that this validator signed. - if err := commitBitmap.SetKey(recvMsg.SenderPubkey.Object, true); err != nil { + if err := commitBitmap.SetKey(recvMsg.SenderPubkey.Bytes, true); err != nil { consensus.commitMutex.Unlock() consensus.getLogger().Warn().Err(err). Msg("[OnCommit] commitBitmap.SetKey failed") diff --git a/consensus/quorum/one-node-staked-vote.go b/consensus/quorum/one-node-staked-vote.go index 9ef09aae7..9e006c9e0 100644 --- a/consensus/quorum/one-node-staked-vote.go +++ b/consensus/quorum/one-node-staked-vote.go @@ -144,17 +144,12 @@ func (v *stakedVoteWeight) currentTotalPower(p Phase) (*numeric.Dec, error) { // ComputeTotalPowerByMask computes the total power indicated by bitmap mask func (v *stakedVoteWeight) computeTotalPowerByMask(mask *bls_cosi.Mask) *numeric.Dec { - pubKeys := mask.Publics - w := bls.SerializedPublicKey{} currentTotal := numeric.ZeroDec() - for i := range pubKeys { - if err := w.FromLibBLSPublicKey(pubKeys[i]); err != nil { - return nil - } - if enabled, err := mask.KeyEnabled(pubKeys[i]); err == nil && enabled { + for key, i := range mask.PublicsIndex { + if enabled, err := mask.IndexEnabled(i); err == nil && enabled { currentTotal = currentTotal.Add( - v.roster.Voters[w].OverallPercent, + v.roster.Voters[key].OverallPercent, ) } } diff --git a/consensus/quorum/one-node-staked-vote_test.go b/consensus/quorum/one-node-staked-vote_test.go index f51c9ab2a..f13072f90 100644 --- a/consensus/quorum/one-node-staked-vote_test.go +++ b/consensus/quorum/one-node-staked-vote_test.go @@ -54,7 +54,7 @@ func setupBaseCase() (Decider, *TallyResult, shard.SlotList, map[string]secretKe sKeys := map[string]secretKeyMap{} sKeys[hmy] = secretKeyMap{} sKeys[reg] = secretKeyMap{} - pubKeys := []*bls_core.PublicKey{} + pubKeys := []bls.PublicKeyWrapper{} for i := 0; i < quorumNodes; i++ { newSlot, sKey := generateRandomSlot() @@ -65,7 +65,9 @@ func setupBaseCase() (Decider, *TallyResult, shard.SlotList, map[string]secretKe sKeys[reg][newSlot.BLSPublicKey] = sKey } slotList = append(slotList, newSlot) - pubKeys = append(pubKeys, sKey.GetPublicKey()) + wrapper := bls.PublicKeyWrapper{Object: sKey.GetPublicKey()} + wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object) + pubKeys = append(pubKeys, wrapper) } decider := NewDecider(SuperMajorityStake, shard.BeaconChainShardID) @@ -83,7 +85,7 @@ func setupBaseCase() (Decider, *TallyResult, shard.SlotList, map[string]secretKe func setupEdgeCase() (Decider, *TallyResult, shard.SlotList, secretKeyMap) { slotList := shard.SlotList{} sKeys := secretKeyMap{} - pubKeys := []*bls_core.PublicKey{} + pubKeys := []bls.PublicKeyWrapper{} for i := 0; i < quorumNodes; i++ { newSlot, sKey := generateRandomSlot() @@ -92,7 +94,9 @@ func setupEdgeCase() (Decider, *TallyResult, shard.SlotList, secretKeyMap) { sKeys[newSlot.BLSPublicKey] = sKey } slotList = append(slotList, newSlot) - pubKeys = append(pubKeys, sKey.GetPublicKey()) + wrapper := bls.PublicKeyWrapper{Object: sKey.GetPublicKey()} + wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object) + pubKeys = append(pubKeys, wrapper) } decider := NewDecider(SuperMajorityStake, shard.BeaconChainShardID) diff --git a/consensus/quorum/quorom_test.go b/consensus/quorum/quorom_test.go index dd4ca10f2..a4e320029 100644 --- a/consensus/quorum/quorom_test.go +++ b/consensus/quorum/quorom_test.go @@ -3,7 +3,6 @@ package quorum import ( "testing" - "github.com/harmony-one/bls/ffi/go/bls" harmony_bls "github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/shard" "github.com/stretchr/testify/assert" @@ -48,11 +47,13 @@ func TestAddingQuoromParticipants(t *testing.T) { assert.Equal(t, int64(0), decider.ParticipantsCount()) - blsKeys := []*bls.PublicKey{} + blsKeys := []harmony_bls.PublicKeyWrapper{} keyCount := int64(5) for i := int64(0); i < keyCount; i++ { blsKey := harmony_bls.RandPrivateKey() - blsKeys = append(blsKeys, blsKey.GetPublicKey()) + wrapper := harmony_bls.PublicKeyWrapper{Object: blsKey.GetPublicKey()} + wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object) + blsKeys = append(blsKeys, wrapper) } decider.UpdateParticipants(blsKeys) diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index ddf34b7b5..17b0a5361 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -73,7 +73,7 @@ type ParticipantTracker interface { IndexOf(bls.SerializedPublicKey) int ParticipantsCount() int64 NextAfter(*bls.PublicKeyWrapper) (bool, *bls.PublicKeyWrapper) - UpdateParticipants(pubKeys []*bls_core.PublicKey) + UpdateParticipants(pubKeys []bls.PublicKeyWrapper) } // SignatoryTracker .. @@ -202,17 +202,12 @@ func (s *cIdentities) Participants() multibls.PublicKeys { return s.publicKeys } -func (s *cIdentities) UpdateParticipants(pubKeys []*bls_core.PublicKey) { - keys := make([]bls.PublicKeyWrapper, len(pubKeys)) +func (s *cIdentities) UpdateParticipants(pubKeys []bls.PublicKeyWrapper) { keyIndexMap := map[bls.SerializedPublicKey]int{} for i := range pubKeys { - kBytes := bls.SerializedPublicKey{} - kBytes.FromLibBLSPublicKey(pubKeys[i]) - - keys[i] = bls.PublicKeyWrapper{Object: pubKeys[i], Bytes: kBytes} - keyIndexMap[kBytes] = i + keyIndexMap[pubKeys[i].Bytes] = i } - s.publicKeys = keys + s.publicKeys = pubKeys s.keyIndexMap = keyIndexMap } diff --git a/consensus/threshold.go b/consensus/threshold.go index e3265195b..27f60ed66 100644 --- a/consensus/threshold.go +++ b/consensus/threshold.go @@ -51,7 +51,7 @@ 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.priKey { - if err := consensus.commitBitmap.SetKey(key.Pub.Object, true); err != nil { + if err := consensus.commitBitmap.SetKey(key.Pub.Bytes, true); err != nil { consensus.getLogger().Warn().Msgf("[OnPrepare] Leader commit bitmap set failed for key at index %d", i) continue } diff --git a/consensus/view_change.go b/consensus/view_change.go index dba2ed494..a95a3f0ce 100644 --- a/consensus/view_change.go +++ b/consensus/view_change.go @@ -216,7 +216,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { consensus.getLogger().Debug().Msg("[onViewChange] add my M1 type messaage") msgToSign := append(preparedMsg.BlockHash[:], preparedMsg.Payload...) for i, key := range consensus.priKey { - if err := consensus.bhpBitmap[recvMsg.ViewID].SetKey(key.Pub.Object, true); err != nil { + if err := consensus.bhpBitmap[recvMsg.ViewID].SetKey(key.Pub.Bytes, true); err != nil { consensus.getLogger().Warn().Msgf("[onViewChange] bhpBitmap setkey failed for key at index %d", i) continue } @@ -229,7 +229,7 @@ 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.priKey { - if err := consensus.nilBitmap[recvMsg.ViewID].SetKey(key.Pub.Object, true); err != nil { + if err := consensus.nilBitmap[recvMsg.ViewID].SetKey(key.Pub.Bytes, true); err != nil { consensus.getLogger().Warn().Msgf("[onViewChange] nilBitmap setkey failed for key at index %d", i) continue } @@ -243,7 +243,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { viewIDBytes := make([]byte, 8) binary.LittleEndian.PutUint64(viewIDBytes, recvMsg.ViewID) for i, key := range consensus.priKey { - if err := consensus.viewIDBitmap[recvMsg.ViewID].SetKey(key.Pub.Object, true); err != nil { + if err := consensus.viewIDBitmap[recvMsg.ViewID].SetKey(key.Pub.Bytes, true); err != nil { consensus.getLogger().Warn().Msgf("[onViewChange] viewIDBitmap setkey failed for key at index %d", i) continue } @@ -283,7 +283,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Add M2 (NIL) type message") 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. + consensus.nilBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Bytes, 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") @@ -354,7 +354,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { Str("validatorPubKey", senderKey.Bytes.Hex()). Msg("[onViewChange] Add M1 (prepared) type message") 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. + consensus.bhpBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Bytes, true) // Set the bitmap indicating that this validator signed. } // check and add viewID (m3 type) message signature @@ -378,7 +378,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { consensus.viewIDSigs[recvMsg.ViewID][senderKey.Bytes.Hex()] = recvMsg.ViewidSig // Set the bitmap indicating that this validator signed. - consensus.viewIDBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Object, true) + consensus.viewIDBitmap[recvMsg.ViewID].SetKey(recvMsg.SenderPubkey.Bytes, true) consensus.getLogger().Debug(). Int("have", len(consensus.viewIDSigs[recvMsg.ViewID])). Int64("total", consensus.Decider.ParticipantsCount()). @@ -422,7 +422,7 @@ 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.priKey { - if err := consensus.commitBitmap.SetKey(key.Pub.Object, true); err != nil { + if err := consensus.commitBitmap.SetKey(key.Pub.Bytes, true); err != nil { consensus.getLogger().Warn(). Msgf("[OnViewChange] New Leader commit bitmap set failed for key at index %d", i) continue diff --git a/consensus/view_change_test.go b/consensus/view_change_test.go index 10a30d150..550552faf 100644 --- a/consensus/view_change_test.go +++ b/consensus/view_change_test.go @@ -125,7 +125,7 @@ func TestGetNextLeaderKeyShouldSucceed(t *testing.T) { assert.Equal(t, int64(0), consensus.Decider.ParticipantsCount()) blsKeys := []*bls_core.PublicKey{} - wrappedBLSKeys := []*bls.PublicKeyWrapper{} + wrappedBLSKeys := []bls.PublicKeyWrapper{} keyCount := int64(5) for i := int64(0); i < keyCount; i++ { @@ -133,17 +133,17 @@ func TestGetNextLeaderKeyShouldSucceed(t *testing.T) { blsPubKey := blsKey.GetPublicKey() bytes := bls.SerializedPublicKey{} bytes.FromLibBLSPublicKey(blsPubKey) - wrapped := &bls.PublicKeyWrapper{Object: blsPubKey, Bytes: bytes} + wrapped := bls.PublicKeyWrapper{Object: blsPubKey, Bytes: bytes} blsKeys = append(blsKeys, blsPubKey) wrappedBLSKeys = append(wrappedBLSKeys, wrapped) } - consensus.Decider.UpdateParticipants(blsKeys) + consensus.Decider.UpdateParticipants(wrappedBLSKeys) assert.Equal(t, keyCount, consensus.Decider.ParticipantsCount()) - consensus.LeaderPubKey = wrappedBLSKeys[0] + consensus.LeaderPubKey = &wrappedBLSKeys[0] nextKey := consensus.GetNextLeaderKey() - assert.Equal(t, nextKey, wrappedBLSKeys[1]) + assert.Equal(t, nextKey, &wrappedBLSKeys[1]) } diff --git a/crypto/bls/mask.go b/crypto/bls/mask.go index a57fcff6d..5e1297ca7 100644 --- a/crypto/bls/mask.go +++ b/crypto/bls/mask.go @@ -67,6 +67,7 @@ func AggregateSig(sigs []*bls.Sign) *bls.Sign { type Mask struct { Bitmap []byte Publics []*bls.PublicKey + PublicsIndex map[SerializedPublicKey]int AggregatePublic *bls.PublicKey } @@ -74,20 +75,24 @@ type Mask struct { // cosigners are disabled by default. If a public key is given it verifies that // it is present in the list of keys and sets the corresponding index in the // bitmask to 1 (enabled). -func NewMask(publics []*bls.PublicKey, myKey *bls.PublicKey) (*Mask, error) { +func NewMask(publics []PublicKeyWrapper, myKey *PublicKeyWrapper) (*Mask, error) { + index := map[SerializedPublicKey]int{} + publicKeys := make([]*bls.PublicKey, len(publics)) + for i, key := range publics { + publicKeys[i] = key.Object + index[key.Bytes] = i + } m := &Mask{ - Publics: publics, + Publics: publicKeys, + PublicsIndex: index, } m.Bitmap = make([]byte, m.Len()) m.AggregatePublic = &bls.PublicKey{} if myKey != nil { - found := false - for i, key := range publics { - if key.IsEqual(myKey) { - m.SetBit(i, true) - found = true - break - } + i, found := m.PublicsIndex[myKey.Bytes] + if found { + m.SetBit(i, true) + found = true } if !found { return nil, errors.New("key not found") @@ -191,21 +196,19 @@ func (m *Mask) IndexEnabled(i int) (bool, error) { // KeyEnabled checks whether the index, corresponding to the given key, is // enabled in the Bitmap or not. -func (m *Mask) KeyEnabled(public *bls.PublicKey) (bool, error) { - for i, key := range m.Publics { - if key.IsEqual(public) { - return m.IndexEnabled(i) - } +func (m *Mask) KeyEnabled(public SerializedPublicKey) (bool, error) { + i, found := m.PublicsIndex[public] + if found { + return m.IndexEnabled(i) } return false, errors.New("key not found") } // SetKey set the bit in the Bitmap for the given cosigner -func (m *Mask) SetKey(public *bls.PublicKey, enable bool) error { - for i, key := range m.Publics { - if key.IsEqual(public) { - return m.SetBit(i, enable) - } +func (m *Mask) SetKey(public SerializedPublicKey, enable bool) error { + i, found := m.PublicsIndex[public] + if found { + return m.SetBit(i, enable) } return errors.New("key not found") } diff --git a/crypto/bls/mask_test.go b/crypto/bls/mask_test.go index d1ec2ecd2..aa25dbed5 100644 --- a/crypto/bls/mask_test.go +++ b/crypto/bls/mask_test.go @@ -9,11 +9,14 @@ import ( // Test the basic functionality of a BLS multi-sig mask. func TestNewMask(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() - pubKey3 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey3 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, err := NewMask([]*bls.PublicKey{pubKey1, pubKey2, pubKey3}, pubKey1) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + pubKey3.Bytes.FromLibBLSPublicKey(pubKey3.Object) + mask, err := NewMask([]PublicKeyWrapper{pubKey1, pubKey2, pubKey3}, &pubKey1) if err != nil { test.Errorf("Failed to create a new Mask: %s", err) @@ -23,7 +26,7 @@ func TestNewMask(test *testing.T) { test.Errorf("Mask created with wrong size: %d", mask.Len()) } - enabled, err := mask.KeyEnabled(pubKey1) + enabled, err := mask.KeyEnabled(pubKey1.Bytes) if !enabled || err != nil { test.Errorf("My key pubKey1 should have been enabled: %s", err) } @@ -38,12 +41,17 @@ func TestNewMask(test *testing.T) { } func TestNewMaskWithAbsentPublicKey(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() - pubKey3 := RandPrivateKey().GetPublicKey() - pubKey4 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey3 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey4 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, err := NewMask([]*bls.PublicKey{pubKey1, pubKey2, pubKey3}, pubKey4) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + pubKey3.Bytes.FromLibBLSPublicKey(pubKey3.Object) + pubKey4.Bytes.FromLibBLSPublicKey(pubKey4.Object) + + mask, err := NewMask([]PublicKeyWrapper{pubKey1, pubKey2, pubKey3}, &pubKey4) if err == nil { test.Errorf("Failed to create a new Mask: %s", err) @@ -56,11 +64,14 @@ func TestNewMaskWithAbsentPublicKey(test *testing.T) { } func TestThreshHoldPolicy(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() - pubKey3 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey3 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, err := NewMask([]*bls.PublicKey{pubKey1, pubKey2, pubKey3}, pubKey1) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + pubKey3.Bytes.FromLibBLSPublicKey(pubKey3.Object) + mask, err := NewMask([]PublicKeyWrapper{pubKey1, pubKey2, pubKey3}, &pubKey1) if err != nil { test.Errorf("Failed to create a new Mask: %s", err) @@ -72,8 +83,8 @@ func TestThreshHoldPolicy(test *testing.T) { threshHoldPolicy := *NewThresholdPolicy(1) - mask.SetKey(pubKey1, true) - mask.SetKey(pubKey2, true) + mask.SetKey(pubKey1.Bytes, true) + mask.SetKey(pubKey2.Bytes, true) if mask.CountEnabled() != 2 { test.Errorf("Number of enabled nodes: %d , expected count = 2 ", mask.CountEnabled()) @@ -83,8 +94,8 @@ func TestThreshHoldPolicy(test *testing.T) { test.Error("Number of enabled nodes less than threshold") } - mask.SetKey(pubKey1, false) - mask.SetKey(pubKey2, false) + mask.SetKey(pubKey1.Bytes, false) + mask.SetKey(pubKey2.Bytes, false) if threshHoldPolicy.Check(mask) { test.Error("Number of enabled nodes more than equal to threshold") @@ -92,11 +103,14 @@ func TestThreshHoldPolicy(test *testing.T) { } func TestCompletePolicy(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() - pubKey3 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey3 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, err := NewMask([]*bls.PublicKey{pubKey1, pubKey2, pubKey3}, pubKey1) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + pubKey3.Bytes.FromLibBLSPublicKey(pubKey3.Object) + mask, err := NewMask([]PublicKeyWrapper{pubKey1, pubKey2, pubKey3}, &pubKey1) if err != nil { test.Errorf("Failed to create a new Mask: %s", err) @@ -108,9 +122,9 @@ func TestCompletePolicy(test *testing.T) { completePolicy := CompletePolicy{} - mask.SetKey(pubKey1, true) - mask.SetKey(pubKey2, true) - mask.SetKey(pubKey3, true) + mask.SetKey(pubKey1.Bytes, true) + mask.SetKey(pubKey2.Bytes, true) + mask.SetKey(pubKey3.Bytes, true) if mask.CountEnabled() != 3 { test.Errorf("Number of enabled nodes: %d , expected count = 3 ", mask.CountEnabled()) @@ -120,7 +134,7 @@ func TestCompletePolicy(test *testing.T) { test.Error("Number of enabled nodes not equal to total count") } - mask.SetKey(pubKey1, false) + mask.SetKey(pubKey1.Bytes, false) if completePolicy.Check(mask) { test.Error("Number of enabled nodes equal to total count") @@ -161,12 +175,16 @@ func TestAggregateMasks(test *testing.T) { } func TestEnableKeyFunctions(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() - pubKey3 := RandPrivateKey().GetPublicKey() - pubKey4 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey3 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey4 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, err := NewMask([]*bls.PublicKey{pubKey1, pubKey2, pubKey3}, pubKey1) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + pubKey3.Bytes.FromLibBLSPublicKey(pubKey3.Object) + pubKey4.Bytes.FromLibBLSPublicKey(pubKey4.Object) + mask, err := NewMask([]PublicKeyWrapper{pubKey1, pubKey2, pubKey3}, &pubKey1) if err != nil { test.Errorf("Failed to create a new Mask: %s", err) @@ -197,7 +215,7 @@ func TestEnableKeyFunctions(test *testing.T) { test.Error("Count of disabled keys don't match") } - if _, error := mask.KeyEnabled(pubKey4); error == nil { + if _, error := mask.KeyEnabled(pubKey4.Bytes); error == nil { test.Error("Expected key not found error") } @@ -205,16 +223,18 @@ func TestEnableKeyFunctions(test *testing.T) { test.Error("Expected index out of range error") } - if err := mask.SetKey(pubKey4, true); err == nil { + if err := mask.SetKey(pubKey4.Bytes, true); err == nil { test.Error("Expected key nout found error") } } func TestCopyParticipatingMask(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, _ := NewMask([]*bls.PublicKey{pubKey1, pubKey2}, pubKey1) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + mask, _ := NewMask([]PublicKeyWrapper{pubKey1, pubKey2}, &pubKey1) clonedMask := mask.Mask() @@ -225,10 +245,12 @@ func TestCopyParticipatingMask(test *testing.T) { } func TestSetMask(test *testing.T) { - pubKey1 := RandPrivateKey().GetPublicKey() - pubKey2 := RandPrivateKey().GetPublicKey() + pubKey1 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} + pubKey2 := PublicKeyWrapper{Object: RandPrivateKey().GetPublicKey()} - mask, _ := NewMask([]*bls.PublicKey{pubKey1, pubKey2}, pubKey1) + pubKey1.Bytes.FromLibBLSPublicKey(pubKey1.Object) + pubKey2.Bytes.FromLibBLSPublicKey(pubKey2.Object) + mask, _ := NewMask([]PublicKeyWrapper{pubKey1, pubKey2}, &pubKey1) _ = mask maskBytes := []byte{3} diff --git a/hmy/api_backend.go b/hmy/api_backend.go index 216557a25..584002ade 100644 --- a/hmy/api_backend.go +++ b/hmy/api_backend.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" - bls_core "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/api/proto" "github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/consensus/quorum" @@ -900,9 +899,10 @@ func (b *APIBackend) GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumbe if err != nil { return nil, nil, err } - pubkeys := make([]*bls_core.PublicKey, len(committee.Slots)) - for i, validator := range committee.Slots { - if pubkeys[i], err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { + pubkeys := make([]internal_bls.PublicKeyWrapper, len(committee.Slots)) + for _, validator := range committee.Slots { + wrapper := internal_bls.PublicKeyWrapper{Bytes: validator.BLSPublicKey} + if wrapper.Object, err = bls.BytesToBLSPublicKey(wrapper.Bytes[:]); err != nil { return nil, nil, err } } diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 6f0e5036b..910b24bd7 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -5,8 +5,9 @@ import ( "math/big" "sort" + harmony_bls "github.com/harmony-one/harmony/crypto/bls" + "github.com/ethereum/go-ethereum/common" - "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/consensus/engine" "github.com/harmony-one/harmony/consensus/quorum" @@ -79,7 +80,7 @@ func (e *engineImpl) VerifyHeaders(chain engine.ChainReader, headers []*block.He // ReadPublicKeysFromLastBlock finds the public keys of last block's committee func ReadPublicKeysFromLastBlock( bc engine.ChainReader, header *block.Header, -) ([]*bls.PublicKey, error) { +) ([]harmony_bls.PublicKeyWrapper, error) { parentHeader := bc.GetHeaderByHash(header.ParentHash()) return GetPublicKeys(bc, parentHeader, false) } @@ -516,7 +517,7 @@ func (e *engineImpl) VerifyHeaderWithSignature(chain engine.ChainReader, header // GetPublicKeys finds the public keys of the committee that signed the block header func GetPublicKeys( chain engine.ChainReader, header *block.Header, reCalculate bool, -) ([]*bls.PublicKey, error) { +) ([]harmony_bls.PublicKeyWrapper, error) { if header == nil { return nil, errors.New("nil header provided") } diff --git a/internal/chain/sig.go b/internal/chain/sig.go index aa4f84be6..38d2b461d 100644 --- a/internal/chain/sig.go +++ b/internal/chain/sig.go @@ -10,7 +10,7 @@ import ( ) // ReadSignatureBitmapByPublicKeys read the payload of signature and bitmap based on public keys -func ReadSignatureBitmapByPublicKeys(recvPayload []byte, publicKeys []*bls_core.PublicKey) (*bls_core.Sign, *bls.Mask, error) { +func ReadSignatureBitmapByPublicKeys(recvPayload []byte, publicKeys []bls.PublicKeyWrapper) (*bls_core.Sign, *bls.Mask, error) { if len(recvPayload) < 96 { return nil, nil, errors.New("payload not have enough length") } diff --git a/internal/hmyapi/apiv1/blockchain.go b/internal/hmyapi/apiv1/blockchain.go index c76b8cb78..b5c07139b 100644 --- a/internal/hmyapi/apiv1/blockchain.go +++ b/internal/hmyapi/apiv1/blockchain.go @@ -6,13 +6,10 @@ import ( "math/big" "time" - "github.com/harmony-one/harmony/crypto/bls" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/rpc" - bls_core "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/consensus/quorum" @@ -268,11 +265,7 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr rpc.B if err != nil { return nil, err } - blsPublicKey := new(bls_core.PublicKey) - if blsPublicKey, err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { - return nil, err - } - if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok { + if ok, err := mask.KeyEnabled(validator.BLSPublicKey); err == nil && ok { signers = append(signers, oneAddress) } } @@ -293,11 +286,7 @@ func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr rp } signers := []string{} for _, validator := range slots { - blsPublicKey := new(bls_core.PublicKey) - if blsPublicKey, err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { - return nil, err - } - if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok { + if ok, err := mask.KeyEnabled(validator.BLSPublicKey); err == nil && ok { signers = append(signers, validator.BLSPublicKey.Hex()) } } @@ -324,11 +313,7 @@ func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr rpc.Blo if oneAddress != address { continue } - blsPublicKey := new(bls_core.PublicKey) - if blsPublicKey, err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { - return false, err - } - if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok { + if ok, err := mask.KeyEnabled(validator.BLSPublicKey); err == nil && ok { return true, nil } } diff --git a/internal/hmyapi/apiv2/blockchain.go b/internal/hmyapi/apiv2/blockchain.go index aa403e676..80f044eb1 100644 --- a/internal/hmyapi/apiv2/blockchain.go +++ b/internal/hmyapi/apiv2/blockchain.go @@ -6,13 +6,10 @@ import ( "math/big" "time" - "github.com/harmony-one/harmony/crypto/bls" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/rpc" - bls_core "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/consensus/quorum" @@ -229,11 +226,7 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr uint6 if err != nil { return nil, err } - blsPublicKey := new(bls_core.PublicKey) - if blsPublicKey, err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { - return nil, err - } - if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok { + if ok, err := mask.KeyEnabled(validator.BLSPublicKey); err == nil && ok { signers = append(signers, oneAddress) } } @@ -254,11 +247,7 @@ func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr ui } signers := []string{} for _, validator := range slots { - blsPublicKey := new(bls_core.PublicKey) - if blsPublicKey, err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { - return nil, err - } - if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok { + if ok, err := mask.KeyEnabled(validator.BLSPublicKey); err == nil && ok { signers = append(signers, validator.BLSPublicKey.Hex()) } } @@ -285,11 +274,7 @@ func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr uint64, if oneAddress != address { continue } - blsPublicKey := new(bls_core.PublicKey) - if blsPublicKey, err = bls.BytesToBLSPublicKey(validator.BLSPublicKey[:]); err != nil { - return false, err - } - if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok { + if ok, err := mask.KeyEnabled(validator.BLSPublicKey); err == nil && ok { return true, nil } } diff --git a/node/node.go b/node/node.go index 77024bbb7..bbf9877a7 100644 --- a/node/node.go +++ b/node/node.go @@ -919,7 +919,7 @@ func (node *Node) InitConsensusWithValidators() (err error) { } for _, key := range pubKeys { - if node.Consensus.GetPublicKeys().Contains(key) { + if node.Consensus.GetPublicKeys().Contains(key.Object) { utils.Logger().Info(). Uint64("blockNum", blockNum). Int("numPubKeys", len(pubKeys)). diff --git a/node/node_handler.go b/node/node_handler.go index 60cb33146..52ab892bf 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -6,8 +6,6 @@ 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" @@ -375,12 +373,8 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) error { func (node *Node) numSignaturesIncludedInBlock(block *types.Block) uint32 { count := uint32(0) 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) + mask, err := internal_bls.NewMask(members, nil) if err != nil { return count } @@ -389,7 +383,7 @@ func (node *Node) numSignaturesIncludedInBlock(block *types.Block) uint32 { return count } for _, key := range node.Consensus.GetPublicKeys() { - if ok, err := mask.KeyEnabled(key.Object); err == nil && ok { + if ok, err := mask.KeyEnabled(key.Bytes); err == nil && ok { count++ } } diff --git a/shard/shard_state.go b/shard/shard_state.go index c7c6c645b..74edeff36 100644 --- a/shard/shard_state.go +++ b/shard/shard_state.go @@ -7,7 +7,6 @@ import ( "math/big" "sort" - bls_core "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/crypto/bls" "github.com/ethereum/go-ethereum/common" @@ -328,19 +327,19 @@ func (c *Committee) Hash() common.Hash { } // BLSPublicKeys .. -func (c *Committee) BLSPublicKeys() ([]*bls_core.PublicKey, error) { +func (c *Committee) BLSPublicKeys() ([]bls.PublicKeyWrapper, error) { if c == nil { return nil, ErrSubCommitteeNil } - slice := make([]*bls_core.PublicKey, len(c.Slots)) + slice := make([]bls.PublicKeyWrapper, len(c.Slots)) for j := range c.Slots { pubKey, err := bls.BytesToBLSPublicKey(c.Slots[j].BLSPublicKey[:]) if err != nil { return nil, err } - slice[j] = pubKey + slice[j] = bls.PublicKeyWrapper{c.Slots[j].BLSPublicKey, pubKey} } return slice, nil