diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-08-22 11:33:39 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-22 11:33:39 +0800 |
commit | 89a65a152ae7956bcf6d241eb15d66e6d955b819 (patch) | |
tree | ec157eab266cf3dd76a94cfdbe90d35a08a2e492 | |
parent | 2c816b5d636b8f7decd234582470a3d4c6b4a93a (diff) | |
download | dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.tar dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.tar.gz dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.tar.bz2 dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.tar.lz dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.tar.xz dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.tar.zst dexon-consensus-89a65a152ae7956bcf6d241eb15d66e6d955b819.zip |
core: Notary ack application. (#70)
-rw-r--r-- | core/consensus.go | 4 | ||||
-rw-r--r-- | core/nonblocking-application.go | 7 | ||||
-rw-r--r-- | core/nonblocking-application_test.go | 2 | ||||
-rw-r--r-- | core/test/app.go | 19 | ||||
-rw-r--r-- | core/test/app_test.go | 26 | ||||
-rw-r--r-- | simulation/fake-network.go | 10 | ||||
-rw-r--r-- | simulation/network.go | 1 | ||||
-rw-r--r-- | simulation/tcp-network.go | 14 | ||||
-rw-r--r-- | simulation/validator.go | 4 |
9 files changed, 87 insertions, 0 deletions
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 +// <http://www.gnu.org/licenses/>. + 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) { diff --git a/simulation/fake-network.go b/simulation/fake-network.go index 99c504a..fc8764a 100644 --- a/simulation/fake-network.go +++ b/simulation/fake-network.go @@ -93,6 +93,16 @@ func (n *FakeNetwork) BroadcastBlock(block *types.Block) { } } +// BroadcastNotaryAck broadcast notaryAck into the network. +func (n *FakeNetwork) BroadcastNotaryAck(notaryAck *types.NotaryAck) { + n.endpointMutex.Lock() + defer n.endpointMutex.Unlock() + + for endpoint := range n.endpoints { + n.Send(endpoint, notaryAck) + } +} + // DeliverBlocks sends blocks to peerServer. func (n *FakeNetwork) DeliverBlocks(blocks BlockList) { // TODO(jimmy-dexon): Implement this method. diff --git a/simulation/network.go b/simulation/network.go index 672a664..f08b638 100644 --- a/simulation/network.go +++ b/simulation/network.go @@ -80,6 +80,7 @@ type Network interface { NumPeers() int Join(endpoint Endpoint) chan interface{} BroadcastBlock(block *types.Block) + BroadcastNotaryAck(notaryAck *types.NotaryAck) Endpoints() types.ValidatorIDs } diff --git a/simulation/tcp-network.go b/simulation/tcp-network.go index c606daf..2da9e3a 100644 --- a/simulation/tcp-network.go +++ b/simulation/tcp-network.go @@ -254,6 +254,9 @@ func (n *TCPNetwork) Send(destID types.ValidatorID, msg interface{}) { case *types.Block: message.Type = "block" message.Payload = v + case *types.NotaryAck: + message.Type = "notaryAck" + message.Payload = v default: fmt.Println("error: invalid message type") return @@ -304,6 +307,17 @@ func (n *TCPNetwork) BroadcastBlock(block *types.Block) { } } +// BroadcastNotaryAck broadcast notaryAck into the network. +func (n *TCPNetwork) BroadcastNotaryAck(notaryAck *types.NotaryAck) { + notaryAck = notaryAck.Clone() + for endpoint := range n.endpoints { + if endpoint == notaryAck.ProposerID { + continue + } + n.Send(endpoint, notaryAck) + } +} + // DeliverBlocks sends blocks to peerServer. func (n *TCPNetwork) DeliverBlocks(blocks BlockList) { messageJSON, err := json.Marshal(blocks) diff --git a/simulation/validator.go b/simulation/validator.go index 1912bf6..fb5f6cd 100644 --- a/simulation/validator.go +++ b/simulation/validator.go @@ -155,6 +155,10 @@ func (v *Validator) MsgServer( fmt.Println(err) //panic(err) } + case *types.NotaryAck: + if err := v.consensus.ProcessNotaryAck(val); err != nil { + fmt.Println(err) + } } } } |