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

feat: add auto gas and fee estimations #3510

Merged
merged 3 commits into from
Jun 3, 2024

Conversation

vgonkivs
Copy link
Member

@vgonkivs vgonkivs commented May 29, 2024

Closes #3342

Overview

Some points to consider:

  • The current version of EstimateGas utilizes Simulate that brings additional roundtrips to the estimation process. As we discussed internally with @cmwaters we should try to get rid of roundtrips in favour of static gas estimations(for different types of messages), as it has been done for blob estimation.
  • ideally I'd add two different Fee handlers to the txClient that estimates gas/fee for PFB transactions and all other types of txs. But it will make sense after reaching the proposal described in 1.

@vgonkivs vgonkivs requested a review from a team as a code owner May 29, 2024 11:27
@vgonkivs vgonkivs requested review from rach-id and evan-forbes and removed request for a team May 29, 2024 11:27
Copy link
Contributor

coderabbitai bot commented May 29, 2024

Walkthrough

The changes introduce several updates to the pkg/user package, including importing new packages, renaming receiver variables for consistency, refactoring test functions, and modifying the txBuilder method in the Signer struct to handle message parameters and return errors. These modifications aim to improve code clarity, maintainability, and functionality, including automatic gas estimation for transactions.

Changes

Files Change Summary
pkg/user/tx_client.go Added package imports, changed Option type signature, renamed receiver variable s to client in methods.
pkg/user/tx_client_test.go Renamed receiver variable in test functions, refactored test functions to include subtests for different scenarios.
pkg/user/signer.go Updated txBuilder method to accept msgs parameter, return client.TxBuilder and error, and handle msgs appropriately.

Sequence Diagram(s) (Beta)

sequenceDiagram
    participant User
    participant TxClient
    participant Signer
    participant CosmosSDK

    User->>TxClient: SubmitPayForBlob
    TxClient->>Signer: Build Transaction with msgs
    Signer->>CosmosSDK: Estimate Gas
    CosmosSDK-->>Signer: Gas Estimate
    Signer-->>TxClient: TxBuilder with Gas
    TxClient-->>User: Transaction Result
Loading

Assessment against linked issues

