Skip to content
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(protocol): fix signal service multi-hop proof verification bugs #15680

Merged
merged 98 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
ab12a57
breaking change by removing signal service overhead
dantaik Feb 5, 2024
3744fc8
Merge branch 'alpha-6' into alpha-7
dantaik Feb 5, 2024
b5728d1
Merge branch 'alpha-6' into alpha-7
dantaik Feb 6, 2024
a0f5efb
remove signalRoot step 1
dantaik Feb 7, 2024
019ef54
Update LibProving.sol
dantaik Feb 7, 2024
45e8ceb
more
dantaik Feb 7, 2024
9224460
Update LibUtils.sol
dantaik Feb 7, 2024
758ab07
Update LibVerifying.sol
dantaik Feb 7, 2024
71396f4
more
dantaik Feb 7, 2024
5aa18f5
Update TaikoL2.sol
dantaik Feb 7, 2024
b050af5
Update TaikoL2.sol
dantaik Feb 7, 2024
f978d83
Update TaikoL2.sol
dantaik Feb 7, 2024
7f48859
Make code compiling
Feb 7, 2024
ed3d47c
Add back helpers and uncomment lines
Feb 7, 2024
d6def2a
fix anchor
dantaik Feb 7, 2024
27de76a
Update TaikoL2.sol
dantaik Feb 7, 2024
05dd063
Update TaikoL2.t.sol
dantaik Feb 7, 2024
2e22f3e
minor
dantaik Feb 7, 2024
28134d6
rename
dantaik Feb 7, 2024
1e70e33
rename
dantaik Feb 7, 2024
425be15
update multi-hop bridging diagrams
dantaik Feb 7, 2024
7a2d7f2
more error messages in signal service
dantaik Feb 7, 2024
0a809f9
Update SignalService.sol
dantaik Feb 7, 2024
27f51d3
Update SignalService.sol
dantaik Feb 7, 2024
2bd445b
Update SignalService.sol
dantaik Feb 7, 2024
8200313
Update SignalService.sol
dantaik Feb 7, 2024
9ded143
comments
dantaik Feb 7, 2024
bef6290
Update LibVerifying.sol
dantaik Feb 7, 2024
c6e72ff
more
dantaik Feb 7, 2024
528288d
Update TaikoL2.sol
dantaik Feb 7, 2024
f8986e4
more
dantaik Feb 7, 2024
13e3f1f
more
dantaik Feb 7, 2024
70a26a4
remove unnecessary resolve
Feb 7, 2024
4ad3781
remove LibBlockHeader
dantaik Feb 8, 2024
5059135
Delete RLPWriter.sol
dantaik Feb 8, 2024
3abba11
more
dantaik Feb 8, 2024
c292c4d
more
dantaik Feb 8, 2024
7ead006
Remove mint
dantaik Feb 8, 2024
dbd15c5
Merge branch 'alpha-7' into remove-signal-root
dantaik Feb 8, 2024
8cc3469
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 8, 2024
30db4aa
more
dantaik Feb 8, 2024
cede345
more
dantaik Feb 8, 2024
8eaf042
Update SignalService.sol
dantaik Feb 8, 2024
0fc2c39
more
dantaik Feb 8, 2024
7bfe4c0
Update MultihopGraph.sol
dantaik Feb 8, 2024
45ed3e5
Update SignalService.sol
dantaik Feb 8, 2024
3c78fb8
Update SignalService.sol
dantaik Feb 8, 2024
f76d680
Update MultihopGraph.sol
dantaik Feb 8, 2024
d2ee9b5
Update MultihopGraph.sol
dantaik Feb 8, 2024
0821cad
Merge branch 'alpha-6' into alpha-7
dantaik Feb 8, 2024
f2cdc30
Update MultiHopGraph.sol
dantaik Feb 8, 2024
b28c832
more
dantaik Feb 8, 2024
9f3c136
Merge branch 'alpha-6' into alpha-7
dantaik Feb 8, 2024
b86f7c5
Merge branch 'alpha-7' into remove-signal-root
dantaik Feb 8, 2024
cae97d3
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 8, 2024
d98614b
Delete AuthorizableContract.t.sol
dantaik Feb 8, 2024
ac07d4a
more
dantaik Feb 8, 2024
911c424
fix tests
dantaik Feb 8, 2024
92066ab
fix tests
dantaik Feb 8, 2024
b9d264c
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 8, 2024
5adc75c
Update TaikoData.sol
dantaik Feb 8, 2024
df57594
rename
dantaik Feb 8, 2024
41220d0
Update SignalService.t.sol
dantaik Feb 8, 2024
11a0a8a
more
dantaik Feb 8, 2024
3cfaf13
more
dantaik Feb 8, 2024
a090455
more
dantaik Feb 8, 2024
458234a
Merge branch 'main' into remove-signal-root
dantaik Feb 9, 2024
4f12970
Update TaikoToken.sol
dantaik Feb 9, 2024
67b9e4f
fix
dantaik Feb 9, 2024
233f712
Update SignalService.sol
dantaik Feb 9, 2024
5b46768
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 9, 2024
101a2e5
fix
dantaik Feb 9, 2024
e3be732
more
dantaik Feb 9, 2024
fb0128a
Update SignalService.sol
dantaik Feb 9, 2024
1eac276
more
dantaik Feb 9, 2024
6c6b9d7
more
dantaik Feb 9, 2024
2227678
fmt
dantaik Feb 9, 2024
03468a0
doc
dantaik Feb 9, 2024
0b2069c
Update SignalService.sol
dantaik Feb 9, 2024
84fc2ae
add one test
dantaik Feb 9, 2024
52147b3
reserve 2 slots for TaikoData.Transition
dantaik Feb 9, 2024
08c0ae2
Revert "reserve 2 slots for TaikoData.Transition"
dantaik Feb 9, 2024
0ed00af
fmt
dantaik Feb 9, 2024
1ad9404
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 9, 2024
538b2ab
fix
dantaik Feb 9, 2024
d19ac48
Update taikoL2.ts
dantaik Feb 9, 2024
2826b17
Merge branch 'main' into remove-signal-root
dantaik Feb 9, 2024
5a4dd4a
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 9, 2024
f73c33a
fix comment
dantaik Feb 9, 2024
238f8a4
Update packages/protocol/contracts/L1/TaikoL1.sol
dantaik Feb 9, 2024
93869d9
Update packages/protocol/contracts/signal/SignalService.sol
dantaik Feb 9, 2024
57b73c5
Update packages/protocol/contracts/L2/TaikoL2.sol
dantaik Feb 9, 2024
298bd20
Update packages/protocol/contracts/signal/SignalService.sol
dantaik Feb 9, 2024
c0b39c8
Update PseZkVerifier.sol
dantaik Feb 9, 2024
a2771e7
Merge branch 'main' into remove-signal-root
dantaik Feb 10, 2024
f9d0b26
Merge branch 'remove-signal-root' into fix-multi-hop-trust-graph-issue
dantaik Feb 10, 2024
76fef95
Merge branch 'main' into fix-multi-hop-trust-graph-issue
dantaik Feb 10, 2024
319dc9e
fix merge
dantaik Feb 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 0 additions & 42 deletions packages/protocol/contracts/common/AuthorizableContract.sol

