Skip to content

Commit

Permalink
Merge branch 'master' into illia-malachyn/746-subscribe-block-headers…
Browse files Browse the repository at this point in the history
…-endpoints
  • Loading branch information
illia-malachyn authored Sep 24, 2024
2 parents 887cdd3 + 9b49f3e commit 8c7f66a
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 31 deletions.
12 changes: 12 additions & 0 deletions access/grpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -240,6 +248,10 @@ func (c *Client) GetExecutionResultForBlockID(ctx context.Context, blockID flow.
return c.grpc.GetExecutionResultForBlockID(ctx, blockID)
}

func (c *Client) GetExecutionResultByID(ctx context.Context, id flow.Identifier) (*flow.ExecutionResult, error) {
return c.grpc.GetExecutionResultByID(ctx, id)
}

func (c *Client) GetExecutionDataByBlockID(ctx context.Context, blockID flow.Identifier) (*flow.ExecutionData, error) {
return c.grpc.GetExecutionDataByBlockID(ctx, blockID)
}
Expand Down
32 changes: 32 additions & 0 deletions access/grpc/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,38 @@ func MessageToTransactionResult(m *access.TransactionResultResponse, options []j
}, nil
}

func MessageToExecutionResult(execResult *entities.ExecutionResult) (*flow.ExecutionResult, error) {
chunks := make([]*flow.Chunk, len(execResult.Chunks))
serviceEvents := make([]*flow.ServiceEvent, len(execResult.ServiceEvents))

for i, chunk := range execResult.Chunks {
chunks[i] = &flow.Chunk{
CollectionIndex: uint(chunk.CollectionIndex),
StartState: flow.BytesToStateCommitment(chunk.StartState),
EventCollection: flow.BytesToHash(chunk.EventCollection),
BlockID: flow.BytesToID(chunk.BlockId),
TotalComputationUsed: chunk.TotalComputationUsed,
NumberOfTransactions: uint16(chunk.NumberOfTransactions),
Index: chunk.Index,
EndState: flow.BytesToStateCommitment(chunk.EndState),
}
}

for i, serviceEvent := range execResult.ServiceEvents {
serviceEvents[i] = &flow.ServiceEvent{
Type: serviceEvent.Type,
Payload: serviceEvent.Payload,
}
}

return &flow.ExecutionResult{
PreviousResultID: flow.BytesToID(execResult.PreviousResultId),
BlockID: flow.BytesToID(execResult.BlockId),
Chunks: chunks,
ServiceEvents: serviceEvents,
}, nil
}

func BlockExecutionDataToMessage(
execData *flow.ExecutionData,
) (*entities.BlockExecutionData, error) {
Expand Down
80 changes: 54 additions & 26 deletions access/grpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -737,35 +782,18 @@ func (c *BaseClient) GetExecutionResultForBlockID(ctx context.Context, blockID f
return nil, newRPCError(err)
}

chunks := make([]*flow.Chunk, len(er.ExecutionResult.Chunks))
serviceEvents := make([]*flow.ServiceEvent, len(er.ExecutionResult.ServiceEvents))

for i, chunk := range er.ExecutionResult.Chunks {
chunks[i] = &flow.Chunk{
CollectionIndex: uint(chunk.CollectionIndex),
StartState: flow.BytesToStateCommitment(chunk.StartState),
EventCollection: flow.BytesToHash(chunk.EventCollection),
BlockID: flow.BytesToID(chunk.BlockId),
TotalComputationUsed: chunk.TotalComputationUsed,
NumberOfTransactions: uint16(chunk.NumberOfTransactions),
Index: chunk.Index,
EndState: flow.BytesToStateCommitment(chunk.EndState),
}
}
return convert.MessageToExecutionResult(er.ExecutionResult)
}

for i, serviceEvent := range er.ExecutionResult.ServiceEvents {
serviceEvents[i] = &flow.ServiceEvent{
Type: serviceEvent.Type,
Payload: serviceEvent.Payload,
}
func (c *BaseClient) GetExecutionResultByID(ctx context.Context, id flow.Identifier, opts ...grpc.CallOption) (*flow.ExecutionResult, error) {
er, err := c.rpcClient.GetExecutionResultByID(ctx, &access.GetExecutionResultByIDRequest{
Id: convert.IdentifierToMessage(id),
}, opts...)
if err != nil {
return nil, newRPCError(err)
}

return &flow.ExecutionResult{
PreviousResultID: flow.BytesToID(er.ExecutionResult.PreviousResultId),
BlockID: flow.BytesToID(er.ExecutionResult.BlockId),
Chunks: chunks,
ServiceEvents: serviceEvents,
}, nil
return convert.MessageToExecutionResult(er.ExecutionResult)
}

func (c *BaseClient) GetExecutionDataByBlockID(
Expand Down
192 changes: 187 additions & 5 deletions access/grpc/grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -1300,13 +1392,103 @@ func TestClient_GetExecutionResultForBlockID(t *testing.T) {

}))

