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

Commit

Permalink
feat: const effect for decoding consts in the metadata (#347)
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay authored Nov 1, 2022
1 parent 3e262ae commit 863eec5
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 62 deletions.
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

0 comments on commit 863eec5

Please sign in to comment.