diff options
Diffstat (limited to 'vendor/github.com/byzantine-lab/dexon-consensus/core/types')
9 files changed, 1229 insertions, 0 deletions
diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/block-randomness.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/block-randomness.go new file mode 100644 index 000000000..b97188705 --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/block-randomness.go @@ -0,0 +1,44 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +import ( + "encoding/hex" + "fmt" + + "github.com/byzantine-lab/dexon-consensus/common" +) + +// AgreementResult describes an agremeent result. +type AgreementResult struct { + BlockHash common.Hash `json:"block_hash"` + Position Position `json:"position"` + Votes []Vote `json:"votes"` + IsEmptyBlock bool `json:"is_empty_block"` + Randomness []byte `json:"randomness"` +} + +func (r *AgreementResult) String() string { + if len(r.Randomness) == 0 { + return fmt.Sprintf("agreementResult{Block:%s Pos:%s}", + r.BlockHash.String()[:6], r.Position) + } + return fmt.Sprintf("agreementResult{Block:%s Pos:%s Rand:%s}", + r.BlockHash.String()[:6], r.Position, + hex.EncodeToString(r.Randomness)[:6]) +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/block.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/block.go new file mode 100644 index 000000000..bc92211b9 --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/block.go @@ -0,0 +1,227 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +// TODO(jimmy-dexon): remove comments of WitnessAck before open source. + +package types + +import ( + "bytes" + "fmt" + "io" + "time" + + "github.com/byzantine-lab/go-tangerine/rlp" + + "github.com/byzantine-lab/dexon-consensus/common" + "github.com/byzantine-lab/dexon-consensus/core/crypto" +) + +// GenesisHeight refers to the initial height the genesis block should be. +const GenesisHeight uint64 = 1 + +// BlockVerifyStatus is the return code for core.Application.VerifyBlock +type BlockVerifyStatus int + +// Enums for return value of core.Application.VerifyBlock. +const ( + // VerifyOK: Block is verified. + VerifyOK BlockVerifyStatus = iota + // VerifyRetryLater: Block is unable to be verified at this moment. + // Try again later. + VerifyRetryLater + // VerifyInvalidBlock: Block is an invalid one. + VerifyInvalidBlock +) + +type rlpTimestamp struct { + time.Time +} + +func (t *rlpTimestamp) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, uint64(t.UTC().UnixNano())) +} + +func (t *rlpTimestamp) DecodeRLP(s *rlp.Stream) error { + var nano uint64 + err := s.Decode(&nano) + if err == nil { + sec := int64(nano) / 1000000000 + nsec := int64(nano) % 1000000000 + t.Time = time.Unix(sec, nsec).UTC() + } + return err +} + +// Witness represents the consensus information on the compaction chain. +type Witness struct { + Height uint64 `json:"height"` + Data []byte `json:"data"` +} + +// Block represents a single event broadcasted on the network. +type Block struct { + ProposerID NodeID `json:"proposer_id"` + ParentHash common.Hash `json:"parent_hash"` + Hash common.Hash `json:"hash"` + Position Position `json:"position"` + Timestamp time.Time `json:"timestamp"` + Payload []byte `json:"payload"` + PayloadHash common.Hash `json:"payload_hash"` + Witness Witness `json:"witness"` + Randomness []byte `json:"randomness"` + Signature crypto.Signature `json:"signature"` + + CRSSignature crypto.Signature `json:"crs_signature"` +} + +type rlpBlock struct { + ProposerID NodeID + ParentHash common.Hash + Hash common.Hash + Position Position + Timestamp *rlpTimestamp + Payload []byte + PayloadHash common.Hash + Witness *Witness + Randomness []byte + Signature crypto.Signature + + CRSSignature crypto.Signature +} + +// EncodeRLP implements rlp.Encoder +func (b *Block) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, rlpBlock{ + ProposerID: b.ProposerID, + ParentHash: b.ParentHash, + Hash: b.Hash, + Position: b.Position, + Timestamp: &rlpTimestamp{b.Timestamp}, + Payload: b.Payload, + PayloadHash: b.PayloadHash, + Witness: &b.Witness, + Randomness: b.Randomness, + Signature: b.Signature, + CRSSignature: b.CRSSignature, + }) +} + +// DecodeRLP implements rlp.Decoder +func (b *Block) DecodeRLP(s *rlp.Stream) error { + var dec rlpBlock + err := s.Decode(&dec) + if err == nil { + *b = Block{ + ProposerID: dec.ProposerID, + ParentHash: dec.ParentHash, + Hash: dec.Hash, + Position: dec.Position, + Timestamp: dec.Timestamp.Time, + Payload: dec.Payload, + PayloadHash: dec.PayloadHash, + Witness: *dec.Witness, + Randomness: dec.Randomness, + Signature: dec.Signature, + CRSSignature: dec.CRSSignature, + } + } + return err +} + +func (b *Block) String() string { + return fmt.Sprintf("Block{Hash:%v %s}", b.Hash.String()[:6], b.Position) +} + +// Clone returns a deep copy of a block. +func (b *Block) Clone() (bcopy *Block) { + bcopy = &Block{} + bcopy.ProposerID = b.ProposerID + bcopy.ParentHash = b.ParentHash + bcopy.Hash = b.Hash + bcopy.Position.Round = b.Position.Round + bcopy.Position.Height = b.Position.Height + bcopy.Signature = b.Signature.Clone() + bcopy.CRSSignature = b.CRSSignature.Clone() + bcopy.Witness.Height = b.Witness.Height + bcopy.Witness.Data = common.CopyBytes(b.Witness.Data) + bcopy.Timestamp = b.Timestamp + bcopy.Payload = common.CopyBytes(b.Payload) + bcopy.PayloadHash = b.PayloadHash + bcopy.Randomness = common.CopyBytes(b.Randomness) + return +} + +// IsGenesis checks if the block is a genesisBlock +func (b *Block) IsGenesis() bool { + return b.Position.Height == GenesisHeight && b.ParentHash == common.Hash{} +} + +// IsFinalized checks if the block is finalized. +func (b *Block) IsFinalized() bool { + return len(b.Randomness) > 0 +} + +// IsEmpty checks if the block is an 'empty block'. +func (b *Block) IsEmpty() bool { + return b.ProposerID.Hash == common.Hash{} +} + +// ByHash is the helper type for sorting slice of blocks by hash. +type ByHash []*Block + +func (b ByHash) Len() int { + return len(b) +} + +func (b ByHash) Less(i int, j int) bool { + return bytes.Compare([]byte(b[i].Hash[:]), []byte(b[j].Hash[:])) == -1 +} + +func (b ByHash) Swap(i int, j int) { + b[i], b[j] = b[j], b[i] +} + +// BlocksByPosition is the helper type for sorting slice of blocks by position. +type BlocksByPosition []*Block + +// Len implements Len method in sort.Sort interface. +func (bs BlocksByPosition) Len() int { + return len(bs) +} + +// Less implements Less method in sort.Sort interface. +func (bs BlocksByPosition) Less(i int, j int) bool { + return bs[j].Position.Newer(bs[i].Position) +} + +// Swap implements Swap method in sort.Sort interface. +func (bs BlocksByPosition) Swap(i int, j int) { + bs[i], bs[j] = bs[j], bs[i] +} + +// Push implements Push method in heap interface. +func (bs *BlocksByPosition) Push(x interface{}) { + *bs = append(*bs, x.(*Block)) +} + +// Pop implements Pop method in heap interface. +func (bs *BlocksByPosition) Pop() (ret interface{}) { + n := len(*bs) + *bs, ret = (*bs)[0:n-1], (*bs)[n-1] + return +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/config.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/config.go new file mode 100644 index 000000000..dce38369e --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/config.go @@ -0,0 +1,75 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +import ( + "encoding/binary" + "time" +) + +// Config stands for Current Configuration Parameters. +type Config struct { + // Lambda related. + LambdaBA time.Duration + LambdaDKG time.Duration + + // Set related. + NotarySetSize uint32 + + // Time related. + RoundLength uint64 + MinBlockInterval time.Duration +} + +// Clone return a copied configuration. +func (c *Config) Clone() *Config { + return &Config{ + LambdaBA: c.LambdaBA, + LambdaDKG: c.LambdaDKG, + NotarySetSize: c.NotarySetSize, + RoundLength: c.RoundLength, + MinBlockInterval: c.MinBlockInterval, + } +} + +// Bytes returns []byte representation of Config. +func (c *Config) Bytes() []byte { + binaryLambdaBA := make([]byte, 8) + binary.LittleEndian.PutUint64( + binaryLambdaBA, uint64(c.LambdaBA.Nanoseconds())) + binaryLambdaDKG := make([]byte, 8) + binary.LittleEndian.PutUint64( + binaryLambdaDKG, uint64(c.LambdaDKG.Nanoseconds())) + + binaryNotarySetSize := make([]byte, 4) + binary.LittleEndian.PutUint32(binaryNotarySetSize, c.NotarySetSize) + + binaryRoundLength := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRoundLength, c.RoundLength) + binaryMinBlockInterval := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryMinBlockInterval, + uint64(c.MinBlockInterval.Nanoseconds())) + + enc := make([]byte, 0, 40) + enc = append(enc, binaryLambdaBA...) + enc = append(enc, binaryLambdaDKG...) + enc = append(enc, binaryNotarySetSize...) + enc = append(enc, binaryRoundLength...) + enc = append(enc, binaryMinBlockInterval...) + return enc +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/dkg/dkg.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/dkg/dkg.go new file mode 100644 index 000000000..6c2b777cd --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/dkg/dkg.go @@ -0,0 +1,485 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package dkg + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + + "github.com/byzantine-lab/go-tangerine/rlp" + + "github.com/byzantine-lab/dexon-consensus/common" + "github.com/byzantine-lab/dexon-consensus/core/crypto" + cryptoDKG "github.com/byzantine-lab/dexon-consensus/core/crypto/dkg" + "github.com/byzantine-lab/dexon-consensus/core/types" +) + +// Errors for typesDKG package. +var ( + ErrNotReachThreshold = fmt.Errorf("threshold not reach") + ErrInvalidThreshold = fmt.Errorf("invalid threshold") +) + +// NewID creates a DKGID from NodeID. +func NewID(ID types.NodeID) cryptoDKG.ID { + return cryptoDKG.NewID(ID.Hash[:]) +} + +// PrivateShare describe a secret share in DKG protocol. +type PrivateShare struct { + ProposerID types.NodeID `json:"proposer_id"` + ReceiverID types.NodeID `json:"receiver_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + PrivateShare cryptoDKG.PrivateKey `json:"private_share"` + Signature crypto.Signature `json:"signature"` +} + +// Equal checks equality between two PrivateShare instances. +func (p *PrivateShare) Equal(other *PrivateShare) bool { + return p.ProposerID.Equal(other.ProposerID) && + p.ReceiverID.Equal(other.ReceiverID) && + p.Round == other.Round && + p.Reset == other.Reset && + p.Signature.Type == other.Signature.Type && + bytes.Compare(p.Signature.Signature, other.Signature.Signature) == 0 && + bytes.Compare( + p.PrivateShare.Bytes(), other.PrivateShare.Bytes()) == 0 +} + +// MasterPublicKey decrtibe a master public key in DKG protocol. +type MasterPublicKey struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + DKGID cryptoDKG.ID `json:"dkg_id"` + PublicKeyShares cryptoDKG.PublicKeyShares `json:"public_key_shares"` + Signature crypto.Signature `json:"signature"` +} + +func (d *MasterPublicKey) String() string { + return fmt.Sprintf("MasterPublicKey{KP:%s Round:%d Reset:%d}", + d.ProposerID.String()[:6], + d.Round, + d.Reset) +} + +// Equal check equality of two DKG master public keys. +func (d *MasterPublicKey) Equal(other *MasterPublicKey) bool { + return d.ProposerID.Equal(other.ProposerID) && + d.Round == other.Round && + d.Reset == other.Reset && + d.DKGID.GetHexString() == other.DKGID.GetHexString() && + d.PublicKeyShares.Equal(&other.PublicKeyShares) && + d.Signature.Type == other.Signature.Type && + bytes.Compare(d.Signature.Signature, other.Signature.Signature) == 0 +} + +type rlpMasterPublicKey struct { + ProposerID types.NodeID + Round uint64 + Reset uint64 + DKGID []byte + PublicKeyShares *cryptoDKG.PublicKeyShares + Signature crypto.Signature +} + +// EncodeRLP implements rlp.Encoder +func (d *MasterPublicKey) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, rlpMasterPublicKey{ + ProposerID: d.ProposerID, + Round: d.Round, + Reset: d.Reset, + DKGID: d.DKGID.GetLittleEndian(), + PublicKeyShares: &d.PublicKeyShares, + Signature: d.Signature, + }) +} + +// DecodeRLP implements rlp.Decoder +func (d *MasterPublicKey) DecodeRLP(s *rlp.Stream) error { + var dec rlpMasterPublicKey + if err := s.Decode(&dec); err != nil { + return err + } + + id, err := cryptoDKG.BytesID(dec.DKGID) + if err != nil { + return err + } + + *d = MasterPublicKey{ + ProposerID: dec.ProposerID, + Round: dec.Round, + Reset: dec.Reset, + DKGID: id, + PublicKeyShares: *dec.PublicKeyShares.Move(), + Signature: dec.Signature, + } + return err +} + +// NewMasterPublicKey returns a new MasterPublicKey instance. +func NewMasterPublicKey() *MasterPublicKey { + return &MasterPublicKey{ + PublicKeyShares: *cryptoDKG.NewEmptyPublicKeyShares(), + } +} + +// UnmarshalJSON implements json.Unmarshaller. +func (d *MasterPublicKey) UnmarshalJSON(data []byte) error { + type innertMasterPublicKey MasterPublicKey + d.PublicKeyShares = *cryptoDKG.NewEmptyPublicKeyShares() + return json.Unmarshal(data, (*innertMasterPublicKey)(d)) +} + +// Complaint describe a complaint in DKG protocol. +type Complaint struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + PrivateShare PrivateShare `json:"private_share"` + Signature crypto.Signature `json:"signature"` +} + +func (c *Complaint) String() string { + if c.IsNack() { + return fmt.Sprintf("DKGNackComplaint{CP:%s Round:%d Reset %d PSP:%s}", + c.ProposerID.String()[:6], c.Round, c.Reset, + c.PrivateShare.ProposerID.String()[:6]) + } + return fmt.Sprintf("DKGComplaint{CP:%s Round:%d Reset %d PrivateShare:%v}", + c.ProposerID.String()[:6], c.Round, c.Reset, c.PrivateShare) +} + +// Equal checks equality between two Complaint instances. +func (c *Complaint) Equal(other *Complaint) bool { + return c.ProposerID.Equal(other.ProposerID) && + c.Round == other.Round && + c.Reset == other.Reset && + c.PrivateShare.Equal(&other.PrivateShare) && + c.Signature.Type == other.Signature.Type && + bytes.Compare(c.Signature.Signature, other.Signature.Signature) == 0 +} + +type rlpComplaint struct { + ProposerID types.NodeID + Round uint64 + Reset uint64 + IsNack bool + PrivateShare []byte + Signature crypto.Signature +} + +// EncodeRLP implements rlp.Encoder +func (c *Complaint) EncodeRLP(w io.Writer) error { + if c.IsNack() { + return rlp.Encode(w, rlpComplaint{ + ProposerID: c.ProposerID, + Round: c.Round, + Reset: c.Reset, + IsNack: true, + PrivateShare: c.PrivateShare.ProposerID.Hash[:], + Signature: c.Signature, + }) + } + prvShare, err := rlp.EncodeToBytes(&c.PrivateShare) + if err != nil { + return err + } + return rlp.Encode(w, rlpComplaint{ + ProposerID: c.ProposerID, + Round: c.Round, + Reset: c.Reset, + IsNack: false, + PrivateShare: prvShare, + Signature: c.Signature, + }) +} + +// DecodeRLP implements rlp.Decoder +func (c *Complaint) DecodeRLP(s *rlp.Stream) error { + var dec rlpComplaint + if err := s.Decode(&dec); err != nil { + return err + } + + var prvShare PrivateShare + if dec.IsNack { + copy(prvShare.ProposerID.Hash[:], dec.PrivateShare) + prvShare.Round = dec.Round + prvShare.Reset = dec.Reset + } else { + if err := rlp.DecodeBytes(dec.PrivateShare, &prvShare); err != nil { + return err + } + } + + *c = Complaint{ + ProposerID: dec.ProposerID, + Round: dec.Round, + Reset: dec.Reset, + PrivateShare: prvShare, + Signature: dec.Signature, + } + return nil +} + +// IsNack returns true if it's a nack complaint in DKG protocol. +func (c *Complaint) IsNack() bool { + return len(c.PrivateShare.Signature.Signature) == 0 +} + +// PartialSignature describe a partial signature in DKG protocol. +type PartialSignature struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Hash common.Hash `json:"hash"` + PartialSignature cryptoDKG.PartialSignature `json:"partial_signature"` + Signature crypto.Signature `json:"signature"` +} + +// MPKReady describe a dkg ready message in DKG protocol. +type MPKReady struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + Signature crypto.Signature `json:"signature"` +} + +func (ready *MPKReady) String() string { + return fmt.Sprintf("DKGMPKReady{RP:%s Round:%d Reset:%d}", + ready.ProposerID.String()[:6], + ready.Round, + ready.Reset) +} + +// Equal check equality of two MPKReady instances. +func (ready *MPKReady) Equal(other *MPKReady) bool { + return ready.ProposerID.Equal(other.ProposerID) && + ready.Round == other.Round && + ready.Reset == other.Reset && + ready.Signature.Type == other.Signature.Type && + bytes.Compare(ready.Signature.Signature, other.Signature.Signature) == 0 +} + +// Finalize describe a dkg finalize message in DKG protocol. +type Finalize struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + Signature crypto.Signature `json:"signature"` +} + +func (final *Finalize) String() string { + return fmt.Sprintf("DKGFinal{FP:%s Round:%d Reset:%d}", + final.ProposerID.String()[:6], + final.Round, + final.Reset) +} + +// Equal check equality of two Finalize instances. +func (final *Finalize) Equal(other *Finalize) bool { + return final.ProposerID.Equal(other.ProposerID) && + final.Round == other.Round && + final.Reset == other.Reset && + final.Signature.Type == other.Signature.Type && + bytes.Compare(final.Signature.Signature, other.Signature.Signature) == 0 +} + +// Success describe a dkg success message in DKG protocol. +type Success struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + Signature crypto.Signature `json:"signature"` +} + +func (s *Success) String() string { + return fmt.Sprintf("DKGSuccess{SP:%s Round:%d Reset:%d}", + s.ProposerID.String()[:6], + s.Round, + s.Reset) +} + +// Equal check equality of two Success instances. +func (s *Success) Equal(other *Success) bool { + return s.ProposerID.Equal(other.ProposerID) && + s.Round == other.Round && + s.Reset == other.Reset && + s.Signature.Type == other.Signature.Type && + bytes.Compare(s.Signature.Signature, other.Signature.Signature) == 0 +} + +// GroupPublicKey is the result of DKG protocol. +type GroupPublicKey struct { + Round uint64 + QualifyIDs cryptoDKG.IDs + QualifyNodeIDs map[types.NodeID]struct{} + IDMap map[types.NodeID]cryptoDKG.ID + GroupPublicKey *cryptoDKG.PublicKey + Threshold int +} + +// VerifySignature verifies if the signature is correct. +func (gpk *GroupPublicKey) VerifySignature( + hash common.Hash, sig crypto.Signature) bool { + return gpk.GroupPublicKey.VerifySignature(hash, sig) +} + +// CalcQualifyNodes returns the qualified nodes. +func CalcQualifyNodes( + mpks []*MasterPublicKey, complaints []*Complaint, threshold int) ( + qualifyIDs cryptoDKG.IDs, qualifyNodeIDs map[types.NodeID]struct{}, err error) { + if len(mpks) < threshold { + err = ErrInvalidThreshold + return + } + + // Calculate qualify members. + disqualifyIDs := map[types.NodeID]struct{}{} + complaintsByID := map[types.NodeID]map[types.NodeID]struct{}{} + for _, complaint := range complaints { + if complaint.IsNack() { + if _, exist := complaintsByID[complaint.PrivateShare.ProposerID]; !exist { + complaintsByID[complaint.PrivateShare.ProposerID] = + make(map[types.NodeID]struct{}) + } + complaintsByID[complaint.PrivateShare.ProposerID][complaint.ProposerID] = + struct{}{} + } else { + disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} + } + } + for nID, complaints := range complaintsByID { + if len(complaints) >= threshold { + disqualifyIDs[nID] = struct{}{} + } + } + qualifyIDs = make(cryptoDKG.IDs, 0, len(mpks)-len(disqualifyIDs)) + if cap(qualifyIDs) < threshold { + err = ErrNotReachThreshold + return + } + qualifyNodeIDs = make(map[types.NodeID]struct{}) + for _, mpk := range mpks { + if _, exist := disqualifyIDs[mpk.ProposerID]; exist { + continue + } + qualifyIDs = append(qualifyIDs, mpk.DKGID) + qualifyNodeIDs[mpk.ProposerID] = struct{}{} + } + return +} + +// NewGroupPublicKey creats a GroupPublicKey instance. +func NewGroupPublicKey( + round uint64, + mpks []*MasterPublicKey, complaints []*Complaint, + threshold int) ( + *GroupPublicKey, error) { + qualifyIDs, qualifyNodeIDs, err := + CalcQualifyNodes(mpks, complaints, threshold) + if err != nil { + return nil, err + } + mpkMap := make(map[cryptoDKG.ID]*MasterPublicKey, cap(qualifyIDs)) + idMap := make(map[types.NodeID]cryptoDKG.ID) + for _, mpk := range mpks { + if _, exist := qualifyNodeIDs[mpk.ProposerID]; !exist { + continue + } + mpkMap[mpk.DKGID] = mpk + idMap[mpk.ProposerID] = mpk.DKGID + } + // Recover Group Public Key. + pubShares := make([]*cryptoDKG.PublicKeyShares, 0, len(qualifyIDs)) + for _, id := range qualifyIDs { + pubShares = append(pubShares, &mpkMap[id].PublicKeyShares) + } + groupPK := cryptoDKG.RecoverGroupPublicKey(pubShares) + return &GroupPublicKey{ + Round: round, + QualifyIDs: qualifyIDs, + QualifyNodeIDs: qualifyNodeIDs, + IDMap: idMap, + Threshold: threshold, + GroupPublicKey: groupPK, + }, nil +} + +// NodePublicKeys is the result of DKG protocol. +type NodePublicKeys struct { + Round uint64 + QualifyIDs cryptoDKG.IDs + QualifyNodeIDs map[types.NodeID]struct{} + IDMap map[types.NodeID]cryptoDKG.ID + PublicKeys map[types.NodeID]*cryptoDKG.PublicKey + Threshold int +} + +// NewNodePublicKeys creats a NodePublicKeys instance. +func NewNodePublicKeys( + round uint64, + mpks []*MasterPublicKey, complaints []*Complaint, + threshold int) ( + *NodePublicKeys, error) { + qualifyIDs, qualifyNodeIDs, err := + CalcQualifyNodes(mpks, complaints, threshold) + if err != nil { + return nil, err + } + mpkMap := make(map[cryptoDKG.ID]*MasterPublicKey, cap(qualifyIDs)) + idMap := make(map[types.NodeID]cryptoDKG.ID) + for _, mpk := range mpks { + if _, exist := qualifyNodeIDs[mpk.ProposerID]; !exist { + continue + } + mpkMap[mpk.DKGID] = mpk + idMap[mpk.ProposerID] = mpk.DKGID + } + // Recover qualify members' public key. + pubKeys := make(map[types.NodeID]*cryptoDKG.PublicKey, len(qualifyIDs)) + for _, recvID := range qualifyIDs { + pubShares := cryptoDKG.NewEmptyPublicKeyShares() + for _, id := range qualifyIDs { + pubShare, err := mpkMap[id].PublicKeyShares.Share(recvID) + if err != nil { + return nil, err + } + if err := pubShares.AddShare(id, pubShare); err != nil { + return nil, err + } + } + pubKey, err := pubShares.RecoverPublicKey(qualifyIDs) + if err != nil { + return nil, err + } + pubKeys[mpkMap[recvID].ProposerID] = pubKey + } + return &NodePublicKeys{ + Round: round, + QualifyIDs: qualifyIDs, + QualifyNodeIDs: qualifyNodeIDs, + IDMap: idMap, + PublicKeys: pubKeys, + Threshold: threshold, + }, nil +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/message.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/message.go new file mode 100644 index 000000000..0335cfaae --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/message.go @@ -0,0 +1,24 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +// Msg for the network ReceiveChan. +type Msg struct { + PeerID interface{} + Payload interface{} +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/node.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/node.go new file mode 100644 index 000000000..84b38a3b1 --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/node.go @@ -0,0 +1,61 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +import ( + "bytes" + "encoding/hex" + + "github.com/byzantine-lab/dexon-consensus/common" + "github.com/byzantine-lab/dexon-consensus/core/crypto" +) + +// NodeID is the ID type for nodes. +type NodeID struct { + common.Hash +} + +// NewNodeID returns a NodeID with Hash set to the hash value of +// public key. +func NewNodeID(pubKey crypto.PublicKey) NodeID { + return NodeID{Hash: crypto.Keccak256Hash(pubKey.Bytes()[1:])} +} + +// Equal checks if the hash representation is the same NodeID. +func (v NodeID) Equal(v2 NodeID) bool { + return v.Hash == v2.Hash +} + +func (v NodeID) String() string { + return hex.EncodeToString(v.Hash[:])[:6] +} + +// NodeIDs implements sort.Interface for NodeID. +type NodeIDs []NodeID + +func (v NodeIDs) Len() int { + return len(v) +} + +func (v NodeIDs) Less(i int, j int) bool { + return bytes.Compare([]byte(v[i].Hash[:]), []byte(v[j].Hash[:])) == -1 +} + +func (v NodeIDs) Swap(i int, j int) { + v[i], v[j] = v[j], v[i] +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/nodeset.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/nodeset.go new file mode 100644 index 000000000..522bcb224 --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/nodeset.go @@ -0,0 +1,162 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +import ( + "container/heap" + "encoding/binary" + "math/big" + + "github.com/byzantine-lab/dexon-consensus/common" + "github.com/byzantine-lab/dexon-consensus/core/crypto" +) + +// NodeSet is the node set structure as defined in DEXON consensus core. +type NodeSet struct { + IDs map[NodeID]struct{} +} + +// SubSetTarget is the sub set target for GetSubSet(). +type SubSetTarget struct { + data [][]byte +} + +type subSetTargetType byte + +const ( + targetNotarySet subSetTargetType = iota + targetNodeLeader +) + +type nodeRank struct { + ID NodeID + rank *big.Int +} + +// rankHeap is a MaxHeap structure. +type rankHeap []*nodeRank + +func (h rankHeap) Len() int { return len(h) } +func (h rankHeap) Less(i, j int) bool { return h[i].rank.Cmp(h[j].rank) > 0 } +func (h rankHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *rankHeap) Push(x interface{}) { + *h = append(*h, x.(*nodeRank)) +} +func (h *rankHeap) Pop() interface{} { + old := *h + n := len(old) + x := old[n-1] + *h = old[0 : n-1] + return x +} + +// NewNodeSet creates a new NodeSet instance. +func NewNodeSet() *NodeSet { + return &NodeSet{ + IDs: make(map[NodeID]struct{}), + } +} + +// NewNodeSetFromMap creates a new NodeSet from NodeID map. +func NewNodeSetFromMap(nodes map[NodeID]struct{}) *NodeSet { + nIDs := make(map[NodeID]struct{}, len(nodes)) + for nID := range nodes { + nIDs[nID] = struct{}{} + } + return &NodeSet{ + IDs: nIDs, + } +} + +// NewNotarySetTarget is the target for getting Notary Set. +func NewNotarySetTarget(crs common.Hash) *SubSetTarget { + return newTarget(targetNotarySet, crs[:]) +} + +// NewNodeLeaderTarget is the target for getting leader of fast BA. +func NewNodeLeaderTarget(crs common.Hash, height uint64) *SubSetTarget { + binaryHeight := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryHeight, height) + return newTarget(targetNodeLeader, crs[:], binaryHeight) +} + +// Add a NodeID to the set. +func (ns *NodeSet) Add(ID NodeID) { + ns.IDs[ID] = struct{}{} +} + +// Clone the NodeSet. +func (ns *NodeSet) Clone() *NodeSet { + nsCopy := NewNodeSet() + for ID := range ns.IDs { + nsCopy.Add(ID) + } + return nsCopy +} + +// GetSubSet returns the subset of given target. +func (ns *NodeSet) GetSubSet( + size int, target *SubSetTarget) map[NodeID]struct{} { + if size == 0 { + return make(map[NodeID]struct{}) + } + h := rankHeap{} + idx := 0 + for nID := range ns.IDs { + if idx < size { + h = append(h, newNodeRank(nID, target)) + } else if idx == size { + heap.Init(&h) + } + if idx >= size { + rank := newNodeRank(nID, target) + if rank.rank.Cmp(h[0].rank) < 0 { + h[0] = rank + heap.Fix(&h, 0) + } + } + idx++ + } + + nIDs := make(map[NodeID]struct{}, size) + for _, rank := range h { + nIDs[rank.ID] = struct{}{} + } + + return nIDs +} + +func newTarget(targetType subSetTargetType, data ...[]byte) *SubSetTarget { + data = append(data, []byte{byte(targetType)}) + return &SubSetTarget{ + data: data, + } +} + +func newNodeRank(ID NodeID, target *SubSetTarget) *nodeRank { + data := make([][]byte, 1, len(target.data)+1) + data[0] = make([]byte, len(ID.Hash)) + copy(data[0], ID.Hash[:]) + data = append(data, target.data...) + h := crypto.Keccak256Hash(data...) + num := new(big.Int).SetBytes(h[:]) + return &nodeRank{ + ID: ID, + rank: num, + } +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/position.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/position.go new file mode 100644 index 000000000..81d23c266 --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/position.go @@ -0,0 +1,51 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +import ( + "fmt" +) + +// Position describes the position in the block lattice of an entity. +type Position struct { + Round uint64 `json:"round"` + Height uint64 `json:"height"` +} + +func (pos Position) String() string { + return fmt.Sprintf("Position{Round:%d Height:%d}", pos.Round, pos.Height) +} + +// Equal checks if two positions are equal. +func (pos Position) Equal(other Position) bool { + return pos.Round == other.Round && pos.Height == other.Height +} + +// Newer checks if one block is newer than another one on the same chain. +// If two blocks on different chain compared by this function, it would panic. +func (pos Position) Newer(other Position) bool { + return pos.Round > other.Round || + (pos.Round == other.Round && pos.Height > other.Height) +} + +// Older checks if one block is older than another one on the same chain. +// If two blocks on different chain compared by this function, it would panic. +func (pos Position) Older(other Position) bool { + return pos.Round < other.Round || + (pos.Round == other.Round && pos.Height < other.Height) +} diff --git a/vendor/github.com/byzantine-lab/dexon-consensus/core/types/vote.go b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/vote.go new file mode 100644 index 000000000..def09293a --- /dev/null +++ b/vendor/github.com/byzantine-lab/dexon-consensus/core/types/vote.go @@ -0,0 +1,100 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package types + +import ( + "fmt" + + "github.com/byzantine-lab/dexon-consensus/common" + "github.com/byzantine-lab/dexon-consensus/core/crypto" + cryptoDKG "github.com/byzantine-lab/dexon-consensus/core/crypto/dkg" +) + +// VoteType is the type of vote. +type VoteType byte + +// VoteType enum. +const ( + VoteInit VoteType = iota + VotePreCom + VoteCom + VoteFast + VoteFastCom + // Do not add any type below MaxVoteType. + MaxVoteType +) + +// NullBlockHash is the blockHash for ⊥ value. +var NullBlockHash common.Hash + +// SkipBlockHash is the blockHash for SKIP value. +var SkipBlockHash common.Hash + +func init() { + for idx := range SkipBlockHash { + SkipBlockHash[idx] = 0xff + } +} + +// VoteHeader is the header for vote, which can be used as map keys. +type VoteHeader struct { + ProposerID NodeID `json:"proposer_id"` + Type VoteType `json:"type"` + BlockHash common.Hash `json:"block_hash"` + Period uint64 `json:"period"` + Position Position `json:"position"` +} + +// Vote is the vote structure defined in Crypto Shuffle Algorithm. +type Vote struct { + VoteHeader `json:"header"` + PartialSignature cryptoDKG.PartialSignature `json:"partial_signature"` + Signature crypto.Signature `json:"signature"` +} + +func (v *Vote) String() string { + return fmt.Sprintf("Vote{VP:%s %s Period:%d Type:%d Hash:%s}", + v.ProposerID.String()[:6], + v.Position, v.Period, v.Type, v.BlockHash.String()[:6]) +} + +// NewVote constructs a Vote instance with header fields. +func NewVote(t VoteType, hash common.Hash, period uint64) *Vote { + return &Vote{ + VoteHeader: VoteHeader{ + Type: t, + BlockHash: hash, + Period: period, + }} +} + +// Clone returns a deep copy of a vote. +func (v *Vote) Clone() *Vote { + return &Vote{ + VoteHeader: VoteHeader{ + ProposerID: v.ProposerID, + Type: v.Type, + BlockHash: v.BlockHash, + Period: v.Period, + Position: v.Position, + }, + PartialSignature: cryptoDKG.PartialSignature( + crypto.Signature(v.PartialSignature).Clone()), + Signature: v.Signature.Clone(), + } +} |