Skip to content

Commit

Permalink
Save polymer data for send packets
Browse files Browse the repository at this point in the history
  • Loading branch information
Inkvi committed Apr 10, 2024
1 parent b358e15 commit 763bc44
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 72 deletions.
8 changes: 8 additions & 0 deletions ponder.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,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(),
}),
Timeout: p.createTable({
id: p.string(),
Expand Down Expand Up @@ -142,6 +145,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(),
}),
WriteTimeoutPacket: p.createTable({
id: p.string(),
Expand Down Expand Up @@ -183,6 +189,8 @@ export default createSchema((p) => ({
ackTx: p.string().optional(),
sendToAckTime: p.int().optional(),
sendToAckGas: p.int().optional(),
sendToRecvPolymerGas: p.int().optional(),
sendToAckPolymerGas: p.int().optional(),
}),
ChannelStates: p.createEnum(["INIT", "TRY", "OPEN", "CLOSED"]),
Channel: p.createTable({
Expand Down
10 changes: 9 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import process from "process";
import { Tendermint37Client } from '@cosmjs/tendermint-rpc';
import { IbcExtension, QueryClient, setupIbcExtension } from '@cosmjs/stargate';
import { IbcExtension, QueryClient, setupIbcExtension, StargateClient } from '@cosmjs/stargate';

export class TmClient {
private static instance: Promise<QueryClient & IbcExtension> | null = null;
private static stargate: Promise<StargateClient> | null = null;

private constructor() {
// Private constructor to prevent direct instantiation
Expand All @@ -16,6 +17,13 @@ export class TmClient {
return TmClient.instance;
}

public static async getStargate(): Promise<StargateClient> {
if (!TmClient.stargate) {
TmClient.stargate = StargateClient.connect(process.env.API_URL!);
}
return TmClient.stargate;
}

private static async createInstance(): Promise<QueryClient & IbcExtension> {
const tmClient = await Tendermint37Client.connect(process.env.API_URL!);
return QueryClient.withExtensions(tmClient, setupIbcExtension);
Expand Down
86 changes: 17 additions & 69 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import logger from './logger';
import { StatName, updateStats } from "./stats";
import { Virtual } from "@ponder/core";
import retry from 'async-retry';
import { updatePacket } from "./packet";

function getAddressAndDispatcherType<name extends Virtual.EventNames<config>>(contractName: "DispatcherSim" | "DispatcherProof", context: Virtual.Context<config, schema, name>) {
let address: `0x${string}` = "0x";
Expand Down Expand Up @@ -354,59 +355,6 @@ async function writeAckPacket<name extends Virtual.EventNames<config>>(event: Vi
await updateStats(context.db.Stat, StatName.WriteAckPacket);
}

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)
return;
}

if (packet.sendPacketId && packet.recvPacketId && !packet.sendToRecvTime) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
const recvPacket = await context.db.RecvPacket.findUnique({id: packet.recvPacketId});
if (sendPacket && recvPacket) {
packet.sendToRecvTime = Number(recvPacket.blockTimestamp - sendPacket.blockTimestamp);
packet.sendToRecvGas = Number(recvPacket.gas + sendPacket.gas);
await context.db.Packet.update({
id,
data: {
sendToRecvTime: packet.sendToRecvTime,
sendToRecvGas: packet.sendToRecvGas,
}
});
}
}

if (packet.sendPacketId && packet.ackPacketId && !packet.sendToAckTime) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
const ackPacket = await context.db.Acknowledgement.findUnique({id: packet.ackPacketId});
if (sendPacket && ackPacket) {
packet.sendToAckTime = Number(ackPacket.blockTimestamp - sendPacket.blockTimestamp);
await context.db.Packet.update({
id,
data: {
sendToAckTime: packet.sendToAckTime,
}
});
}
}

if (packet.sendPacketId && packet.recvPacketId && packet.ackPacketId && !packet.sendToAckGas) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
const recvPacket = await context.db.RecvPacket.findUnique({id: packet.recvPacketId});
const ackPacket = await context.db.Acknowledgement.findUnique({id: packet.ackPacketId});
if (sendPacket && recvPacket && ackPacket) {
packet.sendToAckGas = Number(ackPacket.gas + recvPacket.gas + sendPacket.gas);
await context.db.Packet.update({
id,
data: {
sendToAckGas: packet.sendToAckGas,
}
});
}
}
}

async function recvPacket<name extends Virtual.EventNames<config>>(event: Virtual.Event<config, "DispatcherSim:RecvPacket" | "DispatcherProof:RecvPacket">, context: Virtual.Context<config, schema, name>, contractName: Virtual.ExtractContractName<name>) {
const {address, dispatcherType} = getAddressAndDispatcherType<name>(contractName, context);
let client = DISPATCHER_CLIENT[address!];
Expand Down Expand Up @@ -662,19 +610,19 @@ ponder.on("DispatcherProof:Acknowledgement", async ({event, context}) => {
await acknowledgement(event, context, "DispatcherProof");
});


ponder.on("DispatcherSim:Timeout", async ({event, context}) => {
await timeout(event, context, "DispatcherSim");
});

ponder.on("DispatcherProof:Timeout", async ({event, context}) => {
await timeout(event, context, "DispatcherProof");
});

ponder.on("DispatcherSim:WriteTimeoutPacket", async ({event, context}) => {
await writeTimeoutPacket(event, context, "DispatcherSim");
});

ponder.on("DispatcherProof:WriteTimeoutPacket", async ({event, context}) => {
await writeTimeoutPacket(event, context, "DispatcherProof");
});
//
// ponder.on("DispatcherSim:Timeout", async ({event, context}) => {
// await timeout(event, context, "DispatcherSim");
// });
//
// ponder.on("DispatcherProof:Timeout", async ({event, context}) => {
// await timeout(event, context, "DispatcherProof");
// });
//
// ponder.on("DispatcherSim:WriteTimeoutPacket", async ({event, context}) => {
// await writeTimeoutPacket(event, context, "DispatcherSim");
// });
//
// ponder.on("DispatcherProof:WriteTimeoutPacket", async ({event, context}) => {
// await writeTimeoutPacket(event, context, "DispatcherProof");
// });
182 changes: 182 additions & 0 deletions src/packet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { Virtual } from "@ponder/core";
import { config, schema } from "@/generated";
import { TmClient } from "./client";
import { DatabaseModel } from "@ponder/core/src/types/model";
import { Infer } from "@ponder/core/src/schema/types";
import { Prettify } from "viem/types/utils";


async function updateSendToRecvPolymerGas<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, packet: Prettify<Infer<schema>["Packet"]>) {
if (packet.sendPacketId && !packet.sendToRecvPolymerGas) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
if (sendPacket) {
const stargateClient = await TmClient.getStargate();
const srcPortId = `polyibc.${sendPacket.dispatcherClientName}.${sendPacket.sourcePortAddress.slice(2)}`;

let txs = await stargateClient.searchTx([
{
key: "send_packet.packet_sequence",
value: sendPacket.sequence
},
{
key: "send_packet.packet_src_port",
value: srcPortId
},
{
key: "send_packet.packet_src_channel",
value: sendPacket.sourceChannelId
}
])

if (txs.length > 1) {
throw new Error(`Multiple txs found for sendPacketId: ${sendPacket.id}`);
}

if (txs.length == 1) {
let polymerGas = Number(txs[0]!.gasUsed);
await context.db.SendPacket.update({
id: sendPacket.id,
data: {
polymerGas: polymerGas,
polymerTxHash: txs[0]!.hash,
polymerBlockNumber: BigInt(txs[0]!.height),
}
});

let sendToRecvPolymerGas = polymerGas;

if (packet.sendToAckPolymerGas) {
sendToRecvPolymerGas += packet.sendToAckPolymerGas;
}

await context.db.Packet.update({
id: packet.id,
data: {
sendToRecvPolymerGas: sendToRecvPolymerGas,
}
})
}
}
}
}

async function updateSendToRecvTime<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, packet: Prettify<Infer<schema>["Packet"]>) {
if (packet.sendPacketId && packet.recvPacketId && !packet.sendToRecvTime) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
const recvPacket = await context.db.RecvPacket.findUnique({id: packet.recvPacketId});
if (sendPacket && recvPacket) {
packet.sendToRecvTime = Number(recvPacket.blockTimestamp - sendPacket.blockTimestamp);
packet.sendToRecvGas = Number(recvPacket.gas + sendPacket.gas);
await context.db.Packet.update({
id: packet.id,
data: {
sendToRecvTime: packet.sendToRecvTime,
sendToRecvGas: packet.sendToRecvGas,
}
});
}
}
}

