Skip to content

Commit

Permalink
feat: PragmaDecoder.sol smol refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
JordyRo1 committed Nov 3, 2024
1 parent 5a6a9b0 commit 512a220
Showing 1 changed file with 42 additions and 59 deletions.
101 changes: 42 additions & 59 deletions solidity/src/PragmaDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,20 @@ abstract contract PragmaDecoder {
}
}

function extractMetadataFromheader(bytes calldata updateData) internal pure returns (uint256 encodedOffset) {
function extractMetadataFromheader(bytes calldata updateData, uint256 offset) internal pure returns (uint256) {
unchecked {
encodedOffset = 0;

{
uint8 majorVersion = UnsafeCalldataBytesLib.toUint8(updateData, encodedOffset);
uint8 majorVersion = UnsafeCalldataBytesLib.toUint8(updateData, offset);

encodedOffset += 1;
offset += 1;

if (majorVersion != ConstantsLib.MAJOR_VERSION) {
revert ErrorsLib.InvalidVersion();
}

uint8 minorVersion = UnsafeCalldataBytesLib.toUint8(updateData, encodedOffset);
uint8 minorVersion = UnsafeCalldataBytesLib.toUint8(updateData, offset);

encodedOffset += 1;
offset += 1;

// Minor versions are forward compatible, so we only check
// that the minor version is not less than the minimum allowed
Expand All @@ -75,75 +73,57 @@ abstract contract PragmaDecoder {

// This field ensure that we can add headers in the future
// without breaking the contract (future compatibility)
uint8 trailingHeaderSize = UnsafeCalldataBytesLib.toUint8(updateData, encodedOffset);
encodedOffset += 1;

// We use another encodedOffset for the trailing header and in the end add the
// encodedOffset by trailingHeaderSize to skip the future headers.
//
// An example would be like this:
// uint trailingHeaderOffset = encodedOffset
// uint x = UnsafeBytesLib.ToUint8(updateData, trailingHeaderOffset)
// trailingHeaderOffset += 1

encodedOffset += trailingHeaderSize;
uint8 trailingHeaderSize = UnsafeCalldataBytesLib.toUint8(updateData, offset);
offset += 1;

offset += trailingHeaderSize;
}

if (updateData.length < encodedOffset) {
if (updateData.length < offset) {
revert ErrorsLib.InvalidUpdateData();
}
}
return offset;
}

function extractCheckpointRootAndNumUpdates(bytes calldata updateData, uint256 encodedOffset)
function extractCheckpointRootAndNumUpdates(bytes calldata updateData, uint256 offset)
internal
view
returns (uint256 offset, bytes32 checkpointRoot, uint8 numUpdates, bytes calldata encoded)
returns (uint256, bytes32 checkpointRoot, uint8 numUpdates)
{
unchecked {
encoded = UnsafeCalldataBytesLib.slice(updateData, encodedOffset, updateData.length - encodedOffset);
offset = 0;

uint16 hyMsgSize = UnsafeCalldataBytesLib.toUint16(encoded, offset);
// Get the size of the hyperlane message
uint16 hyMsgSize = UnsafeCalldataBytesLib.toUint16(updateData, offset);
offset += 2;

{
bytes memory encodedPayload;
{
(HyMsg memory hyMsg, uint256 index, bytes32 root) =
parseAndVerifyHyMsg(UnsafeCalldataBytesLib.slice(encoded, offset, hyMsgSize));
checkpointRoot = root;
encodedPayload = hyMsg.payload;
offset += index;
}
// Extract and verify the hyperlane message
bytes calldata hyMsgData = UnsafeCalldataBytesLib.slice(updateData, offset, hyMsgSize);
(HyMsg memory hyMsg, uint256 index, bytes32 root) = parseAndVerifyHyMsg(hyMsgData);

uint256 payloadOffset = 0;
// Set the checkpoint root and get the payload
checkpointRoot = root;
bytes memory encodedPayload = hyMsg.payload;
offset += index;

{
// We don't check equality to enable future compatibility.
if (payloadOffset > encodedPayload.length) {
revert ErrorsLib.InvalidUpdateData();
}
numUpdates = UnsafeBytesLib.toUint8(encodedPayload, payloadOffset);
offset += encodedOffset + 1;
payloadOffset += 1;
}
}
// Extract the number of updates from the payload
numUpdates = UnsafeBytesLib.toUint8(encodedPayload, 0);
offset += 1;
}
return (offset, checkpointRoot, numUpdates);
}

function _isProofValid(bytes calldata encodedProof, uint256 offset, bytes32 root, bytes calldata leafData)
internal
virtual
returns (bool valid, uint256 endOffset)
returns (bool valid, uint256)
{
// TODO: The proof is ignored for now until we figure out how to get it from Hyperlane.

// (valid, endOffset) = MerkleTree.isProofValid(encodedProof, offset, root, leafData);
return (true, offset);
}

function extractDataInfoFromUpdate(bytes calldata encoded, uint256 offset, bytes32 checkpointRoot)
function extractDataInfoFromUpdate(bytes calldata updateData, uint256 offset, bytes32 checkpointRoot)
internal
returns (uint256 endOffset, ParsedData memory parsedData, bytes32 feedId, uint64 publishTime)
{
Expand All @@ -153,19 +133,22 @@ abstract contract PragmaDecoder {
bytes calldata fulldataFeed;

offset += 2;
uint16 proofSize = UnsafeCalldataBytesLib.toUint16(encoded, offset);
uint16 proofSize = UnsafeCalldataBytesLib.toUint16(updateData, offset);
offset += 2;
{
encodedProof = UnsafeCalldataBytesLib.slice(encoded, offset, proofSize);
encodedProof = UnsafeCalldataBytesLib.slice(updateData, offset, proofSize);
uint256 encodedUpdateIndex = offset + proofSize;
encodedUpdate =
UnsafeCalldataBytesLib.slice(encoded, encodedUpdateIndex, encoded.length - 40 - encodedUpdateIndex); // 32 bytes for feedId, 8 bytes for publishTime
encodedUpdate = UnsafeCalldataBytesLib.slice(
updateData, encodedUpdateIndex, updateData.length - 40 - encodedUpdateIndex
); // 32 bytes for feedId, 8 bytes for publishTime
fulldataFeed =
UnsafeCalldataBytesLib.slice(encoded, encodedUpdateIndex, encoded.length - encodedUpdateIndex);
UnsafeCalldataBytesLib.slice(updateData, encodedUpdateIndex, updateData.length - encodedUpdateIndex);
}
// For now, no proof check
// bool valid;
// (valid, offset) = _isProofValid(encoded, offset, checkpointRoot, encodedUpdate);
// (valid, offset) = _isProofValid(updateData, offset, checkpointRoot, encodedUpdate);
// if (!valid) revert ErrorsLib.InvalidHyperlaneCheckpointRoot();

offset += proofSize;
(parsedData, feedId, publishTime) = parseDataFeed(fulldataFeed);
endOffset = offset + fulldataFeed.length;
Expand All @@ -186,15 +169,15 @@ abstract contract PragmaDecoder {
}

function updateDataInfoFromUpdate(bytes calldata updateData) internal returns (uint8 numUpdates) {
// Extract header metadata
uint256 encodedOffset = extractMetadataFromheader(updateData);
uint256 offset = 0;

// Extract header metadata
offset = extractMetadataFromheader(updateData, offset);
// Extract merkle root and number of updates from update data.
uint256 offset;
// uint256 offset;
bytes32 checkpointRoot;
bytes calldata encoded;

(offset, checkpointRoot, numUpdates, encoded) = extractCheckpointRootAndNumUpdates(updateData, encodedOffset);
(offset, checkpointRoot, numUpdates) = extractCheckpointRootAndNumUpdates(updateData, offset);
unchecked {
for (uint256 i = 0; i < numUpdates; i++) {
ParsedData memory parsedData;
Expand Down

0 comments on commit 512a220

Please sign in to comment.