Skip to content

Conversation

@ssd04
Copy link
Contributor

@ssd04 ssd04 commented Dec 17, 2025

Reasoning behind the pull request

  • Sync missing shard and meta header on bootstrap
  • Added fallback to search in storage when starting

Testing procedure

  • System tests with restart and start in epoch

Pre-requisites

Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:

  • was the PR targeted to the correct branch?
  • if this is a larger feature that probably needs more than one PR, is there a feat branch created?
  • if this is a feat branch merging, do all satellite projects have a proper tag inside go.mod?

@ssd04 ssd04 self-assigned this Dec 17, 2025
Base automatically changed from fixes-async-exec to feat/supernova-async-exec December 18, 2025 10:30
@ssd04 ssd04 marked this pull request as ready for review December 22, 2025 14:39
@codecov
Copy link

codecov bot commented Dec 22, 2025

Codecov Report

❌ Patch coverage is 46.94836% with 113 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.67%. Comparing base (410de51) to head (4f5f4ee).
⚠️ Report is 14 commits behind head on feat/supernova-async-exec.

Files with missing lines Patch % Lines
epochStart/bootstrap/metaStorageHandler.go 26.92% 53 Missing and 4 partials ⚠️
epochStart/bootstrap/process.go 63.04% 24 Missing and 10 partials ⚠️
process/sync/baseSync.go 26.92% 18 Missing and 1 partial ⚠️
epochStart/bootstrap/startInEpochScheduled.go 0.00% 1 Missing and 1 partial ⚠️
process/block/shardblock.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@                      Coverage Diff                      @@
##           feat/supernova-async-exec    #7564      +/-   ##
=============================================================
- Coverage                      77.73%   77.67%   -0.06%     
=============================================================
  Files                            875      874       -1     
  Lines                         120400   120586     +186     
=============================================================
+ Hits                           93591    93667      +76     
- Misses                         20662    20757      +95     
- Partials                        6147     6162      +15     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements the ability to save intermediate headers to storage during bootstrap, which is a key feature for V3 headers (Supernova). The main changes involve synchronizing not just epoch start headers but also intermediate headers up to the last executed block, and storing them appropriately during the bootstrap process.

  • Adds functionality to fetch headers from both pool and storage (not just pool) when needed during bootstrap sync
  • Updates header retrieval logic across block processors to check storage in addition to pool for V3 headers
  • Implements proper storage of intermediate headers and metadata during epoch start bootstrap for both meta and shard nodes

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
process/sync/baseSync.go Added new methods getHeaderWithNonce, getMetaHeaderWithNonce, and getShardHeaderWithNonce to fetch headers from both pool and storage; updated prepareForSyncIfNeeded to use the new retrieval methods
process/block/shardblock.go Updated calls to use new getHeaderFromHash method instead of the removed getHeaderFromHash function
process/block/metablock.go Updated multiple methods to use the new getHeaderFromHash method; added debug logging for self-notarized headers
process/block/baseProcess.go Added getHeaderFromHash method to baseProcessor that checks both pool and storage for V3 headers
process/block/common.go Removed the standalone getHeaderFromHash function in favor of the method-based approach
process/asyncExecution/executionManager/executionManager.go Updated to use getHeaderFromPoolOrStorage (which already existed) with a TODO comment about optimization
process/asyncExecution/executionManager/executionManager_test.go Updated test to reflect the new behavior of fetching from storage when pool lookup fails
epochStart/bootstrap/startInEpochScheduled.go Added logic to handle V3 headers differently in getRequiredHeaderByHash; added TODO about analyzing request requirements
epochStart/bootstrap/shardStorageHandler.go Removed filtering that only saved epoch start headers; now saves intermediate headers as well
epochStart/bootstrap/process.go Added multiple new methods for syncing intermediate headers including syncIntermediateMetaBlocksIfNeeded, syncEpochStartDataInfo, syncLastNotarizedMetaForEpochStartData, and requestBlocksUpToLastExecuted
epochStart/bootstrap/metaStorageHandler.go Added methods to compute and store last self-notarized headers for all shards and meta; added saveEpochStartMetaHdrs to save all synchronized headers
epochStart/bootstrap/fromLocalStorage.go Updated to use process.UnmarshalMetaHeader for proper unmarshaling of meta headers (supporting both V2 and V3)
epochStart/bootstrap/process_test.go Updated and expanded tests to cover the new intermediate header syncing behavior; removed obsolete test case
process/sync/storageBootstrap/metaStorageBootstrapper.go Removed blank line (minor formatting change)
Comments suppressed due to low confidence (1)

epochStart/bootstrap/process.go:939

  • Missing documentation for this function. Consider adding a comment describing what this function does, its parameters, and return values.
