aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2019-04-04 12:15:06 +0800
committerWei-Ning Huang <w@dexon.org>2019-04-04 12:15:06 +0800
commit0475adf7692697df91d359d67f7298574adfe327 (patch)
tree7c1dae7d4e8690ecd2b2097233bd534db0fb93ca
parentab2d2d131cadb28a59b51dc5d1142ef8845e2f88 (diff)
downloaddexon-consensus-0475adf7692697df91d359d67f7298574adfe327.tar
dexon-consensus-0475adf7692697df91d359d67f7298574adfe327.tar.gz
dexon-consensus-0475adf7692697df91d359d67f7298574adfe327.tar.bz2
dexon-consensus-0475adf7692697df91d359d67f7298574adfe327.tar.lz
dexon-consensus-0475adf7692697df91d359d67f7298574adfe327.tar.xz
dexon-consensus-0475adf7692697df91d359d67f7298574adfe327.tar.zst
dexon-consensus-0475adf7692697df91d359d67f7298574adfe327.zip
core/crypto/dkg: concurrent access for gpk (#548)
* core/crypto/dkg: add benchmark * core/crypto/dkg: concurrent access for gpk
-rw-r--r--core/crypto/dkg/dkg.go64
-rw-r--r--core/crypto/dkg/dkg_test.go73
-rw-r--r--core/db/level-db_test.go8
-rw-r--r--core/dkg-tsig-protocol.go2
-rw-r--r--core/dkg-tsig-protocol_test.go10
-rw-r--r--core/test/app_test.go2
-rw-r--r--core/test/governance_test.go2
-rw-r--r--core/test/state_test.go2
-rw-r--r--core/types/dkg/dkg.go2
-rw-r--r--core/types/dkg/dkg_test.go4
-rw-r--r--core/utils/crypto_test.go2
-rw-r--r--core/utils/penalty-helper_test.go2
-rw-r--r--core/utils/utils_test.go2
-rw-r--r--integration_test/round-event_test.go2
14 files changed, 133 insertions, 44 deletions
diff --git a/core/crypto/dkg/dkg.go b/core/crypto/dkg/dkg.go
index 796609d..b89ad10 100644
--- a/core/crypto/dkg/dkg.go
+++ b/core/crypto/dkg/dkg.go
@@ -21,6 +21,8 @@ import (
"encoding/json"
"fmt"
"io"
+ "sync"
+ "sync/atomic"
"github.com/dexon-foundation/bls/ffi/go/bls"
"github.com/dexon-foundation/dexon/rlp"
@@ -210,23 +212,30 @@ func (prvs *PrivateKeyShares) DecodeRLP(s *rlp.Stream) error {
return nil
}
+type publicKeySharesCache struct {
+ share []PublicKey
+ index map[ID]int
+}
+
// PublicKeyShares represents a public key shares for DKG protocol.
type PublicKeyShares struct {
- shareCaches []PublicKey
- shareCacheIndex map[ID]int
+ cache atomic.Value
+ lock sync.Mutex
masterPublicKey []bls.PublicKey
}
// Equal checks equality of two PublicKeyShares instance.
func (pubs *PublicKeyShares) Equal(other *PublicKeyShares) bool {
+ cache := pubs.cache.Load().(*publicKeySharesCache)
+ cacheOther := other.cache.Load().(*publicKeySharesCache)
// Check shares.
- for dID, idx := range pubs.shareCacheIndex {
- otherIdx, exists := other.shareCacheIndex[dID]
+ for dID, idx := range cache.index {
+ otherIdx, exists := cacheOther.index[dID]
if !exists {
continue
}
- if !pubs.shareCaches[idx].publicKey.IsEqual(
- &other.shareCaches[otherIdx].publicKey) {
+ if !cache.share[idx].publicKey.IsEqual(
+ &cacheOther.share[otherIdx].publicKey) {
return false
}
}
@@ -267,7 +276,7 @@ func (pubs *PublicKeyShares) DecodeRLP(s *rlp.Stream) error {
ps.masterPublicKey = append(ps.masterPublicKey, key)
}
- *pubs = *ps
+ *pubs = *ps.Move()
return nil
}
@@ -349,13 +358,12 @@ func NewPrivateKeyShares(t int) (*PrivateKeyShares, *PublicKeyShares) {
prv.SetByCSPRNG()
msk := prv.GetMasterSecretKey(t)
mpk := bls.GetMasterPublicKey(msk)
+ pubShare := NewEmptyPublicKeyShares()
+ pubShare.masterPublicKey = mpk
return &PrivateKeyShares{
- masterPrivateKey: msk,
- shareIndex: make(map[ID]int),
- }, &PublicKeyShares{
- shareCacheIndex: make(map[ID]int),
- masterPublicKey: mpk,
- }
+ masterPrivateKey: msk,
+ shareIndex: make(map[ID]int),
+ }, pubShare
}
// NewEmptyPrivateKeyShares creates an empty private key shares.
@@ -442,16 +450,25 @@ func (prvs *PrivateKeyShares) Share(ID ID) (*PrivateKey, bool) {
// NewEmptyPublicKeyShares creates an empty public key shares.
func NewEmptyPublicKeyShares() *PublicKeyShares {
- return &PublicKeyShares{
- shareCacheIndex: make(map[ID]int),
+ cache := &publicKeySharesCache{
+ index: make(map[ID]int),
}
+ pubShares := &PublicKeyShares{}
+ pubShares.cache.Store(cache)
+ return pubShares
+}
+
+// Move will invalidate itself. Do not access to original reference.
+func (pubs *PublicKeyShares) Move() *PublicKeyShares {
+ return pubs
}
// Share returns the share for the ID.
func (pubs *PublicKeyShares) Share(ID ID) (*PublicKey, error) {
- idx, exist := pubs.shareCacheIndex[ID]
+ cache := pubs.cache.Load().(*publicKeySharesCache)
+ idx, exist := cache.index[ID]
if exist {
- return &pubs.shareCaches[idx], nil
+ return &cache.share[idx], nil
}
var pk PublicKey
if err := pk.publicKey.Set(pubs.masterPublicKey, &ID); err != nil {
@@ -465,14 +482,19 @@ func (pubs *PublicKeyShares) Share(ID ID) (*PublicKey, error) {
// AddShare adds a share.
func (pubs *PublicKeyShares) AddShare(ID ID, share *PublicKey) error {
- if idx, exist := pubs.shareCacheIndex[ID]; exist {
- if !share.publicKey.IsEqual(&pubs.shareCaches[idx].publicKey) {
+ cache := pubs.cache.Load().(*publicKeySharesCache)
+ if idx, exist := cache.index[ID]; exist {
+ if !share.publicKey.IsEqual(&cache.share[idx].publicKey) {
return ErrDuplicatedShare
}
return nil
}
- pubs.shareCacheIndex[ID] = len(pubs.shareCaches)
- pubs.shareCaches = append(pubs.shareCaches, *share)
+ pubs.lock.Lock()
+ defer pubs.lock.Unlock()
+ cache = pubs.cache.Load().(*publicKeySharesCache)
+ cache.index[ID] = len(cache.share)
+ cache.share = append(cache.share, *share)
+ pubs.cache.Store(cache)
return nil
}
diff --git a/core/crypto/dkg/dkg_test.go b/core/crypto/dkg/dkg_test.go
index f278932..a679cf4 100644
--- a/core/crypto/dkg/dkg_test.go
+++ b/core/crypto/dkg/dkg_test.go
@@ -307,11 +307,10 @@ func (s *DKGTestSuite) TestPrivateKeyRLPEncodeDecode() {
func (s *DKGTestSuite) TestPublicKeySharesRLPEncodeDecode() {
p := NewEmptyPublicKeyShares()
- for i, id := range s.genID(1) {
+ for _, id := range s.genID(1) {
privkey := NewPrivateKey()
pubkey := privkey.PublicKey().(PublicKey)
- p.shareCaches = append(p.shareCaches, pubkey)
- p.shareCacheIndex[id] = i
+ p.AddShare(id, &pubkey)
p.masterPublicKey = append(p.masterPublicKey, pubkey.publicKey)
}
@@ -371,6 +370,30 @@ func (s *DKGTestSuite) TestPublicKeySharesEquality() {
req.True(pubShares2.Equal(pubShares1))
}
+func (s *DKGTestSuite) TestPublicKeySharesMove() {
+ var req = s.Require()
+ IDs := s.genID(2)
+ _, pubShares1 := NewPrivateKeyShares(4)
+ // Make a copy from an empty share.
+ pubShares2 := pubShares1.Clone()
+ req.True(pubShares1.Equal(pubShares2))
+ // Move from pubShare1.
+ pubShares3 := pubShares1.Move()
+ // Add two shares.
+ prvKey1 := NewPrivateKey()
+ pubKey1 := prvKey1.PublicKey().(PublicKey)
+ req.NoError(pubShares3.AddShare(IDs[0], &pubKey1))
+ prvKey2 := NewPrivateKey()
+ pubKey2 := prvKey2.PublicKey().(PublicKey)
+ req.True(pubShares3.Equal(pubShares2))
+ // Clone the shares.
+ req.NoError(pubShares2.AddShare(IDs[0], &pubKey1))
+ req.NoError(pubShares2.AddShare(IDs[1], &pubKey2))
+ // They should be equal now.
+ req.True(pubShares3.Equal(pubShares2))
+ req.True(pubShares2.Equal(pubShares3))
+}
+
func (s *DKGTestSuite) TestPrivateKeySharesEquality() {
var req = s.Require()
IDs := s.genID(2)
@@ -578,3 +601,47 @@ func BenchmarkDKGProtocol(b *testing.B) {
}
})
}
+
+func BenchmarkGPKShare81_121(b *testing.B) { benchmarkGPKShare(b, 81, 121) }
+
+func benchmarkGPKShare(b *testing.B, t, n int) {
+ _, pubShare := NewPrivateKeyShares(t)
+ IDs := make(IDs, n)
+ for i := range IDs {
+ id := common.NewRandomHash()
+ IDs[i] = NewID(id[:])
+ }
+
+ for _, id := range IDs {
+ _, err := pubShare.Share(id)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ for _, id := range IDs {
+ pubShare.Share(id)
+ }
+ }
+}
+
+func BenchmarkGPKAddShare81_121(b *testing.B) { benchmarkGPKAddShare(b, 81, 121) }
+
+func benchmarkGPKAddShare(b *testing.B, t, n int) {
+ IDs := make(IDs, n)
+ for i := range IDs {
+ id := common.NewRandomHash()
+ IDs[i] = NewID(id[:])
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ _, pubShare := NewPrivateKeyShares(t)
+ b.StartTimer()
+ for _, id := range IDs {
+ pubShare.Share(id)
+ }
+ }
+}
diff --git a/core/db/level-db_test.go b/core/db/level-db_test.go
index d7f70bc..78e3b77 100644
--- a/core/db/level-db_test.go
+++ b/core/db/level-db_test.go
@@ -214,8 +214,8 @@ func (s *LevelDBTestSuite) TestDKGProtocolInfoRLPEncodeDecode() {
types.NodeID{Hash: common.Hash{0x02}}: dkg.ID{},
},
MpkMap: NodeIDToPubShares{
- types.NodeID{Hash: common.Hash{0x01}}: &dkg.PublicKeyShares{},
- types.NodeID{Hash: common.Hash{0x02}}: &dkg.PublicKeyShares{},
+ types.NodeID{Hash: common.Hash{0x01}}: dkg.NewEmptyPublicKeyShares(),
+ types.NodeID{Hash: common.Hash{0x02}}: dkg.NewEmptyPublicKeyShares(),
},
AntiComplaintReceived: NodeIDToNodeIDs{
types.NodeID{Hash: common.Hash{0x01}}: map[types.NodeID]struct{}{
@@ -278,8 +278,8 @@ func (s *LevelDBTestSuite) TestNodeIDRLPEncodeDecode() {
func (s *LevelDBTestSuite) TestNodeIDToPubSharesRLPEncodeDecode() {
m := NodeIDToPubShares{
- types.NodeID{Hash: common.Hash{0x01}}: &dkg.PublicKeyShares{},
- types.NodeID{Hash: common.Hash{0x02}}: &dkg.PublicKeyShares{},
+ types.NodeID{Hash: common.Hash{0x01}}: dkg.NewEmptyPublicKeyShares(),
+ types.NodeID{Hash: common.Hash{0x02}}: dkg.NewEmptyPublicKeyShares(),
}
b, err := rlp.EncodeToBytes(&m)
diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go
index e4ae14c..0612bda 100644
--- a/core/dkg-tsig-protocol.go
+++ b/core/dkg-tsig-protocol.go
@@ -230,7 +230,7 @@ func newDKGProtocol(
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(ID),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
})
return &dkgProtocol{
diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go
index f6909e8..89fd105 100644
--- a/core/dkg-tsig-protocol_test.go
+++ b/core/dkg-tsig-protocol_test.go
@@ -294,7 +294,7 @@ func (s *DKGTSIGProtocolTestSuite) TestErrMPKRegistered() {
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(ID),
- PublicKeyShares: *mpk,
+ PublicKeyShares: *mpk.Move(),
})
}
gov.AddDKGMasterPublicKey(receiver.mpk)
@@ -995,7 +995,7 @@ func (s *DKGTSIGProtocolTestSuite) TestUnexpectedDKGResetCount() {
Round: round,
Reset: reset + 1,
DKGID: typesDKG.NewID(sourceID),
- PublicKeyShares: *mpk,
+ PublicKeyShares: *mpk.Move(),
})
err = protocols[sourceID].processMasterPublicKeys(
[]*typesDKG.MasterPublicKey{receivers[sourceID].mpk})
@@ -1031,7 +1031,7 @@ func benchmarkDKGGroupPubliKey(k, n int, b *testing.B) {
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(types.NewNodeID(pk)),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
})
}
@@ -1075,7 +1075,7 @@ func benchmarkDKGNodePubliKeys(k, n int, b *testing.B) {
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(types.NewNodeID(pk)),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
})
}
@@ -1119,7 +1119,7 @@ func benchmarkCalcQualified(k, n int, b *testing.B) {
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(types.NewNodeID(pk)),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
})
}
diff --git a/core/test/app_test.go b/core/test/app_test.go
index 574604c..828a3c3 100644
--- a/core/test/app_test.go
+++ b/core/test/app_test.go
@@ -82,7 +82,7 @@ func (s *AppTestSuite) proposeMPK(
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(types.NewNodeID(pubKey)),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
}
s.Require().NoError(s.signers[idx].SignDKGMasterPublicKey(mpk))
gov.AddDKGMasterPublicKey(mpk)
diff --git a/core/test/governance_test.go b/core/test/governance_test.go
index 474ec80..e075638 100644
--- a/core/test/governance_test.go
+++ b/core/test/governance_test.go
@@ -130,7 +130,7 @@ func (s *GovernanceTestSuite) TestProhibit() {
mpk := &typesDKG.MasterPublicKey{
Round: round,
DKGID: typesDKG.NewID(types.NewNodeID(k.PublicKey())),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
}
s.Require().NoError(signer.SignDKGMasterPublicKey(mpk))
gov.AddDKGMasterPublicKey(mpk)
diff --git a/core/test/state_test.go b/core/test/state_test.go
index 5ad5a3e..e3ed9bb 100644
--- a/core/test/state_test.go
+++ b/core/test/state_test.go
@@ -50,7 +50,7 @@ func (s *StateTestSuite) newDKGMasterPublicKey(
Round: round,
Reset: reset,
DKGID: dID,
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
}
}
diff --git a/core/types/dkg/dkg.go b/core/types/dkg/dkg.go
index e9b22bc..868f0da 100644
--- a/core/types/dkg/dkg.go
+++ b/core/types/dkg/dkg.go
@@ -130,7 +130,7 @@ func (d *MasterPublicKey) DecodeRLP(s *rlp.Stream) error {
Round: dec.Round,
Reset: dec.Reset,
DKGID: id,
- PublicKeyShares: *dec.PublicKeyShares,
+ PublicKeyShares: *dec.PublicKeyShares.Move(),
Signature: dec.Signature,
}
return err
diff --git a/core/types/dkg/dkg_test.go b/core/types/dkg/dkg_test.go
index ec16a2b..9f50feb 100644
--- a/core/types/dkg/dkg_test.go
+++ b/core/types/dkg/dkg_test.go
@@ -63,7 +63,7 @@ func (s *DKGTestSuite) TestRLPEncodeDecode() {
Round: 10,
Reset: 11,
DKGID: dID,
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Clone(),
Signature: crypto.Signature{
Type: "123",
Signature: []byte{4, 5, 6},
@@ -189,7 +189,7 @@ func (s *DKGTestSuite) TestMasterPublicKeyEquality() {
pubKey := prvKey.PublicKey().(cryptoDKG.PublicKey)
_, pubShares := cryptoDKG.NewPrivateKeyShares(2)
req.NoError(pubShares.AddShare(s.genID(), &pubKey))
- master1.PublicKeyShares = *pubShares
+ master1.PublicKeyShares = *pubShares.Move()
// Prepare another master public key by copying every field.
master2 := &MasterPublicKey{}
s.clone(master1, master2)
diff --git a/core/utils/crypto_test.go b/core/utils/crypto_test.go
index 061f250..5dfd82b 100644
--- a/core/utils/crypto_test.go
+++ b/core/utils/crypto_test.go
@@ -179,7 +179,7 @@ func (s *CryptoTestSuite) TestDKGSignature() {
Round: 5,
Reset: 6,
DKGID: id,
- PublicKeyShares: *pkShare,
+ PublicKeyShares: *pkShare.Move(),
}
mpk.Signature, err = prv.Sign(hashDKGMasterPublicKey(mpk))
s.Require().NoError(err)
diff --git a/core/utils/penalty-helper_test.go b/core/utils/penalty-helper_test.go
index 7b61781..3e4f8b5 100644
--- a/core/utils/penalty-helper_test.go
+++ b/core/utils/penalty-helper_test.go
@@ -52,7 +52,7 @@ func (s *PenaltyHelperTestSuite) TestDKGComplaint() {
mpk := &typesDKG.MasterPublicKey{
ProposerID: nID1,
DKGID: typesDKG.NewID(nID1),
- PublicKeyShares: *pubShares,
+ PublicKeyShares: *pubShares.Move(),
}
mpk.Signature, err = prv1.Sign(hashDKGMasterPublicKey(mpk))
s.Require().NoError(err)
diff --git a/core/utils/utils_test.go b/core/utils/utils_test.go
index 70f6e98..c3afea9 100644
--- a/core/utils/utils_test.go
+++ b/core/utils/utils_test.go
@@ -53,7 +53,7 @@ func (s *UtilsTestSuite) TestVerifyDKGComplaint() {
mpk := &typesDKG.MasterPublicKey{
ProposerID: nID1,
DKGID: typesDKG.NewID(nID1),
- PublicKeyShares: *pubShares,
+ PublicKeyShares: *pubShares.Move(),
}
mpk.Signature, err = prv1.Sign(hashDKGMasterPublicKey(mpk))
s.Require().NoError(err)
diff --git a/integration_test/round-event_test.go b/integration_test/round-event_test.go
index f83a437..dca0834 100644
--- a/integration_test/round-event_test.go
+++ b/integration_test/round-event_test.go
@@ -82,7 +82,7 @@ func (s *RoundEventTestSuite) proposeMPK(
Round: round,
Reset: reset,
DKGID: typesDKG.NewID(types.NewNodeID(pubKey)),
- PublicKeyShares: *pubShare,
+ PublicKeyShares: *pubShare.Move(),
}
s.Require().NoError(s.signers[idx].SignDKGMasterPublicKey(mpk))
gov.AddDKGMasterPublicKey(mpk)