aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-09-26 09:55:08 +0800
committerGitHub <noreply@github.com>2018-09-26 09:55:08 +0800
commita79c10ff1f4717e7e26096f81a57df10b8c9a592 (patch)
tree69081c65669f0a68e7f27a81efffbacfb1983f10 /core
parent0ffea9dadcfc0d8a740942a2d666eccc00613cd4 (diff)
downloadtangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.tar
tangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.tar.gz
tangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.tar.bz2
tangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.tar.lz
tangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.tar.xz
tangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.tar.zst
tangerine-consensus-a79c10ff1f4717e7e26096f81a57df10b8c9a592.zip
core: run TSIG for first configuration block at startup (#135)
Diffstat (limited to 'core')
-rw-r--r--core/configuration-chain.go239
-rw-r--r--core/consensus.go77
-rw-r--r--core/consensus_test.go6
-rw-r--r--core/crypto.go4
-rw-r--r--core/dkg-tsig-protocol.go19
-rw-r--r--core/dkg-tsig-protocol_test.go25
-rw-r--r--core/interfaces.go11
-rw-r--r--core/test/governance.go15
-rw-r--r--core/types/config.go43
-rw-r--r--core/types/dkg.go18
-rw-r--r--core/utils.go28
11 files changed, 427 insertions, 58 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go
new file mode 100644
index 0000000..88232c6
--- /dev/null
+++ b/core/configuration-chain.go
@@ -0,0 +1,239 @@
+// 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 (
+ "fmt"
+ "log"
+ "sync"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
+)
+
+// Errors for configuration chain..
+var (
+ ErrDKGNotRegistered = fmt.Errorf(
+ "not yet registered in DKG protocol")
+ ErrDKGNotReady = fmt.Errorf(
+ "DKG is not ready")
+)
+
+type configurationChain struct {
+ ID types.NodeID
+ recv dkgReceiver
+ gov Governance
+ sigToPub SigToPubFn
+ dkg *dkgProtocol
+ dkgLock sync.RWMutex
+ dkgSigner map[uint64]*dkgShareSecret
+ gpk map[uint64]*dkgGroupPublicKey
+ dkgResult sync.RWMutex
+ tsig *tsigProtocol
+ tsigReady *sync.Cond
+ // TODO(jimmy-dexon): add timeout to pending psig.
+ pendingPsig []*types.DKGPartialSignature
+ prevHash common.Hash
+}
+
+func newConfigurationChain(
+ ID types.NodeID,
+ recv dkgReceiver,
+ gov Governance,
+ sigToPub SigToPubFn) *configurationChain {
+ return &configurationChain{
+ ID: ID,
+ recv: recv,
+ gov: gov,
+ sigToPub: sigToPub,
+ dkgSigner: make(map[uint64]*dkgShareSecret),
+ gpk: make(map[uint64]*dkgGroupPublicKey),
+ tsigReady: sync.NewCond(&sync.Mutex{}),
+ }
+}
+
+func (cc *configurationChain) registerDKG(round uint64, threshold int) {
+ cc.dkg = newDKGProtocol(
+ cc.ID,
+ cc.recv,
+ round,
+ threshold,
+ cc.sigToPub)
+}
+
+func (cc *configurationChain) runDKG(round uint64) error {
+ cc.dkgLock.Lock()
+ defer cc.dkgLock.Unlock()
+ if cc.dkg == nil || cc.dkg.round != round {
+ return ErrDKGNotRegistered
+ }
+ if func() bool {
+ cc.dkgResult.RLock()
+ defer cc.dkgResult.RUnlock()
+ _, exist := cc.gpk[round]
+ return exist
+ }() {
+ return nil
+ }
+
+ ticker := newTicker(cc.gov, TickerDKG)
+ cc.dkgLock.Unlock()
+ <-ticker.Tick()
+ cc.dkgLock.Lock()
+ // Phase 2(T = 0): Exchange DKG secret key share.
+ cc.dkg.processMasterPublicKeys(cc.gov.DKGMasterPublicKeys(round))
+ // Phase 3(T = 0~λ): Propose complaint.
+ // Propose complaint is done in `processMasterPublicKeys`.
+ cc.dkgLock.Unlock()
+ <-ticker.Tick()
+ cc.dkgLock.Lock()
+ // Phase 4(T = λ): Propose nack complaints.
+ cc.dkg.proposeNackComplaints()
+ cc.dkgLock.Unlock()
+ <-ticker.Tick()
+ cc.dkgLock.Lock()
+ // Phase 5(T = 2λ): Propose Anti nack complaint.
+ cc.dkg.processNackComplaints(cc.gov.DKGComplaints(round))
+ cc.dkgLock.Unlock()
+ <-ticker.Tick()
+ cc.dkgLock.Lock()
+ // Phase 6(T = 3λ): Rebroadcast anti nack complaint.
+ // Rebroadcast is done in `processPrivateShare`.
+ cc.dkgLock.Unlock()
+ <-ticker.Tick()
+ cc.dkgLock.Lock()
+ // Phase 7(T = 4λ): Enforce complaints and nack complaints.
+ cc.dkg.enforceNackComplaints(cc.gov.DKGComplaints(round))
+ // Enforce complaint is done in `processPrivateShare`.
+ // Phase 8(T = 5λ): DKG is ready.
+ cc.dkgLock.Unlock()
+ <-ticker.Tick()
+ cc.dkgLock.Lock()
+ gpk, err := newDKGGroupPublicKey(round,
+ cc.gov.DKGMasterPublicKeys(round),
+ cc.gov.DKGComplaints(round),
+ cc.dkg.threshold, cc.sigToPub)
+ if err != nil {
+ return err
+ }
+ signer, err := cc.dkg.recoverShareSecret(gpk.qualifyIDs)
+ if err != nil {
+ return err
+ }
+ qualifies := ""
+ for _, nID := range gpk.qualifyNodeIDs {
+ qualifies += fmt.Sprintf("%s ", nID.String()[:6])
+ }
+ log.Printf("[%s] Qualify Nodes(%d): %s\n",
+ cc.ID, len(gpk.qualifyIDs), qualifies)
+ cc.dkgResult.Lock()
+ defer cc.dkgResult.Unlock()
+ cc.dkgSigner[round] = signer
+ cc.gpk[round] = gpk
+ return nil
+}
+
+func (cc *configurationChain) preparePartialSignature(
+ round uint64, hash common.Hash) (*types.DKGPartialSignature, error) {
+ signer, exist := func() (*dkgShareSecret, bool) {
+ cc.dkgResult.RLock()
+ defer cc.dkgResult.RUnlock()
+ signer, exist := cc.dkgSigner[round]
+ return signer, exist
+ }()
+ if !exist {
+ return nil, ErrDKGNotReady
+ }
+ return &types.DKGPartialSignature{
+ ProposerID: cc.ID,
+ Round: round,
+ PartialSignature: signer.sign(hash),
+ }, nil
+}
+
+func (cc *configurationChain) runBlockTSig(
+ round uint64, hash common.Hash) error {
+ gpk, exist := func() (*dkgGroupPublicKey, bool) {
+ cc.dkgResult.RLock()
+ defer cc.dkgResult.RUnlock()
+ gpk, exist := cc.gpk[round]
+ return gpk, exist
+ }()
+ if !exist {
+ return ErrDKGNotReady
+ }
+ cc.tsigReady.L.Lock()
+ defer cc.tsigReady.L.Unlock()
+ cc.tsig = newTSigProtocol(gpk, hash, types.TSigConfigurationBlock)
+ pendingPsig := cc.pendingPsig
+ cc.pendingPsig = []*types.DKGPartialSignature{}
+ go func() {
+ for _, psig := range pendingPsig {
+ if err := cc.processPartialSignature(psig); err != nil {
+ log.Printf("[%s] %s", cc.ID, err)
+ }
+ }
+ }()
+ var signature crypto.Signature
+ var err error
+ for func() bool {
+ signature, err = cc.tsig.signature()
+ return err == ErrNotEnoughtPartialSignatures
+ }() {
+ cc.tsigReady.Wait()
+ }
+ cc.tsig = nil
+ if err != nil {
+ return err
+ }
+ log.Printf("[%s] TSIG: %s\n", cc.ID, signature)
+ return nil
+}
+
+func (cc *configurationChain) processPrivateShare(
+ prvShare *types.DKGPrivateShare) error {
+ cc.dkgLock.Lock()
+ defer cc.dkgLock.Unlock()
+ if cc.dkg == nil {
+ return nil
+ }
+ return cc.dkg.processPrivateShare(prvShare)
+}
+
+func (cc *configurationChain) processPartialSignature(
+ psig *types.DKGPartialSignature) error {
+ cc.tsigReady.L.Lock()
+ defer cc.tsigReady.L.Unlock()
+ if cc.tsig == nil {
+ ok, err := verifyDKGPartialSignatureSignature(psig, cc.sigToPub)
+ if err != nil {
+ return err
+ }
+ if !ok {
+ return ErrIncorrectPartialSignatureSignature
+ }
+ cc.pendingPsig = append(cc.pendingPsig, psig)
+ return nil
+ }
+ if err := cc.tsig.processPartialSignature(psig); err != nil {
+ return err
+ }
+ cc.tsigReady.Broadcast()
+ return nil
+}
diff --git a/core/consensus.go b/core/consensus.go
index fc7cd70..f6ce3de 100644
--- a/core/consensus.go
+++ b/core/consensus.go
@@ -186,7 +186,7 @@ type Consensus struct {
// DKG.
dkgRunning int32
dkgReady *sync.Cond
- dkgModule *dkgProtocol
+ cfgModule *configurationChain
// Dexon consensus modules.
rbModule *reliableBroadcast
@@ -243,8 +243,7 @@ func NewConsensus(
uint64(float32(len(notarySet)-1)*config.PhiRatio+1),
config.NumChains)
- // Setup DKG Protocol.
- dkgModule := newDKGProtocol(
+ cfgModule := newConfigurationChain(
ID,
&consensusDKGReceiver{
ID: ID,
@@ -252,9 +251,11 @@ func NewConsensus(
prvKey: prv,
network: network,
},
- 0,
- len(notarySet)/3,
+ gov,
sigToPub)
+ // Register DKG for the initial round. This is a temporary function call for
+ // simulation.
+ cfgModule.registerDKG(0, len(notarySet)/3)
// Check if the application implement Debug interface.
debug, _ := app.(Debug)
@@ -272,7 +273,7 @@ func NewConsensus(
tickerObj: newTicker(gov, TickerBA),
prvKey: prv,
dkgReady: sync.NewCond(&sync.Mutex{}),
- dkgModule: dkgModule,
+ cfgModule: cfgModule,
sigToPub: sigToPub,
notarySet: notarySet,
ctx: ctx,
@@ -308,7 +309,7 @@ func NewConsensus(
// Run starts running DEXON Consensus.
func (con *Consensus) Run() {
go con.processMsg(con.network.ReceiveChan(), con.PreProcessBlock)
- con.runDKG()
+ con.runDKGTSIG()
con.dkgReady.L.Lock()
defer con.dkgReady.L.Unlock()
for con.dkgRunning != 2 {
@@ -374,8 +375,8 @@ BALoop:
}
}
-// runDKG starts running DKG protocol.
-func (con *Consensus) runDKG() {
+// runDKGTSIG starts running DKG+TSIG protocol.
+func (con *Consensus) runDKGTSIG() {
con.dkgReady.L.Lock()
defer con.dkgReady.L.Unlock()
if con.dkgRunning != 0 {
@@ -389,40 +390,30 @@ func (con *Consensus) runDKG() {
con.dkgReady.Broadcast()
con.dkgRunning = 2
}()
- ticker := newTicker(con.gov, TickerDKG)
- round := con.dkgModule.round
- <-ticker.Tick()
- // Phase 2(T = 0): Exchange DKG secret key share.
- con.dkgModule.processMasterPublicKeys(con.gov.DKGMasterPublicKeys(round))
- // Phase 3(T = 0~λ): Propose complaint.
- // Propose complaint is done in `processMasterPublicKeys`.
- <-ticker.Tick()
- // Phase 4(T = λ): Propose nack complaints.
- con.dkgModule.proposeNackComplaints()
- <-ticker.Tick()
- // Phase 5(T = 2λ): Propose Anti nack complaint.
- con.dkgModule.processNackComplaints(con.gov.DKGComplaints(round))
- <-ticker.Tick()
- // Phase 6(T = 3λ): Rebroadcast anti nack complaint.
- // Rebroadcast is done in `processPrivateShare`.
- <-ticker.Tick()
- // Phase 7(T = 4λ): Enforce complaints and nack complaints.
- con.dkgModule.enforceNackComplaints(con.gov.DKGComplaints(round))
- // Enforce complaint is done in `processPrivateShare`.
- // Phase 8(T = 5λ): DKG is ready.
- gpk, err := newDKGGroupPublicKey(round,
- con.gov.DKGMasterPublicKeys(round),
- con.gov.DKGComplaints(round),
- con.dkgModule.threshold, con.sigToPub)
+ round := con.cfgModule.dkg.round
+ if err := con.cfgModule.runDKG(round); err != nil {
+ panic(err)
+ }
+ hash := HashConfigurationBlock(
+ con.gov.GetNotarySet(0),
+ con.gov.GetConfiguration(0),
+ common.Hash{},
+ con.cfgModule.prevHash)
+ psig, err := con.cfgModule.preparePartialSignature(round, hash)
+ if err != nil {
+ panic(err)
+ }
+ psig.Signature, err = con.prvKey.Sign(hashDKGPartialSignature(psig))
if err != nil {
panic(err)
}
- qualifies := ""
- for _, nID := range gpk.qualifyNodeIDs {
- qualifies += fmt.Sprintf("%s ", nID.String()[:6])
+ if err = con.cfgModule.processPartialSignature(psig); err != nil {
+ panic(err)
+ }
+ con.network.BroadcastDKGPartialSignature(psig)
+ if err = con.cfgModule.runBlockTSig(round, hash); err != nil {
+ panic(err)
}
- log.Printf("[%s] Qualify Nodes(%d): %s\n",
- con.ID, len(gpk.qualifyIDs), qualifies)
}()
}
@@ -512,10 +503,12 @@ func (con *Consensus) processMsg(
log.Println(err)
}
case *types.DKGPrivateShare:
- if con.dkgRunning == 0 {
- break
+ if err := con.cfgModule.processPrivateShare(val); err != nil {
+ log.Println(err)
}
- if err := con.dkgModule.processPrivateShare(val); err != nil {
+
+ case *types.DKGPartialSignature:
+ if err := con.cfgModule.processPartialSignature(val); err != nil {
log.Println(err)
}
}
diff --git a/core/consensus_test.go b/core/consensus_test.go
index 2b71d6b..a58d3e8 100644
--- a/core/consensus_test.go
+++ b/core/consensus_test.go
@@ -55,6 +55,12 @@ func (n *network) BroadcastDKGPrivateShare(
prvShare *types.DKGPrivateShare) {
}
+// BroadcastDKGPartialSignature broadcasts partialSignature to all
+// DKG participants.
+func (n *network) BroadcastDKGPartialSignature(
+ psig *types.DKGPartialSignature) {
+}
+
// ReceiveChan returns a channel to receive messages from DEXON network.
func (n *network) ReceiveChan() <-chan interface{} {
return make(chan interface{})
diff --git a/core/crypto.go b/core/crypto.go
index c95811e..26e44f9 100644
--- a/core/crypto.go
+++ b/core/crypto.go
@@ -225,9 +225,13 @@ func hashDKGPartialSignature(psig *types.DKGPartialSignature) common.Hash {
binaryRound := make([]byte, 8)
binary.LittleEndian.PutUint64(binaryRound, psig.Round)
+ binaryType := make([]byte, 4)
+ binary.LittleEndian.PutUint32(binaryType, uint32(psig.Type))
+
return crypto.Keccak256Hash(
psig.ProposerID.Hash[:],
binaryRound,
+ binaryType,
psig.PartialSignature[:],
)
}
diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go
index ccd2439..0f5cb0b 100644
--- a/core/dkg-tsig-protocol.go
+++ b/core/dkg-tsig-protocol.go
@@ -38,6 +38,8 @@ var (
"threshold not reach")
ErrIncorrectPrivateShareSignature = fmt.Errorf(
"incorrect private share signature")
+ ErrMismatchPartialSignatureType = fmt.Errorf(
+ "mismatch partialSignature type")
ErrIncorrectPartialSignatureSignature = fmt.Errorf(
"incorrect partialSignature signature")
ErrIncorrectPartialSignature = fmt.Errorf(
@@ -93,6 +95,8 @@ type dkgGroupPublicKey struct {
type tsigProtocol struct {
groupPublicKey *dkgGroupPublicKey
+ hash common.Hash
+ psigType types.DKGPartialSignatureType
sigs map[dkg.ID]dkg.PartialSignature
threshold int
}
@@ -386,9 +390,14 @@ func (gpk *dkgGroupPublicKey) verifySignature(
return gpk.groupPublicKey.VerifySignature(hash, sig)
}
-func newTSigProtocol(gpk *dkgGroupPublicKey) *tsigProtocol {
+func newTSigProtocol(
+ gpk *dkgGroupPublicKey,
+ hash common.Hash,
+ psigType types.DKGPartialSignatureType) *tsigProtocol {
return &tsigProtocol{
groupPublicKey: gpk,
+ hash: hash,
+ psigType: psigType,
sigs: make(map[dkg.ID]dkg.PartialSignature, gpk.threshold+1),
}
}
@@ -406,11 +415,14 @@ func (tsig *tsigProtocol) sanityCheck(psig *types.DKGPartialSignature) error {
if !ok {
return ErrIncorrectPartialSignatureSignature
}
+ if psig.Type != tsig.psigType {
+ return ErrMismatchPartialSignatureType
+ }
return nil
}
func (tsig *tsigProtocol) processPartialSignature(
- hash common.Hash, psig *types.DKGPartialSignature) error {
+ psig *types.DKGPartialSignature) error {
if psig.Round != tsig.groupPublicKey.round {
return nil
}
@@ -422,7 +434,8 @@ func (tsig *tsigProtocol) processPartialSignature(
return err
}
pubKey := tsig.groupPublicKey.publicKeys[psig.ProposerID]
- if !pubKey.VerifySignature(hash, crypto.Signature(psig.PartialSignature)) {
+ if !pubKey.VerifySignature(
+ tsig.hash, crypto.Signature(psig.PartialSignature)) {
return ErrIncorrectPartialSignature
}
tsig.sigs[id] = psig.PartialSignature
diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go
index 19709d3..0c938f7 100644
--- a/core/dkg-tsig-protocol_test.go
+++ b/core/dkg-tsig-protocol_test.go
@@ -211,18 +211,19 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() {
s.Require().NoError(err)
}
- tsig := newTSigProtocol(gpk)
msgHash := crypto.Keccak256Hash([]byte("🏖🍹"))
+ tsig := newTSigProtocol(gpk, msgHash, types.TSigConfigurationBlock)
for nID, shareSecret := range shareSecrets {
psig := &types.DKGPartialSignature{
ProposerID: nID,
Round: round,
+ Type: types.TSigConfigurationBlock,
PartialSignature: shareSecret.sign(msgHash),
}
var err error
psig.Signature, err = s.prvKeys[nID].Sign(hashDKGPartialSignature(psig))
s.Require().NoError(err)
- s.Require().NoError(tsig.processPartialSignature(msgHash, psig))
+ s.Require().NoError(tsig.processPartialSignature(psig))
if len(tsig.sigs) > k {
break
}
@@ -577,28 +578,36 @@ func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() {
s.Require().NoError(err)
}
- tsig := newTSigProtocol(gpk)
msgHash := crypto.Keccak256Hash([]byte("🏖🍹"))
+ tsig := newTSigProtocol(gpk, msgHash, types.TSigConfigurationBlock)
byzantineID2 := s.nIDs[1]
+ byzantineID3 := s.nIDs[2]
for nID, shareSecret := range shareSecrets {
psig := &types.DKGPartialSignature{
ProposerID: nID,
Round: round,
+ Type: types.TSigConfigurationBlock,
PartialSignature: shareSecret.sign(msgHash),
}
- if nID == byzantineID2 {
+ switch nID {
+ case byzantineID2:
psig.PartialSignature = shareSecret.sign(
crypto.Keccak256Hash([]byte("💣")))
+ case byzantineID3:
+ psig.Type = types.TSigNotaryAck
}
var err error
psig.Signature, err = s.prvKeys[nID].Sign(hashDKGPartialSignature(psig))
s.Require().NoError(err)
- err = tsig.processPartialSignature(msgHash, psig)
- if nID == byzantineID {
+ err = tsig.processPartialSignature(psig)
+ switch nID {
+ case byzantineID:
s.Require().Equal(ErrNotQualifyDKGParticipant, err)
- } else if nID == byzantineID2 {
+ case byzantineID2:
s.Require().Equal(ErrIncorrectPartialSignature, err)
- } else {
+ case byzantineID3:
+ s.Require().Equal(ErrMismatchPartialSignatureType, err)
+ default:
s.Require().NoError(err)
}
}
diff --git a/core/interfaces.go b/core/interfaces.go
index 940d9b5..7f6ff2b 100644
--- a/core/interfaces.go
+++ b/core/interfaces.go
@@ -22,6 +22,7 @@ import (
"github.com/dexon-foundation/dexon-consensus-core/common"
"github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
)
// Application describes the application interface that interacts with DEXON
@@ -76,6 +77,10 @@ type Network interface {
// BroadcastDKGPrivateShare broadcasts PrivateShare to all DKG participants.
BroadcastDKGPrivateShare(prvShare *types.DKGPrivateShare)
+ // BroadcastDKGPartialSignature broadcasts partialSignature to all
+ // DKG participants.
+ BroadcastDKGPartialSignature(psig *types.DKGPartialSignature)
+
// ReceiveChan returns a channel to receive messages from DEXON network.
ReceiveChan() <-chan interface{}
}
@@ -92,6 +97,12 @@ type Governance interface {
// Return the genesis notary set if blockHeight == 0.
GetNotarySet(blockHeight uint64) map[types.NodeID]struct{}
+ // Porpose a ThresholdSignature of round.
+ ProposeThresholdSignature(round uint64, signature crypto.Signature)
+
+ // Get a ThresholdSignature of round.
+ GetThresholdSignature(round uint64) (sig crypto.Signature, exist bool)
+
//// DKG-related methods.
// AddDKGComplaint adds a DKGComplaint.
diff --git a/core/test/governance.go b/core/test/governance.go
index 0bcb39a..1225b4a 100644
--- a/core/test/governance.go
+++ b/core/test/governance.go
@@ -38,6 +38,7 @@ type Governance struct {
lambdaDKG time.Duration
notarySet map[types.NodeID]struct{}
privateKeys map[types.NodeID]crypto.PrivateKey
+ tsig map[uint64]crypto.Signature
DKGComplaint map[uint64][]*types.DKGComplaint
DKGMasterPublicKey map[uint64][]*types.DKGMasterPublicKey
}
@@ -50,6 +51,7 @@ func NewGovernance(nodeCount int, lambda time.Duration) (
lambdaDKG: lambda * 10,
notarySet: make(map[types.NodeID]struct{}),
privateKeys: make(map[types.NodeID]crypto.PrivateKey),
+ tsig: make(map[uint64]crypto.Signature),
DKGComplaint: make(map[uint64][]*types.DKGComplaint),
DKGMasterPublicKey: make(map[uint64][]*types.DKGMasterPublicKey),
}
@@ -103,6 +105,19 @@ func (g *Governance) GetPrivateKey(
return
}
+// ProposeThresholdSignature porposes a ThresholdSignature of round.
+func (g *Governance) ProposeThresholdSignature(
+ round uint64, signature crypto.Signature) {
+ g.tsig[round] = signature
+}
+
+// GetThresholdSignature gets a ThresholdSignature of round.
+func (g *Governance) GetThresholdSignature(round uint64) (
+ sig crypto.Signature, exist bool) {
+ sig, exist = g.tsig[round]
+ return
+}
+
// AddDKGComplaint add a DKGComplaint.
func (g *Governance) AddDKGComplaint(complaint *types.DKGComplaint) {
g.DKGComplaint[complaint.Round] = append(g.DKGComplaint[complaint.Round], complaint)
diff --git a/core/types/config.go b/core/types/config.go
index 3c0bced..034853e 100644
--- a/core/types/config.go
+++ b/core/types/config.go
@@ -17,7 +17,11 @@
package types
-import "time"
+import (
+ "encoding/binary"
+ "math"
+ "time"
+)
// Config stands for Current Configuration Parameters.
type Config struct {
@@ -35,4 +39,41 @@ type Config struct {
// Total ordering related.
K int
PhiRatio float32
+
+ // Confiuration chain related.
+ RoundHeight uint64
+}
+
+// Bytes returns []byte representation of Config.
+func (c *Config) Bytes() []byte {
+ binaryNumShards := make([]byte, 4)
+ binary.LittleEndian.PutUint32(binaryNumShards, c.NumShards)
+ binaryNumChains := make([]byte, 4)
+ binary.LittleEndian.PutUint32(binaryNumChains, c.NumChains)
+
+ binaryLambdaBA := make([]byte, 8)
+ binary.LittleEndian.PutUint64(
+ binaryLambdaBA, uint64(c.LambdaBA.Nanoseconds()))
+ binaryLambdaDKG := make([]byte, 8)
+ binary.LittleEndian.PutUint64(
+ binaryLambdaDKG, uint64(c.LambdaDKG.Nanoseconds()))
+
+ binaryK := make([]byte, 4)
+ binary.LittleEndian.PutUint32(binaryK, uint32(c.K))
+ binaryPhiRatio := make([]byte, 4)
+ binary.LittleEndian.PutUint32(binaryPhiRatio, math.Float32bits(c.PhiRatio))
+
+ binaryRoundHeight := make([]byte, 8)
+ binary.LittleEndian.PutUint64(binaryRoundHeight, c.RoundHeight)
+
+ enc := make([]byte, 0, 40)
+ enc = append(enc, binaryNumShards...)
+ enc = append(enc, binaryNumChains...)
+ enc = append(enc, binaryLambdaBA...)
+ enc = append(enc, binaryLambdaDKG...)
+ enc = append(enc, binaryK...)
+ enc = append(enc, binaryPhiRatio...)
+ enc = append(enc, binaryRoundHeight...)
+
+ return enc
}
diff --git a/core/types/dkg.go b/core/types/dkg.go
index ff0aa75..10a31ee 100644
--- a/core/types/dkg.go
+++ b/core/types/dkg.go
@@ -59,12 +59,22 @@ type DKGComplaint struct {
Signature crypto.Signature `json:"signature"`
}
+// DKGPartialSignatureType specifies ths threshold signature type.
+type DKGPartialSignatureType uint32
+
+// TSig enums.
+const (
+ TSigConfigurationBlock DKGPartialSignatureType = iota
+ TSigNotaryAck
+)
+
// DKGPartialSignature describe a partial signature in DKG protocol.
type DKGPartialSignature struct {
- ProposerID NodeID `json:"proposerID"`
- Round uint64 `json:"round"`
- PartialSignature dkg.PartialSignature `json:"partial_signature"`
- Signature crypto.Signature `json:"signature"`
+ ProposerID NodeID `json:"proposerID"`
+ Round uint64 `json:"round"`
+ Type DKGPartialSignatureType `json:"type"`
+ PartialSignature dkg.PartialSignature `json:"partial_signature"`
+ Signature crypto.Signature `json:"signature"`
}
// IsNack returns true if it's a nack complaint in DKG protocol.
diff --git a/core/utils.go b/core/utils.go
index 7aa99f0..30456ef 100644
--- a/core/utils.go
+++ b/core/utils.go
@@ -25,6 +25,8 @@ import (
"time"
"github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
)
var (
@@ -102,3 +104,29 @@ func removeFromSortedUint32Slice(xs []uint32, x uint32) []uint32 {
}
return append(xs[:indexToRemove], xs[indexToRemove+1:]...)
}
+
+// HashConfigurationBlock returns the hash value of configuration block.
+func HashConfigurationBlock(
+ notarySet map[types.NodeID]struct{},
+ config *types.Config,
+ snapshotHash common.Hash,
+ prevHash common.Hash,
+) common.Hash {
+ notaryIDs := make(types.NodeIDs, 0, len(notarySet))
+ for nID := range notarySet {
+ notaryIDs = append(notaryIDs, nID)
+ }
+ sort.Sort(notaryIDs)
+ notarySetBytes := make([]byte, 0, len(notarySet)*len(common.Hash{}))
+ for _, nID := range notaryIDs {
+ notarySetBytes = append(notarySetBytes, nID.Hash[:]...)
+ }
+ configBytes := config.Bytes()
+
+ return crypto.Keccak256Hash(
+ notarySetBytes[:],
+ configBytes[:],
+ snapshotHash[:],
+ prevHash[:],
+ )
+}