Skip to content
This repository has been archived by the owner on Sep 14, 2023. It is now read-only.

Commit

Permalink
chore: beacon-related tweaks (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay authored Jun 20, 2022
1 parent 16fa61f commit ed5d3e1
Show file tree
Hide file tree
Showing 21 changed files with 95 additions and 103 deletions.
18 changes: 9 additions & 9 deletions _tasks/download_frame_metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ const outDir = path.join(Deno.cwd(), "frame_metadata", "_downloaded");
await fs.emptyDir(outDir);
await Promise.all(
Object.entries({
acala: known.ACALA_PROXY_WS_URL,
kusama: known.KUSAMA_PROXY_WS_URL,
moonbeam: known.MOONBEAM_PROXY_WS_URL,
polkadot: known.POLKADOT_PROXY_WS_URL,
statemint: known.STATEMINT_PROXY_WS_URL,
subsocial: known.SUBSOCIAL_PROXY_WS_URL,
westend: known.WESTEND_PROXY_WS_URL,
}).map(async ([name, url]) => {
const client = await rpc.client(rpc.beacon([url]));
acala: known.acalaBeacon,
kusama: known.kusamaBeacon,
moonbeam: known.moonbeamBeacon,
polkadot: known.polkadotBeacon,
statemint: known.statemintBeacon,
subsocial: known.subsocialBeacon,
westend: known.westendBeacon,
}).map(async ([name, beacon]) => {
const client = await rpc.client(beacon);
assert(!(client instanceof Error));
try {
const metadata = await client.call("state_getMetadata", []);
Expand Down
2 changes: 1 addition & 1 deletion effect/std/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { rpcCall } from "./rpcCall.ts";

export const metadata = effector(
"metadata",
(rpc: EffectorItem<rpc.AnyClient>, blockHash?: EffectorItem<U.HashHexString>) => {
(rpc: EffectorItem<any>, blockHash?: EffectorItem<U.HashHexString>) => {
const rpcCall_ = rpcCall(rpc, "state_getMetadata", blockHash);
const result = select(rpcCall_, "result");
return metadataDecoded(result);
Expand Down
2 changes: 1 addition & 1 deletion effect/std/pallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface Pallet {
export const pallet = effector.sync(
"pallet",
() =>
(rpc: AnyClient, name: string): Pallet => ({
(rpc: any, name: string): Pallet => ({
rpc,
name,
}),
Expand Down
2 changes: 1 addition & 1 deletion examples/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { polkadotBeacon } from "../known/mod.ts";
import * as C from "../mod.ts";
import * as rpc from "../rpc/mod.ts";

const client = await rpc.client(rpc.beacon(polkadotBeacon));
const client = await rpc.client(polkadotBeacon);
assert(!(client instanceof Error));
const ss58 = C.ss58FromText("13SceNt2ELz3ti4rnQbY1snpYH4XE4fLFsW8ph9rpwJd6HFC");
const pubKey = C.pubKeyFromSs58(ss58);
Expand Down
2 changes: 1 addition & 1 deletion examples/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { westendBeacon } from "../known/mod.ts";
import * as C from "../mod.ts";
import * as rpc from "../rpc/mod.ts";

const client = await rpc.client(rpc.beacon(westendBeacon));
const client = await rpc.client(westendBeacon);
assert(!(client instanceof Error));
const $pallet = C.pallet(client, "System");
const $entry = C.entry($pallet, "Events");
Expand Down
3 changes: 2 additions & 1 deletion examples/first_ten_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { polkadotBeacon } from "../known/mod.ts";
import * as C from "../mod.ts";
import * as rpc from "../rpc/mod.ts";

const client = await rpc.client(rpc.beacon(polkadotBeacon));
const client = await rpc.client(polkadotBeacon);
assert(!(client instanceof Error));
client;
const pallet = C.pallet(client, "System");
const map = C.map(pallet, "Account");
const result = await C.mapKeys(map, 10).run();
Expand Down
2 changes: 1 addition & 1 deletion examples/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { polkadotBeacon } from "../known/mod.ts";
import * as C from "../mod.ts";
import * as rpc from "../rpc/mod.ts";

const client = await rpc.client(rpc.beacon(polkadotBeacon));
const client = await rpc.client(polkadotBeacon);
assert(!(client instanceof Error));
const $metadata = C.metadata(client);
const result = await $metadata.run();
Expand Down
2 changes: 1 addition & 1 deletion examples/rpc/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { assert } from "../../_deps/asserts.ts";
import { polkadotBeacon } from "../../known/mod.ts";
import * as rpc from "../../rpc/mod.ts";

const client = await rpc.client(rpc.beacon(polkadotBeacon));
const client = await rpc.client(polkadotBeacon);
assert(!(client instanceof Error));
const result = await client.call("state_getMetadata", []);
console.log(result);
Expand Down
2 changes: 1 addition & 1 deletion examples/rpc/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { assert } from "../../_deps/asserts.ts";
import { polkadotBeacon } from "../../known/mod.ts";
import * as rpc from "../../rpc/mod.ts";

const client = await rpc.client(rpc.beacon(polkadotBeacon));
const client = await rpc.client(polkadotBeacon);
assert(!(client instanceof Error));
const stop = await client.subscribe("chain_subscribeAllHeads", [], (message) => {
console.log(message.params.result);
Expand Down
2 changes: 1 addition & 1 deletion examples/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as rpc from "../rpc/mod.ts";
import * as U from "../util/mod.ts";

const [client, sr25519, hashers] = await Promise.all([
rpc.client(rpc.beacon(westendBeacon)),
rpc.client(westendBeacon),
Sr25519(),
Hashers(),
]);
Expand Down
41 changes: 13 additions & 28 deletions known/beacons.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,13 @@
import { EnsureLookup } from "../util/types.ts";
import { LOOKUP } from "./generated.ts";

export type EnsureKnownLookup<
T,
L extends { [N in keyof LOOKUP]: T },
> = EnsureLookup<keyof LOOKUP, T, L>;

export const ACALA_PROXY_WS_URL = "wss://acala-polkadot.api.onfinality.io/public-ws";
export const acalaBeacon = [ACALA_PROXY_WS_URL] as const;

export const KUSAMA_PROXY_WS_URL = "wss://kusama-rpc.polkadot.io";
export const kusamaBeacon = [KUSAMA_PROXY_WS_URL] as const;

export const MOONBEAM_PROXY_WS_URL = "wss://wss.api.moonbeam.network";
export const moonbeamBeacon = [MOONBEAM_PROXY_WS_URL] as const;

export const POLKADOT_PROXY_WS_URL = "wss://rpc.polkadot.io";
export const polkadotBeacon = [POLKADOT_PROXY_WS_URL] as const;

export const STATEMINT_PROXY_WS_URL = "wss://statemint-rpc.polkadot.io";
export const statemintBeacon = [STATEMINT_PROXY_WS_URL] as const;

export const SUBSOCIAL_PROXY_WS_URL = "wss://para.subsocial.network";
export const subsocialBeacon = [SUBSOCIAL_PROXY_WS_URL] as const;

export const WESTEND_PROXY_WS_URL = "wss://westend-rpc.polkadot.io";
export const westendBeacon = [WESTEND_PROXY_WS_URL] as const;
import { beacon } from "../rpc/mod.ts";
import { KnownRpcMethods } from "./methods.ts";

// TODO: swap out `KnownRpcMethods` with narrowed lookups
export const acalaBeacon = beacon<KnownRpcMethods>(
"wss://acala-polkadot.api.onfinality.io/public-ws",
);
export const kusamaBeacon = beacon<KnownRpcMethods>("wss://kusama-rpc.polkadot.io");
export const moonbeamBeacon = beacon<KnownRpcMethods>("wss://wss.api.moonbeam.network");
export const polkadotBeacon = beacon<KnownRpcMethods>("wss://rpc.polkadot.io");
export const statemintBeacon = beacon<KnownRpcMethods>("wss://statemint-rpc.polkadot.io");
export const subsocialBeacon = beacon<KnownRpcMethods>("wss://para.subsocial.network");
export const westendBeacon = beacon<KnownRpcMethods>("wss://westend-rpc.polkadot.io");
12 changes: 0 additions & 12 deletions known/mod.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
import { Branded } from "../util/mod.ts";

// TODO: narrowly type the template literal of `ProxyWsUrlBeacon`
declare const _proxyWsUrl: unique symbol;
export type ProxyWsUrl = Branded<`wss://${string}`, typeof _proxyWsUrl>;

// TODO: use branded type to represent validated chain spec string
declare const _chainSpec: unique symbol;
export type ChainSpec = Branded<string, typeof _proxyWsUrl>;

export type Beacon = ProxyWsUrl | ChainSpec;

export * from "./beacons.ts";
export * from "./generated.ts";
export * from "./methods.ts";
16 changes: 13 additions & 3 deletions rpc/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ export type Subscription<NotificationResult = any> = { [_N]: NotificationResult

export interface ClientProps<
M extends AnyMethods,
Beacon,
DiscoveryValue,
ParsedError extends Error,
> {
beacon: Beacon;
discoveryValue: DiscoveryValue;
hooks?: {
send?: (message: InitMessage<M>) => void;
receive?: (message: IngressMessage<M>) => void;
Expand Down Expand Up @@ -51,7 +51,17 @@ export abstract class Client<
*
* @param egressMessage the message you wish to send to the RPC server
*/
abstract send: (egressMessage: InitMessage<M>) => void;
send = (egressMessage: InitMessage<M>): void => {
this.props.hooks?.send?.(egressMessage);
this._send(egressMessage);
};

/**
* The provider-specific send implementation
*
* @param egressMessage the message you wish to send to the RPC server
*/
abstract _send: (egressMessage: InitMessage<M>) => void;

/**
* Parse messages returned from the RPC server (this includes RPC server errors)
Expand Down
17 changes: 17 additions & 0 deletions rpc/Beacon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as rpc from "../rpc/mod.ts";

export type DiscoveryValues = [string, ...string[]];

declare const _M: unique symbol;

export class Beacon<M extends rpc.AnyMethods> {
declare [_M]: M;
discoveryValues;

constructor(...discoveryValues: DiscoveryValues) {
this.discoveryValues = discoveryValues;
}
}
export function beacon<M extends rpc.AnyMethods>(...discoveryValues: DiscoveryValues): Beacon<M> {
return new Beacon(...discoveryValues);
}
58 changes: 21 additions & 37 deletions rpc/auto.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,35 @@
import { ErrorCtor } from "../util/mod.ts";
import { ErrorCtor, isWsUrl } from "../util/mod.ts";
import { AnyMethods } from "./Base.ts";
import { Beacon } from "./Beacon.ts";
import { FailedToAddChainError, FailedToStartSmoldotError, SmoldotClient } from "./smoldot.ts";
import { FailedToOpenConnectionError, ProxyWsUrlClient } from "./ws.ts";

type DiscoveryValues = readonly [string, ...string[]];
// TODO: replace with better branded types
type Beacon<M extends AnyMethods> = DiscoveryValues & { _beacon: { supported: M } };
export function beacon<Supported extends AnyMethods>(
discoveryValues: DiscoveryValues,
): Beacon<Supported> {
return discoveryValues as Beacon<Supported>;
}

// TODO: use branded beacon types instead of string
// TODO: dyn import smoldot and provider if chain spec is provided
// TODO: handle retry
// TODO: narrow to `[string, ...string[]]`
export async function client<M extends AnyMethods>(beacon: Beacon<M>): Promise<
export async function client<M extends AnyMethods>(
beacon: Beacon<M>,
currentDiscoveryValueI = 0,
): Promise<
| SmoldotClient<M>
| ProxyWsUrlClient<M>
| FailedToOpenConnectionError
| FailedToStartSmoldotError
| FailedToAddChainError
| AllBeaconsErroredError
| BeaconFailedError
> {
const [e0, ...rest] = beacon;
const result = await (async () => {
if (isWsUrl(e0)) {
return ProxyWsUrlClient.open({ beacon: e0 });
} else {
return SmoldotClient.open({ beacon: e0 });
}
})();
if (result instanceof Error) {
if (rest.length > 0) {
return await client(rest as unknown as Beacon<M>);
const currentDiscoveryValue = beacon.discoveryValues[currentDiscoveryValueI];
if (currentDiscoveryValue) {
const result = await (async () => {
if (isWsUrl(currentDiscoveryValue)) {
return ProxyWsUrlClient.open<M>({ discoveryValue: currentDiscoveryValue });
} else {
return SmoldotClient.open<M>({ discoveryValue: currentDiscoveryValue });
}
})();
if (result instanceof Error) {
return await client(beacon, currentDiscoveryValueI + 1);
}
return new AllBeaconsErroredError();
return result;
}
// TODO: fix
return result as any;
}

// TODO: validate chain spec as well
// TODO: better validation
function isWsUrl(inQuestion: string): boolean {
return inQuestion.startsWith("wss://");
return new BeaconFailedError();
}

export class AllBeaconsErroredError extends ErrorCtor("AllBeaconsErrored") {}
export class BeaconFailedError extends ErrorCtor("AllBeaconsErrored") {}
1 change: 1 addition & 0 deletions rpc/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type AnyClient = ProxyWsUrlClient<AnyMethods> | SmoldotClient<AnyMethods>

export * from "./auto.ts";
export * from "./Base.ts";
export * from "./Beacon.ts";
export * from "./messages.ts";
export * from "./smoldot.ts";
export * from "./ws.ts";
4 changes: 2 additions & 2 deletions rpc/smoldot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class SmoldotClient<M extends B.AnyMethods>
const client = new SmoldotClient(props);
// TODO: wire up `onError`
client.#chain = await inner.addChain({
chainSpec: props.beacon,
chainSpec: props.discoveryValue,
jsonRpcCallback: client.onMessage,
});
return client;
Expand All @@ -55,7 +55,7 @@ export class SmoldotClient<M extends B.AnyMethods>
}
};

send = (egressMessage: InitMessage<M>): void => {
_send = (egressMessage: InitMessage<M>): void => {
this.#chain?.sendJsonRpc(JSON.stringify(egressMessage));
};

Expand Down
4 changes: 2 additions & 2 deletions rpc/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class ProxyWsUrlClient<M extends B.AnyMethods>
props: B.ClientProps<M, string, WebSocketInternalError>,
): Promise<ProxyWsUrlClient<M> | FailedToOpenConnectionError> => {
const client = new ProxyWsUrlClient(props);
const ws = new WebSocket(props.beacon);
const ws = new WebSocket(props.discoveryValue);
client.#ws = ws;
ws.addEventListener("error", client.onError);
ws.addEventListener("message", client.onMessage);
Expand Down Expand Up @@ -60,7 +60,7 @@ export class ProxyWsUrlClient<M extends B.AnyMethods>
return pending;
};

send = (egressMessage: InitMessage<M>): void => {
_send = (egressMessage: InitMessage<M>): void => {
this.#ws?.send(JSON.stringify(egressMessage));
};

Expand Down
6 changes: 6 additions & 0 deletions util/discovery_value_validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// TODO: validate chain spec as well
// TODO: better ws validation

export function isWsUrl(inQuestion: string): boolean {
return inQuestion.startsWith("wss://");
}
File renamed without changes.
2 changes: 1 addition & 1 deletion util/mod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from "./branded.ts";
export * from "./discovery_value_validation.ts";
export * from "./ErrorCtor.ts";
export * from "./fn.ts";
export * as hex from "./hex.ts";
export * from "./load_env.ts";
export * from "./types.ts";

0 comments on commit ed5d3e1

Please sign in to comment.