--- /dev/null +++ b/tests/src/util/authorizeEnactUpgrade.ts @@ -0,0 +1,19 @@ +import {readFile} from 'fs/promises'; +import {u8aToHex} from '@polkadot/util'; +import {usingPlaygrounds} from '.'; +import {blake2AsHex} from '@polkadot/util-crypto'; + + +const codePath = process.argv[2]; +if(!codePath) throw new Error('missing code path argument'); + +const code = await readFile(codePath); + +await usingPlaygrounds(async (helper, privateKey) => { + const alice = await privateKey('//Alice'); + const hex = blake2AsHex(code); + await helper.getSudo().executeExtrinsic(alice, 'api.tx.parachainSystem.authorizeUpgrade', [hex, true]); + await helper.getSudo().executeExtrinsicUncheckedWeight(alice, 'api.tx.parachainSystem.enactAuthorizedUpgrade', [u8aToHex(code)]); +}); +// We miss disconnect/unref somewhere. +process.exit(0); --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -732,6 +732,24 @@ } return result as any; } + executeExtrinsicUncheckedWeight< + E extends string, + V extends ( + ...args: any) => any = ForceFunction< + Get2< + AugmentedSubmittables<'promise'>, + E, (...args: any) => Invalid<'not found'> + > + > + >( + sender: TSigner, + extrinsic: `api.tx.${E}`, + params: Parameters, + expectSuccess = true, + options: Partial | null = null,/*, failureMessage='expected success'*/ + ): Promise { + throw new Error('executeExtrinsicUncheckedWeight only supported in sudo'); + } async callRpc // TODO: make it strongly typed, or use api.query/api.rpc directly @@ -4056,6 +4074,38 @@ } return result; } + async executeExtrinsicUncheckedWeight( + sender: IKeyringPair, + extrinsic: string, + params: any[], + expectSuccess?: boolean, + options: Partial | null = null, + ): Promise { + const call = this.constructApiCall(extrinsic, params); + const result = await super.executeExtrinsic( + sender, + 'api.tx.sudo.sudoUncheckedWeight', + [call, {refTime: 0, proofSize: 0}], + expectSuccess, + options, + ); + + if(result.status === 'Fail') return result; + + const data = (result.result.events.find(x => x.event.section == 'sudo' && x.event.method == 'Sudid')?.event.data as any).sudoResult; + if(data.isErr) { + if(data.asErr.isModule) { + const error = (result.result.events[1].event.data as any).sudoResult.asErr.asModule; + const metaError = super.getApi()?.registry.findMetaError(error); + throw new Error(`${metaError.section}.${metaError.name}`); + } else if(data.asErr.isToken) { + throw new Error(`Token: ${data.asErr.asToken}`); + } + // May be [object Object] in case of unhandled non-unit enum + throw new Error(`Misc: ${data.asErr.toHuman()}`); + } + return result; + } }; } --- /dev/null +++ b/tests/src/util/setCode.ts @@ -0,0 +1,15 @@ +import {readFile} from 'fs/promises'; +import {u8aToHex} from '@polkadot/util'; +import {usingPlaygrounds} from '.'; + +const codePath = process.argv[2]; +if(!codePath) throw new Error('missing code path argument'); + +const code = await readFile(codePath); + +await usingPlaygrounds(async (helper, privateKey) => { + const alice = await privateKey('//Alice'); + await helper.getSudo().executeExtrinsicUncheckedWeight(alice, 'api.tx.system.setCode', [u8aToHex(code)]); +}); +// We miss disconnect/unref somewhere. +process.exit(0);