From 89a65a152ae7956bcf6d241eb15d66e6d955b819 Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Wed, 22 Aug 2018 11:33:39 +0800 Subject: core: Notary ack application. (#70) --- core/consensus.go | 4 ++++ core/nonblocking-application.go | 7 +++++++ core/nonblocking-application_test.go | 2 ++ core/test/app.go | 19 +++++++++++++++++++ core/test/app_test.go | 26 ++++++++++++++++++++++++++ 5 files changed, 58 insertions(+) (limited to 'core') diff --git a/core/consensus.go b/core/consensus.go index 75bc934..122f0b0 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -185,6 +185,10 @@ func (con *Consensus) ProcessBlock(blockConv types.BlockConverter) (err error) { if err != nil { return } + err = con.ProcessNotaryAck(notaryAck) + if err != nil { + return + } con.app.NotaryAckDeliver(notaryAck) } return diff --git a/core/nonblocking-application.go b/core/nonblocking-application.go index 921fe3e..ccdf42e 100644 --- a/core/nonblocking-application.go +++ b/core/nonblocking-application.go @@ -40,6 +40,10 @@ type deliverBlockEvent struct { timestamp time.Time } +type notaryAckEvent struct { + notaryAck *types.NotaryAck +} + // nonBlockingApplication implements Application and is a decorator for // Application that makes the methods to be non-blocking. type nonBlockingApplication struct { @@ -90,6 +94,8 @@ func (app *nonBlockingApplication) run() { app.app.TotalOrderingDeliver(e.blockHashes, e.early) case deliverBlockEvent: app.app.DeliverBlock(e.blockHash, e.timestamp) + case notaryAckEvent: + app.app.NotaryAckDeliver(e.notaryAck) default: fmt.Printf("Unknown event %v.", e) } @@ -128,4 +134,5 @@ func (app *nonBlockingApplication) DeliverBlock( // NotaryAckDeliver is called when a notary ack is created. func (app *nonBlockingApplication) NotaryAckDeliver(notaryAck *types.NotaryAck) { + app.addEvent(notaryAckEvent{notaryAck}) } diff --git a/core/nonblocking-application_test.go b/core/nonblocking-application_test.go index 6d6a5ef..336eea0 100644 --- a/core/nonblocking-application_test.go +++ b/core/nonblocking-application_test.go @@ -86,6 +86,7 @@ func (s *NonBlockingAppTestSuite) TestNonBlockingApplication() { for _, hash := range hashes { nbapp.StronglyAcked(hash) nbapp.DeliverBlock(hash, time.Now().UTC()) + nbapp.NotaryAckDeliver(&types.NotaryAck{Hash: hash}) } nbapp.TotalOrderingDeliver(hashes, true) @@ -97,6 +98,7 @@ func (s *NonBlockingAppTestSuite) TestNonBlockingApplication() { s.Contains(app.stronglyAcked, hash) s.Contains(app.totalOrderingDeliver, hash) s.Contains(app.deliverBlock, hash) + s.Contains(app.notaryAck, hash) } } diff --git a/core/test/app.go b/core/test/app.go index ddce31a..e26c20c 100644 --- a/core/test/app.go +++ b/core/test/app.go @@ -50,6 +50,10 @@ var ( // and delivered are different. ErrMismatchTotalOrderingAndDelivered = fmt.Errorf( "mismatch total ordering and delivered sequence") + // ErrNotaryAckUnknownBlock means the notary ack is acking on the unknown + // block. + ErrNotaryAckUnknownBlock = fmt.Errorf( + "notary ack on unknown block") ) // AppAckedRecord caches information when this application received @@ -83,6 +87,8 @@ type App struct { Delivered map[common.Hash]*AppDeliveredRecord DeliverSequence common.Hashes deliveredLock sync.RWMutex + NotaryAckSequence []*types.NotaryAck + notaryAckLock sync.RWMutex } // NewApp constructs a TestApp instance. @@ -137,6 +143,10 @@ func (app *App) DeliverBlock(blockHash common.Hash, timestamp time.Time) { // NotaryAckDeliver implements Application interface. func (app *App) NotaryAckDeliver(notaryAck *types.NotaryAck) { + app.notaryAckLock.Lock() + defer app.notaryAckLock.Unlock() + + app.NotaryAckSequence = append(app.NotaryAckSequence, notaryAck) } // Compare performs these checks against another App instance @@ -224,6 +234,15 @@ Loop: // by total ordering. return ErrMismatchTotalOrderingAndDelivered } + + // Make sure that notaryAck is acking the correct block. + app.notaryAckLock.RLock() + defer app.notaryAckLock.RUnlock() + for _, notaryAck := range app.NotaryAckSequence { + if _, exists := app.Delivered[notaryAck.NotaryBlockHash]; !exists { + return ErrNotaryAckUnknownBlock + } + } return nil } diff --git a/core/test/app_test.go b/core/test/app_test.go index f4c4a74..6966de5 100644 --- a/core/test/app_test.go +++ b/core/test/app_test.go @@ -1,3 +1,20 @@ +// 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 +// . + package test import ( @@ -5,6 +22,7 @@ import ( "time" "github.com/dexon-foundation/dexon-consensus-core/common" + "github.com/dexon-foundation/dexon-consensus-core/core/types" "github.com/stretchr/testify/suite" ) @@ -135,6 +153,14 @@ func (s *AppTestSuite) TestVerify() { app4.StronglyAcked(hash) app4.TotalOrderingDeliver(common.Hashes{hash}, false) s.deliverBlockWithTimeFromSequenceLength(app4, hash) + // Notary ack on unknown block. + app5 := NewApp() + s.setupAppByTotalOrderDeliver(app5, s.to1) + app5.NotaryAckDeliver(&types.NotaryAck{ + Hash: common.NewRandomHash(), + NotaryBlockHash: common.NewRandomHash(), + }) + req.Equal(ErrNotaryAckUnknownBlock, app5.Verify()) } func TestApp(t *testing.T) { -- cgit v1.2.3