This file was deleted.

101 changes: 101 additions & 0 deletions packages/protocol/contracts/signal/HopRelayRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: MIT
// _____ _ _ _ _
// |_ _|_ _(_) |_____ | | __ _| |__ ___
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-<
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/
//
// Email: security@taiko.xyz
// Website: https://taiko.xyz
// GitHub: https://github.com/taikoxyz
// Discord: https://discord.gg/taikoxyz
// Twitter: https://twitter.com/taikoxyz
// Blog: https://mirror.xyz/labs.taiko.eth
// Youtube: https://www.youtube.com/@taikoxyz

pragma solidity 0.8.24;

import "../common/EssentialContract.sol";
import "./IHopRelayRegistry.sol";

/// @title HopRelayRegistry
contract HopRelayRegistry is EssentialContract, IHopRelayRegistry {
mapping(uint64 => mapping(uint64 => mapping(address => bool))) internal registry;
uint256[49] private __gap;

event RelayRegistered(
uint64 indexed srcChainId,
uint64 indexed hopChainId,
address indexed hopRelay,
bool registered
);

error MHG_INVALID_PARAMS();
error MHG_INVALID_STATE();

function init() external initializer {
__Essential_init();
}

/// @dev Register a trusted hop relay.
/// @param srcChainId The source chain ID where state roots correspond to.
/// @param hopChainId The hop relay's local chain ID.
/// @param hopRelay The address of the relay.
function registerRelay(
uint64 srcChainId,
uint64 hopChainId,
address hopRelay
)
external
onlyOwner
{
_registerRelay(srcChainId, hopChainId, hopRelay, true);
}

/// @dev Deregister a trusted hop relay.
/// @param srcChainId The source chain ID where state roots correspond to.
/// @param hopChainId The hop relay's local chain ID.
/// @param hopRelay The address of the relay.
function deregisterRelay(
uint64 srcChainId,
uint64 hopChainId,
address hopRelay
)
external
onlyOwner
{
_registerRelay(srcChainId, hopChainId, hopRelay, false);
}

/// @inheritdoc IHopRelayRegistry
function isRelayRegistered(
uint64 srcChainId,
uint64 hopChainId,
address hopRelay
)
public
view
returns (bool)
{
return registry[srcChainId][hopChainId][hopRelay];
}

function _registerRelay(
uint64 srcChainId,
uint64 hopChainId,
address hopRelay,
bool registered
)
private
{
if (
srcChainId == 0 || hopChainId == 0 || srcChainId == hopChainId || hopRelay == address(0)
) {
revert MHG_INVALID_PARAMS();
}
if (registry[srcChainId][hopChainId][hopRelay] == registered) {
revert MHG_INVALID_STATE();
}
registry[srcChainId][hopChainId][hopRelay] = registered;
emit RelayRegistered(srcChainId, hopChainId, hopRelay, registered);
}
}
35 changes: 35 additions & 0 deletions packages/protocol/contracts/signal/IHopRelayRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
// _____ _ _ _ _
// |_ _|_ _(_) |_____ | | __ _| |__ ___
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-<
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/
//
// Email: security@taiko.xyz
// Website: https://taiko.xyz
// GitHub: https://github.com/taikoxyz
// Discord: https://discord.gg/taikoxyz
// Twitter: https://twitter.com/taikoxyz
// Blog: https://mirror.xyz/labs.taiko.eth
// Youtube: https://www.youtube.com/@taikoxyz

