Skip to content

Commit a59d76b

Browse files
committed
augment existing pruning and finality tests
Signed-off-by: Igor Braga <[email protected]>
1 parent 334b678 commit a59d76b

File tree

4 files changed

+120
-36
lines changed

4 files changed

+120
-36
lines changed

cmd/pruning/pruning.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (r *importantRoots) addHeader(header *types.Header, overwrite bool) error {
8484
var hashListRegex = regexp.MustCompile("^(0x)?[0-9a-fA-F]{64}(,(0x)?[0-9a-fA-F]{64})*$")
8585

8686
// Finds important roots to retain while proving
87-
func findImportantRoots(ctx context.Context, executionDB ethdb.Database, stack *node.Node, initConfig *conf.InitConfig, cacheConfig *core.BlockChainConfig, persistentConfig *conf.PersistentConfig, l1Client *ethclient.Client, rollupAddrs chaininfo.RollupAddresses, validatorRequired, melEnabled bool) ([]common.Hash, error) {
87+
func findImportantRoots(ctx context.Context, executionDB ethdb.Database, initConfig *conf.InitConfig, l1Client *ethclient.Client, rollupAddrs chaininfo.RollupAddresses, validatorRequired bool) ([]common.Hash, error) {
8888
chainConfig := gethexec.TryReadStoredChainConfig(executionDB)
8989
if chainConfig == nil {
9090
return nil, errors.New("database doesn't have a chain config (was this node initialized?)")
@@ -164,7 +164,7 @@ func findImportantRoots(ctx context.Context, executionDB ethdb.Database, stack *
164164
} else {
165165
return nil, fmt.Errorf("unknown pruning mode: \"%v\"", initConfig.Prune)
166166
}
167-
if initConfig.Prune != "minimal" && l1Client != nil {
167+
if initConfig.Prune != "minimal" {
168168
// in pruning modes other than "minimal", get the latest finalized block and add it as a pruning target
169169
finalizedBlockHash := rawdb.ReadFinalizedBlockHash(executionDB)
170170
finalizedBlockNumber, ok := rawdb.ReadHeaderNumber(executionDB, finalizedBlockHash)
@@ -245,7 +245,7 @@ func PruneExecutionDB(ctx context.Context, executionDB ethdb.Database, stack *no
245245
if initConfig.Prune == "" {
246246
return pruner.RecoverPruning(stack.InstanceDir(), executionDB, initConfig.PruneThreads)
247247
}
248-
root, err := findImportantRoots(ctx, executionDB, stack, initConfig, cacheConfig, persistentConfig, l1Client, rollupAddrs, validatorRequired, melEnabled)
248+
root, err := findImportantRoots(ctx, executionDB, initConfig, l1Client, rollupAddrs, validatorRequired)
249249
if err != nil {
250250
return fmt.Errorf("failed to find root to retain for pruning: %w", err)
251251
}

execution/gethexec/sync_monitor.go

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -237,43 +237,73 @@ func (s *SyncMonitor) BlockMetadataByNumber(ctx context.Context, blockNum uint64
237237
return nil, nil
238238
}
239239

240+
func (s *SyncMonitor) getBlockHeaderForFinalityData(
241+
finalityData *arbutil.FinalityData,
242+
finalityDataType string,
243+
modifier func(curr *arbutil.FinalityData) (arbutil.MessageIndex, common.Hash, error),
244+
) (*types.Header, error) {
245+
if finalityData == nil {
246+
return nil, nil
247+
}
248+
249+
msgIdx := finalityData.MsgIdx
250+
blockHash := finalityData.BlockHash
251+
252+
if modifier != nil {
253+
var err error
254+
msgIdx, blockHash, err = modifier(finalityData)
255+
if err != nil {
256+
return nil, err
257+
}
258+
}
259+
260+
blockNumber := s.exec.MessageIndexToBlockNumber(msgIdx)
261+
block := s.exec.bc.GetBlockByNumber(blockNumber)
262+
if block == nil {
263+
log.Debug("block not found", "finalityDataType", finalityDataType, "blockNumber", blockNumber)
264+
return nil, nil
265+
}
266+
if block.Hash() != blockHash {
267+
errorMsg := fmt.Sprintf(
268+
"block hash mismatch,finalityDataType=%s blockNumber=%v, block hash provided by consensus=%v, block hash from execution=%v",
269+
finalityDataType,
270+
blockNumber,
271+
blockHash,
272+
block.Hash(),
273+
)
274+
return nil, errors.New(errorMsg)
275+
}
276+
return block.Header(), nil
277+
}
278+
240279
func (s *SyncMonitor) getFinalityBlockHeader(
241280
waitForBlockValidator bool,
242281
validatedFinalityData *arbutil.FinalityData,
243282
finalityFinalityData *arbutil.FinalityData,
283+
finalityDataType string,
244284
) (*types.Header, error) {
245285
if finalityFinalityData == nil {
246286
return nil, nil
247287
}
248288

249289
finalityMsgIdx := finalityFinalityData.MsgIdx
250290
finalityBlockHash := finalityFinalityData.BlockHash
251-
if waitForBlockValidator {
291+
292+
validatorModifier := func(curr *arbutil.FinalityData) (arbutil.MessageIndex, common.Hash, error) {
293+
if !waitForBlockValidator {
294+
return finalityMsgIdx, finalityBlockHash, nil
295+
}
252296
if validatedFinalityData == nil {
253-
return nil, errors.New("block validator not set")
297+
return 0, common.Hash{}, errors.New("block validator not set")
254298
}
299+
// If the finalized index is ahead of the validated one, cap it at the validated one
255300
if finalityFinalityData.MsgIdx > validatedFinalityData.MsgIdx {
256-
finalityMsgIdx = validatedFinalityData.MsgIdx
257-
finalityBlockHash = validatedFinalityData.BlockHash
301+
return validatedFinalityData.MsgIdx, validatedFinalityData.BlockHash, nil
258302
}
303+
return finalityMsgIdx, finalityBlockHash, nil
259304
}
260305

261-
finalityBlockNumber := s.exec.MessageIndexToBlockNumber(finalityMsgIdx)
262-
finalityBlock := s.exec.bc.GetBlockByNumber(finalityBlockNumber)
263-
if finalityBlock == nil {
264-
log.Debug("Finality block not found", "blockNumber", finalityBlockNumber)
265-
return nil, nil
266-
}
267-
if finalityBlock.Hash() != finalityBlockHash {
268-
errorMsg := fmt.Sprintf(
269-
"finality block hash mismatch, blockNumber=%v, block hash provided by consensus=%v, block hash from execution=%v",
270-
finalityBlockNumber,
271-
finalityBlockHash,
272-
finalityBlock.Hash(),
273-
)
274-
return nil, errors.New(errorMsg)
275-
}
276-
return finalityBlock.Header(), nil
306+
return s.getBlockHeaderForFinalityData(finalityFinalityData, finalityDataType, validatorModifier)
277307
}
278308

279309
func (s *SyncMonitor) SetFinalityData(
@@ -282,28 +312,42 @@ func (s *SyncMonitor) SetFinalityData(
282312
finalizedFinalityData *arbutil.FinalityData,
283313
validatedFinalityData *arbutil.FinalityData,
284314
) error {
315+
// Check finalized blocks
285316
finalizedBlockHeader, err := s.getFinalityBlockHeader(
286317
s.config.FinalizedBlockWaitForBlockValidator,
287318
validatedFinalityData,
288319
finalizedFinalityData,
320+
"finalized",
289321
)
290322
if err != nil {
291323
return err
292324
}
293325
s.exec.bc.SetFinalized(finalizedBlockHeader)
294326

295-
if executionDB != nil && finalizedBlockHeader != nil {
296-
finalizedBlockHash := finalizedBlockHeader.Hash()
297-
err := executionDB.Put(ValidatedBlockHashKey, finalizedBlockHash.Bytes())
327+
// Check validated blocks
328+
validatedBlockHeader, err := s.getBlockHeaderForFinalityData(
329+
validatedFinalityData,
330+
"validated",
331+
nil,
332+
)
333+
if err != nil {
334+
return err
335+
}
336+
337+
if executionDB != nil && validatedBlockHeader != nil {
338+
validatedBlockHash := validatedBlockHeader.Hash()
339+
err := executionDB.Put(ValidatedBlockHashKey, validatedBlockHash.Bytes())
298340
if err != nil {
299341
return err
300342
}
301343
}
302344

345+
// Check safe blocks
303346
safeBlockHeader, err := s.getFinalityBlockHeader(
304347
s.config.SafeBlockWaitForBlockValidator,
305348
validatedFinalityData,
306349
safeFinalityData,
350+
"safe",
307351
)
308352
if err != nil {
309353
return err

system_tests/finality_data_test.go

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/offchainlabs/nitro/arbnode"
1919
"github.com/offchainlabs/nitro/arbutil"
20+
"github.com/offchainlabs/nitro/execution/gethexec"
2021
"github.com/offchainlabs/nitro/util/testhelpers/env"
2122
)
2223

@@ -174,20 +175,52 @@ func TestFinalityDataWaitForBlockValidator(t *testing.T) {
174175
BlockHash: validatedMsgResult.BlockHash,
175176
}
176177

177-
err = builder.L2.ExecNode.SyncMonitor.SetFinalityData(nil, &safeFinalityData, &finalizedFinalityData, &validatedFinalityData)
178+
err = builder.L2.ExecNode.SyncMonitor.SetFinalityData(builder.L2.ExecNode.ExecutionDB, &safeFinalityData, &finalizedFinalityData, &validatedFinalityData)
178179
Require(t, err)
179180

181+
// Make sure finalized and validated blocks in executionDB match the expected ones for builder.L2
182+
data, err := builder.L2.ExecNode.ExecutionDB.Get(gethexec.ValidatedBlockHashKey)
183+
Require(t, err)
184+
validatedBlockHash := common.BytesToHash(data)
185+
finalizedBlockHash := rawdb.ReadFinalizedBlockHash(builder.L2.ExecNode.ExecutionDB)
186+
187+
if validatedBlockHash != validatedMsgResult.BlockHash {
188+
t.Fatalf("validatedBlockHash: %s does not match expected validatedBlockHash: %s", validatedBlockHash.Hex(), validatedMsgResult.BlockHash.Hex())
189+
}
190+
191+
// We compare finalizedBlockHash against validated block hash because FinalizedBlockWaitForBlockValidator is
192+
// set to true therefore we should expect finalized block hash to match the validated block hash
193+
if finalizedBlockHash != validatedMsgResult.BlockHash {
194+
t.Fatalf("finalizedBlockHash: %s does not match expected finalizedBlockHash: %s", finalizedBlockHash.Hex(), validatedMsgResult.BlockHash.Hex())
195+
}
196+
180197
// wait for block validator is set to true in second node
181198
checksFinalityData(t, "first node", ctx, builder.L2, validatedMsgIdx, validatedMsgIdx)
182199

183-
err = testClient2ndNode.ExecNode.SyncMonitor.SetFinalityData(nil, &safeFinalityData, &finalizedFinalityData, &validatedFinalityData)
200+
err = testClient2ndNode.ExecNode.SyncMonitor.SetFinalityData(testClient2ndNode.ExecNode.ExecutionDB, &safeFinalityData, &finalizedFinalityData, &validatedFinalityData)
184201
Require(t, err)
185202

203+
// Make sure finalized and validated blocks in executionDB match the expected ones for second node
204+
data, err = testClient2ndNode.ExecNode.ExecutionDB.Get(gethexec.ValidatedBlockHashKey)
205+
Require(t, err)
206+
validatedBlockHash2ndNode := common.BytesToHash(data)
207+
finalizedBlockHash2ndNode := rawdb.ReadFinalizedBlockHash(testClient2ndNode.ExecNode.ExecutionDB)
208+
209+
if validatedBlockHash2ndNode != validatedMsgResult.BlockHash {
210+
t.Fatalf("validatedBlockHash: %s does not match expected validatedBlockHash: %s", validatedBlockHash2ndNode.Hex(), validatedMsgResult.BlockHash.Hex())
211+
}
212+
213+
// Since FinalizedBlockWaitForBlockValidator is set to true for the second node we can
214+
// compare finalizedBlockHash with expected finalized block hash
215+
if finalizedBlockHash2ndNode != finalizedMsgResult.BlockHash {
216+
t.Fatalf("finalizedBlockHash: %s does not match expected finalizedBlockHash: %s", finalizedBlockHash2ndNode.Hex(), finalizedMsgResult.BlockHash.Hex())
217+
}
218+
186219
// wait for block validator is no set to true in second node
187220
checksFinalityData(t, "2nd node", ctx, testClient2ndNode, finalizedMsgIdx, safeMsgIdx)
188221

189222
// if validatedFinalityData is nil, error should be returned if waitForBlockValidator is set to true
190-
err = builder.L2.ExecNode.SyncMonitor.SetFinalityData(nil, &safeFinalityData, &finalizedFinalityData, nil)
223+
err = builder.L2.ExecNode.SyncMonitor.SetFinalityData(builder.L2.ExecNode.ExecutionDB, &safeFinalityData, &finalizedFinalityData, nil)
191224
if err == nil {
192225
t.Fatalf("err should not be nil")
193226
}

system_tests/pruning_test.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ func testPruning(t *testing.T, mode string, pruneParallelStorageTraversal bool)
4848
// PathScheme prunes the state trie by itself, so only HashScheme should be tested
4949
builder.RequireScheme(t, rawdb.HashScheme)
5050

51-
// Needed to create safe blocks; hence forcing SetFinalityData call
5251
builder.nodeConfig.ParentChainReader.UseFinalityData = true
52+
builder.nodeConfig.BlockValidator.Enable = true
5353

5454
_ = builder.Build(t)
5555
l2cleanupDone := false
@@ -78,8 +78,8 @@ func testPruning(t *testing.T, mode string, pruneParallelStorageTraversal bool)
7878
// add to the new executionDB below
7979
data, err := builder.L2.ExecNode.ExecutionDB.Get(gethexec.ValidatedBlockHashKey)
8080
Require(t, err)
81-
validatedBlockHash := common.BytesToHash(data)
82-
finalizedBlockHash := rawdb.ReadFinalizedBlockHash(builder.L2.ExecNode.ExecutionDB)
81+
expectedValidatedBlockHash := common.BytesToHash(data)
82+
expectedFinalizedBlockHash := rawdb.ReadFinalizedBlockHash(builder.L2.ExecNode.ExecutionDB)
8383

8484
l2cleanupDone = true
8585
builder.L2.cleanup()
@@ -94,11 +94,18 @@ func testPruning(t *testing.T, mode string, pruneParallelStorageTraversal bool)
9494
defer executionDB.Close()
9595
executionDBEntriesBeforePruning := countStateEntries(executionDB)
9696

97-
// Since we're dealing with a new executionDB we store both validatedBlockHash and
98-
// finalized blocks back into this new executionDB.
99-
err = executionDB.Put(gethexec.ValidatedBlockHashKey, validatedBlockHash.Bytes())
97+
data, err := executionDB.Get(gethexec.ValidatedBlockHashKey)
10098
Require(t, err)
101-
rawdb.WriteFinalizedBlockHash(executionDB, finalizedBlockHash)
99+
validatedBlockHash := common.BytesToHash(data)
100+
finalizedBlockHash := rawdb.ReadFinalizedBlockHash(executionDB)
101+
102+
if validatedBlockHash != expectedValidatedBlockHash {
103+
t.Fatalf("validatedBlockHash: %s does not match expected ValidatedBlockHash: %s", validatedBlockHash.Hex(), expectedValidatedBlockHash.Hex())
104+
}
105+
106+
if finalizedBlockHash != expectedFinalizedBlockHash {
107+
t.Fatalf("finalizedBlockHash: %s does not match expected finalizedBlockHash: %s", finalizedBlockHash.Hex(), expectedFinalizedBlockHash.Hex())
108+
}
102109

103110
prand := testhelpers.NewPseudoRandomDataSource(t, 1)
104111
var testKeys [][]byte

0 commit comments

Comments
 (0)