diff --git a/access/grpc/client.go b/access/grpc/client.go index 5ca1729aa..32d79f0f9 100644 --- a/access/grpc/client.go +++ b/access/grpc/client.go @@ -173,10 +173,18 @@ func (c *Client) GetTransaction(ctx context.Context, txID flow.Identifier) (*flo return c.grpc.GetTransaction(ctx, txID) } +func (c *Client) GetSystemTransaction(ctx context.Context, blockID flow.Identifier) (*flow.Transaction, error) { + return c.grpc.GetSystemTransaction(ctx, blockID) +} + func (c *Client) GetTransactionsByBlockID(ctx context.Context, blockID flow.Identifier) ([]*flow.Transaction, error) { return c.grpc.GetTransactionsByBlockID(ctx, blockID) } +func (c *Client) GetSystemTransactionResult(ctx context.Context, blockID flow.Identifier) (*flow.TransactionResult, error) { + return c.grpc.GetSystemTransactionResult(ctx, blockID) +} + func (c *Client) GetTransactionResult(ctx context.Context, txID flow.Identifier) (*flow.TransactionResult, error) { return c.grpc.GetTransactionResult(ctx, txID) } diff --git a/access/grpc/grpc.go b/access/grpc/grpc.go index b70a55bed..d8a3b7915 100644 --- a/access/grpc/grpc.go +++ b/access/grpc/grpc.go @@ -362,6 +362,28 @@ func (c *BaseClient) GetTransaction( return &result, nil } +func (c *BaseClient) GetSystemTransaction( + ctx context.Context, + blockID flow.Identifier, + opts ...grpc.CallOption, +) (*flow.Transaction, error) { + req := &access.GetSystemTransactionRequest{ + BlockId: blockID.Bytes(), + } + + res, err := c.rpcClient.GetSystemTransaction(ctx, req, opts...) + if err != nil { + return nil, newRPCError(err) + } + + result, err := convert.MessageToTransaction(res.GetTransaction()) + if err != nil { + return nil, newMessageToEntityError(entityTransaction, err) + } + + return &result, nil +} + func (c *BaseClient) GetTransactionsByBlockID( ctx context.Context, blockID flow.Identifier, @@ -389,6 +411,29 @@ func (c *BaseClient) GetTransactionsByBlockID( return results, nil } +func (c *BaseClient) GetSystemTransactionResult( + ctx context.Context, + blockID flow.Identifier, + opts ...grpc.CallOption, +) (*flow.TransactionResult, error) { + req := &access.GetSystemTransactionResultRequest{ + BlockId: blockID.Bytes(), + EventEncodingVersion: c.eventEncoding, + } + + res, err := c.rpcClient.GetSystemTransactionResult(ctx, req, opts...) + if err != nil { + return nil, newRPCError(err) + } + + result, err := convert.MessageToTransactionResult(res, c.jsonOptions) + if err != nil { + return nil, newMessageToEntityError(entityTransactionResult, err) + } + + return &result, nil +} + func (c *BaseClient) GetTransactionResult( ctx context.Context, txID flow.Identifier, diff --git a/access/grpc/grpc_test.go b/access/grpc/grpc_test.go index 58a7939f6..4e62d96c3 100644 --- a/access/grpc/grpc_test.go +++ b/access/grpc/grpc_test.go @@ -445,6 +445,42 @@ func TestClient_SendTransaction(t *testing.T) { })) } +func TestClient_GetSystemTransaction(t *testing.T) { + txs := test.TransactionGenerator() + ids := test.IdentifierGenerator() + + t.Run("Success", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) { + blockID := ids.New() + expectedTx := txs.New() + + txMsg, err := convert.TransactionToMessage(*expectedTx) + require.NoError(t, err) + + response := &access.TransactionResponse{ + Transaction: txMsg, + } + + rpc.On("GetSystemTransaction", ctx, mock.Anything).Return(response, nil) + + tx, err := c.GetSystemTransaction(ctx, blockID) + require.NoError(t, err) + + assert.Equal(t, expectedTx, tx) + })) + + t.Run("Not found error", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) { + blockID := ids.New() + + rpc.On("GetSystemTransaction", ctx, mock.Anything). + Return(nil, errNotFound) + + tx, err := c.GetSystemTransaction(ctx, blockID) + assert.Error(t, err) + assert.Equal(t, codes.NotFound, status.Code(err)) + assert.Nil(t, tx) + })) +} + func TestClient_GetTransaction(t *testing.T) { txs := test.TransactionGenerator() ids := test.IdentifierGenerator() @@ -516,6 +552,62 @@ func TestClient_GetTransactionsByBlockID(t *testing.T) { })) } +func TestClient_GetSystemTransactionResult(t *testing.T) { + ids := test.IdentifierGenerator() + + t.Run("Success", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) { + results := test.TransactionResultGenerator(flow.EventEncodingVersionCCF) + blockID := ids.New() + expectedResult := results.New() + response, _ := convert.TransactionResultToMessage(expectedResult, flow.EventEncodingVersionCCF) + + rpc.On("GetSystemTransactionResult", ctx, mock.Anything).Return(response, nil) + + result, err := c.GetSystemTransactionResult(ctx, blockID) + require.NoError(t, err) + + // Force evaluation of type ID, which is cached in type. + // Necessary for equality check below + for _, event := range result.Events { + _ = event.Value.Type().ID() + } + + assert.Equal(t, expectedResult, *result) + })) + + t.Run("Success with jsoncdc", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) { + results := test.TransactionResultGenerator(flow.EventEncodingVersionJSONCDC) + blockID := ids.New() + expectedResult := results.New() + response, _ := convert.TransactionResultToMessage(expectedResult, flow.EventEncodingVersionJSONCDC) + + rpc.On("GetSystemTransactionResult", ctx, mock.Anything).Return(response, nil) + + result, err := c.GetSystemTransactionResult(ctx, blockID) + require.NoError(t, err) + + // Force evaluation of type ID, which is cached in type. + // Necessary for equality check below + for _, event := range result.Events { + _ = event.Value.Type().ID() + } + + assert.Equal(t, expectedResult, *result) + })) + + t.Run("Not found error", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) { + blockID := ids.New() + + rpc.On("GetSystemTransactionResult", ctx, mock.Anything). + Return(nil, errNotFound) + + result, err := c.GetSystemTransactionResult(ctx, blockID) + assert.Error(t, err) + assert.Equal(t, codes.NotFound, status.Code(err)) + assert.Nil(t, result) + })) +} + func TestClient_GetTransactionResult(t *testing.T) { ids := test.IdentifierGenerator()