-
Notifications
You must be signed in to change notification settings - Fork 996
feat(state/core_accessor): add fee estimator #4087
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
Conversation
90f851c
to
7c01a6f
Compare
7c01a6f
to
56afde4
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4087 +/- ##
==========================================
+ Coverage 44.83% 44.97% +0.14%
==========================================
Files 265 310 +45
Lines 14620 22834 +8214
==========================================
+ Hits 6555 10270 +3715
- Misses 7313 11472 +4159
- Partials 752 1092 +340 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest comment rn is just that core_access is super messy 😭 Quite hard to read. Is there anything that can be done to make the code more readable?
func SanitizeAddr(addr string) (string, error) { | ||
original := addr | ||
// NormalizeAddress extracts the host and port, removing unsupported schemes. | ||
func NormalizeAddress(addr string) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does SanitizeAddr not work for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it additionally cuts the port.
addr = strings.Split(addr, ":")[0]
@@ -23,13 +24,14 @@ func coreAccessor( | |||
fraudServ libfraud.Service[*header.ExtendedHeader], | |||
network p2p.Network, | |||
client *grpc.ClientConn, | |||
address core.EstimatorAddress, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't you just grab the core cfg there and take from cfg directly instead of supplying individual value to fx?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are using core.EstimatorAddress only from the core config:
type Config struct {
IP string
Port string
TLSEnabled bool
XTokenPath string
FeeEstimatorAddress EstimatorAddress
}
state/core_access.go
Outdated
|
||
log = logging.Logger("state") | ||
ErrInvalidAmount = errors.New("state: amount must be greater than zero") | ||
errGasPriceExceedsLimit = errors.New("state: estimated gasPrice exceeds max gasPrice") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why unexported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made exported
state/estimator.go
Outdated
if e.estimatorConn != nil && e.estimatorConn.GetState() != connectivity.Shutdown { | ||
gasPrice, gas, err := signer.QueryGasUsedAndPrice(ctx, e.estimatorConn, priority.toApp(), rawTx) | ||
if err == nil { | ||
return gasPrice, gas, nil | ||
} | ||
log.Warn("failed to query gas used and price from the estimator endpoint.", "err", err) | ||
} | ||
|
||
if e.defaultClientConn == nil || e.defaultClientConn.GetState() == connectivity.Shutdown { | ||
return 0, 0, errors.New("connection with the consensus node is dropped") | ||
} | ||
|
||
gasPrice, gas, err := signer.QueryGasUsedAndPrice(ctx, e.defaultClientConn, priority.toApp(), rawTx) | ||
if err != nil { | ||
log.Warn("state: failed to query gas used and price from the default endpoint", "err", err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can unify these to clean it up and just determine which conn to used based on if estimator conn exists.
What err will be returned if you pass a conn where connectivity shutdown to the signer.QueryGasUsedAndPrice? If it's readable (conn is closed) then we cna just return that unwrapped
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simplified
state/core_access.go
Outdated
@@ -136,6 +139,7 @@ func (ca *CoreAccessor) Start(ctx context.Context) error { | |||
if err != nil { | |||
return fmt.Errorf("querying minimum gas price: %w", err) | |||
} | |||
ca.estimator.connect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Start function could use some cleanup (better organisation w.r.t spacing + order)
Did we tested this manually? Like run a node with an estimator submitting a real blob? |
Submit blobs is using a linear formula to calculate gas. I tested it with |
Oh, i see, didnt know that, but you made it with Transfer - to confirm? |
It worked fine last month when I was testing it iirc. I'm getting an error from the estimation endpoint now. Trying to clarify with the app team. |
Ok, let's retest it. BTW, are we sure that estimation is only for Transfers and not blobs? Seems weird that we make this issue a priority if its only for transfers |
Yes, as per ADR blobs should be estimated using formula. All other types of the Txs have to use estimation service |
Tested on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skipping review of semantical nits.
If it works - it works
err = ca.estimator.Start(ctx) | ||
if err != nil { | ||
log.Warn("state: failed to connect to estimator endpoint", "err", err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we return err
here? if no - comment why it's ok to skip it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should actually return an error here bc the only time err is returned from estimator.Start is if grpc conn fails to be created which is an actual err.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
err = ca.estimator.Start(ctx) | ||
if err != nil { | ||
log.Warn("state: failed to connect to estimator endpoint", "err", err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should actually return an error here bc the only time err is returned from estimator.Start is if grpc conn fails to be created which is an actual err.
msg sdktypes.Msg, | ||
) (float64, uint64, error) { | ||
if cfg.GasPrice() != DefaultGasPrice && cfg.GasLimit() != 0 { | ||
return cfg.GasPrice(), cfg.GasLimit(), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so if both GasPrice and GasLimit are set in the config, GasPrice sanity check (checking if it exceeds the MaxGasPrice) can be bypassed? Is the idea here that if the user sets gas themselves that they wouldn't set a max gas price, and if they set a max gas price, that means they probably didn't specify gas and wants the node to calculate for them (within some upper bound)?
We should document this behaviour here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments throughout this function would be nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Not sure about "comments throughout this function", I don't see a good reason for that, added Go-doc only.
priority TxPriority, | ||
rawTx []byte, | ||
) (gasPrice float64, gas uint64, err error) { | ||
conns := []*grpc.ClientConn{e.estimatorConn, e.defaultClientConn} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the idea here is that there will /can be an estimator service that will perform this function, but if not, the default validator you're using to submit txs will also be able to estimate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I understand your comment is just informational, nothing to change, right?
Implemenation of the ADR-13
This PR enables third-party estimation for the submit transactions in the node(besides PFB). By default, fee estimation relies on the consensus node to which the node is connected. But the user can now provide a non-default endpoint, so the node will query gas price and gas from it. It can be provided via cli(using "core.estimator.address"). The address will be added to the node's config as
FeeEstimatorAddress
.Additionally, the user can now provide a maxGasPrice for every submit tx(via
max.gas.price
flag)- the max price that the user is willing to pay for the transaction. The transaction will not be submitted in case when estimated gas price exceeds the maxGasPrice(default:minGasPrice*100
)