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

improve(BundleDataClient,SpokePoolClient): Log about duplicate events and delete getLatestProposedBundleData #884

Merged
merged 40 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b0a7a23
improve(BundleDataClient): Log about duplicate destination chain events
nicholaspai Feb 10, 2025
55783b7
Log duplicate deposits in spoke pool client
nicholaspai Feb 10, 2025
9850552
getLatestProposedBundleData should never load data from scratch
nicholaspai Feb 10, 2025
1ab05cc
lint
nicholaspai Feb 10, 2025
7c30e1a
Update BundleDataClient.ts
nicholaspai Feb 10, 2025
8c066af
Update BundleDataClient.ts
nicholaspai Feb 10, 2025
ce0be1d
Update SpokePoolClient.ts
nicholaspai Feb 10, 2025
bf3bae6
Update BundleDataClient.ts
nicholaspai Feb 10, 2025
faebdb8
exit after n == 4
nicholaspai Feb 10, 2025
42fb574
Update SpokePoolClient.ts
nicholaspai Feb 10, 2025
04d3592
Update BundleDataClient.ts
nicholaspai Feb 10, 2025
7545cf2
reduce noisiness of logs
nicholaspai Feb 11, 2025
2df77cf
Update BundleDataClient.ts
nicholaspai Feb 11, 2025
3f802dc
Update SpokePoolClient.ts
nicholaspai Feb 11, 2025
f2429b8
Clean up logs
nicholaspai Feb 11, 2025
2b6a8dd
Update BundleDataClient.ts
nicholaspai Feb 11, 2025
34ce1e0
Update BundleDataClient.ts
nicholaspai Feb 11, 2025
ea48db5
Update BundleDataClient.ts
nicholaspai Feb 11, 2025
331dd34
Update BundleDataClient.ts
nicholaspai Feb 11, 2025
fafbbb3
Update BundleDataClient.ts
nicholaspai Feb 12, 2025
9e3090b
refactor
nicholaspai Feb 12, 2025
e1c8599
Merge branch 'master' into log-duplicates
nicholaspai Feb 12, 2025
29b9464
duplicate event util
nicholaspai Feb 12, 2025
30a1abb
Add getPendingPoolRebalanceLeavesFromArweave
nicholaspai Feb 12, 2025
c90cb2f
Update BundleDataClient.ts
nicholaspai Feb 12, 2025
d2e23df
fix
nicholaspai Feb 12, 2025
00e1d7b
Update package.json
nicholaspai Feb 12, 2025
6e3ca4d
Update BundleDataClient.ts
nicholaspai Feb 12, 2025
d6b2a36
merge
nicholaspai Feb 13, 2025
54741d6
Update BundleDataClient.ts
nicholaspai Feb 13, 2025
7264854
Update BundleDataClient.ts
nicholaspai Feb 13, 2025
412fa8f
Revert "Update BundleDataClient.ts"
nicholaspai Feb 13, 2025
337adc8
Update BundleDataClient.ts
nicholaspai Feb 13, 2025
988356a
Update BundleDataClient.ts
nicholaspai Feb 13, 2025
34b6010
Update BundleDataClient.ts
nicholaspai Feb 13, 2025
aab61e9
Update src/clients/HubPoolClient.ts
nicholaspai Feb 13, 2025
329d44c
Update HubPoolClient.ts
nicholaspai Feb 13, 2025
4333390
Update SpokePoolClient.ts
nicholaspai Feb 13, 2025
70773e2
Update HubPoolClient.ts
nicholaspai Feb 13, 2025
502ed7f
Update package.json
nicholaspai Feb 13, 2025
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@across-protocol/sdk",
"author": "UMA Team",
"version": "4.1.9",
"version": "4.1.10",
"license": "AGPL-3.0",
"homepage": "https://docs.across.to/reference/sdk",
"files": [
Expand Down
69 changes: 20 additions & 49 deletions src/clients/BundleDataClient/BundleDataClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
Deposit,
DepositWithBlock,
} from "../../interfaces";
import { AcrossConfigStoreClient, SpokePoolClient } from "..";
import { SpokePoolClient } from "..";
import {
BigNumber,
bnZero,
Expand All @@ -41,18 +41,17 @@ import {
isZeroValueFillOrSlowFillRequest,
chainIsEvm,
isValidEvmAddress,
duplicateEvent,
} from "../../utils";
import winston from "winston";
import {
_buildPoolRebalanceRoot,
BundleData,
BundleDataSS,
getEndBlockBuffers,
getRefundInformationFromFill,
getRefundsFromBundle,
getWidestPossibleExpectedBlockRange,
isChainDisabled,
PoolRebalanceRoot,
prettyPrintV3SpokePoolEvents,
V3DepositWithBlock,
V3FillWithBlock,
Expand Down Expand Up @@ -431,52 +430,6 @@ export class BundleDataClient {
}, toBN(0));
}

