-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
FUN-1234 (feat): Chainlink Functions premium fees in USD denomination #12000
Conversation
I see that you haven't updated any README files. Would it make sense to do so? |
6dbe81c
to
32f1943
Compare
32f1943
to
81b7d6d
Compare
contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol
Outdated
Show resolved
Hide resolved
return (uint256(usdPerUnitLink), s_linkToUsdFeed.decimals()); | ||
} | ||
|
||
function _getJuelsFromUsd(uint256 amountUsd) private view returns (uint96) { |
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.
I need to work through this math by hand to verify.
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.
I doubled checked. I think this is good.
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 also have tests that triple and quadruple check this, right?
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 tests are in this PR, yes. They should also be reviewed.
@@ -186,6 +186,10 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, | |||
linkEthFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(owner, b, 18, big.NewInt(5_000_000_000_000_000)) | |||
require.NoError(t, 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.
I noticed we don't have additional tests that cover both the previous contract version & new contracts. My guess is this is gonna be flagged for lack of coverage by SonarQube. I think we need to write tests which cover both in order to get this PR merged.
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.
Actually, I think the SonarQube coverage requirement may have been temporarily paused for other reasons? Either way, I'd really prefer we test with both versions of the contract here just to be safe.
I'm also curious if we can simulate a coordinator contract upgrade in our tests.
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.
There is a test with an upgrade, though it doesn't go from version to version, because previously we only held on to one wrapper.
I think it's a good idea to change this test to actually move through breaking changes
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.
I took an attempt with this, but the types got messy.
I'm opening a new ticket to ensure that this happens, even though it won't be in this PR.
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.
okay. In the mean time, we should properly test this process on staging.
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.
If you can, please preserve existing tests without changes and only add new ones. We can remove obsolete ones later, once prod is fully migrated.
|
||
func (l *logPollerWrapper) logsToResponses(coordinator coordinator, responseLogs []logpoller.Log) ([]evmRelayTypes.OracleResponse, error) { | ||
var responses []evmRelayTypes.OracleResponse | ||
|
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 not set the parsingContract here first based on the version, then remove the 2 duplicated code blocks below?
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.
This is because we don't have a robust way to handle the two different types of wrappers here. Go is very strict about typing. We need a wrapper of wrappers of sorts. Something we will add to our tech debt and tackle soon.
c59aa80
to
fa6410a
Compare
contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol
Outdated
Show resolved
Hide resolved
contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsResponse.sol
Outdated
Show resolved
Hide resolved
2e6532c
to
f5afdb8
Compare
return nil, err | ||
} | ||
return nameEncoded, 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.
Thank you very much for all the additional tests above!
…12066) * fix: test race * Revert "(test): Run LogPollerWrapperTest v1/v2 tests sequentially" This reverts commit 1ba2c06. * chore: refactor logpoller_wrapper by injecting a coordinator dep * fix: remove duplicates abitype definitions * fix: lint sonarqube reliability issue * fix: race conditions due to share variables --------- Co-authored-by: Justin Kaseman <[email protected]>
func init() { | ||
err := initAbiTypes() | ||
if err != nil { | ||
panic(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.
Why are we introducing a panic? This does not seem like the best practice.
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.
Actually, I am not quite sure I understand why this function is here at all...
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 can probably run initAbiTypes() inside NewLogPollerWrapper() and also not panic.
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.
Yeah I don't love the panic either, my initial reasons were:
The init() function can not return an error, so if anything fails this is the only way. The benefits of initialising this here is that it will run after variables are declare and before anything else is executed (this is specially important because these are pkg variables that can be reference from outside). Another pro: It will only run once compare to re-declaring the types on each request.
We can probably run initAbiTypes() inside NewLogPollerWrapper() and also not panic.
I thought about this but, wouldn't we leave the door open to someone referencing these pkg variables before they are initialised? 🤔
I think there is an alternative that could work too without panic and is defining a structure like:
type validAbiTypes struct{
uint32Type abi.Type,
...
}
that contain all the valid types as part of logpuller_wrapper, this could be initialised in the NewLogPollerWrapper and injected down to the V1 and V2 implementations of the Coordinator.
will explore these two last options and have something for today
if errActive != nil || errProposed != nil { | ||
l.lggr.Errorw("LogPollerWrapper: Failed to register filters", "errorActive", errActive, "errorProposed", errProposed) | ||
var activeCoordinator Coordinator | ||
switch { |
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.
This section looks cleaner. Thanks!
@@ -60,28 +55,42 @@ func newSubscriber(expectedCalls int) *subscriber { | |||
return sub | |||
} | |||
|
|||
func addr(t *testing.T, lastByte string) []byte { |
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.
Given that passing t
was not actually the issue which caused the race condition, can we revert this change?
return contractAddr, nil | ||
} | ||
|
||
type setupResponse struct { |
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.
Nice! Good way to clean this up.
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.
A bunch of minor comments and questions.
One small bug (cc @agparadiso please verify)
msg.sender, | ||
commitment | ||
FunctionsResponse.Commitment({ |
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 we add a comment here explaining that we re-pack everything into an older Commitment struct compatible with the Router?
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.
Good suggestion, I agree that it'll make it more clear
s_feePool += commitment.donFee; | ||
s_feePool += commitment.donFeeJuels; | ||
// Pay the operation fee to the Coordinator owner | ||
s_withdrawableTokens[_owner()] += commitment.operationFeeJuels; |
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.
Is there already a proposal for concrete values of all 3 fees in prod? Can we discuss that in the Config sheet maybe?
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's in another PR in tooling. It will be added to the Config sheet once finalized.
emit RequestBilled({ | ||
requestId: requestId, | ||
juelsPerGas: juelsPerGas, | ||
l1FeeShareWei: l1FeeShareWei, | ||
callbackCostJuels: callbackCostJuels, | ||
totalCostJuels: gasOverheadJuels + callbackCostJuels + commitment.donFee + commitment.adminFee | ||
donFeeJuels: commitment.donFeeJuels, |
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.
Will this affect Atlas or other data collection? Any other event changes that we are coordinating (or will) with other teams?)
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 will not. I already double checked that Atlas only uses Router events.
commitment = FunctionsResponse.Commitment({ | ||
adminFee: request.adminFee, | ||
commitment = FunctionsResponse.CommitmentWithOperationFee({ | ||
adminFeeJuels: request.adminFee, |
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.
Since we are deprecating adminFee (right?), could we save all this effort with a new Commitment struct by putting the new operationFee into adminFee field? Still passing a zero to the router so everything matches there. Not the most elegant approach but maybe a lot simpler?
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.
I hadn't considered this. I'd be very curious to know if this is possible as it would be great to eliminate the changes to the log_poller_wrapper.
@@ -186,6 +186,10 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, | |||
linkEthFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(owner, b, 18, big.NewInt(5_000_000_000_000_000)) | |||
require.NoError(t, 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.
If you can, please preserve existing tests without changes and only add new ones. We can remove obsolete ones later, once prod is fully migrated.
if err != nil { | ||
l.lggr.Error("LatestEvents: creating a contract instance for parsing failed") |
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.
Keep this log line (with an appropriate message).
resultsReq = append(resultsReq, requests...) | ||
responses, err := coordinator.LogsToResponses(responseLogs) | ||
if err != nil { | ||
return nil, nil, 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.
Same here - log something with a "LatestEvents" prefix
l.lggr.Error("LogPollerWrapper: cannot update activeCoordinator to zero address") | ||
return | ||
} | ||
|
||
if activeCoordinator == l.activeCoordinator && proposedCoordinator == l.proposedCoordinator { | ||
if (l.activeCoordinator != nil && l.activeCoordinator.Address() == activeCoordinatorAddress) && | ||
(l.proposedCoordinator != nil && l.proposedCoordinator.Address() == proposedCoordinatorAddress) { |
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.
If proposedCoordinator == nil we never get inside this block but often we should. @agparadiso
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.
ok changed to:
if (l.activeCoordinator != nil && l.activeCoordinator.Address() == activeCoordinatorAddress) &&
(l.proposedCoordinator == nil || l.proposedCoordinator.Address() == proposedCoordinatorAddress) {
l.lggr.Debug("LogPollerWrapper: no changes to routes")
return
}
that would contemplate both scenarios
|
||
return c.logPoller.RegisterFilter( | ||
logpoller.Filter{ | ||
Name: logpoller.FilterName("FunctionsLogPollerWrapper", c.address.String(), "-v", "2"), |
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.
Move string to a const used by both files. Also you could encode "-v2" in the prefix.
return | ||
} | ||
|
||
var proposedCoordinator Coordinator |
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 we add a helper method to avoid code duplication?
Quality Gate passedIssues Measures |
Closing in favor of #12104 |
Changes:
operationFee
that pays to the FunctionsCoordinator contract's ownerCommitment
&OracleRequest
structure that uses theoperationFee
typeAndVersion
to select between whichOracleRequest
to watch for