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

fix: arbitrum slowpath processing #6344

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions packages/agents/lighthouse/example.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@lighthouseUrl = https://lighthouse-prover-subscriber.mainnet.connext.ninja

@adminToken = foo

POST {{lighthouseUrl}}/clear-cache
Content-Type: application/json

{
"adminToken": "{{adminToken}}"
}
4 changes: 2 additions & 2 deletions packages/agents/lighthouse/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@
"author": "Connext",
"license": "ISC",
"dependencies": {
"@arbitrum/sdk": "3.1.11",
"@arbitrum/sdk": "4.0.1",
"@connext/nxtp-adapters-database": "workspace:*",
"@connext/nxtp-adapters-relayer": "workspace:*",
"@connext/nxtp-adapters-subgraph": "workspace:*",
"@connext/nxtp-txservice": "workspace:*",
"@connext/nxtp-utils": "workspace:*",
"@connext/smart-contracts": "workspace:*",
"@consensys/linea-sdk": "0.1.6",
"@eth-optimism/sdk": "3.2.0",
"@eth-optimism/sdk": "3.3.2",
"@mantleio/sdk": "1.0.0",
"@sinclair/typebox": "0.25.21",
"@types/aws-lambda": "8.10.110",
Expand Down
12 changes: 7 additions & 5 deletions packages/agents/lighthouse/src/mockable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { getDeployedRootManagerContract as _getDeployedRootManagerContract } fro
import { CrossChainMessenger as _OptimismCrossChainMessenger } from "@eth-optimism/sdk";
import { CrossChainMessenger as _MantleCrossChainMessenger } from "@mantleio/sdk";
import { sendWithRelayerWithBackup as _sendWithRelayerWithBackup } from "@connext/nxtp-adapters-relayer";
import { EventFetcher as _EventFetcher, L2TransactionReceipt as _L2TransactionReceipt } from "@arbitrum/sdk";
import { L1ToL2MessageGasEstimator } from "@arbitrum/sdk/dist/lib/message/L1ToL2MessageGasEstimator";
import { EventFetcher as _EventFetcher, ChildTransactionReceipt as _ChildTransactionReceipt } from "@arbitrum/sdk";
import { ParentToChildMessageGasEstimator } from "@arbitrum/sdk/dist/lib/message/ParentToChildMessageGasEstimator";
import { getBaseFee as _getBaseFee } from "@arbitrum/sdk/dist/lib/utils/lib";
import { LineaSDK as _LineaSDK } from "@consensys/linea-sdk";
import {
Expand Down Expand Up @@ -42,7 +42,7 @@ export const sendWithRelayerWithBackup = _sendWithRelayerWithBackup;

export const EventFetcher = _EventFetcher;

export const L2TransactionReceipt = _L2TransactionReceipt;
export const ChildTransactionReceipt = _ChildTransactionReceipt;

export const RollupUserLogic__factory = _RollupUserLogic__factory;

Expand Down Expand Up @@ -72,8 +72,10 @@ export const getZkSyncWeb3Provider = (url: string): zk.Provider => {
return new zk.Provider(url);
};

export const getL1ToL2MessageGasEstimator = (l2Provider: providers.JsonRpcProvider): L1ToL2MessageGasEstimator => {
return new L1ToL2MessageGasEstimator(l2Provider);
export const getParentToChildMessageGasEstimator = (
l2Provider: providers.JsonRpcProvider,
): ParentToChildMessageGasEstimator => {
return new ParentToChildMessageGasEstimator(l2Provider);
};

export const getContract = (address: string, abi: ContractInterface, provider?: providers.JsonRpcProvider) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createLoggingContext, jsonifyError } from "@connext/nxtp-utils";
import { BigNumber, BigNumberish, utils } from "ethers";
import { l2Networks } from "@arbitrum/sdk/dist/lib/dataEntities/networks";
import { getChildrenForNetwork } from "@arbitrum/sdk";
import { NodeInterface__factory } from "@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory";

import { getContext } from "../processFromRoot";
import { ConfirmDataDoesNotMatch, NoRootAvailable, RollUpNodeStaked } from "../errors";
import { EventFetcher, JsonRpcProvider, L2TransactionReceipt, RollupUserLogic__factory } from "../../../mockable";
import { EventFetcher, JsonRpcProvider, ChildTransactionReceipt, RollupUserLogic__factory } from "../../../mockable";
import { ArbitrumNodeCreatedEventsNotFound } from "../../../errors";

import { GetProcessArgsParams } from ".";
Expand Down Expand Up @@ -37,15 +37,15 @@ export const getProcessFromArbitrumRootArgs = async ({
// // get the tx
const spokeJsonProvider = new JsonRpcProvider(spokeProvider);
const tx = await spokeJsonProvider.getTransactionReceipt(sendHash);
const l2TxnReceipt = new L2TransactionReceipt(tx);
const l2TxnReceipt = new ChildTransactionReceipt(tx);
// @ts-ignore
const dataIsOnL1 = await l2TxnReceipt.isDataAvailable(spokeJsonProvider);
if (!dataIsOnL1) {
throw new NoRootAvailable(spokeChainId, hubChainId, requestContext, methodContext);
}
// get the proof
const hubJsonProvider = new JsonRpcProvider(hubProvider);
const [reader] = await l2TxnReceipt.getL2ToL1Messages(hubJsonProvider);
const [reader] = await l2TxnReceipt.getChildToParentMessages(hubJsonProvider);
const msg = (reader as any).nitroReader;
if (!msg?.event) {
throw new Error(`Could not find event for message in ${sendHash}`);
Expand Down Expand Up @@ -78,7 +78,7 @@ export const getProcessFromArbitrumRootArgs = async ({
// 2. (not used) Calculate the send root and the item hash using the `Outbox.sol` interface, then
// find the event emitted after the `ethBlockNum` of the message containing a matching
// sendRoot. Find the nodeNum from this event, and submit to chain (seen below)
const arbNetwork = l2Networks[spokeChainId];
const arbNetwork = getChildrenForNetwork(hubChainId).find((n) => n.chainId === spokeChainId)!;
const latest = await hubJsonProvider.getBlockNumber();
const fetcher = new EventFetcher(hubJsonProvider);
logger.info("Fetching events", requestContext, methodContext, {
Expand All @@ -105,7 +105,7 @@ export const getProcessFromArbitrumRootArgs = async ({
const log = logs[mid];
let sendCount = BigNumber.from(msg.event.position as BigNumberish);
try {
const block = await msg.getBlockFromNodeLog(spokeJsonProvider, log);
const block = await msg.getBlockFromAssertionLog(spokeJsonProvider, log);
sendCount = BigNumber.from(block.sendCount);
} catch (e: unknown) {
logger.warn("Failed to get block from node log", requestContext, methodContext, {
Expand All @@ -116,14 +116,15 @@ export const getProcessFromArbitrumRootArgs = async ({
if (sendCount.gt(msg.event.position as BigNumberish)) {
foundLog = log;
right = mid - 1;
left = right + 1;
} else {
left = mid + 1;
}
}

const earliestNodeWithExit = foundLog.event.nodeNum;
const rollup = RollupUserLogic__factory.getContract(arbNetwork.ethBridge.rollup, RollupUserLogic__factory.abi);
const foundBlock = await msg.getBlockFromNodeNum(
const foundBlock = await msg.getBlockFromAssertionId(
rollup.connect(hubJsonProvider),
earliestNodeWithExit,
spokeJsonProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { NoSpokeConnector, NoHubConnector, NoProviderForDomain } from "../errors
import { ExtraPropagateParam } from "../operations/propagate";
import {
getJsonRpcProvider,
getL1ToL2MessageGasEstimator,
getParentToChildMessageGasEstimator,
getBaseFee,
getInterface,
getBestProvider,
Expand Down Expand Up @@ -62,7 +62,7 @@ export const getPropagateParams = async (

try {
const l2Provider = getJsonRpcProvider(l2RpcUrl);
const l1ToL2MessageGasEstimate = getL1ToL2MessageGasEstimator(l2Provider);
const l1ToL2MessageGasEstimate = getParentToChildMessageGasEstimator(l2Provider);

// example encoded payload: 0x4ff746f6000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000207465737400000000000000000000000000000000000000000000000000000000
// length = 200 not including 0x = 100 bytes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Logger, createRequestContext, expect, mkHash } from "@connext/nxtp-utils";
import { stub, SinonStub, createStubInstance, SinonStubbedInstance, spy } from "sinon";
import { L2ToL1MessageReader } from "@arbitrum/sdk";
import { ChildToParentMessageReader } from "@arbitrum/sdk";
import { NodeInterface__factory } from "@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory";

import * as MockableFns from "../../../../src/mockable";
Expand All @@ -20,14 +20,14 @@ class MockJsonRpcProvider {
}

let isDataAvailableStub: SinonStub<any[], any>;
let l2ToL1MessageReader: SinonStubbedInstance<L2ToL1MessageReader>;
let l2ToL1MessageReader: SinonStubbedInstance<ChildToParentMessageReader>;
class MockL2TransactionReceipt {
public isDataAvailable = isDataAvailableStub;
public getL2ToL1Messages = stub().resolves([l2ToL1MessageReader]);
public getChildToParentMessages = stub().resolves([l2ToL1MessageReader]);
}
class MockL2TransactionReceiptTemp {
public isDataAvailable = isDataAvailableStub;
public getL2ToL1Messages = stub().resolves([{}]);
public getChildToParentMessages = stub().resolves([{}]);
}

class MockEventFetcher {
Expand All @@ -49,19 +49,19 @@ describe("Helpers: Arbitrum", () => {
let confirmData: SinonStub<any[], any>;
beforeEach(() => {
isDataAvailableStub = stub().resolves(true);
l2ToL1MessageReader = createStubInstance(L2ToL1MessageReader, {
l2ToL1MessageReader = createStubInstance(ChildToParentMessageReader, {
getOutboxProof: Promise.resolve(["hello", "world"]),
} as any);
(l2ToL1MessageReader as any).nitroReader = {
getBlockFromNodeNum: (...args: any) =>
getBlockFromAssertionId: (...args: any) =>
Promise.resolve({
blockNumber: constants.One,
nodeNum: constants.One,
sendRoot: mkHash("0x123"),
sendCount: constants.One,
hash: mkHash("0x456"),
} as any),
getBlockFromNodeLog: (...args: any) =>
getBlockFromAssertionLog: (...args: any) =>
Promise.resolve({
blockNumber: constants.One,
nodeNum: constants.One,
Expand All @@ -71,7 +71,7 @@ describe("Helpers: Arbitrum", () => {
} as any),
event: { position: constants.One, ethBlockNum: constants.One },
};
stub(MockableFns, "L2TransactionReceipt").value(MockL2TransactionReceipt);
stub(MockableFns, "ChildTransactionReceipt").value(MockL2TransactionReceipt);
stub(MockableFns, "JsonRpcProvider").value(MockJsonRpcProvider);
stub(MockableFns, "EventFetcher").value(MockEventFetcher);
stub(MockableFns, "Outbox__factory").value(mockOutboxFactory);
Expand Down Expand Up @@ -101,6 +101,7 @@ describe("Helpers: Arbitrum", () => {
isDataAvailableStub.resolves(false);
await expect(
getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -119,6 +120,7 @@ describe("Helpers: Arbitrum", () => {
confirmData.returns([{ confirmData: "0xfoo" }]);
await expect(
getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -143,6 +145,7 @@ describe("Helpers: Arbitrum", () => {
]);
await expect(
getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -167,6 +170,7 @@ describe("Helpers: Arbitrum", () => {
]);
await expect(
getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -182,9 +186,10 @@ describe("Helpers: Arbitrum", () => {
});

it("should throw error in case msg event is not present", async () => {
stub(MockableFns, "L2TransactionReceipt").value(MockL2TransactionReceiptTemp);
stub(MockableFns, "ChildTransactionReceipt").value(MockL2TransactionReceiptTemp);
await expect(
getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -201,6 +206,7 @@ describe("Helpers: Arbitrum", () => {

it("should work", async () => {
const args = await getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -219,6 +225,7 @@ describe("Helpers: Arbitrum", () => {
stub(MockableFns, "EventFetcher").value(MockEventFetcherError);
await expect(
getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand All @@ -235,15 +242,15 @@ describe("Helpers: Arbitrum", () => {

it("should have warning in getBlockFromNodeLog fails", async () => {
(l2ToL1MessageReader as any).nitroReader = {
getBlockFromNodeNum: (...args: any) =>
getBlockFromAssertionId: (...args: any) =>
Promise.resolve({
blockNumber: constants.One,
nodeNum: constants.One,
sendRoot: mkHash("0x123"),
sendCount: constants.One,
hash: mkHash("0x456"),
} as any),
getBlockFromNodeLog: (...args: any) =>
getBlockFromAssertionLog: (...args: any) =>
Promise.reject({
blockNumber: constants.One,
nodeNum: constants.One,
Expand All @@ -256,6 +263,7 @@ describe("Helpers: Arbitrum", () => {
const loggerSpy = spy(getContext().logger, "warn");

const args = await getProcessFromArbitrumRootArgs({
isSpokeClaim: false,
spokeChainId: 42161,
spokeDomainId: "1",
spokeProvider: "world",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ import * as Mockable from "../../../../src/mockable";
import { getPropagateParams } from "../../../../src/tasks/propagate/helpers/arbitrum";
import { getInterfaceMock, propagateCtxMock, getBestProviderMock } from "../../../globalTestHook";
import { mock } from "../../../mock";
import { L1ToL2MessageGasEstimator } from "@arbitrum/sdk";
import { ParentToChildMessageGasEstimator } from "@arbitrum/sdk";

const requestContext = createRequestContext("test");

const estimateSubmissionFee = Promise.resolve(constants.One);
const estimateRetryableTicketGasLimit = Promise.resolve(constants.Two);
let l1ToL2: SinonStubbedInstance<L1ToL2MessageGasEstimator>;
let l1ToL2: SinonStubbedInstance<ParentToChildMessageGasEstimator>;

describe("Helpers: Arbitrum ", () => {
beforeEach(() => {
l1ToL2 = createStubInstance(L1ToL2MessageGasEstimator, { estimateSubmissionFee, estimateRetryableTicketGasLimit });
l1ToL2 = createStubInstance(ParentToChildMessageGasEstimator, {
estimateSubmissionFee,
estimateRetryableTicketGasLimit,
});
stub(Mockable, "getJsonRpcProvider").returns(createStubInstance(providers.JsonRpcProvider));
stub(Mockable, "getL1ToL2MessageGasEstimator").returns(l1ToL2);
stub(Mockable, "getParentToChildMessageGasEstimator").returns(l1ToL2);
stub(Mockable, "getBaseFee").resolves(BigNumber.from(1));
getInterfaceMock.returns({ encodeFunctionData: stub().resolves(mkBytes32("0xcalldadta")) });
});
Expand Down
4 changes: 2 additions & 2 deletions packages/deployments/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@
"author": "Connext",
"license": "ISC",
"dependencies": {
"@eth-optimism/sdk": "3.2.0"
"@eth-optimism/sdk": "3.3.2"
},
"devDependencies": {
"@arbitrum/sdk": "3.1.11",
"@arbitrum/sdk": "4.0.1",
"@certusone/wormhole-sdk": "0.9.21",
"@connext/nxtp-utils": "workspace:*",
"@consensys/linea-sdk": "0.1.6",
Expand Down
13 changes: 12 additions & 1 deletion packages/deployments/contracts/src/cli/op-mode/switchMode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import commandLineArgs from "command-line-args";

import { Wallet } from "ethers";
import { Contract, Wallet } from "ethers";
import { Env, getProviderFromHardhatConfig } from "../..";
import { SUPPORTED_DOMAINS, HUBS, updateIfNeeded } from "../helpers";
import {
Expand Down Expand Up @@ -107,6 +107,17 @@ export const switchMode = async () => {

// Update SpokeConnector
console.log(`\tUpdating SpokeConnector (${deployments.SpokeConnector.address})...`);
const owner = await deployments.SpokeConnector.contract.owner();
const contract = new Contract(
owner,
["function getThreshold() view returns (uint256)"],
deployments.SpokeConnector.contract.provider,
);
let threshold = "N/A";
try {
threshold = await contract.getThreshold();
} catch (e) {}
console.log(`\t\tOwner: ${owner}, threshold: ${threshold}`);
await updateIfNeeded(
optimistic
? {
Expand Down
Loading
Loading