diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-08-21 12:40:30 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-21 12:40:30 +0800 |
commit | e8f99372159a89fb3128b870de1733a4777a5144 (patch) | |
tree | 14a0591932f55532342ef6cc63bd30ced13f46e8 | |
parent | 1ebe7b8729a166745d56203685232cb2e7d41cab (diff) | |
download | dexon-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.go | 4 | ||||
-rw-r--r-- | core/compaction-chain.go | 232 | ||||
-rw-r--r-- | core/compaction-chain_test.go | 187 | ||||
-rw-r--r-- | core/consensus.go | 48 | ||||
-rw-r--r-- | core/crypto.go | 9 | ||||
-rw-r--r-- | core/crypto_test.go | 67 | ||||
-rw-r--r-- | core/nonblocking-application.go | 4 | ||||
-rw-r--r-- | core/nonblocking-application_test.go | 2 | ||||
-rw-r--r-- | core/test/app.go | 4 | ||||
-rw-r--r-- | core/types/notary.go | 10 | ||||
-rw-r--r-- | simulation/app.go | 4 |
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, ¬aryBlock) +} + +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, ¬aryBlock) + } + + 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(¬aryBlock) - 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) { } |