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

feat: const effect for decoding consts in the metadata #347

Merged
merged 1 commit into from
Nov 1, 2022
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
2 changes: 1 addition & 1 deletion codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ await codegen({

async function getMetadata(src: string): Promise<M.Metadata> {
if (src.startsWith("ws")) {
const client = U.throwIfError(await proxyClient(new Config(() => src, undefined!)));
const client = U.throwIfError(await proxyClient(new Config(() => src)));
const metadata = U.throwIfError(await client.call("state_getMetadata", []));
U.throwIfError(await client.close());
if (metadata.error) fail();
Expand Down
5 changes: 1 addition & 4 deletions config/mod.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
export class Config<DiscoveryValue = any> {
#discoveryValue?: DiscoveryValue | Promise<DiscoveryValue>;

constructor(
readonly initDiscoveryValue: () => DiscoveryValue | Promise<DiscoveryValue>,
readonly addressPrefix: number,
) {}
constructor(readonly initDiscoveryValue: () => DiscoveryValue | Promise<DiscoveryValue>) {}

get discoveryValue() {
if (!this.#discoveryValue) {
Expand Down
32 changes: 32 additions & 0 deletions effects/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Config } from "../config/mod.ts";
import * as Z from "../deps/zones.ts";
import * as U from "../util/mod.ts";
import { codec } from "./core/codec.ts";
import { decoded } from "./core/decoded.ts";
import { deriveCodec } from "./core/deriveCodec.ts";
import { constMetadata, metadata, palletMetadata } from "./metadata.ts";

function const_<
PalletName extends Z.$<string>,
ConstName extends Z.$<string>,
Rest extends [blockHash?: Z.$<U.HexHash | undefined>],
>(
config: Config,
palletName: PalletName,
constName: ConstName,
...[blockHash]: [...Rest]
) {
const metadata_ = metadata(config, blockHash);
const deriveCodec_ = deriveCodec(metadata_);
const palletMetadata_ = palletMetadata(metadata_, palletName);
const constMetadata_ = constMetadata(palletMetadata_, constName);
const entryValueTypeI = constMetadata_.access("ty").access("id");
const constValue = constMetadata_.access("value");
const $const = codec(deriveCodec_, entryValueTypeI);
return decoded($const, constValue, "value");
}
Object.defineProperty(const_, "name", {
value: "const",
writable: false,
});
export { const_ as const };
5 changes: 2 additions & 3 deletions effects/core/decoded.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as $ from "../../deps/scale.ts";
import * as Z from "../../deps/zones.ts";
import * as U from "../../util/mod.ts";

export function decoded<
Codec extends Z.$<$.Codec<unknown>>,
Encoded extends Z.$<U.Hex>,
Encoded extends Z.$<Uint8Array>,
Key extends Z.$<string>,
>(
codec: Codec,
Expand All @@ -14,7 +13,7 @@ export function decoded<
return Z.call(
Z.ls(codec, encoded, key),
function decodedImpl([codec, encoded, key]): Record<Z.T<Key>, any> {
return { [key]: codec.decode(U.hex.decode(encoded)) } as any;
return { [key]: codec.decode(encoded) } as any;
},
);
}
5 changes: 3 additions & 2 deletions effects/entryRead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { $storageKey } from "./core/$storageKey.ts";
import { codec } from "./core/codec.ts";
import { decoded } from "./core/decoded.ts";
import { deriveCodec } from "./core/deriveCodec.ts";
import { hexDecode } from "./core/hex.ts";
import { storageKey } from "./core/storageKey.ts";
import { entryMetadata, metadata, palletMetadata } from "./metadata.ts";
import { rpcCall } from "./rpcCall.ts";
Expand All @@ -30,6 +31,6 @@ export function entryRead<
const storageCall = rpcCall(config, "state_getStorage", [storageKey_, blockHash]);
const entryValueTypeI = entryMetadata_.access("value");
const $entry = codec(deriveCodec_, entryValueTypeI);
const resultHex = storageCall.access("result");
return decoded($entry, resultHex, "value");
const result = storageCall.access("result");
return decoded($entry, hexDecode(result), "value");
}
33 changes: 20 additions & 13 deletions effects/extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Config } from "../mod.ts";
import { NotifMessage } from "../rpc/mod.ts";
import * as ss58 from "../ss58/mod.ts";
import * as U from "../util/mod.ts";
import { const as const_ } from "./const.ts";
import { $extrinsic } from "./core/$extrinsic.ts";
import { deriveCodec } from "./core/deriveCodec.ts";
import { hexDecode } from "./core/hex.ts";
Expand Down Expand Up @@ -49,21 +50,27 @@ export class SignedExtrinsic<
const props = props_ as Z.Rec$Access<Props>;
const metadata_ = metadata(config);
const deriveCodec_ = deriveCodec(metadata_);
const $extrinsic_ = $extrinsic(deriveCodec_, metadata_, this.sign, config.addressPrefix);
const addrPrefix = const_(config, "System", "SS58Prefix")
.access("value")
.as<number>();
const $extrinsic_ = $extrinsic(deriveCodec_, metadata_, this.sign, addrPrefix);
const runtimeVersion = rpcCall(config, "state_getRuntimeVersion", []);
const senderSs58 = Z.call(props.sender, function senderSs58(sender) {
return ((): string => {
switch (sender.type) {
case "Id": {
return ss58.encode(config.addressPrefix, sender.value);
const senderSs58 = Z.call(
Z.ls(addrPrefix, props.sender),
function senderSs58([addrPrefix, sender]) {
return ((): string => {
switch (sender.type) {
case "Id": {
return ss58.encode(addrPrefix, sender.value);
}
// TODO: other types
default: {
unimplemented();
}
}
// TODO: other types
default: {
unimplemented();
}
}
})();
});
})();
},
);
const accountNextIndex = rpcCall(config, "system_accountNextIndex", [senderSs58]);
const genesisHash = hexDecode(rpcCall(config, "chain_getBlockHash", [0]).access("result"));
const checkpointHash = props.checkpoint
Expand Down
15 changes: 15 additions & 0 deletions effects/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ export function entryMetadata<PalletMetadata extends Z.$<M.Pallet>, EntryName ex
);
}

export function constMetadata<
PalletMetadata extends Z.$<M.Pallet>,
ConstName extends Z.$<string>,
>(
palletMetadata: PalletMetadata,
constName: ConstName,
) {
return Z.call(
Z.ls(palletMetadata, constName),
function constMetadataImpl([palletMetadata, constName]) {
return M.getConst(palletMetadata, constName);
},
);
}

export function mapMetadata<PalletMetadata extends Z.$<M.Pallet>, EntryName extends Z.$<string>>(
palletMetadata: PalletMetadata,
entryName: EntryName,
Expand Down
1 change: 1 addition & 0 deletions effects/mod.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./blockRead.ts";
export * from "./blockWatch.ts";
export * from "./const.ts";
export * from "./entryRead.ts";
export * from "./entryWatch.ts";
export * from "./extrinsic.ts";
Expand Down
5 changes: 5 additions & 0 deletions frame_metadata/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ export function getEntry(pallet: Pallet, name: string): StorageEntry | EntryNotF
}
export class EntryNotFoundError extends U.ErrorCtor("EntryNotFound") {}

export function getConst(pallet: Pallet, name: string): Constant | ConstNotFoundError {
return pallet.constants?.find((constant) => constant.name === name) || new ConstNotFoundError();
}
export class ConstNotFoundError extends U.ErrorCtor("ConstNotFound") {}

export function getPalletAndEntry(
metadata: Metadata,
palletName: string,
Expand Down
22 changes: 8 additions & 14 deletions known/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@

import { Config } from "../config/mod.ts";

export const polkadot = new Config(() => "wss://rpc.polkadot.io", 0);
export const kusama = new Config(() => "wss://kusama-rpc.polkadot.io", 2);
export const acala = new Config(() => "wss://acala-polkadot.api.onfinality.io/public-ws", 10);
export const rococo = new Config(
() => "wss://rococo-contracts-rpc.polkadot.io",
undefined!, /* TODO */
);
export const moonbeam = new Config(() => "wss://wss.api.moonbeam.network", 1284);
export const statemint = new Config(
() => "wss://statemint-rpc.polkadot.io",
undefined!, /* TODO */
);
export const subsocial = new Config(() => "wss://para.subsocial.network", 28);
export const westend = new Config(() => "wss://westend-rpc.polkadot.io", 42);
export const polkadot = new Config(() => "wss://rpc.polkadot.io");
export const kusama = new Config(() => "wss://kusama-rpc.polkadot.io");
export const acala = new Config(() => "wss://acala-polkadot.api.onfinality.io/public-ws");
export const rococo = new Config(() => "wss://rococo-contracts-rpc.polkadot.io");
export const moonbeam = new Config(() => "wss://wss.api.moonbeam.network");
export const statemint = new Config(() => "wss://statemint-rpc.polkadot.io");
export const subsocial = new Config(() => "wss://para.subsocial.network");
export const westend = new Config(() => "wss://westend-rpc.polkadot.io");
42 changes: 17 additions & 25 deletions test_util/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,23 @@ import { Config } from "../config/mod.ts";

export class TestConfig extends Config<string> {
constructor(readonly runtimeName: TestConfigRuntime.Name) {
super(
async () => {
const hostname = Deno.env.get("TEST_CTX_HOSTNAME");
const portRaw = Deno.env.get("TEST_CTX_PORT");
if (!hostname || !portRaw) await testCtx();
const conn = await Deno.connect({
hostname,
port: parseInt(portRaw!),
});
conn.write(new Uint8Array([TestConfigRuntime.CODES[runtimeName]]));
const port = await (async () => {
for await (const x of conn.readable) {
return new DataView(x.buffer).getUint16(0);
}
return undefined!;
})();
return `ws://127.0.0.1:${port}`;
},
{
kusama: 2,
rococo: undefined!, // TODO
westend: 0,
polkadot: 0,
}[runtimeName],
);
super(async () => {
const hostname = Deno.env.get("TEST_CTX_HOSTNAME");
const portRaw = Deno.env.get("TEST_CTX_PORT");
if (!hostname || !portRaw) await testCtx();
const conn = await Deno.connect({
hostname,
port: parseInt(portRaw!),
});
conn.write(new Uint8Array([TestConfigRuntime.CODES[runtimeName]]));
const port = await (async () => {
for await (const x of conn.readable) {
return new DataView(x.buffer).getUint16(0);
}
return undefined!;
})();
return `ws://127.0.0.1:${port}`;
});
}
}

Expand Down