aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-08-22 11:33:39 +0800
committerGitHub <noreply@github.com>2018-08-22 11:33:39 +0800
commit89a65a152ae7956bcf6d241eb15d66e6d955b819 (patch)
treeec157eab266cf3dd76a94cfdbe90d35a08a2e492
parent2c816b5d636b8f7decd234582470a3d4c6b4a93a (diff)
downloaddexon-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.go4
-rw-r--r--core/nonblocking-application.go7
-rw-r--r--core/nonblocking-application_test.go2
-rw-r--r--core/test/app.go19
-rw-r--r--core/test/app_test.go26
-rw-r--r--simulation/fake-network.go10
-rw-r--r--simulation/network.go1
-rw-r--r--simulation/tcp-network.go14
-rw-r--r--simulation/validator.go4
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)
+ }
}
}
}