diff --git a/access/grpc/convert/convert.go b/access/grpc/convert/convert.go index 5c2ce0ea8..1165c5f9c 100644 --- a/access/grpc/convert/convert.go +++ b/access/grpc/convert/convert.go @@ -172,14 +172,28 @@ func BlockToMessage(b flow.Block) (*entities.Block, error) { return nil, err } + execReceipts, err := ExecutionReceiptMetaListToMessage(b.ExecutionReceiptMetaList) + if err != nil { + return nil, fmt.Errorf("error converting execution receipts: %w", err) + } + + execResults, err := ExecutionResultsToMessage(b.ExecutionResultsList) + if err != nil { + return nil, fmt.Errorf("error converting execution results: %w", err) + } + return &entities.Block{ - Id: b.BlockHeader.ID.Bytes(), - ParentId: b.BlockHeader.ParentID.Bytes(), - Height: b.BlockHeader.Height, - Timestamp: t, - CollectionGuarantees: CollectionGuaranteesToMessages(b.BlockPayload.CollectionGuarantees), - BlockSeals: BlockSealsToMessages(b.BlockPayload.Seals), - BlockHeader: header, + Id: b.BlockHeader.ID.Bytes(), + ParentId: b.BlockHeader.ParentID.Bytes(), + Height: b.BlockHeader.Height, + Timestamp: t, + CollectionGuarantees: CollectionGuaranteesToMessages(b.BlockPayload.CollectionGuarantees), + BlockSeals: BlockSealsToMessages(b.BlockPayload.Seals), + Signatures: b.Signatures, + ExecutionReceiptMetaList: execReceipts, + ExecutionResultList: execResults, + BlockHeader: header, + ProtocolStateId: b.ProtocolStateID.Bytes(), }, nil } @@ -193,7 +207,7 @@ func MessageToBlock(m *entities.Block) (flow.Block, error) { tc, err := MessageToTimeoutCertificate(m.BlockHeader.GetLastViewTc()) if err != nil { - return flow.Block{}, err + return flow.Block{}, fmt.Errorf("error converting timeout certificate: %w", err) } header := &flow.BlockHeader{ @@ -214,17 +228,31 @@ func MessageToBlock(m *entities.Block) (flow.Block, error) { guarantees, err := MessagesToCollectionGuarantees(m.GetCollectionGuarantees()) if err != nil { - return flow.Block{}, err + return flow.Block{}, fmt.Errorf("error converting collection guarantees: %w", err) } seals, err := MessagesToBlockSeals(m.GetBlockSeals()) if err != nil { - return flow.Block{}, err + return flow.Block{}, fmt.Errorf("error converting block seals: %w", err) + } + + executionReceiptsMeta, err := MessageToExecutionReceiptMetaList(m.GetExecutionReceiptMetaList()) + if err != nil { + return flow.Block{}, fmt.Errorf("error converting execution receipt meta list: %w", err) + } + + executionResults, err := MessageToExecutionResults(m.GetExecutionResultList()) + if err != nil { + return flow.Block{}, fmt.Errorf("error converting execution results: %w", err) } payload := &flow.BlockPayload{ - CollectionGuarantees: guarantees, - Seals: seals, + CollectionGuarantees: guarantees, + Seals: seals, + Signatures: m.GetSignatures(), + ExecutionReceiptMetaList: executionReceiptsMeta, + ExecutionResultsList: executionResults, + ProtocolStateID: flow.HashToID(m.GetProtocolStateId()), } return flow.Block{ @@ -233,6 +261,54 @@ func MessageToBlock(m *entities.Block) (flow.Block, error) { }, nil } +func MessageToExecutionReceiptMeta(m *entities.ExecutionReceiptMeta) (*flow.ExecutionReceiptMeta, error) { + if m == nil { + return nil, ErrEmptyMessage + } + + return &flow.ExecutionReceiptMeta{ + ExecutorID: flow.HashToID(m.GetExecutorId()), + ResultID: flow.HashToID(m.GetResultId()), + Spocks: m.GetSpocks(), + ExecutorSignature: m.GetExecutorSignature(), + }, nil +} + +func ExecutionReceiptMetaToMessage(receipt flow.ExecutionReceiptMeta) (*entities.ExecutionReceiptMeta, error) { + return &entities.ExecutionReceiptMeta{ + ExecutorId: receipt.ExecutorID.Bytes(), + ResultId: receipt.ResultID.Bytes(), + Spocks: receipt.Spocks, + ExecutorSignature: receipt.ExecutorSignature, + }, nil +} + +func MessageToExecutionReceiptMetaList(m []*entities.ExecutionReceiptMeta) ([]*flow.ExecutionReceiptMeta, error) { + results := make([]*flow.ExecutionReceiptMeta, len(m)) + + for i, entity := range m { + executionReceiptMeta, err := MessageToExecutionReceiptMeta(entity) + if err != nil { + return nil, err + } + results[i] = executionReceiptMeta + } + + return results, nil +} + +func ExecutionReceiptMetaListToMessage(receipts []*flow.ExecutionReceiptMeta) ([]*entities.ExecutionReceiptMeta, error) { + results := make([]*entities.ExecutionReceiptMeta, len(receipts)) + for i, receipt := range receipts { + executionReceiptMeta, err := ExecutionReceiptMetaToMessage(*receipt) + if err != nil { + return nil, err + } + results[i] = executionReceiptMeta + } + return results, nil +} + func BlockHeaderToMessage(b flow.BlockHeader) (*entities.BlockHeader, error) { t := timestamppb.New(b.Timestamp) tc, err := TimeoutCertificateToMessage(b.LastViewTimeoutCertificate) @@ -896,6 +972,65 @@ func MessageToExecutionResult(execResult *entities.ExecutionResult) (*flow.Execu }, nil } +func ExecutionResultToMessage(result flow.ExecutionResult) (*entities.ExecutionResult, error) { + chunks := make([]*entities.Chunk, len(result.Chunks)) + for i, chunk := range result.Chunks { + chunks[i] = &entities.Chunk{ + CollectionIndex: uint32(chunk.CollectionIndex), + StartState: IdentifierToMessage(flow.Identifier(chunk.StartState)), + EventCollection: chunk.EventCollection, + BlockId: chunk.BlockID.Bytes(), + TotalComputationUsed: chunk.TotalComputationUsed, + NumberOfTransactions: uint32(chunk.NumberOfTransactions), + Index: chunk.Index, + EndState: IdentifierToMessage(flow.Identifier(chunk.EndState)), + } + } + + serviceEvents := make([]*entities.ServiceEvent, len(result.ServiceEvents)) + for i, event := range result.ServiceEvents { + serviceEvents[i] = &entities.ServiceEvent{ + Type: event.Type, + Payload: event.Payload, + } + } + + return &entities.ExecutionResult{ + PreviousResultId: result.PreviousResultID.Bytes(), + BlockId: result.BlockID.Bytes(), + Chunks: chunks, + ServiceEvents: serviceEvents, + }, nil +} + +func MessageToExecutionResults(m []*entities.ExecutionResult) ([]*flow.ExecutionResult, error) { + results := make([]*flow.ExecutionResult, len(m)) + + for i, result := range m { + res, err := MessageToExecutionResult(result) + if err != nil { + return nil, err + } + results[i] = res + } + + return results, nil +} + +func ExecutionResultsToMessage(execResults []*flow.ExecutionResult) ([]*entities.ExecutionResult, error) { + results := make([]*entities.ExecutionResult, len(execResults)) + + for i, result := range execResults { + res, err := ExecutionResultToMessage(*result) + if err != nil { + return nil, err + } + results[i] = res + } + + return results, nil +} + func BlockExecutionDataToMessage( execData *flow.ExecutionData, ) (*entities.BlockExecutionData, error) { diff --git a/block.go b/block.go index 3a27c0ad6..8cda6cb3d 100644 --- a/block.go +++ b/block.go @@ -88,8 +88,19 @@ func BlockStatusFromString(s string) BlockStatus { // // A payload contains the collection guarantees and seals for a block. type BlockPayload struct { - CollectionGuarantees []*CollectionGuarantee - Seals []*BlockSeal + CollectionGuarantees []*CollectionGuarantee + Seals []*BlockSeal + Signatures [][]byte + ExecutionReceiptMetaList []*ExecutionReceiptMeta + ExecutionResultsList []*ExecutionResult + ProtocolStateID Identifier +} + +type ExecutionReceiptMeta struct { + ExecutorID Identifier + ResultID Identifier + Spocks [][]byte + ExecutorSignature []byte } // BlockSeal is the attestation by verification nodes that the transactions in a previously diff --git a/test/entities.go b/test/entities.go index 65d25147c..ab7a42287 100644 --- a/test/entities.go +++ b/test/entities.go @@ -127,6 +127,9 @@ type Blocks struct { guarantees *CollectionGuarantees seals *BlockSeals signatures *Signatures + ids *Identifiers + bytes *Bytes + chunks *ChuckExecutionResult } func BlockGenerator() *Blocks { @@ -135,6 +138,9 @@ func BlockGenerator() *Blocks { guarantees: CollectionGuaranteeGenerator(), seals: BlockSealGenerator(), signatures: SignaturesGenerator(), + ids: IdentifierGenerator(), + bytes: BytesGenerator(), + chunks: ChuckExecutionResultGenerator(), } } @@ -151,9 +157,32 @@ func (g *Blocks) New() *flow.Block { g.seals.New(), } + executionReceiptMetaList := []*flow.ExecutionReceiptMeta{{ + ExecutorID: g.ids.New(), + ResultID: g.ids.New(), + Spocks: [][]byte{g.bytes.New()}, + ExecutorSignature: g.bytes.New(), + }} + + serviceEvents := []*flow.ServiceEvent{{ + Type: string(g.bytes.New()), + Payload: g.bytes.New(), + }} + + executionResults := []*flow.ExecutionResult{{ + PreviousResultID: g.ids.New(), + BlockID: g.ids.New(), + Chunks: []*flow.Chunk{g.chunks.New()}, + ServiceEvents: serviceEvents, + }} + payload := flow.BlockPayload{ - CollectionGuarantees: guarantees, - Seals: seals, + CollectionGuarantees: guarantees, + Seals: seals, + Signatures: g.signatures.New(), + ExecutionReceiptMetaList: executionReceiptMetaList, + ExecutionResultsList: executionResults, + ProtocolStateID: g.ids.New(), } return &flow.Block{ @@ -639,3 +668,28 @@ func (g *Bytes) New() []byte { } return randomBytes } + +type ChuckExecutionResult struct { + ids *Identifiers + bytes *Bytes +} + +func ChuckExecutionResultGenerator() *ChuckExecutionResult { + return &ChuckExecutionResult{ + ids: IdentifierGenerator(), + bytes: BytesGenerator(), + } +} + +func (g *ChuckExecutionResult) New() *flow.Chunk { + return &flow.Chunk{ + CollectionIndex: 42, + StartState: flow.StateCommitment(g.ids.New()), + EventCollection: g.bytes.New(), + BlockID: g.ids.New(), + TotalComputationUsed: 42, + NumberOfTransactions: 42, + Index: 42, + EndState: flow.StateCommitment(g.ids.New()), + } +}