Objective Addressed Explanation
Signer automatically estimates gas (#3342)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@celestia-bot celestia-bot requested a review from a team May 29, 2024 11:27
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Outside diff range and nitpick comments (2)
pkg/user/tx_client_test.go (1)

46-68: Consider adding more detailed assertions in TestSubmitPayForBlob to verify the transaction details.

It would be beneficial to include assertions that check specific transaction details beyond just the response code and gas wanted, to ensure that the transactions are formed and processed correctly.

pkg/user/tx_client.go (1)

34-34: Document the Option type more thoroughly.

It would be helpful to add more detailed documentation for the Option type, explaining its purpose and usage within the TxClient configuration.

Comment on lines +275 to +284
func (s *Signer) txBuilder(msgs []sdktypes.Msg, opts ...TxOption) (client.TxBuilder, error) {
builder := s.enc.NewTxBuilder()
if err := builder.SetMsgs(msgs...); err != nil {
return nil, err
}

for _, opt := range opts {
builder = opt(builder)
}
return builder
return builder, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor txBuilder to simplify error handling and improve readability.

- if err := builder.SetMsgs(msgs...); err != nil {
-   return nil, err
- }
+ err := builder.SetMsgs(msgs...)
+ if err != nil {
+   return nil, err
+ }

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func (s *Signer) txBuilder(msgs []sdktypes.Msg, opts ...TxOption) (client.TxBuilder, error) {
builder := s.enc.NewTxBuilder()
if err := builder.SetMsgs(msgs...); err != nil {
return nil, err
}
for _, opt := range opts {
builder = opt(builder)
}
return builder
return builder, nil
func (s *Signer) txBuilder(msgs []sdktypes.Msg, opts ...TxOption) (client.TxBuilder, error) {
builder := s.enc.NewTxBuilder()
err := builder.SetMsgs(msgs...)
if err != nil {
return nil, err
}
for _, opt := range opts {
builder = opt(builder)
}
return builder, nil

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Outside diff range and nitpick comments (2)
pkg/user/tx_client.go (2)

8-8: Consider documenting the purpose of the math import.

Adding a comment explaining why the math package is imported could help maintainability, especially for future developers who might wonder about its usage.


Line range hint 381-411: Enhance error handling in ConfirmTx.

The method for determining whether to retry a transaction based on the error message string is brittle. Consider implementing a more robust mechanism or using error types/codes for this purpose.

Refactor the error handling to use error types or specific error codes instead of relying on string matching, which is prone to breaking with changes in error message text.

Comment on lines +423 to +439
func (client *TxClient) estimateGas(ctx context.Context, txBuilder client.TxBuilder) (uint64, error) {
_, _, err := client.signer.signTransaction(txBuilder)
if err != nil {
return 0, err
}

txBytes, err := s.signer.EncodeTx(txBuilder.GetTx())
txBytes, err := client.signer.EncodeTx(txBuilder.GetTx())
if err != nil {
return 0, err
}

resp, err := sdktx.NewServiceClient(s.grpc).Simulate(ctx, &sdktx.SimulateRequest{
resp, err := sdktx.NewServiceClient(client.grpc).Simulate(ctx, &sdktx.SimulateRequest{
TxBytes: txBytes,
})
if err != nil {
return 0, err
}

gasLimit := uint64(float64(resp.GasInfo.GasUsed) * s.gasMultiplier)
gasLimit := uint64(float64(resp.GasInfo.GasUsed) * client.gasMultiplier)
Copy link
Contributor

Choose a reason for hiding this comment

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

Optimize gas estimation logic in estimateGas.

The method could benefit from caching or other optimizations to reduce the overhead of repeated gas estimations, especially in high-throughput scenarios.

Consider implementing caching mechanisms or other performance optimizations to reduce the computational overhead of gas estimation.

Comment on lines 233 to 286
func (client *TxClient) BroadcastTx(ctx context.Context, msgs []sdktypes.Msg, opts ...TxOption) (*sdktypes.TxResponse, error) {
client.mtx.Lock()
defer client.mtx.Unlock()
account, err := client.getAccountNameFromMsgs(msgs)
if err != nil {
return nil, err
}

if err := s.checkAccountLoaded(ctx, account); err != nil {
if err := client.checkAccountLoaded(ctx, account); err != nil {
return nil, err
}

tx, account, _, err := s.signer.SignTx(msgs, opts...)
txBuilder, err := client.signer.txBuilder(msgs, opts...)
if err != nil {
return nil, err
}

txBytes, err := s.signer.EncodeTx(tx)
estimated := false
for _, coin := range txBuilder.GetTx().GetFee() {
if coin.Denom == appconsts.BondDenom {
estimated = true
break
}
}

gasLimit := txBuilder.GetTx().GetGas()
if float32(gasLimit) < appconsts.DefaultMinGasPrice {
if !estimated {
// add at least 1utia as fee to builder as it affects gas calculation.
txBuilder.SetFeeAmount(sdktypes.NewCoins(sdktypes.NewCoin(appconsts.BondDenom, sdktypes.NewInt(1))))
}
gasLimit, err = client.estimateGas(ctx, txBuilder)
if err != nil {
return nil, err
}
txBuilder.SetGasLimit(gasLimit)
}

if !estimated {
fee := int64(math.Ceil(appconsts.DefaultMinGasPrice * float64(gasLimit)))
txBuilder.SetFeeAmount(sdktypes.NewCoins(sdktypes.NewCoin(appconsts.BondDenom, sdktypes.NewInt(fee))))
}

account, _, err = client.signer.signTransaction(txBuilder)
if err != nil {
return nil, err
}

return s.broadcastTx(ctx, txBytes, account)
txBytes, err := client.signer.EncodeTx(txBuilder.GetTx())
if err != nil {
return nil, err
}

return client.broadcastTx(ctx, txBytes, account)
Copy link
Contributor

Choose a reason for hiding this comment

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

Review complex transaction handling in BroadcastTx.

The function handles multiple aspects of transaction processing, including locking, account loading, gas estimation, and broadcasting. Consider breaking down this function into smaller, more focused functions to enhance readability and maintainability.

Consider refactoring to separate concerns, such as account loading, gas estimation, and transaction broadcasting into distinct methods.

)

const (
DefaultPollTime = 3 * time.Second
DefaultGasMultiplier float64 = 1.1
)

type Option func(s *TxClient)
type Option func(client *TxClient)
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor Option type function signature for clarity.

The change from func(s *TxClient) to func(client *TxClient) improves clarity by using a more descriptive parameter name. This is a good practice as it enhances code readability.

Copy link
Contributor

@cmwaters cmwaters left a comment

Choose a reason for hiding this comment

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

Good work! Added a few comments

pkg/user/tx_client.go Outdated Show resolved Hide resolved
pkg/user/tx_client.go Outdated Show resolved Hide resolved
pkg/user/tx_client.go Show resolved Hide resolved
pkg/user/tx_client.go Show resolved Hide resolved
pkg/user/tx_client_test.go Outdated Show resolved Hide resolved
Comment on lines +209 to +212
gasLimit := uint64(float64(types.DefaultEstimateGas(blobSizes)) * client.gasMultiplier)
fee := uint64(math.Ceil(appconsts.DefaultMinGasPrice * float64(gasLimit)))
// prepend calculated params, so it can be overwritten in case the user has specified it.
opts = append([]TxOption{SetGasLimit(gasLimit), SetFee(fee)}, opts...)
Copy link
Contributor

Choose a reason for hiding this comment

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

This currently breaks down if someone wants us to estimate the gas but wants to provide a gas price themselves (if there's congestion for example). We should create an issue and look to address that in the future

Copy link
Member Author

@vgonkivs vgonkivs May 30, 2024

Choose a reason for hiding this comment

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

This case works fine, as the gas will be estimated but the calculated gas price will be overwritten. The issue might be if the user wants us to estimate gas price, providing a gas limit. But in this case, I guess we will get an insufficient fee error that is already handled, so the tx will be retried with higher fees.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it doesn't quite work as would be intuitive. Ideally, I as a user could set the gas price and request that the client estimates the gas limit and sets the fee by multiplying the gas price I provided with the gas limit that was estimated. This is a bit tricky to do so I think we should follow it up later.

pkg/user/tx_client.go Outdated Show resolved Hide resolved
@vgonkivs vgonkivs requested a review from cmwaters May 30, 2024 11:02
@celestia-bot celestia-bot requested a review from a team May 30, 2024 11:02
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Outside diff range and nitpick comments (1)
pkg/user/tx_client.go (1)

Line range hint 381-411: The ConfirmTx method's logic to handle transaction confirmation is generally sound. However, the error handling could be more robust to differentiate between different reasons for a transaction not being found.

- if !strings.Contains(err.Error(), "not found") {
+ if !strings.Contains(err.Error(), "not found") // Add more specific error handling here

pkg/user/tx_client.go Show resolved Hide resolved
pkg/user/tx_client.go Show resolved Hide resolved
@vgonkivs
Copy link
Member Author

Generally, I'd make a FeeHandler middleware that can intercept all requests that are coming to the Client and perform all needed computations.

Copy link
Contributor

@cmwaters cmwaters left a comment

Choose a reason for hiding this comment

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

LGTM

@cmwaters
Copy link
Contributor

Generally, I'd make a FeeHandler middleware that can intercept all requests that are coming to the Client and perform all needed computations.

Can you elaborate on this?

@vgonkivs
Copy link
Member Author

Can create an issue, describing all ideas so we can have a clear understanding of what should be done and do we need it.

@cmwaters
Copy link
Contributor

Yes let's create an issue and discuss it further there

Copy link
Member

@evan-forbes evan-forbes left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@ninabarbakadze ninabarbakadze left a comment

Choose a reason for hiding this comment

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

lgtm. thanks!

@celestia-bot celestia-bot requested review from a team and ramin and removed request for a team June 3, 2024 10:15
@cmwaters cmwaters enabled auto-merge (squash) June 3, 2024 10:15
@cmwaters cmwaters merged commit af426bf into celestiaorg:main Jun 3, 2024
32 of 33 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.

pkg/user: Signer automatically estimates gas
4 participants