async function updateSendToAckPolymerGas<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, packet: Prettify<Infer<schema>["Packet"]>) {
if (packet.writeAckPacketId && !packet.sendToAckPolymerGas) {
const writeAckPacket = await context.db.WriteAckPacket.findUnique({id: packet.writeAckPacketId});
if (writeAckPacket) {
const stargateClient = await TmClient.getStargate();
const destPortId = `polyibc.${writeAckPacket.dispatcherClientName}.${writeAckPacket.writerPortAddress.slice(2)}`;

let txs = await stargateClient.searchTx([
{
key: "write_acknowledgement.packet_sequence",
value: writeAckPacket.sequence
},
{
key: "write_acknowledgement.packet_dst_port",
value: destPortId
},
{
key: "write_acknowledgement.packet_dst_channel",
value: writeAckPacket.writerChannelId
}
])

if (txs.length > 1) {
throw new Error(`Multiple txs found for writePacketId: ${writeAckPacket.id}`);
}

if (txs.length == 1) {
let polymerGas = Number(txs[0]!.gasUsed);
await context.db.WriteAckPacket.update({
id: writeAckPacket.id,
data: {
polymerGas: polymerGas,
polymerTxHash: txs[0]!.hash,
polymerBlockNumber: BigInt(txs[0]!.height),
}
});

let sendToAckGas = polymerGas;

if (packet.sendToRecvPolymerGas) {
sendToAckGas += packet.sendToRecvPolymerGas;
}

await context.db.Packet.update({
id: packet.id,
data: {
sendToAckPolymerGas: sendToAckGas,
}
})
}
}
}

}


