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

Bedrock prod #4414

Merged
merged 6 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,70 +37,50 @@ export const getProcessFromOptimismRootArgs = async ({
// uint256 _messageNonce, -> ?
// L2MessageInclusionProof memory _proof -> taken from sdk

const isBedrock = spokeChainId === 420;

// create the messenger
const messenger = new CrossChainMessenger({
l2ChainId: spokeChainId,
l2SignerOrProvider: new providers.JsonRpcProvider(spokeProvider),
l1ChainId: hubChainId,
l1SignerOrProvider: new providers.JsonRpcProvider(hubProvider),
bedrock: isBedrock,
bedrock: true,
});

if (isBedrock) {
// Handle bedrock proof
const status = await messenger.getMessageStatus(sendHash);
if (status !== MessageStatus.READY_TO_PROVE) {
throw new Error(`Optimism message status is not ready to prove: ${status}`);
}
// get the message
const resolved = await messenger.toCrossChainMessage(sendHash);
const {
messageNonce: nonce,
sender,
target,
value,
message: data,
minGasLimit: gasLimit,
} = await messenger.toLowLevelMessage(resolved);

// get the tx
const tx = {
nonce: nonce.toString(),
sender,
target,
value,
gasLimit,
data,
};
logger.info("Got withdrawal tx from optimism", requestContext, methodContext, { tx, isBedrock });

// get the proof
const proof = await messenger.getBedrockMessageProof(sendHash);
logger.info("Got L2 message proof from optimism", requestContext, methodContext, { proof, isBedrock });
if (!proof) {
throw new NoRootAvailable(spokeChainId, hubChainId, requestContext, methodContext);
}
const { l2OutputIndex, outputRootProof, withdrawalProof } = proof;

// Format arguments
return [tx, l2OutputIndex, outputRootProof, withdrawalProof];
// Handle bedrock proof
const status = await messenger.getMessageStatus(sendHash);
if (status !== MessageStatus.READY_TO_PROVE) {
throw new Error(`Optimism message status is not ready to prove: ${status}`);
}

// check to make sure you can prove
const root = await messenger.getMessageStateRoot(sendHash);
if (!root) {
// get the message
const resolved = await messenger.toCrossChainMessage(sendHash);
const {
messageNonce: nonce,
sender,
target,
value,
message: data,
minGasLimit: gasLimit,
} = await messenger.toLowLevelMessage(resolved);

// get the tx
const tx = {
nonce: nonce.toString(),
sender,
target,
value,
gasLimit,
data,
};
logger.info("Got withdrawal tx from optimism", requestContext, methodContext, { tx });

// get the proof
const proof = await messenger.getBedrockMessageProof(sendHash);
logger.info("Got L2 message proof from optimism", requestContext, methodContext, { proof });
if (!proof) {
throw new NoRootAvailable(spokeChainId, hubChainId, requestContext, methodContext);
}
const { l2OutputIndex, outputRootProof, withdrawalProof } = proof;

// get the message to get the message nonce
const [message] = await messenger.getMessagesByTransaction(sendHash);
logger.info("Got message from optimism", requestContext, methodContext, { message });

// get the inclusion proof
const proof = await messenger.getMessageProof(sendHash);
logger.info("Got proof from optimism", requestContext, methodContext, { proof });

return [message.target, message.sender, message.message, message.messageNonce, proof];
// Format arguments
return [tx, l2OutputIndex, outputRootProof, withdrawalProof];
};
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { createRequestContext, expect, mkAddress, mkBytes32, mkHash } from "@connext/nxtp-utils";
import { stub, SinonStub } from "sinon";
import { CrossChainMessage, CrossChainMessageProof } from "@eth-optimism/sdk";
import { CrossChainMessage, MessageStatus } from "@eth-optimism/sdk";

import * as MockableFns from "../../../../src/mockable";
import { getProcessFromOptimismRootArgs } from "../../../../src/tasks/processFromRoot/helpers";
import { NoRootAvailable } from "../../../../src/tasks/processFromRoot/errors";
import { BigNumber, constants } from "ethers";

let getMessageStateRootStub: SinonStub;
let getMessagesByTransactionStub: SinonStub;
let getMessageProofStub: SinonStub;
let getMessageStatusStub: SinonStub;
let toCrosschainMessageStub: SinonStub;
let toLowLevelMessageStub: SinonStub;
let getBedrockMessageProofStub: SinonStub;

// TODO: need to import from sdk but not in types
interface BedrockCrossChainMessageProof {
l2OutputIndex: number;
outputRootProof: string[];
withdrawalProof: string[];
}

class MockCrossChainMessenger {
public getMessageStateRoot = getMessageStateRootStub;
public getMessagesByTransaction = getMessagesByTransactionStub;
public getMessageProof = getMessageProofStub;
public getMessageStatus = getMessageStatusStub;
public toCrossChainMessage = toCrosschainMessageStub;
public getBedrockMessageProof = getBedrockMessageProofStub;
public toLowLevelMessage = toLowLevelMessageStub;
}

const mockCrossChainMessage: CrossChainMessage = {
Expand All @@ -30,30 +39,41 @@ const mockCrossChainMessage: CrossChainMessage = {
value: constants.Two,
};

const mockCrossChainMessageProof: CrossChainMessageProof = {
stateRoot: mkBytes32("0xdeadbeef"),
stateRootBatchHeader: {
batchIndex: constants.One,
batchRoot: mkBytes32("0xbbb"),
batchSize: constants.Two,
extraData: "0xfee",
prevTotalElements: constants.Zero,
},
stateRootProof: { index: 42, siblings: [] },
stateTrieWitness: mkAddress("0xdeaf"),
storageTrieWitness: mkAddress("0xddbeef"),
const mockCrossChainMessageProof: BedrockCrossChainMessageProof = {
l2OutputIndex: 1235,
outputRootProof: [mkBytes32("0xdeaf")],
withdrawalProof: [mkBytes32("0xddbeef")],
};

describe("Helpers: Optimism", () => {
beforeEach(() => {
stub(MockableFns, "CrossChainMessenger").value(MockCrossChainMessenger);
getMessageStateRootStub = stub().resolves(mkHash("0xdeadbeef"));
getMessagesByTransactionStub = stub().resolves([mockCrossChainMessage]);
getMessageProofStub = stub().resolves(mockCrossChainMessageProof);
getMessageStatusStub = stub().resolves(MessageStatus.READY_TO_PROVE);
toCrosschainMessageStub = stub().resolves(mockCrossChainMessage);
toLowLevelMessageStub = stub().resolves(mockCrossChainMessage);
getBedrockMessageProofStub = stub().resolves(mockCrossChainMessageProof);
});

it("should throw error if status is not ready to prove", async () => {
getMessageStatusStub.resolves(MessageStatus.STATE_ROOT_NOT_PUBLISHED);
await expect(
getProcessFromOptimismRootArgs({
spokeChainId: 1,
spokeDomainId: "1",
spokeProvider: "world",
hubChainId: 2,
hubDomainId: "2",
hubProvider: "hello",
sendHash: mkHash("0xbaa"),
_requestContext: createRequestContext("foo"),
message: "0xbabababababa",
blockNumber: 1,
}),
).to.be.rejectedWith(`Optimism message status is not ready to prove: ${MessageStatus.STATE_ROOT_NOT_PUBLISHED}`);
});

it("should throw error if undefined", async () => {
getMessageStateRootStub.resolves(undefined);
it("should throw error if no proof found", async () => {
getBedrockMessageProofStub.resolves(undefined);
await expect(
getProcessFromOptimismRootArgs({
spokeChainId: 1,
Expand All @@ -64,6 +84,8 @@ describe("Helpers: Optimism", () => {
hubProvider: "hello",
sendHash: mkHash("0xbaa"),
_requestContext: createRequestContext("foo"),
message: "0xbabababababa",
blockNumber: 1,
}),
).to.be.rejectedWith(NoRootAvailable);
});
Expand All @@ -78,13 +100,21 @@ describe("Helpers: Optimism", () => {
hubProvider: "hello",
sendHash: mkHash("0xbaa"),
_requestContext: createRequestContext("foo"),
message: "0xbabababababa",
blockNumber: 1,
});
expect(args).to.deep.eq([
mockCrossChainMessage.target,
mockCrossChainMessage.sender,
mockCrossChainMessage.message,
mockCrossChainMessage.messageNonce,
mockCrossChainMessageProof,
{
nonce: mockCrossChainMessage.messageNonce.toString(),
target: mockCrossChainMessage.target,
sender: mockCrossChainMessage.sender,
data: mockCrossChainMessage.message,
value: mockCrossChainMessage.value,
gasLimit: mockCrossChainMessage.minGasLimit,
},
mockCrossChainMessageProof.l2OutputIndex,
mockCrossChainMessageProof.outputRootProof,
mockCrossChainMessageProof.withdrawalProof,
]);
});
});
16 changes: 2 additions & 14 deletions packages/deployments/contracts/deploy/01_deployMessaging.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction, DeployResult } from "hardhat-deploy/types";
import { BigNumber, constants, Wallet } from "ethers";
import { constants, Wallet } from "ethers";
import { chainIdToDomain } from "@connext/nxtp-utils";

import { getConnectorName, getDeploymentName, getProtocolNetwork, deployBeaconProxy } from "../src";
import { MessagingProtocolConfig, MESSAGING_PROTOCOL_CONFIGS } from "../deployConfig/shared";
import { chainIdToDomain } from "@connext/nxtp-utils";

// Format the arguments for Connector contract constructor.
const formatConnectorArgs = (
Expand Down Expand Up @@ -113,18 +113,6 @@ const handleDeployHub = async (
});
console.log(`RootManager deployed to ${rootManager.address}`);

// setArborist to Merkle for RootManager
const merkleForRootContract = await hre.ethers.getContractAt(
"MerkleTreeManager",
merkleTreeManagerForRoot.address,
deployer,
);
if (!(await merkleForRootContract.arborist())) {
const tx = await merkleForRootContract.setArborist(rootManager.address);
console.log(`setArborist for RootManager tx submitted:`, tx.hash);
await tx.wait();
}

// Deploy MerkleTreeManager(beacon proxy)
console.log("Deploying MerkleTreeManager proxy For MainnetSpokeConnector...");
const merkleTreeManagerForSpoke = await deployBeaconProxy(
Expand Down
Loading