private async getLatestProposedBundleData(): Promise<{ bundleData: LoadDataReturnValue; blockRanges: number[][] }> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer need these functions in across-protocol/relayer#2085

const hubPoolClient = this.clients.hubPoolClient;
// Determine which bundle we should fetch from arweave, either the pending bundle or the latest
// executed one. Both should have arweave data but if for some reason the arweave data is missing,
// this function will have to compute the bundle data from scratch which will be slow. We have to fallback
// to computing the bundle from scratch since this function needs to return the full bundle data so that
// it can be used to get the running balance proposed using its data.
const bundleBlockRanges = getImpliedBundleBlockRanges(
hubPoolClient,
this.clients.configStoreClient,
hubPoolClient.hasPendingProposal()
? hubPoolClient.getLatestProposedRootBundle()
: hubPoolClient.getLatestFullyExecutedRootBundle(hubPoolClient.latestBlockSearched)! // ! because we know there is a bundle
);
return {
blockRanges: bundleBlockRanges,
bundleData: await this.loadData(
bundleBlockRanges,
this.spokePoolClients,
true // this bundle data should have been published to arweave
),
};
}

async getLatestPoolRebalanceRoot(): Promise<{ root: PoolRebalanceRoot; blockRanges: number[][] }> {
const { bundleData, blockRanges } = await this.getLatestProposedBundleData();
const hubPoolClient = this.clients.hubPoolClient;
const root = _buildPoolRebalanceRoot(
hubPoolClient.latestBlockSearched,
blockRanges[0][1],
bundleData.bundleDepositsV3,
bundleData.bundleFillsV3,
bundleData.bundleSlowFillsV3,
bundleData.unexecutableSlowFills,
bundleData.expiredDepositsToRefundV3,
{
hubPoolClient,
configStoreClient: hubPoolClient.configStoreClient as AcrossConfigStoreClient,
}
);
return {
root,
blockRanges,
};
}

// @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
// Return refunds from the next valid bundle. This will contain any refunds that have been sent but are not included
// in a valid bundle with all of its leaves executed. This contains refunds from:
Expand Down Expand Up @@ -867,6 +820,14 @@ export class BundleDataClient {
"Not using correct bundle deposit hash key"
);
if (deposit.blockNumber >= originChainBlockRange[0]) {
if (bundleDepositsV3?.[originChainId]?.[deposit.inputToken]?.find((d) => duplicateEvent(deposit, d))) {
this.logger.debug({
at: "BundleDataClient#loadData",
message: "Duplicate deposit detected",
deposit,
});
throw new Error("Duplicate deposit detected");
}
bundleDepositHashes.push(newBundleDepositHash);
updateBundleDepositsV3(bundleDepositsV3, deposit);
} else if (deposit.blockNumber < originChainBlockRange[0]) {
Expand Down Expand Up @@ -978,6 +939,11 @@ export class BundleDataClient {
}
}
} else {
this.logger.debug({
at: "BundleDataClient#loadData",
message: "Duplicate fill detected",
fill,
});
Comment on lines +942 to +946
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the subsequent Duplicate slow fill request detected log message are pretty far away from the if statement that can trigger them; it's hard to see the logic in github at least. wdyt about relocating them to the top?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creates a big diff but good point: 9e3090b

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pxrl I've decided to revert back to this implementation becaues the diff is so big and hard to verify.

throw new Error("Duplicate fill detected");
}
return;
Expand Down Expand Up @@ -1099,6 +1065,11 @@ export class BundleDataClient {
validatedBundleSlowFills.push(matchedDeposit);
}
} else {
this.logger.debug({
at: "BundleDataClient#loadData",
message: "Duplicate slow fill request detected",
slowFillRequest,
});
throw new Error("Duplicate slow fill request detected.");
}
return;
Expand Down
31 changes: 20 additions & 11 deletions src/clients/HubPoolClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -776,22 +776,31 @@ export class HubPoolClient extends BaseAbstractClient {
return endBlock > 0 ? endBlock + 1 : 0;
}

