diff --git a/consensus/spos/bls/v2/subroundStartRound.go b/consensus/spos/bls/v2/subroundStartRound.go index 17c4a890ecf..e8e20319a0a 100644 --- a/consensus/spos/bls/v2/subroundStartRound.go +++ b/consensus/spos/bls/v2/subroundStartRound.go @@ -265,17 +265,11 @@ func (sr *subroundStartRound) indexRoundIfNeeded(pubKeys []string) { return } - signersIndexes, err := sr.NodesCoordinator().GetValidatorsIndexes(pubKeys, epoch) - if err != nil { - log.Error(err.Error()) - return - } - round := sr.RoundHandler().Index() roundInfo := &outportcore.RoundInfo{ Round: uint64(round), - SignersIndexes: signersIndexes, + SignersIndexes: make([]uint64, 0), BlockWasProposed: false, ShardId: shardId, Epoch: epoch, diff --git a/consensus/spos/bls/v2/subroundStartRound_test.go b/consensus/spos/bls/v2/subroundStartRound_test.go index abcddc258a0..fa6853f0314 100644 --- a/consensus/spos/bls/v2/subroundStartRound_test.go +++ b/consensus/spos/bls/v2/subroundStartRound_test.go @@ -894,7 +894,7 @@ func TestSubroundStartRound_IndexRoundIfNeededFailShardIdForEpoch(t *testing.T) } -func TestSubroundStartRound_IndexRoundIfNeededFailGetValidatorsIndexes(t *testing.T) { +func TestSubroundStartRound_IndexRoundIfNeededGetValidatorsIndexesShouldNotBeCalled(t *testing.T) { pubKeys := []string{"testKey1", "testKey2"} @@ -911,6 +911,7 @@ func TestSubroundStartRound_IndexRoundIfNeededFailGetValidatorsIndexes(t *testin container.SetNodesCoordinator( &shardingMocks.NodesCoordinatorStub{ GetValidatorsIndexesCalled: func(pubKeys []string, epoch uint32) ([]uint64, error) { + require.Fail(t, "SaveRoundsInfo should not be called") return nil, expErr }, }) @@ -925,17 +926,18 @@ func TestSubroundStartRound_IndexRoundIfNeededFailGetValidatorsIndexes(t *testin ) require.Nil(t, err) + called := false _ = startRound.SetOutportHandler(&outport.OutportStub{ HasDriversCalled: func() bool { return true }, SaveRoundsInfoCalled: func(roundsInfo *outportcore.RoundsInfo) { - require.Fail(t, "SaveRoundsInfo should not be called") + called = true }, }) startRound.IndexRoundIfNeeded(pubKeys) - + require.True(t, called) } func TestSubroundStartRound_IndexRoundIfNeededShouldFullyWork(t *testing.T) { diff --git a/go.mod b/go.mod index d9ebcbb5b01..609461716f6 100644 --- a/go.mod +++ b/go.mod @@ -15,9 +15,9 @@ require ( github.com/klauspost/cpuid/v2 v2.2.7 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.2-0.20250307100720-d2d999fc12af - github.com/multiversx/mx-chain-core-go v1.2.25-0.20250219104810-75b7a8ff6bbb + github.com/multiversx/mx-chain-core-go v1.2.25-0.20250311124759-d7677eab18f2 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.17-0.20250219142548-1e626a9520a4 + github.com/multiversx/mx-chain-es-indexer-go v1.7.17-0.20250311085008-58675dd2ea38 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.19 diff --git a/go.sum b/go.sum index c1a00b265e2..fef287dabb7 100644 --- a/go.sum +++ b/go.sum @@ -391,12 +391,12 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.2-0.20250307100720-d2d999fc12af h1:7JoTWjlYtJuid/ndLIDBrEOTkpdII64cm7xuUtHFotA= github.com/multiversx/mx-chain-communication-go v1.1.2-0.20250307100720-d2d999fc12af/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.25-0.20250219104810-75b7a8ff6bbb h1:XoFaZ3/KEaI7N0o1gqiek+2s/PlqmcvwukAT4iCvAIM= -github.com/multiversx/mx-chain-core-go v1.2.25-0.20250219104810-75b7a8ff6bbb/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.25-0.20250311124759-d7677eab18f2 h1:E6ZegEUcWTT/DDfbx2epjjqWOZnAhd/tyX0OsW0wvtQ= +github.com/multiversx/mx-chain-core-go v1.2.25-0.20250311124759-d7677eab18f2/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.17-0.20250219142548-1e626a9520a4 h1:9xX1uLW6W43BZnvJv+v0mXrz795pcN92JbpQHLbV3W8= -github.com/multiversx/mx-chain-es-indexer-go v1.7.17-0.20250219142548-1e626a9520a4/go.mod h1:YcHldZCKZCncRGtGXx52YVdZWzJ3j0Dn6gMlk6nBbEw= +github.com/multiversx/mx-chain-es-indexer-go v1.7.17-0.20250311085008-58675dd2ea38 h1:sglIVcRAuxQhPEL0f0vtbPPio1i9aksNdH3C19VH0cc= +github.com/multiversx/mx-chain-es-indexer-go v1.7.17-0.20250311085008-58675dd2ea38/go.mod h1:IwFRBYbbri/C3epb+e0YmE3umXnZhewD3pwvNQM85fw= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= diff --git a/outport/process/outportDataProvider.go b/outport/process/outportDataProvider.go index cb2d4e7ee1f..7a8f7ee9ce8 100644 --- a/outport/process/outportDataProvider.go +++ b/outport/process/outportDataProvider.go @@ -133,7 +133,7 @@ func (odp *outportDataProvider) PrepareOutportSaveBlockData(arg ArgPrepareOutpor return nil, fmt.Errorf("alteredAccountsProvider.ExtractAlteredAccountsFromPool %s", err) } - signersIndexes, err := odp.getSignersIndexes(arg.Header) + leaderBlsKey, leaderIndex, signersIndexes, err := odp.getSignersIndexes(arg.Header) if err != nil { return nil, err } @@ -161,6 +161,8 @@ func (odp *outportDataProvider) PrepareOutportSaveBlockData(arg ArgPrepareOutpor HighestFinalBlockNonce: arg.HighestFinalBlockNonce, HighestFinalBlockHash: arg.HighestFinalBlockHash, + LeaderIndex: leaderIndex, + LeaderBLSKey: []byte(leaderBlsKey), }, HeaderDataWithBody: &outportcore.HeaderDataWithBody{ Body: arg.Body, @@ -310,24 +312,41 @@ func (odp *outportDataProvider) computeEpoch(header data.HeaderHandler) uint32 { return epoch } -func (odp *outportDataProvider) getSignersIndexes(header data.HeaderHandler) ([]uint64, error) { +func (odp *outportDataProvider) getSignersIndexes(header data.HeaderHandler) (string, uint64, []uint64, error) { epoch := odp.computeEpoch(header) - _, pubKeys, err := odp.nodesCoordinator.GetConsensusValidatorsPublicKeys( + leader, pubKeys, err := odp.nodesCoordinator.GetConsensusValidatorsPublicKeys( header.GetPrevRandSeed(), header.GetRound(), odp.shardID, epoch, ) + if err != nil { - return nil, fmt.Errorf("nodesCoordinator.GetConsensusValidatorsPublicKeys %w", err) + return "", 0, nil, fmt.Errorf("nodesCoordinator.GetConsensusValidatorsPublicKeys %w", err) + } + + leaderIndex := findLeaderIndex(pubKeys, leader) + + signersIndexes := make([]uint64, 0) + // when EquivalentMessages flag is enabled signer indices can be empty because all validators are in consensus group + if odp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, header.GetEpoch()) { + return leader, leaderIndex, signersIndexes, nil } - signersIndexes, err := odp.nodesCoordinator.GetValidatorsIndexes(pubKeys, epoch) + signersIndexes, err = odp.nodesCoordinator.GetValidatorsIndexes(pubKeys, epoch) if err != nil { - return nil, fmt.Errorf("nodesCoordinator.GetValidatorsIndexes %s", err) + return "", 0, nil, fmt.Errorf("nodesCoordinator.GetValidatorsIndexes %s", err) } + return leader, leaderIndex, signersIndexes, nil +} - return signersIndexes, nil +func findLeaderIndex(blsKeys []string, leaderBlsKey string) uint64 { + for i := 0; i < len(blsKeys); i++ { + if blsKeys[i] == leaderBlsKey { + return uint64(i) + } + } + return 0 } func (odp *outportDataProvider) createPool(rewardsTxs map[string]data.TransactionHandler) (*outportcore.TransactionPool, error) { diff --git a/outport/process/outportDataProvider_test.go b/outport/process/outportDataProvider_test.go index 676d1452c53..af0a64eaf04 100644 --- a/outport/process/outportDataProvider_test.go +++ b/outport/process/outportDataProvider_test.go @@ -571,6 +571,22 @@ func Test_collectExecutedTxHashes(t *testing.T) { }) } +func TestFindLeaderIndex(t *testing.T) { + t.Parallel() + + leaderKey := "a" + keys := []string{"a", "b", "c", "d", "e", "f", "g"} + require.Equal(t, uint64(0), findLeaderIndex(keys, leaderKey)) + + leaderKey = "g" + keys = []string{"a", "b", "c", "d", "e", "f", "g"} + require.Equal(t, uint64(6), findLeaderIndex(keys, leaderKey)) + + leaderKey = "notFound" + keys = []string{"a", "b", "c", "d", "e", "f", "g"} + require.Equal(t, uint64(0), findLeaderIndex(keys, leaderKey)) +} + func createMbsAndMbHeaders(numPairs int, numTxsPerMb int) ([]*block.MiniBlock, []block.MiniBlockHeader) { mbs := make([]*block.MiniBlock, numPairs) mbHeaders := make([]block.MiniBlockHeader, numPairs) diff --git a/process/block/metrics.go b/process/block/metrics.go index 94ab2e00276..17cf255022a 100644 --- a/process/block/metrics.go +++ b/process/block/metrics.go @@ -185,13 +185,9 @@ func indexRoundInfo( roundsInfo := make([]*outportcore.RoundInfo, 0) roundsInfo = append(roundsInfo, roundInfo) for i := lastBlockRound + 1; i < currentBlockRound; i++ { - _, publicKeys, err := nodesCoordinator.GetConsensusValidatorsPublicKeys(lastHeader.GetRandSeed(), i, shardId, lastHeader.GetEpoch()) - if err != nil { - continue - } - signersIndexes, err = nodesCoordinator.GetValidatorsIndexes(publicKeys, lastHeader.GetEpoch()) - if err != nil { - log.Error(err.Error(), "round", i) + var ok bool + signersIndexes, ok = getSignersIndices(header, lastHeader, i, nodesCoordinator) + if !ok { continue } @@ -210,6 +206,28 @@ func indexRoundInfo( outportHandler.SaveRoundsInfo(&outportcore.RoundsInfo{ShardID: shardId, RoundsInfo: roundsInfo}) } +func getSignersIndices(header, lastHeader data.HeaderHandler, round uint64, nodesCoordinator nodesCoordinator.NodesCoordinator) ([]uint64, bool) { + havePrevProf := !check.IfNilReflect(header.GetPreviousProof()) + // if a header have previous proof EquivalentMessage flag is active and all validators are in consensus group - signer indices no longer needed + if havePrevProf { + return make([]uint64, 0), true + } + + _, publicKeys, err := nodesCoordinator.GetConsensusValidatorsPublicKeys(lastHeader.GetRandSeed(), round, header.GetShardID(), lastHeader.GetEpoch()) + if err != nil { + log.Error("getSignersIndices: cannot get validators public keys", "error", err.Error(), "round", round) + return nil, false + } + + signersIndexes, err := nodesCoordinator.GetValidatorsIndexes(publicKeys, lastHeader.GetEpoch()) + if err != nil { + log.Error("getSignersIndices: cannot get signers indices", "error", err.Error(), "round", round) + return nil, false + } + + return signersIndexes, true +} + func indexValidatorsRating( outportHandler outport.OutportHandler, valStatProc process.ValidatorStatisticsProcessor,