diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-08-16 10:22:54 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-16 10:22:54 +0800 |
commit | 96fcee4688dacd812292376994a3500e2c78edeb (patch) | |
tree | 2e15153e47b9d75bce11e35d47ad265466856afa | |
parent | d3107b56cbef1f05baddb64880c3e97d7eda87a4 (diff) | |
download | dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.tar dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.tar.gz dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.tar.bz2 dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.tar.lz dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.tar.xz dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.tar.zst dexon-consensus-96fcee4688dacd812292376994a3500e2c78edeb.zip |
core: Add compaction chain module. (#60)
-rw-r--r-- | core/compaction-chain.go | 73 | ||||
-rw-r--r-- | core/compaction-chain_test.go | 88 | ||||
-rw-r--r-- | core/consensus.go | 9 | ||||
-rw-r--r-- | core/crypto.go | 10 | ||||
-rw-r--r-- | core/crypto_test.go | 18 | ||||
-rw-r--r-- | core/types/block.go | 8 |
6 files changed, 188 insertions, 18 deletions
diff --git a/core/compaction-chain.go b/core/compaction-chain.go new file mode 100644 index 0000000..7890b4f --- /dev/null +++ b/core/compaction-chain.go @@ -0,0 +1,73 @@ +// 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 ( + "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" +) + +type compactionChain struct { + prevBlock *types.Block + lock sync.RWMutex +} + +func newCompactionChain() *compactionChain { + return &compactionChain{} +} + +func (cc *compactionChain) prepareBlock( + block *types.Block, prvKey crypto.PrivateKey) (err error) { + prevBlock := cc.lastBlock() + if prevBlock != nil { + block.CompactionChainAck.ConsensusInfoSignature, err = + signConsensusInfo(prevBlock, prvKey) + if err != nil { + return + } + block.CompactionChainAck.AckingBlockHash = prevBlock.Hash + } + return +} + +func (cc *compactionChain) processBlock(block *types.Block) (err error) { + prevBlock := cc.lastBlock() + if prevBlock == nil { + block.ConsensusInfo.Height = 0 + block.ConsensusInfoParentHash = common.Hash{} + } else { + block.ConsensusInfo.Height = prevBlock.ConsensusInfo.Height + 1 + block.ConsensusInfoParentHash, err = hashConsensusInfo(prevBlock) + if err != nil { + return + } + } + cc.lock.Lock() + defer cc.lock.Unlock() + cc.prevBlock = block + return +} + +func (cc *compactionChain) lastBlock() *types.Block { + cc.lock.RLock() + defer cc.lock.RUnlock() + return cc.prevBlock +} diff --git a/core/compaction-chain_test.go b/core/compaction-chain_test.go new file mode 100644 index 0000000..402394d --- /dev/null +++ b/core/compaction-chain_test.go @@ -0,0 +1,88 @@ +// 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 ( + "testing" + + "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/eth" + "github.com/stretchr/testify/suite" +) + +type CompactionChainTestSuite struct { + suite.Suite +} + +func (s *CompactionChainTestSuite) TestProcessBlock() { + cc := newCompactionChain() + blocks := make([]*types.Block, 10) + for idx := range blocks { + blocks[idx] = &types.Block{ + Hash: common.NewRandomHash(), + } + } + var prevBlock *types.Block + for _, block := range blocks { + s.Equal(cc.prevBlock, prevBlock) + cc.processBlock(block) + if prevBlock != nil { + s.Equal(block.ConsensusInfo.Height, prevBlock.ConsensusInfo.Height+1) + prevHash, err := hashConsensusInfo(prevBlock) + s.Require().Nil(err) + s.Equal(prevHash, block.ConsensusInfoParentHash) + } + prevBlock = block + } +} + +func (s *CompactionChainTestSuite) TestPrepareBlock() { + cc := newCompactionChain() + blocks := make([]*types.Block, 10) + for idx := range blocks { + blocks[idx] = &types.Block{ + Hash: common.NewRandomHash(), + ConsensusInfo: types.ConsensusInfo{ + Height: uint64(idx), + }, + } + if idx > 0 { + var err error + blocks[idx].ConsensusInfoParentHash, err = hashConsensusInfo(blocks[idx-1]) + s.Require().Nil(err) + } + } + prv, err := eth.NewPrivateKey() + s.Require().Nil(err) + for _, block := range blocks { + cc.prepareBlock(block, prv) + if cc.prevBlock != nil { + s.True(verifyConsensusInfoSignature( + prv.PublicKey(), + cc.prevBlock, + block.CompactionChainAck.ConsensusInfoSignature)) + s.Equal(block.CompactionChainAck.AckingBlockHash, cc.prevBlock.Hash) + } + cc.prevBlock = block + } +} + +func TestCompactionChain(t *testing.T) { + suite.Run(t, new(CompactionChainTestSuite)) +} diff --git a/core/consensus.go b/core/consensus.go index f591db5..36e54ec 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -56,6 +56,7 @@ type Consensus struct { rbModule *reliableBroadcast toModule *totalOrdering ctModule *consensusTimestamp + ccModule *compactionChain db blockdb.BlockDatabase prvKey crypto.PrivateKey sigToPub SigToPubFn @@ -87,6 +88,7 @@ func NewConsensus( rbModule: rb, toModule: to, ctModule: newConsensusTimestamp(), + ccModule: newCompactionChain(), app: newNonBlockingApplication(app), gov: gov, db: db, @@ -165,6 +167,9 @@ func (con *Consensus) ProcessBlock(blockConv types.BlockConverter) (err error) { return } for _, b := range deliveredBlocks { + if err = con.ccModule.processBlock(b); err != nil { + return + } if err = con.db.Update(*b); err != nil { return } @@ -203,6 +208,10 @@ func (con *Consensus) PrepareBlock(blockConv types.BlockConverter, if err != nil { return } + err = con.ccModule.prepareBlock(b, con.prvKey) + if err != nil { + return + } blockConv.SetBlock(b) return } diff --git a/core/crypto.go b/core/crypto.go index 564ad38..e193e36 100644 --- a/core/crypto.go +++ b/core/crypto.go @@ -26,7 +26,7 @@ import ( "github.com/dexon-foundation/dexon-consensus-core/crypto" ) -func hashCompactionChainAck(block *types.Block) (common.Hash, error) { +func hashConsensusInfo(block *types.Block) (common.Hash, error) { binaryTime, err := block.ConsensusInfo.Timestamp.MarshalBinary() if err != nil { return common.Hash{}, err @@ -40,18 +40,18 @@ func hashCompactionChainAck(block *types.Block) (common.Hash, error) { return hash, nil } -func signCompactionChainAck(block *types.Block, +func signConsensusInfo(block *types.Block, prv crypto.PrivateKey) (crypto.Signature, error) { - hash, err := hashCompactionChainAck(block) + hash, err := hashConsensusInfo(block) if err != nil { return crypto.Signature{}, err } return prv.Sign(hash) } -func verifyCompactionChainAckSignature(pubkey crypto.PublicKey, +func verifyConsensusInfoSignature(pubkey crypto.PublicKey, ackingBlock *types.Block, sig crypto.Signature) (bool, error) { - hash, err := hashCompactionChainAck(ackingBlock) + hash, err := hashConsensusInfo(ackingBlock) if err != nil { return false, err } diff --git a/core/crypto_test.go b/core/crypto_test.go index e59e66e..f5ec28e 100644 --- a/core/crypto_test.go +++ b/core/crypto_test.go @@ -64,7 +64,7 @@ func (s *CryptoTestSuite) prepareBlock(prevBlock *types.Block) *types.Block { }, } } - parentHash, err := hashCompactionChainAck(prevBlock) + parentHash, err := hashConsensusInfo(prevBlock) s.Require().Nil(err) s.Require().NotEqual(prevBlock.Hash, common.Hash{}) acks[parentHash] = struct{}{} @@ -102,10 +102,10 @@ func (s *CryptoTestSuite) generateCompactionChain( blocks[idx] = block var err error if idx > 0 { - block.ConsensusInfoParentHash, err = hashCompactionChainAck(blocks[idx-1]) + block.ConsensusInfoParentHash, err = hashConsensusInfo(blocks[idx-1]) s.Require().Nil(err) - block.CompactionChainAck.ConsensusSignature, err = - signCompactionChainAck(blocks[idx-1], prv) + block.CompactionChainAck.ConsensusInfoSignature, err = + signConsensusInfo(blocks[idx-1], prv) s.Require().Nil(err) } } @@ -128,11 +128,11 @@ func (s *CryptoTestSuite) TestCompactionChainAckSignature() { ackingBlock, exist := blockMap[block.CompactionChainAck.AckingBlockHash] s.Require().True(exist) s.True(ackingBlock.ConsensusInfo.Height == block.ConsensusInfo.Height-1) - hash, err := hashCompactionChainAck(ackingBlock) + hash, err := hashConsensusInfo(ackingBlock) s.Require().Nil(err) s.Equal(hash, block.ConsensusInfoParentHash) - s.True(verifyCompactionChainAckSignature( - pub, ackingBlock, block.CompactionChainAck.ConsensusSignature)) + s.True(verifyConsensusInfoSignature( + pub, ackingBlock, block.CompactionChainAck.ConsensusInfoSignature)) } // Modify Block.ConsensusTime and verify signature again. for _, block := range blocks { @@ -142,8 +142,8 @@ func (s *CryptoTestSuite) TestCompactionChainAckSignature() { } ackingBlock, exist := blockMap[block.CompactionChainAck.AckingBlockHash] s.Require().True(exist) - s.False(verifyCompactionChainAckSignature( - pub, ackingBlock, block.CompactionChainAck.ConsensusSignature)) + s.False(verifyConsensusInfoSignature( + pub, ackingBlock, block.CompactionChainAck.ConsensusInfoSignature)) } } diff --git a/core/types/block.go b/core/types/block.go index 15fae8b..0fa16d4 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -40,9 +40,9 @@ const ( // CompactionChainAck represents the acking to the compaction chain. type CompactionChainAck struct { AckingBlockHash common.Hash `json:"acking_block_hash"` - // Signature is the signature of the hash value of + // ConsensusInfoSignature is the signature of the hash value of // Block.ConsensusInfoParentHash and Block.ConsensusInfo. - ConsensusSignature crypto.Signature `json:"consensus_signature"` + ConsensusInfoSignature crypto.Signature `json:"consensus_info_signature"` } // ConsensusInfo represents the consensus information on the compaction chain. @@ -120,8 +120,8 @@ func (b *Block) Clone() *Block { }, ConsensusInfoParentHash: b.ConsensusInfoParentHash, } - bcopy.CompactionChainAck.ConsensusSignature = append( - crypto.Signature(nil), b.CompactionChainAck.ConsensusSignature...) + bcopy.CompactionChainAck.ConsensusInfoSignature = append( + crypto.Signature(nil), b.CompactionChainAck.ConsensusInfoSignature...) for k, v := range b.Timestamps { bcopy.Timestamps[k] = v } |