github.com/koko1123/flow-go-1@v0.29.6/engine/verification/verifier/engine_test.go (about)

     1  package verifier_test
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"testing"
     7  
     8  	"github.com/rs/zerolog"
     9  	"github.com/stretchr/testify/mock"
    10  	testifymock "github.com/stretchr/testify/mock"
    11  	"github.com/stretchr/testify/require"
    12  	"github.com/stretchr/testify/suite"
    13  
    14  	"github.com/onflow/flow-go/crypto"
    15  	"github.com/onflow/flow-go/crypto/hash"
    16  	"github.com/koko1123/flow-go-1/engine/testutil/mocklocal"
    17  	"github.com/koko1123/flow-go-1/engine/verification/utils"
    18  	"github.com/koko1123/flow-go-1/engine/verification/verifier"
    19  	chmodel "github.com/koko1123/flow-go-1/model/chunks"
    20  	"github.com/koko1123/flow-go-1/model/flow"
    21  	"github.com/koko1123/flow-go-1/model/verification"
    22  	realModule "github.com/koko1123/flow-go-1/module"
    23  	mockmodule "github.com/koko1123/flow-go-1/module/mock"
    24  	"github.com/koko1123/flow-go-1/module/trace"
    25  	"github.com/koko1123/flow-go-1/network/channels"
    26  	"github.com/koko1123/flow-go-1/network/mocknetwork"
    27  	protocol "github.com/koko1123/flow-go-1/state/protocol/mock"
    28  	mockstorage "github.com/koko1123/flow-go-1/storage/mock"
    29  	"github.com/koko1123/flow-go-1/utils/unittest"
    30  )
    31  
    32  type VerifierEngineTestSuite struct {
    33  	suite.Suite
    34  	net       *mocknetwork.Network
    35  	tracer    realModule.Tracer
    36  	state     *protocol.State
    37  	ss        *protocol.Snapshot
    38  	me        *mocklocal.MockLocal
    39  	sk        crypto.PrivateKey
    40  	hasher    hash.Hasher
    41  	chain     flow.Chain
    42  	pushCon   *mocknetwork.Conduit // mocks con for submitting result approvals
    43  	pullCon   *mocknetwork.Conduit
    44  	metrics   *mockmodule.VerificationMetrics // mocks performance monitoring metrics
    45  	approvals *mockstorage.ResultApprovals
    46  }
    47  
    48  func TestVerifierEngine(t *testing.T) {
    49  	suite.Run(t, new(VerifierEngineTestSuite))
    50  }
    51  
    52  func (suite *VerifierEngineTestSuite) SetupTest() {
    53  
    54  	suite.state = &protocol.State{}
    55  	suite.net = &mocknetwork.Network{}
    56  	suite.tracer = trace.NewNoopTracer()
    57  	suite.ss = &protocol.Snapshot{}
    58  	suite.pushCon = &mocknetwork.Conduit{}
    59  	suite.pullCon = &mocknetwork.Conduit{}
    60  	suite.metrics = &mockmodule.VerificationMetrics{}
    61  	suite.chain = flow.Testnet.Chain()
    62  	suite.approvals = &mockstorage.ResultApprovals{}
    63  
    64  	suite.approvals.On("Store", mock.Anything).Return(nil)
    65  	suite.approvals.On("Index", mock.Anything, mock.Anything, mock.Anything).Return(nil)
    66  
    67  	suite.net.On("Register", channels.PushApprovals, testifymock.Anything).
    68  		Return(suite.pushCon, nil).
    69  		Once()
    70  
    71  	suite.net.On("Register", channels.ProvideApprovalsByChunk, testifymock.Anything).
    72  		Return(suite.pullCon, nil).
    73  		Once()
    74  
    75  	suite.state.On("Final").Return(suite.ss)
    76  
    77  	// Mocks the signature oracle of the engine
    78  	//
    79  	// generates signing and verification keys
    80  	seed := make([]byte, crypto.KeyGenSeedMinLenBLSBLS12381)
    81  	n, err := rand.Read(seed)
    82  	require.Equal(suite.T(), n, crypto.KeyGenSeedMinLenBLSBLS12381)
    83  	require.NoError(suite.T(), err)
    84  
    85  	// creates private key of verification node
    86  	sk, err := crypto.GeneratePrivateKey(crypto.BLSBLS12381, seed)
    87  	require.NoError(suite.T(), err)
    88  	suite.sk = sk
    89  
    90  	// tag of hasher should be the same as the tag of engine's hasher
    91  	suite.hasher = utils.NewResultApprovalHasher()
    92  
    93  	// defines the identity of verification node and attaches its key.
    94  	verIdentity := unittest.IdentityFixture(unittest.WithRole(flow.RoleVerification))
    95  	verIdentity.StakingPubKey = sk.PublicKey()
    96  	suite.me = mocklocal.NewMockLocal(sk, verIdentity.NodeID, suite.T())
    97  }
    98  
    99  func (suite *VerifierEngineTestSuite) TestNewEngine() *verifier.Engine {
   100  	e, err := verifier.New(
   101  		zerolog.Logger{},
   102  		suite.metrics,
   103  		suite.tracer,
   104  		suite.net,
   105  		suite.state,
   106  		suite.me,
   107  		ChunkVerifierMock{},
   108  		suite.approvals)
   109  	require.Nil(suite.T(), err)
   110  
   111  	suite.net.AssertExpectations(suite.T())
   112  	return e
   113  
   114  }
   115  
   116  func (suite *VerifierEngineTestSuite) TestIncorrectResult() {
   117  	// TODO when ERs are verified
   118  }
   119  
   120  // TestVerifyHappyPath tests the verification path for a single verifiable chunk, which is
   121  // assigned to the verifier node, and is passed by the ingest engine
   122  // The tests evaluates that a result approval is emitted to all consensus nodes
   123  // about the input execution receipt
   124  func (suite *VerifierEngineTestSuite) TestVerifyHappyPath() {
   125  
   126  	eng := suite.TestNewEngine()
   127  	myID := unittest.IdentifierFixture()
   128  	consensusNodes := unittest.IdentityListFixture(1, unittest.WithRole(flow.RoleConsensus))
   129  	// creates a verifiable chunk
   130  	vChunk := unittest.VerifiableChunkDataFixture(uint64(0))
   131  
   132  	// mocking node ID using the LocalMock
   133  	suite.me.MockNodeID(myID)
   134  	suite.ss.On("Identities", testifymock.Anything).Return(consensusNodes, nil)
   135  
   136  	// mocks metrics
   137  	// reception of verifiable chunk
   138  	suite.metrics.On("OnVerifiableChunkReceivedAtVerifierEngine").Return()
   139  	// emission of result approval
   140  	suite.metrics.On("OnResultApprovalDispatchedInNetworkByVerifier").Return()
   141  
   142  	suite.pushCon.
   143  		On("Publish", testifymock.Anything, testifymock.Anything).
   144  		Return(nil).
   145  		Run(func(args testifymock.Arguments) {
   146  			// check that the approval matches the input execution result
   147  			ra, ok := args[0].(*flow.ResultApproval)
   148  			suite.Assert().True(ok)
   149  			suite.Assert().Equal(vChunk.Result.ID(), ra.Body.ExecutionResultID)
   150  
   151  			// verifies the signatures
   152  			atstID := ra.Body.Attestation.ID()
   153  			suite.Assert().True(suite.sk.PublicKey().Verify(ra.Body.AttestationSignature, atstID[:], suite.hasher))
   154  			bodyID := ra.Body.ID()
   155  			suite.Assert().True(suite.sk.PublicKey().Verify(ra.VerifierSignature, bodyID[:], suite.hasher))
   156  
   157  			// spock should be non-nil
   158  			suite.Assert().NotNil(ra.Body.Spock)
   159  		}).
   160  		Once()
   161  
   162  	err := eng.ProcessLocal(vChunk)
   163  	suite.Assert().NoError(err)
   164  	suite.ss.AssertExpectations(suite.T())
   165  	suite.pushCon.AssertExpectations(suite.T())
   166  
   167  }
   168  
   169  func (suite *VerifierEngineTestSuite) TestVerifyUnhappyPaths() {
   170  	eng := suite.TestNewEngine()
   171  	myID := unittest.IdentifierFixture()
   172  	consensusNodes := unittest.IdentityListFixture(1, unittest.WithRole(flow.RoleConsensus))
   173  
   174  	// mocking node ID using the LocalMock
   175  	suite.me.MockNodeID(myID)
   176  	suite.ss.On("Identities", testifymock.Anything).Return(consensusNodes, nil)
   177  
   178  	// mocks metrics
   179  	// reception of verifiable chunk
   180  	suite.metrics.On("OnVerifiableChunkReceivedAtVerifierEngine").Return()
   181  
   182  	// we shouldn't receive any result approval
   183  	suite.pushCon.
   184  		On("Publish", testifymock.Anything, testifymock.Anything).
   185  		Return(nil).
   186  		Run(func(args testifymock.Arguments) {
   187  			// TODO change this to check challeneges
   188  			_, ok := args[0].(*flow.ResultApproval)
   189  			// TODO change this to false when missing register is rolled back
   190  			suite.Assert().True(ok)
   191  		})
   192  
   193  	// emission of result approval
   194  	suite.metrics.On("OnResultApprovalDispatchedInNetworkByVerifier").Return()
   195  
   196  	var tests = []struct {
   197  		vc          *verification.VerifiableChunkData
   198  		expectedErr error
   199  	}{
   200  		{unittest.VerifiableChunkDataFixture(uint64(1)), nil},
   201  		{unittest.VerifiableChunkDataFixture(uint64(2)), nil},
   202  		{unittest.VerifiableChunkDataFixture(uint64(3)), nil},
   203  	}
   204  	for _, test := range tests {
   205  		err := eng.ProcessLocal(test.vc)
   206  		suite.Assert().NoError(err)
   207  	}
   208  }
   209  
   210  type ChunkVerifierMock struct {
   211  }
   212  
   213  func (v ChunkVerifierMock) Verify(vc *verification.VerifiableChunkData) ([]byte, chmodel.ChunkFault, error) {
   214  	if vc.IsSystemChunk {
   215  		return nil, nil, nil
   216  	}
   217  
   218  	switch vc.Chunk.Index {
   219  	case 0:
   220  		return []byte{}, nil, nil
   221  	// return error
   222  	case 1:
   223  		return nil, chmodel.NewCFMissingRegisterTouch(
   224  			[]string{"test missing register touch"},
   225  			vc.Chunk.Index,
   226  			vc.Result.ID(),
   227  			unittest.TransactionFixture().ID()), nil
   228  
   229  	case 2:
   230  		return nil, chmodel.NewCFInvalidVerifiableChunk(
   231  			"test",
   232  			errors.New("test invalid verifiable chunk"),
   233  			vc.Chunk.Index,
   234  			vc.Result.ID()), nil
   235  
   236  	case 3:
   237  		return nil, chmodel.NewCFNonMatchingFinalState(
   238  			unittest.StateCommitmentFixture(),
   239  			unittest.StateCommitmentFixture(),
   240  			vc.Chunk.Index,
   241  			vc.Result.ID()), nil
   242  
   243  	// TODO add cases for challenges
   244  	// return successful by default
   245  	default:
   246  		return nil, nil, nil
   247  	}
   248  
   249  }