Skip to content

Commit

Permalink
Compute initToTry time for channels
Browse files Browse the repository at this point in the history
  • Loading branch information
Inkvi committed Apr 11, 2024
1 parent 4fca302 commit b51e0dd
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 23 deletions.
27 changes: 27 additions & 0 deletions ponder.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,19 @@ export default createSchema((p) => ({
maxFeePerGas: p.bigint().optional(),
maxPriorityFeePerGas: p.bigint().optional(),
from: p.string(),
polymerTxHash: p.string().optional(),
polymerGas: p.int().optional(),
polymerBlockNumber: p.bigint().optional(),
}),
ConnectIbcChannel: p.createTable({
id: p.string(),
dispatcherAddress: p.string(),
dispatcherType: p.string(),
dispatcherClientName: p.string(),
portId: p.string(),
portAddress: p.string(),
counterpartyPortId: p.string(),
counterpartyChannelId: p.string(),
channelId: p.string(),
blockNumber: p.bigint(),
blockTimestamp: p.bigint(),
Expand All @@ -49,12 +55,16 @@ export default createSchema((p) => ({
maxFeePerGas: p.bigint().optional(),
maxPriorityFeePerGas: p.bigint().optional(),
from: p.string(),
polymerTxHash: p.string().optional(),
polymerGas: p.int().optional(),
polymerBlockNumber: p.bigint().optional(),
}),
OpenIbcChannel: p.createTable({
id: p.string(),
dispatcherAddress: p.string(),
dispatcherType: p.string(),
dispatcherClientName: p.string(),
portId: p.string(),
portAddress: p.string(),
version: p.string(),
ordering: p.int(),
Expand All @@ -70,6 +80,9 @@ export default createSchema((p) => ({
maxFeePerGas: p.bigint().optional(),
maxPriorityFeePerGas: p.bigint().optional(),
from: p.string(),
polymerTxHash: p.string().optional(),
polymerGas: p.int().optional(),
polymerBlockNumber: p.bigint().optional(),
}),
RecvPacket: p.createTable({
id: p.string(),
Expand Down Expand Up @@ -204,6 +217,20 @@ export default createSchema((p) => ({
blockTimestamp: p.bigint(),
transactionHash: p.string(),
state: p.enum('ChannelStates'),
openInitChannel: p.one('openInitChannelId'),
openInitChannelId: p.string().optional().references('OpenIbcChannel.id'),
openTryChannel: p.one('openTryChannelId'),
openTryChannelId: p.string().optional().references('OpenIbcChannel.id'),
openAckChannel: p.one('openAckChannelId'),
openAckChannelId: p.string().optional().references('ConnectIbcChannel.id'),
openConfirmChannel: p.one('openConfirmChannelId'),
openConfirmChannelId: p.string().optional().references('ConnectIbcChannel.id'),
closeChannel: p.one('closeChannelId'),
closeChannelId: p.string().optional().references('CloseIbcChannel.id'),
initToTryTime: p.int().optional(),
initToOpenTime: p.int().optional(),
initToAckTime: p.int().optional(),
initToConfirmTime: p.int().optional(),
}),
Stat: p.createTable({
id: p.string(),
Expand Down
122 changes: 122 additions & 0 deletions src/channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Virtual } from "@ponder/core";
import { config, schema } from "@/generated";
import { Prettify } from "viem/types/utils";
import { Infer } from "@ponder/core/src/schema/types";
import logger from "./logger";

async function updateInitToTryTime<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, channel: Prettify<Infer<schema>["Channel"]>) {
if (channel.state == "INIT" && !channel.initToTryTime) {
const openInitChannel = await context.db.OpenIbcChannel.findUnique({id: channel.openInitChannelId});
if (!openInitChannel) {
throw new Error(`No openInitChannel found for channel with state INIT and id: ${channel.id}`);
}

const openTryChannel = await context.db.OpenIbcChannel.findMany({
where: {
portId: openInitChannel.counterpartyPortId,
blockTimestamp: {gt: openInitChannel.blockTimestamp}
},
orderBy: {blockTimestamp: "asc"},
limit: 1
});

if (openTryChannel.items.length > 1) {
throw new Error(`Multiple openTryChannels found for openInitChannelId: ${channel.openInitChannelId}`);
}

if (openTryChannel.items.length == 1) {
let initToTryTime = openTryChannel.items[0]!.blockTimestamp - openInitChannel.blockTimestamp;
await context.db.Channel.update({
id: channel.id,
data: {
initToTryTime: Number(initToTryTime),
openTryChannelId: openTryChannel.items[0]!.id,
},
});
const cpChannel = await context.db.Channel.findMany({
where: {
openTryChannelId: openTryChannel.items[0]!.id,
state: "TRY"
}
});

if (cpChannel.items.length == 0) {
throw new Error(`No counterparty channel found for openTryChannelId: ${openTryChannel.items[0]!.id}`);
}

if (cpChannel.items.length > 1) {
throw new Error(`Multiple counterparty channels found for openTryChannelId: ${openTryChannel.items[0]!.id}`);
}

await context.db.Channel.update({
id: cpChannel.items[0]!.id,
data: {
initToTryTime: Number(initToTryTime),
openInitChannelId: channel.id,
},
});
}
}

if (channel.state == "TRY" && !channel.initToTryTime) {
const openTryChannel = await context.db.OpenIbcChannel.findUnique({id: channel.openTryChannelId});
const openInitChannel = await context.db.OpenIbcChannel.findMany({
where: {
portId: openTryChannel?.counterpartyPortId,
blockTimestamp: {lt: openTryChannel!.blockTimestamp}
},
orderBy: {blockTimestamp: "desc"},
limit: 1
});

if (openInitChannel.items.length > 1) {
throw new Error(`Multiple openInitChannels found for openTryChannelId: ${channel.openTryChannelId}`);
}

if (openInitChannel.items.length == 1) {
let initToTryTime = openTryChannel!.blockTimestamp - openInitChannel.items[0]!.blockTimestamp;
await context.db.Channel.update({
id: channel.id,
data: {
initToTryTime: Number(initToTryTime),
openInitChannelId: openInitChannel.items[0]!.id
},
});
const cpChannel = await context.db.Channel.findMany({
where: {
openInitChannelId: openInitChannel.items[0]!.id,
state: "INIT"
}
});

if (cpChannel.items.length == 0) {
logger.error(`No counterparty channel found for openInitChannelId: ${openInitChannel.items[0]!.id}`);
return;
}

if (cpChannel.items.length > 1) {
logger.error(`Multiple counterparty channels found for openInitChannelId: ${openInitChannel.items[0]!.id}`);
return;
}

await context.db.Channel.update({
id: cpChannel.items[0]!.id,
data: {
initToTryTime: Number(initToTryTime),
openTryChannelId: channel.id
},
});
}
}

}

export async function updateChannel<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, id: string) {
let channel = await context.db.Channel.findUnique({id})
if (!channel) {
console.warn('No channel found with id', id)
return;
}

await updateInitToTryTime(context, channel)
}
59 changes: 37 additions & 22 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Virtual } from "@ponder/core";
import retry from 'async-retry';
import { updatePacket } from "./packet";
import { defaultRetryOpts } from "./retry";
import { updateChannel } from "./channel";

function getAddressAndDispatcherType<name extends Virtual.EventNames<config>>(contractName: "DispatcherSim" | "DispatcherProof", context: Virtual.Context<config, schema, name>) {
let address: `0x${string}` = "0x";
Expand All @@ -29,6 +30,7 @@ async function openIbcChannel<name extends Virtual.EventNames<config>>(event: Vi
let counterpartyChannelId = ethers.decodeBytes32String(event.args.counterpartyChannelId);
let connectionHops = event.args.connectionHops;
let portAddress = event.args.portAddress;
let portId = `polyibc.${client}.${portAddress.slice(2)}`;
let version = event.args.version;

await context.db.OpenIbcChannel.create({
Expand All @@ -38,6 +40,7 @@ async function openIbcChannel<name extends Virtual.EventNames<config>>(event: Vi
dispatcherType: dispatcherType,
dispatcherClientName: client!,
portAddress: portAddress,
portId: portId,
version: version,
ordering: event.args.ordering,
feeEnabled: event.args.feeEnabled,
Expand All @@ -57,10 +60,15 @@ async function openIbcChannel<name extends Virtual.EventNames<config>>(event: Vi
});

let channelId = '';
let portId = `polyibc.${client}.${portAddress.slice(2)}`;
let state: "INIT" | "TRY" = counterpartyChannelId == "" ? "INIT" : "TRY";
let openInitChannelId, openTryChannelId;

if (state == "INIT") {
openInitChannelId = event.log.id;
}

if (state == "TRY") {
openTryChannelId = event.log.id;
const tmClient = await TmClient.getInstance();
await retry(async bail => {
// If anything throws within this function, it will retry
Expand All @@ -80,7 +88,6 @@ async function openIbcChannel<name extends Virtual.EventNames<config>>(event: Vi
});
}


await context.db.Channel.create({
id: event.log.id,
data: {
Expand All @@ -93,8 +100,12 @@ async function openIbcChannel<name extends Virtual.EventNames<config>>(event: Vi
blockTimestamp: event.block.timestamp,
transactionHash: event.transaction.hash,
state: state,
openInitChannelId: openInitChannelId,
openTryChannelId: openTryChannelId,
}
})

await updateChannel(context, event.log.id)
await updateStats(context.db.Stat, StatName.OpenIBCChannel)
}

Expand All @@ -104,29 +115,10 @@ async function connectIbcChannel<name extends Virtual.EventNames<config>>(event:
const chainId = context.network.chainId as number;
let channelId = ethers.decodeBytes32String(event.args.channelId);
let portAddress = event.args.portAddress;

await context.db.ConnectIbcChannel.create({
id: event.log.id,
data: {
dispatcherAddress: address || "0x",
dispatcherType: dispatcherType,
dispatcherClientName: client!,
portAddress: portAddress,
channelId: channelId,
chainId: chainId,
blockNumber: event.block.number,
blockTimestamp: event.block.timestamp,
transactionHash: event.transaction.hash,
gas: Number(event.transaction.gas),
maxFeePerGas: event.transaction.maxFeePerGas,
maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas,
from: event.transaction.from.toString(),
},
});
let portId = `polyibc.${client}.${portAddress.slice(2)}`;

let counterpartyPortId = '';
let counterpartyChannelId = '';
let portId = `polyibc.${client}.${portAddress.slice(2)}`;

const tmClient = await TmClient.getInstance();

Expand All @@ -149,6 +141,29 @@ async function connectIbcChannel<name extends Virtual.EventNames<config>>(event:
});



await context.db.ConnectIbcChannel.create({
id: event.log.id,
data: {
dispatcherAddress: address || "0x",
dispatcherType,
dispatcherClientName: client!,
portId,
counterpartyPortId,
counterpartyChannelId,
portAddress,
channelId,
chainId,
blockNumber: event.block.number,
blockTimestamp: event.block.timestamp,
transactionHash: event.transaction.hash,
gas: Number(event.transaction.gas),
maxFeePerGas: event.transaction.maxFeePerGas,
maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas,
from: event.transaction.from.toString(),
},
});

// update earliest INIT state record that have incomplete id
let channels = await context.db.Channel.findMany({
where: {portId: portId, channelId: ""},
Expand Down
2 changes: 1 addition & 1 deletion src/packet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ async function updateSendToAckGas<name extends Virtual.EventNames<config>>(conte
export async function updatePacket<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, id: string) {
let packet = await context.db.Packet.findUnique({id})
if (!packet) {
console.warn('No packet found for updatePacket', id)
console.warn('No packet found with id', id)
return;
}

Expand Down

0 comments on commit b51e0dd

Please sign in to comment.