Skip to content

Commit a5005de

Browse files
authored
evm: Update endpoint instruction handling (#180)
* evm: Update endpoint instruction handling * evm: forge formatting
1 parent 3d65497 commit a5005de

File tree

2 files changed

+32
-44
lines changed

2 files changed

+32
-44
lines changed

evm/src/Manager.sol

+6-16
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,7 @@ contract Manager is
227227
revert CannotRenounceManagerOwnership(owner());
228228
}
229229

230-
/// @dev This will either cross-call or internal call, depending on whether the contract is standalone or not.
231-
/// This method should return an array of delivery prices corresponding to each endpoint.
230+
/// @dev This method should return an array of delivery prices corresponding to each endpoint.
232231
function quoteDeliveryPrice(
233232
uint16 recipientChain,
234233
EndpointStructs.EndpointInstruction[] memory endpointInstructions,
@@ -251,8 +250,6 @@ contract Manager is
251250
return (priceQuotes, totalPriceQuote);
252251
}
253252

254-
/// @dev This will either cross-call or internal call, depending on
255-
/// whether the contract is standalone or not.
256253
function _sendMessageToEndpoints(
257254
uint16 recipientChain,
258255
uint256[] memory priceQuotes,
@@ -420,12 +417,6 @@ contract Manager is
420417
revert InvalidRecipient();
421418
}
422419

423-
// parse the instructions up front to ensure they:
424-
// - are encoded correctly
425-
// - follow payload length restrictions
426-
427-
EndpointStructs.parseEndpointInstructions(endpointInstructions);
428-
429420
{
430421
// Lock/burn tokens before checking rate limits
431422
if (mode == Mode.LOCKING) {
@@ -530,15 +521,14 @@ contract Manager is
530521
address sender,
531522
bytes memory endpointInstructions
532523
) internal returns (uint64 msgSequence) {
533-
// parse and reorganize the endpoint instructions based on index
534-
EndpointStructs.EndpointInstruction[] memory sortedInstructions = EndpointStructs
535-
.sortEndpointInstructions(EndpointStructs.parseEndpointInstructions(endpointInstructions));
536-
537524
// cache enabled endpoints to avoid multiple storage reads
538525
address[] memory enabledEndpoints = _getEnabledEndpointsStorage();
539526

527+
EndpointStructs.EndpointInstruction[] memory instructions =
528+
EndpointStructs.parseEndpointInstructions(endpointInstructions, enabledEndpoints.length);
529+
540530
(uint256[] memory priceQuotes, uint256 totalPriceQuote) =
541-
quoteDeliveryPrice(recipientChain, sortedInstructions, enabledEndpoints);
531+
quoteDeliveryPrice(recipientChain, instructions, enabledEndpoints);
542532
{
543533
// check up front that msg.value will cover the delivery price
544534
if (msg.value < totalPriceQuote) {
@@ -567,7 +557,7 @@ contract Manager is
567557

568558
// send the message
569559
_sendMessageToEndpoints(
570-
recipientChain, priceQuotes, sortedInstructions, enabledEndpoints, encodedManagerPayload
560+
recipientChain, priceQuotes, instructions, enabledEndpoints, encodedManagerPayload
571561
);
572562

573563
emit TransferSent(recipient, nttDenormalize(amount), recipientChain, sequence);

evm/src/libraries/EndpointStructs.sol

+26-28
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ library EndpointStructs {
1010

1111
error PayloadTooLong(uint256 size);
1212
error IncorrectPrefix(bytes4 prefix);
13+
error UnorderedInstructions();
1314

1415
/// @dev Prefix for all NativeTokenTransfer payloads
1516
/// This is 0x99'N''T''T'
@@ -307,50 +308,47 @@ library EndpointStructs {
307308
if (instructions.length > type(uint8).max) {
308309
revert PayloadTooLong(instructions.length);
309310
}
310-
uint8 instructionsLength = uint8(instructions.length);
311+
uint256 instructionsLength = instructions.length;
311312

312313
bytes memory encoded;
313-
for (uint8 i = 0; i < instructionsLength; i++) {
314+
for (uint256 i = 0; i < instructionsLength; i++) {
314315
bytes memory innerEncoded = encodeEndpointInstruction(instructions[i]);
315316
encoded = bytes.concat(encoded, innerEncoded);
316317
}
317-
return abi.encodePacked(instructionsLength, encoded);
318+
return abi.encodePacked(uint8(instructionsLength), encoded);
318319
}
319320

320-
function parseEndpointInstructions(bytes memory encoded)
321-
public
322-
pure
323-
returns (EndpointInstruction[] memory)
324-
{
321+
function parseEndpointInstructions(
322+
bytes memory encoded,
323+
uint256 numEnabledEndpoints
324+
) public pure returns (EndpointInstruction[] memory) {
325325
uint256 offset = 0;
326-
uint8 instructionsLength;
326+
uint256 instructionsLength;
327327
(instructionsLength, offset) = encoded.asUint8Unchecked(offset);
328-
EndpointInstruction[] memory instructions = new EndpointInstruction[](instructionsLength);
329328

330-
for (uint8 i = 0; i < instructionsLength; i++) {
329+
// We allocate an array with the length of the number of enabled endpoints
330+
// This gives us the flexibility to not have to pass instructions for endpoints that
331+
// don't need them
332+
EndpointInstruction[] memory instructions = new EndpointInstruction[](numEnabledEndpoints);
333+
334+
uint256 lastIndex = 0;
335+
for (uint256 i = 0; i < instructionsLength; i++) {
331336
EndpointInstruction memory instruction;
332337
(instruction, offset) = parseEndpointInstructionUnchecked(encoded, offset);
333-
instructions[i] = instruction;
338+
339+
uint8 instructionIndex = instruction.index;
340+
341+
// The instructions passed in have to be strictly increasing in terms of endpoint index
342+
if (i != 0 && instructionIndex <= lastIndex) {
343+
revert UnorderedInstructions();
344+
}
345+
lastIndex = instructionIndex;
346+
347+
instructions[instructionIndex] = instruction;
334348
}
335349

336350
encoded.checkLength(offset);
337351

338352
return instructions;
339353
}
340-
341-
/*
342-
* @dev This function takes a list of EndpointInstructions and expands them to a 256-length list,
343-
* inserting each instruction into the expanded list based on `instruction.index`.
344-
*/
345-
function sortEndpointInstructions(EndpointInstruction[] memory instructions)
346-
public
347-
pure
348-
returns (EndpointInstruction[] memory)
349-
{
350-
EndpointInstruction[] memory sortedInstructions = new EndpointInstruction[](type(uint8).max);
351-
for (uint8 i = 0; i < instructions.length; i++) {
352-
sortedInstructions[instructions[i].index] = instructions[i];
353-
}
354-
return sortedInstructions;
355-
}
356354
}

0 commit comments

Comments
 (0)