pragma solidity 0.8.24;

/// @title IHopRelayRegistry
/// @notice A registry of hop relays for multi-hop bridging.
// A hop relay is a contract that relays a corresponding chain's state roots to its loal signal
// service.
interface IHopRelayRegistry {
/// @dev Returns if a relay is trusted.
/// @param srcChainId The source chain ID where state roots correspond to.
/// @param hopChainId The hop relay's local chain ID.
/// @param hopRelay The address of the relay.
/// @return trusted True if the relay is a trusted one.
function isRelayRegistered(
uint64 srcChainId,
uint64 hopChainId,
address hopRelay
)
external
view
returns (bool trusted);
}
85 changes: 51 additions & 34 deletions packages/protocol/contracts/signal/SignalService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
pragma solidity 0.8.24;

import "lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol";
import "../common/AuthorizableContract.sol";
import "../common/EssentialContract.sol";
import "../common/ICrossChainSync.sol";
import "../thirdparty/optimism/trie/SecureMerkleTrie.sol";
import "../thirdparty/optimism/rlp/RLPReader.sol";
import "./IHopRelayRegistry.sol";
import "./ISignalService.sol";

/// @title SignalService
Expand All @@ -31,38 +32,40 @@ import "./ISignalService.sol";
/// Use the respective chain IDs as labels for authorization.
/// Note: SignalService should not authorize Bridges or other Bridgable
/// applications.
contract SignalService is AuthorizableContract, ISignalService {
contract SignalService is EssentialContract, ISignalService {
using SafeCast for uint256;

// merkleProof represents ABI-encoded tuple of (key, value, and proof)
// returned from the eth_getProof() API.
struct Hop {
uint64 chainId;
address relay;
bytes32 stateRoot;
bytes merkleProof;
}

struct Proof {
address crossChainSync;
uint64 height;
bytes merkleProof;
// Ensure that hops are ordered such that those closer to the signal's source chain come
// before others.
Hop[] hops;
}

error SS_INVALID_FUNC_PARAMS();
error SS_INVALID_PROOF_PARAMS();
error SS_CROSS_CHAIN_SYNC_UNAUTHORIZED(uint256 chaindId);
error SS_CROSS_CHAIN_SYNC_ZERO_STATE_ROOT();
error SS_HOP_RELAYER_UNAUTHORIZED();
uint256[50] private __gap;

error SS_INVALID_PARAMS();
error SS_INVALID_PROOF();
error SS_INVALID_APP();
error SS_INVALID_APP_PROOF();
error SS_INVALID_HOP_PROOF();
error SS_INVALID_RELAY();
error SS_INVALID_SIGNAL();
error SS_INVALID_STATE_ROOT();
error SS_MULTIHOP_DISABLED();
error SS_UNSUPPORTED();

/// @dev Initializer to be called after being deployed behind a proxy.
function init() external initializer {
__OwnerUUPSUpgradable_init();
function init(address _addressManager) external initializer {
__Essential_init(_addressManager);
}

/// @inheritdoc ISignalService
Expand Down Expand Up @@ -100,49 +103,50 @@ contract SignalService is AuthorizableContract, ISignalService {
returns (bool)
{
if (app == address(0) || signal == 0 || srcChainId == 0 || srcChainId == block.chainid) {
revert SS_INVALID_FUNC_PARAMS();
revert SS_INVALID_PARAMS();
}

Proof memory p = abi.decode(proof, (Proof));
if (p.crossChainSync == address(0) || p.merkleProof.length == 0) {
revert SS_INVALID_PROOF_PARAMS();
if (!isMultiHopEnabled() && p.hops.length > 0) {
revert SS_MULTIHOP_DISABLED();
}

for (uint256 i; i < p.hops.length; ++i) {
if (p.hops[i].stateRoot == 0 || p.hops[i].merkleProof.length == 0) {
revert SS_INVALID_PROOF_PARAMS();
}
}
uint64 _srcChainId = srcChainId;
address _srcApp = app;
bytes32 _srcSignal = signal;

// p.crossChainSync is either a TaikoL1 contract or a TaikoL2 contract
if (!isAuthorizedAs(p.crossChainSync, bytes32(block.chainid))) {
revert SS_CROSS_CHAIN_SYNC_UNAUTHORIZED(block.chainid);
// Verify hop proofs
IHopRelayRegistry hrr;
if (p.hops.length > 0) {
hrr = IHopRelayRegistry(resolve("hop_relay_registry", false));
}

bytes32 stateRoot = ICrossChainSync(p.crossChainSync).getSyncedSnippet(p.height).stateRoot;
if (stateRoot == 0) revert SS_CROSS_CHAIN_SYNC_ZERO_STATE_ROOT();

// If a signal is sent from chainA -> chainB -> chainC (this chain), we verify the proofs in
// the following order:
// 1. using chainC's latest parent's stateRoot to verify that chainB's TaikoL1/TaikoL2 contract has
// 1. using chainC's latest parent's stateRoot to verify that chainB's TaikoL1/TaikoL2
// contract has
// sent a given hop stateRoot on chainB using its own signal service.
// 2. using the verified hop stateRoot to verify that the source app on chainA has sent a
// signal using its own signal service.
// We always verify the proofs in the reversed order (top to bottom).
for (uint256 i; i < p.hops.length; ++i) {
Hop memory hop = p.hops[i];
if (hop.stateRoot == stateRoot) revert SS_INVALID_HOP_PROOF();

bytes32 label = authorizedAddresses[hop.relay];
if (label == 0) revert SS_HOP_RELAYER_UNAUTHORIZED();
if (!hrr.isRelayRegistered(_srcChainId, hop.chainId, hop.relay)) {
revert SS_INVALID_RELAY();
}

uint64 hopChainId = uint256(label).toUint64();
verifyMerkleProof(hop.stateRoot, _srcChainId, _srcApp, _srcSignal, hop.merkleProof);

verifyMerkleProof(stateRoot, hopChainId, hop.relay, hop.stateRoot, hop.merkleProof);
stateRoot = hop.stateRoot;
_srcChainId = hop.chainId;
_srcApp = hop.relay;
_srcSignal = hop.stateRoot;
}

verifyMerkleProof(stateRoot, srcChainId, app, signal, p.merkleProof);
ICrossChainSync ccs = ICrossChainSync(resolve("taiko", false));
bytes32 stateRoot = ccs.getSyncedSnippet(p.height).stateRoot;

verifyMerkleProof(stateRoot, _srcChainId, _srcApp, _srcSignal, p.merkleProof);
return true;
}

Expand All @@ -157,7 +161,20 @@ contract SignalService is AuthorizableContract, ISignalService {
view
virtual
{
if (stateRoot == 0) revert SS_INVALID_STATE_ROOT();
if (merkleProof.length == 0) revert SS_INVALID_PROOF();

bool verified;

// TODO(dani): implement this please

if (!verified) revert SS_INVALID_PROOF();
}

/// @notice Checks if multi-hop is enabled.
/// @return Returns true if multi-hop bridging is enabled.
function isMultiHopEnabled() public view virtual returns (bool) {
return false;
}

/// @notice Get the storage slot of the signal.
Expand Down
7 changes: 0 additions & 7 deletions packages/protocol/genesis/GenerateGenesis.g.sol
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,6 @@ contract TestGenerateGenesis is Test, AddressResolver {

signalServiceProxy.sendSignal(keccak256(abi.encodePacked(block.prevrandao)));

assertEq(
true,
signalServiceProxy.isAuthorizedAs(
getPredeployedContractAddress("TaikoL2"), bytes32((block.chainid))
)
);

vm.startPrank(ownerSecurityCouncil);

SignalService signalService =
Expand Down
Loading
Loading