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

Update TxStore to use parent context created at initialization #10735

Merged
merged 10 commits into from
Oct 4, 2023

Conversation

amit-momin
Copy link
Contributor

@amit-momin amit-momin commented Sep 20, 2023

BCI-1585

  • Updated TxStore methods to use both the parent context created at initialization and (if available) the context passed in as a parameter
  • Removed pg.Opts from TxStore methods
  • Updated relevant methods to use a dedicated context parameter where one was previously passed in through pg.Opts
  • Updated upstream callers of these methods including services external to the TXM

@github-actions
Copy link
Contributor

I see that you haven't updated any CHANGELOG files. Would it make sense to do so?

@github-actions
Copy link
Contributor

I see that you haven't updated any README files. Would it make sense to do so?

@amit-momin amit-momin marked this pull request as ready for review September 20, 2023 17:50
Copy link
Collaborator

@samsondav samsondav left a comment

Choose a reason for hiding this comment

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

Why are we removing this?

@amit-momin
Copy link
Contributor Author

Why are we removing this?

We want TXM to solely be in charge of the TxStore lifecycle so we wanted to move all of the methods to use a parent context created at TxStore initialization. This is also part of the work to untangle the TXM from external components so we didn't want to expose pg.Opts anymore on TxStore methods.

@jmank88
Copy link
Contributor

jmank88 commented Sep 20, 2023

Why are we removing this?

We want TXM to solely be in charge of the TxStore lifecycle so we wanted to move all of the methods to use a parent context created at TxStore initialization. This is also part of the work to untangle the TXM from external components so we didn't want to expose pg.Opts anymore on TxStore methods.

Removing pg.Opts from the exported API makes sense, but why remove context.Context rather than use it in the traditional way? I'm concerned about upstream callers depending on the context behavior in subtle ways - switching from non-blocking to blocking is a major change.

@prashantkumar1982
Copy link
Contributor

Why are we removing this?

We want TXM to solely be in charge of the TxStore lifecycle so we wanted to move all of the methods to use a parent context created at TxStore initialization. This is also part of the work to untangle the TXM from external components so we didn't want to expose pg.Opts anymore on TxStore methods.

Removing pg.Opts from the exported API makes sense, but why remove context.Context rather than use it in the traditional way? I'm concerned about upstream callers depending on the context behavior in subtle ways - switching from non-blocking to blocking is a major change.

Yes, we should actually use Context in all places that have origin from an external caller.
For example, every downstream dependency of CreateTransaction() should use the Context that's coming from the caller.
Similarly, the ec.ProcessHead() is already passing us a Context, and we se should use it everywhere that we end up calling.

Only those functions which originate from within the TXM's poller threads can ignore passing in Context. But they still need to use the Context stored in the TxStore.

The idea is that if an external caller's call is stuck in a DB operation, and the external caller wants to cancel it, we should be able to cancel that call.
For other calls that are within TXM's internal lifecycle, they should use TxStore's member Context, so if TxStore is closing, all these calls can quickly return.

if err != nil {
return tx, errors.Wrap(err, "Txm#CreateTransaction")
}

tx, err = b.txStore.CreateTransaction(txRequest, b.chainID, qs...)
tx, err = b.txStore.CreateTransaction(txRequest, b.chainID)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this call is ultimately coming from an external caller, we should take a param ctx from external caller, and pass the ctx all the way to the evmTxStore.CreateTx(), and in to the DB call.
Thus, if the caller wants to abandon their call, they should be able to.

@@ -96,7 +95,7 @@ type TxHistoryReaper[CHAIN_ID types.ID] interface {
}

type UnstartedTxQueuePruner interface {
PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, qopts ...pg.QOpt) (n int64, err error)
PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, queryTimeout time.Duration) (n int64, err error)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should also take ctx, which is coming from the external caller.

}

// Only to be used directly for atomic transactions internal to the tx store
func (o *evmTxStore) PreloadTxesAtomic(attempts []TxAttempt, qopts ...pg.QOpt) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

If this is internal, please rename to preloadTxesAtomic. No need to export this function

@amit-momin
Copy link
Contributor Author

Why are we removing this?

We want TXM to solely be in charge of the TxStore lifecycle so we wanted to move all of the methods to use a parent context created at TxStore initialization. This is also part of the work to untangle the TXM from external components so we didn't want to expose pg.Opts anymore on TxStore methods.

Removing pg.Opts from the exported API makes sense, but why remove context.Context rather than use it in the traditional way? I'm concerned about upstream callers depending on the context behavior in subtle ways - switching from non-blocking to blocking is a major change.

Yes, we should actually use Context in all places that have origin from an external caller. For example, every downstream dependency of CreateTransaction() should use the Context that's coming from the caller. Similarly, the ec.ProcessHead() is already passing us a Context, and we se should use it everywhere that we end up calling.

