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

Commit

Permalink
feat: net "targets" (aka. served connection swapping) (#983)
Browse files Browse the repository at this point in the history
Co-authored-by: T6 <[email protected]>
Co-authored-by: Matias Volpe <[email protected]>
  • Loading branch information
3 people authored May 15, 2023
1 parent cae412f commit cd9cffd
Show file tree
Hide file tree
Showing 21 changed files with 104 additions and 105 deletions.
34 changes: 13 additions & 21 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@ import { bins, net } from "capi"

const bin = bins({ polkadot: ["polkadot", "v0.9.38"] })

// The Polkadot relay chain
export const polkadot = net.ws({ url: "wss://rpc.polkadot.io/" })

// A Polkadot development network
export const polkadotDev = net.dev({
bin: bin.polkadot,
chain: "polkadot-dev",
})

// The Polkadot relay chain
export const polkadot = net.ws({
url: "wss://rpc.polkadot.io/",
targets: { dev: polkadotDev },
})
```

## Command Line Tool
Expand Down Expand Up @@ -100,30 +103,19 @@ const accounts = await polkadot.System.Account.entries({ count: 10 }).run()

## Development Networks

Let's modify the usage above to target our configured devnet.

```diff
- import { polkadot } from "@capi/polkadot"
+ import { polkadotDev } from "@capi/polkadot-dev"

- const accounts = await polkadot.System.Account
+ const accounts = await polkadotDev.System.Account
.entries({ count: 10 })
.run()
```

To run code that depends on a devnet, use the `serve` command, followed by a
"--" and your devnet-using command. In this case, we'll run the script
(`main.js`) with Node.JS.
During development, we may want to swap out the underlying connection with that
of a devnet. This can be achieved via targets — by specifying alternate targets
in your `nets.ts` file, you can switch to them by wrapping your command with
`capi serve --target someTarget --`. For example:

```sh
capi serve -- node main.js
capi serve --target dev -- node main.js
```

> Other examples:
>
> - `capi serve -- npm run start`
> - `capi serve -- deno run -A ./main.ts`
> - `capi serve --target dev -- npm run start`
> - `capi serve --target dev -- deno run -A ./main.ts`
## Running Examples

Expand Down
2 changes: 1 addition & 1 deletion _tasks/use_remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ if (await isUploaded(capiServer, codegenHash)) {
console.log("codegen already uploaded")
} else {
console.log("uploading codegen")
await syncNets("https://capi.dev/", "target/capi", await resolveNets())
await syncNets(capiServer, "target/capi", await resolveNets())
}

async function isUploaded(server: string, hash: string) {
Expand Down
5 changes: 3 additions & 2 deletions cli/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { tempDir } from "../util/tempDir.ts"
import { resolveNets } from "./resolveNets.ts"

export default async function(...args: string[]) {
const { port, "--": cmd, out } = flags.parse(args, {
string: ["port", "out"],
const { port, "--": cmd, out, target } = flags.parse(args, {
string: ["port", "out", "target"],
default: {
port: "4646",
out: "target/capi",
Expand Down Expand Up @@ -77,6 +77,7 @@ export default async function(...args: string[]) {
signal,
env: {
CAPI_SERVER: href,
...target ? { CAPI_TARGET: target } : {},
},
})
const status = await command.spawn().status
Expand Down
4 changes: 2 additions & 2 deletions dprint.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
],
"plugins": [
"https://plugins.dprint.dev/dockerfile-0.3.0.wasm",
"https://plugins.dprint.dev/json-0.17.0.wasm",
"https://plugins.dprint.dev/json-0.17.2.wasm",
"https://plugins.dprint.dev/markdown-0.15.2.wasm",
"https://plugins.dprint.dev/toml-0.5.4.wasm",
"https://plugins.dprint.dev/typescript-0.80.2.wasm"
"https://plugins.dprint.dev/typescript-0.84.4.wasm"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @description utilize a raw connection to interact with an RPC node
*/

import { $, hex, WsConnection } from "capi"
import { $, WsConnection } from "capi"

/// The connection's life will be bound to the following controller.
const controller = new AbortController()
Expand All @@ -13,17 +13,12 @@ const { signal } = controller
/// Open the connection.
const connection = WsConnection.connect("wss://rpc.polkadot.io/", signal)

/// Use the connection to retrieve the raw FRAME metadata.
const { result } = await connection.call("state_getMetadata", [])
/// Use the connection to call the `system_version` RPC method.
const { result } = await connection.call("system_version", [])

/// Ensure the result is a string.
console.log(result)
$.assert($.str, result)

/// Dispose of the connection.
controller.abort()

/// Write the metadata to a a file for later use.
await Deno.writeFile(
new URL("./metadata", import.meta.url),
hex.decode(result),
)
Binary file removed examples/raw_rpc/metadata
Binary file not shown.
2 changes: 1 addition & 1 deletion import_map.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"imports": {
"@capi/": "http://localhost:4646/c203f477e2a88c37/"
"@capi/": "http://localhost:4646/a6371dd9c3e070f3/"
},
"scopes": {
"examples/": {
Expand Down
4 changes: 0 additions & 4 deletions nets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,3 @@ export const rococoDevXcmStatemine = rococoDevXcm.parachain({
chain: "statemine-local",
id: 1000,
})

export const polkadotFromMetadata = net.metadata({
metadata: await Deno.readFile("examples/raw_rpc/metadata"),
})
6 changes: 3 additions & 3 deletions nets/DevNetSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { getFreePort, portReady } from "../util/port.ts"
import { BinaryResolver } from "./bins.ts"
import { createRawChainSpec } from "./chain_spec/mod.ts"
import type { DevRelaySpec } from "./DevRelaySpec.ts"
import { getMetadataFromWsUrl, NetSpec } from "./NetSpec.ts"
import { getMetadataFromWsUrl, NetProps, NetSpec } from "./NetSpec.ts"

export interface DevNetProps {
export interface DevNetProps extends NetProps {
bin: BinaryResolver
chain: string
nodeCount?: number
Expand All @@ -23,7 +23,7 @@ export abstract class DevNetSpec extends NetSpec {
readonly nodeCount
readonly customize
constructor(props: DevNetProps) {
super()
super(props)
this.binary = props.bin
this.chain = props.chain
this.nodeCount = props.nodeCount
Expand Down
21 changes: 0 additions & 21 deletions nets/MetadataNetSpec.ts

This file was deleted.

13 changes: 11 additions & 2 deletions nets/NetSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ import * as $ from "../deps/scale.ts"
import { WsConnection } from "../rpc/mod.ts"
import { withSignal } from "../util/mod.ts"

export abstract class NetSpec {
export interface NetProps {
targets?: Record<string, NetSpec>
}

export abstract class NetSpec implements NetProps {
name!: string // set by `resolveNets.ts`
targets

abstract connection(name: string): ConnectionSpec | undefined
abstract connection(name: string): ConnectionSpec
abstract metadata(signal: AbortSignal, tempDir: string): Promise<Uint8Array>

constructor({ targets }: NetProps) {
this.targets = targets
}
}

export function getMetadataFromWsUrl(url: string) {
Expand Down
6 changes: 3 additions & 3 deletions nets/WsNetSpec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getMetadataFromWsUrl, NetSpec } from "./NetSpec.ts"
import { getMetadataFromWsUrl, NetProps, NetSpec } from "./NetSpec.ts"

export interface WsNetProps {
export interface WsNetProps extends NetProps {
url: string
version?: string
}
Expand All @@ -9,7 +9,7 @@ export class WsNetSpec extends NetSpec {
readonly url
readonly version
constructor(props: WsNetProps) {
super()
super(props)
this.url = props.url
this.version = props.version ?? "latest"
}
Expand Down
5 changes: 0 additions & 5 deletions nets/mod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DevNetProps } from "./DevNetSpec.ts"
import { DevRelaySpec } from "./DevRelaySpec.ts"
import { MetadataNetProps, MetadataNetSpec } from "./MetadataNetSpec.ts"
import { WsNetProps, WsNetSpec } from "./WsNetSpec.ts"

export namespace net {
Expand All @@ -10,9 +9,6 @@ export namespace net {
export function ws(props: WsNetProps) {
return new WsNetSpec(props)
}
export function metadata(props: MetadataNetProps) {
return new MetadataNetSpec(props)
}
}

// moderate
Expand All @@ -22,6 +18,5 @@ export * from "./chain_spec/mod.ts"
export * from "./DevNetSpec.ts"
export * from "./DevParachainSpec.ts"
export * from "./DevRelaySpec.ts"
export * from "./MetadataNetSpec.ts"
export * from "./NetSpec.ts"
export * from "./WsNetSpec.ts"
4 changes: 3 additions & 1 deletion rpc/Connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export abstract class Connection {
static bind<D>(
this: new(discovery: D) => Connection,
discovery: D,
): (signal: AbortSignal) => Connection {
): Connect {
return (signal) => (Connection.connect<D>).call(this, discovery, signal)
}

Expand Down Expand Up @@ -111,3 +111,5 @@ export abstract class Connection {
}
}
}

export type Connect = (signal: AbortSignal) => Connection
2 changes: 1 addition & 1 deletion rune/ValueRune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Access<T, K extends keyof T, _K = NonIndexSignatureKeys<T>> = [
/** @ts-ignore: assume it's a valid key */
type GetPath<T, P> = P extends [infer K, ...infer Q] ? GetPath<T[K], Q> : T

type EnsurePath<T, P> = never extends P ? P extends [infer K, ...infer Q] ?
type EnsurePath<T, P> = never extends P ? P extends [infer K, ...infer Q] ?
| [K & keyof T, ...EnsurePath<T[K & keyof T], Q>]
| [keyof T, ...PropertyKey[]]
: [(keyof T)?]
Expand Down
3 changes: 2 additions & 1 deletion server/CodegenSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const $codegenEntry = $.taggedUnion("type", [
"frame",
$.field("metadataHash", $.sizedUint8Array(64)),
$.field("chainName", $.str),
$.optionalField("connection", $connectionSpec),
$.field("connection", $connectionSpec),
$.optionalField("targets", $.record($connectionSpec)),
),
])

Expand Down
5 changes: 4 additions & 1 deletion server/capi.dev/delegator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ async function github<T>(url: string): Promise<T> {
Authorization: `token ${githubToken}`,
},
})
if (!response.ok) throw new Error(`${url}: invalid response`)
if (!response.ok) {
console.error(await response.text())
throw new Error(`${url}: invalid response`)
}
return await response.json()
}

Expand Down
21 changes: 21 additions & 0 deletions server/client/detectConnect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ConnectionSpec } from "../../nets/mod.ts"
import { Connect, WsConnection } from "../../rpc/mod.ts"
import { DevnetConnection } from "./DevnetConnection.ts"

export function detectConnect(
defaultConnectionSpec: ConnectionSpec,
targets: Record<string, ConnectionSpec>,
): Connect {
let connectionSpec = defaultConnectionSpec
const targetName = Deno.env.get("CAPI_TARGET")
if (targetName) {
const target = targets[targetName]
if (target) connectionSpec = target
}
switch (connectionSpec.type) {
case "WsConnection":
return WsConnection.bind(connectionSpec.discovery)
case "DevnetConnection":
return DevnetConnection.bind(connectionSpec.discovery)
}
}
1 change: 1 addition & 0 deletions server/client/mod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// moderate

export * from "./createDevUsers.ts"
export * from "./detectConnect.ts"
export * from "./detectServer.ts"
export * from "./DevnetConnection.ts"
export * from "./syncNets.ts"
13 changes: 12 additions & 1 deletion server/client/syncNets.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { blake2_512, blake2_64, Hasher, hex } from "../../crypto/mod.ts"
import { mapEntries } from "../../deps/std/collections/map_entries.ts"
import { gray, green } from "../../deps/std/fmt/colors.ts"
import { NetSpec } from "../../nets/mod.ts"
import { normalizePackageName, normalizeTypeName, withSignal } from "../../util/mod.ts"
Expand All @@ -24,7 +25,17 @@ export async function syncNets(
`@capi/${packageName}`,
)
const connection = netSpec.connection(name)
return [packageName, { type: "frame", metadataHash, chainName, connection }]
const targets = mapEntries(
netSpec.targets ?? {},
([targetName, targetNet]) => [targetName, targetNet.connection(targetNet.name)],
)
return [packageName, {
type: "frame",
metadataHash,
chainName,
connection,
targets,
}]
}),
)
const sortedEntries = new Map([...entries].sort((a, b) => a[0] < b[0] ? 1 : -1))
Expand Down
Loading

0 comments on commit cd9cffd

Please sign in to comment.