diff --git a/check.go b/check.go index d6c02de1..47f24d7f 100644 --- a/check.go +++ b/check.go @@ -72,7 +72,7 @@ func (d *DBFT) checkCommit() { d.ProcessBlock(d.block) - d.InitializeConsensus(0) + d.InitializeConsensus(0, d.Timestamp) } func (d *DBFT) checkChangeView(view byte) { @@ -99,5 +99,5 @@ func (d *DBFT) checkChangeView(view byte) { } } - d.InitializeConsensus(view) + d.InitializeConsensus(view, d.lastBlockTimestamp) } diff --git a/context.go b/context.go index 3f3d13cd..74468db8 100644 --- a/context.go +++ b/context.go @@ -66,8 +66,9 @@ type Context struct { // if this node never heard from validator i, LastSeenMessage[i] will be -1. LastSeenMessage []*timer.HV - lastBlockTime time.Time - lastBlockIndex uint32 + lastBlockTimestamp uint64 // ns-precision timestamp from the last header (used for the next block timestamp calculations). + lastBlockTime time.Time // Wall clock time of when the last block was first seen (used for timer adjustments). + lastBlockIndex uint32 } // N returns total number of validators. @@ -169,8 +170,10 @@ func (c *Context) MoreThanFNodesCommittedOrLost() bool { return c.CountCommitted()+c.CountFailed() > c.F() } -func (c *Context) reset(view byte) { +func (c *Context) reset(view byte, ts uint64) { c.MyIndex = -1 + c.lastBlockTimestamp = ts + if view == 0 { c.PrevHash = c.Config.CurrentBlockHash() c.BlockIndex = c.Config.CurrentHeight() + 1 @@ -238,10 +241,9 @@ func (c *Context) Fill() { validators := c.Config.GetValidators(txx...) c.NextConsensus = c.Config.GetConsensusAddress(validators...) - if now := c.getTimestamp(); now > c.Timestamp+c.Config.TimestampIncrement { + c.Timestamp = c.lastBlockTimestamp + c.Config.TimestampIncrement + if now := c.getTimestamp(); now > c.Timestamp { c.Timestamp = now - } else { - c.Timestamp += c.Config.TimestampIncrement } } diff --git a/dbft.go b/dbft.go index 4b2fe093..e6b79fa9 100644 --- a/dbft.go +++ b/dbft.go @@ -25,7 +25,7 @@ type ( // Service is an interface for dBFT consensus. Service interface { - Start() + Start(uint64) OnTransaction(block.Transaction) OnReceive(payload.ConsensusPayload) OnTimeout(timer.HV) @@ -75,16 +75,17 @@ func (d *DBFT) addTransaction(tx block.Transaction) { } } -// Start initializes dBFT instance and starts protocol if node is primary. -func (d *DBFT) Start() { +// Start initializes dBFT instance and starts protocol if node is primary. It +// accepts a timestamp of the previous block. +func (d *DBFT) Start(ts uint64) { d.cache = newCache() - d.InitializeConsensus(0) + d.InitializeConsensus(0, ts) d.start() } // InitializeConsensus initializes dBFT instance. -func (d *DBFT) InitializeConsensus(view byte) { - d.reset(view) +func (d *DBFT) InitializeConsensus(view byte, ts uint64) { + d.reset(view, ts) var role string diff --git a/dbft_test.go b/dbft_test.go index bfdae798..2c8c2766 100644 --- a/dbft_test.go +++ b/dbft_test.go @@ -46,7 +46,7 @@ func TestDBFT_OnStartPrimarySendPrepareRequest(t *testing.T) { s.currHeight = 0 service := New(s.getOptions()...) - service.Start() + service.Start(0) require.Nil(t, s.tryRecv()) }) @@ -54,7 +54,7 @@ func TestDBFT_OnStartPrimarySendPrepareRequest(t *testing.T) { s.currHeight = 1 service := New(s.getOptions()...) - service.Start() + service.Start(0) p := s.tryRecv() require.NotNil(t, p) require.Equal(t, payload.PrepareRequestType, p.Type()) @@ -93,7 +93,7 @@ func TestDBFT_SingleNode(t *testing.T) { s.currHeight = 2 service := New(s.getOptions()...) - service.Start() + service.Start(0) p := s.tryRecv() require.NotNil(t, p) require.Equal(t, payload.PrepareRequestType, p.Type()) @@ -135,7 +135,7 @@ func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { p := s.getPrepareRequest(5, txs[0].Hash()) - service.Start() + service.Start(0) service.OnReceive(p) resp := s.tryRecv() @@ -164,7 +164,7 @@ func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { service := New(s.getOptions()...) txs := []testTx{10} - service.Start() + service.Start(0) for i := range service.LastSeenMessage { service.LastSeenMessage[i] = &timer.HV{Height: s.currHeight + 1} @@ -193,7 +193,7 @@ func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { txs := []testTx{1, 2} s.pool.Add(txs[0]) - service.Start() + service.Start(0) t.Run("wrong primary index", func(t *testing.T) { p := s.getPrepareRequest(4, txs[0].Hash()) @@ -239,7 +239,7 @@ func TestDBFT_CommitOnTransaction(t *testing.T) { s.currHeight = 1 srv := New(s.getOptions()...) - srv.Start() + srv.Start(0) require.Nil(t, s.tryRecv()) tx := testTx(42) @@ -259,7 +259,7 @@ func TestDBFT_CommitOnTransaction(t *testing.T) { } s1.pool.Add(tx) srv1 := New(s1.getOptions()...) - srv1.Start() + srv1.Start(0) srv1.OnReceive(req) srv1.OnReceive(s1.getPrepareResponse(1, req.Hash())) srv1.OnReceive(s1.getPrepareResponse(3, req.Hash())) @@ -281,7 +281,7 @@ func TestDBFT_OnReceiveCommit(t *testing.T) { t.Run("send commit after enough responses", func(t *testing.T) { s.currHeight = 1 service := New(s.getOptions()...) - service.Start() + service.Start(0) req := s.tryRecv() require.NotNil(t, req) @@ -341,7 +341,7 @@ func TestDBFT_OnReceiveRecoveryRequest(t *testing.T) { t.Run("send recovery message", func(t *testing.T) { s.currHeight = 1 service := New(s.getOptions()...) - service.Start() + service.Start(0) req := s.tryRecv() require.NotNil(t, req) @@ -363,7 +363,7 @@ func TestDBFT_OnReceiveRecoveryRequest(t *testing.T) { other := s.copyWithIndex(3) srv2 := New(other.getOptions()...) - srv2.Start() + srv2.Start(0) srv2.OnReceive(rm) r2 := other.tryRecv() @@ -386,7 +386,7 @@ func TestDBFT_OnReceiveChangeView(t *testing.T) { t.Run("change view correctly", func(t *testing.T) { s.currHeight = 6 service := New(s.getOptions()...) - service.Start() + service.Start(0) resp := s.getChangeView(1, 1) service.OnReceive(resp) diff --git a/simulation/main.go b/simulation/main.go index 300ac5e8..faae3a06 100644 --- a/simulation/main.go +++ b/simulation/main.go @@ -88,7 +88,7 @@ func main() { // Run implements simple event loop. func (n *simNode) Run(ctx context.Context) { - n.d.Start() + n.d.Start(0) for { select {