Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Access] SendAndSubscribeTransactionStatuses endpoint implementation for Access Streaming API #5310

Conversation

Guitarheroua
Copy link
Collaborator

@Guitarheroua Guitarheroua commented Jan 29, 2024

Implementation of SendAndSubscribeTransactionStatuses endpoint for Access Streaming API.

Depends on: onflow/flow-emulator#613

FLIP: onflow/flips#229

@Guitarheroua Guitarheroua changed the title Guitarheroua/send and subscribe transaction statuses [Access] SendAndSubscribeTransactionStatuses endpoint implementation for Access Streaming API Jan 29, 2024
Guitarheroua and others added 7 commits February 1, 2024 00:33
…be-blocks' into guitarheroua/send-and-subscribe-transaction_statuses
…be-blocks' into guitarheroua/send-and-subscribe-transaction_statuses
…be-blocks' into guitarheroua/send-and-subscribe-transaction_statuses
…be-blocks' into guitarheroua/send-and-subscribe-transaction_statuses
@Guitarheroua Guitarheroua marked this pull request as ready for review February 19, 2024 08:56
@codecov-commenter
Copy link

codecov-commenter commented Feb 19, 2024

Codecov Report

Attention: Patch coverage is 72.45509% with 46 lines in your changes are missing coverage. Please review.

Project coverage is 56.79%. Comparing base (c0b292e) to head (6c092e1).

Files Patch % Lines
.../access/rpc/backend/backend_stream_transactions.go 67.70% 22 Missing and 9 partials ⚠️
engine/access/subscription/streamer.go 36.36% 4 Missing and 3 partials ⚠️
engine/common/rpc/convert/transactions.go 0.00% 6 Missing ⚠️
engine/access/rpc/backend/backend_transactions.go 87.50% 1 Missing ⚠️
...ss/rpc/backend/transactions_local_data_provider.go 87.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5310      +/-   ##
==========================================
+ Coverage   55.63%   56.79%   +1.16%     
==========================================
  Files        1036      800     -236     
  Lines      101233    81209   -20024     
==========================================
- Hits        56320    46124   -10196     
+ Misses      40590    31378    -9212     
+ Partials     4323     3707     -616     
Flag Coverage Δ
unittests 56.79% <72.45%> (+1.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Guitarheroua and others added 11 commits February 19, 2024 11:20
…f github.com:Guitarheroua/flow-go into guitarheroua/send-and-subscribe-transaction_statuses
…be-blocks' into guitarheroua/send-and-subscribe-transaction_statuses
…f github.com:Guitarheroua/flow-go into guitarheroua/send-and-subscribe-transaction_statuses
…eroua/send-and-subscribe-transaction_statuses
Copy link
Contributor

@peterargue peterargue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the logic in backendSubscribeTransactions quite captures what's needed. I believe it will return pending until the tx is indexed, which happens after the block is sealed.

Instead of checking if we have the tx result in the local storage, check if we know which block is supposed to include the tx. this is how we do it in GetTransactionResult
https://github.com/onflow/flow-go/blob/master/engine/access/rpc/backend/backend_transactions.go#L670-L682

This will tell us that the tx is included in a finalized block. once you know the block, you can just track the block's status. After finalized, we'll wait for it to be executed. You can check that by checking for the executionResult. If one exists, the tx is executed. From executed, we just need to check if the sealed.

access/handler.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
access/handler.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
}

