Skip to content

Commit 59cceb0

Browse files
committed
evm: TransceiverRegistry split
1 parent ada34c1 commit 59cceb0

File tree

1 file changed

+162
-93
lines changed

1 file changed

+162
-93
lines changed

evm/src/NttManager/TransceiverRegistry.sol

Lines changed: 162 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
11
// SPDX-License-Identifier: Apache 2
22
pragma solidity >=0.8.8 <0.9.0;
33

4-
/// @title TransceiverRegistry
5-
/// @author Wormhole Project Contributors.
6-
/// @notice This contract is responsible for handling the registration of Transceivers.
7-
/// @dev This contract checks that a few critical invariants hold when transceivers are added or removed,
8-
/// including:
9-
/// 1. If a transceiver is not registered, it should be enabled.
10-
/// 2. The value set in the bitmap of trannsceivers
11-
/// should directly correspond to the whether the transceiver is enabled
12-
abstract contract TransceiverRegistry {
13-
constructor() {
14-
_checkTransceiversInvariants();
15-
}
16-
4+
/// @dev TransceiverRegistryBase is a base class shared between TransceiverRegistry and TransceiverRegistryAdmin.
5+
abstract contract TransceiverRegistryBase {
176
/// @dev Information about registered transceivers.
187
struct TransceiverInfo {
198
// whether this transceiver is registered
@@ -38,7 +27,83 @@ abstract contract TransceiverRegistry {
3827
uint8 enabled;
3928
}
4029

41-
uint8 constant MAX_TRANSCEIVERS = 64;
30+
uint8 public constant MAX_TRANSCEIVERS = 64;
31+
32+
bytes32 internal constant TRANSCEIVER_INFOS_SLOT =
33+
bytes32(uint256(keccak256("ntt.transceiverInfos")) - 1);
34+
35+
bytes32 internal constant TRANSCEIVER_BITMAP_SLOT =
36+
bytes32(uint256(keccak256("ntt.transceiverBitmap")) - 1);
37+
38+
bytes32 internal constant ENABLED_TRANSCEIVERS_SLOT =
39+
bytes32(uint256(keccak256("ntt.enabledTransceivers")) - 1);
40+
41+
bytes32 internal constant REGISTERED_TRANSCEIVERS_SLOT =
42+
bytes32(uint256(keccak256("ntt.registeredTransceivers")) - 1);
43+
44+
bytes32 internal constant NUM_REGISTERED_TRANSCEIVERS_SLOT =
45+
bytes32(uint256(keccak256("ntt.numRegisteredTransceivers")) - 1);
46+
47+
function _getTransceiverInfosStorage()
48+
internal
49+
pure
50+
returns (mapping(address => TransceiverInfo) storage $)
51+
{
52+
uint256 slot = uint256(TRANSCEIVER_INFOS_SLOT);
53+
assembly ("memory-safe") {
54+
$.slot := slot
55+
}
56+
}
57+
58+
function _getTransceiverBitmapStorage()
59+
internal
60+
pure
61+
returns (_EnabledTransceiverBitmap storage $)
62+
{
63+
uint256 slot = uint256(TRANSCEIVER_BITMAP_SLOT);
64+
assembly ("memory-safe") {
65+
$.slot := slot
66+
}
67+
}
68+
69+
function _getRegisteredTransceiversStorage() internal pure returns (address[] storage $) {
70+
uint256 slot = uint256(REGISTERED_TRANSCEIVERS_SLOT);
71+
assembly ("memory-safe") {
72+
$.slot := slot
73+
}
74+
}
75+
76+
function _getNumTransceiversStorage() internal pure returns (_NumTransceivers storage $) {
77+
uint256 slot = uint256(NUM_REGISTERED_TRANSCEIVERS_SLOT);
78+
assembly ("memory-safe") {
79+
$.slot := slot
80+
}
81+
}
82+
83+
function _getEnabledTransceiversStorage() internal pure returns (address[] storage $) {
84+
uint256 slot = uint256(ENABLED_TRANSCEIVERS_SLOT);
85+
assembly ("memory-safe") {
86+
$.slot := slot
87+
}
88+
}
89+
}
90+
91+
/// @title TransceiverRegistry
92+
/// @author Wormhole Project Contributors.
93+
/// @notice This contract is responsible for handling the registration of Transceivers.
94+
/// @dev This contract checks that a few critical invariants hold when transceivers are added or removed,
95+
/// including:
96+
/// 1. If a transceiver is not registered, it should be enabled.
97+
/// 2. The value set in the bitmap of trannsceivers
98+
/// should directly correspond to the whether the transceiver is enabled
99+
abstract contract TransceiverRegistry is TransceiverRegistryBase {
100+
// TODO: Tests fail if I remove the immutable. Could pass this into the constructor and make `TransceiverRegistryAdmin` upgradeable.
101+
address private immutable _admin;
102+
103+
constructor() {
104+
_admin = address(new TransceiverRegistryAdmin());
105+
_checkTransceiversInvariants();
106+
}
42107

43108
/// @notice Error when the caller is not the transceiver.
44109
/// @dev Selector 0xa0ae911d.
@@ -76,86 +141,114 @@ abstract contract TransceiverRegistry {
76141
_;
77142
}
78143

79-
// =============== Storage ===============================================
144+
// =============== Storage Getters/Setters ========================================
80145

81-
bytes32 private constant TRANSCEIVER_INFOS_SLOT =
82-
bytes32(uint256(keccak256("ntt.transceiverInfos")) - 1);
146+
function _setTransceiver(
147+
address transceiver
148+
) internal returns (uint8 index) {
149+
(bool success, bytes memory returnData) = _admin.delegatecall(
150+
abi.encodeWithSelector(TransceiverRegistryAdmin._setTransceiver.selector, transceiver)
151+
);
152+
_checkDelegateCallRevert(success, returnData);
153+
(index) = abi.decode(returnData, (uint8));
154+
}
83155

84-
bytes32 private constant TRANSCEIVER_BITMAP_SLOT =
85-
bytes32(uint256(keccak256("ntt.transceiverBitmap")) - 1);
156+
function _removeTransceiver(
157+
address transceiver
158+
) internal {
159+
(bool success, bytes memory returnData) = _admin.delegatecall(
160+
abi.encodeWithSelector(
161+
TransceiverRegistryAdmin._removeTransceiver.selector, transceiver
162+
)
163+
);
164+
_checkDelegateCallRevert(success, returnData);
165+
}
86166

87-
bytes32 private constant ENABLED_TRANSCEIVERS_SLOT =
88-
bytes32(uint256(keccak256("ntt.enabledTransceivers")) - 1);
167+
function _getEnabledTransceiversBitmap() internal view virtual returns (uint64 bitmap) {
168+
return _getTransceiverBitmapStorage().bitmap;
169+
}
89170

90-
bytes32 private constant REGISTERED_TRANSCEIVERS_SLOT =
91-
bytes32(uint256(keccak256("ntt.registeredTransceivers")) - 1);
171+
/// @notice Returns the Transceiver contracts that have been enabled via governance.
172+
function getTransceivers() external pure returns (address[] memory result) {
173+
result = _getEnabledTransceiversStorage();
174+
}
92175

93-
bytes32 private constant NUM_REGISTERED_TRANSCEIVERS_SLOT =
94-
bytes32(uint256(keccak256("ntt.numRegisteredTransceivers")) - 1);
176+
/// @notice Returns the info for all enabled transceivers
177+
/// @dev moving this into `TransceiverRegistryAdmin` reduces the size of `NttManger` but increases the size of `NttManagerNoRateLimiting`.
178+
function getTransceiverInfo() external view returns (TransceiverInfo[] memory) {
179+
address[] memory enabledTransceivers = _getEnabledTransceiversStorage();
180+
uint256 numEnabledTransceivers = enabledTransceivers.length;
181+
TransceiverInfo[] memory result = new TransceiverInfo[](numEnabledTransceivers);
95182

96-
function _getTransceiverInfosStorage()
97-
internal
98-
pure
99-
returns (mapping(address => TransceiverInfo) storage $)
100-
{
101-
uint256 slot = uint256(TRANSCEIVER_INFOS_SLOT);
102-
assembly ("memory-safe") {
103-
$.slot := slot
183+
for (uint256 i = 0; i < numEnabledTransceivers; ++i) {
184+
result[i] = _getTransceiverInfosStorage()[enabledTransceivers[i]];
104185
}
105-
}
106186

107-
function _getEnabledTransceiversStorage() internal pure returns (address[] storage $) {
108-
uint256 slot = uint256(ENABLED_TRANSCEIVERS_SLOT);
109-
assembly ("memory-safe") {
110-
$.slot := slot
111-
}
187+
return result;
112188
}
113189

114-
function _getTransceiverBitmapStorage()
115-
private
116-
pure
117-
returns (_EnabledTransceiverBitmap storage $)
118-
{
119-
uint256 slot = uint256(TRANSCEIVER_BITMAP_SLOT);
120-
assembly ("memory-safe") {
121-
$.slot := slot
122-
}
190+
// ============== Invariants =============================================
191+
192+
/// @dev Check that the transceiver nttManager is in a valid state.
193+
/// Checking these invariants is somewhat costly, but we only need to do it
194+
/// when modifying the transceivers, which happens infrequently.
195+
function _checkTransceiversInvariants() internal view {
196+
(bool success, bytes memory returnData) = _admin.staticcall(
197+
abi.encodeWithSelector(TransceiverRegistryAdmin._checkTransceiversInvariants.selector)
198+
);
199+
_checkDelegateCallRevert(success, returnData);
123200
}
124201

125-
function _getRegisteredTransceiversStorage() internal pure returns (address[] storage $) {
126-
uint256 slot = uint256(REGISTERED_TRANSCEIVERS_SLOT);
127-
assembly ("memory-safe") {
128-
$.slot := slot
129-
}
202+
// @dev Check that the transceiver is in a valid state.
203+
function _checkTransceiverInvariants(
204+
address transceiver
205+
) private view {
206+
(bool success, bytes memory returnData) = _admin.staticcall(
207+
abi.encodeWithSelector(
208+
TransceiverRegistryAdmin._checkTransceiverInvariants.selector, transceiver
209+
)
210+
);
211+
_checkDelegateCallRevert(success, returnData);
130212
}
131213

132-
function _getNumTransceiversStorage() internal pure returns (_NumTransceivers storage $) {
133-
uint256 slot = uint256(NUM_REGISTERED_TRANSCEIVERS_SLOT);
134-
assembly ("memory-safe") {
135-
$.slot := slot
214+
function _checkDelegateCallRevert(bool success, bytes memory returnData) private pure {
215+
// if the function call reverted
216+
if (success == false) {
217+
// if there is a return reason string
218+
if (returnData.length > 0) {
219+
// bubble up any reason for revert
220+
assembly {
221+
let returndata_size := mload(returnData)
222+
revert(add(32, returnData), returndata_size)
223+
}
224+
} else {
225+
revert("_removeTransceiver reverted");
226+
}
136227
}
137228
}
229+
}
138230

139-
// =============== Storage Getters/Setters ========================================
140-
231+
/// @dev TransceiverRegistryAdmin is a helper contract to TransceiverRegistry.
232+
/// It implements admin functionality and is called via `delegatecall`.
233+
contract TransceiverRegistryAdmin is TransceiverRegistryBase {
141234
function _setTransceiver(
142235
address transceiver
143-
) internal returns (uint8 index) {
236+
) public returns (uint8 index) {
144237
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
145238
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage();
146239
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
147240

148241
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage();
149242

150243
if (transceiver == address(0)) {
151-
revert InvalidTransceiverZeroAddress();
244+
revert TransceiverRegistry.InvalidTransceiverZeroAddress();
152245
}
153246

154247
if (transceiverInfos[transceiver].registered) {
155248
transceiverInfos[transceiver].enabled = true;
156249
} else {
157250
if (_numTransceivers.registered >= MAX_TRANSCEIVERS) {
158-
revert TooManyTransceivers();
251+
revert TransceiverRegistry.TooManyTransceivers();
159252
}
160253

161254
transceiverInfos[transceiver] = TransceiverInfo({
@@ -174,7 +267,7 @@ abstract contract TransceiverRegistry {
174267
_enabledTransceiverBitmap.bitmap | uint64(1 << transceiverInfos[transceiver].index);
175268
// ensure that this actually changed the bitmap
176269
if (updatedEnabledTransceiverBitmap == _enabledTransceiverBitmap.bitmap) {
177-
revert TransceiverAlreadyEnabled(transceiver);
270+
revert TransceiverRegistry.TransceiverAlreadyEnabled(transceiver);
178271
}
179272
_enabledTransceiverBitmap.bitmap = updatedEnabledTransceiverBitmap;
180273

@@ -185,21 +278,21 @@ abstract contract TransceiverRegistry {
185278

186279
function _removeTransceiver(
187280
address transceiver
188-
) internal {
281+
) public {
189282
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
190283
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage();
191284
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
192285

193286
if (transceiver == address(0)) {
194-
revert InvalidTransceiverZeroAddress();
287+
revert TransceiverRegistry.InvalidTransceiverZeroAddress();
195288
}
196289

197290
if (!transceiverInfos[transceiver].registered) {
198-
revert NonRegisteredTransceiver(transceiver);
291+
revert TransceiverRegistry.NonRegisteredTransceiver(transceiver);
199292
}
200293

201294
if (!transceiverInfos[transceiver].enabled) {
202-
revert DisabledTransceiver(transceiver);
295+
revert TransceiverRegistry.DisabledTransceiver(transceiver);
203296
}
204297

205298
transceiverInfos[transceiver].enabled = false;
@@ -230,34 +323,10 @@ abstract contract TransceiverRegistry {
230323
_checkTransceiverInvariants(transceiver);
231324
}
232325

233-
function _getEnabledTransceiversBitmap() internal view virtual returns (uint64 bitmap) {
234-
return _getTransceiverBitmapStorage().bitmap;
235-
}
236-
237-
/// @notice Returns the Transceiver contracts that have been enabled via governance.
238-
function getTransceivers() external pure returns (address[] memory result) {
239-
result = _getEnabledTransceiversStorage();
240-
}
241-
242-
/// @notice Returns the info for all enabled transceivers
243-
function getTransceiverInfo() external view returns (TransceiverInfo[] memory) {
244-
address[] memory enabledTransceivers = _getEnabledTransceiversStorage();
245-
uint256 numEnabledTransceivers = enabledTransceivers.length;
246-
TransceiverInfo[] memory result = new TransceiverInfo[](numEnabledTransceivers);
247-
248-
for (uint256 i = 0; i < numEnabledTransceivers; ++i) {
249-
result[i] = _getTransceiverInfosStorage()[enabledTransceivers[i]];
250-
}
251-
252-
return result;
253-
}
254-
255-
// ============== Invariants =============================================
256-
257326
/// @dev Check that the transceiver nttManager is in a valid state.
258327
/// Checking these invariants is somewhat costly, but we only need to do it
259328
/// when modifying the transceivers, which happens infrequently.
260-
function _checkTransceiversInvariants() internal view {
329+
function _checkTransceiversInvariants() public view {
261330
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage();
262331
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
263332

@@ -282,7 +351,7 @@ abstract contract TransceiverRegistry {
282351
// @dev Check that the transceiver is in a valid state.
283352
function _checkTransceiverInvariants(
284353
address transceiver
285-
) private view {
354+
) public view {
286355
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
287356
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage();
288357
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage();

0 commit comments

Comments
 (0)