-
Notifications
You must be signed in to change notification settings - Fork 33
/
Message.sol
127 lines (109 loc) · 6.02 KB
/
Message.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {BaseMessageLib} from "./BaseMessage.sol";
import {ByteString} from "./ByteString.sol";
import {HEADER_LENGTH} from "../Constants.sol";
import {MemView, MemViewLib} from "./MemView.sol";
import {UnformattedMessage} from "../Errors.sol";
import {MerkleMath} from "../merkle/MerkleMath.sol";
import {Header, HeaderLib, MessageFlag} from "../stack/Header.sol";
/// Message is a memory over over a formatted message payload.
type Message is uint256;
using MessageLib for Message global;
/// Library for formatting the various messages supported by Origin and Destination.
///
/// # Message memory layout
///
/// | Position | Field | Type | Bytes | Description |
/// | ---------- | ------ | ------- | ----- | ------------------------------------------------------- |
/// | [000..017) | header | uint136 | 17 | Encoded general routing information for the message |
/// | [017..AAA) | body | bytes | ?? | Formatted payload (according to flag) with message body |
library MessageLib {
using BaseMessageLib for MemView;
using ByteString for MemView;
using MemViewLib for bytes;
using HeaderLib for MemView;
/// @dev The variables below are not supposed to be used outside of the library directly.
uint256 private constant OFFSET_HEADER = 0;
uint256 private constant OFFSET_BODY = OFFSET_HEADER + HEADER_LENGTH;
// ══════════════════════════════════════════════════ MESSAGE ══════════════════════════════════════════════════════
/**
* @notice Returns formatted message with provided fields.
* @param header_ Encoded general routing information for the message
* @param body_ Formatted payload (according to flag) with message body
* @return Formatted message
*/
function formatMessage(Header header_, bytes memory body_) internal pure returns (bytes memory) {
return abi.encodePacked(header_, body_);
}
/**
* @notice Returns a Message view over for the given payload.
* @dev Will revert if the payload is not a message payload.
*/
function castToMessage(bytes memory payload) internal pure returns (Message) {
return castToMessage(payload.ref());
}
/**
* @notice Casts a memory view to a Message view.
* @dev Will revert if the memory view is not over a message payload.
*/
function castToMessage(MemView memView) internal pure returns (Message) {
if (!isMessage(memView)) revert UnformattedMessage();
return Message.wrap(MemView.unwrap(memView));
}
/**
* @notice Checks that a payload is a formatted Message.
*/
function isMessage(MemView memView) internal pure returns (bool) {
uint256 length = memView.len();
// Check if headers exist in the payload
if (length < OFFSET_BODY) return false;
// Check that Header is valid
uint256 paddedHeader = _header(memView);
if (!HeaderLib.isHeader(paddedHeader)) return false;
// Check that body is formatted according to the flag
// Only Base/Manager message flags exist
if (HeaderLib.wrapPadded(paddedHeader).flag() == MessageFlag.Base) {
// Check if body is a formatted base message
return _body(memView).isBaseMessage();
} else {
// Check if body is a formatted calldata for AgentManager call
return _body(memView).isCallData();
}
}
/// @notice Convenience shortcut for unwrapping a view.
function unwrap(Message message) internal pure returns (MemView) {
return MemView.wrap(Message.unwrap(message));
}
/// @notice Returns message's hash: a leaf to be inserted in the Merkle tree.
function leaf(Message message) internal pure returns (bytes32) {
// We hash header and body separately to make message proofs easier to verify
Header header_ = message.header();
// Only Base/Manager message flags exist
if (header_.flag() == MessageFlag.Base) {
return MerkleMath.getParent(header_.leaf(), message.body().castToBaseMessage().leaf());
} else {
return MerkleMath.getParent(header_.leaf(), message.body().castToCallData().leaf());
}
}
// ══════════════════════════════════════════════ MESSAGE SLICING ══════════════════════════════════════════════════
/// @notice Returns message's encoded header field.
function header(Message message) internal pure returns (Header) {
return HeaderLib.wrapPadded((message.unwrap().indexUint({index_: OFFSET_HEADER, bytes_: HEADER_LENGTH})));
}
/// @notice Returns message's body field as an untyped memory view.
function body(Message message) internal pure returns (MemView) {
MemView memView = message.unwrap();
return _body(memView);
}
// ══════════════════════════════════════════════ PRIVATE HELPERS ══════════════════════════════════════════════════
/// @dev Returns message's padded header without checking that it is a valid header.
function _header(MemView memView) private pure returns (uint256) {
return memView.indexUint({index_: OFFSET_HEADER, bytes_: HEADER_LENGTH});
}
/// @dev Returns an untyped memory view over the body field without checking
/// if the whole payload or the body are properly formatted.
function _body(MemView memView) private pure returns (MemView) {
return memView.sliceFrom({index_: OFFSET_BODY});
}
}