Skip to content

Commit

Permalink
feat(protocol)!: re-implement multi-hop bridging with optional caching (
Browse files Browse the repository at this point in the history
#15761)

Co-authored-by: David <david@taiko.xyz>
Co-authored-by: D <51912515+adaki2004@users.noreply.github.com>
Co-authored-by: Keszey Dániel <keszeyd@MacBook-Pro.local>
  • Loading branch information
4 people committed Feb 15, 2024
1 parent 136bdb7 commit a3a12de
Show file tree
Hide file tree
Showing 39 changed files with 1,023 additions and 645 deletions.
1 change: 1 addition & 0 deletions packages/protocol/contracts/L1/TaikoErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ abstract contract TaikoErrors {
error L1_BLOB_NOT_REUSEABLE();
error L1_BLOB_NOT_USED();
error L1_BLOCK_MISMATCH();
error L1_CHAIN_DATA_NOT_RELAYED();
error L1_INVALID_BLOCK_ID();
error L1_INVALID_CONFIG();
error L1_INVALID_ETH_DEPOSIT();
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ contract TaikoL1 is
override
returns (ICrossChainSync.Snippet memory)
{
return LibUtils.getSyncedSnippet(state, getConfig(), blockId);
return LibUtils.getSyncedSnippet(state, getConfig(), AddressResolver(this), blockId);
}

/// @notice Gets the state variables of the TaikoL1 contract.
Expand Down
18 changes: 14 additions & 4 deletions packages/protocol/contracts/L1/libs/LibUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@

pragma solidity 0.8.24;

import "../../common/AddressResolver.sol";
import "../../common/ICrossChainSync.sol";
import "../../signal/ISignalService.sol";
import "../../signal/LibSignals.sol";
import "../TaikoData.sol";

/// @title LibUtils
/// @notice A library that offers helper functions.
library LibUtils {
// Warning: Any errors defined here must also be defined in TaikoErrors.sol.
error L1_BLOCK_MISMATCH();
error L1_CHAIN_DATA_NOT_RELAYED();
error L1_INVALID_BLOCK_ID();
error L1_TRANSITION_NOT_FOUND();
error L1_UNEXPECTED_TRANSITION_ID();
Expand Down Expand Up @@ -56,6 +60,7 @@ library LibUtils {
function getSyncedSnippet(
TaikoData.State storage state,
TaikoData.Config memory config,
AddressResolver resolver,
uint64 blockId
)
external
Expand All @@ -70,14 +75,19 @@ library LibUtils {
if (blk.blockId != _blockId) revert L1_BLOCK_MISMATCH();
if (blk.verifiedTransitionId == 0) revert L1_TRANSITION_NOT_FOUND();

TaikoData.TransitionState storage transition =
state.transitions[slot][blk.verifiedTransitionId];
TaikoData.TransitionState storage ts = state.transitions[slot][blk.verifiedTransitionId];

// bool relayed = ISignalService(resolver.resolve("signal_service",
// false)).isChainDataRelayed(
// config.chainId, LibSignals.STATE_ROOT, ts.stateRoot
// );
// if (!relayed) revert L1_CHAIN_DATA_NOT_RELAYED();

return ICrossChainSync.Snippet({
syncedInBlock: blk.proposedIn,
blockId: blockId,
blockHash: transition.blockHash,
stateRoot: transition.stateRoot
blockHash: ts.blockHash,
stateRoot: ts.stateRoot
});
}

Expand Down
5 changes: 4 additions & 1 deletion packages/protocol/contracts/L1/libs/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../common/AddressResolver.sol";
import "../../libs/LibMath.sol";
import "../../signal/ISignalService.sol";
import "../../signal/LibSignals.sol";
import "../tiers/ITierProvider.sol";
import "../TaikoData.sol";
import "./LibUtils.sol";
Expand Down Expand Up @@ -247,7 +248,9 @@ library LibVerifying {
// This also means if we verified more than one block, only the last one's stateRoot
// is sent as a signal and verifiable with merkle proofs, all other blocks'
// stateRoot are not.
ISignalService(resolver.resolve("signal_service", false)).sendSignal(stateRoot);
ISignalService(resolver.resolve("signal_service", false)).relayChainData(
config.chainId, LibSignals.STATE_ROOT, stateRoot
);

emit CrossChainSynced(
uint64(block.number), lastVerifiedBlockId, blockHash, stateRoot
Expand Down
6 changes: 4 additions & 2 deletions packages/protocol/contracts/L2/TaikoL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../common/ICrossChainSync.sol";
import "../signal/ISignalService.sol";
import "../signal/LibSignals.sol";
import "../libs/LibAddress.sol";
import "../libs/LibMath.sol";
import "./Lib1559Math.sol";
Expand Down Expand Up @@ -143,7 +144,9 @@ contract TaikoL2 is CrossChainOwned, ICrossChainSync {

// Store the L1's state root as a signal to the local signal service to
// allow for multi-hop bridging.
ISignalService(resolve("signal_service", false)).sendSignal(l1StateRoot);
ISignalService(resolve("signal_service", false)).relayChainData(
ownerChainId, LibSignals.STATE_ROOT, l1StateRoot
);

emit CrossChainSynced(uint64(block.number), l1Height, l1BlockHash, l1StateRoot);

Expand All @@ -157,7 +160,6 @@ contract TaikoL2 is CrossChainOwned, ICrossChainSync {
});
publicInputHash = publicInputHashNew;
latestSyncedL1Height = l1Height;

emit Anchored(blockhash(parentId), gasExcess);
}

Expand Down
7 changes: 3 additions & 4 deletions packages/protocol/contracts/bridge/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ contract Bridge is EssentialContract, IBridge {
/// @param signal The signal.
/// @param chainId The ID of the chain the signal is stored on
/// @param proof The merkle inclusion proof.
/// @return True if the message was received.
/// @return success True if the message was received.
function _proveSignalReceived(
address signalService,
bytes32 signal,
Expand All @@ -582,13 +582,12 @@ contract Bridge is EssentialContract, IBridge {
)
private
view
returns (bool)
returns (bool success)
{
bytes memory data = abi.encodeCall(
ISignalService.proveSignalReceived,
(chainId, resolve(chainId, "bridge", false), signal, proof)
);
(bool success, bytes memory ret) = signalService.staticcall(data);
return success ? abi.decode(ret, (bool)) : false;
(success,) = signalService.staticcall(data);
}
}
47 changes: 26 additions & 21 deletions packages/protocol/contracts/libs/LibTrieProof.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,42 @@ library LibTrieProof {
error LTP_INVALID_ACCOUNT_PROOF();
error LTP_INVALID_INCLUSION_PROOF();

/**
* Verifies that the value of a slot in the storage of an account is value.
*
* @param stateRoot The merkle root of state tree.
* @param addr The address of contract.
* @param slot The slot in the contract.
* @param value The value to be verified.
* @param mkproof The proof obtained by encoding storage proof.
*/
function verifyFullMerkleProof(
bytes32 stateRoot,
/// @notice Verifies that the value of a slot in the storage of an account is value.
///
/// @param rootHash The merkle root of state tree or the account tree. If accountProof's length
/// is zero, it is used as the account's storage root, otherwise it will be used as the state
/// root.
/// @param addr The address of contract.
/// @param slot The slot in the contract.
/// @param value The value to be verified.
/// @param accountProof The account proof
/// @param storageProof The storage proof
/// @return storageRoot The account's storage root
function verifyMerkleProof(
bytes32 rootHash,
address addr,
bytes32 slot,
bytes memory value,
bytes memory mkproof
bytes[] memory accountProof,
bytes[] memory storageProof
)
internal
pure
returns (bytes32 storageRoot)
{
(bytes[] memory accountProof, bytes[] memory storageProof) =
abi.decode(mkproof, (bytes[], bytes[]));
if (accountProof.length != 0) {
bytes memory rlpAccount =
SecureMerkleTrie.get(abi.encodePacked(addr), accountProof, rootHash);

bytes memory rlpAccount =
SecureMerkleTrie.get(abi.encodePacked(addr), accountProof, stateRoot);
if (rlpAccount.length == 0) revert LTP_INVALID_ACCOUNT_PROOF();

if (rlpAccount.length == 0) revert LTP_INVALID_ACCOUNT_PROOF();
RLPReader.RLPItem[] memory accountState = RLPReader.readList(rlpAccount);

RLPReader.RLPItem[] memory accountState = RLPReader.readList(rlpAccount);

bytes memory storageRoot =
RLPReader.readBytes(accountState[ACCOUNT_FIELD_INDEX_STORAGE_HASH]);
storageRoot =
bytes32(RLPReader.readBytes(accountState[ACCOUNT_FIELD_INDEX_STORAGE_HASH]));
} else {
storageRoot = rootHash;
}

bool verified = SecureMerkleTrie.verifyInclusionProof(
bytes.concat(slot), value, storageProof, bytes32(storageRoot)
Expand Down
101 changes: 0 additions & 101 deletions packages/protocol/contracts/signal/HopRelayRegistry.sol

This file was deleted.

35 changes: 0 additions & 35 deletions packages/protocol/contracts/signal/IHopRelayRegistry.sol

This file was deleted.

Loading

0 comments on commit a3a12de

Please sign in to comment.