github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/signature/block_signer_decoder_test.go (about)

     1  package signature
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/mock"
     8  	"github.com/stretchr/testify/require"
     9  	"github.com/stretchr/testify/suite"
    10  
    11  	hotstuff "github.com/koko1123/flow-go-1/consensus/hotstuff/mocks"
    12  	"github.com/koko1123/flow-go-1/model/flow"
    13  	"github.com/koko1123/flow-go-1/model/flow/order"
    14  	"github.com/koko1123/flow-go-1/module/signature"
    15  	"github.com/koko1123/flow-go-1/state"
    16  	"github.com/koko1123/flow-go-1/storage"
    17  	"github.com/koko1123/flow-go-1/utils/unittest"
    18  )
    19  
    20  func TestBlockSignerDecoder(t *testing.T) {
    21  	suite.Run(t, new(blockSignerDecoderSuite))
    22  }
    23  
    24  type blockSignerDecoderSuite struct {
    25  	suite.Suite
    26  	allConsensus flow.IdentityList
    27  	committee    *hotstuff.Committee
    28  
    29  	decoder *BlockSignerDecoder
    30  	block   flow.Block
    31  }
    32  
    33  func (s *blockSignerDecoderSuite) SetupTest() {
    34  	// the default header fixture creates signerIDs for a committee of 10 nodes, so we prepare a committee same as that
    35  	s.allConsensus = unittest.IdentityListFixture(40, unittest.WithRole(flow.RoleConsensus)).Sort(order.Canonical)
    36  
    37  	// prepare valid test block:
    38  	voterIndices, err := signature.EncodeSignersToIndices(s.allConsensus.NodeIDs(), s.allConsensus.NodeIDs())
    39  	require.NoError(s.T(), err)
    40  	s.block = unittest.BlockFixture()
    41  	s.block.Header.ParentVoterIndices = voterIndices
    42  
    43  	// mock consensus committee
    44  	s.committee = new(hotstuff.Committee)
    45  	s.committee.On("Identities", s.block.Header.ParentID).Return(s.allConsensus, nil)
    46  
    47  	s.decoder = NewBlockSignerDecoder(s.committee)
    48  }
    49  
    50  // Test_SuccessfulDecode tests happy path decoding
    51  func (s *blockSignerDecoderSuite) Test_SuccessfulDecode() {
    52  	ids, err := s.decoder.DecodeSignerIDs(s.block.Header)
    53  	require.NoError(s.T(), err)
    54  	require.Equal(s.T(), s.allConsensus.NodeIDs(), ids)
    55  }
    56  
    57  // Test_RootBlock tests decoder accepts root block with empty signer indices
    58  func (s *blockSignerDecoderSuite) Test_RootBlock() {
    59  	s.block.Header.ParentVoterIndices = nil
    60  	s.block.Header.ParentVoterSigData = nil
    61  	s.block.Header.View = 0
    62  
    63  	ids, err := s.decoder.DecodeSignerIDs(s.block.Header)
    64  	require.NoError(s.T(), err)
    65  	require.Empty(s.T(), ids)
    66  }
    67  
    68  // Test_UnknownBlock tests handling of an unknwon block.
    69  // At the moment, hotstuff.Committee returns an storage.ErrNotFound for an unknown block,
    70  // which we expect the `BlockSignerDecoder` to wrap into a `state.UnknownBlockError`
    71  func (s *blockSignerDecoderSuite) Test_UnknownBlock() {
    72  	*s.committee = hotstuff.Committee{}
    73  	s.committee.On("Identities", mock.Anything).Return(nil, storage.ErrNotFound)
    74  
    75  	ids, err := s.decoder.DecodeSignerIDs(s.block.Header)
    76  	require.Empty(s.T(), ids)
    77  	require.True(s.T(), state.IsUnknownBlockError(err))
    78  }
    79  
    80  // Test_UnexpectedCommitteeException verifies that `BlockSignerDecoder`
    81  // does _not_ erroneously interpret an unexpecgted exception from the committee as
    82  // a sign of an unknown block, i.e. the decouder should _not_ return an `state.UnknownBlockError`
    83  func (s *blockSignerDecoderSuite) Test_UnexpectedCommitteeException() {
    84  	exception := errors.New("unexpected exception")
    85  	*s.committee = hotstuff.Committee{}
    86  	s.committee.On("Identities", mock.Anything).Return(nil, exception)
    87  
    88  	ids, err := s.decoder.DecodeSignerIDs(s.block.Header)
    89  	require.Empty(s.T(), ids)
    90  	require.False(s.T(), state.IsUnknownBlockError(err))
    91  	require.True(s.T(), errors.Is(err, exception))
    92  }
    93  
    94  // Test_InvalidIndices verifies that `BlockSignerDecoder` returns
    95  // signature.InvalidSignerIndicesError is the signer indices in the provided header
    96  // are not a valid encoding.
    97  func (s *blockSignerDecoderSuite) Test_InvalidIndices() {
    98  	s.block.Header.ParentVoterIndices = unittest.RandomBytes(1)
    99  	ids, err := s.decoder.DecodeSignerIDs(s.block.Header)
   100  	require.Empty(s.T(), ids)
   101  	require.True(s.T(), signature.IsInvalidSignerIndicesError(err))
   102  }