Skip to content

Commit

Permalink
Merge pull request #6552 from multiversx/MX-15948-bootstrap-cross-cha…
Browse files Browse the repository at this point in the history
…in-header

[sovereign] Save last cross chain notarized headers + bootstrap
  • Loading branch information
mariusmihaic authored Oct 28, 2024
2 parents ae64696 + 3b7ebfa commit 1549191
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 49 deletions.
23 changes: 20 additions & 3 deletions epochStart/bootstrap/bootStrapSovereignShardProcessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/multiversx/mx-chain-go/epochStart/bootstrap/disabled"
bootStrapFactory "github.com/multiversx/mx-chain-go/epochStart/bootstrap/factory"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/process/block/sovereign/incomingHeader"
"github.com/multiversx/mx-chain-go/process/factory/interceptorscontainer"
"github.com/multiversx/mx-chain-go/sharding/nodesCoordinator"
"github.com/multiversx/mx-chain-go/storage/cache"
Expand Down Expand Up @@ -158,8 +159,14 @@ func (sbp *sovereignBootStrapShardProcessor) baseSyncHeaders(
meta data.MetaHeaderHandler,
timeToWaitForRequestedData time.Duration,
) (map[string]data.HeaderHandler, error) {
hashesToRequest := make([][]byte, 0, 1)
shardIds := make([]uint32, 0, 1)
hashesToRequest := make([][]byte, 0, 2)
shardIds := make([]uint32, 0, 2)

for _, epochStartData := range meta.GetEpochStartHandler().GetLastFinalizedHeaderHandlers() {
hashesToRequest = append(hashesToRequest, epochStartData.GetHeaderHash())
shardIds = append(shardIds, epochStartData.GetShardID())
}

if meta.GetEpoch() > sbp.startEpoch+1 { // no need to request genesis block
hashesToRequest = append(hashesToRequest, meta.GetEpochStartHandler().GetEconomicsHandler().GetPrevEpochStartHash())
shardIds = append(shardIds, core.SovereignChainShardId)
Expand Down Expand Up @@ -259,9 +266,19 @@ func (sbp *sovereignBootStrapShardProcessor) createEpochStartInterceptorsContain
return nil, nil, err
}

incomingHeaderProcessor, err := incomingHeader.CreateIncomingHeaderProcessor(
sbp.generalConfig.SovereignConfig.NotifierConfig.WebSocketConfig,
sbp.dataPool,
sbp.generalConfig.SovereignConfig.MainChainNotarization.MainChainNotarizationStartRound,
sbp.runTypeComponents,
)
if err != nil {
return nil, nil, err
}

interceptorsContainerFactory, err := interceptorscontainer.NewSovereignShardInterceptorsContainerFactory(interceptorscontainer.ArgsSovereignShardInterceptorsContainerFactory{
ShardContainer: sp,
IncomingHeaderSubscriber: disabled.NewIncomingHeaderSubscriber(),
IncomingHeaderSubscriber: incomingHeaderProcessor,
})
if err != nil {
return nil, nil, err
Expand Down
11 changes: 9 additions & 2 deletions epochStart/bootstrap/bootStrapSovereignShardProcessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func TestBootStrapSovereignShardProcessor_syncHeadersFrom(t *testing.T) {
sovProc := createSovBootStrapProc()

prevEpochStartHash := []byte("prevEpochStartHash")
lastCrossChainHeaderHash := []byte("lastCrossChainHeaderHash")
sovHdr := &block.SovereignChainHeader{
Header: &block.Header{
Epoch: 4,
Expand All @@ -131,6 +132,10 @@ func TestBootStrapSovereignShardProcessor_syncHeadersFrom(t *testing.T) {
Economics: block.Economics{
PrevEpochStartHash: prevEpochStartHash,
},
LastFinalizedCrossChainHeader: block.EpochStartCrossChainData{
ShardID: core.MainChainShardId,
HeaderHash: lastCrossChainHeaderHash,
},
},
}

Expand All @@ -140,8 +145,8 @@ func TestBootStrapSovereignShardProcessor_syncHeadersFrom(t *testing.T) {
headersSyncedCt := 0
sovProc.headersSyncer = &epochStartMocks.HeadersByHashSyncerStub{
SyncMissingHeadersByHashCalled: func(shardIDs []uint32, headersHashes [][]byte, ctx context.Context) error {
require.Equal(t, []uint32{core.SovereignChainShardId}, shardIDs)
require.Equal(t, [][]byte{prevEpochStartHash}, headersHashes)
require.Equal(t, []uint32{core.MainChainShardId, core.SovereignChainShardId}, shardIDs)
require.Equal(t, [][]byte{lastCrossChainHeaderHash, prevEpochStartHash}, headersHashes)
headersSyncedCt++
return nil
},
Expand Down Expand Up @@ -242,6 +247,8 @@ func TestBootStrapSovereignShardProcessor_createEpochStartInterceptorsContainers
t.Parallel()

sovProc := createSovBootStrapProc()
sovProc.dataPool = dataRetrieverMock.NewPoolsHolderMock()

args := factoryInterceptors.ArgsEpochStartInterceptorContainer{
CoreComponents: sovProc.coreComponentsHolder,
CryptoComponents: sovProc.cryptoComponentsHolder,
Expand Down
30 changes: 0 additions & 30 deletions epochStart/bootstrap/disabled/incomingHeaderSubscriber.go

This file was deleted.

5 changes: 5 additions & 0 deletions epochStart/bootstrap/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import (
"time"

"github.com/multiversx/mx-chain-go/dataRetriever"
sovereignBlock "github.com/multiversx/mx-chain-go/dataRetriever/dataPool/sovereign"
requesterscontainer "github.com/multiversx/mx-chain-go/dataRetriever/factory/requestersContainer"
storageRequestFactory "github.com/multiversx/mx-chain-go/dataRetriever/factory/storageRequestersContainer/factory"
"github.com/multiversx/mx-chain-go/dataRetriever/requestHandlers"
"github.com/multiversx/mx-chain-go/epochStart"
bootStrapFactory "github.com/multiversx/mx-chain-go/epochStart/bootstrap/factory"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/process/block/sovereign"
"github.com/multiversx/mx-chain-go/sharding"
"github.com/multiversx/mx-chain-go/sharding/nodesCoordinator"
syncerFactory "github.com/multiversx/mx-chain-go/state/syncer/factory"
Expand Down Expand Up @@ -92,6 +94,9 @@ type RunTypeComponentsHolder interface {
RequestersContainerFactoryCreator() requesterscontainer.RequesterContainerFactoryCreator
ValidatorAccountsSyncerFactoryHandler() syncerFactory.ValidatorAccountsSyncerFactoryHandler
ShardRequestersContainerCreatorHandler() storageRequestFactory.ShardRequestersContainerCreatorHandler
OutGoingOperationsPoolHandler() sovereignBlock.OutGoingOperationsPool
DataCodecHandler() sovereign.DataCodecHandler
TopicsCheckerHandler() sovereign.TopicsCheckerHandler
IsInterfaceNil() bool
}

Expand Down
84 changes: 83 additions & 1 deletion epochStart/bootstrap/shardSovereignStorageHandler.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package bootstrap

import (
"encoding/hex"
"errors"
"fmt"

"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/data"
"github.com/multiversx/mx-chain-core-go/data/block"
"github.com/multiversx/mx-chain-go/dataRetriever"
"github.com/multiversx/mx-chain-go/epochStart"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/process/block/bootstrapStorage"
)
Expand Down Expand Up @@ -50,9 +53,14 @@ func (ssh *sovereignShardStorageHandler) SaveDataToStorage(components *Component
return err
}

lastCrossNotarizedHeaders, err := ssh.saveLastCrossChainNotarizedHeaders(components.EpochStartMetaBlock, components.Headers)
if err != nil {
return err
}

bootStrapData := bootstrapStorage.BootstrapData{
LastHeader: lastHeader,
LastCrossNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{},
LastCrossNotarizedHeaders: lastCrossNotarizedHeaders,
LastSelfNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{lastHeader},
ProcessedMiniBlocks: []bootstrapStorage.MiniBlocksInMeta{},
PendingMiniBlocks: []bootstrapStorage.PendingMiniBlocksInfo{},
Expand Down Expand Up @@ -88,3 +96,77 @@ func (ssh *sovereignShardStorageHandler) saveTriggerRegistry(components *Compone

return ssh.baseSaveTriggerRegistry(&triggerReg, sovHeader.GetRound())
}

func (ssh *sovereignShardStorageHandler) saveLastCrossChainNotarizedHeaders(
sovBlock data.MetaHeaderHandler,
headers map[string]data.HeaderHandler,
) ([]bootstrapStorage.BootstrapHeaderInfo, error) {
log.Debug("sovereignShardStorageHandler.saveLastCrossChainNotarizedHeaders")

lastCrossChainNotarizedData, err := getEpochStartShardData(sovBlock, core.MainChainShardId)
if errors.Is(err, epochStart.ErrEpochStartDataForShardNotFound) {
log.Debug("no cross chain header has been notarized yet")
return []bootstrapStorage.BootstrapHeaderInfo{}, nil
} else if err != nil {
return nil, err
}

lastCrossChainHeaderHash := lastCrossChainNotarizedData.GetHeaderHash()
log.Debug("sovereignShardStorageHandler.saveLastCrossChainNotarizedHeaders",
"hash", lastCrossChainHeaderHash,
)

neededHdr, ok := headers[string(lastCrossChainHeaderHash)]
if !ok {
return nil, fmt.Errorf("%w in sovereignShardStorageHandler.saveLastCrossChainNotarizedHeaders: hash: %s",
epochStart.ErrMissingHeader,
hex.EncodeToString(lastCrossChainHeaderHash))
}

extendedShardHeader, ok := neededHdr.(data.ShardHeaderExtendedHandler)
if !ok {
return nil, fmt.Errorf("%w in sovereignShardStorageHandler.saveLastCrossChainNotarizedHeaders for extended shard header",
epochStart.ErrWrongTypeAssertion,
)
}

err = ssh.saveExtendedHeaderToStorage(extendedShardHeader, lastCrossChainHeaderHash)
if err != nil {
return nil, err
}

crossNotarizedHeaders := make([]bootstrapStorage.BootstrapHeaderInfo, 0)
crossNotarizedHeaders = append(crossNotarizedHeaders, bootstrapStorage.BootstrapHeaderInfo{
ShardId: core.MainChainShardId,
Nonce: lastCrossChainNotarizedData.GetNonce(),
Hash: lastCrossChainHeaderHash,
Epoch: lastCrossChainNotarizedData.GetEpoch(),
})

return crossNotarizedHeaders, nil
}

func (bsh *sovereignShardStorageHandler) saveExtendedHeaderToStorage(extendedShardHeader data.HeaderHandler, headerHash []byte) error {
headerBytes, err := bsh.marshalizer.Marshal(extendedShardHeader)
if err != nil {
return err
}

extendedHdrStorer, err := bsh.storageService.GetStorer(dataRetriever.ExtendedShardHeadersUnit)
if err != nil {
return err
}

err = extendedHdrStorer.Put(headerHash, headerBytes)
if err != nil {
return err
}

nonceToByteSlice := bsh.uint64Converter.ToByteSlice(extendedShardHeader.GetNonce())
extendedHdrNonceStorage, err := bsh.storageService.GetStorer(dataRetriever.ExtendedShardHeadersNonceHashDataUnit)
if err != nil {
return err
}

return extendedHdrNonceStorage.Put(nonceToByteSlice, headerHash)
}
118 changes: 113 additions & 5 deletions epochStart/bootstrap/shardSovereignStorageHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/multiversx/mx-chain-go/process/block/bootstrapStorage"
"github.com/multiversx/mx-chain-go/sharding/nodesCoordinator"
"github.com/multiversx/mx-chain-go/storage"
"github.com/multiversx/mx-chain-go/storage/factory"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -83,20 +84,20 @@ func TestSovereignShardStorageHandler_SaveDataToStorage(t *testing.T) {
bootStrapData := getStoredBootstrapData(t, sovShardStorage.marshalizer, bootStorer, hdr1.GetRound())
require.Equal(t, &bootstrapStorage.BootstrapData{
LastHeader: bootstrapStorage.BootstrapHeaderInfo{
Nonce: 1,
Epoch: 1,
Nonce: hdr1.GetNonce(),
Epoch: hdr1.GetEpoch(),
Hash: hdrHash,
},
LastCrossNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{},
LastSelfNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{{
Nonce: 1,
Epoch: 1,
Nonce: hdr1.GetNonce(),
Epoch: hdr1.GetEpoch(),
Hash: hdrHash,
}},
ProcessedMiniBlocks: []bootstrapStorage.MiniBlocksInMeta{},
PendingMiniBlocks: []bootstrapStorage.PendingMiniBlocksInfo{},
NodesCoordinatorConfigKey: nil,
EpochStartTriggerConfigKey: []byte(fmt.Sprint(1)),
EpochStartTriggerConfigKey: []byte(fmt.Sprint(hdr1.GetEpoch())),
HighestFinalBlockNonce: hdr1.GetNonce(),
LastRound: 0,
}, bootStrapData)
Expand Down Expand Up @@ -125,3 +126,110 @@ func TestSovereignShardStorageHandler_SaveDataToStorage(t *testing.T) {
_, err = metaStorer.Get([]byte("epochStartBlock_2"))
require.NotNil(t, err)
}

func TestSovereignShardStorageHandler_SaveDataToStorageCheckLastCrossChainNotarizedDataIsSaved(t *testing.T) {
t.Parallel()

args := createStorageHandlerArgs()
args.AdditionalStorageServiceCreator = factory.NewSovereignAdditionalStorageServiceFactory()
shardStorage, _ := NewShardStorageHandler(args)
sovShardStorage := newSovereignShardStorageHandler(shardStorage)

hash1 := []byte("hash1")
lastFinalizedCrossChainHeaderHash := []byte("lastFinalizedCrossChainHeaderHash")
lastFinalizedCrossChainHeader := &block.ShardHeaderExtended{
Header: &block.HeaderV2{
Header: &block.Header{
Epoch: 1,
Round: 4,
Nonce: 4,
},
},
}
sovHdr := &block.SovereignChainHeader{
Header: &block.Header{
Nonce: 2,
Round: 2,
Epoch: 2,
},
EpochStart: block.EpochStartSovereign{
LastFinalizedCrossChainHeader: block.EpochStartCrossChainData{
ShardID: core.MainChainShardId,
Epoch: 1,
Round: 4,
Nonce: 4,
HeaderHash: lastFinalizedCrossChainHeaderHash,
},
},
}
headers := map[string]data.HeaderHandler{
string(hash1): sovHdr,
string(lastFinalizedCrossChainHeaderHash): lastFinalizedCrossChainHeader,
}

components := &ComponentsNeededForBootstrap{
EpochStartMetaBlock: sovHdr,
PreviousEpochStart: sovHdr,
ShardHeader: sovHdr,
Headers: headers,
NodesConfig: &nodesCoordinator.NodesCoordinatorRegistry{},
}

err := sovShardStorage.SaveDataToStorage(components, components.ShardHeader, false, nil)
require.Nil(t, err)

bootStorer, err := sovShardStorage.storageService.GetStorer(dataRetriever.BootstrapUnit)
require.Nil(t, err)

hdrHash, err := core.CalculateHash(sovShardStorage.marshalizer, sovShardStorage.hasher, sovHdr)
require.Nil(t, err)

bootStrapData := getStoredBootstrapData(t, sovShardStorage.marshalizer, bootStorer, sovHdr.GetRound())
require.Equal(t, &bootstrapStorage.BootstrapData{
LastHeader: bootstrapStorage.BootstrapHeaderInfo{
Nonce: sovHdr.GetNonce(),
Epoch: sovHdr.GetEpoch(),
Hash: hdrHash,
},
LastCrossNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{
{
ShardId: core.MainChainShardId,
Epoch: lastFinalizedCrossChainHeader.GetEpoch(),
Nonce: lastFinalizedCrossChainHeader.GetNonce(),
Hash: lastFinalizedCrossChainHeaderHash,
},
},
LastSelfNotarizedHeaders: []bootstrapStorage.BootstrapHeaderInfo{
{
Nonce: sovHdr.GetNonce(),
Epoch: sovHdr.GetEpoch(),
Hash: hdrHash,
},
},
ProcessedMiniBlocks: []bootstrapStorage.MiniBlocksInMeta{},
PendingMiniBlocks: []bootstrapStorage.PendingMiniBlocksInfo{},
NodesCoordinatorConfigKey: nil,
EpochStartTriggerConfigKey: []byte(fmt.Sprint(sovHdr.GetEpoch())),
HighestFinalBlockNonce: sovHdr.GetNonce(),
LastRound: 0,
}, bootStrapData)

extendedHdrStorer, err := sovShardStorage.storageService.GetStorer(dataRetriever.ExtendedShardHeadersUnit)
require.Nil(t, err)

extendedHdrBytes, err := extendedHdrStorer.Get(lastFinalizedCrossChainHeaderHash)
require.Nil(t, err)

extendedHdrStored := &block.ShardHeaderExtended{}
err = sovShardStorage.marshalizer.Unmarshal(extendedHdrStored, extendedHdrBytes)
require.Nil(t, err)
require.Equal(t, lastFinalizedCrossChainHeader, extendedHdrStored)

extendedHdrNonceStorer, err := sovShardStorage.storageService.GetStorer(dataRetriever.ExtendedShardHeadersNonceHashDataUnit)
require.Nil(t, err)

nonceToBytesKey := sovShardStorage.uint64Converter.ToByteSlice(lastFinalizedCrossChainHeader.GetNonce())
extendedHdrNonceBytesHash, err := extendedHdrNonceStorer.Get(nonceToBytesKey)
require.Nil(t, err)
require.Equal(t, lastFinalizedCrossChainHeaderHash, extendedHdrNonceBytesHash)
}
Loading

0 comments on commit 1549191

Please sign in to comment.