aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-08-16 10:22:54 +0800
committerGitHub <noreply@github.com>2018-08-16 10:22:54 +0800
commit96fcee4688dacd812292376994a3500e2c78edeb (patch)
tree2e15153e47b9d75bce11e35d47ad265466856afa
parentd3107b56cbef1f05baddb64880c3e97d7eda87a4 (diff)
downloaddexon-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.go73
-rw-r--r--core/compaction-chain_test.go88
-rw-r--r--core/consensus.go9
-rw-r--r--core/crypto.go10
-rw-r--r--core/crypto_test.go18
-rw-r--r--core/types/block.go8
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
}