Skip to content

Commit

Permalink
fix: Paginate InsuredBridgeL1Client event search for select events (U…
Browse files Browse the repository at this point in the history
…MAprotocol#3902)

* WIP

* fix test

* Update RelayerConfig.ts

* Fix across monitor

* add await

* fix

* Update InsuredBridgeL1Client.ts

* Update InsuredBridgeL1Client.ts
  • Loading branch information
nicholaspai authored May 9, 2022
1 parent 18da1ad commit 6fff88a
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 111 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,6 @@
"packages": [
"packages/*"
]
}
},
"dependencies": {}
}
11 changes: 4 additions & 7 deletions packages/across-monitor/src/AcrossMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class AcrossMonitor {
readonly monitorConfig: AcrossMonitorConfig,
readonly l1Client: InsuredBridgeL1Client
) {
this.relayEventProcessor = new RelayEventProcessor();
this.relayEventProcessor = new RelayEventProcessor(l1Client);
}

async update(): Promise<void> {
Expand All @@ -60,7 +60,7 @@ export class AcrossMonitor {
// misconfiguration).
this.startingBlock = Math.min(this.startingBlock, this.endingBlock);

await this.relayEventProcessor.update(this.endingBlock);
this.relayEventProcessor.update(this.endingBlock);
}

async checkUtilization(): Promise<void> {
Expand Down Expand Up @@ -110,13 +110,10 @@ export class AcrossMonitor {
return;
}

async checkUnknownRelayers(): Promise<void> {
checkUnknownRelayers(): void {
this.logger.debug({ at: "AcrossMonitor#UnknownRelayers", message: "Checking for unknown relayers" });

const relayEvents: EventInfo[] = await this.relayEventProcessor.getRelayEventInfo(
this.startingBlock,
this.endingBlock
);
const relayEvents: EventInfo[] = this.relayEventProcessor.getRelayEventInfo(this.startingBlock, this.endingBlock);
for (const event of relayEvents) {
// Skip notifications for known relay caller addresses.
if (this.monitorConfig.whitelistedAddresses.includes(toChecksumAddress(event.caller))) {
Expand Down
21 changes: 21 additions & 0 deletions packages/across-monitor/src/AcrossMonitorConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ export interface BotModes {
unknownRelayersEnabled: boolean; // Monitors relay related events triggered by non-whitelisted addresses
}

// Following settings can be overridden to optimize L1 event search for select events. For example,
// the "DepositRelayed" event search request could return > 10,000 return values so we need to shorten the block
// search using these parameters because some node providers like Infura limit event search return values to 10,000.

// This is set to the oldest SpokePool's deploy block height because we can assume that there will not be any
// BridgePool events on any BridgePool at blocks lower than this height. This is specifically the WETH
// BridgePool's deploy block.
export const bridgePoolEarliestBlockToSearch = 13545377;
export const bridgePoolMaxBlocksToSeach = 1_000_000;

export class AcrossMonitorConfig {
readonly bridgeAdminChainId: number;

Expand All @@ -20,6 +30,8 @@ export class AcrossMonitorConfig {

readonly startingBlock: number | undefined;
readonly endingBlock: number | undefined;
readonly bridgePoolEarliestBlockToSearch: number;
readonly bridgePoolMaxBlocksToSeach: number;

readonly utilizationThreshold: number;
readonly whitelistedAddresses: string[];
Expand All @@ -37,6 +49,8 @@ export class AcrossMonitorConfig {
WHITELISTED_ADDRESSES,
UTILIZATION_ENABLED,
UNKNOWN_RELAYERS_ENABLED,
BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK,
BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH,
} = env;

this.botModes = {
Expand Down Expand Up @@ -65,5 +79,12 @@ export class AcrossMonitorConfig {
// In serverless mode use block range from environment to fetch for latest events.
this.startingBlock = STARTING_BLOCK_NUMBER ? Number(STARTING_BLOCK_NUMBER) : undefined;
this.endingBlock = ENDING_BLOCK_NUMBER ? Number(ENDING_BLOCK_NUMBER) : undefined;

this.bridgePoolEarliestBlockToSearch = BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK
? Number(BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK)
: bridgePoolEarliestBlockToSearch;
this.bridgePoolMaxBlocksToSeach = BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH
? Number(BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH)
: bridgePoolMaxBlocksToSeach;
}
}
79 changes: 17 additions & 62 deletions packages/across-monitor/src/RelayEventProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import type { BridgePoolData } from "@uma/financial-templates-lib";

// Note that Relay parameters are narrower in this module than in @uma/financial-templates-lib.
interface Relay {
chainId: number;
depositId: number;
l2Sender: string;
l1Recipient: string;
amount: string;
slowRelayFeePct: string;
instantRelayFeePct: string;
realizedLpFeePct: string;
depositHash: string;
}
import type { BridgePoolData, InsuredBridgeL1Client, RelayedDeposit } from "@uma/financial-templates-lib";
import { EventData } from "web3-eth-contract";

export interface EventInfo {
l1Token: string;
poolCollateralDecimals: number;
poolCollateralSymbol: string;
relay: Relay;
relay: RelayedDeposit;
caller: string;
action: string;
transactionHash: string;
Expand All @@ -30,7 +18,7 @@ export class RelayEventProcessor {

private lastRelayUpdate = -1; // DepositRelayed events are fetched from lastRelayUpdate + 1 block.

private deposits: { [key: string]: { [key: string]: Relay } } = {}; // L1TokenAddress=>depositHash=>Relay.
private deposits: { [key: string]: { [key: string]: RelayedDeposit } } = {}; // L1TokenAddress=>depositHash=>Relay.
private eventActions: { [key: string]: string } = {
DepositRelayed: "slow relayed",
RelaySpedUp: "sped up",
Expand All @@ -39,14 +27,14 @@ export class RelayEventProcessor {
RelayCanceled: "canceled",
};

constructor() {
constructor(readonly l1Client: InsuredBridgeL1Client) {
// do nothing.
}

// update() should be called only after having populated bridgePools.
// update() should be called only after having updated L1 client
// This fetches all DepositRelayed events since lastRelayUpdate block in order to store deposit and relay hash
// mappings that could be referenced by other events.
async update(endingBlock: number): Promise<void> {
update(endingBlock: number): void {
// Only update if endingBlock is more recent than the lastRelayUpdate block from last update() call.
const startingBlock = this.lastRelayUpdate + 1;
if (startingBlock > endingBlock) {
Expand All @@ -58,58 +46,25 @@ export class RelayEventProcessor {
this.deposits[l1TokenAddress] = this.deposits[l1TokenAddress] ? this.deposits[l1TokenAddress] : {};
}

await Promise.all(
Object.keys(this.bridgePools).map(async (l1TokenAddress) => {
const depositRelayedEvents = await this.bridgePools[l1TokenAddress].contract.getPastEvents("DepositRelayed", {
fromBlock: startingBlock,
toBlock: endingBlock,
});
for (const depositRelayedEvent of depositRelayedEvents) {
const relayData: Relay = {
chainId: Number(depositRelayedEvent.returnValues.depositData.chainId),
depositId: Number(depositRelayedEvent.returnValues.depositData.depositId),
l2Sender: depositRelayedEvent.returnValues.depositData.l2Sender,
l1Recipient: depositRelayedEvent.returnValues.depositData.l1Recipient,
amount: depositRelayedEvent.returnValues.depositData.amount,
slowRelayFeePct: depositRelayedEvent.returnValues.depositData.slowRelayFeePct,
instantRelayFeePct: depositRelayedEvent.returnValues.depositData.instantRelayFeePct,
realizedLpFeePct: depositRelayedEvent.returnValues.relay.realizedLpFeePct,
depositHash: depositRelayedEvent.returnValues.depositHash,
};
this.deposits[l1TokenAddress][depositRelayedEvent.returnValues.depositHash] = relayData;
}
})
);
// This will return all relayed deposit data including disputed ones.
for (const relayData of this.l1Client.getAllRelayedDepositsSimple()) {
this.deposits[relayData.l1Token][relayData.depositHash] = relayData;
}

this.lastRelayUpdate = endingBlock;
}

async getRelayEventInfo(startingBlock: number | undefined, endingBlock: number | undefined): Promise<EventInfo[]> {
const blockSearchConfig = { fromBlock: startingBlock, toBlock: endingBlock };
getRelayEventInfo(startingBlock: number | undefined, endingBlock: number | undefined): EventInfo[] {
const relayEvents: EventInfo[] = [];
// Fetch all relay related events.
for (const [l1TokenAddress, bridgePool] of Object.entries(this.bridgePools)) {
const [
depositRelayedEvents,
relaySpedUpEvents,
relaySettledEvents,
relayDisputedEvents,
relayCanceledEvents,
] = await Promise.all([
bridgePool.contract.getPastEvents("DepositRelayed", blockSearchConfig),
bridgePool.contract.getPastEvents("RelaySpedUp", blockSearchConfig),
bridgePool.contract.getPastEvents("RelaySettled", blockSearchConfig),
bridgePool.contract.getPastEvents("RelayDisputed", blockSearchConfig),
bridgePool.contract.getPastEvents("RelayCanceled", blockSearchConfig),
]);

// Process all relay related events, get caller, type and match with additional properties by depositHash that
// were cached on update().
const allEvents = depositRelayedEvents
.concat(relaySpedUpEvents)
.concat(relaySettledEvents)
.concat(relayDisputedEvents)
.concat(relayCanceledEvents);
const allEvents = this.l1Client.allRelayEventData[bridgePool.contract.options.address].filter(
(e: EventData) =>
(startingBlock === undefined || e.blockNumber >= startingBlock) &&
(endingBlock === undefined || e.blockNumber <= endingBlock)
);
for (const event of allEvents) {
const depositHash = event.returnValues.depositHash;
if (!this.deposits[l1TokenAddress][depositHash]) {
Expand Down
12 changes: 10 additions & 2 deletions packages/across-monitor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ export async function run(logger: winston.Logger, l1Web3: Web3): Promise<void> {

// l1Client uses bridgeAdmin contract for bridge pool discovery.
const bridgeAdminAddress = await getAddress("BridgeAdmin", config.bridgeAdminChainId);
const l1Client = new InsuredBridgeL1Client(logger, l1Web3, bridgeAdminAddress, null);
const l1Client = new InsuredBridgeL1Client(
logger,
l1Web3,
bridgeAdminAddress,
null,
config.bridgePoolEarliestBlockToSearch,
null, // Use latest block as end block
config.bridgePoolMaxBlocksToSeach
);

const acrossMonitor = new AcrossMonitor(logger, config, l1Client);

Expand All @@ -39,7 +47,7 @@ export async function run(logger: winston.Logger, l1Web3: Web3): Promise<void> {
if (config.botModes.utilizationEnabled) await acrossMonitor.checkUtilization();
else logger.debug({ at: "AcrossMonitor#Utilization", message: "Utilization monitor disabled" });

if (config.botModes.unknownRelayersEnabled) await acrossMonitor.checkUnknownRelayers();
if (config.botModes.unknownRelayersEnabled) acrossMonitor.checkUnknownRelayers();
else logger.debug({ at: "AcrossMonitor#UnknownRelayers", message: "UnknownRelayers monitor disabled" });
},
{
Expand Down
Loading

0 comments on commit 6fff88a

Please sign in to comment.