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

chore: rewrite RPC system #591

Merged
merged 23 commits into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions _tasks/download_frame_metadata.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { rawClient as kusama } from "kusama/client.ts"
import { rawClient as polkadot } from "polkadot/client.ts"
import { rawClient as rococo } from "rococo/client.ts"
import { rawClient as westend } from "westend/client.ts"
import { chain as kusama } from "kusama/mod.ts"
import { chain as polkadot } from "polkadot/mod.ts"
import { chain as rococo } from "rococo/mod.ts"
import { chain as westend } from "westend/mod.ts"

const knownClients = { kusama, polkadot, westend, rococo }
const knownChains = { kusama, polkadot, westend, rococo }

const names = Object.keys(knownClients)
const names = Object.keys(knownChains)
const outDir = new URL("../frame_metadata/_downloaded", import.meta.url)
try {
Deno.removeSync(outDir, { recursive: true })
Expand Down Expand Up @@ -33,13 +33,10 @@ async function download(name: string) {
Deno.writeTextFileSync(modFilePath, modFileContents, { create: true })

await Promise.all(
Object.entries(knownClients).map(async ([name, client]) => {
const r = await client.call(name, "state_getMetadata", [])
if (r instanceof Error) throw r
if (r.error) throw new Error(r.error.message)
Object.entries(knownChains).map(async ([name, chain]) => {
const result = await chain.connection.call("state_getMetadata").run()
const outPath = new URL(`_downloaded/${name}.scale`, outDir)
console.log(`Downloading ${name} metadata to "${outPath}".`)
await Deno.writeTextFile(outPath, r.result)
await client.discard()
await Deno.writeTextFile(outPath, result)
}),
)
12 changes: 6 additions & 6 deletions codegen/frame/FrameCodegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import { typeVisitor } from "./typeVisitor.ts"

export interface FrameCodegenProps {
metadata: Metadata
clientFile: File
chainFile: File
}

export class FrameCodegen {
files = new Map<string, File>()

metadata
clientFile
chainFile

typeVisitor
typeFiles = new Map<string, TypeFile>()

constructor({ metadata, clientFile }: FrameCodegenProps) {
constructor({ metadata, chainFile }: FrameCodegenProps) {
this.metadata = metadata
this.clientFile = clientFile
this.chainFile = chainFile

this.typeVisitor = typeVisitor(this)

Expand All @@ -33,7 +33,7 @@ export class FrameCodegen {

this.files.set("codecs.ts", codecs(this))

this.files.set("client.ts", clientFile)
this.files.set("chain.ts", chainFile)

const callTy = Object
.fromEntries(this.metadata.extrinsic.ty.params.map((x) => [x.name.toLowerCase(), x.ty]))
Expand All @@ -60,7 +60,7 @@ export class FrameCodegen {
this.typeVisitor.visit(eventTy)
}>

export * from "./client.ts"
export * from "./chain.ts"
export * as types from "./types/mod.ts"

${palletNamespaceExports}
Expand Down
6 changes: 3 additions & 3 deletions codegen/frame/pallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ export function pallet(ctx: FrameCodegen, pallet: Pallet) {
import * as codecs from "./codecs.ts"
import { $ } from "./capi.ts"
import * as C from "./capi.ts"
import { client } from "./client.ts"
import { chain } from "./chain.ts"
`]
for (const entry of pallet.storage?.entries ?? []) {
items.push(
makeDocComment(entry.docs)
+ `export const ${entry.name} = client.metadata()`
+ `export const ${entry.name} = chain.metadata()`
+ `.pallet(${S.string(pallet.name)})`
+ `.storage(${S.string(entry.name)})`
+ `["_asCodegenStorage"](${
Expand All @@ -39,7 +39,7 @@ export function pallet(ctx: FrameCodegen, pallet: Pallet) {
items.push(
makeDocComment(call.docs)
+ `export function ${type}<X>(...args: Parameters<typeof ${typeName}<X>>): C.ExtrinsicRune<C.RunicArgs.U<X>, Chain>`
+ `{ return client.extrinsic(C.Rune.rec({ type: ${
+ `{ return chain.extrinsic(C.Rune.rec({ type: ${
S.string(pallet.name)
}, value: ${typeName}(...args) })) }`,
)
Expand Down
4 changes: 2 additions & 2 deletions examples/block_author.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { babeBlockAuthor } from "capi/patterns/consensus/mod.ts"
import { client } from "polkadot/mod.ts"
import { chain } from "polkadot/mod.ts"

const result = await babeBlockAuthor(client, client.latestBlock.hash).run()
const result = await babeBlockAuthor(chain, chain.latestBlock.hash).run()

console.log(result)
4 changes: 2 additions & 2 deletions examples/block_events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { client } from "polkadot/mod.ts"
import { chain } from "polkadot/mod.ts"

const result = await client.latestBlock.events().run()
const result = await chain.latestBlock.events().run()

console.log(result)
4 changes: 2 additions & 2 deletions examples/block_extrinsics.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { client } from "polkadot/mod.ts"
import { chain } from "polkadot/mod.ts"

const result = await client.latestBlock.extrinsics().run()
const result = await chain.latestBlock.extrinsics().run()

console.log(result)
4 changes: 2 additions & 2 deletions examples/dynamic/balance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { alice } from "capi"
import { client } from "polkadot_dev/mod.ts"
import { chain } from "polkadot_dev/mod.ts"

const result = await client
const result = await chain
.metadata()
.pallet("System")
.storage("Account")
Expand Down
18 changes: 9 additions & 9 deletions examples/ink_e2e/main.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { AddressRune, alice } from "capi"
import { AddressRune, alice, Rune } from "capi"
import {
InkMetadataRune,
instantiationEventIntoPublicKey,
isInstantiatedEvent,
parse as parseMetadata,
} from "capi/patterns/ink/mod.ts"
import { client } from "zombienet/rococo_contracts.toml/collator/@latest/mod.ts"
import { chain } from "zombienet/rococo_contracts.toml/collator/@latest/mod.ts"
import { parse } from "../../deps/std/flags.ts"

export const metadata = InkMetadataRune.from(
client,
Deno.readTextFileSync("examples/ink_e2e/metadata.json"),
)
export const metadata = Rune
.resolve(parseMetadata(Deno.readTextFileSync("examples/ink_e2e/metadata.json")))
.into(InkMetadataRune, chain)

const sender = alice.publicKey

Expand All @@ -34,15 +34,15 @@ if (!address) {
)
.unhandle(FailedToFindContractInstantiatedError)
.pipe(instantiationEventIntoPublicKey)
.address(client)
.address(chain)
.run()
}
console.log(`Contract address: ${address}`)

const publicKey = AddressRune.from(address, client).publicKey()
const publicKey = Rune.resolve(address).into(AddressRune, chain).publicKey()
console.log("Contract public key:", await publicKey.run())

const contract = metadata.instance(client, publicKey)
const contract = metadata.instance(chain, publicKey)

console.log("Get:", await contract.call({ sender, method: "get" }).run())

Expand Down
4 changes: 2 additions & 2 deletions examples/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { client } from "polkadot_dev/mod.ts"
import { chain } from "polkadot_dev/mod.ts"

const result = await client.metadata().run()
const result = await chain.metadata().run()

console.log(result)
14 changes: 8 additions & 6 deletions examples/multisig_transfer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { alice, bob, charlie, dave, ValueRune } from "capi"
import { alice, bob, charlie, dave, Rune, ValueRune } from "capi"
import { MultisigRune } from "capi/patterns/MultisigRune.ts"
import { Balances, client, System } from "polkadot_dev/mod.ts"
import { Balances, chain, System } from "polkadot_dev/mod.ts"
// TODO: utilize type exposed from capi/patterns/MultisigRune.ts (when we enable client env specificity)
import { MultiAddress } from "polkadot_dev/types/sp_runtime/multiaddress.ts"

const multisig = MultisigRune.from(client, {
signatories: [alice.publicKey, bob.publicKey, charlie.publicKey],
threshold: 2,
})
const multisig = Rune
.constant({
signatories: [alice.publicKey, bob.publicKey, charlie.publicKey],
threshold: 2,
})
.into(MultisigRune, chain)

// Read dave's initial balance (to-be changed by the call)
console.log("Dave initial balance:", await System.Account.entry([dave.publicKey]).run())
Expand Down
4 changes: 2 additions & 2 deletions examples/watch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Rune } from "capi"
import { client, Timestamp } from "polkadot/mod.ts"
import { chain, Timestamp } from "polkadot/mod.ts"

const block = client.latestBlock
const block = chain.latestBlock
const extrinsics = block.extrinsics()
const events = block.events()
const now = Timestamp.Now.entry([], block.hash)
Expand Down
13 changes: 6 additions & 7 deletions examples/xcm_asset_teleportation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { alice, Rune } from "capi"
import { types, XcmPallet } from "zombienet/statemine.toml/alice/@latest/mod.ts"
import { Event as XcmPalletEvent } from "zombienet/statemine.toml/alice/@latest/types/pallet_xcm/pallet.ts"
import { RuntimeEvent as AliceRuntimeEvent } from "zombienet/statemine.toml/alice/@latest/types/rococo_runtime/mod.ts"
import { client, System } from "zombienet/statemine.toml/collator/@latest/mod.ts"
import { chain, System } from "zombienet/statemine.toml/collator/@latest/mod.ts"
import { Event as ParachainSystemEvent } from "zombienet/statemine.toml/collator/@latest/types/cumulus_pallet_parachain_system/pallet.ts"
import { RuntimeEvent as CollatorRuntimeEvent } from "zombienet/statemine.toml/collator/@latest/types/statemine_runtime.ts"

Expand Down Expand Up @@ -59,13 +59,12 @@ const initiatedEvent = XcmPallet
.log("Initiated event:")

const processedEvent = System.Events
.entry([], client.latestBlock.hash)
.entry([], chain.latestBlock.hash)
.map((events) =>
events
?.find((e) =>
CollatorRuntimeEvent.isParachainSystem(e.event)
&& ParachainSystemEvent.isDownwardMessagesProcessed(e.event.value)
)
events?.find((e) =>
CollatorRuntimeEvent.isParachainSystem(e.event)
&& ParachainSystemEvent.isDownwardMessagesProcessed(e.event.value)
)
)
.filter((event) => !!event)
.log("Processed events:")
Expand Down
11 changes: 3 additions & 8 deletions fluent/AddressRune.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import { Client } from "../rpc/mod.ts"
import { Rune, RunicArgs } from "../rune/mod.ts"
import { Rune } from "../rune/mod.ts"
import { ValueRune } from "../rune/ValueRune.ts"
import { ss58 } from "../util/mod.ts"
import { Chain, ClientRune } from "./ClientRune.ts"
import { Chain, ChainRune } from "./ChainRune.ts"
import { PublicKeyRune } from "./PublicKeyRune.ts"

export class AddressRune<out U, out C extends Chain = Chain> extends Rune<string, U> {
constructor(_prime: AddressRune<U>["_prime"], readonly client: ClientRune<U, C>) {
constructor(_prime: AddressRune<U>["_prime"], readonly chain: ChainRune<U, C>) {
super(_prime)
}

static from<X>(...[address, client]: RunicArgs<X, [address: string, client: Client]>) {
return Rune.resolve(address).into(AddressRune, Rune.resolve(client).into(ClientRune))
}

publicKey() {
return this
.into(ValueRune)
Expand Down
12 changes: 6 additions & 6 deletions fluent/BlockRune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { known } from "../rpc/mod.ts"
import { ArrayRune, Rune } from "../rune/mod.ts"
import { ValueRune } from "../rune/ValueRune.ts"
import { hex, HexHash } from "../util/mod.ts"
import { Chain, ClientRune } from "./ClientRune.ts"
import { Chain, ChainRune } from "./ChainRune.ts"
import { CodecRune } from "./CodecRune.ts"

export class BlockRune<out U, out C extends Chain = Chain> extends Rune<known.SignedBlock, U> {
constructor(
_prime: BlockRune<U, C>["_prime"],
readonly client: ClientRune<U, C>,
readonly chain: ChainRune<U, C>,
readonly hash: Rune<HexHash, U>,
) {
super(_prime)
Expand All @@ -24,7 +24,7 @@ export class BlockRune<out U, out C extends Chain = Chain> extends Rune<known.Si
}

extrinsics() {
const metadata = this.client.metadata()
const metadata = this.chain.metadata()
const $extrinsic = Rune
.rec({
metadata,
Expand All @@ -41,14 +41,14 @@ export class BlockRune<out U, out C extends Chain = Chain> extends Rune<known.Si
}

events() {
return this.client
return this.chain
.metadata()
.pallet("System")
.storage("Events")
.entry([], this.hash)
.unsafeAs<C["event"][] | undefined>()
.unsafeAs<Chain.Event<C>[] | undefined>()
.into(ValueRune)
.unhandle(undefined)
.rehandle(undefined, () => Rune.constant<C["event"][]>([]))
.rehandle(undefined, () => Rune.constant<Chain.Event<C>[]>([]))
}
}
70 changes: 70 additions & 0 deletions fluent/ChainRune.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as $ from "../deps/scale.ts"
import * as M from "../frame_metadata/mod.ts"
import { Event } from "../primitives/mod.ts"
import { Connection } from "../rpc/mod.ts"
import { Rune, RunicArgs, ValueRune } from "../rune/mod.ts"
import { HexHash } from "../util/mod.ts"
import { BlockRune } from "./BlockRune.ts"
import { ConnectionRune } from "./ConnectionRune.ts"
import { ExtrinsicRune } from "./ExtrinsicRune.ts"
import { MetadataRune } from "./MetadataRune.ts"

export interface Chain<C = any, E extends Event = any> {
connection: Connection
_call?: $.Codec<C>
_event?: $.Codec<E>
}

export namespace Chain {
export type Call<C extends Chain> = C extends Chain<infer Call, any> ? Call : never
export type Event<C extends Chain> = C extends Chain<any, infer Event> ? Event : never
}

// TODO: do we want to represent the discovery value and conn type within the type system?
export class ChainRune<out U, out C extends Chain = Chain> extends Rune<C, U> {
connection = this.into(ValueRune<Chain, U>).access("connection").into(ConnectionRune)

latestBlock = this.block(
this.connection
.call(
"chain_getBlockHash",
this.connection
.subscribe("chain_subscribeNewHeads", "chain_unsubscribeNewHeads")
.access("number"),
)
.unsafeAs<HexHash>(),
)

block<X>(...[blockHash]: RunicArgs<X, [blockHash: HexHash]>) {
return this.connection.call("chain_getBlock", blockHash)
.unhandle(null)
.into(BlockRune, this, Rune.resolve(blockHash))
}

metadata<X>(...[blockHash]: RunicArgs<X, [blockHash?: HexHash]>) {
return this.connection.call("state_getMetadata", blockHash)
.map(M.fromPrefixedHex)
.throws($.ScaleError)
.into(MetadataRune, this)
}

extrinsic<X>(...args: RunicArgs<X, [call: Chain.Call<C>]>) {
const [call] = RunicArgs.resolve(args)
return call.into(ExtrinsicRune, this.as(ChainRune))
}

addressPrefix() {
return this
.metadata()
.pallet("System")
.const("SS58Prefix")
.decoded
.unsafeAs<number>()
}

chainVersion = this.connection.call("system_version")

private _asCodegen<C extends Chain>() {
return this as any as ChainRune<U, C>
}
}
Loading