async function updateSendToAckTime<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, packet: Prettify<Infer<schema>["Packet"]>) {
if (packet.sendPacketId && packet.ackPacketId && !packet.sendToAckTime) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
const ackPacket = await context.db.Acknowledgement.findUnique({id: packet.ackPacketId});
if (sendPacket && ackPacket) {
packet.sendToAckTime = Number(ackPacket.blockTimestamp - sendPacket.blockTimestamp);
await context.db.Packet.update({
id: packet.id,
data: {
sendToAckTime: packet.sendToAckTime,
}
});
}
}
}

async function updateSendToAckGas<name extends Virtual.EventNames<config>>(context: Virtual.Context<config, schema, name>, packet: DatabaseModel<"Packet">) {
if (packet.sendPacketId && packet.recvPacketId && packet.ackPacketId && !packet.sendToAckGas) {
const sendPacket = await context.db.SendPacket.findUnique({id: packet.sendPacketId});
const recvPacket = await context.db.RecvPacket.findUnique({id: packet.recvPacketId});
const ackPacket = await context.db.Acknowledgement.findUnique({id: packet.ackPacketId});
if (sendPacket && recvPacket && ackPacket) {
packet.sendToAckGas = Number(ackPacket.gas + recvPacket.gas + sendPacket.gas);
await context.db.Packet.update({
id: packet.id,
data: {
sendToAckGas: packet.sendToAckGas,
}
});
}
}
}

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)
return;
}

await updateSendToRecvTime(context, packet)
await updateSendToAckTime(context, packet)
await updateSendToAckGas(context, packet)
await updateSendToRecvPolymerGas(context, packet)
await updateSendToAckPolymerGas(context, packet)
}
3 changes: 1 addition & 2 deletions src/stats.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { DatabaseModel } from "@ponder/core/src/types/model";
import { Infer } from "@ponder/core/src/schema/types";
import { schema } from "@/generated";

Expand All @@ -14,7 +13,7 @@ export enum StatName {
ConnectIbcChannel = 'ConnectIbcChannel',
}

export async function updateStats<T extends DatabaseModel<Infer<schema>["Stat"]>>(Stat: T, id: StatName) {
export async function updateStats<T extends Infer<schema>["Stat"]>(Stat: T, id: StatName) {
await Stat.upsert({
id: id,
create: {
Expand Down

0 comments on commit 763bc44

Please sign in to comment.