consensus: validate timestamp in `verifyBlock()
Not doing this can possibly lead to the same node being validator again and again.
This commit is contained in:
parent
4dcd06ef44
commit
c5f9f6a3fd
2 changed files with 24 additions and 0 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue