Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:defi-wonderland/safe-liveness into f…
Browse files Browse the repository at this point in the history
…ix/storage-mirror-types
  • Loading branch information
0xOneTony committed Nov 21, 2023
2 parents a42a466 + 8e55d38 commit 8111bbd
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 10 deletions.
69 changes: 69 additions & 0 deletions solidity/contracts/StorageMirrorRootRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.19;

import {IBlockHeaderOracle} from 'interfaces/IBlockHeaderOracle.sol';
import {IVerifierModule} from 'interfaces/IVerifierModule.sol';
import {IStorageMirrorRootRegistry} from 'interfaces/IStorageMirrorRootRegistry.sol';

/**
* @title StorageMirrorRootRegistry
* @notice This contract should accept and store storageRoots of the StorageMirror contract in L1.
*/
contract StorageMirrorRootRegistry is IStorageMirrorRootRegistry {
/**
* @notice The address of the StorageMirror contract in Home chain
*/
address public immutable STORAGE_MIRROR;

/**
* @notice The address of the Verifier Module
*/
IVerifierModule public immutable VERIFIER_MODULE;

/**
* @notice The block header oracle
*/
IBlockHeaderOracle public immutable BLOCK_HEADER_ORACLE;

/**
* @notice The latest verified storage root of the StorageMirror contract in Home chain
*/
bytes32 public latestVerifiedStorageMirrorStorageRoot;

/**
* @notice The latest verified block number of the Home chain
*/
uint256 public latestVerifiedBlockNumber;

constructor(address _storageMirror, IVerifierModule _verifierModule, IBlockHeaderOracle _blockHeaderOracle) {
STORAGE_MIRROR = _storageMirror;
VERIFIER_MODULE = _verifierModule;
BLOCK_HEADER_ORACLE = _blockHeaderOracle;
}

/**
* @notice Users can use to propose and verify a storage root of the StorageMirror contract in Home chain
* @dev Calls queryL1BlockHeader to get the block header of the Home chain
* @dev Call verifier module for the actual verificationn
* @param _accountProof The account proof of the StorageMirror contract in Home chain
*/
function proposeAndVerifyStorageMirrorStorageRoot(bytes memory _accountProof) external {
bytes memory _blockHeader = _queryL1BlockHeader();

(bytes32 _latestVerifiedStorageMirrorStorageRoot, uint256 _blockNumber) =
VERIFIER_MODULE.extractStorageMirrorStorageRoot(_blockHeader, _accountProof);

latestVerifiedStorageMirrorStorageRoot = _latestVerifiedStorageMirrorStorageRoot;
latestVerifiedBlockNumber = _blockNumber;

emit VerifiedStorageMirrorStorageRoot(_blockNumber, latestVerifiedStorageMirrorStorageRoot);
}

/**
* @notice Function that queries an oracle to get the latest bridged block header of the Home chain
* @return _blockHeader The block header of the Home chain
*/
function _queryL1BlockHeader() internal view returns (bytes memory _blockHeader) {
(_blockHeader,) = BLOCK_HEADER_ORACLE.getLatestBlockHeader();
}
}
2 changes: 1 addition & 1 deletion solidity/contracts/VerifierModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ contract VerifierModule is IVerifierModule {
IStorageMirror.SafeSettings memory _proposedSettings,
bytes memory _storageMirrorStorageProof
) internal view virtual returns (bytes32 _hashedProposedSettings) {
bytes32 _latestStorageRoot = STORAGE_MIRROR_ROOT_REGISTRY.latestVerifiedStorageRoot();
bytes32 _latestStorageRoot = STORAGE_MIRROR_ROOT_REGISTRY.latestVerifiedStorageMirrorStorageRoot();

// The slot of where the latest settings hash is stored in the storage mirror
bytes32 _safeSettingsSlot = keccak256(abi.encode(_safe, _LATEST_VERIFIED_SETTINGS_SLOT));
Expand Down
46 changes: 44 additions & 2 deletions solidity/interfaces/IStorageMirrorRootRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,57 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.19;

import {IVerifierModule} from 'interfaces/IVerifierModule.sol';
import {IBlockHeaderOracle} from 'interfaces/IBlockHeaderOracle.sol';

interface IStorageMirrorRootRegistry {
/*///////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/

/**
* @notice Emits after the storage root gets verified
* @param _homeChainBlockNumber The block number of the Home chain
* @param _storageRoot The storage root of the StorageMirror contract in Home chain that was verified
*/
event VerifiedStorageMirrorStorageRoot(uint256 indexed _homeChainBlockNumber, bytes32 _storageRoot);

/*///////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////*/

/**
* @notice The latest verified storage root
* @notice The address of the StorageMirror contract in Home chain
* @return _storageMirror The address of the StorageMirror contract in Home chain
*/
function STORAGE_MIRROR() external view returns (address _storageMirror);

/**
* @notice The address of the Verifier Module
* @return _verifierModule The address of the Verifier Module
*/
function VERIFIER_MODULE() external view returns (IVerifierModule _verifierModule);

/**
* @notice The address of the Block Header Oracle
* @return _blockHeaderOracle The address of the Block Header Oracle
*/
function BLOCK_HEADER_ORACLE() external view returns (IBlockHeaderOracle _blockHeaderOracle);

/**
* @notice The latest verified block number of the Home chain
* @return _latestVerifiedBlockNumber The latest verified block number of the Home chain
*/
function latestVerifiedBlockNumber() external view returns (uint256 _latestVerifiedBlockNumber);

/**
* @notice The latest verified storage root of the StorageMirror contract in Home chain
* @return _latestVerifiedStorageMirrorStorageRoot The latest verified storage root of the StorageMirror contract in Home chain
*/
function latestVerifiedStorageRoot() external view returns (bytes32 _latestVerifiedStorageRoot);
function latestVerifiedStorageMirrorStorageRoot()
external
view
returns (bytes32 _latestVerifiedStorageMirrorStorageRoot);

/*///////////////////////////////////////////////////////////////
LOGIC
Expand Down
File renamed without changes.
88 changes: 88 additions & 0 deletions solidity/test/unit/StorageMirrorRootRegistry.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.4 <0.9.0;

import {Test} from 'forge-std/Test.sol';
import {BlockHeaderOracle} from 'contracts/BlockHeaderOracle.sol';
import {StorageMirrorRootRegistry} from 'contracts/StorageMirrorRootRegistry.sol';
import {IBlockHeaderOracle} from 'interfaces/IBlockHeaderOracle.sol';
import {IStorageMirrorRootRegistry} from 'interfaces/IStorageMirrorRootRegistry.sol';
import {IVerifierModule} from 'interfaces/IVerifierModule.sol';

contract StorageMirrorRootRegistryForTest is StorageMirrorRootRegistry {
constructor(
address _storageMirror,
IVerifierModule _verifierModule,
IBlockHeaderOracle _blockHeaderOracle
) StorageMirrorRootRegistry(_storageMirror, _verifierModule, _blockHeaderOracle) {}

function queryL1BlockHeader() external view returns (bytes memory _blockHeader) {
_blockHeader = _queryL1BlockHeader();
}
}

abstract contract Base is Test {
event VerifiedStorageMirrorStorageRoot(uint256 indexed _homeChainBlockNumber, bytes32 _storageRoot);

address public user;
address public storageMirror;
StorageMirrorRootRegistry public storageMirrorRootRegistry;
StorageMirrorRootRegistryForTest public storageMirrorRootRegistryForTest;
BlockHeaderOracle public blockHeaderOracle;
IVerifierModule public verifierModule;

function setUp() public {
user = makeAddr('user');
storageMirror = makeAddr('StorageMirror');
blockHeaderOracle = new BlockHeaderOracle();
verifierModule = IVerifierModule(makeAddr('VerifierModule'));
storageMirrorRootRegistry =
new StorageMirrorRootRegistry(storageMirror, verifierModule, IBlockHeaderOracle(blockHeaderOracle));
storageMirrorRootRegistryForTest =
new StorageMirrorRootRegistryForTest(storageMirror, verifierModule, IBlockHeaderOracle(blockHeaderOracle));
}
}

contract UnitStorageMirrorRootRegistryQueryL1BlockHeader is Base {
function testQueryL1BlockHeader(bytes memory _blockHeader, uint256 _blockTimestamp, uint256 _blockNumber) public {
vm.prank(user);
blockHeaderOracle.updateBlockHeader(_blockHeader, _blockTimestamp, _blockNumber);

vm.expectCall(address(blockHeaderOracle), abi.encodeWithSelector(blockHeaderOracle.getLatestBlockHeader.selector));
vm.prank(user);
bytes memory _savedBlockHeader = storageMirrorRootRegistryForTest.queryL1BlockHeader();

assertEq(_blockHeader, _savedBlockHeader, 'Block header should be saved');
}
}

contract UnitStorageMirrorRootRegistryProposeAndVerifyStorageMirrorStorageRoot is Base {
function testProposeAndVerifyStorageMirrorStorageRoot(bytes memory _accountProof) public {
bytes memory _blockHeader = '0x1234';
uint256 _blockTimestamp = 1234;
uint256 _blockNumber = 1234;
bytes32 _storageRoot = '0x1234';

vm.prank(user);
blockHeaderOracle.updateBlockHeader(_blockHeader, _blockTimestamp, _blockNumber);

vm.mockCall(
address(verifierModule),
abi.encodeWithSelector(verifierModule.extractStorageMirrorStorageRoot.selector, _blockHeader, _accountProof),
abi.encode(_storageRoot, _blockNumber)
);
vm.expectCall(
address(verifierModule),
abi.encodeWithSelector(verifierModule.extractStorageMirrorStorageRoot.selector, _blockHeader, _accountProof)
);

vm.expectEmit(true, true, true, true);
emit VerifiedStorageMirrorStorageRoot(_blockNumber, _storageRoot);

vm.prank(user);
storageMirrorRootRegistry.proposeAndVerifyStorageMirrorStorageRoot(_accountProof);

assertEq(
_storageRoot, storageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot(), 'Storage root should be saved'
);
}
}
15 changes: 8 additions & 7 deletions solidity/test/unit/VerifierModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ contract TestVerifierModule is VerifierModule {
IStorageMirror.SafeSettings memory _proposedSettings,
bytes memory _storageMirrorStorageProof
) public view returns (bytes32 _hashedProposedSettings) {
bytes32 _latestStorageRoot = IStorageMirrorRootRegistry(STORAGE_MIRROR_ROOT_REGISTRY).latestVerifiedStorageRoot();
bytes32 _latestStorageRoot =
IStorageMirrorRootRegistry(STORAGE_MIRROR_ROOT_REGISTRY).latestVerifiedStorageMirrorStorageRoot();

// The slot of where the latest settings hash is stored in the storage mirror
bytes32 _safeSettingsSlot = keccak256(abi.encode(_safe, 0));
Expand Down Expand Up @@ -337,7 +338,7 @@ contract UnitMerklePatriciaTree is Base {

vm.mockCall(
address(_storageMirrorRegistry),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageRoot.selector),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot.selector),
abi.encode(_fakeStorageRoot)
);

Expand Down Expand Up @@ -380,7 +381,7 @@ contract UnitMerklePatriciaTree is Base {

vm.mockCall(
address(_storageMirrorRegistry),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageRoot.selector),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot.selector),
abi.encode(_fakeStorageRoot)
);

Expand Down Expand Up @@ -412,7 +413,7 @@ contract UnitMerklePatriciaTree is Base {

vm.mockCall(
address(_storageMirrorRegistry),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageRoot.selector),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot.selector),
abi.encode(_fakeStorageRoot)
);

Expand Down Expand Up @@ -461,7 +462,7 @@ contract UnitMerklePatriciaTree is Base {

vm.mockCall(
address(_storageMirrorRegistry),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageRoot.selector),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot.selector),
abi.encode(_fakeStorageRoot)
);

Expand Down Expand Up @@ -563,7 +564,7 @@ contract UnitMerklePatriciaTree is Base {

vm.mockCall(
address(_storageMirrorRegistry),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageRoot.selector),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot.selector),
abi.encode(_fakeStorageRoot)
);

Expand Down Expand Up @@ -655,7 +656,7 @@ contract UnitMerklePatriciaTree is Base {

vm.mockCall(
address(_storageMirrorRegistry),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageRoot.selector),
abi.encodeWithSelector(IStorageMirrorRootRegistry.latestVerifiedStorageMirrorStorageRoot.selector),
abi.encode(_fakeStorageRoot)
);

Expand Down

0 comments on commit 8111bbd

Please sign in to comment.