aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/compaction-chain.go2
-rw-r--r--core/compaction-chain_test.go12
-rw-r--r--core/consensus-timestamp.go2
-rw-r--r--core/consensus-timestamp_test.go2
-rw-r--r--core/crypto.go20
-rw-r--r--core/crypto_test.go16
-rw-r--r--core/interfaces.go7
-rw-r--r--core/lattice.go13
-rw-r--r--core/lattice_test.go33
-rw-r--r--core/nonblocking.go11
-rw-r--r--core/nonblocking_test.go8
-rw-r--r--core/test/app.go15
-rw-r--r--core/test/app_test.go7
-rw-r--r--core/test/stopper_test.go4
-rw-r--r--core/types/block.go22
15 files changed, 125 insertions, 49 deletions
diff --git a/core/compaction-chain.go b/core/compaction-chain.go
index 21b8412..c6d423d 100644
--- a/core/compaction-chain.go
+++ b/core/compaction-chain.go
@@ -59,7 +59,7 @@ func (cc *compactionChain) sanityCheck(witnessBlock *types.Block) error {
func (cc *compactionChain) processBlock(block *types.Block) error {
prevBlock := cc.lastBlock()
if prevBlock != nil {
- block.Witness.Height = prevBlock.Witness.Height + 1
+ block.ConsensusHeight = prevBlock.ConsensusHeight + 1
}
cc.prevBlockLock.Lock()
defer cc.prevBlockLock.Unlock()
diff --git a/core/compaction-chain_test.go b/core/compaction-chain_test.go
index b8f446e..6f62aa2 100644
--- a/core/compaction-chain_test.go
+++ b/core/compaction-chain_test.go
@@ -48,10 +48,8 @@ func (s *CompactionChainTestSuite) generateBlocks(
blocks := make([]*types.Block, size)
for idx := range blocks {
blocks[idx] = &types.Block{
- Hash: common.NewRandomHash(),
- Witness: types.Witness{
- Timestamp: now,
- },
+ Hash: common.NewRandomHash(),
+ ConsensusTimestamp: now,
}
now = now.Add(100 * time.Millisecond)
}
@@ -68,10 +66,8 @@ func (s *CompactionChainTestSuite) TestProcessBlock() {
blocks := make([]*types.Block, 10)
for idx := range blocks {
blocks[idx] = &types.Block{
- Hash: common.NewRandomHash(),
- Witness: types.Witness{
- Timestamp: now,
- },
+ Hash: common.NewRandomHash(),
+ ConsensusTimestamp: now,
}
now = now.Add(100 * time.Millisecond)
}
diff --git a/core/consensus-timestamp.go b/core/consensus-timestamp.go
index 9188c02..62298d9 100644
--- a/core/consensus-timestamp.go
+++ b/core/consensus-timestamp.go
@@ -63,7 +63,7 @@ func (ct *consensusTimestamp) appendConfig(
func (ct *consensusTimestamp) processBlocks(blocks []*types.Block) (err error) {
for _, block := range blocks {
if !block.IsGenesis() {
- block.Witness.Timestamp, err = getMedianTime(ct.chainTimestamps)
+ block.ConsensusTimestamp, err = getMedianTime(ct.chainTimestamps)
if err != nil {
return
}
diff --git a/core/consensus-timestamp_test.go b/core/consensus-timestamp_test.go
index ea85c38..615142c 100644
--- a/core/consensus-timestamp_test.go
+++ b/core/consensus-timestamp_test.go
@@ -82,7 +82,7 @@ func (s *ConsensusTimestampTest) extractTimestamps(
if block.IsGenesis() {
continue
}
- timestamps = append(timestamps, block.Witness.Timestamp)
+ timestamps = append(timestamps, block.ConsensusTimestamp)
}
return timestamps
}
diff --git a/core/crypto.go b/core/crypto.go
index a0bacac..6fc0d1b 100644
--- a/core/crypto.go
+++ b/core/crypto.go
@@ -25,6 +25,19 @@ import (
"github.com/dexon-foundation/dexon-consensus-core/core/types"
)
+func hashWitness(witness *types.Witness) (common.Hash, error) {
+ binaryTimestamp, err := witness.Timestamp.MarshalBinary()
+ if err != nil {
+ return common.Hash{}, err
+ }
+ binaryHeight := make([]byte, 8)
+ binary.LittleEndian.PutUint64(binaryHeight, witness.Height)
+ return crypto.Keccak256Hash(
+ binaryHeight,
+ binaryTimestamp,
+ witness.Data), nil
+}
+
func hashBlock(block *types.Block) (common.Hash, error) {
hashPosition := hashPosition(block.Position)
// Handling Block.Acks.
@@ -37,6 +50,10 @@ func hashBlock(block *types.Block) (common.Hash, error) {
if err != nil {
return common.Hash{}, err
}
+ binaryWitness, err := hashWitness(&block.Witness)
+ if err != nil {
+ return common.Hash{}, err
+ }
payloadHash := crypto.Keccak256Hash(block.Payload)
hash := crypto.Keccak256Hash(
@@ -45,7 +62,8 @@ func hashBlock(block *types.Block) (common.Hash, error) {
hashPosition[:],
hashAcks[:],
binaryTimestamp[:],
- payloadHash[:])
+ payloadHash[:],
+ binaryWitness[:])
return hash, nil
}
diff --git a/core/crypto_test.go b/core/crypto_test.go
index 1fdc802..dabcb21 100644
--- a/core/crypto_test.go
+++ b/core/crypto_test.go
@@ -40,12 +40,10 @@ func (s *CryptoTestSuite) prepareBlock(prevBlock *types.Block) *types.Block {
now := time.Now().UTC()
if prevBlock == nil {
return &types.Block{
- Acks: common.NewSortedHashes(acks),
- Timestamp: now,
- Witness: types.Witness{
- Timestamp: time.Now(),
- Height: 0,
- },
+ Acks: common.NewSortedHashes(acks),
+ Timestamp: now,
+ ConsensusTimestamp: time.Now(),
+ ConsensusHeight: 0,
}
}
s.Require().NotEqual(prevBlock.Hash, common.Hash{})
@@ -56,10 +54,8 @@ func (s *CryptoTestSuite) prepareBlock(prevBlock *types.Block) *types.Block {
Position: types.Position{
Height: prevBlock.Position.Height + 1,
},
- Witness: types.Witness{
- Timestamp: time.Now(),
- Height: prevBlock.Witness.Height + 1,
- },
+ ConsensusTimestamp: time.Now(),
+ ConsensusHeight: prevBlock.ConsensusHeight + 1,
}
}
diff --git a/core/interfaces.go b/core/interfaces.go
index fa593eb..c367933 100644
--- a/core/interfaces.go
+++ b/core/interfaces.go
@@ -28,8 +28,11 @@ import (
// Application describes the application interface that interacts with DEXON
// consensus core.
type Application interface {
- // PrepareBlock is called when consensus core is preparing a block.
- PrepareBlock(position types.Position) (payload []byte, witnessData []byte)
+ // PreparePayload is called when consensus core is preparing a block.
+ PreparePayload(position types.Position) (payload []byte)
+
+ // PrepareWitness will return the witness data no lower than consensusHeight.
+ PrepareWitness(consensusHeight uint64) (witness types.Witness)
// VerifyBlock verifies if the block is valid.
VerifyBlock(block *types.Block) bool
diff --git a/core/lattice.go b/core/lattice.go
index 8906c74..bb3bccd 100644
--- a/core/lattice.go
+++ b/core/lattice.go
@@ -38,6 +38,8 @@ var (
ErrInvalidChainID = fmt.Errorf("invalid chain id")
ErrInvalidProposerID = fmt.Errorf("invalid proposer id")
ErrInvalidTimestamp = fmt.Errorf("invalid timestamp")
+ ErrInvalidWitness = fmt.Errorf("invalid witness data")
+ ErrInvalidBlock = fmt.Errorf("invalid block")
ErrForkBlock = fmt.Errorf("fork block")
ErrNotAckParent = fmt.Errorf("not ack parent")
ErrDoubleAck = fmt.Errorf("double ack")
@@ -146,6 +148,9 @@ func (data *latticeData) sanityCheck(b *types.Block) error {
if bParent.Position.Height != b.Position.Height-1 {
return ErrInvalidBlockHeight
}
+ if bParent.Witness.Height > b.Witness.Height {
+ return ErrInvalidWitness
+ }
// Check if its timestamp is valid.
if !b.Timestamp.After(bParent.Timestamp) {
return ErrInvalidTimestamp
@@ -290,6 +295,7 @@ func (data *latticeData) prepareBlock(block *types.Block) {
if uint32(chainID) == block.Position.ChainID {
block.ParentHash = curBlock.Hash
block.Position.Height = curBlock.Position.Height + 1
+ block.Witness.Height = curBlock.Witness.Height
}
}
block.Acks = common.NewSortedHashes(acks)
@@ -465,7 +471,8 @@ func (s *Lattice) PrepareBlock(
// TODO(mission): the proposeTime might be earlier than tip block of
// that chain. We should let latticeData suggest the time.
b.Timestamp = proposeTime
- b.Payload, b.Witness.Data = s.app.PrepareBlock(b.Position)
+ b.Payload = s.app.PreparePayload(b.Position)
+ b.Witness = s.app.PrepareWitness(b.Witness.Height)
if err = s.authModule.SignBlock(b); err != nil {
return
}
@@ -492,6 +499,10 @@ func (s *Lattice) SanityCheck(b *types.Block) (err error) {
err = ErrIncorrectSignature
return
}
+ if !s.app.VerifyBlock(b) {
+ err = ErrInvalidBlock
+ return err
+ }
s.lock.RLock()
defer s.lock.RUnlock()
if err = s.data.sanityCheck(b); err != nil {
diff --git a/core/lattice_test.go b/core/lattice_test.go
index 1be9a0e..329d698 100644
--- a/core/lattice_test.go
+++ b/core/lattice_test.go
@@ -184,6 +184,9 @@ func (s *LatticeTestSuite) genTestCase1() (data *latticeData) {
Height: 1,
},
Acks: common.NewSortedHashes(common.Hashes{h}),
+ Witness: types.Witness{
+ Height: 1,
+ },
}
s.hashBlock(b)
delivered, err = data.addBlock(b)
@@ -205,6 +208,9 @@ func (s *LatticeTestSuite) genTestCase1() (data *latticeData) {
h,
data.chains[1].getBlockByHeight(0).Hash,
}),
+ Witness: types.Witness{
+ Height: 2,
+ },
}
s.hashBlock(b)
delivered, err = data.addBlock(b)
@@ -224,6 +230,9 @@ func (s *LatticeTestSuite) genTestCase1() (data *latticeData) {
Height: 3,
},
Acks: common.NewSortedHashes(common.Hashes{h}),
+ Witness: types.Witness{
+ Height: 3,
+ },
}
s.hashBlock(b)
delivered, err = data.addBlock(b)
@@ -243,6 +252,9 @@ func (s *LatticeTestSuite) genTestCase1() (data *latticeData) {
Height: 1,
},
Acks: common.NewSortedHashes(common.Hashes{h}),
+ Witness: types.Witness{
+ Height: 1,
+ },
}
s.hashBlock(b)
delivered, err = data.addBlock(b)
@@ -399,6 +411,27 @@ func (s *LatticeTestSuite) TestSanityCheckInDataLayer() {
req.NotNil(err)
req.Equal(err.Error(), ErrDuplicatedAckOnOneChain.Error())
+ // Witness height decreases.
+ h = data.chains[0].getBlockByHeight(3).Hash
+ b = &types.Block{
+ ParentHash: h,
+ Position: types.Position{
+ ChainID: 0,
+ Height: 4,
+ },
+ Timestamp: time.Now().UTC(),
+ Acks: common.NewSortedHashes(common.Hashes{
+ h,
+ }),
+ Witness: types.Witness{
+ Height: 2,
+ },
+ }
+ s.hashBlock(b)
+ err = data.sanityCheck(b)
+ req.NotNil(err)
+ req.Equal(err.Error(), ErrInvalidWitness.Error())
+
// Add block 3-1 which acks 3-0, and violet reasonable block time interval.
h = data.chains[2].getBlockByHeight(0).Hash
b = &types.Block{
diff --git a/core/nonblocking.go b/core/nonblocking.go
index 2e5bfeb..4948a4f 100644
--- a/core/nonblocking.go
+++ b/core/nonblocking.go
@@ -117,9 +117,14 @@ func (nb *nonBlocking) wait() {
nb.running.Wait()
}
-// PrepareBlock cannot be non-blocking.
-func (nb *nonBlocking) PrepareBlock(position types.Position) ([]byte, []byte) {
- return nb.app.PrepareBlock(position)
+// PreparePayload cannot be non-blocking.
+func (nb *nonBlocking) PreparePayload(position types.Position) []byte {
+ return nb.app.PreparePayload(position)
+}
+
+// PrepareWitness cannot be non-blocking.
+func (nb *nonBlocking) PrepareWitness(height uint64) types.Witness {
+ return nb.app.PrepareWitness(height)
}
// VerifyBlock cannot be non-blocking.
diff --git a/core/nonblocking_test.go b/core/nonblocking_test.go
index 8c3cda9..7599456 100644
--- a/core/nonblocking_test.go
+++ b/core/nonblocking_test.go
@@ -45,8 +45,12 @@ func newSlowApp(sleep time.Duration) *slowApp {
}
}
-func (app *slowApp) PrepareBlock(_ types.Position) ([]byte, []byte) {
- return []byte{}, []byte{}
+func (app *slowApp) PreparePayload(_ types.Position) []byte {
+ return []byte{}
+}
+
+func (app *slowApp) PrepareWitness(_ uint64) types.Witness {
+ return types.Witness{}
}
func (app *slowApp) VerifyBlock(_ *types.Block) bool {
diff --git a/core/test/app.go b/core/test/app.go
index 3ec670c..bf14d1b 100644
--- a/core/test/app.go
+++ b/core/test/app.go
@@ -96,9 +96,16 @@ func NewApp() *App {
}
}
-// PrepareBlock implements Application interface.
-func (app *App) PrepareBlock(position types.Position) ([]byte, []byte) {
- return []byte{}, []byte{}
+// PreparePayload implements Application interface.
+func (app *App) PreparePayload(position types.Position) []byte {
+ return []byte{}
+}
+
+// PrepareWitness implements Application interface.
+func (app *App) PrepareWitness(height uint64) types.Witness {
+ return types.Witness{
+ Height: height,
+ }
}
// VerifyBlock implements Application.
@@ -143,7 +150,7 @@ func (app *App) BlockDelivered(block types.Block) {
defer app.deliveredLock.Unlock()
app.Delivered[block.Hash] = &AppDeliveredRecord{
- ConsensusTime: block.Witness.Timestamp,
+ ConsensusTime: block.ConsensusTimestamp,
When: time.Now().UTC(),
}
app.DeliverSequence = append(app.DeliverSequence, block.Hash)
diff --git a/core/test/app_test.go b/core/test/app_test.go
index baea838..21d4e24 100644
--- a/core/test/app_test.go
+++ b/core/test/app_test.go
@@ -81,10 +81,9 @@ func (s *AppTestSuite) deliverBlock(
app *App, hash common.Hash, timestamp time.Time) {
app.BlockDelivered(types.Block{
- Hash: hash,
- Witness: types.Witness{
- Timestamp: timestamp,
- }})
+ Hash: hash,
+ ConsensusTimestamp: timestamp,
+ })
}
func (s *AppTestSuite) TestCompare() {
diff --git a/core/test/stopper_test.go b/core/test/stopper_test.go
index de1c1a5..df207ec 100644
--- a/core/test/stopper_test.go
+++ b/core/test/stopper_test.go
@@ -62,8 +62,8 @@ func (s *StopperTestSuite) TestStopByConfirmedBlocks() {
app.TotalOrderingDelivered(hashes, false)
for _, h := range hashes {
app.BlockDelivered(types.Block{
- Hash: h,
- Witness: types.Witness{Timestamp: time.Time{}}})
+ Hash: h,
+ ConsensusTimestamp: time.Time{}})
}
}
}
diff --git a/core/types/block.go b/core/types/block.go
index 1d994e6..c785969 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -61,15 +61,17 @@ func NewBlock() (b *Block) {
// 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:"timestamps"`
- Acks common.SortedHashes `json:"acks"`
- Payload []byte `json:"payload"`
- Witness Witness `json:"witness"`
- Signature crypto.Signature `json:"signature"`
+ ProposerID NodeID `json:"proposer_id"`
+ ParentHash common.Hash `json:"parent_hash"`
+ Hash common.Hash `json:"hash"`
+ Position Position `json:"position"`
+ Timestamp time.Time `json:"timestamps"`
+ Acks common.SortedHashes `json:"acks"`
+ Payload []byte `json:"payload"`
+ ConsensusTimestamp time.Time `json:"consensus_timestamp"`
+ ConsensusHeight uint64 `json:"consensus_height"`
+ Witness Witness `json:"witness"`
+ Signature crypto.Signature `json:"signature"`
CRSSignature crypto.Signature `json:"crs_signature"`
}
@@ -89,6 +91,8 @@ func (b *Block) Clone() (bcopy *Block) {
bcopy.Position.Height = b.Position.Height
bcopy.Signature = b.Signature.Clone()
bcopy.CRSSignature = b.CRSSignature.Clone()
+ bcopy.ConsensusTimestamp = b.ConsensusTimestamp
+ bcopy.ConsensusHeight = b.ConsensusHeight
bcopy.Witness.Timestamp = b.Witness.Timestamp
bcopy.Witness.Height = b.Witness.Height
bcopy.Timestamp = b.Timestamp