Skip to content

Commit

Permalink
fix: extrinsic's call decoding (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
tien authored Aug 16, 2024
1 parent fdc379c commit c9c6cbf
Showing 1 changed file with 105 additions and 57 deletions.
162 changes: 105 additions & 57 deletions packages/core/src/actions/get-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {
getLookupFn,
} from "@polkadot-api/metadata-builders";
import {
Struct,
Bytes,
enhanceCodec,
metadata as metadataCodec,
Struct,
u8,
type V15,
} from "@polkadot-api/substrate-bindings";
Expand Down Expand Up @@ -39,6 +39,20 @@ export function getBlock<TOptions extends GetBlockOptions>(
}
}

type MultiAddress = Enum<{
Id: SS58String;
Index: number | bigint;
Raw: Binary;
Address32: FixedSizeBinary<32>;
Address20: FixedSizeBinary<20>;
}>;

type MultiSignature = Enum<{
Ed25519: FixedSizeBinary<64>;
Sr25519: FixedSizeBinary<64>;
Ecdsa: FixedSizeBinary<65>;
}>;

type Extra = Partial<{
nonZeroSender: undefined;
specVersion: undefined;
Expand All @@ -52,6 +66,22 @@ type Extra = Partial<{
[key: string]: unknown;
}>;

type Call = {
module: string;
func: string;
args: unknown;
};

type Extrinsic = { version: number; call: Call } & (
| { signed: false }
| {
signed: true;
sender: MultiAddress;
signature: MultiSignature;
extra: Extra;
}
);

export async function unstable_getBlockExtrinsics(
client: PolkadotClient,
typedApi: TypedApi<ChainDefinition>,
Expand Down Expand Up @@ -89,33 +119,55 @@ export async function unstable_getBlockExtrinsics(

const address$ = dynamicBuilder.buildDefinition(
metadata.extrinsic.address,
) as Codec<
Enum<{
Id: SS58String;
Index: number | bigint;
Raw: Binary;
Address32: FixedSizeBinary<32>;
Address20: FixedSizeBinary<20>;
}>
>;
) as Codec<MultiAddress>;

const signature$ = dynamicBuilder.buildDefinition(
metadata.extrinsic.signature,
) as Codec<
Enum<{
Ed25519: FixedSizeBinary<64>;
Sr25519: FixedSizeBinary<64>;
Ecdsa: FixedSizeBinary<65>;
}>
>;

const extra$ = dynamicBuilder.buildDefinition(
) as Codec<MultiSignature>;

const rawExtra$ = dynamicBuilder.buildDefinition(
metadata.extrinsic.extra,
) as Codec<unknown[]>;

const call$ = dynamicBuilder.buildDefinition(
const extra$ = enhanceCodec(
rawExtra$,
(extra: Extra) =>
metadata.extrinsic.signedExtensions.map(
(signedExtension) =>
extra[
"Check" +
signedExtension.identifier.slice(0, 1).toUpperCase() +
signedExtension.identifier.slice(1, 0)
],
),
(extra) =>
Object.fromEntries(
metadata.extrinsic.signedExtensions.map((signedExtension, index) => {
const name = signedExtension.identifier.replace(/^Check/, "");
return [
name.slice(0, 1).toLowerCase() + name.slice(1),
extra[index],
] as const;
}),
) as Extra,
);

const rawCall$ = dynamicBuilder.buildDefinition(
metadata.extrinsic.call,
) as Codec<{ module: string; method: string; args: unknown }>;
) as Codec<{ type: string; value: { type: string; value: unknown } }>;

const call$ = enhanceCodec(
rawCall$,
(call: Call) => ({
type: call.module,
value: { type: call.func, value: call.args },
}),
(call) => ({
module: call.type,
func: call.value.type,
args: call.value.value,
}),
);

const inherentExtrinsic$ = Struct({
version: version$ as Codec<{ version: number; signed: false }>,
Expand All @@ -125,54 +177,50 @@ export async function unstable_getBlockExtrinsics(
const signedExtrinsic$ = Struct({
version: version$ as Codec<{ version: number; signed: true }>,
body: Struct({
signer: address$,
sender: address$,
signature: signature$,
extra: extra$,
call: call$,
}),
});

const blockBody = await client.getBlockBody(blockHash);

const simpleVersion$ = Struct({
version: version$,
});

const bytes$ = Bytes();

return blockBody.map((extrinsicHex: string) => {
const bytes = bytes$.dec(extrinsicHex);

const {
version: { version, signed },
} = simpleVersion$.dec(bytes);

if (version !== 4) {
return;
}

const decodedExtrinsic = (
signed ? signedExtrinsic$.dec : inherentExtrinsic$.dec
)(bytes);

if (!("extra" in decodedExtrinsic.body)) {
return decodedExtrinsic;
}

const extraArray = decodedExtrinsic.body.extra;
const extrinsic$ = enhanceCodec(
Bytes(),
(extrinsic: Extrinsic) =>
extrinsic.signed
? signedExtrinsic$.enc({
version: { version: extrinsic.version, signed: extrinsic.signed },
body: {
sender: extrinsic.sender,
signature: extrinsic.signature,
extra: extrinsic.extra,
call: extrinsic.call,
},
})
: inherentExtrinsic$.enc({
version: { version: extrinsic.version, signed: extrinsic.signed },
body: { call: extrinsic.call },
}),
(extrinsicBytes) => {
const {
version: { signed },
} = simpleVersion$.dec(extrinsicBytes);

const rawExtrinsic = (
signed ? signedExtrinsic$.dec : inherentExtrinsic$.dec
)(extrinsicBytes);

return { ...rawExtrinsic.version, ...rawExtrinsic.body } as Extrinsic;
},
);

const extra = Object.fromEntries(
metadata.extrinsic.signedExtensions.map((signedExtension, index) => {
const name = signedExtension.identifier.replace(/^Check/, "");
return [
name.slice(0, 1).toLowerCase() + name.slice(1),
extraArray[index],
] as const;
}),
) as Extra;
const blockBody = await client.getBlockBody(blockHash);

return { ...decodedExtrinsic, body: { ...decodedExtrinsic.body, extra } };
});
return blockBody.map(extrinsic$.dec);
}

const dynamicBuilders = new WeakMap<
Expand Down

0 comments on commit c9c6cbf

Please sign in to comment.