From 6d6a330622962406c9f61b3eff51496b126565ab Mon Sep 17 00:00:00 2001 From: Illia Malachyn Date: Tue, 17 Sep 2024 13:31:55 +0300 Subject: [PATCH] Add GetExecutionResultByID endpoint --- access/grpc/client.go | 4 ++ access/grpc/convert/convert.go | 32 +++++++++++ access/grpc/grpc.go | 35 +++--------- access/grpc/grpc_test.go | 100 +++++++++++++++++++++++++++++++-- examples/go.mod | 4 +- examples/go.sum | 2 + 6 files changed, 144 insertions(+), 33 deletions(-) diff --git a/access/grpc/client.go b/access/grpc/client.go index 7171ed797..37d06401b 100644 --- a/access/grpc/client.go +++ b/access/grpc/client.go @@ -232,6 +232,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) } diff --git a/access/grpc/convert/convert.go b/access/grpc/convert/convert.go index e52500a08..0c45da014 100644 --- a/access/grpc/convert/convert.go +++ b/access/grpc/convert/convert.go @@ -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) { diff --git a/access/grpc/grpc.go b/access/grpc/grpc.go index 51df44442..93a66b00e 100644 --- a/access/grpc/grpc.go +++ b/access/grpc/grpc.go @@ -701,35 +701,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( diff --git a/access/grpc/grpc_test.go b/access/grpc/grpc_test.go index d818f898e..8287b0ef4 100644 --- a/access/grpc/grpc_test.go +++ b/access/grpc/grpc_test.go @@ -1233,13 +1233,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)) })) } diff --git a/examples/go.mod b/examples/go.mod index b1c8aae8f..03a20899a 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.4 replace github.com/onflow/flow-go-sdk => ../ require ( - github.com/onflow/cadence v1.0.0-preview.38 + github.com/onflow/cadence v1.0.0-preview.52 github.com/onflow/flow-cli/flowkit v1.11.0 github.com/onflow/flow-go-sdk v0.41.17 github.com/spf13/afero v1.11.0 @@ -41,7 +41,7 @@ require ( github.com/logrusorgru/aurora/v4 v4.0.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/onflow/atree v0.7.0-rc.2 // indirect + github.com/onflow/atree v0.8.0-rc.6 // indirect github.com/onflow/crypto v0.25.1 // indirect github.com/onflow/flow/protobuf/go/flow v0.4.3 // indirect github.com/onflow/sdks v0.6.0-preview.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index cbdeadaee..262eb6949 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -104,6 +104,7 @@ github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVF github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= github.com/onflow/atree v0.6.1-0.20240429171449-cb486ceb1f9c/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= github.com/onflow/atree v0.7.0-rc.2/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= +github.com/onflow/atree v0.8.0-rc.6/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= github.com/onflow/cadence v0.42.7 h1:Qp9VYX901saO7wPwF/rwV4cMS+0mfWxnm9EqbYElYy4= github.com/onflow/cadence v0.42.7/go.mod h1:raU8va8QRyTa/eUbhej4mbyW2ETePfSaywoo36MddgE= github.com/onflow/cadence v1.0.0-M3/go.mod h1:odXGZZ/wGNA5mwT8bC9v8u8EXACHllB2ABSZK65TGL8= @@ -115,6 +116,7 @@ github.com/onflow/cadence v1.0.0-preview.31/go.mod h1:3LM1VgE9HkJ815whY/F0LYWULw github.com/onflow/cadence v1.0.0-preview.35/go.mod h1:jOwvPSSLTr9TvaKMs7KKiBYMmpdpNNAFxBsjMlrqVD0= github.com/onflow/cadence v1.0.0-preview.36/go.mod h1:jOwvPSSLTr9TvaKMs7KKiBYMmpdpNNAFxBsjMlrqVD0= github.com/onflow/cadence v1.0.0-preview.38/go.mod h1:jOwvPSSLTr9TvaKMs7KKiBYMmpdpNNAFxBsjMlrqVD0= +github.com/onflow/cadence v1.0.0-preview.52/go.mod h1:7wvvecnAZtYOspLOS3Lh+FuAmMeSrXhAWiycC3kQ1UU= github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onflow/crypto v0.25.1/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=