From 35501a281a78a579cd425203d9b7bc1df05e9f04 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 25 Jun 2021 13:24:24 +0300 Subject: [PATCH] core: remove untraceable blocks wrt StateSyncInterval --- pkg/core/blockchain.go | 18 ++++++- pkg/core/blockchain_test.go | 103 ++++++++++++++++++++++++++++-------- 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 16edf08dd..68493987b 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -740,8 +740,22 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error } } if bc.config.RemoveUntraceableBlocks { - if block.Index > bc.config.MaxTraceableBlocks { - index := block.Index - bc.config.MaxTraceableBlocks // is at least 1 + var start, stop uint32 + if bc.config.P2PStateExchangeExtensions { + // remove batch of old blocks starting from P2-MaxTraceableBlocks-StateSyncInterval up to P2-MaxTraceableBlocks + if block.Index >= 2*uint32(bc.config.StateSyncInterval) && + block.Index >= uint32(bc.config.StateSyncInterval)+bc.config.MaxTraceableBlocks && // check this in case if MaxTraceableBlocks>StateSyncInterval + int(block.Index)%bc.config.StateSyncInterval == 0 { + stop = block.Index - uint32(bc.config.StateSyncInterval) - bc.config.MaxTraceableBlocks + if stop > uint32(bc.config.StateSyncInterval) { + start = stop - uint32(bc.config.StateSyncInterval) + } + } + } else if block.Index > bc.config.MaxTraceableBlocks { + start = block.Index - bc.config.MaxTraceableBlocks // is at least 1 + stop = start + 1 + } + for index := start; index < stop; index++ { err := kvcache.DeleteBlock(bc.headerHashes[index], writeBuf) if err != nil { bc.log.Warn("error while removing old block", diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 8f0d00d51..8b58e2a1f 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -1579,35 +1579,92 @@ func TestDumpAndRestore(t *testing.T) { } func TestRemoveUntraceable(t *testing.T) { - bc := newTestChainWithCustomCfg(t, func(c *config.Config) { - c.ProtocolConfiguration.MaxTraceableBlocks = 2 - c.ProtocolConfiguration.RemoveUntraceableBlocks = true + check := func(t *testing.T, bc *Blockchain, tHash, bHash util.Uint256, errorExpected bool) { + _, _, err := bc.GetTransaction(tHash) + if errorExpected { + require.Error(t, err) + } else { + require.NoError(t, err) + } + _, err = bc.GetAppExecResults(tHash, trigger.Application) + if errorExpected { + require.Error(t, err) + } else { + require.NoError(t, err) + } + _, err = bc.GetBlock(bHash) + if errorExpected { + require.Error(t, err) + } else { + require.NoError(t, err) + } + _, err = bc.GetHeader(bHash) + require.NoError(t, err) + } + t.Run("P2PStateExchangeExtensions off", func(t *testing.T) { + bc := newTestChainWithCustomCfg(t, func(c *config.Config) { + c.ProtocolConfiguration.MaxTraceableBlocks = 2 + c.ProtocolConfiguration.RemoveUntraceableBlocks = true + }) + + tx1, err := testchain.NewTransferFromOwner(bc, bc.contracts.NEO.Hash, util.Uint160{}, 1, 0, bc.BlockHeight()+1) + require.NoError(t, err) + b1 := bc.newBlock(tx1) + require.NoError(t, bc.AddBlock(b1)) + tx1Height := bc.BlockHeight() + + tx2, err := testchain.NewTransferFromOwner(bc, bc.contracts.NEO.Hash, util.Uint160{}, 1, 0, bc.BlockHeight()+1) + require.NoError(t, err) + require.NoError(t, bc.AddBlock(bc.newBlock(tx2))) + + _, h1, err := bc.GetTransaction(tx1.Hash()) + require.NoError(t, err) + require.Equal(t, tx1Height, h1) + + require.NoError(t, bc.AddBlock(bc.newBlock())) + + check(t, bc, tx1.Hash(), b1.Hash(), true) }) + t.Run("P2PStateExchangeExtensions on", func(t *testing.T) { + bc := newTestChainWithCustomCfg(t, func(c *config.Config) { + c.ProtocolConfiguration.MaxTraceableBlocks = 2 + c.ProtocolConfiguration.RemoveUntraceableBlocks = true + c.ProtocolConfiguration.P2PStateExchangeExtensions = true + c.ProtocolConfiguration.StateSyncInterval = 2 + c.ProtocolConfiguration.StateRootInHeader = true + }) - tx1, err := testchain.NewTransferFromOwner(bc, bc.contracts.NEO.Hash, util.Uint160{}, 1, 0, bc.BlockHeight()+1) - require.NoError(t, err) - b1 := bc.newBlock(tx1) - require.NoError(t, bc.AddBlock(b1)) - tx1Height := bc.BlockHeight() + tx1, err := testchain.NewTransferFromOwner(bc, bc.contracts.NEO.Hash, util.Uint160{}, 1, 0, bc.BlockHeight()+1) + require.NoError(t, err) + b1 := bc.newBlock(tx1) + require.NoError(t, bc.AddBlock(b1)) + tx1Height := bc.BlockHeight() - tx2, err := testchain.NewTransferFromOwner(bc, bc.contracts.NEO.Hash, util.Uint160{}, 1, 0, bc.BlockHeight()+1) - require.NoError(t, err) - require.NoError(t, bc.AddBlock(bc.newBlock(tx2))) + tx2, err := testchain.NewTransferFromOwner(bc, bc.contracts.NEO.Hash, util.Uint160{}, 1, 0, bc.BlockHeight()+1) + require.NoError(t, err) + b2 := bc.newBlock(tx2) + require.NoError(t, bc.AddBlock(b2)) + tx2Height := bc.BlockHeight() - _, h1, err := bc.GetTransaction(tx1.Hash()) - require.NoError(t, err) - require.Equal(t, tx1Height, h1) + _, h1, err := bc.GetTransaction(tx1.Hash()) + require.NoError(t, err) + require.Equal(t, tx1Height, h1) - require.NoError(t, bc.AddBlock(bc.newBlock())) + require.NoError(t, bc.AddBlock(bc.newBlock())) + require.NoError(t, bc.AddBlock(bc.newBlock())) + require.NoError(t, bc.AddBlock(bc.newBlock())) - _, _, err = bc.GetTransaction(tx1.Hash()) - require.Error(t, err) - _, err = bc.GetAppExecResults(tx1.Hash(), trigger.Application) - require.Error(t, err) - _, err = bc.GetBlock(b1.Hash()) - require.Error(t, err) - _, err = bc.GetHeader(b1.Hash()) - require.NoError(t, err) + check(t, bc, tx1.Hash(), b1.Hash(), false) + check(t, bc, tx2.Hash(), b2.Hash(), false) + + require.NoError(t, bc.AddBlock(bc.newBlock())) + + check(t, bc, tx1.Hash(), b1.Hash(), true) + check(t, bc, tx2.Hash(), b2.Hash(), false) + _, h2, err := bc.GetTransaction(tx2.Hash()) + require.NoError(t, err) + require.Equal(t, tx2Height, h2) + }) } func TestInvalidNotification(t *testing.T) {