getRunningBalanceBeforeBlockForChain(block: number, chain: number, l1Token: string): TokenRunningBalance {
getLatestExecutedRootBundleContainingL1Token(
block: number,
chain: number,
l1Token: string
): ExecutedRootBundle | undefined {
// Search ExecutedRootBundles in descending block order to find the most recent event before the target block.
const executedRootBundle = sortEventsDescending(this.executedRootBundles).find(
(executedLeaf: ExecutedRootBundle) => {
return (
executedLeaf.blockNumber <= block &&
executedLeaf.chainId === chain &&
executedLeaf.l1Tokens.map((l1Token) => l1Token.toLowerCase()).includes(l1Token.toLowerCase())
);
}
) as ExecutedRootBundle;
return sortEventsDescending(this.executedRootBundles).find((executedLeaf: ExecutedRootBundle) => {
return (
executedLeaf.blockNumber <= block &&
executedLeaf.chainId === chain &&
executedLeaf.l1Tokens.some((token) => token.toLowerCase() === l1Token.toLowerCase())
);
});
}

getRunningBalanceBeforeBlockForChain(block: number, chain: number, l1Token: string): TokenRunningBalance {
const executedRootBundle = this.getLatestExecutedRootBundleContainingL1Token(block, chain, l1Token);

return this.getRunningBalanceForToken(l1Token, executedRootBundle);
}

public getRunningBalanceForToken(l1Token: string, executedRootBundle: ExecutedRootBundle): TokenRunningBalance {
public getRunningBalanceForToken(
l1Token: string,
executedRootBundle: ExecutedRootBundle | undefined
): TokenRunningBalance {
let runningBalance = toBN(0);
if (executedRootBundle) {
const indexOfL1Token = executedRootBundle.l1Tokens
Expand Down
29 changes: 29 additions & 0 deletions src/clients/SpokePoolClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
toAddress,
} from "../utils";
import {
duplicateEvent,
paginatedEventQuery,
sortEventsAscendingInPlace,
spreadEvent,
Expand Down Expand Up @@ -587,6 +588,7 @@ export class SpokePoolClient extends BaseAbstractClient {
* @see _update
*/
public async update(eventsToQuery = this.queryableEventNames): Promise<void> {
const duplicateEvents: Log[] = [];
if (this.hubPoolClient !== null && !this.hubPoolClient.isUpdated) {
throw new Error("HubPoolClient not updated");
}
Expand Down Expand Up @@ -656,6 +658,12 @@ export class SpokePoolClient extends BaseAbstractClient {
}

if (this.depositHashes[getRelayEventKey(deposit)] !== undefined) {
// Sanity check that this event is not a duplicate, even though the relay data hash is a duplicate.
const allDeposits = this._getDuplicateDeposits(deposit).concat(this.depositHashes[getRelayEventKey(deposit)]);
if (allDeposits.some((e) => duplicateEvent(deposit, e))) {
duplicateEvents.push(event);
continue;
}
assign(this.duplicateDepositHashes, [getRelayEventKey(deposit)], [deposit]);
continue;
}
Expand Down Expand Up @@ -718,6 +726,13 @@ export class SpokePoolClient extends BaseAbstractClient {
}

const depositHash = getRelayEventKey({ ...slowFillRequest, destinationChainId: this.chainId });

// Sanity check that this event is not a duplicate.
if (this.slowFillRequests[depositHash] !== undefined) {
duplicateEvents.push(event);
continue;
}

this.slowFillRequests[depositHash] ??= slowFillRequest;
}
};
Expand Down Expand Up @@ -751,6 +766,13 @@ export class SpokePoolClient extends BaseAbstractClient {
fill.relayExecutionInfo.updatedMessageHash = getMessageHash(event.args.relayExecutionInfo.updatedMessage);
}

// Sanity check that this event is not a duplicate.
const duplicateFill = this.fills[fill.originChainId]?.find((f) => duplicateEvent(fill, f));
if (duplicateFill) {
duplicateEvents.push(event);
continue;
}

assign(this.fills, [fill.originChainId], [fill]);
assign(this.depositHashesToFills, [this.getDepositHash(fill)], [fill]);
}
Expand Down Expand Up @@ -795,6 +817,13 @@ export class SpokePoolClient extends BaseAbstractClient {
}
}

if (duplicateEvents.length > 0) {
this.log("debug", "Duplicate events listed", {
duplicateEvents,
});
this.log("error", "Duplicate events detected, check debug logs");
}

// Next iteration should start off from where this one ended.
this.currentTime = currentTime;
if (this.oldestTime === 0) this.oldestTime = oldestTime; // Set oldest time only after the first update.
Expand Down
4 changes: 4 additions & 0 deletions src/utils/EventUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,7 @@ export function isEventOlder<T extends SortableEvent>(ex: T, ey: T): boolean {
export function getTransactionHashes(events: SortableEvent[]): string[] {
return [...Array.from(new Set(events.map((e) => e.transactionHash)))];
}

export function duplicateEvent(a: SortableEvent, b: SortableEvent): boolean {
return a.transactionHash === b.transactionHash && a.logIndex === b.logIndex;
}