Skip to content

Commit

Permalink
Hyperclient: Support resuming streams (#316)
Browse files Browse the repository at this point in the history
  • Loading branch information
seunlanlege authored Sep 28, 2024
1 parent ca02004 commit d914c77
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 506 deletions.
182 changes: 109 additions & 73 deletions modules/hyperclient/hyperclient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@
*/
export function start(): void;

interface IConfig {
export type HexString = `0x{string}` | `0x${string}`;

export interface IConfig {
// confuration object for the source chain
source: IChainConfig;
source: IEvmConfig | ISubstrateConfig;
// confuration object for the destination chain
dest: IChainConfig;
dest: IEvmConfig | ISubstrateConfig;
// confuration object for hyperbridge
hyperbridge: IHyperbridgeConfig;
// Indexer url
indexer: string;
}

interface IChainConfig {
export interface IEvmConfig {
// rpc url of the chain
rpc_url: string;
// state machine identifier as a string
Expand All @@ -41,12 +43,21 @@ interface IChainConfig {
consensus_state_id: string;
}

interface IHyperbridgeConfig {
export interface ISubstrateConfig {
// rpc url of the chain
rpc_url: string;
// consensus state identifier of this chain on hyperbridge
consensus_state_id: string;
// consensus state identifier of this chain on hyperbridge
hash_algo: "Keccak" | "Blake2";
}

export interface IHyperbridgeConfig {
// websocket rpc endpoint for hyperbridge
rpc_url: string;
}

interface IPostRequest {
export interface IPostRequest {
// The source state machine of this request.
source: string;
// The destination state machine of this request.
Expand All @@ -61,11 +72,9 @@ interface IPostRequest {
body: string;
// Timestamp which this request expires in seconds.
timeoutTimestamp: bigint;
// Height at which this request was emitted on the source
txHeight: bigint;
}

interface IGetRequest {
export interface IGetRequest {
// The source state machine of this request.
source: string;
// The destination state machine of this request.
Expand All @@ -87,14 +96,12 @@ interface IGetRequest {
/// `<https://github.com/paritytech/substrate/blob/master/frame/support/src/storage/types/value.rs#L37>`
/// For fetching keys from EVM contracts each key should be 52 bytes
/// This should be a concatenation of contract address and slot hash
keys: `0x{string}`[];
keys: HexString[];
// Timestamp which this request expires in seconds.
timeoutTimestamp: bigint;
// Height at which this request was emitted on the source
txHeight: bigint;
}

interface IPostResponse {
export interface IPostResponse {
// The request that triggered this response.
post: IPostRequest;
// The response message.
Expand All @@ -103,157 +110,174 @@ interface IPostResponse {
timeoutTimestamp: bigint;
}

type MessageStatus =
| Pending
| SourceFinalized
| HyperbridgeDelivered
| HyperbridgeFinalized
| DestinationDelivered
| Timeout;

// This transaction is still pending on the source chain
interface Pending {
export interface Pending {
kind: "Pending";
}

// This event is emitted on hyperbridge
interface SourceFinalized {
export interface SourceFinalized {
kind: "SourceFinalized";
}

// This event is emitted on hyperbridge
interface HyperbridgeDelivered {
kind: "HyperbridgeDelivered";
export interface HyperbridgeVerified {
kind: "HyperbridgeVerified";
}

// This event is emitted on the destination chain
interface HyperbridgeFinalized {
export interface HyperbridgeFinalized {
kind: "HyperbridgeFinalized";
}

// This event is emitted on the destination chain
interface DestinationDelivered {
export interface DestinationDelivered {
kind: "DestinationDelivered";
}

// The request has now timed out
interface Timeout {
export interface Timeout {
kind: "Timeout";
}

// The request has now timed out
interface DestinationFinalized {
export interface DestinationFinalized {
kind: "DestinationFinalized";
}

// The request has now timed out
interface HyperbridgeTimedout {
export interface HyperbridgeTimedout {
kind: "HyperbridgeTimedout";
}

// The request has now timed out
interface HyperbridgeTimedout {
export interface HyperbridgeTimedout {
kind: "HyperbridgeTimedout";
}

// The request timeout has been finalized by the destination
export interface DestinationFinalizedState {
// the height of the destination chain at which the time out was finalized
DestinationFinalized: bigint
}

// Hyperbridge has finalized some state
export interface HyperbridgeFinalizedState {
// The height of the state commitment that was finalized
HyperbridgeFinalized: bigint
}

// The source chain has finalized some state commitment
export interface SourceFinalizedState {
// The height of the source chain which was finalized
SourceFinalized: bigint
}

// The message has been verified & aggregated to Hyperbridge
export interface HyperbridgeVerifiedState {
// Height at which the message was aggregated to Hyperbridge
HyperbridgeVerified: bigint
}

// Initial state for a pending cross-chain message
export interface MessageDispatched {
// The height at which the message was dispatched from the source chain
Dispatched: bigint
}

// The possible initial states of a timeout (Post request or response) stream
export type TimeoutStreamState = "Pending" | DestinationFinalizedState | HyperbridgeVerifiedState | HyperbridgeFinalizedState;

// The possible initial states of a message status (Post request or response) stream
export type MessageStatusStreamState = MessageDispatched | SourceFinalizedState | HyperbridgeVerifiedState | HyperbridgeFinalizedState;

// The possible states of an inflight request
type MessageStatusWithMeta =
export type MessageStatusWithMeta =
| SourceFinalizedWithMetadata
| HyperbridgeDeliveredWithMetadata
| HyperbridgeVerifiedWithMetadata
| HyperbridgeFinalizedWithMetadata
| DestinationDeliveredWithMetadata
| Timeout
| ErrorWithMetadata;

// The possible states of a timed-out request
type TimeoutStatusWithMeta =
export type TimeoutStatusWithMeta =
| DestinationFinalizedWithMetadata
| HyperbridgeTimedoutWithMetadata
| HyperbridgeVerifiedWithMetadata
| HyperbridgeFinalizedWithMetadata
| TimeoutMessage
| ErrorWithMetadata;

// This event is emitted on hyperbridge
interface SourceFinalizedWithMetadata {
export interface SourceFinalizedWithMetadata {
kind: "SourceFinalized";
// Block height of the source chain that was finalized.
finalized_height: bigint;
// The hash of the block where the event was emitted
block_hash: `0x{string}`;
block_hash: HexString;
// The hash of the extrinsic responsible for the event
transaction_hash: `0x{string}`;
transaction_hash: HexString;
// The block number where the event was emitted
block_number: bigint;
}

// This event is emitted on hyperbridge
interface HyperbridgeDeliveredWithMetadata {
kind: "HyperbridgeDelivered";
export interface HyperbridgeVerifiedWithMetadata {
kind: "HyperbridgeVerified";
// The hash of the block where the event was emitted
block_hash: `0x{string}`;
block_hash: HexString;
// The hash of the extrinsic responsible for the event
transaction_hash: `0x{string}`;
transaction_hash: HexString;
// The block number where the event was emitted
block_number: bigint;
}

// This event is emitted on the destination chain
interface HyperbridgeFinalizedWithMetadata {
export interface HyperbridgeFinalizedWithMetadata {
kind: "HyperbridgeFinalized";
// Block height of hyperbridge chain that was finalized.
finalized_height: bigint;
// The hash of the block where the event was emitted
block_hash: `0x{string}`;
block_hash: HexString;
// The hash of the extrinsic responsible for the event
transaction_hash: `0x{string}`;
transaction_hash: HexString;
// The block number where the event was emitted
block_number: bigint;
// The transaction calldata which can be used for self-relay
calldata: `0x{string}`;
}

// This event is emitted on hyperbridge
interface HyperbridgeTimedoutWithMetadata {
kind: "HyperbridgeTimedout";
// The hash of the block where the event was emitted
block_hash: `0x{string}`;
// The hash of the extrinsic responsible for the event
transaction_hash: `0x{string}`;
// The block number where the event was emitted
block_number: bigint;
calldata: HexString;
}

// This event is emitted on the destination chain
interface DestinationDeliveredWithMetadata {
export interface DestinationDeliveredWithMetadata {
kind: "DestinationDelivered";
// The hash of the block where the event was emitted
block_hash: `0x{string}`;
block_hash: HexString;
// The hash of the extrinsic responsible for the event
transaction_hash: `0x{string}`;
transaction_hash: HexString;
// The block number where the event was emitted
block_number: bigint;
}

// This event is emitted on the destination chain
interface TimeoutMessage {
export interface TimeoutMessage {
kind: "TimeoutMessage";
// encoded call for HandlerV1.handlePostRequestTimeouts
calldata: `0x{string}`;
calldata: HexString;
}

// This event is emitted on hyperbridge
interface DestinationFinalizedWithMetadata {
export interface DestinationFinalizedWithMetadata {
kind: "DestinationFinalized";
// The hash of the block where the event was emitted
block_hash: `0x{string}`;
block_hash: HexString;
// The hash of the extrinsic responsible for the event
transaction_hash: `0x{string}`;
transaction_hash: HexString;
// The block number where the event was emitted
block_number: bigint;
}

// An error was encountered in the stream, the stream will come to an end.
interface ErrorWithMetadata {
export interface ErrorWithMetadata {
kind: "Error";
// error description
description: string;
Expand All @@ -265,49 +289,55 @@ interface ErrorWithMetadata {
*/
export class HyperClient {
free(): void;

/**
* Initialize the hyperclient
* @param {IConfig} config
* @returns {Promise<HyperClient>}
*/
static init(config: IConfig): Promise<HyperClient>;

/**
* Queries the status of a request and returns `MessageStatusWithMetadata`
* Queries the status of a POST request`
* @param {IPostRequest} request
* @returns {Promise<MessageStatusWithMeta>}
*/
query_post_request_status(
request: IPostRequest,
): Promise<MessageStatusWithMeta>;

/**
* Queries the status of a request and returns `MessageStatusWithMetadata`
* Queries the status of a GET request`
* @param {IGetRequest} request
* @returns {Promise<any>}
*/
query_get_request_status(
request: IGetRequest,
): Promise<MessageStatusWithMeta>;

/**
* Accepts a post response and returns a `MessageStatusWithMetadata`
* Queries the status of a POST response`
* @param {IPostResponse} response
* @returns {Promise<MessageStatusWithMeta>}
*/
query_post_response_status(
response: IPostResponse,
): Promise<MessageStatusWithMeta>;

/**
* Return the status of a post request as a `ReadableStream` that yields
* `MessageStatusWithMeta`
* Return the status of a post request as a `ReadableStream`. If the stream terminates abruptly,
* perhaps as a result of some error, it can be resumed given some initial state.
* @param {IPostRequest} request
* @param {MessageStatusStreamState} state
* @returns {Promise<ReadableStream<MessageStatusWithMeta>>}
*/
post_request_status_stream(
request: IPostRequest,
state: MessageStatusStreamState,
): Promise<ReadableStream<MessageStatusWithMeta>>;

/**
* Return the status of a get request as a `ReadableStream` that yields
* `MessageStatusWithMeta`
* Return the status of a get request as a `ReadableStream`
* @param {IGetRequest} request
* @returns {Promise<ReadableStream<MessageStatusWithMeta>>}
*/
Expand All @@ -320,12 +350,18 @@ export class HyperClient {
* `TimeoutStatus` This function will not check if the request has timed out, only call it
* when you receive a `MesssageStatus::TimeOut` from `query_request_status` or
* `request_status_stream`. The stream ends when once it yields a `TimeoutMessage`
*
* If the stream terminates abruptly, perhaps as a result of some error, it can be resumed given some initial state.
*
* @param {IPostRequest} request
* @param {TimeoutStreamState} state
* @returns {Promise<ReadableStream<TimeoutStatusWithMeta>>}
*/
timeout_post_request(
request: IPostRequest,
state: TimeoutStreamState,
): Promise<ReadableStream<TimeoutStatusWithMeta>>;

/**
* @returns {string | undefined}
*/
Expand Down
2 changes: 1 addition & 1 deletion modules/hyperclient/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@polytope-labs/hyperclient",
"description": "The hyperclient is a library for managing (in-flight) ISMP requests",
"version": "0.5.2",
"version": "0.6.2",
"author": "Polytope Labs ([email protected])",
"license": "Apache-2.0",
"bugs": {
Expand Down
Loading

0 comments on commit d914c77

Please sign in to comment.