-
Notifications
You must be signed in to change notification settings - Fork 360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add succinct lightclient ISM #4334
base: main
Are you sure you want to change the base?
Changes from all commits
bdc535f
56673cf
44d079e
9ee112b
252f2d4
59eeb98
ef903da
98e09ae
2b63e14
24ee39f
b7cd7f6
2bc9fee
0af2020
67979a1
ed2d545
29e4ca4
2a4681e
69cafaa
4d2957c
122cf29
b5a8f8f
df5731c
79b4f8c
36a9d1f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@hyperlane-xyz/ccip-server': minor | ||
'@hyperlane-xyz/core': minor | ||
--- | ||
|
||
Add SP1LightClient ISM, DispatchedHook. Update CCIP server and ProofService to make a request to beacon node and RPC for proofs. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.13; | ||
|
||
import {AbstractPostDispatchHook} from "./libs/AbstractPostDispatchHook.sol"; | ||
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; | ||
import {Message} from "../libs/Message.sol"; | ||
|
||
/** | ||
* @title DispatchedHook | ||
* @notice Hook that updates a mapping to keep track of dispatched messages | ||
*/ | ||
contract DispatchedHook is AbstractPostDispatchHook { | ||
Check failure Code scanning / Olympix Integrated Security Contracts that can receive ether but cannot send it may lock value permanently. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/locked-ether Critical
Contracts that can receive ether but cannot send it may lock value permanently. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/locked-ether
|
||
using Message for bytes; | ||
|
||
mapping(uint256 messageNonce => bytes32 messageId) public dispatched; | ||
Check warning Code scanning / Olympix Integrated Security Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables Medium
Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables
|
||
|
||
/// @inheritdoc IPostDispatchHook | ||
function hookType() external pure returns (uint8) { | ||
return uint8(IPostDispatchHook.Types.DISPATCHED); | ||
} | ||
|
||
/** | ||
* @notice Sets the dispatched mapping to be used for storage proofs in the Telepathy CCIP ISM. | ||
* @param message Message to be dispatched | ||
*/ | ||
function _postDispatch( | ||
bytes calldata, | ||
bytes calldata message | ||
) internal virtual override { | ||
dispatched[message.nonce()] = message.id(); | ||
} | ||
|
||
/// @inheritdoc AbstractPostDispatchHook | ||
function _quoteDispatch( | ||
bytes calldata, | ||
bytes calldata | ||
) internal view virtual override returns (uint256) { | ||
return 0; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.0; | ||
Check notice Code scanning / Olympix Integrated Security Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma Low
Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma
|
||
|
||
interface ISP1LightClient { | ||
/// @notice The latest slot the light client has a finalized header for. | ||
function head() external view returns (uint256); | ||
|
||
/// @notice Maps from a slot to the current finalized ethereum1 execution state root. | ||
function executionStateRoots(uint256) external view returns (bytes32); | ||
|
||
/// @notice Maps from a period to the poseidon commitment for the sync committee. | ||
function syncCommitteePoseidons(uint256) external view returns (bytes32); | ||
|
||
function GENESIS_TIME() external view returns (uint256); | ||
|
||
function SECONDS_PER_SLOT() external view returns (uint256); | ||
|
||
function SLOTS_PER_PERIOD() external view returns (uint256); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.0; | ||
Check notice Code scanning / Olympix Integrated Security Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma Low
Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma
|
||
|
||
/** | ||
* @title ERC-3668 Succinct Prover Service Interface | ||
* @dev See https://eips.ethereum.org/EIPS/eip-3668 | ||
* @dev This interface is not intended to be implemented as a contract. | ||
* Instead, it is the interface for ProofsService.ts in the ccip-server. | ||
*/ | ||
interface ISuccinctProofsService { | ||
/** | ||
* Requests the Succinct proof, state proof, and returns account and storage proof | ||
* @param target contract address to get the proof for | ||
* @param storageKey storage key to get the proof for | ||
* @param slot current head slot of the LightClient | ||
*/ | ||
function getProofs( | ||
address target, | ||
bytes32 storageKey, | ||
uint256 slot | ||
) external view returns (string[][] memory proofs); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.0; | ||
Check notice Code scanning / Olympix Integrated Security Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma Low
Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma
|
||
|
||
/*@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@@@@@@@@@@@@@@@@@ | ||
@@@@@ HYPERLANE @@@@@@@ | ||
@@@@@@@@@@@@@@@@@@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@*/ | ||
|
||
// ============ External Imports ============ | ||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
import {ISP1LightClient} from "../../interfaces/ISP1LightClient.sol"; | ||
|
||
// ============ Internal Imports ============ | ||
|
||
import {AbstractCcipReadIsm} from "./AbstractCcipReadIsm.sol"; | ||
import {Message} from "../../libs/Message.sol"; | ||
import {Mailbox} from "../../Mailbox.sol"; | ||
import {DispatchedHook} from "../../hooks/DispatchedHook.sol"; | ||
import {StorageProof} from "../../libs/StateProofHelpers.sol"; | ||
import {ISuccinctProofsService} from "../../interfaces/ccip-gateways/ISuccinctProofsService.sol"; | ||
import {StorageProofIsm} from "./StorageProofIsm.sol"; | ||
|
||
/** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would love some readme/mermaid diagrams explain the general architecture |
||
* @title SP1LightClientIsm | ||
* @notice Uses Succinct to verify that a message was delivered via a Hyperlane Mailbox and tracked by DispatchedHook | ||
*/ | ||
contract SP1LightClientIsm is StorageProofIsm { | ||
using Message for bytes; | ||
|
||
/** | ||
* @notice Gets the current head state root from Succinct LightClient | ||
*/ | ||
function getHeadStateRoot() public view override returns (bytes32) { | ||
return | ||
ISP1LightClient(lightClient).executionStateRoots( | ||
ISP1LightClient(lightClient).head() | ||
); | ||
} | ||
|
||
function getHeadStateSlot() public view override returns (uint256) { | ||
return ISP1LightClient(lightClient).head(); | ||
} | ||
|
||
/** | ||
* @notice Reverts with the data needed to query Succinct for header proofs | ||
* @dev See https://eips.ethereum.org/EIPS/eip-3668 for more information | ||
* @param _message encoded Message that will be included in offchain query | ||
* | ||
* @dev In the future, check if fees have been paid before request a proof from Succinct. | ||
* For now this feature is not complete according to the Succinct team. | ||
*/ | ||
function getOffchainVerifyInfo( | ||
bytes calldata _message | ||
) external view override { | ||
revert OffchainLookup( | ||
Check warning Code scanning / Olympix Integrated Security Test functions fail to verify specific revert reasons, potentially missing important contract behavior validation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-revert-reason-tests Medium
Test functions fail to verify specific revert reasons, potentially missing important contract behavior validation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-revert-reason-tests
|
||
address(this), | ||
offchainUrls, | ||
abi.encodeWithSelector( | ||
ISuccinctProofsService.getProofs.selector, | ||
address(dispatchedHook), | ||
dispatchedSlotKey(_message.nonce()), | ||
getHeadStateSlot() | ||
), | ||
StorageProofIsm.process.selector, | ||
_message | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.0; | ||
Check notice Code scanning / Olympix Integrated Security Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma Low
Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma
|
||
|
||
/*@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@@@@@@@@@@@@@@@@@ | ||
@@@@@ HYPERLANE @@@@@@@ | ||
@@@@@@@@@@@@@@@@@@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@@ | ||
@@@@@@@@@ @@@@@@@@*/ | ||
|
||
// ============ External Imports ============ | ||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
|
||
// ============ Internal Imports ============ | ||
|
||
import {AbstractCcipReadIsm} from "./AbstractCcipReadIsm.sol"; | ||
import {Message} from "../../libs/Message.sol"; | ||
import {Mailbox} from "../../Mailbox.sol"; | ||
import {DispatchedHook} from "../../hooks/DispatchedHook.sol"; | ||
import {StorageProof} from "../../libs/StateProofHelpers.sol"; | ||
import {ISuccinctProofsService} from "../../interfaces/ccip-gateways/ISuccinctProofsService.sol"; | ||
|
||
/** | ||
* @title StorageProofIsm | ||
* @notice Uses a LightClient to verify that a message was delivered via a Hyperlane Mailbox and tracked by DispatchedHook | ||
*/ | ||
abstract contract StorageProofIsm is AbstractCcipReadIsm, OwnableUpgradeable { | ||
using Message for bytes; | ||
|
||
/// @notice LightClient to read the state root from | ||
address public lightClient; | ||
Check warning Code scanning / Olympix Integrated Security Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables Medium
Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables
|
||
|
||
/// @notice Destination Mailbox | ||
Mailbox public mailbox; | ||
Check warning Code scanning / Olympix Integrated Security Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables Medium
Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables
|
||
|
||
/// @notice Source DispatchedHook | ||
DispatchedHook public dispatchedHook; | ||
Check warning Code scanning / Olympix Integrated Security Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables Medium
Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables
|
||
|
||
/// @notice Slot # of the Source DispatchedHook.dispatched store that will be used to generate a Storage Key. The resulting Key will be passed into eth_getProof | ||
uint256 public dispatchedSlot; | ||
Check warning Code scanning / Olympix Integrated Security Using uninitialized state variables may lead to unexpected behavior. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/uninitialized-state-variable Medium
Using uninitialized state variables may lead to unexpected behavior. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/uninitialized-state-variable
Check warning Code scanning / Olympix Integrated Security Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables Medium
Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables
|
||
|
||
/// @notice Array of Gateway URLs that the Relayer will call to fetch proofs | ||
string[] public offchainUrls; | ||
Check warning Code scanning / Olympix Integrated Security Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables Medium
Some state variables are not being fuzzed in test functions, potentially leaving vulnerabilities unexplored. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-variables
|
||
|
||
/** | ||
* @param _mailbox the destination chain Mailbox | ||
* @param _dispatchedHook the source chain DispatchedHook | ||
* @param _dispatchedSlot the source chain DispatchedHook slot number of the dispatched mapping | ||
* @param _offchainUrls urls to make ccip read queries | ||
*/ | ||
function initialize( | ||
address _mailbox, | ||
address _dispatchedHook, | ||
address _lightClient, | ||
uint256 _dispatchedSlot, | ||
string[] memory _offchainUrls | ||
) external initializer { | ||
__Ownable_init(); | ||
mailbox = Mailbox(_mailbox); | ||
dispatchedHook = DispatchedHook(_dispatchedHook); | ||
lightClient = _lightClient; | ||
dispatchedSlot = _dispatchedSlot; | ||
offchainUrls = _offchainUrls; | ||
} | ||
|
||
function offchainUrlsLength() external view returns (uint256) { | ||
return offchainUrls.length; | ||
} | ||
|
||
/** | ||
* @notice Sets the offchain urls used by CCIP read. | ||
* The first url will be used and if the request fails, the next one will be used, and so on | ||
* @param _urls an allowlist of urls that will get passed into the Gateway | ||
*/ | ||
function setOffchainUrls(string[] memory _urls) external onlyOwner { | ||
require(_urls.length > 0, "!length"); | ||
Check warning Code scanning / Olympix Integrated Security Test functions fail to verify specific revert reasons, potentially missing important contract behavior validation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-revert-reason-tests Medium
Test functions fail to verify specific revert reasons, potentially missing important contract behavior validation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-revert-reason-tests
|
||
offchainUrls = _urls; | ||
} | ||
|
||
/** | ||
* @notice Verifies that the message id is valid by using the headers by Succinct and eth_getProof | ||
* @dev Basically, this checks if the DispatchedHook.dispatched has messageId set on the source chain | ||
* @param _proofs accountProof and storageProof from eth_getProof | ||
* @param _message Hyperlane encoded interchain message | ||
* @return True if the message was dispatched by source Mailbox | ||
*/ | ||
function verify( | ||
bytes calldata _proofs, | ||
bytes calldata _message | ||
) external view returns (bool) { | ||
try | ||
this.getDispatchedValue( | ||
_proofs, | ||
dispatchedSlotKey(_message.nonce()) | ||
) | ||
returns (bytes memory dispatchedMessageId) { | ||
return keccak256(dispatchedMessageId) != _message.id(); | ||
} catch { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* @notice Gets the slot value of DispatchedHook.dispatched mapping given a slot key and proofs | ||
* @param _proofs encoded account proof and storage proof | ||
* @param _dispatchedSlotKey hash of the source chain DispatchedHook slot number to do a storage proof for | ||
* @return byte value of the dispatched[nonce] | ||
*/ | ||
function getDispatchedValue( | ||
bytes calldata _proofs, | ||
bytes32 _dispatchedSlotKey | ||
) public view returns (bytes memory) { | ||
// Get the slot value as bytes | ||
bytes[][2] memory proofs = abi.decode(_proofs, (bytes[][2])); | ||
Check notice Code scanning / Olympix Integrated Security Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables Low
Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables
|
||
bytes[] memory accountProof = proofs[0]; | ||
Check notice Code scanning / Olympix Integrated Security Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables Low
Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables
|
||
bytes[] memory storageProof = proofs[1]; | ||
Check notice Code scanning / Olympix Integrated Security Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables Low
Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables
|
||
|
||
// Get the storage root of DispatchedHook | ||
bytes32 storageRoot = StorageProof.getStorageRoot( | ||
Check notice Code scanning / Olympix Integrated Security Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables Low
Local variables in test functions are not properly fuzzed, potentially reducing the effectiveness of property-based testing. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unfuzzed-local-variables
|
||
address(dispatchedHook), | ||
accountProof, | ||
getHeadStateRoot() | ||
); | ||
// Returns the value of dispatched | ||
return | ||
StorageProof.getStorageBytes( | ||
keccak256(abi.encode(_dispatchedSlotKey)), | ||
storageProof, | ||
storageRoot | ||
); | ||
} | ||
|
||
/** | ||
* @notice Gets the current head state root from LightClient | ||
*/ | ||
function getHeadStateRoot() public view virtual returns (bytes32); | ||
|
||
/** | ||
* @notice Gets the current head state slot from LightClient | ||
*/ | ||
function getHeadStateSlot() public view virtual returns (uint256); | ||
|
||
/** | ||
* @notice Calculates storage key of the source chain DispatchedHook.dispatched mapping | ||
* @param _messageNonce message nonce | ||
* | ||
* mapping(uint256 messageNonce => messageId) | ||
*/ | ||
function dispatchedSlotKey( | ||
uint32 _messageNonce | ||
) public view returns (bytes32) { | ||
return keccak256(abi.encode(_messageNonce, dispatchedSlot)); | ||
} | ||
|
||
/** | ||
* @notice Callback after CCIP read activities are complete. | ||
* @dev See https://eips.ethereum.org/EIPS/eip-3668 for more information | ||
* @param _proofs response from CCIP read that will be passed back to verify() through the DispatchedHook | ||
* @param _message data that will help construct the offchain query | ||
*/ | ||
function process(bytes calldata _proofs, bytes calldata _message) external { | ||
mailbox.process(_proofs, _message); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be configurable to correctly meter for the relayer gas consumption of the ISM?