diff --git a/epochStart/bootstrap/fromLocalStorage.go b/epochStart/bootstrap/fromLocalStorage.go index f460ad4fd66..c6ae3f5bccf 100644 --- a/epochStart/bootstrap/fromLocalStorage.go +++ b/epochStart/bootstrap/fromLocalStorage.go @@ -13,6 +13,7 @@ import ( "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/epochStart" "github.com/multiversx/mx-chain-go/epochStart/bootstrap/disabled" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/bootstrapStorage" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/sharding/nodesCoordinator" @@ -288,8 +289,7 @@ func (e *epochStartBootstrap) getEpochStartMetaFromStorage(storer storage.Storer return nil, err } - metaBlock := &block.MetaBlock{} - err = e.coreComponentsHolder.InternalMarshalizer().Unmarshal(metaBlock, epochStartMetaBlock) + metaBlock, err := process.UnmarshalMetaHeader(e.coreComponentsHolder.InternalMarshalizer(), epochStartMetaBlock) if err != nil { return nil, err } diff --git a/epochStart/bootstrap/metaStorageHandler.go b/epochStart/bootstrap/metaStorageHandler.go index 6c735aecd2d..9b216dee234 100644 --- a/epochStart/bootstrap/metaStorageHandler.go +++ b/epochStart/bootstrap/metaStorageHandler.go @@ -104,6 +104,11 @@ func (msh *metaStorageHandler) SaveDataToStorage(components *ComponentsNeededFor return err } + err = msh.saveEpochStartMetaHdrs(components) + if err != nil { + return err + } + msh.saveMiniblocksFromComponents(components) miniBlocks, err := msh.groupMiniBlocksByShard(components.PendingMiniBlocks) @@ -126,10 +131,19 @@ func (msh *metaStorageHandler) SaveDataToStorage(components *ComponentsNeededFor return err } + lastSelfNotarizedHeaders, err := msh.getLastSelfNotarizedHeaders( + components.EpochStartMetaBlock, + lastHeader, + components.Headers, + ) + if err != nil { + return err + } + bootStrapData := bootstrapStorage.BootstrapData{ LastHeader: lastHeader, LastCrossNotarizedHeaders: lastCrossNotarizedHeaders, - LastSelfNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{lastHeader}, + LastSelfNotarizedHeaders: lastSelfNotarizedHeaders, ProcessedMiniBlocks: []bootstrapStorage.MiniBlocksInMeta{}, PendingMiniBlocks: miniBlocks, NodesCoordinatorConfigKey: nodesCoordinatorConfigKey, @@ -163,6 +177,130 @@ func (msh *metaStorageHandler) SaveDataToStorage(components *ComponentsNeededFor return nil } +func (msh *metaStorageHandler) getLastSelfNotarizedHeaders( + epochStartMeta data.MetaHeaderHandler, + epochStartMetaBootstrapInfo bootstrapStorage.BootstrapHeaderInfo, + syncedHeaders map[string]data.HeaderHandler, +) ([]bootstrapStorage.BootstrapHeaderInfo, error) { + var lastSelfNotarizedHeaders []bootstrapStorage.BootstrapHeaderInfo + if !epochStartMeta.IsHeaderV3() { + return []bootstrapStorage.BootstrapHeaderInfo{ + epochStartMetaBootstrapInfo, + }, nil + } + + for _, epochStartData := range epochStartMeta.GetEpochStartHandler().GetLastFinalizedHeaderHandlers() { + bootstrapHdrInfo, err := msh.getLastNotarizedBootstrapInfoForEpochStartData(epochStartData, syncedHeaders) + if err != nil { + return nil, err + } + + lastSelfNotarizedHeaders = append(lastSelfNotarizedHeaders, bootstrapHdrInfo) + } + + bootstrapHdrInfoMeta, err := msh.getLastMetaBootstrapInfo(epochStartMeta, syncedHeaders) + if err != nil { + return nil, err + } + + lastSelfNotarizedHeaders = append(lastSelfNotarizedHeaders, bootstrapHdrInfoMeta) + + return lastSelfNotarizedHeaders, nil +} + +func (msh *metaStorageHandler) getLastMetaBootstrapInfo( + epochStartMeta data.MetaHeaderHandler, + syncedHeaders map[string]data.HeaderHandler, +) (bootstrapStorage.BootstrapHeaderInfo, error) { + lastExecRes, err := common.GetLastBaseExecutionResultHandler(epochStartMeta) + if err != nil { + return bootstrapStorage.BootstrapHeaderInfo{}, err + } + + lastExecMetaHeader, ok := syncedHeaders[string(lastExecRes.GetHeaderHash())] + if !ok { + return bootstrapStorage.BootstrapHeaderInfo{}, epochStart.ErrMissingHeader + } + + bootstrapHdrInfoMeta := bootstrapStorage.BootstrapHeaderInfo{ + ShardId: core.MetachainShardId, + Epoch: lastExecMetaHeader.GetEpoch(), + Nonce: lastExecMetaHeader.GetNonce(), + Hash: lastExecRes.GetHeaderHash(), + } + + return bootstrapHdrInfoMeta, nil +} + +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 +} + +func (msh *metaStorageHandler) getLastNotarizedBootstrapInfoForEpochStartData( + epochStartData data.EpochStartShardDataHandler, + syncedHeaders map[string]data.HeaderHandler, +) (bootstrapStorage.BootstrapHeaderInfo, error) { + shardHeaderHash := epochStartData.GetHeaderHash() + shardHeader, ok := syncedHeaders[string(shardHeaderHash)] + if !ok { + return bootstrapStorage.BootstrapHeaderInfo{}, epochStart.ErrMissingHeader + } + + lastReferencedMetaHash, err := getLastReferencedMetaHash(syncedHeaders, fetchPrevHeader, shardHeader) + if err != nil { + return bootstrapStorage.BootstrapHeaderInfo{}, err + } + + lastReferencesMetaBlock, ok := syncedHeaders[string(lastReferencedMetaHash)] + if !ok { + return bootstrapStorage.BootstrapHeaderInfo{}, epochStart.ErrMissingHeader + } + + bootstrapHdrInfo := bootstrapStorage.BootstrapHeaderInfo{ + ShardId: epochStartData.GetShardID(), + Epoch: lastReferencesMetaBlock.GetEpoch(), + Nonce: lastReferencesMetaBlock.GetNonce(), + Hash: lastReferencedMetaHash, + } + + return bootstrapHdrInfo, nil +} + +func (msh *metaStorageHandler) saveEpochStartMetaHdrs(components *ComponentsNeededForBootstrap) error { + for _, hdr := range components.Headers { + isForCurrentShard := hdr.GetShardID() == msh.shardCoordinator.SelfId() + if !isForCurrentShard { + _, err := msh.saveShardHdrToStorage(hdr) + if err != nil { + return err + } + + continue + } + + _, err := msh.saveMetaHdrToStorage(hdr) + if err != nil { + return err + } + } + + return nil +} + func (msh *metaStorageHandler) saveLastCrossNotarizedHeaders( meta data.MetaHeaderHandler, mapHeaders map[string]data.HeaderHandler, diff --git a/epochStart/bootstrap/process.go b/epochStart/bootstrap/process.go index 473820f478a..97495c67dfe 100644 --- a/epochStart/bootstrap/process.go +++ b/epochStart/bootstrap/process.go @@ -692,15 +692,19 @@ func (e *epochStartBootstrap) createSyncers() error { func (e *epochStartBootstrap) syncHeadersV3From(meta data.MetaHeaderHandler) (map[string]data.HeaderHandler, error) { syncedHeaders := make(map[string]data.HeaderHandler) + + hashesToRequest := make([][]byte, 0) + shardIds := make([]uint32, 0) for _, epochStartData := range meta.GetEpochStartHandler().GetLastFinalizedHeaderHandlers() { - err := e.requestIntermediateBlocksIfNeeded(syncedHeaders, epochStartData.GetHeaderHash(), epochStartData.GetShardID()) + err := e.syncEpochStartDataInfo(meta, epochStartData, syncedHeaders) if err != nil { return nil, err } + + hashesToRequest = append(hashesToRequest, epochStartData.GetLastFinishedMetaBlock()) + shardIds = append(shardIds, core.MetachainShardId) } - hashesToRequest := make([][]byte, 0) - shardIds := make([]uint32, 0) syncedMetaHeaders, err := e.syncEpochStartMetaHeaders(meta, hashesToRequest, shardIds) if err != nil { return nil, err @@ -713,16 +717,166 @@ func (e *epochStartBootstrap) syncHeadersV3From(meta data.MetaHeaderHandler) (ma return syncedHeaders, nil } +func (e *epochStartBootstrap) syncIntermediateBlocksIfNeeded( + syncedHeaders map[string]data.HeaderHandler, + header data.HeaderHandler, + lastExecutedNonce uint64, +) error { + shardID := header.GetShardID() + + hashToSync := header.GetPrevHash() + currNonce := header.GetNonce() + + if lastExecutedNonce >= currNonce { + return nil + } + + for currNonce > lastExecutedNonce { + // check if not already synced (when handled for the other shards) + header, ok := syncedHeaders[string(hashToSync)] + if ok { + hashToSync = header.GetPrevHash() + currNonce = header.GetNonce() + continue + } + + header, err := e.syncOneHeader(hashToSync, shardID) + if err != nil { + return err + } + syncedHeaders[string(hashToSync)] = header + + hashToSync = header.GetPrevHash() + currNonce = header.GetNonce() + } + + return nil +} + +func (e *epochStartBootstrap) syncEpochStartDataInfo( + epochStartMeta data.HeaderHandler, + epochStartData data.EpochStartShardDataHandler, + syncedHeaders map[string]data.HeaderHandler, +) error { + syncedHeader, err := e.syncOneHeader(epochStartData.GetHeaderHash(), epochStartData.GetShardID()) + if err != nil { + return err + } + syncedHeaders[string(epochStartData.GetHeaderHash())] = syncedHeader + + if !syncedHeader.IsHeaderV3() { + return nil + } + + err = e.syncBlocksUpToLastExecuted(syncedHeaders, syncedHeader, epochStartData.GetShardID()) + if err != nil { + return err + } + + // sync last notarized meta header references by epoch start header for shard + // this will sync based on the meta block hashes references on header and based on the provided LastFinishedMetaBlock + err = e.syncLastNotarizedMetaForEpochStartData(syncedHeaders, syncedHeader) + if err != nil { + return err + } + + lastFinishedMetaBlockForShard, err := e.syncOneHeader(epochStartData.GetLastFinishedMetaBlock(), core.MetachainShardId) + if err != nil { + return err + } + syncedHeaders[string(epochStartData.GetLastFinishedMetaBlock())] = lastFinishedMetaBlockForShard + + // sync meta blocks from epoch start meta blocks up to last finished metablock referenced on shard + return e.syncIntermediateBlocksIfNeeded(syncedHeaders, epochStartMeta, lastFinishedMetaBlockForShard.GetNonce()) +} + +func (e *epochStartBootstrap) syncLastNotarizedMetaForEpochStartData( + syncedHeaders map[string]data.HeaderHandler, + header data.HeaderHandler, +) error { + lastReferencedMetaHash, err := getLastReferencedMetaHash(syncedHeaders, e.syncPrevShardHeaderHandler, header) + if err != nil { + return err + } + + syncedHeader, err := e.syncOneHeader(lastReferencedMetaHash, core.MetachainShardId) + if err != nil { + return err + } + syncedHeaders[string(lastReferencedMetaHash)] = syncedHeader + + return nil +} + +func getLastReferencedMetaHash( + syncedHeaders map[string]data.HeaderHandler, + fetchPrevHeader func(syncedHeaders map[string]data.HeaderHandler, header data.HeaderHandler) (data.ShardHeaderHandler, error), + header data.HeaderHandler, +) ([]byte, error) { + // get last execution result header for epoch start data shard header + lastExecutionResult, err := common.GetLastBaseExecutionResultHandler(header) + if err != nil { + return nil, err + } + + lastExecutedHeader, ok := syncedHeaders[string(lastExecutionResult.GetHeaderHash())] + if !ok { + return nil, epochStart.ErrMissingHeader + } + + lastExecutedShardHeader, ok := lastExecutedHeader.(data.ShardHeaderHandler) + if !ok { + return nil, epochStart.ErrWrongTypeAssertion + } + + var lastReferencedMetaHash []byte + + currentHdr := lastExecutedShardHeader + for currentHdr.GetNonce() > 0 { + numIncludedMetaBlocks := len(currentHdr.GetMetaBlockHashes()) + + // if there are notarized meta headers, return last included meta header + if numIncludedMetaBlocks > 0 { + lastReferencedMetaHash = currentHdr.GetMetaBlockHashes()[numIncludedMetaBlocks-1] + break + } + + // if there are no included meta blocks, go to prev header + header, err := fetchPrevHeader(syncedHeaders, currentHdr) + if err != nil { + return nil, err + } + + currentHdr = header + } + + return lastReferencedMetaHash, nil +} + +func (e *epochStartBootstrap) syncPrevShardHeaderHandler( + syncedHeaders map[string]data.HeaderHandler, + header data.HeaderHandler, +) (data.ShardHeaderHandler, error) { + prevHash := header.GetPrevHash() + syncedHeader, err := e.syncOneHeader(prevHash, header.GetShardID()) + if err != nil { + return nil, err + } + syncedHeaders[string(prevHash)] = syncedHeader + + shardHeader, ok := syncedHeader.(data.ShardHeaderHandler) + if !ok { + return nil, epochStart.ErrWrongTypeAssertion + } + + return shardHeader, nil +} + func (e *epochStartBootstrap) syncEpochStartMetaHeaders( meta data.MetaHeaderHandler, hashesToRequest [][]byte, shardIds []uint32, ) (map[string]data.HeaderHandler, error) { - if meta.GetEpoch() > e.startEpoch+1 { // no need to request genesis block - hashesToRequest = append(hashesToRequest, meta.GetEpochStartHandler().GetEconomicsHandler().GetPrevEpochStartHash()) - shardIds = append(shardIds, core.MetachainShardId) - } - epochStartMetaHash, err := core.CalculateHash(e.coreComponentsHolder.InternalMarshalizer(), e.coreComponentsHolder.Hasher(), meta) if err != nil { return nil, err @@ -732,6 +886,19 @@ func (e *epochStartBootstrap) syncEpochStartMetaHeaders( hashesToRequest = append(hashesToRequest, epochStartMetaHash) shardIds = append(shardIds, core.MetachainShardId) + // sync meta header with intermediate blocks up to last executed (for supernova) + syncedHeaders := make(map[string]data.HeaderHandler) + err = e.syncBlocksUpToLastExecuted(syncedHeaders, meta, core.MetachainShardId) + if err != nil { + return nil, err + } + + // sync also the other meta related headers, as before supernova + if meta.GetEpoch() > e.startEpoch+1 { // no need to request genesis block + hashesToRequest = append(hashesToRequest, meta.GetEpochStartHandler().GetEconomicsHandler().GetPrevEpochStartHash()) + shardIds = append(shardIds, core.MetachainShardId) + } + ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeToWaitForRequestedData) err = e.headersSyncer.SyncMissingHeadersByHash(shardIds, hashesToRequest, ctx) cancel() @@ -739,7 +906,7 @@ func (e *epochStartBootstrap) syncEpochStartMetaHeaders( return nil, err } - syncedHeaders, err := e.headersSyncer.GetHeaders() + syncedHeaders, err = e.headersSyncer.GetHeaders() if err != nil { return nil, err } @@ -772,17 +939,11 @@ func (e *epochStartBootstrap) syncHeadersFrom(meta data.MetaHeaderHandler) (map[ return syncedHeaders, nil } -func (e *epochStartBootstrap) requestIntermediateBlocksIfNeeded( +func (e *epochStartBootstrap) syncBlocksUpToLastExecuted( syncedHeaders map[string]data.HeaderHandler, - headerHash []byte, + header data.HeaderHandler, shardID uint32, ) error { - header, err := e.syncOneHeader(headerHash, shardID) - if err != nil { - return err - } - syncedHeaders[string(headerHash)] = header - if !header.IsHeaderV3() { return nil } @@ -792,28 +953,7 @@ func (e *epochStartBootstrap) requestIntermediateBlocksIfNeeded( 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 + return e.syncIntermediateBlocksIfNeeded(syncedHeaders, header, lastExecutionResult.GetHeaderNonce()) } func (e *epochStartBootstrap) syncOneHeader( diff --git a/epochStart/bootstrap/process_test.go b/epochStart/bootstrap/process_test.go index 8a6ac7d7871..b839ad9ec92 100644 --- a/epochStart/bootstrap/process_test.go +++ b/epochStart/bootstrap/process_test.go @@ -2603,54 +2603,6 @@ func TestSyncSetGuardianTransaction(t *testing.T) { func TestEpochStartBoostrap_SyncHeadersV3FromMeta(t *testing.T) { t.Parallel() - t.Run("should return early if last executed nonce equal to current nonce", func(t *testing.T) { - t.Parallel() - - hdrHash1 := []byte("hdrHash1") - hdrHash2 := []byte("hdrHash2") - - header1 := &block.HeaderV3{ - Nonce: 11, - PrevHash: hdrHash2, - LastExecutionResult: &block.ExecutionResultInfo{ - ExecutionResult: &block.BaseExecutionResult{ - HeaderNonce: 11, - }, - }, - } - - coreComp, cryptoComp := createComponentsForEpochStart() - args := createMockEpochStartBootstrapArgs(coreComp, cryptoComp) - - epochStartProvider, _ := NewEpochStartBootstrap(args) - epochStartProvider.headersSyncer = &epochStartMocks.HeadersByHashSyncerStub{ - SyncMissingHeadersByHashCalled: func(shardIDs []uint32, headersHashes [][]byte, ctx context.Context) error { - return nil - }, - GetHeadersCalled: func() (m map[string]data.HeaderHandler, err error) { - return map[string]data.HeaderHandler{ - string(hdrHash1): header1, - }, nil - }, - } - - metaBlock := &block.MetaBlockV3{ - Epoch: 2, - EpochStart: block.EpochStart{ - LastFinalizedHeaders: []block.EpochStartShardData{ - {HeaderHash: hdrHash1, ShardID: 0}, - }, - Economics: block.Economics{ - PrevEpochStartHash: hdrHash2, - }, - }, - } - - headers, err := epochStartProvider.syncHeadersFrom(metaBlock) - require.Nil(t, err) - require.Equal(t, 1, len(headers)) - }) - t.Run("should error if requested header not in returned headers", func(t *testing.T) { t.Parallel() @@ -2823,6 +2775,11 @@ func TestEpochStartBoostrap_SyncHeadersV3FromMeta(t *testing.T) { PrevEpochStartHash: hdrHash2, }, }, + LastExecutionResult: &block.MetaExecutionResultInfo{ + ExecutionResult: &block.BaseMetaExecutionResult{ + BaseExecutionResult: &block.BaseExecutionResult{}, + }, + }, } headers, err := epochStartProvider.syncHeadersFrom(metaBlock) @@ -2835,12 +2792,22 @@ func TestEpochStartBoostrap_SyncHeadersV3FromMeta(t *testing.T) { hdrHash1 := []byte("hdrHash1") hdrHash2 := []byte("hdrHash2") + lastExecMetaHash := []byte("lastExecMetaHash") header1 := &block.Header{ Nonce: 11, PrevHash: hdrHash2, } + lastExecMeta := &block.MetaBlockV3{ + Nonce: 20, + LastExecutionResult: &block.MetaExecutionResultInfo{ + ExecutionResult: &block.BaseMetaExecutionResult{ + BaseExecutionResult: &block.BaseExecutionResult{}, + }, + }, + } + coreComp, cryptoComp := createComponentsForEpochStart() args := createMockEpochStartBootstrapArgs(coreComp, cryptoComp) @@ -2851,26 +2818,41 @@ func TestEpochStartBoostrap_SyncHeadersV3FromMeta(t *testing.T) { }, GetHeadersCalled: func() (m map[string]data.HeaderHandler, err error) { return map[string]data.HeaderHandler{ - string(hdrHash1): header1, + string(hdrHash1): header1, + string(lastExecMetaHash): lastExecMeta, }, nil }, } metaBlock := &block.MetaBlockV3{ - Epoch: 2, + Epoch: 2, + Nonce: 21, + PrevHash: lastExecMetaHash, EpochStart: block.EpochStart{ LastFinalizedHeaders: []block.EpochStartShardData{ - {HeaderHash: hdrHash1, ShardID: 0}, + { + HeaderHash: hdrHash1, + ShardID: 0, + LastFinishedMetaBlock: lastExecMetaHash, + }, }, Economics: block.Economics{ PrevEpochStartHash: hdrHash2, }, }, + LastExecutionResult: &block.MetaExecutionResultInfo{ + ExecutionResult: &block.BaseMetaExecutionResult{ + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderNonce: 20, + HeaderHash: lastExecMetaHash, + }, + }, + }, } headers, err := epochStartProvider.syncHeadersFrom(metaBlock) require.Nil(t, err) - require.Equal(t, 1, len(headers)) + require.Equal(t, 2, len(headers)) }) t.Run("should work with meta v3 and shard v3", func(t *testing.T) { @@ -2878,19 +2860,45 @@ func TestEpochStartBoostrap_SyncHeadersV3FromMeta(t *testing.T) { hdrHash1 := []byte("hdrHash1") hdrHash2 := []byte("hdrHash2") + hdrHash3 := []byte("hdrHash3") + hdrHash4 := []byte("hdrHash4") + lastExecMetaHash := []byte("lastExecMetaHash") header1 := &block.HeaderV3{ - Nonce: 11, + Nonce: 12, PrevHash: hdrHash2, LastExecutionResult: &block.ExecutionResultInfo{ ExecutionResult: &block.BaseExecutionResult{ HeaderNonce: 10, + HeaderHash: hdrHash3, }, }, } header2 := &block.HeaderV3{ + Nonce: 11, + PrevHash: hdrHash3, + LastExecutionResult: &block.ExecutionResultInfo{}, + } + header3 := &block.HeaderV3{ Nonce: 10, LastExecutionResult: &block.ExecutionResultInfo{}, + MetaBlockHashes: [][]byte{hdrHash4, lastExecMetaHash}, + } + + lastExecMeta := &block.MetaBlockV3{ + Nonce: 20, + PrevHash: hdrHash4, + LastExecutionResult: &block.MetaExecutionResultInfo{ + ExecutionResult: &block.BaseMetaExecutionResult{ + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderNonce: 19, + }, + }, + }, + } + + metaHeader4 := &block.MetaBlockV3{ + Nonce: 19, } coreComp, cryptoComp := createComponentsForEpochStart() @@ -2903,27 +2911,44 @@ func TestEpochStartBoostrap_SyncHeadersV3FromMeta(t *testing.T) { }, GetHeadersCalled: func() (m map[string]data.HeaderHandler, err error) { return map[string]data.HeaderHandler{ - string(hdrHash1): header1, - string(hdrHash2): header2, + string(hdrHash1): header1, + string(hdrHash2): header2, + string(hdrHash3): header3, + string(hdrHash4): metaHeader4, + string(lastExecMetaHash): lastExecMeta, }, nil }, } metaBlock := &block.MetaBlockV3{ - Epoch: 2, + Epoch: 2, + Nonce: 21, + PrevHash: lastExecMetaHash, EpochStart: block.EpochStart{ LastFinalizedHeaders: []block.EpochStartShardData{ - {HeaderHash: hdrHash1, ShardID: 0}, + { + HeaderHash: hdrHash1, + ShardID: 0, + LastFinishedMetaBlock: lastExecMetaHash, + }, }, Economics: block.Economics{ PrevEpochStartHash: hdrHash2, }, }, + LastExecutionResult: &block.MetaExecutionResultInfo{ + ExecutionResult: &block.BaseMetaExecutionResult{ + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderHash: lastExecMetaHash, + HeaderNonce: 20, + }, + }, + }, } headers, err := epochStartProvider.syncHeadersFrom(metaBlock) require.Nil(t, err) - require.Equal(t, 2, len(headers)) + require.Equal(t, 5, len(headers)) }) } diff --git a/epochStart/bootstrap/shardStorageHandler.go b/epochStart/bootstrap/shardStorageHandler.go index a15ff743f16..f2af348ad89 100644 --- a/epochStart/bootstrap/shardStorageHandler.go +++ b/epochStart/bootstrap/shardStorageHandler.go @@ -183,9 +183,8 @@ func (ssh *shardStorageHandler) saveEpochStartMetaHdrs(components *ComponentsNee func (ssh *shardStorageHandler) saveEpochStartShardHdrs(components *ComponentsNeededForBootstrap) error { for _, hdr := range components.Headers { - if !hdr.IsStartOfEpochBlock() { - continue - } + // not only start of epoch header should be saved at this point, we should save + // also intermediate headers up to last executed header isForCurrentShard := hdr.GetShardID() == ssh.shardCoordinator.SelfId() if !isForCurrentShard { diff --git a/epochStart/bootstrap/startInEpochScheduled.go b/epochStart/bootstrap/startInEpochScheduled.go index 265cf4dcc72..4454bb96206 100644 --- a/epochStart/bootstrap/startInEpochScheduled.go +++ b/epochStart/bootstrap/startInEpochScheduled.go @@ -90,6 +90,9 @@ func (ses *startInEpochWithScheduledDataSyncer) IsInterfaceNil() bool { func (ses *startInEpochWithScheduledDataSyncer) getRequiredHeaderByHash( notarizedShardHeader data.ShardHeaderHandler, ) (data.ShardHeaderHandler, map[string]data.HeaderHandler, error) { + // TODO: analyze the requested headers in this func, after andromeda committed blocks are final + // it might not be needed to request based on prev header + shardIDs, hashesToRequest := getShardIDAndHashesForIncludedMetaBlocks(notarizedShardHeader) shardIDs = append(shardIDs, notarizedShardHeader.GetShardID()) @@ -145,6 +148,10 @@ func (ses *startInEpochWithScheduledDataSyncer) getRequiredHeaderByHash( } } + if notarizedShardHeader.IsHeaderV3() { + headerToBeProcessed = notarizedShardHeader + } + return headerToBeProcessed, headers, nil } diff --git a/process/asyncExecution/executionManager/executionManager.go b/process/asyncExecution/executionManager/executionManager.go index 35e62d35330..166c94884eb 100644 --- a/process/asyncExecution/executionManager/executionManager.go +++ b/process/asyncExecution/executionManager/executionManager.go @@ -142,7 +142,8 @@ func (em *executionManager) updateContextForReplacedHeader(header data.HeaderHan return err } - headerToSet, err := em.headers.GetHeaderByHash(executionResultToSet.GetHeaderHash()) + // TODO: optimize to add into pool at bootstrap + headerToSet, err := em.getHeaderFromPoolOrStorage(executionResultToSet.GetHeaderHash()) if err != nil { return err } diff --git a/process/asyncExecution/executionManager/executionManager_test.go b/process/asyncExecution/executionManager/executionManager_test.go index 67f6070f384..16b959d1f7e 100644 --- a/process/asyncExecution/executionManager/executionManager_test.go +++ b/process/asyncExecution/executionManager/executionManager_test.go @@ -342,7 +342,16 @@ func TestExecutionManager_AddPairForExecution(t *testing.T) { args.Headers = &pool.HeadersPoolStub{ GetHeaderByHashCalled: func(hash []byte) (data.HeaderHandler, error) { - return nil, errExpected + return nil, errors.New("fetch error") + }, + } + args.StorageService = &storageStubs.ChainStorerStub{ + GetStorerCalled: func(unitType dataRetriever.UnitType) (storage.Storer, error) { + return &storageStubs.StorerStub{ + GetCalled: func(key []byte) ([]byte, error) { + return nil, errExpected + }, + }, nil }, } @@ -357,7 +366,7 @@ func TestExecutionManager_AddPairForExecution(t *testing.T) { } err := em.AddPairForExecution(pair) - require.Equal(t, errExpected, err) + require.ErrorIs(t, err, process.ErrMissingHeader) require.Equal(t, 0, counter) }) diff --git a/process/block/baseProcess.go b/process/block/baseProcess.go index 266408764bd..39d6c7593fd 100644 --- a/process/block/baseProcess.go +++ b/process/block/baseProcess.go @@ -3764,6 +3764,23 @@ func (bp *baseProcessor) getBlockBodyFromPool( return &block.Body{MiniBlocks: miniBlocks}, nil } +func (bp *baseProcessor) getHeaderFromHash( + isHeaderV3 bool, + headerHash []byte, + shardID uint32, +) (data.HeaderHandler, error) { + if isHeaderV3 { + return process.GetHeader(headerHash, bp.dataPool.Headers(), bp.store, bp.marshalizer, shardID) + } + + headerInfo, ok := bp.hdrsForCurrBlock.GetHeaderInfo(string(headerHash)) + if !ok { + return nil, process.ErrMissingHeader + } + + return headerInfo.GetHeader(), nil +} + func getProposedAndExecutedMiniBlockHeaders( header data.HeaderHandler, ) ([]data.MiniBlockHeaderHandler, error) { diff --git a/process/block/common.go b/process/block/common.go deleted file mode 100644 index cae507a8961..00000000000 --- a/process/block/common.go +++ /dev/null @@ -1,31 +0,0 @@ -package block - -import ( - "github.com/multiversx/mx-chain-core-go/data" - - "github.com/multiversx/mx-chain-go/dataRetriever" - "github.com/multiversx/mx-chain-go/process" -) - -func getHeaderFromHash( - headersPool dataRetriever.HeadersPool, - hdrsForCurrBlock HeadersForBlock, - isHeaderV3 bool, - headerHash []byte, -) (data.HeaderHandler, error) { - if isHeaderV3 { - header, err := headersPool.GetHeaderByHash(headerHash) - // TODO: debug only, remove after test - if err != nil { - log.Error("getHeaderFromHash - failed to get header from headers pool", "hash", headerHash, "error", err) - } - return header, err - } - - headerInfo, ok := hdrsForCurrBlock.GetHeaderInfo(string(headerHash)) - if !ok { - return nil, process.ErrMissingHeader - } - - return headerInfo.GetHeader(), nil -} diff --git a/process/block/metablock.go b/process/block/metablock.go index d8823883aec..ac65fefee02 100644 --- a/process/block/metablock.go +++ b/process/block/metablock.go @@ -496,7 +496,7 @@ func (mp *metaProcessor) getAllMiniBlockDstMeFromShards(metaHdr data.MetaHeaderH var shardHeaderHandler data.HeaderHandler var err error for _, shardInfo := range getShardHeadersReferencedByMeta(metaHdr) { - shardHeaderHandler, err = getHeaderFromHash(mp.dataPool.Headers(), mp.hdrsForCurrBlock, metaHdr.IsHeaderV3(), shardInfo.GetHeaderHash()) + shardHeaderHandler, err = mp.getHeaderFromHash(metaHdr.IsHeaderV3(), shardInfo.GetHeaderHash(), shardInfo.GetShardID()) if err != nil { return nil, fmt.Errorf("%w : for shardInfo.HeaderHash = %s", process.ErrMissingHeader, hex.EncodeToString(shardInfo.GetHeaderHash())) @@ -1487,7 +1487,7 @@ func (mp *metaProcessor) computeFinalMetaBlock(metaBlock data.MetaHeaderHandler, func (mp *metaProcessor) updateCrossShardInfo(metaHeader data.MetaHeaderHandler) ([]string, error) { notarizedHeadersHashes := make([]string, 0) for _, shardData := range getShardHeadersReferencedByMeta(metaHeader) { - header, err := getHeaderFromHash(mp.dataPool.Headers(), mp.hdrsForCurrBlock, metaHeader.IsHeaderV3(), shardData.GetHeaderHash()) + header, err := mp.getHeaderFromHash(metaHeader.IsHeaderV3(), shardData.GetHeaderHash(), shardData.GetShardID()) if err != nil { return nil, fmt.Errorf("%w : updateCrossShardInfo shardHeaderHash = %s", err, logger.DisplayByteSlice(shardData.GetHeaderHash())) @@ -1751,7 +1751,7 @@ func (mp *metaProcessor) getLastSelfNotarizedHeaderByShard( continue } - header, err := getHeaderFromHash(mp.dataPool.Headers(), mp.hdrsForCurrBlock, metaHeader.IsHeaderV3(), shardData.GetHeaderHash()) + header, err := mp.getHeaderFromHash(metaHeader.IsHeaderV3(), shardData.GetHeaderHash(), shardData.GetShardID()) if err != nil { log.Debug("getLastSelfNotarizedHeaderByShard", "error", err.Error(), @@ -1962,7 +1962,7 @@ func (mp *metaProcessor) saveLastNotarizedHeader(metaHeader data.MetaHeaderHandl } for _, shardData := range getShardHeadersReferencedByMeta(metaHeader) { - header, err := getHeaderFromHash(mp.dataPool.Headers(), mp.hdrsForCurrBlock, metaHeader.IsHeaderV3(), shardData.GetHeaderHash()) + header, err := mp.getHeaderFromHash(metaHeader.IsHeaderV3(), shardData.GetHeaderHash(), shardData.GetShardID()) if err != nil { return fmt.Errorf("%w : saveLastNotarizedHeader shardHeaderHash = %s", err, logger.DisplayByteSlice(shardData.GetHeaderHash())) diff --git a/process/block/shardblock.go b/process/block/shardblock.go index 19475738798..3d9343863e0 100644 --- a/process/block/shardblock.go +++ b/process/block/shardblock.go @@ -1428,7 +1428,7 @@ func (sp *shardProcessor) snapShotEpochStartFromMeta(header data.ShardHeaderHand accounts := sp.accountsDB[state.UserAccountsState] for _, metaHash := range header.GetMetaBlockHashes() { - hdr, err := getHeaderFromHash(sp.dataPool.Headers(), sp.hdrsForCurrBlock, header.IsHeaderV3(), metaHash) + hdr, err := sp.getHeaderFromHash(header.IsHeaderV3(), metaHash, core.MetachainShardId) if err != nil { continue } @@ -1782,7 +1782,7 @@ func (sp *shardProcessor) addProcessedCrossMiniBlocksFromHeader(headerHandler da } for _, metaBlockHash := range shardHeader.GetMetaBlockHashes() { - hdr, err := getHeaderFromHash(sp.dataPool.Headers(), sp.hdrsForCurrBlock, shardHeader.IsHeaderV3(), metaBlockHash) + hdr, err := sp.getHeaderFromHash(shardHeader.IsHeaderV3(), metaBlockHash, core.MetachainShardId) if err != nil { return fmt.Errorf("%w : addProcessedCrossMiniBlocksFromHeader metaBlockHash = %s", err, logger.DisplayByteSlice(metaBlockHash)) diff --git a/process/sync/baseSync.go b/process/sync/baseSync.go index 153cf2f6558..949fee5e320 100644 --- a/process/sync/baseSync.go +++ b/process/sync/baseSync.go @@ -1092,7 +1092,7 @@ func (boot *baseBootstrap) prepareForSyncIfNeeded(syncingNonce uint64) error { // if there are multiple headers in between the syncing header and the last one executed, // add them into the queue and pool for i := lastExecutionResultHeaderNonce + 1; i < syncingNonce; i++ { - hdr, hdrHash, errGetHdr := boot.getHeaderFromPoolWithNonce(i) + hdr, hdrHash, errGetHdr := boot.getHeaderWithNonce(i) if errGetHdr != nil { log.Debug("prepareForSyncIfNeeded: failed to get header with nonce", "nonce", i, "error", errGetHdr) return errGetHdr @@ -1789,6 +1789,7 @@ func (boot *baseBootstrap) getHeader(hash []byte) (data.HeaderHandler, error) { return process.GetShardHeader(hash, boot.headers, boot.marshalizer, boot.store) } +// getHeaderFromPool will try to get the header from pool func (boot *baseBootstrap) getHeaderFromPool(hash []byte) (data.HeaderHandler, error) { if boot.shardCoordinator.SelfId() == core.MetachainShardId { return process.GetMetaHeaderFromPool(hash, boot.headers) @@ -1797,6 +1798,49 @@ func (boot *baseBootstrap) getHeaderFromPool(hash []byte) (data.HeaderHandler, e return process.GetShardHeaderFromPool(hash, boot.headers) } +func (boot *baseBootstrap) getHeaderWithNonce( + nonce uint64, +) (data.HeaderHandler, []byte, error) { + if boot.shardCoordinator.SelfId() == core.MetachainShardId { + return boot.getMetaHeaderWithNonce(nonce) + } + + return boot.getShardHeaderWithNonce(nonce) +} + +func (boot *baseBootstrap) getMetaHeaderWithNonce( + nonce uint64, +) (data.HeaderHandler, []byte, error) { + header, hash, err := process.GetMetaHeaderFromPoolWithNonce(nonce, boot.headers) + if err == nil { + return header, hash, nil + } + + return process.GetMetaHeaderFromStorageWithNonce( + nonce, + boot.store, + boot.uint64Converter, + boot.marshalizer, + ) +} + +func (boot *baseBootstrap) getShardHeaderWithNonce( + nonce uint64, +) (data.HeaderHandler, []byte, error) { + header, hash, err := process.GetShardHeaderFromPoolWithNonce(nonce, boot.shardCoordinator.SelfId(), boot.headers) + if err == nil { + return header, hash, nil + } + + return process.GetShardHeaderFromStorageWithNonce( + nonce, + boot.shardCoordinator.SelfId(), + boot.store, + boot.uint64Converter, + boot.marshalizer, + ) +} + func (boot *baseBootstrap) getHeaderFromPoolWithNonce( nonce uint64, ) (data.HeaderHandler, []byte, error) { diff --git a/process/sync/storageBootstrap/metaStorageBootstrapper.go b/process/sync/storageBootstrap/metaStorageBootstrapper.go index 328d6f5023b..64dc475562b 100644 --- a/process/sync/storageBootstrap/metaStorageBootstrapper.go +++ b/process/sync/storageBootstrap/metaStorageBootstrapper.go @@ -160,7 +160,6 @@ func (msb *metaStorageBootstrapper) cleanupNotarizedStorageForHigherNoncesIfExis func (msb *metaStorageBootstrapper) applySelfNotarizedHeaders( bootstrapHeadersInfo []bootstrapStorage.BootstrapHeaderInfo, ) ([]data.HeaderHandler, [][]byte, error) { - for _, bootstrapHeaderInfo := range bootstrapHeadersInfo { selfNotarizedHeader, err := msb.getHeader(bootstrapHeaderInfo.Hash) if err != nil {