From 591433d2d23c13ca559d51ed9168105ec18211d8 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Sat, 27 Jan 2024 00:22:32 +0200 Subject: [PATCH] - fixed the multikey backup step-in --- consensus/spos/bls/subroundEndRound.go | 27 +------- process/block/baseProcess.go | 9 ++- process/block/baseProcess_test.go | 8 ++- process/block/metablock_test.go | 1 + process/block/shardblock_test.go | 2 +- process/headerCheck/common.go | 24 +++++++ process/headerCheck/common_test.go | 92 ++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 30 deletions(-) diff --git a/consensus/spos/bls/subroundEndRound.go b/consensus/spos/bls/subroundEndRound.go index 3171f806077..21675715f39 100644 --- a/consensus/spos/bls/subroundEndRound.go +++ b/consensus/spos/bls/subroundEndRound.go @@ -15,6 +15,7 @@ import ( "github.com/multiversx/mx-chain-go/consensus" "github.com/multiversx/mx-chain-go/consensus/spos" "github.com/multiversx/mx-chain-go/p2p" + "github.com/multiversx/mx-chain-go/process/headerCheck" ) type subroundEndRound struct { @@ -861,33 +862,9 @@ func (sr *subroundEndRound) doEndRoundConsensusCheck() bool { return false } -// computeSignersPublicKeys will extract from the provided consensus group slice only the strings that matched with the bitmap -func computeSignersPublicKeys(consensusGroup []string, bitmap []byte) []string { - nbBitsBitmap := len(bitmap) * 8 - consensusGroupSize := len(consensusGroup) - size := consensusGroupSize - if consensusGroupSize > nbBitsBitmap { - size = nbBitsBitmap - } - - result := make([]string, 0, len(consensusGroup)) - - for i := 0; i < size; i++ { - indexRequired := (bitmap[i/8] & (1 << uint16(i%8))) > 0 - if !indexRequired { - continue - } - - pubKey := consensusGroup[i] - result = append(result, pubKey) - } - - return result -} - func (sr *subroundEndRound) checkSignaturesValidity(bitmap []byte) error { consensusGroup := sr.ConsensusGroup() - signers := computeSignersPublicKeys(consensusGroup, bitmap) + signers := headerCheck.ComputeSignersPublicKeys(consensusGroup, bitmap) for _, pubKey := range signers { isSigJobDone, err := sr.JobDone(pubKey, SrSignature) if err != nil { diff --git a/process/block/baseProcess.go b/process/block/baseProcess.go index c51d7510110..fbe3da11832 100644 --- a/process/block/baseProcess.go +++ b/process/block/baseProcess.go @@ -2122,8 +2122,15 @@ func (bp *baseProcessor) checkSentSignaturesAtCommitTime(header data.HeaderHandl return err } + consensusGroup := make([]string, 0, len(validatorsGroup)) for _, validator := range validatorsGroup { - bp.sentSignaturesTracker.ResetCountersForManagedBlockSigner(validator.PubKey()) + consensusGroup = append(consensusGroup, string(validator.PubKey())) + } + + signers := headerCheck.ComputeSignersPublicKeys(consensusGroup, header.GetPubKeysBitmap()) + + for _, signer := range signers { + bp.sentSignaturesTracker.ResetCountersForManagedBlockSigner([]byte(signer)) } return nil diff --git a/process/block/baseProcess_test.go b/process/block/baseProcess_test.go index 71737a1b2e4..2921d29caaa 100644 --- a/process/block/baseProcess_test.go +++ b/process/block/baseProcess_test.go @@ -3153,7 +3153,7 @@ func TestBaseProcessor_CheckSentSignaturesAtCommitTime(t *testing.T) { err := bp.CheckSentSignaturesAtCommitTime(&block.Header{}) assert.Equal(t, expectedErr, err) }) - t.Run("should work", func(t *testing.T) { + t.Run("should work with bitmap", func(t *testing.T) { validator0, _ := nodesCoordinator.NewValidator([]byte("pk0"), 0, 0) validator1, _ := nodesCoordinator.NewValidator([]byte("pk1"), 1, 1) validator2, _ := nodesCoordinator.NewValidator([]byte("pk2"), 2, 2) @@ -3173,9 +3173,11 @@ func TestBaseProcessor_CheckSentSignaturesAtCommitTime(t *testing.T) { arguments.NodesCoordinator = nodesCoordinatorInstance bp, _ := blproc.NewShardProcessor(arguments) - err := bp.CheckSentSignaturesAtCommitTime(&block.Header{}) + err := bp.CheckSentSignaturesAtCommitTime(&block.Header{ + PubKeysBitmap: []byte{0b00000101}, + }) assert.Nil(t, err) - assert.Equal(t, [][]byte{validator0.PubKey(), validator1.PubKey(), validator2.PubKey()}, resetCountersCalled) + assert.Equal(t, [][]byte{validator0.PubKey(), validator2.PubKey()}, resetCountersCalled) }) } diff --git a/process/block/metablock_test.go b/process/block/metablock_test.go index e06611c10f8..30051e3d582 100644 --- a/process/block/metablock_test.go +++ b/process/block/metablock_test.go @@ -991,6 +991,7 @@ func TestMetaProcessor_CommitBlockOkValsShouldWork(t *testing.T) { mdp := initDataPool([]byte("tx_hash")) rootHash := []byte("rootHash") hdr := createMetaBlockHeader() + hdr.PubKeysBitmap = []byte{0b11111111} body := &block.Body{} accounts := &stateMock.AccountsStub{ CommitCalled: func() (i []byte, e error) { diff --git a/process/block/shardblock_test.go b/process/block/shardblock_test.go index 1c967862542..1a2e2865266 100644 --- a/process/block/shardblock_test.go +++ b/process/block/shardblock_test.go @@ -2048,7 +2048,7 @@ func TestShardProcessor_CommitBlockOkValsShouldWork(t *testing.T) { hdr := &block.Header{ Nonce: 1, Round: 1, - PubKeysBitmap: rootHash, + PubKeysBitmap: []byte{0b11111111}, PrevHash: hdrHash, Signature: rootHash, RootHash: rootHash, diff --git a/process/headerCheck/common.go b/process/headerCheck/common.go index b25e12c0833..01946580d87 100644 --- a/process/headerCheck/common.go +++ b/process/headerCheck/common.go @@ -26,3 +26,27 @@ func ComputeConsensusGroup(header data.HeaderHandler, nodesCoordinator nodesCoor return nodesCoordinator.ComputeConsensusGroup(prevRandSeed, header.GetRound(), header.GetShardID(), epoch) } + +// ComputeSignersPublicKeys will extract from the provided consensus group slice only the strings that matched with the bitmap +func ComputeSignersPublicKeys(consensusGroup []string, bitmap []byte) []string { + nbBitsBitmap := len(bitmap) * 8 + consensusGroupSize := len(consensusGroup) + size := consensusGroupSize + if consensusGroupSize > nbBitsBitmap { + size = nbBitsBitmap + } + + result := make([]string, 0, len(consensusGroup)) + + for i := 0; i < size; i++ { + indexRequired := (bitmap[i/8] & (1 << uint16(i%8))) > 0 + if !indexRequired { + continue + } + + pubKey := consensusGroup[i] + result = append(result, pubKey) + } + + return result +} diff --git a/process/headerCheck/common_test.go b/process/headerCheck/common_test.go index 3833a7b2d60..0961b7f2a20 100644 --- a/process/headerCheck/common_test.go +++ b/process/headerCheck/common_test.go @@ -1,6 +1,7 @@ package headerCheck import ( + "fmt" "testing" "github.com/multiversx/mx-chain-core-go/data/block" @@ -93,3 +94,94 @@ func TestComputeConsensusGroup(t *testing.T) { assert.Equal(t, validatorGroup, vGroup) }) } + +func generatePubKeys(num int) []string { + consensusGroup := make([]string, 0, num) + for i := 0; i < num; i++ { + consensusGroup = append(consensusGroup, fmt.Sprintf("pub key %d", i)) + } + + return consensusGroup +} + +func TestComputeSignersPublicKeys(t *testing.T) { + t.Parallel() + + t.Run("should compute with 16 validators", func(t *testing.T) { + t.Parallel() + + consensusGroup := generatePubKeys(16) + mask0 := byte(0b00110101) + mask1 := byte(0b01001101) + + result := ComputeSignersPublicKeys(consensusGroup, []byte{mask0, mask1}) + expected := []string{ + "pub key 0", + "pub key 2", + "pub key 4", + "pub key 5", + + "pub key 8", + "pub key 10", + "pub key 11", + "pub key 14", + } + + assert.Equal(t, expected, result) + }) + t.Run("should compute with 14 validators", func(t *testing.T) { + t.Parallel() + + consensusGroup := generatePubKeys(14) + mask0 := byte(0b00110101) + mask1 := byte(0b00001101) + + result := ComputeSignersPublicKeys(consensusGroup, []byte{mask0, mask1}) + expected := []string{ + "pub key 0", + "pub key 2", + "pub key 4", + "pub key 5", + + "pub key 8", + "pub key 10", + "pub key 11", + } + + assert.Equal(t, expected, result) + }) + t.Run("should compute with 14 validators, mask is 0", func(t *testing.T) { + t.Parallel() + + consensusGroup := generatePubKeys(14) + mask0 := byte(0b00000000) + mask1 := byte(0b00000000) + + result := ComputeSignersPublicKeys(consensusGroup, []byte{mask0, mask1}) + expected := make([]string, 0) + + assert.Equal(t, expected, result) + }) + t.Run("should compute with 14 validators, mask contains all bits set", func(t *testing.T) { + t.Parallel() + + consensusGroup := generatePubKeys(14) + mask0 := byte(0b11111111) + mask1 := byte(0b00111111) + + result := ComputeSignersPublicKeys(consensusGroup, []byte{mask0, mask1}) + + assert.Equal(t, consensusGroup, result) + }) + t.Run("should compute with 17 validators, mask contains 2 bytes", func(t *testing.T) { + t.Parallel() + + consensusGroup := generatePubKeys(17) + mask0 := byte(0b11111111) + mask1 := byte(0b11111111) + + result := ComputeSignersPublicKeys(consensusGroup, []byte{mask0, mask1}) + expected := generatePubKeys(16) + assert.Equal(t, expected, result) + }) +}