@polkadot-api/cli 0.0.1-0a3edb2e805b29fa7d3ebb02c2084a125c4ee78b.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/metadata.scale +0 -0
- package/out.txt +42 -0
- package/package.json +39 -0
- package/src/CheckboxData.ts +38 -0
- package/src/ExtrinsicData.ts +119 -0
- package/src/_polyfills.ts +3 -0
- package/src/deferred.ts +48 -0
- package/src/descriptor-schema.ts +19 -0
- package/src/guards.ts +20 -0
- package/src/main.ts +839 -0
- package/src/metadata.ts +140 -0
- package/src/smolldot-worker.ts +42 -0
- package/src/testing.ts +32 -0
- package/tsconfig-build.json +4 -0
- package/tsconfig.json +12 -0
package/src/metadata.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { WellKnownChain } from "@substrate/connect"
|
|
2
|
+
import { createClient } from "@polkadot-api/substrate-client"
|
|
3
|
+
import { GetProvider } from "@polkadot-api/json-rpc-provider"
|
|
4
|
+
import { deferred } from "./deferred"
|
|
5
|
+
import { fromHex } from "@polkadot-api/utils"
|
|
6
|
+
import * as fs from "node:fs/promises"
|
|
7
|
+
import {
|
|
8
|
+
metadata as $metadata,
|
|
9
|
+
CodecType,
|
|
10
|
+
OpaqueCodec,
|
|
11
|
+
} from "@polkadot-api/substrate-bindings"
|
|
12
|
+
import { PROVIDER_WORKER_CODE } from "./smolldot-worker"
|
|
13
|
+
import { Worker } from "node:worker_threads"
|
|
14
|
+
import { Subject } from "rxjs"
|
|
15
|
+
import { z } from "zod"
|
|
16
|
+
|
|
17
|
+
type Metadata = ReturnType<typeof $metadata.dec>["metadata"]
|
|
18
|
+
|
|
19
|
+
async function getChainMetadata(chain: WellKnownChain): Promise<Uint8Array> {
|
|
20
|
+
const worker = new Worker(PROVIDER_WORKER_CODE, {
|
|
21
|
+
eval: true,
|
|
22
|
+
workerData: chain,
|
|
23
|
+
stderr: true,
|
|
24
|
+
stdout: true,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const onMsgSubject = new Subject<string>()
|
|
28
|
+
const onStatusSubject = new Subject<0 | 1 | 2>()
|
|
29
|
+
|
|
30
|
+
const msgSchema = z.discriminatedUnion("type", [
|
|
31
|
+
z.object({ type: z.literal("message"), value: z.string() }),
|
|
32
|
+
z.object({
|
|
33
|
+
type: z.literal("status"),
|
|
34
|
+
value: z.union([z.literal(0), z.literal(1), z.literal(2)]),
|
|
35
|
+
}),
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
worker.on("message", (msg) => {
|
|
39
|
+
const parsedMsg = msgSchema.parse(msg)
|
|
40
|
+
switch (parsedMsg.type) {
|
|
41
|
+
case "message":
|
|
42
|
+
onMsgSubject.next(parsedMsg.value)
|
|
43
|
+
break
|
|
44
|
+
case "status":
|
|
45
|
+
onStatusSubject.next(parsedMsg.value)
|
|
46
|
+
break
|
|
47
|
+
default:
|
|
48
|
+
break
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const provider: GetProvider = (onMsg, onStatus) => {
|
|
53
|
+
onMsgSubject.subscribe((msg) => onMsg(msg))
|
|
54
|
+
onStatusSubject.subscribe((status) => onStatus(status))
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
send: (msg) => worker.postMessage({ type: "send", value: msg }),
|
|
58
|
+
open: () => worker.postMessage({ type: "open" }),
|
|
59
|
+
close: () => worker.postMessage({ type: "close" }),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { chainHead } = createClient(provider)
|
|
64
|
+
|
|
65
|
+
const blockHashDeferred = deferred<string>()
|
|
66
|
+
const chainHeadFollower = chainHead(
|
|
67
|
+
true,
|
|
68
|
+
(event) => {
|
|
69
|
+
switch (event.event) {
|
|
70
|
+
case "finalized":
|
|
71
|
+
blockHashDeferred.resolve(
|
|
72
|
+
event.finalizedBlockHashes[event.finalizedBlockHashes.length - 1],
|
|
73
|
+
)
|
|
74
|
+
break
|
|
75
|
+
default:
|
|
76
|
+
break
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
console.error,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
const blockHash = await blockHashDeferred
|
|
83
|
+
|
|
84
|
+
const metadata = fromHex(
|
|
85
|
+
await chainHeadFollower.call(blockHash, "Metadata_metadata", ""),
|
|
86
|
+
)
|
|
87
|
+
chainHeadFollower.unfollow()
|
|
88
|
+
await worker.terminate()
|
|
89
|
+
|
|
90
|
+
return metadata
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type GetMetadataArgs =
|
|
94
|
+
| {
|
|
95
|
+
source: "chain"
|
|
96
|
+
chain: WellKnownChain
|
|
97
|
+
}
|
|
98
|
+
| {
|
|
99
|
+
source: "file"
|
|
100
|
+
file: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function getRawMetadata(args: GetMetadataArgs): Promise<Uint8Array> {
|
|
104
|
+
switch (args.source) {
|
|
105
|
+
case "chain": {
|
|
106
|
+
return getChainMetadata(args.chain)
|
|
107
|
+
}
|
|
108
|
+
case "file": {
|
|
109
|
+
return fs.readFile(args.file)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function getMetadata(args: GetMetadataArgs) {
|
|
115
|
+
const rawMetadata = await getRawMetadata(args)
|
|
116
|
+
const { inner } = OpaqueCodec($metadata).dec(rawMetadata)
|
|
117
|
+
|
|
118
|
+
const { magicNumber, metadata } = inner()
|
|
119
|
+
|
|
120
|
+
assertIsv14(metadata)
|
|
121
|
+
|
|
122
|
+
return { magicNumber, metadata }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function encodeMetadata(metadata: CodecType<typeof $metadata>) {
|
|
126
|
+
const encodedMetadata = $metadata.enc(metadata)
|
|
127
|
+
|
|
128
|
+
return OpaqueCodec($metadata).enc({
|
|
129
|
+
length: encodedMetadata.length,
|
|
130
|
+
inner: () => metadata,
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function assertIsv14(
|
|
135
|
+
metadata: Metadata,
|
|
136
|
+
): asserts metadata is Metadata & { tag: "v14" } {
|
|
137
|
+
if (metadata.tag !== "v14") {
|
|
138
|
+
throw new Error("unreachable")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const PROVIDER_WORKER_CODE = `
|
|
2
|
+
const { parentPort, workerData } = require("node:worker_threads")
|
|
3
|
+
const { ScProvider } = require("@polkadot-api/sc-provider")
|
|
4
|
+
const { z } = require("zod")
|
|
5
|
+
|
|
6
|
+
const msgSchema = z.discriminatedUnion("type", [
|
|
7
|
+
z.object({ type: z.literal("send"), value: z.string() }),
|
|
8
|
+
z.object({
|
|
9
|
+
type: z.literal("open"),
|
|
10
|
+
}),
|
|
11
|
+
z.object({
|
|
12
|
+
type: z.literal("close"),
|
|
13
|
+
}),
|
|
14
|
+
])
|
|
15
|
+
|
|
16
|
+
const chain = workerData
|
|
17
|
+
const getProvider = ScProvider(chain)
|
|
18
|
+
|
|
19
|
+
if (!parentPort) {
|
|
20
|
+
throw new Error("no parent port")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const provider = getProvider(
|
|
24
|
+
(msg) => parentPort.postMessage({ type: "message", value: msg }),
|
|
25
|
+
(status) => parentPort.postMessage({ type: "status", value: status }),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
parentPort.on("message", (msg) => {
|
|
29
|
+
const parsedMsg = msgSchema.parse(msg)
|
|
30
|
+
switch (parsedMsg.type) {
|
|
31
|
+
case "send":
|
|
32
|
+
provider.send(parsedMsg.value)
|
|
33
|
+
break
|
|
34
|
+
case "open":
|
|
35
|
+
provider.open()
|
|
36
|
+
break
|
|
37
|
+
case "close":
|
|
38
|
+
provider.close()
|
|
39
|
+
break
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
`
|
package/src/testing.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getMetadata } from "./metadata"
|
|
2
|
+
import type { AsyncReturnType } from "type-fest"
|
|
3
|
+
|
|
4
|
+
export function blowupMetadata(
|
|
5
|
+
metadata: AsyncReturnType<typeof getMetadata>["metadata"],
|
|
6
|
+
) {
|
|
7
|
+
const { pallets, lookup } = metadata.value
|
|
8
|
+
|
|
9
|
+
for (const pallet of pallets) {
|
|
10
|
+
popRandom(pallet.constants)
|
|
11
|
+
popRandom(pallet.storage?.items ?? [])
|
|
12
|
+
|
|
13
|
+
const events = lookup.find((l) => l.id == pallet.events)
|
|
14
|
+
if (events?.def.tag === "variant") {
|
|
15
|
+
popRandom(events.def.value)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const errors = lookup.find((l) => l.id == pallet.errors)
|
|
19
|
+
if (errors?.def.tag === "variant") {
|
|
20
|
+
popRandom(errors.def.value)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const calls = lookup.find((l) => l.id == pallet.calls)
|
|
24
|
+
if (calls?.def.tag === "variant") {
|
|
25
|
+
popRandom(calls.def.value)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function popRandom<A>(arr: A[]) {
|
|
31
|
+
arr.splice(Math.floor(Math.random() * arr.length), 1)
|
|
32
|
+
}
|