98 lines
3.8 KiB
Solidity
98 lines
3.8 KiB
Solidity
pragma solidity 0.4.24;
|
|
|
|
library ArbitraryMessage {
|
|
/**
|
|
* @dev Unpacks data fields from AMB message
|
|
* layout of message :: bytes:
|
|
* offset 0 : 32 bytes :: uint256 - message length
|
|
* offset 32 : 32 bytes :: bytes32 - messageId
|
|
* offset 64 : 20 bytes :: address - sender address
|
|
* offset 84 : 20 bytes :: address - executor contract
|
|
* offset 104 : 4 bytes :: uint32 - gasLimit
|
|
* offset 108 : 1 bytes :: uint8 - source chain id length (X)
|
|
* offset 109 : 1 bytes :: uint8 - destination chain id length (Y)
|
|
* offset 110 : 1 bytes :: uint8 - dataType
|
|
* offset 111 : X bytes :: bytes - source chain id
|
|
* offset 111 + X : Y bytes :: bytes - destination chain id
|
|
|
|
* NOTE: when message structure is changed, make sure that MESSAGE_PACKING_VERSION from VersionableAMB is updated as well
|
|
* NOTE: assembly code uses calldatacopy, make sure that message is passed as the first argument in the calldata
|
|
* @param _data encoded message
|
|
*/
|
|
function unpackData(bytes _data)
|
|
internal
|
|
pure
|
|
returns (
|
|
bytes32 messageId,
|
|
address sender,
|
|
address executor,
|
|
uint32 gasLimit,
|
|
uint8 dataType,
|
|
uint256[2] chainIds,
|
|
bytes memory data
|
|
)
|
|
{
|
|
// 32 (message id) + 20 (sender) + 20 (executor) + 4 (gasLimit) + 1 (source chain id length) + 1 (destination chain id length) + 1 (dataType)
|
|
uint256 srcdataptr = 32 + 20 + 20 + 4 + 1 + 1 + 1;
|
|
uint256 datasize;
|
|
|
|
assembly {
|
|
messageId := mload(add(_data, 32)) // 32 bytes
|
|
sender := and(mload(add(_data, 52)), 0xffffffffffffffffffffffffffffffffffffffff) // 20 bytes
|
|
|
|
// executor (20 bytes) + gasLimit (4 bytes) + srcChainIdLength (1 byte) + dstChainIdLength (1 bytes) + dataType (1 byte) + remainder (5 bytes)
|
|
let blob := mload(add(_data, 84))
|
|
|
|
// after bit shift left 12 bytes are zeros automatically
|
|
executor := shr(96, blob)
|
|
gasLimit := and(shr(64, blob), 0xffffffff)
|
|
|
|
dataType := byte(26, blob)
|
|
|
|
// load source chain id length
|
|
let chainIdLength := byte(24, blob)
|
|
|
|
// at this moment srcdataptr points to sourceChainId
|
|
|
|
// mask for sourceChainId
|
|
// e.g. length X -> (1 << (X * 8)) - 1
|
|
let mask := sub(shl(shl(3, chainIdLength), 1), 1)
|
|
|
|
// increase payload offset by length of source chain id
|
|
srcdataptr := add(srcdataptr, chainIdLength)
|
|
|
|
// write sourceChainId
|
|
mstore(chainIds, and(mload(add(_data, srcdataptr)), mask))
|
|
|
|
// at this moment srcdataptr points to destinationChainId
|
|
|
|
// load destination chain id length
|
|
chainIdLength := byte(25, blob)
|
|
|
|
// mask for destinationChainId
|
|
// e.g. length X -> (1 << (X * 8)) - 1
|
|
mask := sub(shl(shl(3, chainIdLength), 1), 1)
|
|
|
|
// increase payload offset by length of destination chain id
|
|
srcdataptr := add(srcdataptr, chainIdLength)
|
|
|
|
// write destinationChainId
|
|
mstore(add(chainIds, 32), and(mload(add(_data, srcdataptr)), mask))
|
|
|
|
// at this moment srcdataptr points to payload
|
|
|
|
// datasize = message length - payload offset
|
|
datasize := sub(mload(_data), srcdataptr)
|
|
}
|
|
|
|
data = new bytes(datasize);
|
|
assembly {
|
|
// 36 = 4 (selector) + 32 (bytes length header)
|
|
srcdataptr := add(srcdataptr, 36)
|
|
|
|
// calldataload(4) - offset of first bytes argument in the calldata
|
|
calldatacopy(add(data, 32), add(calldataload(4), srcdataptr), datasize)
|
|
}
|
|
}
|
|
}
|