12345678910import {encodeAddress} from '@polkadot/keyring';11import type {IKeyringPair} from '@polkadot/types/types';12import {usingPlaygrounds, Pallets} from './index.js';13import {ChainHelperBase} from '@unique/playgrounds/unique.js';1415const relayUrl = process.argv[2] ?? 'ws://localhost:9844';16const paraUrl = process.argv[3] ?? 'ws://localhost:9944';17const key = process.argv.length > 4 ? process.argv.slice(4).join(' ') : '//Alice';1819export function extractAccountId(key: any): string {20 return (key as any).toHuman()[0];21}2223export function extractIdentityInfo(value: any): object {24 const heart = (value as any).unwrap();25 const identity = heart.toJSON();26 identity.judgements = heart.judgements.toHuman();27 return identity;28}2930export function extractIdentity(key: any, value: any): [string, any] {31 return [extractAccountId(key), extractIdentityInfo(value)];32}3334export async function getIdentities(helper: ChainHelperBase, noneCasePredicate?: (key: any, value: any) => void) {35 const identities: [string, any][] = [];36 for(const [key, v] of await helper.getApi().query.identity.identityOf.entries()) {37 const value = v as any;38 if(value.isNone) {39 if(noneCasePredicate) noneCasePredicate(key, value);40 continue;41 }42 identities.push(extractIdentity(key, value));43 }44 return identities;45}464748function isCurrentChainDataPriority(helper: ChainHelperBase, currentChainId: number | undefined, relayChainId: number) {49 if(!currentChainId) return false;50 51 if(currentChainId == helper.chain.getChainProperties().ss58Format) return true;52 53 return currentChainId < relayChainId;54}555657export function constructSubInfo(identityAccount: string, subQuery: any, supers: any[], ss58?: number): [string, any] {58 const deposit = subQuery.toJSON()[0];59 const subIdentities = subQuery.toHuman()[1];60 subIdentities.map((sub: string) => supers.find((sup: any) => sup[0] === sub));6162 return [63 encodeAddress(identityAccount, ss58), [64 deposit,65 subIdentities.map((sub: string): [string, object] | null => {66 const sup = supers.find((sup: any) => sup[0] === sub);67 if(!sup) {68 console.error(`Error: Could not find info on super for \nsub-identity account\t${sub} of \nsuper account \t\t${identityAccount}, skipping.`);69 return null;70 }71 return [encodeAddress(sub, ss58), sup[1].toJSON()[1]];72 }).filter((x: any) => x),73 ],74 ];75}7677export async function getSubs(helper: ChainHelperBase) {78 return (await helper.getApi().query.identity.subsOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);79}8081export async function getSupers(helper: ChainHelperBase) {82 return (await helper.getApi().query.identity.superOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);83}8485async function uploadPreimage(helper: ChainHelperBase, preimageMaker: IKeyringPair, preimage: string) {86 try {87 await helper.executeExtrinsic(preimageMaker, 'api.tx.preimage.notePreimage', [preimage]);88 } catch (e: any) {89 if(e.message.includes('AlreadyNoted')) {90 console.warn('Warning: The same preimage already exists on the chain. Nothing was uploaded.');91 } else {92 console.error(e);93 }94 }95}969798const forceInsertIdentities = async (): Promise<void> => {99 let relaySS58Prefix = 0;100 const identitiesOnRelay: any[] = [];101 const subsOnRelay: any[] = [];102 const identitiesToRemove: string[] = [];103 await usingPlaygrounds(async helper => {104 try {105 relaySS58Prefix = helper.chain.getChainProperties().ss58Format;106 107 for(const [key, value] of await getIdentities(helper, (key, _value) => identitiesToRemove.push((key as any).toHuman()[0]))) {108 109 let knownGood = false, reasonable = false;110 for(const [_id, judgement] of value.judgements) {111 if(judgement == 'KnownGood') knownGood = true;112 if(judgement == 'Reasonable') reasonable = true;113 }114 if(!(reasonable || knownGood)) continue;115 116 value.judgements = [[helper.chain.getChainProperties().ss58Format, knownGood ? 'KnownGood' : 'Reasonable']];117 identitiesOnRelay.push([key, value]);118 }119120 const sublessIdentities = [...identitiesOnRelay];121 const supersOfSubs = await getSupers(helper);122123 124 for(const [key, value] of await getSubs(helper)) {125 126 const identityIndex = sublessIdentities.findIndex((x: any) => x[0] == key);127 if(identityIndex == -1) continue;128 sublessIdentities.splice(identityIndex, 1);129 subsOnRelay.push(constructSubInfo(key, value, supersOfSubs));130 }131132 133 134135136 } catch (error) {137 console.error(error);138 throw Error('Error during fetching identities');139 }140 }, relayUrl);141142 await usingPlaygrounds(async (helper, privateKey) => {143 if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) console.error('pallet-identity is not included in parachain.');144 if(helper.fetchMissingPalletNames([Pallets.Preimage]).length != 0) console.error('pallet-preimage is not included in parachain.');145146 try {147 const preimageMaker = await privateKey(key);148 const ss58Format = helper.chain.getChainProperties().ss58Format;149 const paraIdentities = await getIdentities(helper);150 const identitiesToAdd: any[] = [];151 const paraAccountsRegistrators: {[name: string]: number} = {};152153 154 for(const [key, value] of identitiesOnRelay) {155 const encodedKey = encodeAddress(key, ss58Format);156157 158 const identity = paraIdentities.find(i => i[0] === encodedKey);159 if(identity) {160 const registratorId = identity[1].judgements[0][0];161 paraAccountsRegistrators[encodedKey] = registratorId;162 if(isCurrentChainDataPriority(helper, registratorId, value.judgements[0][0])163 || JSON.stringify(value.info) === JSON.stringify(identity[1].info)) {164 continue;165 }166 }167168 identitiesToAdd.push([key, value]);169 170 171 172 173 }174175 if(identitiesToRemove.length != 0)176 await uploadPreimage(177 helper,178 preimageMaker,179 helper.constructApiCall('api.tx.identity.forceRemoveIdentities', [identitiesToRemove]).method.toHex(),180 );181 if(identitiesToAdd.length != 0)182 await uploadPreimage(183 helper,184 preimageMaker,185 helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex(),186 );187188 console.log(`Tried to push ${identitiesToAdd.length} identities`189 + ` and found ${identitiesToRemove.length} identities for potential removal.`190 + ` Currently there are ${(await helper.getApi().query.identity.identityOf.keys()).length} identities on the chain.`);191192 193 const paraSubs = await getSubs(helper);194 const supersOfSubs = await getSupers(helper);195 const subsToUpdate: any[] = [];196197 for(const [key, value] of subsOnRelay) {198 const encodedKey = encodeAddress(key, ss58Format);199 const sub = paraSubs.find(i => i[0] === encodedKey);200 if(sub) {201 202 if(isCurrentChainDataPriority(helper, paraAccountsRegistrators[encodedKey], relaySS58Prefix)203 || JSON.stringify(value) === JSON.stringify(constructSubInfo(sub[0], sub[1], supersOfSubs)[1])) {204 continue;205 }206 } else if(value[1].length == 0)207 continue;208209 subsToUpdate.push([key, value]);210 }211212 if(subsToUpdate.length != 0)213 await uploadPreimage(214 helper,215 preimageMaker,216 helper.constructApiCall('api.tx.identity.forceSetSubs', [subsToUpdate]).method.toHex(),217 );218219 console.log(`Also tried to push ${subsToUpdate.length} identities with their sub-identities.`220 + ` Currently there are ${(await helper.getApi().query.identity.subsOf.keys()).length} identities with subs.`);221 } catch (error) {222 console.error(error);223 throw Error('Error during setting identities');224 }225 }, paraUrl);226};227228if(process.argv[1] === module.filename)229 forceInsertIdentities().catch(() => process.exit(1));