aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-08-08 11:28:57 +0800
committerGitHub <noreply@github.com>2018-08-08 11:28:57 +0800
commita418ea95c0f5afb50cbb78aedecc68373353d06e (patch)
tree79bee8ef152f58c0b3bbcbe38d4dd537050b72aa /core
parent3a929b656b6bd5846849fd98dc29ff761db97ed3 (diff)
downloaddexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.gz
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.bz2
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.lz
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.xz
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.zst
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.zip
crypto: Add crypto module. (#34)
Diffstat (limited to 'core')
-rw-r--r--core/blocklattice.go2
-rw-r--r--core/consensus-timestamp.go10
-rw-r--r--core/consensus-timestamp_test.go2
-rw-r--r--core/crypto.go58
-rw-r--r--core/crypto_test.go116
-rw-r--r--core/types/block.go36
6 files changed, 210 insertions, 14 deletions
diff --git a/core/blocklattice.go b/core/blocklattice.go
index f94cc9a..0f5fc11 100644
--- a/core/blocklattice.go
+++ b/core/blocklattice.go
@@ -542,7 +542,7 @@ func (l *BlockLattice) totalOrdering(b *types.Block) {
panic(err)
}
for _, block := range blocksReady {
- l.app.DeliverBlock(block.Hash, block.ConsensusTime)
+ l.app.DeliverBlock(block.Hash, block.ConsensusInfo.Timestamp)
}
}
diff --git a/core/consensus-timestamp.go b/core/consensus-timestamp.go
index e9b5cce..ab904fb 100644
--- a/core/consensus-timestamp.go
+++ b/core/consensus-timestamp.go
@@ -72,17 +72,19 @@ func (ct *consensusTimestamp) processBlocks(blocks []*types.Block) (
return
} else if block.Hash == mainChain[idxMainChain].Hash {
rightMainChainIdx = idx
- blocksWithTimestamp[idx].ConsensusTime, err = ct.getMedianTime(block)
+ blocksWithTimestamp[idx].ConsensusInfo.Timestamp, err =
+ ct.getMedianTime(block)
if err != nil {
return
}
// Process Non-MainChain blocks.
if rightMainChainIdx > leftMainChainIdx {
for idx, timestamp := range interpoTime(
- blocksWithTimestamp[leftMainChainIdx].ConsensusTime,
- blocksWithTimestamp[rightMainChainIdx].ConsensusTime,
+ blocksWithTimestamp[leftMainChainIdx].ConsensusInfo.Timestamp,
+ blocksWithTimestamp[rightMainChainIdx].ConsensusInfo.Timestamp,
rightMainChainIdx-leftMainChainIdx-1) {
- blocksWithTimestamp[leftMainChainIdx+idx+1].ConsensusTime = timestamp
+ blocksWithTimestamp[leftMainChainIdx+idx+1].ConsensusInfo.Timestamp =
+ timestamp
}
}
leftMainChainIdx = idx
diff --git a/core/consensus-timestamp_test.go b/core/consensus-timestamp_test.go
index 8a82080..aeba00a 100644
--- a/core/consensus-timestamp_test.go
+++ b/core/consensus-timestamp_test.go
@@ -79,7 +79,7 @@ func fillBlocksTimestamps(blocks []*types.Block, validatorNum int,
func extractTimestamps(blocks []*types.Block) []time.Time {
timestamps := make([]time.Time, len(blocks))
for idx, block := range blocks {
- timestamps[idx] = block.ConsensusTime
+ timestamps[idx] = block.ConsensusInfo.Timestamp
}
return timestamps
}
diff --git a/core/crypto.go b/core/crypto.go
new file mode 100644
index 0000000..679b045
--- /dev/null
+++ b/core/crypto.go
@@ -0,0 +1,58 @@
+// 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 (
+ "encoding/binary"
+
+ "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"
+)
+
+func hashCompactionChainAck(block *types.Block) (common.Hash, error) {
+ binaryTime, err := block.ConsensusInfo.Timestamp.MarshalBinary()
+ if err != nil {
+ return common.Hash{}, err
+ }
+ binaryHeight := make([]byte, 8)
+ binary.LittleEndian.PutUint64(binaryHeight, block.ConsensusInfo.Height)
+ hash := crypto.Keccak256Hash(
+ block.ConsensusInfoParentHash[:],
+ binaryTime,
+ binaryHeight)
+ return hash, nil
+}
+
+func signCompactionChainAck(block *types.Block,
+ prv crypto.PrivateKey) (crypto.Signature, error) {
+ hash, err := hashCompactionChainAck(block)
+ if err != nil {
+ return crypto.Signature{}, err
+ }
+ return prv.Sign(hash)
+}
+
+func verifyCompactionChainAckSignature(pubkey crypto.PublicKey,
+ ackingBlock *types.Block, sig crypto.Signature) (bool, error) {
+ hash, err := hashCompactionChainAck(ackingBlock)
+ if err != nil {
+ return false, err
+ }
+ return pubkey.VerifySignature(hash, sig), nil
+}
diff --git a/core/crypto_test.go b/core/crypto_test.go
new file mode 100644
index 0000000..0ee28e4
--- /dev/null
+++ b/core/crypto_test.go
@@ -0,0 +1,116 @@
+// 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"
+ "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"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto/eth"
+ "github.com/stretchr/testify/suite"
+)
+
+type CryptoTestSuite struct {
+ suite.Suite
+}
+
+func (s *CryptoTestSuite) newBlock(prevBlock *types.Block) *types.Block {
+ if prevBlock == nil {
+ return &types.Block{
+ Hash: common.NewRandomHash(),
+ ConsensusInfo: types.ConsensusInfo{
+ Timestamp: time.Now(),
+ Height: 0,
+ },
+ }
+ }
+ parentHash, err := hashCompactionChainAck(prevBlock)
+ s.Require().Nil(err)
+ return &types.Block{
+ Hash: common.NewRandomHash(),
+ ConsensusInfoParentHash: parentHash,
+ CompactionChainAck: types.CompactionChainAck{
+ AckingBlockHash: prevBlock.Hash,
+ },
+ ConsensusInfo: types.ConsensusInfo{
+ Timestamp: time.Now(),
+ Height: prevBlock.ConsensusInfo.Height + 1,
+ },
+ }
+}
+
+func (s *CryptoTestSuite) generateCompactionChain(
+ length int, prv crypto.PrivateKey) []*types.Block {
+ blocks := make([]*types.Block, length)
+ var prevBlock *types.Block
+ for idx := range blocks {
+ block := s.newBlock(prevBlock)
+ blocks[idx] = block
+ var err error
+ if idx > 0 {
+ block.ConsensusInfoParentHash, err = hashCompactionChainAck(blocks[idx-1])
+ s.Require().Nil(err)
+ block.CompactionChainAck.ConsensusSignature, err =
+ signCompactionChainAck(blocks[idx-1], prv)
+ s.Require().Nil(err)
+ }
+ }
+ return blocks
+}
+
+func (s *CryptoTestSuite) TestSignature() {
+ prv, err := eth.NewPrivateKey()
+ pub := prv.PublicKey()
+ s.Require().Nil(err)
+ blocks := s.generateCompactionChain(10, prv)
+ blockMap := make(map[common.Hash]*types.Block)
+ for _, block := range blocks {
+ blockMap[block.Hash] = block
+ }
+ for _, block := range blocks {
+ if block.ConsensusInfo.Height == 0 {
+ continue
+ }
+ ackingBlock, exist := blockMap[block.CompactionChainAck.AckingBlockHash]
+ s.Require().True(exist)
+ s.True(ackingBlock.ConsensusInfo.Height == block.ConsensusInfo.Height-1)
+ hash, err := hashCompactionChainAck(ackingBlock)
+ s.Require().Nil(err)
+ s.Equal(hash, block.ConsensusInfoParentHash)
+ s.True(verifyCompactionChainAckSignature(
+ pub, ackingBlock, block.CompactionChainAck.ConsensusSignature))
+ }
+ // Modify Block.ConsensusTime and verify signature again.
+ for _, block := range blocks {
+ block.ConsensusInfo.Timestamp = time.Time{}
+ if block.ConsensusInfo.Height == 0 {
+ continue
+ }
+ ackingBlock, exist := blockMap[block.CompactionChainAck.AckingBlockHash]
+ s.Require().True(exist)
+ s.False(verifyCompactionChainAckSignature(
+ pub, ackingBlock, block.CompactionChainAck.ConsensusSignature))
+ }
+}
+
+func TestCrypto(t *testing.T) {
+ suite.Run(t, new(CryptoTestSuite))
+}
diff --git a/core/types/block.go b/core/types/block.go
index 56b456c..8a27ab0 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -23,6 +23,7 @@ import (
"time"
"github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
)
// Status represents the block process state.
@@ -36,16 +37,35 @@ const (
BlockStatusFinal
)
+// 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
+ // Block.ConsensusInfoParentHash and Block.ConsensusInfo.
+ ConsensusSignature crypto.Signature `json:"consensus_signature"`
+}
+
+// ConsensusInfo represents the consensus information on the compaction chain.
+type ConsensusInfo struct {
+ Timestamp time.Time `json:"timestamp"`
+ Height uint64 `json:"height"`
+}
+
// Block represents a single event broadcasted on the network.
type Block struct {
- ProposerID ValidatorID `json:"proposer_id"`
- ParentHash common.Hash `json:"parent_hash"`
- Hash common.Hash `json:"hash"`
- Height uint64 `json:"height"`
- Timestamps map[ValidatorID]time.Time `json:"timestamps"`
- Acks map[common.Hash]struct{} `json:"acks"`
- ConsensusTime time.Time `json:"consensus_time"`
- ConsensusHeight uint64 `json:"consensus_height"`
+ ProposerID ValidatorID `json:"proposer_id"`
+ ParentHash common.Hash `json:"parent_hash"`
+ Hash common.Hash `json:"hash"`
+ Height uint64 `json:"height"`
+ Timestamps map[ValidatorID]time.Time `json:"timestamps"`
+ Acks map[common.Hash]struct{} `json:"acks"`
+ CompactionChainAck CompactionChainAck `json:"compaction_chain_ack"`
+
+ ConsensusInfo ConsensusInfo `json:"consensus_info"`
+ // ConsensusInfoParentHash is the hash value of Block.ConsensusInfoParentHash
+ // and Block.ConsensusInfo, where Block is the previous block on
+ // the compaction chain.
+ ConsensusInfoParentHash common.Hash `json:"consensus_info_parent_hash"`
Ackeds map[common.Hash]struct{} `json:"-"`
AckedValidators map[ValidatorID]struct{} `json:"-"`