Skip to content

Commit

Permalink
Merge pull request #757 from The-K-R-O-K/illia-malachyn/752-get-execu…
Browse files Browse the repository at this point in the history
…tion-result-by-id-endpoint

Add GetExecutionResultByID endpoint
  • Loading branch information
franklywatson authored Sep 18, 2024
2 parents 3048f51 + b87f9c7 commit 9b49f3e
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 31 deletions.
4 changes: 4 additions & 0 deletions access/grpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,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 @@ -575,6 +575,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
35 changes: 9 additions & 26 deletions access/grpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,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
100 changes: 95 additions & 5 deletions access/grpc/grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1392,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 9b49f3e

Please sign in to comment.