Skip to content

Commit 43f4385

Browse files
authored
feat: refactor preimage hooks (#7258)
* feat: refactor preimage hooks * refactor useOldPreimage * Remove enable papi flag * Update * Update * Update
1 parent ca39081 commit 43f4385

File tree

11 files changed

+716
-13
lines changed

11 files changed

+716
-13
lines changed

packages/next-common/components/preImages/desktop.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import useColumns from "next-common/components/styledList/useColumns";
22
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
33
import { useState } from "react";
4-
import useOldPreimage from "next-common/hooks/useOldPreimage";
5-
import useOldPreimagePapi from "next-common/hooks/useOldPreimagePapi";
6-
import usePreimage from "next-common/hooks/usePreimage";
7-
import usePreimagePapi from "next-common/hooks/usePreimagePapi";
4+
import useOldPreimage from "next-common/hooks/useOldPreimageNew";
5+
import useOldPreimagePapi from "next-common/hooks/useOldPreimagePapiNew";
6+
import usePreimage from "next-common/hooks/usePreimageNew";
7+
import usePreimagePapi from "next-common/hooks/usePreimagePapiNew";
88
import { useChainSettings } from "next-common/context/chain";
99
import { useDispatch, useSelector } from "react-redux";
1010
import {

packages/next-common/components/preImages/mobile.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
22
import React, { useState, useEffect, useRef } from "react";
3-
import usePreimage from "next-common/hooks/usePreimage";
4-
import usePreimagePapi from "next-common/hooks/usePreimagePapi";
5-
import useOldPreimage from "next-common/hooks/useOldPreimage";
6-
import useOldPreimagePapi from "next-common/hooks/useOldPreimagePapi";
3+
import usePreimage from "next-common/hooks/usePreimageNew";
4+
import usePreimagePapi from "next-common/hooks/usePreimagePapiNew";
5+
import useOldPreimage from "next-common/hooks/useOldPreimageNew";
6+
import useOldPreimagePapi from "next-common/hooks/useOldPreimagePapiNew";
77
import { useChainSettings } from "next-common/context/chain";
88
import { useDispatch } from "react-redux";
99
import { incPreImagesTrigger } from "next-common/store/reducers/preImagesSlice";

packages/next-common/hooks/common/useSubStorage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export default function useSubStorage(
151151

152152
const paramsKey = normalizedParams
153153
.map((p) => {
154-
if (p === null || p === undefined) return "null";
154+
if (isNil(p)) return "null";
155155
if (typeof p === "object") {
156156
try {
157157
return JSON.stringify(p);

packages/next-common/hooks/useOldPreimageCommon.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ function unwrapMaybeValue(value) {
103103

104104
export function toPreimageLength(value) {
105105
const unwrappedValue = unwrapMaybeValue(value);
106-
if (unwrappedValue === null || unwrappedValue === undefined) {
106+
if (isNil(unwrappedValue)) {
107107
return null;
108108
}
109109

@@ -116,7 +116,7 @@ export function toPreimageLength(value) {
116116

117117
export function toPreimageCount(value) {
118118
const unwrappedValue = unwrapMaybeValue(value);
119-
if (unwrappedValue === null || unwrappedValue === undefined) {
119+
if (isNil(unwrappedValue)) {
120120
return undefined;
121121
}
122122

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { useAsync } from "react-use";
2+
import { useContextApi } from "next-common/context/api";
3+
import { BN_ZERO } from "@polkadot/util";
4+
import { Option } from "@polkadot/types";
5+
import {
6+
buildNoBytesResult,
7+
buildBaseResult,
8+
buildCompletedResult,
9+
buildPreimageForKey,
10+
decodeCallBytes,
11+
extractCallData,
12+
isHashOnlyStorageKey,
13+
parseHashOrBounded,
14+
resolveInlinePreimage,
15+
} from "./usePreimageNewCommon";
16+
17+
const oldPreimageResultCache = new Map();
18+
19+
function parseDeposit(rawDeposit) {
20+
if (!rawDeposit) return undefined;
21+
return { who: rawDeposit[0].toString(), amount: rawDeposit[1] };
22+
}
23+
24+
function parseStatusFor(optStatus) {
25+
const status = optStatus.unwrapOr(null);
26+
if (!status) return { status: null };
27+
28+
if (status.isRequested) {
29+
const req = status.asRequested;
30+
// Older versions: asRequested is an option with no structured fields.
31+
if (req instanceof Option) {
32+
return { status, statusName: "requested" };
33+
}
34+
return {
35+
status,
36+
statusName: "requested",
37+
count: req.count.toNumber(),
38+
deposit: parseDeposit(req.deposit.unwrapOr(null)),
39+
proposalLength: req.len.unwrapOr(BN_ZERO),
40+
};
41+
}
42+
43+
if (status.isUnrequested) {
44+
const unreq = status.asUnrequested;
45+
// Older versions, asUnrequested is an option.
46+
if (unreq instanceof Option) {
47+
return {
48+
status,
49+
statusName: "unrequested",
50+
deposit: parseDeposit(unreq.unwrapOr(null)),
51+
};
52+
}
53+
return {
54+
status,
55+
statusName: "unrequested",
56+
deposit: parseDeposit(unreq.deposit),
57+
proposalLength: unreq.len,
58+
};
59+
}
60+
61+
console.error(`Unhandled PalletPreimageRequestStatus type: ${status.type}`);
62+
return { status };
63+
}
64+
65+
async function fetchOldPreimage(proposalHash, api, hashOnly) {
66+
const base = buildBaseResult(proposalHash, hashOnly, api.registry, null);
67+
68+
if (!api.query.preimage?.statusFor) return base;
69+
70+
const optStatus = await api.query.preimage.statusFor(proposalHash);
71+
const parsedStatus = parseStatusFor(optStatus);
72+
const withStatus = { ...base, ...parsedStatus };
73+
74+
if (!parsedStatus.status) return withStatus;
75+
76+
if (!api.query.preimage?.preimageFor) return withStatus;
77+
78+
const bytesKey = buildPreimageForKey(
79+
proposalHash,
80+
withStatus.proposalLength,
81+
hashOnly,
82+
);
83+
const optBytes = await api.query.preimage.preimageFor(...bytesKey);
84+
const callData = extractCallData(optBytes);
85+
86+
if (!callData) return buildNoBytesResult(withStatus);
87+
88+
const decoded = decodeCallBytes(
89+
callData,
90+
api.registry,
91+
withStatus.proposalLength,
92+
);
93+
return buildCompletedResult(withStatus, decoded);
94+
}
95+
96+
export default function useOldPreimage(hashOrBounded) {
97+
const api = useContextApi();
98+
99+
const { value, loading } = useAsync(async () => {
100+
if (!hashOrBounded || !api) return null;
101+
102+
const { proposalHash, inlineData } = parseHashOrBounded(hashOrBounded, api);
103+
if (!proposalHash) return null;
104+
105+
if (oldPreimageResultCache.has(proposalHash)) {
106+
return oldPreimageResultCache.get(proposalHash);
107+
}
108+
109+
const hashOnly = isHashOnlyStorageKey(api);
110+
111+
const result = inlineData
112+
? resolveInlinePreimage(proposalHash, hashOnly, api, inlineData)
113+
: await fetchOldPreimage(proposalHash, api, hashOnly);
114+
115+
if (result?.isCompleted) {
116+
oldPreimageResultCache.set(proposalHash, result);
117+
}
118+
119+
return result;
120+
}, [hashOrBounded, api]);
121+
122+
const isStatusLoaded = Boolean(api) && !loading;
123+
const isPreimageLoaded =
124+
Boolean(api) && !loading && Boolean(value?.isCompleted);
125+
126+
return [value ?? {}, isStatusLoaded, isPreimageLoaded];
127+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { useAsync } from "react-use";
2+
import { Binary } from "polkadot-api";
3+
import { useContextPapi } from "next-common/context/papi";
4+
import {
5+
fetchPapiPreimageBytes,
6+
decodePreimageWithPapi,
7+
toPreimageCount,
8+
toPreimageLength,
9+
convertPapiDepositTuple,
10+
getPapiStatusName,
11+
} from "./useOldPreimageCommon";
12+
import {
13+
parsePapiHashOrBounded,
14+
buildNoBytesResult,
15+
buildBasePapiResult,
16+
resolveInlinePapiPreimage,
17+
} from "./usePreimageNewCommon";
18+
19+
const oldPapiPreimageResultCache = new Map();
20+
21+
function parsePapiStatusFor(rawStatus) {
22+
if (!rawStatus) return { status: null };
23+
24+
const statusName = getPapiStatusName(rawStatus);
25+
const { type, value = {} } = rawStatus;
26+
const result = { status: rawStatus, statusName };
27+
28+
if (type === "Requested") {
29+
result.count = toPreimageCount(value.count);
30+
result.deposit = convertPapiDepositTuple(value.deposit);
31+
result.proposalLength = toPreimageLength(value.len);
32+
} else if (type === "Unrequested") {
33+
result.deposit = convertPapiDepositTuple(value.deposit);
34+
result.proposalLength = toPreimageLength(value.len);
35+
} else {
36+
console.error(`Unhandled PAPI Preimage.StatusFor type: ${type}`);
37+
}
38+
39+
return result;
40+
}
41+
42+
async function fetchOldPapiPreimage(proposalHash, papi, client) {
43+
const base = buildBasePapiResult(proposalHash, null);
44+
45+
if (!papi.query?.Preimage?.StatusFor) return base;
46+
47+
const rawStatus = await papi.query.Preimage.StatusFor.getValue(
48+
Binary.fromHex(proposalHash),
49+
);
50+
51+
const parsedStatus = parsePapiStatusFor(rawStatus);
52+
const withStatus = { ...base, ...parsedStatus };
53+
54+
if (!parsedStatus.status) return withStatus;
55+
56+
const bytes = await fetchPapiPreimageBytes(
57+
papi,
58+
proposalHash,
59+
withStatus.proposalLength,
60+
);
61+
62+
if (!bytes) return buildNoBytesResult(withStatus);
63+
64+
let decoded;
65+
try {
66+
decoded = await decodePreimageWithPapi(withStatus, bytes, client);
67+
} catch {
68+
// ignore
69+
}
70+
71+
if (!decoded) {
72+
return {
73+
...withStatus,
74+
isCompleted: true,
75+
proposalError: "Unable to decode preimage bytes into a valid Call",
76+
};
77+
}
78+
79+
return decoded;
80+
}
81+
82+
export default function useOldPreimagePapi(hashOrBounded) {
83+
const { api: papi, client } = useContextPapi();
84+
85+
const { value, loading } = useAsync(async () => {
86+
if (!hashOrBounded || !papi || !client) return null;
87+
88+
const { proposalHash, inlineData } = parsePapiHashOrBounded(hashOrBounded);
89+
if (!proposalHash) return null;
90+
91+
if (oldPapiPreimageResultCache.has(proposalHash)) {
92+
return oldPapiPreimageResultCache.get(proposalHash);
93+
}
94+
95+
const result = inlineData
96+
? await resolveInlinePapiPreimage(proposalHash, inlineData, client)
97+
: await fetchOldPapiPreimage(proposalHash, papi, client);
98+
99+
if (result?.isCompleted) {
100+
oldPapiPreimageResultCache.set(proposalHash, result);
101+
}
102+
103+
return result;
104+
}, [hashOrBounded, papi, client]);
105+
106+
const isStatusLoaded = Boolean(papi) && Boolean(client) && !loading;
107+
const isPreimageLoaded =
108+
Boolean(papi) && Boolean(client) && !loading && Boolean(value?.isCompleted);
109+
110+
return [value ?? {}, isStatusLoaded, isPreimageLoaded];
111+
}

0 commit comments

Comments
 (0)