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

GraphQL API changes to support pre-confirmations #2752

Open
wants to merge 29 commits into
base: master
Choose a base branch
from

Conversation

rafal-ch
Copy link
Contributor

@rafal-ch rafal-ch commented Feb 24, 2025

Closes #2771

Description

This PR contains the changes to the GraphQL API supporting the upcoming pre-confirmations feature.

Summary:

  1. TransactionStatus has grown three new variants: SuccessDuringBlockProductionStatus, SqueezedOutDuringBlockProductionStatus and FailureDuringBlockProductionStatus
    1. these new variants should be considered as pre-confirmations, i.e. they will be gossiped and provided by the client even before the entire block containing the transaction is produced. Technically, they will be signed and gossiped as soon as the transaction was executed.
    2. the old variants will be created in exactly the same way as they were before this change
  2. Introduction of TransactionStatusStorage type, which is just an old TransactionStatus under the new name. Ultimately, we need to convert it to a new type which only contains Success and Failure variants, since only these two states are only ever persisted in the DB

Before requesting review

  • I have reviewed the code myself

After merging, notify other teams

Comment on lines 338 to 341
type FailureDuringBlockProductionStatus {
blockHeight: U32!
}

Choose a reason for hiding this comment

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

What can lead to a transaction failing with a FailureDuringBlockProductionStatus?

I’ve noticed this status doesn’t include a reason property like FailureStatus does.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What can lead to a transaction failing with a FailureDuringBlockProductionStatus?

There could be a change in state (for example, different gas price) between these two points in time:

  1. executor grabs the transaction from the TxPool (where it sits, validated and ready to be executed)
  2. executor actually tries to execute the transaction

I’ve noticed this status doesn’t include a reason property like FailureStatus does.

The exact shape of the API is not finalized yet. We decided to add the reason to FailureDuringBlockProductionStatus as well. There will be more commits added to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reason is now added to the FailureDuringBlockProductionStatus variant

@rafal-ch rafal-ch changed the title Rafal/preconfirmations api changes GraphQL API changes to support pre-confirmations Feb 24, 2025
@rafal-ch rafal-ch marked this pull request as ready for review February 25, 2025 15:06
@rafal-ch rafal-ch self-assigned this Feb 25, 2025
@rafal-ch rafal-ch requested a review from a team as a code owner February 26, 2025 08:17
@@ -187,8 +190,11 @@ impl TryFrom<ProgramState> for fuel_vm::ProgramState {
pub enum TransactionStatus {
SubmittedStatus(SubmittedStatus),
SuccessStatus(SuccessStatus),
SuccessDuringBlockProductionStatus(SuccessDuringBlockProductionStatus),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we use a name which relates more closely to the pre-confirmations? For example SuccessPreConfirmed, FailurePreConfirmed, etc.

cc: @xgreenx

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, maybe this name is better, buy you can ask in Slack channel what SDKs prefer more=D

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed in a473dbb, as agreed with SDK.

The only minor drawback I see is that in case in the future other components than BlockProducer are able to create preconfirmations we'll not carry the information about the preconfirmation source. Most likely a YAGNI case, that's why I didn't add any kind of "source" field to preconfirmations.

@@ -187,8 +190,11 @@ impl TryFrom<ProgramState> for fuel_vm::ProgramState {
pub enum TransactionStatus {
SubmittedStatus(SubmittedStatus),
SuccessStatus(SuccessStatus),
SuccessDuringBlockProductionStatus(SuccessDuringBlockProductionStatus),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, maybe this name is better, buy you can ask in Slack channel what SDKs prefer more=D

@@ -67,7 +67,7 @@ pub struct TransactionStatuses;
impl Mappable for TransactionStatuses {
type Key = Bytes32;
type OwnedKey = Self::Key;
type Value = TransactionStatus;
type Value = TransactionStatusStorage; // TODO[RC]: TransactionStatusStorage should ultimately only contain `Success` and `Failed` variants. We don't need to persist any other states.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you want to solve it in this PR, or in follow-up?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Follow-up: #2794
Commit: 1de525f

Comment on lines 132 to 136
/// The transaction failed to execute and was included in a block.
Failed,
/// Transaction was eligible for execution and inclusion in the block but
/// it failed during the execution.
FailureDuringBlockProduction,
Copy link
Collaborator

Choose a reason for hiding this comment

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

IT would be nice to have parity on Failed and Failure

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated in d702ca7

@@ -333,7 +334,7 @@ impl From<&PoolTransaction> for CheckedTransaction {
/// The status of the transaction during its life from the tx pool until the block.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TransactionStatus {
pub enum TransactionStatusStorage {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to use some other name, since we also use this type as a result of execution, maybe TransactionExecutionStatus , idk

Copy link
Contributor Author

@rafal-ch rafal-ch Mar 4, 2025

Choose a reason for hiding this comment

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

Updated in 4667fc3

TransactionExecutionStatus already exists in executor: https://github.com/FuelLabs/fuel-core/blob/master/crates/types/src/services/executor.rs#L185-L190

We also seem to already have what we need (albeit there are differences in fields) in the form of TransactionExecutionResult: https://github.com/FuelLabs/fuel-core/blob/master/crates/types/src/services/executor.rs#L195-L218

For now I used the explicit qualification (txpool::TransactionExecutionStatus) to resolve conflicts to avoid introducing yet another name for transaction status.

Follow-up issue for grooming: #2795

async fn transaction(
&self,
ctx: &Context<'_>,
) -> Option<async_graphql::Result<Transaction>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
) -> Option<async_graphql::Result<Transaction>> {
) -> async_graphql::Result<Option<Transaction>> {

) -> Option<async_graphql::Result<Transaction>> {
self.tx_id.map(|tx_id| {
let query = ctx.read_view()?;
let transaction = query.transaction(&tx_id)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Usually pre-confirmed transaction will live in TxPool, not in the database, so I would suggest to go there=D

})
}

async fn receipts(&self) -> Option<async_graphql::Result<Vec<Receipt>>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need to return an error? Looks like we can't have error here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did it like that for consistency with already existing types, like SuccessStatus here.

}

#[Object]
impl SuccessDuringBlockProductionStatus {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comments as for failure

#[derive(Debug)]
pub struct SuccessDuringBlockProductionStatus {
pub tx_pointer: TxPointer,
pub tx_id: Option<TxId>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

tx_id always will exist in pre-confirmation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated in 87aaf7c

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.

Pre-confirmations: Implement the GraphQL API changes
4 participants