forked from TrueCloudLab/neoneo-go
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
|
started *atomic.Bool
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
finished 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.
|
// 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",
|
s.log.Debug("new block in the chain",
|
||||||
zap.Uint32("dbft index", s.dbft.BlockIndex),
|
zap.Uint32("dbft index", s.dbft.BlockIndex),
|
||||||
zap.Uint32("chain index", s.Chain.BlockHeight()))
|
zap.Uint32("chain index", s.Chain.BlockHeight()))
|
||||||
|
if s.lastTimestamp < b.Timestamp {
|
||||||
|
s.lastTimestamp = b.Timestamp
|
||||||
|
}
|
||||||
s.dbft.InitializeConsensus(0)
|
s.dbft.InitializeConsensus(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,6 +426,12 @@ func (s *service) verifyBlock(b block.Block) bool {
|
||||||
s.log.Warn("proposed block has already outdated")
|
s.log.Warn("proposed block has already outdated")
|
||||||
return false
|
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())
|
maxBlockSize := int(s.Chain.GetPolicer().GetMaxBlockSize())
|
||||||
size := io.GetVarSize(coreb)
|
size := io.GetVarSize(coreb)
|
||||||
if size > maxBlockSize {
|
if size > maxBlockSize {
|
||||||
|
@ -492,6 +506,9 @@ func (s *service) processBlock(b block.Block) {
|
||||||
s.log.Warn("error on add block", zap.Error(err))
|
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 {
|
func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness {
|
||||||
|
|
|
@ -344,6 +344,8 @@ func TestService_OnPayload(t *testing.T) {
|
||||||
func TestVerifyBlock(t *testing.T) {
|
func TestVerifyBlock(t *testing.T) {
|
||||||
srv := newTestService(t)
|
srv := newTestService(t)
|
||||||
defer srv.Chain.Close()
|
defer srv.Chain.Close()
|
||||||
|
|
||||||
|
srv.lastTimestamp = 1
|
||||||
t.Run("good empty", func(t *testing.T) {
|
t.Run("good empty", func(t *testing.T) {
|
||||||
b := testchain.NewBlock(t, srv.Chain, 1, 0)
|
b := testchain.NewBlock(t, srv.Chain, 1, 0)
|
||||||
require.True(t, srv.verifyBlock(&neoBlock{Block: *b}))
|
require.True(t, srv.verifyBlock(&neoBlock{Block: *b}))
|
||||||
|
@ -386,6 +388,11 @@ func TestVerifyBlock(t *testing.T) {
|
||||||
b.Index = srv.Chain.BlockHeight()
|
b.Index = srv.Chain.BlockHeight()
|
||||||
require.False(t, srv.verifyBlock(&neoBlock{Block: *b}))
|
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) {
|
t.Run("bad big size", func(t *testing.T) {
|
||||||
script := make([]byte, int(srv.Chain.GetPolicer().GetMaxBlockSize()))
|
script := make([]byte, int(srv.Chain.GetPolicer().GetMaxBlockSize()))
|
||||||
script[0] = byte(opcode.RET)
|
script[0] = byte(opcode.RET)
|
||||||
|
|
Loading…
Reference in a new issue