aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-08-21 12:40:30 +0800
committerGitHub <noreply@github.com>2018-08-21 12:40:30 +0800
commite8f99372159a89fb3128b870de1733a4777a5144 (patch)
tree14a0591932f55532342ef6cc63bd30ced13f46e8
parent1ebe7b8729a166745d56203685232cb2e7d41cab (diff)
downloaddexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.tar
dexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.tar.gz
dexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.tar.bz2
dexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.tar.lz
dexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.tar.xz
dexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.tar.zst
dexon-consensus-e8f99372159a89fb3128b870de1733a4777a5144.zip
core: Notary ack (#69)
-rw-r--r--core/application.go4
-rw-r--r--core/compaction-chain.go232
-rw-r--r--core/compaction-chain_test.go187
-rw-r--r--core/consensus.go48
-rw-r--r--core/crypto.go9
-rw-r--r--core/crypto_test.go67
-rw-r--r--core/nonblocking-application.go4
-rw-r--r--core/nonblocking-application_test.go2
-rw-r--r--core/test/app.go4
-rw-r--r--core/types/notary.go10
-rw-r--r--simulation/app.go4
11 files changed, 383 insertions, 188 deletions
diff --git a/core/application.go b/core/application.go
index e39e238..3834d68 100644
--- a/core/application.go
+++ b/core/application.go
@@ -36,6 +36,6 @@ type Application interface {
// DeliverBlock is called when a block is add to the compaction chain.
DeliverBlock(blockHash common.Hash, timestamp time.Time)
- // NotaryAck is called when a notary ack is created.
- NotaryAck(notaryAck types.NotaryAck)
+ // NotaryAckDeliver is called when a notary ack is created.
+ NotaryAckDeliver(notaryAck *types.NotaryAck)
}
diff --git a/core/compaction-chain.go b/core/compaction-chain.go
index 664b692..243bda0 100644
--- a/core/compaction-chain.go
+++ b/core/compaction-chain.go
@@ -22,86 +22,226 @@ package core
import (
"fmt"
"sync"
+ "time"
+ "github.com/dexon-foundation/dexon-consensus-core/blockdb"
+ "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"
)
// Errors for compaction chain.
var (
- ErrIncorrectNotaryAck = fmt.Errorf(
- "compaction chain notary of block is incorrect")
+ ErrNoNotaryToAck = fmt.Errorf(
+ "no notary to ack")
+ ErrIncorrectNotaryHash = fmt.Errorf(
+ "hash of notary ack is incorrect")
+ ErrIncorrectNotarySignature = fmt.Errorf(
+ "signature of notary ack is incorrect")
)
+type pendingAck struct {
+ receivedTime time.Time
+ notaryAck *types.NotaryAck
+}
+
type compactionChain struct {
+ db blockdb.Reader
+ pendingAckLock sync.RWMutex
+ pendingAck map[common.Hash]*pendingAck
+ prevBlockLock sync.RWMutex
prevBlock *types.Block
- lock sync.RWMutex
- latestNotaryAcks map[types.ValidatorID]types.NotaryAck
+ notaryAcksLock sync.RWMutex
+ latestNotaryAcks map[types.ValidatorID]*types.NotaryAck
+ sigToPub SigToPubFn
}
-func newCompactionChain() *compactionChain {
- return &compactionChain{}
+func newCompactionChain(
+ db blockdb.Reader,
+ sigToPub SigToPubFn,
+) *compactionChain {
+ return &compactionChain{
+ db: db,
+ pendingAck: make(map[common.Hash]*pendingAck),
+ latestNotaryAcks: make(map[types.ValidatorID]*types.NotaryAck),
+ sigToPub: sigToPub,
+ }
}
-func (cc *compactionChain) sanityCheck(notaryAck types.NotaryAck) bool {
- return true
+func (cc *compactionChain) sanityCheck(
+ notaryAck *types.NotaryAck, notaryBlock *types.Block) error {
+ if notaryBlock != nil {
+ hash, err := hashNotary(notaryBlock)
+ if err != nil {
+ return err
+ }
+ if hash != notaryAck.Hash {
+ return ErrIncorrectNotaryHash
+ }
+ }
+ pubKey, err := cc.sigToPub(notaryAck.Hash, notaryAck.Signature)
+ if err != nil {
+ return err
+ }
+ if notaryAck.ProposerID != types.NewValidatorID(pubKey) {
+ return ErrIncorrectNotarySignature
+ }
+ return nil
}
-func (cc *compactionChain) processBlock(block *types.Block) (err error) {
- cc.lock.Lock()
- defer cc.lock.Unlock()
- cc.prevBlock = block
- /*
- prevBlock := cc.lastBlock()
- if prevBlock != nil {
- block.NotaryAck.NotarySignature, err =
- signNotary(prevBlock, prvKey)
- if err != nil {
- return
- }
- block.NotaryAck.NotaryBlockHash = prevBlock.Hash
+// TODO(jimmy-dexon): processBlock and prepareNotaryAck can be extraced to
+// another struct.
+func (cc *compactionChain) processBlock(block *types.Block) error {
+ prevBlock := cc.lastBlock()
+ if prevBlock != nil {
+ hash, err := hashNotary(prevBlock)
+ if err != nil {
+ return err
}
- */
- return
+ block.Notary.Height = prevBlock.Notary.Height + 1
+ block.Notary.ParentHash = hash
+ }
+ cc.prevBlockLock.Lock()
+ defer cc.prevBlockLock.Unlock()
+ cc.prevBlock = block
+ return nil
}
+
func (cc *compactionChain) prepareNotaryAck(prvKey crypto.PrivateKey) (
- notaryAck types.NotaryAck, err error) {
- notaryAck.NotaryBlockHash = cc.lastBlock().Hash
+ notaryAck *types.NotaryAck, err error) {
+ lastBlock := cc.lastBlock()
+ if lastBlock == nil {
+ err = ErrNoNotaryToAck
+ return
+ }
+ hash, err := hashNotary(lastBlock)
+ if err != nil {
+ return
+ }
+ sig, err := prvKey.Sign(hash)
+ if err != nil {
+ return
+ }
+ notaryAck = &types.NotaryAck{
+ ProposerID: types.NewValidatorID(prvKey.PublicKey()),
+ NotaryBlockHash: lastBlock.Hash,
+ Signature: sig,
+ Hash: hash,
+ }
return
}
-func (cc *compactionChain) processNotaryAck(notaryAck types.NotaryAck) (
+func (cc *compactionChain) processNotaryAck(notaryAck *types.NotaryAck) (
err error) {
- if !cc.sanityCheck(notaryAck) {
- err = ErrIncorrectNotaryAck
+ // Before getting the Block from notaryAck.NotaryBlockHash, we can still
+ // do some sanityCheck to prevent invalid ack appending to pendingAck.
+ if err = cc.sanityCheck(notaryAck, nil); err != nil {
return
}
- /*
- prevBlock := cc.lastBlock()
- if prevBlock == nil {
- block.Notary.Height = 0
- block.NotaryParentHash = common.Hash{}
- } else {
- block.Notary.Height = prevBlock.Notary.Height + 1
- block.NotaryParentHash, err = hashNotary(prevBlock)
- if err != nil {
- return
+ pendingFinished := make(chan struct{})
+ go func() {
+ cc.processPendingNotaryAcks()
+ pendingFinished <- struct{}{}
+ }()
+ defer func() {
+ <-pendingFinished
+ }()
+ notaryBlock, err := cc.db.Get(notaryAck.NotaryBlockHash)
+ if err != nil {
+ if err == blockdb.ErrBlockDoesNotExist {
+ cc.pendingAckLock.Lock()
+ defer cc.pendingAckLock.Unlock()
+ cc.pendingAck[notaryAck.Hash] = &pendingAck{
+ receivedTime: time.Now().UTC(),
+ notaryAck: notaryAck,
}
+ err = nil
+ }
+ return
+ }
+ return cc.processOneNotaryAck(notaryAck, &notaryBlock)
+}
+
+func (cc *compactionChain) processOneNotaryAck(
+ notaryAck *types.NotaryAck, notaryBlock *types.Block) (
+ err error) {
+ if err = cc.sanityCheck(notaryAck, notaryBlock); err != nil {
+ return
+ }
+ lastNotaryAck, exist := func() (ack *types.NotaryAck, exist bool) {
+ cc.notaryAcksLock.RLock()
+ defer cc.notaryAcksLock.RUnlock()
+ ack, exist = cc.latestNotaryAcks[notaryAck.ProposerID]
+ return
+ }()
+ if exist {
+ lastNotaryBlock, err2 := cc.db.Get(lastNotaryAck.NotaryBlockHash)
+ err = err2
+ if err != nil {
+ return
+ }
+ if lastNotaryBlock.Notary.Height > notaryBlock.Notary.Height {
+ return
}
- cc.lock.Lock()
- defer cc.lock.Unlock()
- cc.prevBlock = block
- */
+ }
+ cc.notaryAcksLock.Lock()
+ defer cc.notaryAcksLock.Unlock()
cc.latestNotaryAcks[notaryAck.ProposerID] = notaryAck
return
}
-func (cc *compactionChain) notaryAcks() map[types.ValidatorID]types.NotaryAck {
- return cc.latestNotaryAcks
+func (cc *compactionChain) processPendingNotaryAcks() {
+ pendingAck := func() map[common.Hash]*pendingAck {
+ pendingAck := make(map[common.Hash]*pendingAck)
+ cc.pendingAckLock.RLock()
+ defer cc.pendingAckLock.RUnlock()
+ for k, v := range cc.pendingAck {
+ pendingAck[k] = v
+ }
+ return pendingAck
+ }()
+
+ for hash, ack := range pendingAck {
+ // TODO(jimmy-dexon): customizable timeout.
+ if ack.receivedTime.Add(30 * time.Second).Before(time.Now().UTC()) {
+ delete(pendingAck, hash)
+ continue
+ }
+ }
+ for hash, ack := range pendingAck {
+ notaryBlock, err := cc.db.Get(ack.notaryAck.NotaryBlockHash)
+ if err != nil {
+ if err == blockdb.ErrBlockDoesNotExist {
+ continue
+ }
+ // TODO(jimmy-dexon): this error needs to be handled properly.
+ fmt.Println(err)
+ delete(pendingAck, hash)
+ }
+ delete(pendingAck, hash)
+ cc.processOneNotaryAck(ack.notaryAck, &notaryBlock)
+ }
+
+ cc.pendingAckLock.Lock()
+ defer cc.pendingAckLock.Unlock()
+ for k, v := range cc.pendingAck {
+ pendingAck[k] = v
+ }
+ cc.pendingAck = pendingAck
+}
+
+func (cc *compactionChain) notaryAcks() map[types.ValidatorID]*types.NotaryAck {
+ cc.notaryAcksLock.RLock()
+ defer cc.notaryAcksLock.RUnlock()
+ acks := make(map[types.ValidatorID]*types.NotaryAck)
+ for k, v := range cc.latestNotaryAcks {
+ acks[k] = v.Clone()
+ }
+ return acks
}
func (cc *compactionChain) lastBlock() *types.Block {
- cc.lock.RLock()
- defer cc.lock.RUnlock()
+ cc.prevBlockLock.RLock()
+ defer cc.prevBlockLock.RUnlock()
return cc.prevBlock
}
diff --git a/core/compaction-chain_test.go b/core/compaction-chain_test.go
index 05122a3..46d4e10 100644
--- a/core/compaction-chain_test.go
+++ b/core/compaction-chain_test.go
@@ -19,76 +19,153 @@ 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/eth"
- */
+ "github.com/dexon-foundation/dexon-consensus-core/blockdb"
+ "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
+ db blockdb.BlockDatabase
+}
+
+func (s *CompactionChainTestSuite) SetupTest() {
+ var err error
+ s.db, err = blockdb.NewMemBackedBlockDB()
+ s.Require().Nil(err)
+}
+
+func (s *CompactionChainTestSuite) newCompactionChain() *compactionChain {
+ return newCompactionChain(s.db, eth.SigToPub)
+}
+
+func (s *CompactionChainTestSuite) generateBlocks(
+ size int, cc *compactionChain) []*types.Block {
+ now := time.Now().UTC()
+ blocks := make([]*types.Block, size)
+ for idx := range blocks {
+ blocks[idx] = &types.Block{
+ Hash: common.NewRandomHash(),
+ Notary: types.Notary{
+ Timestamp: now,
+ },
+ }
+ now = now.Add(100 * time.Millisecond)
+ }
+ for _, block := range blocks {
+ err := cc.processBlock(block)
+ s.Require().Nil(err)
+ }
+ return blocks
}
func (s *CompactionChainTestSuite) TestProcessBlock() {
- /*
- cc := newCompactionChain()
- blocks := make([]*types.Block, 10)
- for idx := range blocks {
- blocks[idx] = &types.Block{
- Hash: common.NewRandomHash(),
- }
+ cc := s.newCompactionChain()
+ now := time.Now().UTC()
+ blocks := make([]*types.Block, 10)
+ for idx := range blocks {
+ blocks[idx] = &types.Block{
+ Hash: common.NewRandomHash(),
+ Notary: types.Notary{
+ Timestamp: now,
+ },
}
- var prevBlock *types.Block
- for _, block := range blocks {
- s.Equal(cc.prevBlock, prevBlock)
- cc.processBlock(block)
- if prevBlock != nil {
- s.Equal(block.Notary.Height, prevBlock.Notary.Height+1)
- prevHash, err := hashNotary(prevBlock)
- s.Require().Nil(err)
- s.Equal(prevHash, block.NotaryParentHash)
- }
- prevBlock = block
+ now = now.Add(100 * time.Millisecond)
+ }
+ var prevBlock *types.Block
+ for _, block := range blocks {
+ s.Equal(cc.prevBlock, prevBlock)
+ err := cc.processBlock(block)
+ s.Require().Nil(err)
+ if prevBlock != nil {
+ s.Equal(block.Notary.Height, prevBlock.Notary.Height+1)
+ prevHash, err := hashNotary(prevBlock)
+ s.Require().Nil(err)
+ s.Equal(prevHash, block.Notary.ParentHash)
}
- */
+ prevBlock = block
+ }
}
-func (s *CompactionChainTestSuite) TestPrepareBlock() {
- /*
- cc := newCompactionChain()
- blocks := make([]*types.Block, 10)
- for idx := range blocks {
- blocks[idx] = &types.Block{
- Hash: common.NewRandomHash(),
- Notary: types.Notary{
- Height: uint64(idx),
- },
- }
- if idx > 0 {
- var err error
- blocks[idx].NotaryParentHash, err = hashNotary(blocks[idx-1])
- s.Require().Nil(err)
- }
+func (s *CompactionChainTestSuite) TestPrepareNotaryAck() {
+ cc := s.newCompactionChain()
+ blocks := s.generateBlocks(10, cc)
+ prv, err := eth.NewPrivateKey()
+ s.Require().Nil(err)
+ for _, block := range blocks {
+ notaryAck, err := cc.prepareNotaryAck(prv)
+ s.Require().Nil(err)
+ if cc.prevBlock != nil {
+ s.True(verifyNotarySignature(
+ prv.PublicKey(),
+ cc.prevBlock,
+ notaryAck.Signature))
+ s.Equal(notaryAck.NotaryBlockHash, cc.prevBlock.Hash)
}
- prv, err := eth.NewPrivateKey()
- s.Require().Nil(err)
- for _, block := range blocks {
- cc.prepareBlock(block, prv)
- if cc.prevBlock != nil {
- s.True(verifyNotarySignature(
- prv.PublicKey(),
- cc.prevBlock,
- block.NotaryAck.NotarySignature))
- s.Equal(block.NotaryAck.NotaryBlockHash, cc.prevBlock.Hash)
- }
- cc.prevBlock = block
- }
- */
+ cc.prevBlock = block
+ }
+}
+
+func (s *CompactionChainTestSuite) TestProcessNotaryAck() {
+ cc := s.newCompactionChain()
+ blocks := s.generateBlocks(10, cc)
+ prv1, err := eth.NewPrivateKey()
+ s.Require().Nil(err)
+ prv2, err := eth.NewPrivateKey()
+ s.Require().Nil(err)
+ vID1 := types.NewValidatorID(prv1.PublicKey())
+ vID2 := types.NewValidatorID(prv2.PublicKey())
+ notaryAcks1 := []*types.NotaryAck{}
+ notaryAcks2 := []*types.NotaryAck{}
+ for _, block := range blocks {
+ cc.prevBlock = block
+ notaryAck1, err := cc.prepareNotaryAck(prv1)
+ s.Require().Nil(err)
+ notaryAck2, err := cc.prepareNotaryAck(prv2)
+ s.Require().Nil(err)
+ notaryAcks1 = append(notaryAcks1, notaryAck1)
+ notaryAcks2 = append(notaryAcks2, notaryAck2)
+ }
+ // The acked block is not yet in db.
+ err = cc.processNotaryAck(notaryAcks1[0])
+ s.Nil(err)
+ s.Equal(0, len(cc.notaryAcks()))
+ err = cc.processNotaryAck(notaryAcks2[1])
+ s.Nil(err)
+ s.Equal(0, len(cc.notaryAcks()))
+ // Insert to block to db and trigger processPendingNotaryAck.
+ s.Require().Nil(s.db.Put(*blocks[0]))
+ s.Require().Nil(s.db.Put(*blocks[1]))
+ err = cc.processNotaryAck(notaryAcks1[2])
+ s.Nil(err)
+ s.Equal(2, len(cc.notaryAcks()))
+
+ // Test the notaryAcks should be the last notaryAck.
+ s.Require().Nil(s.db.Put(*blocks[2]))
+ s.Require().Nil(s.db.Put(*blocks[3]))
+ s.Nil(cc.processNotaryAck(notaryAcks1[3]))
+
+ acks := cc.notaryAcks()
+ s.Equal(blocks[3].Hash, acks[vID1].NotaryBlockHash)
+ s.Equal(blocks[1].Hash, acks[vID2].NotaryBlockHash)
+
+ // Test that notaryAck on less Notary.Height should be ignored.
+ s.Require().Nil(s.db.Put(*blocks[4]))
+ s.Require().Nil(s.db.Put(*blocks[5]))
+ s.Nil(cc.processNotaryAck(notaryAcks1[5]))
+ s.Nil(cc.processNotaryAck(notaryAcks2[5]))
+ s.Nil(cc.processNotaryAck(notaryAcks1[4]))
+ s.Nil(cc.processNotaryAck(notaryAcks2[4]))
+
+ acks = cc.notaryAcks()
+ s.Equal(blocks[5].Hash, acks[vID1].NotaryBlockHash)
+ s.Equal(blocks[5].Hash, acks[vID2].NotaryBlockHash)
}
-func TestNotary(t *testing.T) {
+func TestCompactionChain(t *testing.T) {
suite.Run(t, new(CompactionChainTestSuite))
}
diff --git a/core/consensus.go b/core/consensus.go
index 0b4ea62..75bc934 100644
--- a/core/consensus.go
+++ b/core/consensus.go
@@ -44,6 +44,8 @@ func (e *ErrMissingBlockInfo) Error() string {
// Errors for consensus core.
var (
+ ErrProposerNotValidator = fmt.Errorf(
+ "proposer is not a validator")
ErrIncorrectHash = fmt.Errorf(
"hash of block is incorrect")
ErrIncorrectSignature = fmt.Errorf(
@@ -91,7 +93,7 @@ func NewConsensus(
rbModule: rb,
toModule: to,
ctModule: newConsensusTimestamp(),
- ccModule: newCompactionChain(),
+ ccModule: newCompactionChain(db, sigToPub),
app: newNonBlockingApplication(app),
gov: gov,
db: db,
@@ -117,30 +119,6 @@ func (con *Consensus) sanityCheck(blockConv types.BlockConverter) (err error) {
if !b.ProposerID.Equal(crypto.Keccak256Hash(pubKey.Bytes())) {
return ErrIncorrectSignature
}
-
- // TODO(jimmy-dexon): remove these comments before open source.
- /*
- // Check the notary ack.
- if notaryBlockHash :=
- b.NotaryAck.NotaryBlockHash; (notaryBlockHash != common.Hash{}) {
- notaryBlock, err := con.db.Get(notaryBlockHash)
- if err != nil {
- return err
- }
- hash, err := hashNotary(&notaryBlock)
- if err != nil {
- return err
- }
- pubKey, err := con.sigToPub(hash,
- b.NotaryAck.NotarySignature)
- if err != nil {
- return err
- }
- if !b.ProposerID.Equal(crypto.Keccak256Hash(pubKey.Bytes())) {
- return ErrIncorrectNotaryAck
- }
- }
- */
return nil
}
@@ -202,12 +180,12 @@ func (con *Consensus) ProcessBlock(blockConv types.BlockConverter) (err error) {
}
con.app.DeliverBlock(b.Hash, b.Notary.Timestamp)
}
- var notaryAck types.NotaryAck
+ var notaryAck *types.NotaryAck
notaryAck, err = con.ccModule.prepareNotaryAck(con.prvKey)
if err != nil {
return
}
- con.app.NotaryAck(notaryAck)
+ con.app.NotaryAckDeliver(notaryAck)
}
return
}
@@ -277,17 +255,17 @@ func (con *Consensus) PrepareGenesisBlock(blockConv types.BlockConverter,
}
// ProcessNotaryAck is the entry point to submit one notary ack.
-func (con *Consensus) ProcessNotaryAck(notaryAck types.NotaryAck) (err error) {
+func (con *Consensus) ProcessNotaryAck(notaryAck *types.NotaryAck) (err error) {
+ notaryAck = notaryAck.Clone()
+ if _, exists := con.gov.GetValidatorSet()[notaryAck.ProposerID]; !exists {
+ err = ErrProposerNotValidator
+ return
+ }
err = con.ccModule.processNotaryAck(notaryAck)
return
}
// NotaryAcks returns the latest NotaryAck received from all other validators.
-func (con *Consensus) NotaryAcks() (
- notaryAcks map[types.ValidatorID]types.NotaryAck) {
- notaryAcks = make(map[types.ValidatorID]types.NotaryAck)
- for k, v := range con.ccModule.notaryAcks() {
- notaryAcks[k] = v
- }
- return
+func (con *Consensus) NotaryAcks() map[types.ValidatorID]*types.NotaryAck {
+ return con.ccModule.notaryAcks()
}
diff --git a/core/crypto.go b/core/crypto.go
index 0de73af..4fc49d7 100644
--- a/core/crypto.go
+++ b/core/crypto.go
@@ -40,15 +40,6 @@ func hashNotary(block *types.Block) (common.Hash, error) {
return hash, nil
}
-func signNotary(block *types.Block,
- prv crypto.PrivateKey) (crypto.Signature, error) {
- hash, err := hashNotary(block)
- if err != nil {
- return crypto.Signature{}, err
- }
- return prv.Sign(hash)
-}
-
func verifyNotarySignature(pubkey crypto.PublicKey,
notaryBlock *types.Block, sig crypto.Signature) (bool, error) {
hash, err := hashNotary(notaryBlock)
diff --git a/core/crypto_test.go b/core/crypto_test.go
index 3aa1674..0690a32 100644
--- a/core/crypto_test.go
+++ b/core/crypto_test.go
@@ -90,63 +90,62 @@ func (s *CryptoTestSuite) newBlock(prevBlock *types.Block) *types.Block {
}
func (s *CryptoTestSuite) generateCompactionChain(
- length int, prv crypto.PrivateKey) []*types.Block {
+ length int, prv crypto.PrivateKey) (
+ []*types.Block, []types.NotaryAck) {
blocks := make([]*types.Block, length)
+ notaryAcks := make([]types.NotaryAck, length)
var prevBlock *types.Block
for idx := range blocks {
block := s.newBlock(prevBlock)
prevBlock = block
blocks[idx] = block
var err error
+ notaryAcks[idx].Hash, err = hashNotary(blocks[idx])
+ s.Require().Nil(err)
+ notaryAcks[idx].NotaryBlockHash = blocks[idx].Hash
+ notaryAcks[idx].Signature, err = prv.Sign(notaryAcks[idx].Hash)
+ s.Require().Nil(err)
if idx > 0 {
- block.Notary.ParentHash, err = hashNotary(blocks[idx-1])
- s.Require().Nil(err)
- /*
- block.NotaryAck.NotarySignature, err =
- signNotary(blocks[idx-1], prv)
- s.Require().Nil(err)
- */
+ block.Notary.ParentHash = notaryAcks[idx-1].Hash
}
}
- return blocks
+ return blocks, notaryAcks
}
func (s *CryptoTestSuite) TestNotaryAckSignature() {
prv, err := eth.NewPrivateKey()
- //pub := prv.PublicKey()
+ pub := prv.PublicKey()
s.Require().Nil(err)
- blocks := s.generateCompactionChain(10, prv)
+ blocks, notaryAcks := 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.Notary.Height == 0 {
+ parentBlock := blocks[0]
+ for _, notaryAck := range notaryAcks {
+ notaryBlock, exist := blockMap[notaryAck.NotaryBlockHash]
+ s.Require().True(exist)
+ if notaryBlock.Notary.Height == 0 {
continue
}
- /*
- ackingBlock, exist := blockMap[block.NotaryAck.NotaryBlockHash]
- s.Require().True(exist)
- s.True(ackingBlock.Notary.Height == block.Notary.Height-1)
- hash, err := hashNotary(ackingBlock)
- s.Require().Nil(err)
- s.Equal(hash, block.NotaryParentHash)
- s.True(verifyNotarySignature(
- pub, ackingBlock, block.NotaryAck.NotarySignature))
- */
+ s.True(parentBlock.Notary.Height == notaryBlock.Notary.Height-1)
+ hash, err := hashNotary(parentBlock)
+ s.Require().Nil(err)
+ s.Equal(hash, notaryBlock.Notary.ParentHash)
+ s.True(verifyNotarySignature(
+ pub, notaryBlock, notaryAck.Signature))
+ parentBlock = notaryBlock
+
}
- // Modify Block.ConsensusTime and verify signature again.
- for _, block := range blocks {
+ // Modify Block.Notary.Timestamp and verify signature again.
+ for _, notaryAck := range notaryAcks {
+ block, exist := blockMap[notaryAck.NotaryBlockHash]
+ s.Require().True(exist)
block.Notary.Timestamp = time.Time{}
- if block.Notary.Height == 0 {
- continue
- }
- /*
- ackingBlock, exist := blockMap[block.NotaryAck.NotaryBlockHash]
- s.Require().True(exist)
- s.False(verifyNotarySignature(
- pub, ackingBlock, block.NotaryAck.NotarySignature))
- */
+ ackingBlock, exist := blockMap[notaryAck.NotaryBlockHash]
+ s.Require().True(exist)
+ s.False(verifyNotarySignature(
+ pub, ackingBlock, notaryAck.Signature))
}
}
diff --git a/core/nonblocking-application.go b/core/nonblocking-application.go
index a04d7d2..921fe3e 100644
--- a/core/nonblocking-application.go
+++ b/core/nonblocking-application.go
@@ -126,6 +126,6 @@ func (app *nonBlockingApplication) DeliverBlock(
app.addEvent(deliverBlockEvent{blockHash, timestamp})
}
-// NotaryAck is called when a notary ack is created.
-func (app *nonBlockingApplication) NotaryAck(notaryAck types.NotaryAck) {
+// NotaryAckDeliver is called when a notary ack is created.
+func (app *nonBlockingApplication) NotaryAckDeliver(notaryAck *types.NotaryAck) {
}
diff --git a/core/nonblocking-application_test.go b/core/nonblocking-application_test.go
index 0f7d7f2..6d6a5ef 100644
--- a/core/nonblocking-application_test.go
+++ b/core/nonblocking-application_test.go
@@ -62,7 +62,7 @@ func (app *slowApp) DeliverBlock(blockHash common.Hash, timestamp time.Time) {
app.deliverBlock[blockHash] = struct{}{}
}
-func (app *slowApp) NotaryAck(notaryAck types.NotaryAck) {
+func (app *slowApp) NotaryAckDeliver(notaryAck *types.NotaryAck) {
time.Sleep(app.sleep)
app.notaryAck[notaryAck.Hash] = struct{}{}
}
diff --git a/core/test/app.go b/core/test/app.go
index 4a704a0..0242ca5 100644
--- a/core/test/app.go
+++ b/core/test/app.go
@@ -106,8 +106,8 @@ func (app *App) DeliverBlock(blockHash common.Hash, timestamp time.Time) {
app.DeliverSequence = append(app.DeliverSequence, blockHash)
}
-// NotaryAck implements Application interface.
-func (app *App) NotaryAck(notaryAck types.NotaryAck) {
+// NotaryAckDeliver implements Application interface.
+func (app *App) NotaryAckDeliver(notaryAck *types.NotaryAck) {
}
// Compare performs these checks against another App instance
diff --git a/core/types/notary.go b/core/types/notary.go
index 01237b4..216466c 100644
--- a/core/types/notary.go
+++ b/core/types/notary.go
@@ -35,6 +35,16 @@ type NotaryAck struct {
Signature crypto.Signature `json:"signature"`
}
+// Clone returns a deep copy of a NotaryAck.
+func (a *NotaryAck) Clone() *NotaryAck {
+ return &NotaryAck{
+ ProposerID: a.ProposerID,
+ NotaryBlockHash: a.NotaryBlockHash,
+ Hash: a.Hash,
+ Signature: a.Signature,
+ }
+}
+
// Notary represents the consensus information on the compaction chain.
type Notary struct {
ParentHash common.Hash `json:"parent_hash"`
diff --git a/simulation/app.go b/simulation/app.go
index 986893c..c7a7ccf 100644
--- a/simulation/app.go
+++ b/simulation/app.go
@@ -185,6 +185,6 @@ func (a *simApp) DeliverBlock(blockHash common.Hash, timestamp time.Time) {
a.Network.NotifyServer(msg)
}
-// NotaryAck is called when a notary ack is created.
-func (a *simApp) NotaryAck(notaryAck types.NotaryAck) {
+// NotaryAckDeliver is called when a notary ack is created.
+func (a *simApp) NotaryAckDeliver(notaryAck *types.NotaryAck) {
}