github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/consensus/approvals/chunk_collector_test.go (about)

     1  package approvals
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  	"github.com/stretchr/testify/suite"
     8  
     9  	"github.com/onflow/flow-go/model/flow"
    10  	"github.com/onflow/flow-go/utils/unittest"
    11  )
    12  
    13  // TestChunkApprovalCollector performs isolated testing of ChunkApprovalCollector.
    14  // ChunkApprovalCollector has to process and cache signatures for result approvals that satisfy assignment.
    15  // ChunkApprovalCollector has to reject approvals with invalid assignment.
    16  // ChunkApprovalCollector is responsible for properly accumulating signatures and creating aggregated signature when requested.
    17  func TestChunkApprovalCollector(t *testing.T) {
    18  	suite.Run(t, new(ChunkApprovalCollectorTestSuite))
    19  }
    20  
    21  type ChunkApprovalCollectorTestSuite struct {
    22  	BaseApprovalsTestSuite
    23  
    24  	chunk           *flow.Chunk
    25  	chunkAssignment map[flow.Identifier]struct{}
    26  	collector       *ChunkApprovalCollector
    27  }
    28  
    29  func (s *ChunkApprovalCollectorTestSuite) SetupTest() {
    30  	s.BaseApprovalsTestSuite.SetupTest()
    31  	s.chunk = s.Chunks[0]
    32  	s.chunkAssignment = make(map[flow.Identifier]struct{})
    33  	for _, verifier := range s.ChunksAssignment.Verifiers(s.chunk) {
    34  		s.chunkAssignment[verifier] = struct{}{}
    35  	}
    36  	s.collector = NewChunkApprovalCollector(s.chunkAssignment, uint(len(s.chunkAssignment)))
    37  }
    38  
    39  // TestProcessApproval_ValidApproval tests processing a valid approval. Expected to process it without error
    40  // and report status to caller.
    41  func (s *ChunkApprovalCollectorTestSuite) TestProcessApproval_ValidApproval() {
    42  	approval := unittest.ResultApprovalFixture(unittest.WithChunk(s.chunk.Index), unittest.WithApproverID(s.VerID))
    43  	_, collected := s.collector.ProcessApproval(approval)
    44  	require.False(s.T(), collected)
    45  	require.Equal(s.T(), uint(1), s.collector.chunkApprovals.NumberSignatures())
    46  }
    47  
    48  // TestProcessApproval_InvalidChunkAssignment tests processing approval with invalid chunk assignment. Expected to
    49  // reject this approval, signature cache shouldn't be affected.
    50  func (s *ChunkApprovalCollectorTestSuite) TestProcessApproval_InvalidChunkAssignment() {
    51  	approval := unittest.ResultApprovalFixture(unittest.WithChunk(s.chunk.Index), unittest.WithApproverID(s.VerID))
    52  	delete(s.chunkAssignment, s.VerID)
    53  	_, collected := s.collector.ProcessApproval(approval)
    54  	require.False(s.T(), collected)
    55  	require.Equal(s.T(), uint(0), s.collector.chunkApprovals.NumberSignatures())
    56  }
    57  
    58  // TestGetAggregatedSignature_MultipleApprovals tests processing approvals from different verifiers. Expected to provide a valid
    59  // aggregated sig that has `AttestationSignature` for every approval.
    60  func (s *ChunkApprovalCollectorTestSuite) TestGetAggregatedSignature_MultipleApprovals() {
    61  	var aggregatedSig flow.AggregatedSignature
    62  	var collected bool
    63  	sigCollector := NewSignatureCollector()
    64  	for verID := range s.AuthorizedVerifiers {
    65  		approval := unittest.ResultApprovalFixture(unittest.WithChunk(s.chunk.Index), unittest.WithApproverID(verID))
    66  		aggregatedSig, collected = s.collector.ProcessApproval(approval)
    67  		sigCollector.Add(approval.Body.ApproverID, approval.Body.AttestationSignature)
    68  	}
    69  
    70  	require.True(s.T(), collected)
    71  	require.NotNil(s.T(), aggregatedSig)
    72  	require.Equal(s.T(), uint(len(s.AuthorizedVerifiers)), s.collector.chunkApprovals.NumberSignatures())
    73  	require.Equal(s.T(), sigCollector.ToAggregatedSignature(), aggregatedSig)
    74  }
    75  
    76  // TestGetMissingSigners tests that missing signers returns correct IDs of approvers that haven't provided an approval
    77  func (s *ChunkApprovalCollectorTestSuite) TestGetMissingSigners() {
    78  	assignedSigners := make(flow.IdentifierList, 0, len(s.chunkAssignment))
    79  	for id := range s.chunkAssignment {
    80  		assignedSigners = append(assignedSigners, id)
    81  	}
    82  	require.ElementsMatch(s.T(), assignedSigners, s.collector.GetMissingSigners())
    83  
    84  	approval := unittest.ResultApprovalFixture(unittest.WithChunk(s.chunk.Index), unittest.WithApproverID(assignedSigners[0]))
    85  	s.collector.ProcessApproval(approval)
    86  
    87  	require.ElementsMatch(s.T(), assignedSigners[1:], s.collector.GetMissingSigners())
    88  
    89  	for verID := range s.AuthorizedVerifiers {
    90  		approval := unittest.ResultApprovalFixture(unittest.WithChunk(s.chunk.Index), unittest.WithApproverID(verID))
    91  		s.collector.ProcessApproval(approval)
    92  	}
    93  
    94  	require.Empty(s.T(), s.collector.GetMissingSigners())
    95  }