-
Notifications
You must be signed in to change notification settings - Fork 48
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
MultiAggregateRateLimiter - non-evm and multi-lane remote token support #939
MultiAggregateRateLimiter - non-evm and multi-lane remote token support #939
Conversation
Go solidity wrappers are out-of-date, regenerate them via the |
Go solidity wrappers are out-of-date, regenerate them via the |
LCOV of commit
|
7624cab
to
4bff80f
Compare
Go solidity wrappers are out-of-date, regenerate them via the |
I see you updated files related to
|
2dbb822
to
fbc8f6f
Compare
/// @notice RateLimitToken struct containing both the local and remote token addresses | ||
struct RateLimitTokenArgs { | ||
LocalRateLimitToken localTokenArgs; // Local token update args scoped to one remote chain | ||
bytes32 remoteToken; // Token on the remote chain (for OnRamp - dest, of OffRamp - source) |
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.
theoretically possible this would be bytes, but we could upgrade worst case
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.
Agreed, we should revisit this when we get to non-EVM, since right now we have not identified addresses with > 32 bytes
/// @dev Tokens that should be included in Aggregate Rate Limiting (from local chain (this chain) -> remote), | ||
/// grouped per-remote chain. | ||
mapping(uint64 remoteChainSelector => EnumerableMapAddresses.AddressToBytes32Map) internal | ||
s_rateLimitedTokensLocalToRemote; | ||
|
||
/// @dev Set of callers that can call the validation functions (this is required since the validations modify state) |
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.
did we consider deriving these from the router like the token pool does? Simpler config wise and I think it'd also give you the property that the on/offramp can only call their respective methods
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 agree with the config simplicity + there would be an added level of misconfiguration since we would check the chain selectors together with the ramps. However, it is a ~10% increase in gas due to the external call:
Function Name | min | avg | median | max | # calls |
---|---|---|---|---|---|
onIncomingMessage (authorizedCallers) | 27390 | 50521 | 54146 | 60411 | 14 |
onIncomingMessage (router) | 33118 | 56238 | 59862 | 66127 | 14 |
I recon the added config redundancy is worth it to save costs in this case, especially since this cost is per-message? Given it is easy to set this config (we can just query the Router ramps in a tooling script and set them to the authorized callers) - should we keep the current approach?
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 it also a 10% increase if the msg came from the router, and therefore the router is hot?
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 you're right, I believe it would indeed be the case for the OffRamp, since we check OnlyOffRamp
in the same router anyway.
However, the increase could still be there for the OnRamp if there are no token transfers (otherwise there would also be a hot-path through the TokenPool in most cases)
Another aspect is when we have 2 routers at the same time (one test router, and one prod router), it becomes much harder to configure the multi-ARL, since we would typically not re-deploy the multi-ARL. We had this complexity for the Nonce Manager as well, and it looks like the easiest option would be to explicitly maintain the authorized callers set ( I recon we can later refactor out this functionality to an abstract contract that will be re-used by both the multi-ARL and Nonce Manager )
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 guess the OnRamp no-tokens case can be optimized - so the gas cost issue can be mitigated:
function onOutgoingMessage(Client.EVM2AnyMessage memory message, uint64 destChainSelector) external {
if (message.tokenAmounts.length == 0) {
return;
}
isOnRamp(msg.sender);
}
I'm still in favour of the current approach though due to the complexity above
uint64 remoteChainSelector = message.sourceChainSelector; | ||
RateLimiter.TokenBucket storage tokenBucket = _getTokenBucket(remoteChainSelector, false); | ||
|
||
// Skip rate limiting if it is disabled |
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 would also be the default behaviour right? E.g. say we have a rate limited token, which then is added to a new lane. By default it'd be excluded from the rate limit until we actively enable it with updateRateLimitTokens. Seems potentially safer the other way i.e. default we revert until rate limit set for the new lane
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.
Yes this would be the default behaviour. The change here is mostly a gas optimization - if the rate limiter is disabled, we do not need to loop over all tokens and calculate the total value.
Seems potentially safer the other way i.e. default we revert until rate limit set for the new lane
This would not work because the message validator is called into by all lanes: see OffRamp. If we reverted with an unset rate-limit, we would be forced to set a rate limit config for all lanes. I think it's better to allow the flexibility to partially enable rate limits
@@ -72,7 +79,7 @@ contract MultiAggregateRateLimiter is IMessageInterceptor, OwnerIsCreator { | |||
address internal s_priceRegistry; | |||
|
|||
/// @notice Rate limiter token bucket states per chain, with separate buckets for incoming and outgoing lanes. | |||
mapping(uint64 remoteChainSelector => RateLimiterBuckets buckets) s_rateLimitersByChainSelector; | |||
mapping(uint64 remoteChainSelector => RateLimiterBuckets buckets) internal s_rateLimitersByChainSelector; | |||
|
|||
/// @param rateLimiterConfigs The RateLimiter.Configs per chain containing the capacity and refill rate | |||
/// of the bucket |
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.
Comment on constructor: given this is a chain contract, which will always be deployed before the lanes, I think it's fine to remove the RateLimiterConfigArgs[] memory rateLimiterConfigs
args there. I would think it will always be left empty. We could then rm the internal function
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.
True, this is not required now since the contract is completely separate - removing this
Inconsistent order in |
* feat: add EnumerableMapAddresses library * refactor: remove redundant helpers
b6009c8
to
ac6b754
Compare
4b5036f
to
d322f60
Compare
…rt (#939) ## Motivation Follow up of #916 to integrate non-EVM token support, and convert `rateLimitedTokens` configuration to be per-chain. This converts the multi-ARL to be truly multi-lane and untied from EVM2EVM to EVM2Any, Any2EVM ## Solution * Add `chainSelector` to rate limit tokens state * Convert addresses from `bytes` to `bytes32` (for now assuming that we can fit token addresses in `bytes32` for all non-EVM chains)
Motivation
Follow up of #916 to integrate non-EVM token support, and convert
rateLimitedTokens
configuration to be per-chain. This converts the multi-ARL to be truly multi-lane and untied from EVM2EVM to EVM2Any, Any2EVMSolution
chainSelector
to rate limit tokens statebytes
tobytes32
(for now assuming that we can fit token addresses inbytes32
for all non-EVM chains)