func (e *epochStartBootstrap) requestBlocksUpToLastExecuted(
	syncedHeaders map[string]data.HeaderHandler,
	header data.HeaderHandler,
	shardID uint32,
) error {
	if !header.IsHeaderV3() {
		return nil
	}

	lastExecutionResult, err := common.GetLastBaseExecutionResultHandler(header)
	if err != nil {
		return err
	}

	baseHeaderNonce := header.GetNonce()
	lastExecutedNonce := lastExecutionResult.GetHeaderNonce()

	if lastExecutedNonce >= baseHeaderNonce {
		return nil
	}

	headerHashToSync := header.GetPrevHash()
	currentNonce := baseHeaderNonce
	for currentNonce > lastExecutedNonce {
		syncedHeader, err := e.syncOneHeader(headerHashToSync, shardID)
		if err != nil {
			return err
		}

		syncedHeaders[string(headerHashToSync)] = syncedHeader

		headerHashToSync = syncedHeader.GetPrevHash()
		currentNonce = syncedHeader.GetNonce()
	}

	return nil
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ssd04 ssd04 changed the title save intermediate header to storage on bootstrap Fix boostrap from network Dec 24, 2025
@AdoAdoAdo AdoAdoAdo requested a review from Copilot December 29, 2025 07:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

sstanculeanu
sstanculeanu previously approved these changes Dec 29, 2025
return nil
}

for currNonce > lastFinished.GetNonce() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks very similar to the sync loop on requestIntermediateBlocksIfNeeded

can you extract in a func and call it in both places?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored to reduce common code

}

for _, epochStartData := range epochStartMeta.GetEpochStartHandler().GetLastFinalizedHeaderHandlers() {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return bootstrapStorage.BootstrapHeaderInfo{}, epochStart.ErrWrongTypeAssertion
}

if len(shardHeaderHandler.GetMetaBlockHashes()) <= 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be == 0, as it cannot be negative

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored this part

}, nil
}

metaHash := shardHeaderHandler.GetMetaBlockHashes()[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be the last referenced metablock hash instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

}, nil
}

metaHash := shardHeaderHandler.GetMetaBlockHashes()[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed, the metaHash should be the last referenced metablock on the shardHeader.LastExecutinResult
if no Meta referenced there, then search on the previous and so forth until one is found.

valid for all returned bootstrapStorage.BootstrapHeaderInfo in the context of supernova

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated


func (bp *baseProcessor) getHeaderFromHash(
isHeaderV3 bool,
shardHeaderHash []byte,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename this to headerHash?

as this could also apply to metablocks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

sstanculeanu
sstanculeanu previously approved these changes Dec 29, 2025
sstanculeanu
sstanculeanu previously approved these changes Dec 29, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 833 to 851
for {
numIncludedMetaBlocks := len(currentHdr.GetMetaBlockHashes())

// if there are no included meta blocks, go to prev header
if numIncludedMetaBlocks == 0 {
header, err := fetchPrevHeader(syncedHeaders, currentHdr)
if err != nil {
return nil, err
}

currentHdr = header
continue
}

// if there are notarized meta headers, return last included meta header
metaHash := currentHdr.GetMetaBlockHashes()[numIncludedMetaBlocks-1]

return metaHash, nil
}
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential infinite loop: the for loop in getLastReferencedMetaHash lacks a termination condition if all previous shard headers have no meta block hashes. The loop will continue calling fetchPrevHeader indefinitely until it either finds a header with meta block hashes or hits an error. Consider adding a maximum iteration count or checking if we've reached the genesis block to prevent an infinite loop in edge cases.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added genesis check condition

Comment on lines +235 to +251
func fetchPrevHeader(
syncedHeaders map[string]data.HeaderHandler,
header data.HeaderHandler,
) (data.ShardHeaderHandler, error) {
prevHash := header.GetPrevHash()
syncedHeader, ok := syncedHeaders[string(prevHash)]
if !ok {
return nil, epochStart.ErrMissingHeader
}

shardHeader, ok := syncedHeader.(data.ShardHeaderHandler)
if !ok {
return nil, epochStart.ErrWrongTypeAssertion
}

return shardHeader, nil
}
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated function: The fetchPrevHeader function in metaStorageHandler.go (lines 235-251) is identical to the syncPrevShardHeaderHandler method in process.go (lines 854-871), except the latter also stores the header in syncedHeaders. Consider extracting this into a shared utility function to avoid code duplication and potential maintenance issues.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mainly the similar part is the type assertion, otherwise they are quite different since the other one uses syncOneHeader which needs other things like request, data pool, we can have a function pointer for this call, but it would be very similar with what we already have now

@sstanculeanu sstanculeanu merged commit e7e0cd1 into feat/supernova-async-exec Dec 29, 2025
9 of 11 checks passed
@sstanculeanu sstanculeanu deleted the fix-meta-bootstrap-sync branch December 29, 2025 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants