diff --git a/go.mod b/go.mod index 5f39beb8a..293f77835 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/hashicorp/golang-lru v0.5.4 github.com/mr-tron/base58 v1.1.2 - github.com/nspcc-dev/dbft v0.0.0-20201109143252-cd27d76617ed + github.com/nspcc-dev/dbft v0.0.0-20201216144126-a4bc58feae87 github.com/nspcc-dev/rfc6979 v0.2.0 github.com/pierrec/lz4 v2.5.2+incompatible github.com/prometheus/client_golang v1.2.1 diff --git a/go.sum b/go.sum index 5b659bcfb..6a1094feb 100644 --- a/go.sum +++ b/go.sum @@ -166,8 +166,8 @@ github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a h1:ajvxgEe9qY4vvoSm github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1 h1:yEx9WznS+rjE0jl0dLujCxuZSIb+UTjF+005TJu/nNI= github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ= -github.com/nspcc-dev/dbft v0.0.0-20201109143252-cd27d76617ed h1:T4qjutPMqjnYDQFyrbCew3lGeJt6MIbNyNn7gRx0o/g= -github.com/nspcc-dev/dbft v0.0.0-20201109143252-cd27d76617ed/go.mod h1:I5D0W3tu3epdt2RMCTxS//HDr4S+OHRqajouQTOAHI8= +github.com/nspcc-dev/dbft v0.0.0-20201216144126-a4bc58feae87 h1:sKV7BKdp2iDW39AkGp0GPGHRDuR9vgQT7gDdMKMkuOI= +github.com/nspcc-dev/dbft v0.0.0-20201216144126-a4bc58feae87/go.mod h1:I5D0W3tu3epdt2RMCTxS//HDr4S+OHRqajouQTOAHI8= github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg= github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index 03a7a8efb..ebf8d4d25 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -81,6 +81,11 @@ type service struct { started *atomic.Bool quit chan struct{} finished chan struct{} + // lastTimestamp contains timestamp for the last processed block. + // We can't rely on timestamp from dbft context because it is changed + // before block is accepted, so in case of change view it will contain + // updated value. + lastTimestamp uint64 } // Config is a configuration for consensus services. @@ -298,6 +303,9 @@ func (s *service) handleChainBlock(b *coreb.Block) { s.log.Debug("new block in the chain", zap.Uint32("dbft index", s.dbft.BlockIndex), zap.Uint32("chain index", s.Chain.BlockHeight())) + if s.lastTimestamp < b.Timestamp { + s.lastTimestamp = b.Timestamp + } s.dbft.InitializeConsensus(0) } } @@ -418,6 +426,12 @@ func (s *service) verifyBlock(b block.Block) bool { s.log.Warn("proposed block has already outdated") return false } + if s.lastTimestamp >= coreb.Timestamp { + s.log.Warn("proposed block has small timestamp", + zap.Uint64("ts", coreb.Timestamp), + zap.Uint64("last", s.lastTimestamp)) + return false + } maxBlockSize := int(s.Chain.GetPolicer().GetMaxBlockSize()) size := io.GetVarSize(coreb) if size > maxBlockSize { @@ -492,6 +506,9 @@ func (s *service) processBlock(b block.Block) { s.log.Warn("error on add block", zap.Error(err)) } } + if s.lastTimestamp < bb.Timestamp { + s.lastTimestamp = bb.Timestamp + } } func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness { diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index d3983f9bf..99ae07bb0 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -344,6 +344,8 @@ func TestService_OnPayload(t *testing.T) { func TestVerifyBlock(t *testing.T) { srv := newTestService(t) defer srv.Chain.Close() + + srv.lastTimestamp = 1 t.Run("good empty", func(t *testing.T) { b := testchain.NewBlock(t, srv.Chain, 1, 0) require.True(t, srv.verifyBlock(&neoBlock{Block: *b})) @@ -386,6 +388,11 @@ func TestVerifyBlock(t *testing.T) { b.Index = srv.Chain.BlockHeight() require.False(t, srv.verifyBlock(&neoBlock{Block: *b})) }) + t.Run("bad timestamp", func(t *testing.T) { + b := testchain.NewBlock(t, srv.Chain, 1, 0) + b.Timestamp = srv.lastTimestamp - 1 + require.False(t, srv.verifyBlock(&neoBlock{Block: *b})) + }) t.Run("bad big size", func(t *testing.T) { script := make([]byte, int(srv.Chain.GetPolicer().GetMaxBlockSize())) script[0] = byte(opcode.RET)