Skip to content

Commit

Permalink
chore: dev comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Mani Brar authored and Mani Brar committed Jan 6, 2025
1 parent c4fa598 commit 76dc985
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 35 deletions.
33 changes: 17 additions & 16 deletions validator-cli/src/ArbToEth/transactionHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe("ArbToEthTransactionHandler", () => {
challenger: "0x1234",
};
});

describe("constructor", () => {
it("should create a new TransactionHandler without claim", () => {
const transactionHandler = new ArbToEthTransactionHandler(
Expand Down Expand Up @@ -84,49 +85,49 @@ describe("ArbToEthTransactionHandler", () => {
veaInboxProvider.getBlock.mockResolvedValue({ number: finalityBlock });
});

it("should return false if transaction is not final", async () => {
it("should return 2 if transaction is not final", async () => {
jest.spyOn(mockEmitter, "emit");
veaInboxProvider.getTransactionReceipt.mockResolvedValue({
blockNumber: finalityBlock - (transactionHandler.requiredConfirmations - 1),
});
const trnxHash = "0x123456";
const status = await transactionHandler.checkTransactionStatus(trnxHash, ContractType.INBOX);
expect(status).toBeTruthy();
expect(status).toEqual(2);
expect(mockEmitter.emit).toHaveBeenCalledWith(
BotEvents.TXN_NOT_FINAL,
trnxHash,
transactionHandler.requiredConfirmations - 1
);
});

it("should return true if transaction is pending", async () => {
it("should return 1 if transaction is pending", async () => {
jest.spyOn(mockEmitter, "emit");
veaInboxProvider.getTransactionReceipt.mockResolvedValue(null);
const trnxHash = "0x123456";
const status = await transactionHandler.checkTransactionStatus(trnxHash, ContractType.INBOX);
expect(status).toBeTruthy();
expect(status).toEqual(1);
expect(mockEmitter.emit).toHaveBeenCalledWith(BotEvents.TXN_PENDING, trnxHash);
});

it("should return false if transaction is final", async () => {
it("should return 3 if transaction is final", async () => {
jest.spyOn(mockEmitter, "emit");
veaInboxProvider.getTransactionReceipt.mockResolvedValue({
blockNumber: finalityBlock - transactionHandler.requiredConfirmations,
});
const trnxHash = "0x123456";
const status = await transactionHandler.checkTransactionStatus(trnxHash, ContractType.INBOX);
expect(status).toBeFalsy();
expect(status).toEqual(3);
expect(mockEmitter.emit).toHaveBeenCalledWith(
BotEvents.TXN_FINAL,
trnxHash,
transactionHandler.requiredConfirmations
);
});

it("should return false if transaction hash is null", async () => {
it("should return 0 if transaction hash is null", async () => {
const trnxHash = null;
const status = await transactionHandler.checkTransactionStatus(trnxHash, ContractType.INBOX);
expect(status).toBeFalsy();
expect(status).toEqual(0);
});
});

Expand All @@ -153,7 +154,7 @@ describe("ArbToEthTransactionHandler", () => {
});

it("should not challenge claim if txn is pending", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(true);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(1);
transactionHandler.transactions.challengeTxn = "0x1234";
await transactionHandler.challengeClaim();
expect(transactionHandler.checkTransactionStatus).toHaveBeenCalledWith(
Expand All @@ -164,7 +165,7 @@ describe("ArbToEthTransactionHandler", () => {
});

it("should challenge claim", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(false);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(0);
const mockChallenge = jest.fn().mockResolvedValue({ hash: "0x1234" }) as any;
(mockChallenge as any).estimateGas = jest.fn().mockResolvedValue(BigInt(100000));
veaOutbox["challenge(uint256,(bytes32,address,uint32,uint32,uint32,uint8,address))"] = mockChallenge;
Expand Down Expand Up @@ -193,15 +194,15 @@ describe("ArbToEthTransactionHandler", () => {
});

it("should withdraw deposit", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(false);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(0);
veaOutbox.withdrawChallengeDeposit.mockResolvedValue({ hash: "0x1234" });
await transactionHandler.withdrawChallengeDeposit();
expect(transactionHandler.checkTransactionStatus).toHaveBeenCalledWith(null, ContractType.OUTBOX);
expect(transactionHandler.transactions.withdrawChallengeDepositTxn).toEqual("0x1234");
});

it("should not withdraw deposit if txn is pending", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(true);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(1);
transactionHandler.transactions.withdrawChallengeDepositTxn = "0x1234";
await transactionHandler.withdrawChallengeDeposit();
expect(transactionHandler.checkTransactionStatus).toHaveBeenCalledWith(
Expand Down Expand Up @@ -238,15 +239,15 @@ describe("ArbToEthTransactionHandler", () => {
});

it("should send snapshot", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(false);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(0);
veaInbox.sendSnapshot.mockResolvedValue({ hash: "0x1234" });
await transactionHandler.sendSnapshot();
expect(transactionHandler.checkTransactionStatus).toHaveBeenCalledWith(null, ContractType.INBOX);
expect(transactionHandler.transactions.sendSnapshotTxn).toEqual("0x1234");
});

it("should not send snapshot if txn is pending", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(true);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(1);
transactionHandler.transactions.sendSnapshotTxn = "0x1234";
await transactionHandler.sendSnapshot();
expect(transactionHandler.checkTransactionStatus).toHaveBeenCalledWith(
Expand Down Expand Up @@ -280,7 +281,7 @@ describe("ArbToEthTransactionHandler", () => {
);
});
it("should resolve challenged claim", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(false);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(0);
transactionHandler.transactions.sendSnapshotTxn = "0x1234";
mockMessageExecutor.mockResolvedValue({ hash: "0x1234" });
await transactionHandler.resolveChallengedClaim(
Expand All @@ -295,7 +296,7 @@ describe("ArbToEthTransactionHandler", () => {
});

it("should not resolve challenged claim if txn is pending", async () => {
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(true);
jest.spyOn(transactionHandler, "checkTransactionStatus").mockResolvedValue(1);
transactionHandler.transactions.sendSnapshotTxn = "0x1234";
await transactionHandler.resolveChallengedClaim(mockMessageExecutor);
expect(transactionHandler.checkTransactionStatus).toHaveBeenCalledWith(
Expand Down
19 changes: 10 additions & 9 deletions validator-cli/src/ArbToEth/transactionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class ArbToEthTransactionHandler {
*
* @returns False if transaction is pending || not final || not made, else True.
*/
public async checkTransactionStatus(trnxHash: string | null, contract: ContractType): Promise<boolean> {
public async checkTransactionStatus(trnxHash: string | null, contract: ContractType): Promise<number> {
let provider: JsonRpcProvider;
if (contract === ContractType.INBOX) {
provider = this.veaInboxProvider;
Expand All @@ -82,25 +82,26 @@ export class ArbToEthTransactionHandler {
}

if (trnxHash == null) {
return false;
return 0;
}

const receipt = await provider.getTransactionReceipt(trnxHash);

if (!receipt) {
// TODO: Add transaction pending timeout- redo transaction.
this.emitter.emit(BotEvents.TXN_PENDING, trnxHash);
return true;
return 1;
}

const currentBlock = await provider.getBlock("latest");
const confirmations = currentBlock.number - receipt.blockNumber;

if (confirmations >= this.requiredConfirmations) {
this.emitter.emit(BotEvents.TXN_FINAL, trnxHash, confirmations);
return false;
return 3;
} else {
this.emitter.emit(BotEvents.TXN_NOT_FINAL, trnxHash, confirmations);
return true;
return 2;
}
}

Expand All @@ -113,7 +114,7 @@ export class ArbToEthTransactionHandler {
if (!this.claim) {
throw new ClaimNotSetError();
}
if (await this.checkTransactionStatus(this.transactions.challengeTxn, ContractType.OUTBOX)) {
if ((await this.checkTransactionStatus(this.transactions.challengeTxn, ContractType.OUTBOX)) > 0) {
return;
}
const { deposit } = getBridgeConfig(this.chainId);
Expand Down Expand Up @@ -151,7 +152,7 @@ export class ArbToEthTransactionHandler {
if (!this.claim) {
throw new ClaimNotSetError();
}
if (await this.checkTransactionStatus(this.transactions.withdrawChallengeDepositTxn, ContractType.OUTBOX)) {
if ((await this.checkTransactionStatus(this.transactions.withdrawChallengeDepositTxn, ContractType.OUTBOX)) > 0) {
return;
}
const withdrawDepositTxn = await this.veaOutbox.withdrawChallengeDeposit(this.epoch, this.claim);
Expand All @@ -167,7 +168,7 @@ export class ArbToEthTransactionHandler {
if (!this.claim) {
throw new ClaimNotSetError();
}
if (await this.checkTransactionStatus(this.transactions.sendSnapshotTxn, ContractType.INBOX)) {
if ((await this.checkTransactionStatus(this.transactions.sendSnapshotTxn, ContractType.INBOX)) > 0) {
return;
}
const sendSnapshotTxn = await this.veaInbox.sendSnapshot(this.epoch, this.claim);
Expand All @@ -180,7 +181,7 @@ export class ArbToEthTransactionHandler {
*/
public async resolveChallengedClaim(sendSnapshotTxn: string, executeMsg: typeof messageExecutor = messageExecutor) {
this.emitter.emit(BotEvents.EXECUTING_SNAPSHOT, this.epoch);
if (await this.checkTransactionStatus(this.transactions.sendSnapshotTxn, ContractType.OUTBOX)) {
if ((await this.checkTransactionStatus(this.transactions.sendSnapshotTxn, ContractType.OUTBOX)) > 0) {
return;
}
const msgExecuteTrnx = await executeMsg(sendSnapshotTxn, this.veaInboxProvider, this.veaOutboxProvider);
Expand Down
4 changes: 2 additions & 2 deletions validator-cli/src/consts/bridgeRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Bridge {
inboxAddress: string;
outboxAddress: string;
routerAddress?: string;
roueterProvider?: string;
routerProvider?: string;
}

const bridges: { [chainId: number]: Bridge } = {
Expand All @@ -34,7 +34,7 @@ const bridges: { [chainId: number]: Bridge } = {
sequencerDelayLimit: 86400,
inboxRPC: process.env.RPC_ARB,
outboxRPC: process.env.RPC_GNOSIS,
roueterProvider: process.env.RPC_ETH,
routerProvider: process.env.RPC_ETH,
inboxAddress: process.env.VEAINBOX_ARB_TO_GNOSIS_ADDRESS,
routerAddress: process.env.VEA_ROUTER_ARB_TO_GNOSIS_ADDRESS,
outboxAddress: process.env.VEAOUTBOX_ARB_TO_GNOSIS_ADDRESS,
Expand Down
19 changes: 18 additions & 1 deletion validator-cli/src/utils/arbMsgExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ import { JsonRpcProvider, TransactionReceipt } from "@ethersproject/providers";
import { Signer } from "@ethersproject/abstract-signer";
import { ContractTransaction } from "@ethersproject/contracts";

// Execute the child-to-parent (arbitrum-to-ethereum) message, for reference see: https://docs.arbitrum.io/sdk/reference/message/ChildToParentMessage
/**
* Execute the child-to-parent (arbitrum-to-ethereum) message,
* for reference see: https://docs.arbitrum.io/sdk/reference/message/ChildToParentMessage
*
* @param trnxHash Hash of the transaction
* @param childJsonRpc L2 provider
* @param parentJsonRpc L1 provider
* @returns Execution transaction for the message
*
* */
async function messageExecutor(
trnxHash: string,
childJsonRpc: JsonRpcProvider,
Expand Down Expand Up @@ -37,6 +46,14 @@ async function messageExecutor(
return res;
}

/**
*
* @param trnxHash Hash of the transaction
* @param childJsonRpc L2 provider
* @param parentJsonRpc L1 provider
* @returns status of the message: 0 - not ready, 1 - ready
*
*/
async function getMessageStatus(
trnxHash: string,
childJsonRpc: JsonRpcProvider,
Expand Down
37 changes: 36 additions & 1 deletion validator-cli/src/utils/arbToEthState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,23 @@ import { SequencerInbox__factory } from "@arbitrum/sdk/dist/lib/abi/factories/Se
const slotsPerEpochEth = 32;
const secondsPerSlotEth = 12;

/**
* This function checks the finality of the blocks on Arbitrum and Ethereum.
* It returns the latest/finalized block on Arbitrum(found on Ethereum) and Ethereum and a flag indicating if there is a finality issue on Ethereum.
*
* @param EthProvider Ethereum provider
* @param ArbProvider Arbitrum provider
* @param veaEpoch epoch number of the claim to be fetched
* @param veaEpochPeriod epoch period of the claim to be fetched
*
* @returns [Arbitrum block, Ethereum block, finalityIssueFlag]
* */
const getBlocksAndCheckFinality = async (
EthProvider: JsonRpcProvider,
ArbProvider: JsonRpcProvider,
veaEpoch: number,
veaEpochPeriod: number
): Promise<[Block, Block, Boolean] | undefined> => {
): Promise<[Block, Block, boolean] | undefined> => {
const currentEpoch = Math.floor(Date.now() / 1000 / veaEpochPeriod);

const l2Network = await getArbitrumNetwork(ArbProvider);
Expand Down Expand Up @@ -134,6 +145,20 @@ const getBlocksAndCheckFinality = async (
return [blockArbitrum, blockFinalizedEth, finalityIssueFlagEth];
};

/**
*
* This function finds the corresponding L1(Eth) block for a given L2(Arb) block.
*
* @param L2Provider Arbitrum provider
* @param sequencer Arbitrum sequencerInbox
* @param L2Block L2 block
* @param fromBlockEth from block number on Eth
* @param fromArbBlock from block number on Arb
* @param fallbackLatest fallback to latest L2 block if the L2 block is not found on L1
*
* @returns [L1Block, L2BlockNumberFallback]
*/

const ArbBlockToL1Block = async (
L2Provider: JsonRpcProvider,
sequencer: SequencerInbox,
Expand Down Expand Up @@ -182,6 +207,16 @@ const ArbBlockToL1Block = async (
return [L1Block, L2BlockNumberFallback];
};

/**
* This function finds the latest L2 batch and block number that has a corresponding batch on L1.
*
* @param nodeInterface Arbitrum NodeInterface
* @param fromArbBlock from block number on Arb
* @param latestBlockNumber latest block number on Arb
*
* @returns [latest L2 batch number, latest L2 block number]
*/

const findLatestL2BatchAndBlock = async (
nodeInterface: NodeInterface,
fromArbBlock: number,
Expand Down
Loading

0 comments on commit 76dc985

Please sign in to comment.