Skip to content

Commit ef51222

Browse files
committed
ci: fix astar para ID and test session key rotation in compatibility run
1 parent b6e821c commit ef51222

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Rotates keys via `author_rotateKeysWithOwner` and checks `session.setKeys` enforces the proof; returns 1 on success.
2+
3+
const ROTATE_RPC = "author_rotateKeysWithOwner";
4+
const TX_TIMEOUT_MS = 60_000;
5+
6+
// Resolves to null on success, or to the dispatch error name.
7+
function submit(api, tx, signer) {
8+
return new Promise((resolve, reject) => {
9+
const timer = setTimeout(
10+
() => reject(new Error(`tx not in a block after ${TX_TIMEOUT_MS}ms`)),
11+
TX_TIMEOUT_MS
12+
);
13+
tx.signAndSend(signer, ({ status, dispatchError }) => {
14+
if (!status.isInBlock) return;
15+
clearTimeout(timer);
16+
if (!dispatchError) return resolve(null);
17+
resolve(
18+
dispatchError.isModule
19+
? api.registry.findMetaError(dispatchError.asModule).name
20+
: dispatchError.toString()
21+
);
22+
}).catch((err) => {
23+
clearTimeout(timer);
24+
reject(err);
25+
});
26+
});
27+
}
28+
29+
// Collator order depends on the client tags, so find the one that exposes the RPC.
30+
async function connectToCollatorWithRpc(networkInfo) {
31+
const collators = Object.entries(networkInfo.nodesByName).filter(([name]) =>
32+
name.startsWith("collator")
33+
);
34+
for (const [name, { wsUri, userDefinedTypes }] of collators) {
35+
const api = await zombie.connect(wsUri, userDefinedTypes);
36+
const { methods } = await api.rpc.rpc.methods();
37+
if (methods.some((m) => m.toString() === ROTATE_RPC)) {
38+
return { name, wsUri, api };
39+
}
40+
await api.disconnect();
41+
}
42+
return null;
43+
}
44+
45+
async function rotateAndRegister(name, wsUri, api) {
46+
const alice = new zombie.Keyring({ type: "sr25519" }).addFromUri("//Alice");
47+
const owner = "0x" + Buffer.from(alice.publicKey).toString("hex");
48+
49+
// polkadot-js doesn't decorate this RPC, so call it through a raw provider.
50+
const provider = new zombie.WsProvider(wsUri);
51+
try {
52+
await provider.isReady;
53+
54+
const { keys, proof } = await provider.send(ROTATE_RPC, [owner]);
55+
if (!proof) {
56+
console.log(`FAIL ${name} returned no proof: runtime lacks SessionKeys API v2`);
57+
return 0;
58+
}
59+
60+
const badProof = proof.slice(0, -1) + (proof.endsWith("0") ? "1" : "0");
61+
const badResult = await submit(api, api.tx.session.setKeys(keys, badProof), alice);
62+
if (badResult !== "InvalidProof") {
63+
console.log(`FAIL tampered proof: expected InvalidProof, got ${badResult}`);
64+
return 0;
65+
}
66+
67+
const result = await submit(api, api.tx.session.setKeys(keys, proof), alice);
68+
if (result !== null) {
69+
console.log(`FAIL setKeys with valid proof: ${result}`);
70+
return 0;
71+
}
72+
73+
const next = await api.query.session.nextKeys(alice.address);
74+
if (next.isNone || next.unwrap().toHex() !== keys) {
75+
console.log(`FAIL session.nextKeys is ${next.toHex()}, expected ${keys}`);
76+
return 0;
77+
}
78+
79+
if (!(await provider.send("author_hasSessionKeys", [keys]))) {
80+
console.log(`FAIL ${name} keystore lacks the rotated keys`);
81+
return 0;
82+
}
83+
84+
console.log(`rotated session keys on ${name} and registered them with a proof`);
85+
return 1;
86+
} finally {
87+
await provider.disconnect();
88+
}
89+
}
90+
91+
async function run(_nodeName, networkInfo) {
92+
const target = await connectToCollatorWithRpc(networkInfo);
93+
if (!target) {
94+
console.log(`FAIL no collator exposes ${ROTATE_RPC}: a stable2603+ client is required`);
95+
return 0;
96+
}
97+
98+
const { name, wsUri, api } = target;
99+
try {
100+
return await rotateAndRegister(name, wsUri, api);
101+
} catch (err) {
102+
console.log(`FAIL ${err.message}`);
103+
return 0;
104+
} finally {
105+
await api.disconnect();
106+
}
107+
}
108+
109+
module.exports = { run };

0 commit comments

Comments
 (0)