aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-09-26 11:46:48 +0800
committerGitHub <noreply@github.com>2018-09-26 11:46:48 +0800
commit616e2d8d864d48593c90c2438dce187d42ca875c (patch)
tree54449307979c0a7b7dbe16cd185786c776ddf209
parenta79c10ff1f4717e7e26096f81a57df10b8c9a592 (diff)
downloaddexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.tar
dexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.tar.gz
dexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.tar.bz2
dexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.tar.lz
dexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.tar.xz
dexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.tar.zst
dexon-consensus-616e2d8d864d48593c90c2438dce187d42ca875c.zip
core: configuration chain test (#137)
-rw-r--r--core/configuration-chain.go8
-rw-r--r--core/configuration-chain_test.go213
-rw-r--r--core/consensus.go2
-rw-r--r--core/types/dkg.go7
-rw-r--r--simulation/marshaller.go5
5 files changed, 226 insertions, 9 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go
index 88232c6..a6c0f39 100644
--- a/core/configuration-chain.go
+++ b/core/configuration-chain.go
@@ -168,7 +168,7 @@ func (cc *configurationChain) preparePartialSignature(
}
func (cc *configurationChain) runBlockTSig(
- round uint64, hash common.Hash) error {
+ round uint64, hash common.Hash) (crypto.Signature, error) {
gpk, exist := func() (*dkgGroupPublicKey, bool) {
cc.dkgResult.RLock()
defer cc.dkgResult.RUnlock()
@@ -176,7 +176,7 @@ func (cc *configurationChain) runBlockTSig(
return gpk, exist
}()
if !exist {
- return ErrDKGNotReady
+ return nil, ErrDKGNotReady
}
cc.tsigReady.L.Lock()
defer cc.tsigReady.L.Unlock()
@@ -200,10 +200,10 @@ func (cc *configurationChain) runBlockTSig(
}
cc.tsig = nil
if err != nil {
- return err
+ return nil, err
}
log.Printf("[%s] TSIG: %s\n", cc.ID, signature)
- return nil
+ return signature, nil
}
func (cc *configurationChain) processPrivateShare(
diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go
new file mode 100644
index 0000000..ae82e42
--- /dev/null
+++ b/core/configuration-chain_test.go
@@ -0,0 +1,213 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+ "encoding/json"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/suite"
+
+ "github.com/dexon-foundation/dexon-consensus-core/core/test"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto/dkg"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto/eth"
+)
+
+type ConfigurationChainTestSuite struct {
+ suite.Suite
+
+ nIDs types.NodeIDs
+ dkgIDs map[types.NodeID]dkg.ID
+ prvKeys map[types.NodeID]crypto.PrivateKey
+}
+
+type testCCReceiver struct {
+ s *ConfigurationChainTestSuite
+
+ nodes map[types.NodeID]*configurationChain
+ govs map[types.NodeID]Governance
+}
+
+func newTestCCReceiver(
+ s *ConfigurationChainTestSuite) *testCCReceiver {
+ return &testCCReceiver{
+ s: s,
+ nodes: make(map[types.NodeID]*configurationChain),
+ govs: make(map[types.NodeID]Governance),
+ }
+}
+
+func (r *testCCReceiver) ProposeDKGComplaint(complaint *types.DKGComplaint) {
+ prvKey, exist := r.s.prvKeys[complaint.ProposerID]
+ r.s.Require().True(exist)
+ var err error
+ complaint.Signature, err = prvKey.Sign(hashDKGComplaint(complaint))
+ r.s.Require().NoError(err)
+ for _, gov := range r.govs {
+ // Use Marshal/Unmarshal to do deep copy.
+ data, err := json.Marshal(complaint)
+ r.s.Require().NoError(err)
+ complaintCopy := &types.DKGComplaint{}
+ r.s.Require().NoError(json.Unmarshal(data, complaintCopy))
+ gov.AddDKGComplaint(complaintCopy)
+ }
+}
+
+func (r *testCCReceiver) ProposeDKGMasterPublicKey(
+ mpk *types.DKGMasterPublicKey) {
+ prvKey, exist := r.s.prvKeys[mpk.ProposerID]
+ r.s.Require().True(exist)
+ var err error
+ mpk.Signature, err = prvKey.Sign(hashDKGMasterPublicKey(mpk))
+ r.s.Require().NoError(err)
+ for _, gov := range r.govs {
+ // Use Marshal/Unmarshal to do deep copy.
+ data, err := json.Marshal(mpk)
+ r.s.Require().NoError(err)
+ mpkCopy := types.NewDKGMasterPublicKey()
+ r.s.Require().NoError(json.Unmarshal(data, mpkCopy))
+ gov.AddDKGMasterPublicKey(mpkCopy)
+ }
+}
+
+func (r *testCCReceiver) ProposeDKGPrivateShare(
+ prv *types.DKGPrivateShare) {
+ go func() {
+ prvKey, exist := r.s.prvKeys[prv.ProposerID]
+ r.s.Require().True(exist)
+ var err error
+ prv.Signature, err = prvKey.Sign(hashDKGPrivateShare(prv))
+ r.s.Require().NoError(err)
+ receiver, exist := r.nodes[prv.ReceiverID]
+ r.s.Require().True(exist)
+ err = receiver.processPrivateShare(prv)
+ r.s.Require().NoError(err)
+ }()
+}
+
+func (r *testCCReceiver) ProposeDKGAntiNackComplaint(
+ prv *types.DKGPrivateShare) {
+ go func() {
+ prvKey, exist := r.s.prvKeys[prv.ProposerID]
+ r.s.Require().True(exist)
+ var err error
+ prv.Signature, err = prvKey.Sign(hashDKGPrivateShare(prv))
+ r.s.Require().NoError(err)
+ for _, cc := range r.nodes {
+ err = cc.processPrivateShare(prv)
+ r.s.Require().NoError(err)
+ }
+ }()
+}
+
+func (s *ConfigurationChainTestSuite) setupNodes(n int) {
+ s.nIDs = make(types.NodeIDs, 0, n)
+ s.prvKeys = make(map[types.NodeID]crypto.PrivateKey, n)
+ s.dkgIDs = make(map[types.NodeID]dkg.ID)
+ ids := make(dkg.IDs, 0, n)
+ for i := 0; i < n; i++ {
+ prvKey, err := eth.NewPrivateKey()
+ s.Require().NoError(err)
+ nID := types.NewNodeID(prvKey.PublicKey())
+ s.nIDs = append(s.nIDs, nID)
+ s.prvKeys[nID] = prvKey
+ id := dkg.NewID(nID.Hash[:])
+ ids = append(ids, id)
+ s.dkgIDs[nID] = id
+ }
+}
+
+// TestConfigurationChain will test the entire DKG+TISG protocol including
+// exchanging private shares, recovering share secret, creating partial sign and
+// recovering threshold signature.
+// All participants are good people in this test.
+func (s *ConfigurationChainTestSuite) TestConfigurationChain() {
+ k := 3
+ n := 10
+ round := uint64(1)
+ s.setupNodes(n)
+
+ cfgChains := make(map[types.NodeID]*configurationChain)
+ recv := newTestCCReceiver(s)
+
+ for _, nID := range s.nIDs {
+ gov, err := test.NewGovernance(0, 50*time.Millisecond)
+ s.Require().NoError(err)
+ cfgChains[nID] = newConfigurationChain(nID, recv, gov, eth.SigToPub)
+ recv.nodes[nID] = cfgChains[nID]
+ recv.govs[nID] = gov
+ }
+
+ for _, cc := range cfgChains {
+ cc.registerDKG(round, k)
+ }
+
+ for _, gov := range recv.govs {
+ s.Require().Len(gov.DKGMasterPublicKeys(round), n)
+ }
+
+ wg := sync.WaitGroup{}
+ wg.Add(n)
+ for _, cc := range cfgChains {
+ go func(cc *configurationChain) {
+ defer wg.Done()
+ s.Require().NoError(cc.runDKG(round))
+ }(cc)
+ }
+ wg.Wait()
+
+ psigs := make([]*types.DKGPartialSignature, 0, n)
+ hash := crypto.Keccak256Hash([]byte("🌚🌝"))
+ for _, cc := range cfgChains {
+ psig, err := cc.preparePartialSignature(round, hash)
+ s.Require().NoError(err)
+ prvKey, exist := s.prvKeys[cc.ID]
+ s.Require().True(exist)
+ psig.Signature, err = prvKey.Sign(hashDKGPartialSignature(psig))
+ s.Require().NoError(err)
+ psigs = append(psigs, psig)
+ }
+
+ tsigs := make([]crypto.Signature, 0, n)
+ tsigChan := make(chan crypto.Signature)
+ for _, cc := range cfgChains {
+ go func(cc *configurationChain) {
+ tsig, err := cc.runBlockTSig(round, hash)
+ s.Require().NoError(err)
+ tsigChan <- tsig
+ }(cc)
+ for _, psig := range psigs {
+ err := cc.processPartialSignature(psig)
+ s.Require().NoError(err)
+ }
+ }
+ for range cfgChains {
+ tsig := <-tsigChan
+ for _, prevTsig := range tsigs {
+ s.Equal(prevTsig, tsig)
+ }
+ }
+}
+
+func TestConfigurationChain(t *testing.T) {
+ suite.Run(t, new(ConfigurationChainTestSuite))
+}
diff --git a/core/consensus.go b/core/consensus.go
index f6ce3de..c7eea32 100644
--- a/core/consensus.go
+++ b/core/consensus.go
@@ -411,7 +411,7 @@ func (con *Consensus) runDKGTSIG() {
panic(err)
}
con.network.BroadcastDKGPartialSignature(psig)
- if err = con.cfgModule.runBlockTSig(round, hash); err != nil {
+ if _, err = con.cfgModule.runBlockTSig(round, hash); err != nil {
panic(err)
}
}()
diff --git a/core/types/dkg.go b/core/types/dkg.go
index 10a31ee..a21c983 100644
--- a/core/types/dkg.go
+++ b/core/types/dkg.go
@@ -51,6 +51,13 @@ type DKGMasterPublicKey struct {
Signature crypto.Signature `json:"signature"`
}
+// NewDKGMasterPublicKey returns a new DKGMasterPublicKey instance.
+func NewDKGMasterPublicKey() *DKGMasterPublicKey {
+ return &DKGMasterPublicKey{
+ PublicKeyShares: *dkg.NewEmptyPublicKeyShares(),
+ }
+}
+
// DKGComplaint describe a complaint in DKG protocol.
type DKGComplaint struct {
ProposerID NodeID `json:"proposer_id"`
diff --git a/simulation/marshaller.go b/simulation/marshaller.go
index 08d67a9..f2d17af 100644
--- a/simulation/marshaller.go
+++ b/simulation/marshaller.go
@@ -22,7 +22,6 @@ import (
"fmt"
"github.com/dexon-foundation/dexon-consensus-core/core/types"
- "github.com/dexon-foundation/dexon-consensus-core/crypto/dkg"
)
// jsonMarshaller implements test.Marshaller to marshal simulation related
@@ -77,9 +76,7 @@ func (m *jsonMarshaller) Unmarshal(
}
msg = privateShare
case "dkg-master-public-key":
- masterPublicKey := &types.DKGMasterPublicKey{
- PublicKeyShares: *dkg.NewEmptyPublicKeyShares(),
- }
+ masterPublicKey := types.NewDKGMasterPublicKey()
if err = json.Unmarshal(payload, masterPublicKey); err != nil {
break
}