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

evm: per chain transceivers #517

Conversation

bruce-riley
Copy link
Contributor

@bruce-riley bruce-riley commented Sep 12, 2024

This PR implements the NttManagerWithPerChainTransceivers contract which inherits from NttManagerNoRateLimiting and allows configuring different transceivers and thresholds for each chain. You can configure a different set of send and receive transceivers for each chain. If you don't specifically enable any transceivers for a chain, then all transceivers will be used.

This new contract has to inherit from the no-rate-limiting due to the contract size limit.

@bruce-riley bruce-riley force-pushed the evm/per-chain-transceivers branch 4 times, most recently from 54ec5cd to 964a4de Compare September 16, 2024 21:13
@bruce-riley bruce-riley force-pushed the evm/per-chain-transceivers branch 15 times, most recently from e442b2d to 6f7cfc4 Compare September 25, 2024 15:22
@bruce-riley
Copy link
Contributor Author

bruce-riley commented Sep 25, 2024

Contract sizes before this feature:

| NttManager                            |   23,615 |        961 |
| NttManagerNoRateLimiting              |   18,169 |      6,407 |

Contract sizes with this feature:

| NttManager                                  |   23,651 |        925 |
| NttManagerNoRateLimiting                    |   18,205 |      6,371 |
| NttManagerWithPerChainTransceivers          |   22,804 |      1,772 |

@bruce-riley bruce-riley force-pushed the evm/per-chain-transceivers branch 10 times, most recently from 1270075 to 6eebeda Compare September 26, 2024 19:37
@bruce-riley
Copy link
Contributor Author

Would like to have a longer look at this next week, the bitmap and threshold stuff was a source of some pain in the original audit.

One general comment is I feel like it becomes a lot easier to misconfig with these changes. For example, in a 2 transceiver, threshold of 2 global setup, if only 1 transceiver is enabled for receiving from a given chain, but the deployer forgets to set the perChainThreshold for that chain, then messages won't get delivered. Maybe in enableRecvTransceiverForChain we need to check that perChainThreshold is <= set bits in the joint enabledTransceiverBitmap & enabledTransceiversForChain bitmap?

That would require them to set the per-chain threshold before enabling anything, right? Is that acceptable?

@djb15
Copy link
Collaborator

djb15 commented Sep 28, 2024

Would like to have a longer look at this next week, the bitmap and threshold stuff was a source of some pain in the original audit.
One general comment is I feel like it becomes a lot easier to misconfig with these changes. For example, in a 2 transceiver, threshold of 2 global setup, if only 1 transceiver is enabled for receiving from a given chain, but the deployer forgets to set the perChainThreshold for that chain, then messages won't get delivered. Maybe in enableRecvTransceiverForChain we need to check that perChainThreshold is <= set bits in the joint enabledTransceiverBitmap & enabledTransceiversForChain bitmap?

That would require them to set the per-chain threshold before enabling anything, right? Is that acceptable?

I was thinking we could write perChainThreshold to 1 when we add the first per chain transceiver? I think we do something similar in the existing transceiver registry

@bruce-riley bruce-riley force-pushed the evm/per-chain-transceivers branch 2 times, most recently from 5aa1e47 to e6a1aca Compare September 29, 2024 16:25
Copy link

@banescusebi banescusebi left a comment

Choose a reason for hiding this comment

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

I will continue looking a bit into the test files, but wanted to submit the comments so far.

evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/src/interfaces/IManagerBase.sol Outdated Show resolved Hide resolved
evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/src/NttManager/NttManagerWithPerChainTransceivers.sol Outdated Show resolved Hide resolved
evm/test/PerChainTransceivers.t.sol Show resolved Hide resolved
evm/test/PerChainTransceivers.t.sol Outdated Show resolved Hide resolved
@bruce-riley
Copy link
Contributor Author

We've decided to not support falling back to the global defaults, and also switch to functions to get / set the bitmaps per chain, rather than doing enable/disable.

I'm converting this back to draft while I do the rework.

@bruce-riley bruce-riley marked this pull request as draft October 1, 2024 14:03
evm/README.md Outdated Show resolved Hide resolved
evm/README.md Outdated Show resolved Hide resolved
@bruce-riley bruce-riley marked this pull request as ready for review October 2, 2024 19:37
Copy link
Collaborator

