Skip to content

Commit

Permalink
feat: update client to prevent client expiration
Browse files Browse the repository at this point in the history
  • Loading branch information
ALPAC-4 committed Dec 16, 2024
1 parent d322283 commit 4178274
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 25 deletions.
62 changes: 58 additions & 4 deletions src/db/controller/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DB } from '..'
import { insert, selectOne } from '../utils'
import { insert, select, selectOne, update } from '../utils'
import { Any } from 'cosmjs-types/google/protobuf/any'
import { UpdateClientEvent, ClientTable } from 'src/types'
import { Header } from 'cosmjs-types/ibc/lightclients/tendermint/v1/tendermint'
Expand Down Expand Up @@ -51,15 +51,35 @@ export class ClientController {
const client = await this.getClient(rest, chainId, clientId)

// update client
client.revision_height = parseInt(
const revisionHeight = parseInt(
event.consensusHeights.split(',')[0].split('-')[1]
)

if (revisionHeight > client.revision_height) {
client.revision_height = revisionHeight
}

if (header.signedHeader?.header?.time.seconds) {
client.last_update_time = Number(header.signedHeader.header.time.seconds)
const lastUpdateTime = Number(header.signedHeader.header.time.seconds)
if (lastUpdateTime > client.last_update_time) {
client.last_update_time = lastUpdateTime
}
}

insert(DB, this.tableName, client)
update<ClientTable>(
DB,
this.tableName,
{
revision_height: client.revision_height,
last_update_time: client.last_update_time,
},
[
{
chain_id: client.chain_id,
client_id: client.client_id,
},
]
)
}

public static async getClient(
Expand All @@ -77,4 +97,38 @@ export class ClientController {

return client ?? this.addClient(rest, chainId, clientId)
}

public static getClientsToUpdate(
chainId: string,
counterpartyChainIds: string[]
): ClientTable[] {
const clients = select<ClientTable>(
DB,
this.tableName,
counterpartyChainIds.map((counterpartyChainId) => ({
chain_id: chainId,
counterparty_chain_id: counterpartyChainId,
}))
)

// check need updates
const currentTimestamp = new Date().valueOf() / 1000

return clients.filter((client) => {
// check expired
if (client.last_update_time + client.trusting_period < currentTimestamp) {
return false
}

// check need update
if (
client.last_update_time + client.trusting_period * 0.666 <
currentTimestamp
) {
return true
}

return false
})
}
}
19 changes: 18 additions & 1 deletion src/lib/eventParser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Event } from '@cosmjs/tendermint-rpc/build/comet38/responses'
import { ChannelOpenCloseInfo, PacketFeeEvent, PacketInfo } from 'src/types'
import {
ChannelOpenCloseInfo,
PacketFeeEvent,
PacketInfo,
UpdateClientEvent,
} from 'src/types'

export function parsePacketEvent(event: Event, height: number): PacketInfo {
const connectionId = getConnection(event) as string
Expand Down Expand Up @@ -124,6 +129,18 @@ export function parsePacketFeeEvent(event: Event): PacketFeeEvent {
}
}

export function parseUpdateClientEvent(event: Event): UpdateClientEvent {
const clientId = find(event, 'client_id') as string
const header = find(event, 'header') as string
const consensusHeights = find(event, 'consensus_heights') as string

return {
clientId,
header,
consensusHeights,
}
}

