Skip to content

Commit 4ae647a

Browse files
Mani BrarMani Brar
authored andcommitted
fix: bot review fixes
1 parent c6f5d19 commit 4ae647a

15 files changed

+218
-134
lines changed

validator-cli/src/helpers/claimer.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { getClaim, ClaimHonestState } from "../utils/claim";
55
import { getLastClaimedEpoch } from "../utils/graphQueries";
66
import { BotEvents } from "../utils/botEvents";
77
import { ClaimStruct } from "@kleros/vea-contracts/typechain-types/arbitrumToEth/VeaInboxArbToEth";
8-
import { ITransactionHandler, IDevnetTransactionHandler } from "../utils/transactionHandlers";
9-
import { getTransactionHandler } from "../utils/ethers";
8+
import { ITransactionHandler, IDevnetTransactionHandler, getTransactionHandler } from "../utils/transactionHandlers";
109
import { Network } from "../consts/bridgeRoutes";
1110
interface CheckAndClaimParams {
1211
chainId: number;

validator-cli/src/helpers/validator.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ describe("validator", () => {
1111
let mockClaim: any;
1212
let mockGetClaimState: any;
1313
let mockGetBlockFinality: any;
14+
let mockGetBlockFromEpoch: any;
1415
let mockDeps: any;
1516
beforeEach(() => {
1617
veaInbox = {
@@ -38,6 +39,7 @@ describe("validator", () => {
3839
honest: 0,
3940
challenger: ethers.ZeroAddress,
4041
};
42+
mockGetBlockFromEpoch = jest.fn().mockResolvedValue({ number: 0, timestamp: 100 });
4143
mockGetBlockFinality = jest.fn().mockResolvedValue([{ number: 0 }, { number: 0, timestamp: 100 }, false]);
4244
mockDeps = {
4345
chainId: 11155111,
@@ -52,6 +54,7 @@ describe("validator", () => {
5254
emitter,
5355
fetchClaimResolveState: mockGetClaimState,
5456
fetchBlocksAndCheckFinality: mockGetBlockFinality,
57+
fetchBlockFromEpoch: mockGetBlockFromEpoch,
5558
};
5659
});
5760
afterEach(() => {
@@ -136,7 +139,7 @@ describe("validator", () => {
136139
expect(updatedTransactionHandler.claim).toEqual(mockClaim);
137140
});
138141

139-
it("withdraw challenge deposit if snapshot sent and executed", async () => {
142+
it("withdraw challenge deposit if snapshot sent and challenger won", async () => {
140143
mockClaim.challenger = mockClaim.claimer;
141144
mockGetClaimState = jest.fn().mockReturnValue({
142145
sendSnapshot: { status: true, txnHash: "0x123" },
@@ -154,6 +157,7 @@ describe("validator", () => {
154157
};
155158
mockDeps.transactionHandler = mockTransactionHandler;
156159
mockDeps.fetchClaimResolveState = mockGetClaimState;
160+
mockDeps.claim.honest = 2; // Set honest to 1 to indicate the challenger is honest
157161
const updatedTransactionHandler = await challengeAndResolveClaim(mockDeps);
158162
expect(updatedTransactionHandler.transactions.withdrawChallengeDepositTxn).toEqual("0x1234");
159163
expect(mockTransactionHandler.withdrawChallengeDeposit).toHaveBeenCalled();
Lines changed: 111 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import { JsonRpcProvider } from "@ethersproject/providers";
22
import { ethers } from "ethers";
3-
import { ITransactionHandler } from "../utils/transactionHandlers";
3+
import { ITransactionHandler, getTransactionHandler } from "../utils/transactionHandlers";
44
import { getClaim, getClaimResolveState } from "../utils/claim";
55
import { defaultEmitter } from "../utils/emitter";
66
import { BotEvents } from "../utils/botEvents";
77
import { getBlocksAndCheckFinality } from "../utils/arbToEthState";
88
import { Network } from "../consts/bridgeRoutes";
99
import { ClaimStruct } from "@kleros/vea-contracts/typechain-types/arbitrumToEth/VeaInboxArbToEth";
10-
import { getTransactionHandler } from "../utils/ethers";
11-
12-
// https://github.com/prysmaticlabs/prysm/blob/493905ee9e33a64293b66823e69704f012b39627/config/params/mainnet_config.go#L103
13-
const secondsPerSlotEth = 12;
10+
import { getBlockFromEpoch } from "../utils/epochHandler";
1411

1512
export interface ChallengeAndResolveClaimParams {
1613
chainId: number;
@@ -28,6 +25,7 @@ export interface ChallengeAndResolveClaimParams {
2825
fetchClaimResolveState?: typeof getClaimResolveState;
2926
fetchBlocksAndCheckFinality?: typeof getBlocksAndCheckFinality;
3027
fetchTransactionHandler?: typeof getTransactionHandler;
28+
fetchBlockFromEpoch?: typeof getBlockFromEpoch;
3129
}
3230

3331
export async function challengeAndResolveClaim({
@@ -45,27 +43,19 @@ export async function challengeAndResolveClaim({
4543
fetchClaimResolveState = getClaimResolveState,
4644
fetchBlocksAndCheckFinality = getBlocksAndCheckFinality,
4745
fetchTransactionHandler = getTransactionHandler,
46+
fetchBlockFromEpoch = getBlockFromEpoch,
4847
}: ChallengeAndResolveClaimParams): Promise<ITransactionHandler | null> {
4948
if (!claim) {
5049
emitter.emit(BotEvents.NO_CLAIM, epoch);
5150
return null;
5251
}
53-
const queryRpc = veaRouterProvider ? veaRouterProvider : veaOutboxProvider;
54-
const [arbitrumBlock, ethFinalizedBlock, finalityIssueFlagEth] = await fetchBlocksAndCheckFinality(
52+
const queryRpc = veaRouterProvider ?? veaOutboxProvider;
53+
const [arbitrumBlock, , finalityIssueFlagEth] = await fetchBlocksAndCheckFinality(
5554
queryRpc,
5655
veaInboxProvider,
5756
epoch,
5857
epochPeriod
5958
);
60-
let blockNumberOutboxLowerBound: number;
61-
const epochClaimableFinalized = Math.floor(ethFinalizedBlock.timestamp / epochPeriod) - 2;
62-
// to query event performantly, we limit the block range with the heuristic that. delta blocknumber <= delta timestamp / secondsPerSlot
63-
if (epoch <= epochClaimableFinalized) {
64-
blockNumberOutboxLowerBound =
65-
ethFinalizedBlock.number - Math.ceil(((epochClaimableFinalized - epoch + 2) * epochPeriod) / secondsPerSlotEth);
66-
} else {
67-
blockNumberOutboxLowerBound = ethFinalizedBlock.number - Math.ceil(epochPeriod / secondsPerSlotEth);
68-
}
6959
const ethBlockTag = finalityIssueFlagEth ? "finalized" : "latest";
7060
if (!transactionHandler) {
7161
const TransactionHandler = fetchTransactionHandler(chainId, Network.TESTNET);
@@ -78,41 +68,118 @@ export async function challengeAndResolveClaim({
7868
veaInboxProvider,
7969
veaOutboxProvider,
8070
veaRouterProvider,
81-
emitter: defaultEmitter,
71+
emitter,
8272
claim,
8373
});
8474
} else {
8575
transactionHandler.claim = claim;
8676
}
8777

88-
const claimSnapshot = await veaInbox.snapshots(epoch, { blockTag: arbitrumBlock.number });
89-
if (claimSnapshot != claim.stateRoot && claim.challenger == ethers.ZeroAddress) {
90-
await transactionHandler.challengeClaim();
91-
} else {
92-
if (claimSnapshot == claim.stateRoot && claim.challenger == ethers.ZeroAddress) {
93-
emitter.emit(BotEvents.VALID_CLAIM, epoch);
94-
return null;
95-
} else {
96-
const claimResolveState = await fetchClaimResolveState(
97-
chainId,
98-
veaInbox,
99-
veaInboxProvider,
100-
queryRpc,
101-
epoch,
102-
blockNumberOutboxLowerBound,
103-
ethBlockTag
104-
);
105-
if (!claimResolveState.sendSnapshot.status) {
106-
await transactionHandler.sendSnapshot();
107-
} else if (claimResolveState.execution.status == 1) {
108-
await transactionHandler.resolveChallengedClaim(claimResolveState.sendSnapshot.txHash);
109-
} else if (claimResolveState.execution.status == 2 && claim.honest == 2) {
110-
await transactionHandler.withdrawChallengeDeposit();
111-
} else {
112-
emitter.emit(BotEvents.WAITING_ARB_TIMEOUT, epoch);
113-
}
114-
}
78+
const { challenged, toRelay } = await challengeAndCheckRelay({
79+
veaInbox,
80+
epoch,
81+
claim,
82+
transactionHandler,
83+
arbitrumBlockNumber: arbitrumBlock.number,
84+
});
85+
if (!toRelay && !challenged) {
86+
return null;
87+
} else if (challenged && !toRelay) {
88+
return transactionHandler;
11589
}
90+
await handleResolveFlow({
91+
chainId,
92+
epoch,
93+
epochPeriod,
94+
claim,
95+
veaInbox,
96+
veaInboxProvider,
97+
queryRpc,
98+
ethBlockTag,
99+
transactionHandler,
100+
fetchClaimResolveState,
101+
fetchBlockFromEpoch,
102+
});
116103

117104
return transactionHandler;
118105
}
106+
107+
interface ChallengeAndCheckRelayParams {
108+
veaInbox: any;
109+
epoch: number;
110+
claim: ClaimStruct;
111+
transactionHandler: ITransactionHandler;
112+
arbitrumBlockNumber: number;
113+
}
114+
async function challengeAndCheckRelay({
115+
veaInbox,
116+
epoch,
117+
claim,
118+
transactionHandler,
119+
arbitrumBlockNumber,
120+
}: ChallengeAndCheckRelayParams): Promise<{ challenged: boolean; toRelay: boolean }> {
121+
const onChainSnapshot = await veaInbox.snapshots(epoch, { blockTag: arbitrumBlockNumber });
122+
const isNotChallenged = claim.challenger === ethers.ZeroAddress;
123+
const challengeAndRelayState = {
124+
challenged: false,
125+
toRelay: false,
126+
};
127+
if (onChainSnapshot !== claim.stateRoot && isNotChallenged) {
128+
await transactionHandler.challengeClaim();
129+
challengeAndRelayState.challenged = true;
130+
}
131+
if (!isNotChallenged) {
132+
return { challenged: true, toRelay: true };
133+
}
134+
return challengeAndRelayState;
135+
}
136+
137+
interface ResolveFlowParams {
138+
chainId: number;
139+
epoch: number;
140+
epochPeriod: number;
141+
claim: ClaimStruct;
142+
veaInbox: any;
143+
veaInboxProvider: JsonRpcProvider;
144+
queryRpc: JsonRpcProvider;
145+
ethBlockTag: "latest" | "finalized";
146+
transactionHandler: ITransactionHandler;
147+
fetchClaimResolveState: typeof getClaimResolveState;
148+
fetchBlockFromEpoch: typeof getBlockFromEpoch;
149+
}
150+
async function handleResolveFlow({
151+
chainId,
152+
epoch,
153+
epochPeriod,
154+
claim,
155+
veaInbox,
156+
veaInboxProvider,
157+
queryRpc,
158+
ethBlockTag,
159+
transactionHandler,
160+
fetchClaimResolveState,
161+
fetchBlockFromEpoch,
162+
}: ResolveFlowParams): Promise<void> {
163+
const blockNumberOutboxLowerBound = await fetchBlockFromEpoch(epoch, epochPeriod, queryRpc);
164+
const claimResolveState = await fetchClaimResolveState({
165+
chainId,
166+
veaInbox,
167+
veaInboxProvider,
168+
veaOutboxProvider: queryRpc,
169+
epoch,
170+
fromBlock: blockNumberOutboxLowerBound,
171+
toBlock: ethBlockTag,
172+
});
173+
174+
if (!claimResolveState.sendSnapshot.status) {
175+
await transactionHandler.sendSnapshot();
176+
return;
177+
}
178+
179+
const execStatus = claimResolveState.execution.status;
180+
if (execStatus === 1) {
181+
await transactionHandler.resolveChallengedClaim(claimResolveState.sendSnapshot.txHash);
182+
} else if (execStatus === 2 && claim.honest === 2) {
183+
await transactionHandler.withdrawChallengeDeposit();
184+
}
185+
}

validator-cli/src/utils/claim.test.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ethers } from "ethers";
22
import { ClaimStruct } from "@kleros/vea-contracts/typechain-types/arbitrumToEth/VeaInboxArbToEth";
3-
import { getClaim, hashClaim, getClaimResolveState } from "./claim";
3+
import { getClaim, hashClaim, getClaimResolveState, ClaimResolveStateParams } from "./claim";
44
import { ClaimNotFoundError } from "./errors";
55

66
let mockClaim: ClaimStruct;
@@ -237,6 +237,7 @@ describe("snapshotClaim", () => {
237237
const epoch = 1;
238238
const blockNumberOutboxLowerBound = 1234;
239239
const toBlock = "latest";
240+
let mockClaimResolveStateParams: any;
240241
beforeEach(() => {
241242
mockClaim = {
242243
stateRoot: "0xeac817ed5c5b3d1c2c548f231b7cf9a0dfd174059f450ec6f0805acf6a16a551",
@@ -253,19 +254,25 @@ describe("snapshotClaim", () => {
253254
SnapshotSent: jest.fn(),
254255
},
255256
};
257+
mockClaimResolveStateParams = {
258+
chainId: 11155111,
259+
veaInbox,
260+
veaInboxProvider: {
261+
getBlock: jest.fn().mockResolvedValueOnce({ timestamp: mockClaim.timestampClaimed, number: 1234 }),
262+
} as any,
263+
veaOutboxProvider: {
264+
getBlock: jest.fn().mockResolvedValueOnce({ timestamp: mockClaim.timestampClaimed, number: 1234 }),
265+
} as any,
266+
epoch,
267+
fromBlock: blockNumberOutboxLowerBound,
268+
toBlock,
269+
fetchMessageStatus: jest.fn(),
270+
};
256271
});
257272

258273
it("should return pending state for both", async () => {
259274
veaInbox.queryFilter.mockResolvedValueOnce([]);
260-
const claimResolveState = await getClaimResolveState(
261-
11155111,
262-
veaInbox,
263-
veaInboxProvider,
264-
veaOutboxProvider,
265-
epoch,
266-
blockNumberOutboxLowerBound,
267-
toBlock
268-
);
275+
const claimResolveState = await getClaimResolveState(mockClaimResolveStateParams);
269276
expect(claimResolveState).toBeDefined();
270277
expect(claimResolveState.sendSnapshot.status).toBeFalsy();
271278
expect(claimResolveState.execution.status).toBe(0);
@@ -274,16 +281,8 @@ describe("snapshotClaim", () => {
274281
it("should return pending state for execution", async () => {
275282
veaInbox.queryFilter.mockResolvedValueOnce([{ transactionHash: "0x1234" }]);
276283
const mockGetMessageStatus = jest.fn().mockResolvedValueOnce(0);
277-
const claimResolveState = await getClaimResolveState(
278-
11155111,
279-
veaInbox,
280-
veaInboxProvider,
281-
veaOutboxProvider,
282-
epoch,
283-
blockNumberOutboxLowerBound,
284-
toBlock,
285-
mockGetMessageStatus
286-
);
284+
mockClaimResolveStateParams.fetchMessageStatus = mockGetMessageStatus;
285+
const claimResolveState = await getClaimResolveState(mockClaimResolveStateParams);
287286
expect(claimResolveState).toBeDefined();
288287
expect(claimResolveState.sendSnapshot.status).toBeTruthy();
289288
expect(claimResolveState.execution.status).toBe(0);

validator-cli/src/utils/claim.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ type ClaimResolveState = {
114114
};
115115
};
116116

117+
export interface ClaimResolveStateParams {
118+
chainId: number;
119+
veaInbox: any;
120+
veaInboxProvider: JsonRpcProvider;
121+
veaOutboxProvider: JsonRpcProvider;
122+
epoch: number;
123+
fromBlock: number;
124+
toBlock: number | string;
125+
fetchMessageStatus?: typeof getMessageStatus;
126+
}
127+
117128
/**
118129
* Fetches the claim resolve state.
119130
* @param veaInbox VeaInbox contract instance
@@ -125,16 +136,16 @@ type ClaimResolveState = {
125136
* @param fetchMessageStatus function to fetch message status
126137
* @returns ClaimResolveState
127138
**/
128-
const getClaimResolveState = async (
129-
chainId: number,
130-
veaInbox: any,
131-
veaInboxProvider: JsonRpcProvider,
132-
veaOutboxProvider: JsonRpcProvider,
133-
epoch: number,
134-
fromBlock: number,
135-
toBlock: number | string,
136-
fetchMessageStatus: typeof getMessageStatus = getMessageStatus
137-
): Promise<ClaimResolveState> => {
139+
const getClaimResolveState = async ({
140+
chainId,
141+
veaInbox,
142+
veaInboxProvider,
143+
veaOutboxProvider,
144+
epoch,
145+
fromBlock,
146+
toBlock,
147+
fetchMessageStatus,
148+
}: ClaimResolveStateParams): Promise<ClaimResolveState> => {
138149
let claimResolveState: ClaimResolveState = {
139150
sendSnapshot: {
140151
status: false,

validator-cli/src/utils/epochHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const getLatestChallengeableEpoch = (epochPeriod: number, now: number = Date.now
6464
*/
6565
const getBlockFromEpoch = async (epoch: number, epochPeriod: number, provider: JsonRpcProvider): Promise<number> => {
6666
const epochTimestamp = epoch * epochPeriod;
67-
const latestBlock = await provider.getBlock("latest");
67+
const latestBlock = await provider.getBlock("final");
6868
const baseBlock = await provider.getBlock(latestBlock.number - 500);
6969
const secPerBlock = (latestBlock.timestamp - baseBlock.timestamp) / (latestBlock.number - baseBlock.number);
7070
const blockFallBack = Math.floor((latestBlock.timestamp - epochTimestamp) / secPerBlock);

0 commit comments

Comments
 (0)