@djb15 djb15 left a comment

Choose a reason for hiding this comment

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

  • Should setThreshold be overridden and revert?
  • More generally to the above bullet point, we should try to minimise unintended side effects of enabling/disabling transceivers globally/per-chain and also setting global/per-chain thresholds (global thresholds appear to be unused now, but worth being explicit)

Copy link

@banescusebi banescusebi left a comment

Choose a reason for hiding this comment

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

Overall looks pretty solid this way. Just a few nits and questions from my side.

/// @notice The structure of a per-chain entry in the call to setTransceiversForChains.
struct SetTransceiversForChainEntry {
uint64 sendBitmap;
uint64 recvBitmap;

Choose a reason for hiding this comment

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

Genera question regarding this 64 transceiver limit: as more and more chains pop-up and are added to WH, will 64 bits be sufficient in the future?

function _isSendTransceiverEnabledForChain(
address transceiver,
uint16 forChainId
) internal view override returns (bool) {
uint64 bitmap = _getPerChainTransceiverBitmap(forChainId, SEND_TRANSCEIVER_BITMAP_SLOT);
uint8 index = _getTransceiverInfosStorage()[transceiver].index;
return (bitmap & uint64(1 << index)) != 0;
return (bitmap & uint64(1 << index)) > 0;

Choose a reason for hiding this comment

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

Why this small change here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This was me! != needs 2 opcodes vs > just needs 1, so we save (a small amount of) gas here. Plus it matches how we do it elsewhere in the codebase

uint64 enabledTransceiverBitmap = _getEnabledTransceiversBitmap();
uint64 enabledTransceiversForChain =
_getEnabledRecvTransceiversForChain(attInfo.sourceChainId);
return attInfo.attestedTransceivers & enabledTransceiverBitmap & enabledTransceiversForChain;

Choose a reason for hiding this comment

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

The _checkTransceiversInvariants() ensures that you can't remove a transceiver globally, when it's enabled for a chain. Therefore enabledTransceiversForChain is a subset of enabledTransceiverBitmap.

function _checkTransceiversInvariants() internal view override {
super._checkTransceiversInvariants();
_validateTransceivers(SEND_ENABLED_CHAINS_SLOT, SEND_TRANSCEIVER_BITMAP_SLOT);
_validateTransceivers(RECV_ENABLED_CHAINS_SLOT, RECV_TRANSCEIVER_BITMAP_SLOT);

Choose a reason for hiding this comment

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

This _checkTransceiversInvariants() seems quite heavy. Would it be worth doing an analysis at how many chains and how many transceivers per chain do the calling functions hit the block gas limit?


// Can't enable transceiver for an unknown address.
// Can't globally remove a transceiver when it's enabled for a chain.

Choose a reason for hiding this comment

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

Love this test.

The `NttManagerWithPerChainTransceivers` contract which inherits from `NttManagerNoRateLimiting` and allows configuring different transceivers and thresholds for each chain.
You can configure a different set of send and receive transceivers for each chain. If you don't specifically enable any transceivers for a chain, then all transceivers will be used.
The `NttManagerWithPerChainTransceivers` contract inherits from `NttManagerNoRateLimiting` and allows configuring different transceivers and thresholds for each chain.
You can configure a different set of send and receive transceivers for each chain, as well as the receive threshold for the chain.

Choose a reason for hiding this comment

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

Something that might be worth adding to the README.md:

Even when only using per chain transceivers, one needs to register each transceiver using the setTransceiver() method inherited from ManagerBase. Note that this only allows registering up to 64 transceivers in total (to be used as send and/or receive transceivers).

@evan-gray
Copy link
Contributor

evan-gray commented Oct 11, 2024

Closing this PR given the following:

  • the implementation has become increasingly complex to make safe for upgrading NttManagers while maintaining the config and method identifiers
  • these changes push the contract over the size limit
  • we expect to rework the transceiver configuration in a future, breaking version

Therefore, despite the much appreciated effort and reviews, I do not recommend proceeding.

@evan-gray evan-gray closed this Oct 11, 2024
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.

5 participants