function pendingDatagrams(chain: Chain, counterparty: Chain): List<Set<Datagram>> {
const localDatagrams = []
const counterpartyDatagrams = []
// ICS2 : Clients
// - Determine if light client needs to be updated (local & counterparty)
height = chain.latestHeight()
client = counterparty.queryClientConsensusState(chain)
if client.height < height {
header = chain.latestHeader()
counterpartyDatagrams.push(ClientUpdate{chain, header})
}
counterpartyHeight = counterparty.latestHeight()
client = chain.queryClientConsensusState(counterparty)
if client.height < counterpartyHeight {
header = counterparty.latestHeader()
localDatagrams.push(ClientUpdate{counterparty, header})
}
// ICS3 : Connections
// - Determine if any connection handshakes are in progress
connections = chain.getConnectionsUsingClient(counterparty)
for (const localEnd of connections) {
remoteEnd = counterparty.getConnection(localEnd.counterpartyIdentifier)
if (localEnd.state === INIT && remoteEnd === null)
// Handshake has started locally (1 step done), relay `connOpenTry` to the remote end
counterpartyDatagrams.push(ConnOpenTry{
desiredIdentifier: localEnd.counterpartyConnectionIdentifier,
counterpartyConnectionIdentifier: localEnd.identifier,
counterpartyClientIdentifier: localEnd.clientIdentifier,
counterpartyPrefix: localEnd.commitmentPrefix,
clientIdentifier: localEnd.counterpartyClientIdentifier,
version: localEnd.version,
counterpartyVersion: localEnd.version,
proofInit: localEnd.proof(height),
proofConsensus: localEnd.client.consensusState.proof(),
proofHeight: height,
consensusHeight: localEnd.client.height,
})
else if (localEnd.state === INIT && remoteEnd.state === TRYOPEN)
// Handshake has started on the other end (2 steps done), relay `connOpenAck` to the local end
localDatagrams.push(ConnOpenAck{
identifier: localEnd.identifier,
version: remoteEnd.version,
proofTry: remoteEnd.proof(counterpartyHeight),
proofConsensus: remoteEnd.client.consensusState.proof(),
proofHeight: counterpartyHeight,
consensusHeight: remoteEnd.client.height,
})
else if (localEnd.state === OPEN && remoteEnd.state === TRYOPEN)
// Handshake has confirmed locally (3 steps done), relay `connOpenConfirm` to the remote end
counterpartyDatagrams.push(ConnOpenConfirm{
identifier: remoteEnd.identifier,
proofAck: localEnd.proof(height),
proofHeight: height,
})
}
// ICS4 : Channels & Packets
// - Determine if any channel handshakes are in progress
// - Determine if any packets, acknowledgements, or timeouts need to be relayed
channels = chain.getChannelsUsingConnections(connections)
for (const localEnd of channels) {
remoteEnd = counterparty.getConnection(localEnd.counterpartyIdentifier)
// Deal with handshakes in progress
if (localEnd.state === INIT && remoteEnd === null)
// Handshake has started locally (1 step done), relay `chanOpenTry` to the remote end
counterpartyDatagrams.push(ChanOpenTry{
order: localEnd.order,
connectionHops: localEnd.connectionHops.reverse(),
portIdentifier: localEnd.counterpartyPortIdentifier,
channelIdentifier: localEnd.counterpartyChannelIdentifier,
counterpartyPortIdentifier: localEnd.portIdentifier,
counterpartyChannelIdentifier: localEnd.channelIdentifier,
version: localEnd.version,
counterpartyVersion: localEnd.version,
proofInit: localEnd.proof(height),
proofHeight: height,
})
else if (localEnd.state === INIT && remoteEnd.state === TRYOPEN)
// Handshake has started on the other end (2 steps done), relay `chanOpenAck` to the local end
localDatagrams.push(ChanOpenAck{
portIdentifier: localEnd.portIdentifier,
channelIdentifier: localEnd.channelIdentifier,
version: remoteEnd.version,
proofTry: remoteEnd.proof(counterpartyHeight),
proofHeight: counterpartyHeight,
})
else if (localEnd.state === OPEN && remoteEnd.state === TRYOPEN)
// Handshake has confirmed locally (3 steps done), relay `chanOpenConfirm` to the remote end
counterpartyDatagrams.push(ChanOpenConfirm{
portIdentifier: remoteEnd.portIdentifier,
channelIdentifier: remoteEnd.channelIdentifier,
proofAck: localEnd.proof(height),
proofHeight: height
})
// Deal with packets
// First, scan logs for sent packets and relay all of them
sentPacketLogs = queryByTopic(height, "sendPacket")
for (const logEntry of sentPacketLogs) {
// relay packet with this sequence number
packetData = Packet{logEntry.sequence, logEntry.timeoutHeight, logEntry.timeoutTimestamp,
localEnd.portIdentifier, localEnd.channelIdentifier,
remoteEnd.portIdentifier, remoteEnd.channelIdentifier, logEntry.data}
counterpartyDatagrams.push(PacketRecv{
packet: packetData,
proof: packet.proof(),
proofHeight: height,
})
}
// Then, scan logs for acknowledgements, relay back to sending chain
recvPacketLogs = queryByTopic(height, "writeAcknowledgement")
for (const logEntry of recvPacketLogs) {
// relay packet acknowledgement with this sequence number
packetData = Packet{logEntry.sequence, logEntry.timeoutHeight, logEntry.timeoutTimestamp,
localEnd.portIdentifier, localEnd.channelIdentifier,
remoteEnd.portIdentifier, remoteEnd.channelIdentifier, logEntry.data}
counterpartyDatagrams.push(PacketAcknowledgement{
packet: packetData,
acknowledgement: logEntry.acknowledgement,
proof: packet.proof(),
proofHeight: height,
})
}
}
return [localDatagrams, counterpartyDatagrams]
}