t.Run("Internal error", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) {
rpc.On("GetLatestProtocolStateSnapshot", ctx, mock.Anything).
Return(nil, errInternal)
t.Run("Not found error", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) {
blockId := ids.New()

_, err := c.GetLatestProtocolStateSnapshot(ctx)
rpc.On("GetExecutionResultForBlockID", ctx, &access.GetExecutionResultForBlockIDRequest{
BlockId: blockId.Bytes(),
}).Return(nil, errNotFound)

res, err := c.GetExecutionResultForBlockID(ctx, blockId)
assert.Error(t, err)
assert.Equal(t, codes.Internal, status.Code(err))
assert.Nil(t, res)
assert.Equal(t, codes.NotFound, status.Code(err))
}))
}

func TestClient_GetExecutionResultByID(t *testing.T) {
ids := test.IdentifierGenerator()
t.Run("Success", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) {
blockID := ids.New()
executionResult := &entities.ExecutionResult{
PreviousResultId: ids.New().Bytes(),
BlockId: blockID.Bytes(),
Chunks: []*entities.Chunk{
{
CollectionIndex: 0,
StartState: ids.New().Bytes(),
EventCollection: ids.New().Bytes(),
BlockId: blockID.Bytes(),
TotalComputationUsed: 22,
NumberOfTransactions: 33,
Index: 0,
EndState: ids.New().Bytes(),
},
{
CollectionIndex: 1,
StartState: ids.New().Bytes(),
EventCollection: ids.New().Bytes(),
BlockId: blockID.Bytes(),
TotalComputationUsed: 222,
NumberOfTransactions: 333,
Index: 1,
EndState: ids.New().Bytes(),
},
},
ServiceEvents: []*entities.ServiceEvent{
{
Type: "serviceEvent",
Payload: []byte("{\"whatever\":21}"),
},
},
}
result := &access.ExecutionResultByIDResponse{
ExecutionResult: executionResult,
}
rpc.On("GetExecutionResultByID", ctx, &access.GetExecutionResultByIDRequest{
Id: blockID.Bytes(),
}).Return(result, nil)

res, err := c.GetExecutionResultByID(ctx, blockID)
assert.NoError(t, err)

require.NotNil(t, res)

require.Len(t, res.Chunks, len(executionResult.Chunks))
require.Len(t, res.ServiceEvents, len(executionResult.ServiceEvents))

assert.Equal(t, res.BlockID.Bytes(), executionResult.BlockId)
assert.Equal(t, res.PreviousResultID.Bytes(), executionResult.PreviousResultId)

for i, chunk := range res.Chunks {
assert.Equal(t, chunk.BlockID[:], executionResult.Chunks[i].BlockId)
assert.Equal(t, chunk.Index, executionResult.Chunks[i].Index)
assert.Equal(t, uint32(chunk.CollectionIndex), executionResult.Chunks[i].CollectionIndex)
assert.Equal(t, chunk.StartState[:], executionResult.Chunks[i].StartState)
assert.Equal(t, []byte(chunk.EventCollection), executionResult.Chunks[i].EventCollection)
assert.Equal(t, chunk.TotalComputationUsed, executionResult.Chunks[i].TotalComputationUsed)
assert.Equal(t, uint32(chunk.NumberOfTransactions), executionResult.Chunks[i].NumberOfTransactions)
assert.Equal(t, chunk.EndState[:], executionResult.Chunks[i].EndState)
}

for i, serviceEvent := range res.ServiceEvents {
assert.Equal(t, serviceEvent.Type, executionResult.ServiceEvents[i].Type)
assert.Equal(t, serviceEvent.Payload, executionResult.ServiceEvents[i].Payload)
}

}))

t.Run("Not found error", clientTest(func(t *testing.T, ctx context.Context, rpc *mocks.MockRPCClient, c *BaseClient) {
id := ids.New()

rpc.On("GetExecutionResultByID", ctx, &access.GetExecutionResultByIDRequest{
Id: id.Bytes(),
}).Return(nil, errNotFound)

res, err := c.GetExecutionResultByID(ctx, id)
assert.Error(t, err)
assert.Nil(t, res)
assert.Equal(t, codes.NotFound, status.Code(err))
}))
}

Expand Down

0 comments on commit 8c7f66a

Please sign in to comment.