function getConnection(event: Event): string | undefined {
return find(event, 'connection_id') || find(event, 'packet_connection')
}
Expand Down
13 changes: 6 additions & 7 deletions src/msgs/updateClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,10 @@ async function getValidatorSet(
chain: ChainWorker,
height: number
): Promise<ValidatorSet> {
let block = await chain.rest.tendermint
.blockInfo(height)
.catch(() => undefined)
let header = await chain.rpc.header(height).catch(() => undefined)
let count = 0
while (block === undefined) {
block = await chain.rest.tendermint.blockInfo(height).catch((e) => {
while (header === undefined) {
header = await chain.rpc.header(height).catch((e) => {
if (count > 5) {
throw e
}
Expand All @@ -90,7 +88,7 @@ async function getValidatorSet(
await delay(100)
count++
}
const proposerAddress = block.block.header.proposer_address
const proposerAddress = header.header.proposer_address
// we need to query the header to find out who the proposer was, and pull them out
const validators = await chain.rpc.validatorsAll(height)
let totalVotingPower = BigInt(0)
Expand All @@ -117,7 +115,8 @@ async function getValidatorSet(
})

const proposer: Validator | undefined = mappedValidators.find(
(val) => Buffer.from(val.address).toString('base64') === proposerAddress
(val) =>
Buffer.from(val.address).toString('hex') === proposerAddress.toLowerCase()
)

return ValidatorSet.fromPartial({
Expand Down
28 changes: 27 additions & 1 deletion src/workers/chain.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { RPCClient } from 'src/lib/rpcClient'
import { createLoggerWithPrefix } from 'src/lib/logger'
import { ChannelOpenCloseEvent, PacketEvent, PacketFeeEvent } from 'src/types'
import {
ChannelOpenCloseEvent,
PacketEvent,
PacketFeeEvent,
UpdateClientEvent,
} from 'src/types'
import {
parseChannelCloseEvent,
parseChannelOpenEvent,
parsePacketEvent,
parsePacketFeeEvent,
parseUpdateClientEvent,
} from 'src/lib/eventParser'
import { DB } from 'src/db'
import { SyncInfoController } from 'src/db/controller/syncInfo'
Expand All @@ -16,6 +22,7 @@ import { RESTClient } from 'src/lib/restClient'
import { ChannelController } from 'src/db/controller/channel'
import { PacketFeeController } from 'src/db/controller/packetFee'
import { PacketFee } from 'src/lib/config'
import { ClientController } from 'src/db/controller/client'

export class ChainWorker {
public latestHeight: number
Expand Down Expand Up @@ -138,11 +145,23 @@ class SyncWorker {
const packetEvents = events.map((e) => e.packetEvents).flat()
const channelOpenEvents = events.map((e) => e.channelOpenEvents).flat()
const packetFeeEvents = events.map((e) => e.packetFeeEvents).flat()
const updateClientEvents = events
.map((e) => e.updateClientEvents)
.flat()

this.logger.debug(
`Fetched block results for heights (${JSON.stringify(heights)})`
)

// `feedUpdateClient` does not need to be included in the db transaction
for (const event of updateClientEvents) {
await ClientController.feedUpdateClientEvent(
this.chain.rest,
this.chain.chainId,
event
)
}

let finish = false

const packetEventFeed = await PacketController.feedEvents(
Expand Down Expand Up @@ -196,6 +215,7 @@ class SyncWorker {
packetEvents: PacketEvent[]
channelOpenEvents: ChannelOpenCloseEvent[]
packetFeeEvents: PacketFeeEvent[]
updateClientEvents: UpdateClientEvent[]
}> {
this.logger.debug(`Fetch new block results (height - ${height})`)
const blockResult = await this.chain.rpc.blockResults(height)
Expand All @@ -204,6 +224,7 @@ class SyncWorker {
const packetEvents: PacketEvent[] = []
const channelOpenEvents: ChannelOpenCloseEvent[] = []
const packetFeeEvents: PacketFeeEvent[] = []
const updateClientEvents: UpdateClientEvent[] = []

txData.map((data) => {
for (const event of data.events) {
Expand Down Expand Up @@ -245,13 +266,18 @@ class SyncWorker {
if (event.type === 'incentivized_ibc_packet') {
packetFeeEvents.push(parsePacketFeeEvent(event))
}

if (event.type === 'update_client') {
updateClientEvents.push(parseUpdateClientEvent(event))
}
}
})

return {
packetEvents,
channelOpenEvents,
packetFeeEvents,
updateClientEvents,
}
}
}
Expand Down
26 changes: 14 additions & 12 deletions src/workers/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import { Logger } from 'winston'
import { ChannelController } from 'src/db/controller/channel'
import { State } from '@initia/initia.proto/ibc/core/channel/v1/channel'
import { PacketFee } from 'src/lib/config'
import { ClientController } from 'src/db/controller/client'

// TODO: add update client worker
export class WalletWorker {
private sequence?: number
private accountNumber?: number
Expand Down Expand Up @@ -163,26 +163,18 @@ export class WalletWorker {
await this.filterTimeoutPackets(timeoutPackets)
const filteredChannelOpenCloseEvents =
await this.filterChannelOpenCloseEvents(channelOpenEvents)
if (
filteredSendPackets.length === 0 &&
filteredWriteAckPackets.length === 0 &&
filteredTimeoutPackets.length === 0 &&
filteredChannelOpenCloseEvents.length === 0
) {
return
}

// create msgs

// generate update client msgs
// get unique client id
const connections = [
...filteredSendPackets.map((packet) => packet.dst_connection_id),
...filteredWriteAckPackets.map((packet) => packet.src_connection_id),
...filteredTimeoutPackets.map((packet) => packet.src_connection_id),
...filteredChannelOpenCloseEvents.map((event) => event.connection_id),
].filter((v, i, a) => a.indexOf(v) === i)

// get client ids from connections
const connectionClientMap: Record<string, string> = {}
await Promise.all(
connections.map(async (connection) => {
Expand All @@ -195,10 +187,18 @@ export class WalletWorker {
})
)

const clientIds = Object.values(connectionClientMap).filter(
(v, i, a) => a.indexOf(v) === i
// check clients that need to update
const clientsToUpdate = ClientController.getClientsToUpdate(
this.chain.chainId,
counterpartyChainIdsWithFeeFilter.map((f) => f.chainId)
)

// get unique client id
const clientIds = [
...Object.values(connectionClientMap),
...clientsToUpdate.map((c) => c.client_id),
].filter((v, i, a) => a.indexOf(v) === i)

// generate msgs
const updateClientMsgs: Record<
string,
Expand Down Expand Up @@ -303,6 +303,8 @@ export class WalletWorker {
...channelOpenMsgs,
]

if (msgs.length === 0) return

// init sequence
if (!this.sequence) {
await this.initAccInfo()
Expand Down

0 comments on commit 4178274

Please sign in to comment.