diff options
Diffstat (limited to 'vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go')
-rw-r--r-- | vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go new file mode 100644 index 000000000..bde07d518 --- /dev/null +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go @@ -0,0 +1,341 @@ +// 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" + "sort" + "sync" + "time" + + "github.com/dexon-foundation/dexon/rlp" + + "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core/crypto" +) + +// 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 +) + +var ( + // blockPool is the blocks cache to reuse allocated blocks. + blockPool = sync.Pool{ + New: func() interface{} { + return &Block{} + }, + } +) + +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 +} + +// FinalizationResult represents the result of DEXON consensus algorithm. +type FinalizationResult struct { + ParentHash common.Hash `json:"parent_hash"` + Randomness []byte `json:"randomness"` + Timestamp time.Time `json:"timestamp"` + Height uint64 `json:"height"` +} + +type rlpFinalizationResult struct { + ParentHash common.Hash + Randomness []byte + Timestamp *rlpTimestamp + Height uint64 +} + +// EncodeRLP implements rlp.Encoder +func (f *FinalizationResult) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, &rlpFinalizationResult{ + ParentHash: f.ParentHash, + Randomness: f.Randomness, + Timestamp: &rlpTimestamp{f.Timestamp}, + Height: f.Height, + }) +} + +// DecodeRLP implements rlp.Decoder +func (f *FinalizationResult) DecodeRLP(s *rlp.Stream) error { + var dec rlpFinalizationResult + err := s.Decode(&dec) + if err == nil { + *f = FinalizationResult{ + ParentHash: dec.ParentHash, + Randomness: dec.Randomness, + Timestamp: dec.Timestamp.Time, + Height: dec.Height, + } + } + return err +} + +// Witness represents the consensus information on the compaction chain. +type Witness struct { + Height uint64 `json:"height"` + Data []byte `json:"data"` +} + +// RecycleBlock put unused block into cache, which might be reused if +// not garbage collected. +func RecycleBlock(b *Block) { + blockPool.Put(b) +} + +// NewBlock initiate a block. +func NewBlock() (b *Block) { + b = blockPool.Get().(*Block) + b.Acks = b.Acks[:0] + return +} + +// 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"` + Acks common.SortedHashes `json:"acks"` + Payload []byte `json:"payload"` + PayloadHash common.Hash `json:"payload_hash"` + Witness Witness `json:"witness"` + Finalization FinalizationResult `json:"finalization"` + 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 + Acks common.SortedHashes + Payload []byte + PayloadHash common.Hash + Witness *Witness + Finalization *FinalizationResult + 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}, + Acks: b.Acks, + Payload: b.Payload, + PayloadHash: b.PayloadHash, + Witness: &b.Witness, + Finalization: &b.Finalization, + 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, + Acks: dec.Acks, + Payload: dec.Payload, + PayloadHash: dec.PayloadHash, + Witness: *dec.Witness, + Finalization: *dec.Finalization, + Signature: dec.Signature, + CRSSignature: dec.CRSSignature, + } + } + return err +} + +func (b *Block) String() string { + return fmt.Sprintf("Block(%v:%d:%d)", b.Hash.String()[:6], + b.Position.ChainID, b.Position.Height) +} + +// Clone returns a deep copy of a block. +func (b *Block) Clone() (bcopy *Block) { + bcopy = NewBlock() + bcopy.ProposerID = b.ProposerID + bcopy.ParentHash = b.ParentHash + bcopy.Hash = b.Hash + bcopy.Position.Round = b.Position.Round + bcopy.Position.ChainID = b.Position.ChainID + bcopy.Position.Height = b.Position.Height + bcopy.Signature = b.Signature.Clone() + bcopy.CRSSignature = b.CRSSignature.Clone() + bcopy.Finalization.ParentHash = b.Finalization.ParentHash + bcopy.Finalization.Timestamp = b.Finalization.Timestamp + bcopy.Finalization.Height = b.Finalization.Height + bcopy.Witness.Height = b.Witness.Height + bcopy.Witness.Data = make([]byte, len(b.Witness.Data)) + copy(bcopy.Witness.Data, b.Witness.Data) + bcopy.Timestamp = b.Timestamp + bcopy.Acks = make(common.SortedHashes, len(b.Acks)) + copy(bcopy.Acks, b.Acks) + bcopy.Payload = make([]byte, len(b.Payload)) + copy(bcopy.Payload, b.Payload) + bcopy.PayloadHash = b.PayloadHash + bcopy.Finalization.Randomness = make([]byte, len(b.Finalization.Randomness)) + copy(bcopy.Finalization.Randomness, b.Finalization.Randomness) + return +} + +// IsGenesis checks if the block is a genesisBlock +func (b *Block) IsGenesis() bool { + return b.Position.Height == 0 && b.ParentHash == common.Hash{} +} + +// IsFinalized checks if the finalization data is ready. +func (b *Block) IsFinalized() bool { + return b.Finalization.Height != 0 +} + +// IsEmpty checks if the block is an 'empty block'. +func (b *Block) IsEmpty() bool { + return b.ProposerID.Hash == common.Hash{} +} + +// IsAcking checks if a block acking another by it's hash. +func (b *Block) IsAcking(hash common.Hash) bool { + idx := sort.Search(len(b.Acks), func(i int) bool { + return bytes.Compare(b.Acks[i][:], hash[:]) >= 0 + }) + return !(idx == len(b.Acks) || b.Acks[idx] != 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] +} + +// ByPosition is the helper type for sorting slice of blocks by position. +type ByPosition []*Block + +// Len implements Len method in sort.Sort interface. +func (bs ByPosition) Len() int { + return len(bs) +} + +// Less implements Less method in sort.Sort interface. +func (bs ByPosition) Less(i int, j int) bool { + return bs[j].Position.Newer(&bs[i].Position) +} + +// Swap implements Swap method in sort.Sort interface. +func (bs ByPosition) Swap(i int, j int) { + bs[i], bs[j] = bs[j], bs[i] +} + +// Push implements Push method in heap interface. +func (bs *ByPosition) Push(x interface{}) { + *bs = append(*bs, x.(*Block)) +} + +// Pop implements Pop method in heap interface. +func (bs *ByPosition) Pop() (ret interface{}) { + n := len(*bs) + *bs, ret = (*bs)[0:n-1], (*bs)[n-1] + return +} + +// ByFinalizationHeight is the helper type for sorting slice of blocks by +// finalization height. +type ByFinalizationHeight []*Block + +// Len implements Len method in sort.Sort interface. +func (bs ByFinalizationHeight) Len() int { + return len(bs) +} + +// Less implements Less method in sort.Sort interface. +func (bs ByFinalizationHeight) Less(i int, j int) bool { + return bs[i].Finalization.Height < bs[j].Finalization.Height +} + +// Swap implements Swap method in sort.Sort interface. +func (bs ByFinalizationHeight) Swap(i int, j int) { + bs[i], bs[j] = bs[j], bs[i] +} + +// Push implements Push method in heap interface. +func (bs *ByFinalizationHeight) Push(x interface{}) { + *bs = append(*bs, x.(*Block)) +} + +// Pop implements Pop method in heap interface. +func (bs *ByFinalizationHeight) Pop() (ret interface{}) { + n := len(*bs) + *bs, ret = (*bs)[0:n-1], (*bs)[n-1] + return +} |