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): implement Bridge.isMessageFailed #13004

Merged
merged 11 commits into from
Jan 21, 2023
14 changes: 14 additions & 0 deletions packages/protocol/contracts/bridge/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ contract Bridge is EssentialContract, IBridge {
});
}

function isMessageFailed(
bytes32 msgHash,
uint256 destChainId,
bytes calldata proof
) public view virtual override returns (bool) {
return
LibBridgeStatus.isMessageFailed({
resolver: AddressResolver(this),
msgHash: msgHash,
destChainId: destChainId,
proof: proof
});
}

function getMessageStatus(
bytes32 msgHash
) public view virtual returns (LibBridgeStatus.MessageStatus) {
Expand Down
7 changes: 7 additions & 0 deletions packages/protocol/contracts/bridge/IBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ interface IBridge {
bytes calldata proof
) external view returns (bool);

/// Checks if a msgHash has been failed on the destination chain.
function isMessageFailed(
bytes32 msgHash,
uint256 destChainId,
bytes calldata proof
) external view returns (bool);

/// Returns the bridge state context.
function context() external view returns (Context memory context);
}
6 changes: 6 additions & 0 deletions packages/protocol/contracts/bridge/libs/LibBridgeData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pragma solidity ^0.8.9;

import "../../common/AddressResolver.sol";
import "../../libs/LibAddress.sol";
import "../../libs/LibBlockHeader.sol";
import "../../libs/LibMath.sol";
import "../IBridge.sol";

Expand All @@ -23,6 +24,11 @@ library LibBridgeData {
uint256[46] __gap;
}

struct StatusProof {
BlockHeader header;
bytes proof;
}

bytes32 internal constant MESSAGE_HASH_PLACEHOLDER = bytes32(uint256(1));
uint256 internal constant CHAINID_PLACEHOLDER = type(uint256).max;
address internal constant SRC_CHAIN_SENDER_PLACEHOLDER =
Expand Down
40 changes: 40 additions & 0 deletions packages/protocol/contracts/bridge/libs/LibBridgeStatus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@

pragma solidity ^0.8.9;

import "../../common/IHeaderSync.sol";
import "../../libs/LibBlockHeader.sol";
import "../../libs/LibTrieProof.sol";
import "./LibBridgeData.sol";

/**
* @author dantaik <[email protected]>
*/
library LibBridgeStatus {
using LibBlockHeader for BlockHeader;

enum MessageStatus {
NEW,
RETRIABLE,
Expand Down Expand Up @@ -52,6 +59,39 @@ library LibBridgeStatus {
return keccak256(abi.encodePacked("MESSAGE_STATUS", msgHash));
}

function isMessageFailed(
AddressResolver resolver,
bytes32 msgHash,
uint256 destChainId,
bytes calldata proof
) internal view returns (bool) {
require(destChainId != block.chainid, "B:destChainId");
require(msgHash != 0, "B:msgHash");

LibBridgeData.StatusProof memory sp = abi.decode(
proof,
(LibBridgeData.StatusProof)
);
bytes32 syncedHeaderHash = IHeaderSync(resolver.resolve("taiko", false))
.getSyncedHeader(sp.header.height);

if (
syncedHeaderHash == 0 ||
syncedHeaderHash != sp.header.hashBlockHeader()
) {
return false;
}

return
LibTrieProof.verify({
stateRoot: sp.header.stateRoot,
addr: resolver.resolve(destChainId, "bridge", false),
slot: getMessageStatusSlot(msgHash),
value: bytes32(uint256(LibBridgeStatus.MessageStatus.FAILED)),
mkproof: sp.proof
});
}

function _setMessageStatus(bytes32 msgHash, MessageStatus status) private {
bytes32 slot = getMessageStatusSlot(msgHash);
uint256 value = uint256(status);
Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/tasks/deploy_L1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,13 +240,15 @@ async function deployBaseLibs(hre: any) {
}

async function deployBridge(hre: any, addressManager: string): Promise<any> {
const libTrieProof = await utils.deployContract(hre, "LibTrieProof");
const libBridgeRetry = await utils.deployContract(hre, "LibBridgeRetry");
const libBridgeProcess = await utils.deployContract(
hre,
"LibBridgeProcess"
);

const Bridge = await utils.deployContract(hre, "Bridge", {
LibTrieProof: libTrieProof.address,
LibBridgeRetry: libBridgeRetry.address,
LibBridgeProcess: libBridgeProcess.address,
});
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/test/libs/LibTrieProof.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe("integration:LibTrieProof", function () {
libraries: {
LibBridgeProcess: libBridgeProcess.address,
LibBridgeRetry: libBridgeRetry.address,
LibTrieProof: testLibTreProof.address,
dantaik marked this conversation as resolved.
Show resolved Hide resolved
},
});

Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/test/test_integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ docker run -d \
function waitTestNode {
echo "Waiting for test node: $1"
# Wait till the test node fully started
RETRIES=30
RETRIES=120
i=0
until curl \
--silent \
Expand Down
8 changes: 8 additions & 0 deletions packages/protocol/test/utils/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
SignalService,
EtherVault,
TestHeaderSync,
LibTrieProof,
} from "../../typechain";
import { Message } from "./message";
import { Block, BlockHeader, getBlockHeader } from "./rpc";
Expand All @@ -16,6 +17,12 @@ async function deployBridge(
addressManager: AddressManager,
chainId: number
): Promise<{ bridge: Bridge; etherVault: EtherVault }> {
const libTrieProof: LibTrieProof = await (
await hardhatEthers.getContractFactory("LibTrieProof")
)
.connect(signer)
.deploy();

const libBridgeProcess = await (
await hardhatEthers.getContractFactory("LibBridgeProcess")
)
Expand All @@ -30,6 +37,7 @@ async function deployBridge(

const BridgeFactory = await hardhatEthers.getContractFactory("Bridge", {
libraries: {
LibTrieProof: libTrieProof.address,
LibBridgeProcess: libBridgeProcess.address,
LibBridgeRetry: libBridgeRetry.address,
},
Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/utils/generate_genesis/taikoL2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,12 @@ async function generateContractConfigs(
break;
case "Bridge":
if (
!addressMap.LibTrieProof ||
!addressMap.LibBridgeRetry ||
!addressMap.LibBridgeProcess
) {
throw new Error(
"LibBridgeRetry/LibBridgeProcess not initialized"
"LibTrieProof/LibBridgeRetry/LibBridgeProcess not initialized"
);
}

Expand Down