Conversation
|
| return nil, fmt.Errorf("failed to sign tiered attempt for txID: %v: %w", tx.ID, err) | ||
| } | ||
|
|
||
| d.lggr.Infow("Intercepting attempt for tx", "txID", tx.ID, "hash", signedTx.Hash(), "toAddress", tx.ToAddress, "gasLimit", tieredGasLimit, |
There was a problem hiding this comment.
Does this need to be info level?
I'd rather have an info level log after the attempt has been sent to the OFA to print all the context
There was a problem hiding this comment.
The existing log has inaccurate information of the transaction since it has the wrong details (gasLimit). This log is the only way to get the hash of the different OFAs accordingly so we can track them on-chain.
There was a problem hiding this comment.
What if we would log this directly after a tx gets sent to an OFA? Then the hash and gasLimit would be correct and we wouldn't have to distinguish mentally between intercepted and non-intercepted attempts.
| @@ -38,10 +36,10 @@ type multiOfaClient struct { | |||
| var _ txm.Client = (*multiOfaClient)(nil) | |||
|
|
|||
| // newMultiOfaClient builds backends from URLs: index 0 is primary (outcome and nonces); the rest are secondaries. | |||
There was a problem hiding this comment.
| // newMultiOfaClient builds backends from URLs: index 0 is primary (outcome and nonces); the rest are secondaries. | |
| // NewMultiOfaClient builds backends from URLs: index 0 is primary (outcome and nonces); the rest are secondaries. |
There was a problem hiding this comment.
We need to be able to import this client for local testing, similar to the rest of the clients.
There was a problem hiding this comment.
Ah ok, clear. Can you point me to the way you do local testing for this? Is there a doc/some guidelines?
| // createAttemptWithTiering creates a tiered attempt that has a different gas limit for each OFA backend, by reserving the last two digits. | ||
| // Each OFA has 10 values spaced 10 units apart for the gas limit so there is room for feed-specific tiers per OFA in the future. | ||
| // Unfortunately, the per-OFA attempts are not tracked by the txm. We can track them by looking at the individual logs per attempt stored. | ||
| func (d *ofaBackend) createAttemptWithTiering(ctx context.Context, tx *types.Transaction, attempt *types.Attempt) (*types.Attempt, error) { |
There was a problem hiding this comment.
I'd prefer to not use the keyword tiering here since this is more about tracking, and the term might get confused with feed tiering
There was a problem hiding this comment.
Maybe createAttemptWithAccountability or createAttemptForOFAAccountability?
We can add to the docs that we've reserved space to support feed tiering in the future.
There was a problem hiding this comment.
How about createAttemptWithTracedFee
lhmerino
left a comment
There was a problem hiding this comment.
Looks great, thank you!
I have just one safety comment regarding the gas limit.
| if suffix >= 100 { | ||
| return 0, fmt.Errorf("cannot calculate OFA gas limit tier for %s: suffix %d is not two digits", k.name(), suffix) | ||
| } | ||
| return gasLimit - gasLimit%100 + suffix, nil |
There was a problem hiding this comment.
I would suggest bumping the gas limit to the next hundred to ensure the new gas limit is always greater than or equal to the original gas limit for safety reasons.
Could be as simple as the following statement after applying the suffix change tieredLimit := gasLimit - (gasLimit % 100) + suffix:
if tieredLimit < gasLimit {
tieredLimit += 100
}
There was a problem hiding this comment.
Following on, might also be nice to make 100 be a constant since its used in multiple locations as well.
There was a problem hiding this comment.
Pull request overview
This PR introduces gas-limit “tiering” for dual-broadcast via the multi-OFA client so downstream systems can infer which OFA relay included a transaction on-chain by inspecting the last two digits of the gas limit.
Changes:
- Re-sign dual-broadcast transactions with a tiered gas limit suffix prior to OFA submission.
- Export and refactor
NewMultiOfaClientto depend on narrower interfaces and pass keystore support through to Nova. - Update/add unit tests and fixtures to use dynamic-fee transactions and validate tiering behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/txm/clientwrappers/dualbroadcast/selector.go | Switches to the exported NewMultiOfaClient constructor. |
| pkg/txm/clientwrappers/dualbroadcast/ofa_backend.go | Adds gas-limit tiering via re-signing; refactors keystore/txstore interfaces. |
| pkg/txm/clientwrappers/dualbroadcast/ofa_backend_test.go | Updates fixtures to dynamic-fee txs, adds tiering tests, introduces a test keystore helper. |
| pkg/txm/clientwrappers/dualbroadcast/multiofa_client.go | Exports constructor and adjusts dependencies to interfaces; passes keystore to Nova client creation. |
| pkg/txm/clientwrappers/dualbroadcast/multiofa_client_test.go | Updates tests to use NewMultiOfaClient and provide a keystore where needed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -38,10 +36,10 @@ type multiOfaClient struct { | |||
| var _ txm.Client = (*multiOfaClient)(nil) | |||
|
|
|||
| // newMultiOfaClient builds backends from URLs: index 0 is primary (outcome and nonces); the rest are secondaries. | |||
| if !attempt.Fee.ValidDynamic() { | ||
| return nil, errors.New("attempt is not a dynamic fee attempt") // We could potentially support legacy transactions, but dynamic transactions are the default so this is ok. | ||
| } |
| GasTipCap: attempt.Fee.GasTipCap.ToInt(), | ||
| Data: tx.Data, | ||
| } | ||
|
|
| func (k ofa) tieredGasLimit(gasLimit uint64) (uint64, error) { | ||
| suffix := (uint64(k) + 1) * 10 | ||
| if suffix >= tieringSpace { | ||
| return 0, fmt.Errorf("cannot calculate OFA gas limit tier for %s: suffix %d is not in the range 0-%d", k.name(), suffix, tieringSpace-1) | ||
| } | ||
| tieredLimit := gasLimit - gasLimit%tieringSpace + suffix |
SVR needs an easy way to keep track which OFA included the transaction on-chain. To accomplish this we reserve the last two digits of the gas limit and we assign 10 values space for each one of them, for example:
... and so on.
For now only the first position is used, i.e. 10, 20, etc. However in the future we might want to include per-feed tiering across each OFA, so we reserve 10 spaces upfront.