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

feat: runtime validation #369

Merged
merged 9 commits into from
Nov 9, 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
25 changes: 6 additions & 19 deletions _tasks/dnt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,20 @@ await fs.emptyDir(outDir);

await Promise.all([
build({
entryPoints: ["mod.ts", {
name: "./frame_metadata",
path: "frame_metadata/mod.ts",
}, {
name: "./effect",
path: "effect/mod.ts",
}, {
name: "./known",
path: "known/mod.ts",
}, {
name: "./rpc",
path: "rpc/mod.ts",
}],
entryPoints: ["mod.ts"],
outDir,
mappings: {
"https://deno.land/x/[email protected].0/mod.ts": {
"https://deno.land/x/[email protected].1/mod.ts": {
name: "scale-codec",
version: "^0.9.0",
version: "^0.9.1",
},
"https://deno.land/x/[email protected].6/mod.ts": {
"https://deno.land/x/[email protected].12/mod.ts": {
name: "zones",
version: "0.1.0-beta.6",
version: "0.1.0-beta.12",
},
"deps/smoldot_phantom.ts": {
"https://deno.land/x/[email protected]/index-deno.js": {
name: "@substrate/smoldot-light",
version: "0.6.20",
peerDependency: true,
},
},
package: {
Expand Down
2 changes: 1 addition & 1 deletion deps/scale.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "https://deno.land/x/[email protected].0/mod.ts";
export * from "https://deno.land/x/[email protected].1/mod.ts";
38 changes: 22 additions & 16 deletions effects/extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ export class SignedExtrinsic<
const metadata_ = metadata(this.props.client)();
const deriveCodec_ = deriveCodec(metadata_);
const addrPrefix = const_(this.props.client)("System", "SS58Prefix")
.access("value").as<number>();
.access("value")
.as<number>();
const $extrinsic_ = $extrinsic(deriveCodec_, metadata_, this.sign, addrPrefix);
const versions = const_(this.props.client)("System", "Version").access("value");
const specVersion = versions.access("spec_version").as<number>();
const transactionVersion = versions.access("transaction_version").as<number>();
const versions = const_(this.props.client)("System", "Version")
.access("value");
const specVersion = versions
.access("spec_version").as<number>();
const transactionVersion = versions
.access("transaction_version").as<number>();
// TODO: create match effect in zones and use here
// TODO: MultiAddress conversion utils
const senderSs58 = Z.ls(addrPrefix, this.props.sender).next(([addrPrefix, sender]) => {
Expand All @@ -76,24 +80,26 @@ export class SignedExtrinsic<
const checkpointHash = this.props.checkpoint
? Z.option(this.props.checkpoint, U.hex.decode)
: genesisHash;
const mortality = Z
.lift(this.props.mortality)
.next((mortality) => {
return mortality
? M.era.mortal(mortality[0], mortality[1])
: M.era.immortal;
});
const extra = Z.ls(mortality, nonce, this.props.tip || 0);
const additional = Z.ls(specVersion, transactionVersion, checkpointHash, genesisHash);
const signature = Z.rec({ address: this.props.sender, extra, additional });
const $extrinsicProps = Z.rec({
protocolVersion: 4,
palletName: this.props.palletName,
methodName: this.props.methodName,
args: this.props.args,
signature: Z.rec({
address: this.props.sender,
extra: Z.ls(
this.props.mortality
? Z.rec({ type: "Mortal", value: this.props.mortality })
: { type: "Immortal" },
nonce,
this.props.tip || 0,
),
additional: Z.ls(specVersion, transactionVersion, checkpointHash, genesisHash),
}),
signature,
});
this.extrinsic = e$.scaleEncoded($extrinsic_, $extrinsicProps, true).next(U.hex.encode);
this.extrinsic = e$
.scaleEncoded($extrinsic_, $extrinsicProps, true)
.next(U.hex.encode);
}

watch<Listener extends Z.$<U.Listener<known.TransactionStatus, rpc.ClientSubscribeContext>>>(
Expand Down
28 changes: 15 additions & 13 deletions frame_metadata/Era.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import * as $ from "../deps/scale.ts";

export type Era = { type: "Immortal" } | { type: "Mortal"; period: bigint; phase: bigint };

export function immortalEra(): Era {
return { type: "Immortal" };
}

export function mortalEra(period: bigint, current: bigint): Era {
const adjustedPeriod = minN(maxN(nextPowerOfTwo(period), 4n), 1n << 16n);
const phase = current % adjustedPeriod;
const quantizeFactor = maxN(adjustedPeriod >> 12n, 1n);
const quantizedPhase = phase / quantizeFactor * quantizeFactor;
return { type: "Mortal", period: adjustedPeriod, phase: quantizedPhase };
export namespace era {
export const immortal: Era = { type: "Immortal" };
export function mortal(period: bigint, current: bigint): Era {
const adjustedPeriod = minN(maxN(nextPowerOfTwo(period), 4n), 1n << 16n);
const phase = current % adjustedPeriod;
const quantizeFactor = maxN(adjustedPeriod >> 12n, 1n);
const quantizedPhase = phase / quantizeFactor * quantizeFactor;
return { type: "Mortal", period: adjustedPeriod, phase: quantizedPhase };
}
}

export const $era: $.Codec<Era> = $.createCodec({
Expand Down Expand Up @@ -43,9 +42,12 @@ export const $era: $.Codec<Era> = $.createCodec({
}
}
},
_assert() {
// TODO
},
_assert: $
.taggedUnion("type", [
["Immortal"],
["Mortal", ["period", $.u64], ["phase", $.u64]],
])
._assert,
});

function maxN(a: bigint, b: bigint) {
Expand Down
29 changes: 27 additions & 2 deletions frame_metadata/Extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,33 @@ export function $extrinsic(props: ExtrinsicCodecProps): $.Codec<Extrinsic> {
const { type: palletName, value: { type: methodName, ...args } } = call;
return { protocolVersion, signature, palletName, methodName, args };
},
_assert() {
// TODO
_assert(assert) {
assert.typeof(this, "object");
assert
.key(this, "protocolVersion")
.equals($.u8, 4);
const value_ = assert.value as any;
// TODO: use `assert.key(this, "call")` upon merging https://github.com/paritytech/capi/pull/368
$call._assert(
new $.AssertState({
type: value_.palletName,
value: {
type: value_.methodName,
...value_.args,
},
}),
);
if (value_.signature) {
const signatureAssertState = assert.key(this, "signature");
signatureAssertState.key($address, "address");
signatureAssertState.key($extra, "extra");
if ("additional" in signatureAssertState) {
signatureAssertState.key($additional, "additional");
}
if ("sig" in signatureAssertState) {
signatureAssertState.key($sig, "sig");
}
}
},
});

Expand Down
7 changes: 5 additions & 2 deletions frame_metadata/Key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,11 @@ export function $storageKey(props: StorageKeyProps): $.Codec<unknown[]> {
buffer.index += 32;
return $keys[Object.values($keys).length - 1]!._decode(buffer);
},
_assert() {
// TODO #362
_assert(assert) {
assert.instanceof(this, Array);
const value = assert.value as unknown[];
if (value.length === 0) return;
$keys[value.length]!._assert(assert);
},
});
}
10 changes: 5 additions & 5 deletions frame_metadata/scale_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ export const $tys: $.Codec<Ty[]> = $.createCodec({
}
return tys;
},
_assert() {
// TODO #362
_assert(assert) {
$.array($ty)._assert(assert);
},
});

export const $tyId: $.Codec<Ty> = $.createCodec({
_metadata: $.metadata("$tyId"),
_staticSize: $compactU32._staticSize,
_encode(buffer, value) {
$.compact($.u32)._encode(buffer, value.id);
$compactU32._encode(buffer, value.id);
},
_decode(buffer) {
const ctx = buffer.context.get(TyDecodeCtx);
const id = $compactU32._decode(buffer);
return ctx.tys?.[id] ?? { id } as any;
},
_assert() {
// TODO #362
_assert(assert) {
$compactU32._assert(assert.key(this, "id"));
},
});

Expand Down