Only those functions which originate from within the TXM's poller threads can ignore passing in Context. But they still need to use the Context stored in the TxStore.

The idea is that if an external caller's call is stuck in a DB operation, and the external caller wants to cancel it, we should be able to cancel that call. For other calls that are within TXM's internal lifecycle, they should use TxStore's member Context, so if TxStore is closing, all these calls can quickly return.

I see so I should be using both the context that's passed and the one created during TxStore's initialization. @jmank88 would you have any examples where we have the design pattern to chain multiple contexts?

@jmank88
Copy link
Contributor

jmank88 commented Sep 22, 2023

Why are we removing this?

We want TXM to solely be in charge of the TxStore lifecycle so we wanted to move all of the methods to use a parent context created at TxStore initialization. This is also part of the work to untangle the TXM from external components so we didn't want to expose pg.Opts anymore on TxStore methods.

Removing pg.Opts from the exported API makes sense, but why remove context.Context rather than use it in the traditional way? I'm concerned about upstream callers depending on the context behavior in subtle ways - switching from non-blocking to blocking is a major change.

Yes, we should actually use Context in all places that have origin from an external caller. For example, every downstream dependency of CreateTransaction() should use the Context that's coming from the caller. Similarly, the ec.ProcessHead() is already passing us a Context, and we se should use it everywhere that we end up calling.
Only those functions which originate from within the TXM's poller threads can ignore passing in Context. But they still need to use the Context stored in the TxStore.
The idea is that if an external caller's call is stuck in a DB operation, and the external caller wants to cancel it, we should be able to cancel that call. For other calls that are within TXM's internal lifecycle, they should use TxStore's member Context, so if TxStore is closing, all these calls can quickly return.

I see so I should be using both the context that's passed and the one created during TxStore's initialization. @jmank88 would you have any examples where we have the design pattern to chain multiple contexts?

Normally contexts are not meant to be stored, and they should only branch, never merge. However, if we are stuck with legacy code, then we can use a new 1.21 feature context.AfterFunc to have one cancel the other.

@@ -917,7 +917,7 @@ func (lsn *listenerV2) enqueueForceFulfillment(
requestID := common.BytesToHash(p.req.req.RequestID().Bytes())
subID := p.req.req.SubID()
requestTxHash := p.req.req.Raw().TxHash
etx, err = lsn.txm.CreateTransaction(txmgr.TxRequest{
etx, err = lsn.txm.CreateTransaction(context.TODO(), txmgr.TxRequest{
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem quite right. If this context is actually used we should probably pass in a non-test object.

common/txmgr/strategies.go Outdated Show resolved Hide resolved
common/txmgr/txmgr.go Outdated Show resolved Hide resolved
@amit-momin amit-momin force-pushed the txm/BCI-1585 branch 2 times, most recently from 29c5398 to fe3f8c6 Compare September 25, 2023 17:53
SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error
SaveInProgressAttempt(attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
SaveInsufficientFundsAttempt(timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error
SaveReplacementInProgressAttempt(oldAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error
SaveReplacementInProgressAttempt(oldAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
SaveSentAttempt(timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error
SetBroadcastBeforeBlockNum(blockNum int64, chainID CHAIN_ID) error
Copy link
Contributor

Choose a reason for hiding this comment

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

This one too originates from ec.ProcessHead(), where we get an external context.
I guess there are more such functions from the above.

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 ended up leaving the methods that weren't passed a context upstream through pg.Opts alone but I can wire them up as well

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've added a context parameter to the rest of the TxStore methods and wired them up to contexts upstream except for UpdateTxAttemptInProgressToBroadcast which will be handled in this PR

Copy link
Contributor

@prashantkumar1982 prashantkumar1982 left a comment

Choose a reason for hiding this comment

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

Looks good to me, except the few places in TxStore interface that still are missing ctx, and are called from upstream callers.

@amit-momin amit-momin force-pushed the txm/BCI-1585 branch 2 times, most recently from 32c5e45 to 96e95c8 Compare September 26, 2023 19:09
Copy link
Contributor

@makramkd makramkd left a comment

Choose a reason for hiding this comment

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

VRF+BHS changes LGTM

@prashantkumar1982 prashantkumar1982 added this pull request to the merge queue Oct 4, 2023
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 4, 2023
@prashantkumar1982 prashantkumar1982 added this pull request to the merge queue Oct 4, 2023
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 4, 2023
@prashantkumar1982 prashantkumar1982 added this pull request to the merge queue Oct 4, 2023
@cl-sonarqube-production
Copy link

Merged via the queue into develop with commit 61ccf8b Oct 4, 2023
83 checks passed
@prashantkumar1982 prashantkumar1982 deleted the txm/BCI-1585 branch October 4, 2023 07:56
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