if txInfo.lastTxStatus == flow.TransactionStatusSealed || txInfo.lastTxStatus == flow.TransactionStatusExpired {
return nil, fmt.Errorf("transaction final status %s was already reported %w", txInfo.lastTxStatus.String(), subscription.ErrResponseNotAvailableForBlock)
Copy link
Contributor

@peterargue peterargue Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about returning some form of "end of data" error here. Then the subscription can just close the connection without an error if that error is encountered?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the scenario I am talking about in: https://github.com/onflow/flow-go/pull/5310/files#r1530079851
This falls under consolidation of error handling for subscriptions. For this PR I would return nil, nil and leave a TODO to take care of it later with a proper termination logic. @peterargue thoughts?

Copy link
Contributor

@peterargue peterargue Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the challenge with nil, nil is it's unclear how the subscription would differentiate when a block should be skipped and when the stream should be shutdown. returning "end of data" would make it explicit

engine/access/subscription/streamer.go Outdated Show resolved Hide resolved
access/handler.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved
engine/access/rpc/backend/backend_stream_transactions.go Outdated Show resolved Hide resolved

// The same transaction status should not be reported, so return here with no response
if txInfo.lastTxStatus == txStatus {
return nil, fmt.Errorf("transaction status %s was already reported %w", txInfo.lastTxStatus.String(), subscription.ErrResponseNotAvailableForBlock)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a huge fan of using sentinels for branching between happy case scenarios, I think this return return nil, nil and streamer should send nothing in case it sees a response like this.

@@ -21,6 +21,9 @@ import (
"github.com/onflow/flow-go/storage"
)

// ErrTransactionNotInBlock represents an error indicating that the transaction is not found in the block.
var ErrTransactionNotInBlock = errors.New("transaction not in block")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this sentinel? To me it seems we can return storage.ErrNotFound instead of this.

Copy link
Contributor

@peterargue peterargue Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I requested this. It's because the methods used to lookup a transaction in a block need to lookup each collection in the guarantee list, then check if the transaction exists in one of the collections. Collections are synced by the Access node after the block is finalized, so it's common for there to be collections that aren't available yet when doing this lookup for non-sealed blocks.

This sentinel makes it easy for the caller to differentiate between a block that has missing collections, and one where all collections were indexed, but the tx just wasn't included.

continue
}

if errors.Is(err, storage.ErrNotFound) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is where we need to take a step back and consolidate error handling. An action for a future issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. In a separate PR, we should update all the other endpoints to use ErrBlockNotReady.

Comment on lines 1096 to 1097
subCtx, cancel := context.WithCancel(stream.Context())
defer cancel()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're not using cancel anymore, can you remove it

Suggested change
subCtx, cancel := context.WithCancel(stream.Context())
defer cancel()
ctx := stream.Context()

@@ -21,6 +21,9 @@ import (
"github.com/onflow/flow-go/storage"
)

// ErrTransactionNotInBlock represents an error indicating that the transaction is not found in the block.
var ErrTransactionNotInBlock = errors.New("transaction not in block")
Copy link
Contributor

@peterargue peterargue Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I requested this. It's because the methods used to lookup a transaction in a block need to lookup each collection in the guarantee list, then check if the transaction exists in one of the collections. Collections are synced by the Access node after the block is finalized, so it's common for there to be collections that aren't available yet when doing this lookup for non-sealed blocks.

This sentinel makes it easy for the caller to differentiate between a block that has missing collections, and one where all collections were indexed, but the tx just wasn't included.

Copy link
Contributor

@peterargue peterargue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a couple small comments, but otherwise looks good.

continue
}

if errors.Is(err, storage.ErrNotFound) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. In a separate PR, we should update all the other endpoints to use ErrBlockNotReady.

s.Assert().Equal(txID, sdk.Identifier(resp.GetId()))

expectedCounter++
finalTxStatus = resp.Status
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you have it also check that it receives notifications for each of the statuses in the processes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was checked, and it returns the next pattern "Pending"->"Finalized"->"Sealed". Should return all the statuses including "Executed", as agreed, this will be done in the next iteration, when this endpoint will be expanded with TX Result.

access/handler.go Outdated Show resolved Hide resolved
Copy link
Member

@durkmurder durkmurder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready to go

@peterargue peterargue added this pull request to the merge queue Mar 21, 2024
Merged via the queue into onflow:master with commit 022f21f Mar 21, 2024
55 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants