git.delta.rocks / unique-network / refs/commits / e7f049d5aecf

difftreelog

util(identity-setter): compose pulled identities into preimages

Fahrrader2023-02-21parent: #1fd2934.patch.diff
in: master

1 file changed

modifiedtests/src/util/identitySetter.tsdiffbeforeafterboth
before · tests/src/util/identitySetter.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.03//4// Pulls identities and sub-identities from a chain and then uses sudo to force upload them into another.5// Only changed or previously non-existent data are inserted.6//7// Usage: `yarn setIdentities [relay WS URL] [parachain WS URL] [sudo key]`8// Example: `yarn setIdentities wss://polkadot-rpc.dwellir.com ws://localhost:9944 escape pattern miracle train sudden cart adapt embark wedding alien lamp mesh`910import {encodeAddress} from '@polkadot/keyring';11import {usingPlaygrounds, Pallets} from './index';12import {ChainHelperBase} from './playgrounds/unique';1314const relayUrl = process.argv[2] ?? 'ws://localhost:9844';15const paraUrl = process.argv[3] ?? 'ws://localhost:9944';16const key = process.argv.length > 4 ? process.argv.slice(4).join(' ') : '//Alice';1718export function extractAccountId(key: any): string {19  return (key as any).toHuman()[0];20}2122export function extractIdentityInfo(value: any): object {23  const heart = (value as any).unwrap();24  const identity = heart.toJSON();25  identity.judgements = heart.judgements.toHuman();26  return identity;27}2829export function extractIdentity(key: any, value: any): [string, any] {30  return [extractAccountId(key), extractIdentityInfo(value)];31}3233export async function getIdentities(helper: ChainHelperBase, noneCasePredicate?: (key: any, value: any) => void) {34  const identities: [string, any][] = [];35  for(const [key, v] of await helper.getApi().query.identity.identityOf.entries()) {36    const value = v as any;37    if (value.isNone) {38      if (noneCasePredicate) noneCasePredicate(key, value);39      continue;40    }41    identities.push(extractIdentity(key, value));42  }43  return identities;44}4546// whether the existing chain data is more important than the coming47function isCurrentChainDataPriority(helper: ChainHelperBase, currentChainId: number | undefined, relayChainId: number) {48  if (!currentChainId) return false;49  // information has come from local chain, and is automatically superior50  if (currentChainId == helper.chain.getChainProperties().ss58Format) return true;51  // the lower the id, the more important it is (Polkadot has ss58 prefix = 0, Kusama has ss58 prefix = 2)52  return currentChainId < relayChainId;53}5455// construct an object with all data necessary for insertion from storage query results56export function constructSubInfo(identityAccount: string, subQuery: any, supers: any[], ss58?: number): [string, any] {57  const deposit = subQuery.toJSON()[0];58  const subIdentities = subQuery.toHuman()[1];59  subIdentities.map((sub: string) => supers.find((sup: any) => sup[0] === sub));6061  return [62    encodeAddress(identityAccount, ss58), [63      deposit,64      subIdentities.map((sub: string): [string, object] | null => {65        const sup = supers.find((sup: any) => sup[0] === sub);66        if (!sup) {67          console.error(`Error: Could not find info on super for \nsub-identity account\t${sub} of \nsuper account \t\t${identityAccount}, skipping.`);68          return null;69        }70        return [encodeAddress(sub, ss58), sup[1].toJSON()[1]];71      }).filter((x: any) => x),72    ],73  ];74}7576export async function getSubs(helper: ChainHelperBase) {77  return (await helper.getApi().query.identity.subsOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);78}7980export async function getSupers(helper: ChainHelperBase) {81  return (await helper.getApi().query.identity.superOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);82}8384// The utility for pulling identity and sub-identity data85const forceInsertIdentities = async (): Promise<void> => {86  let relaySS58Prefix = 0;87  const identitiesOnRelay: any[] = [];88  const subsOnRelay: any[] = [];89  const identitiesToRemove: string[] = [];90  await usingPlaygrounds(async helper => {91    try {92      relaySS58Prefix = helper.chain.getChainProperties().ss58Format;93      // iterate over every identity94      for(const [key, value] of await getIdentities(helper, (key, _value) => identitiesToRemove.push((key as any).toHuman()[0]))) {95        // if any of the judgements resulted in a good confirmed outcome, keep this identity96        let knownGood = false, reasonable = false;97        for (const [_id, judgement] of value.judgements) {98          if (judgement == 'KnownGood') knownGood = true;99          if (judgement == 'Reasonable') reasonable = true;100        }101        if (!(reasonable || knownGood)) continue;102        // replace the registrator id with the relay chain's ss58 format103        value.judgements = [[helper.chain.getChainProperties().ss58Format, knownGood ? 'KnownGood' : 'Reasonable']];104        identitiesOnRelay.push([key, value]);105      }106107      const sublessIdentities = [...identitiesOnRelay];108      const supersOfSubs = await getSupers(helper);109110      // iterate over every sub-identity111      for(const [key, value] of await getSubs(helper)) {112        // only get subs of the identities interesting to us113        const identityIndex = sublessIdentities.findIndex((x: any) => x[0] == key);114        if (identityIndex == -1) continue;115        sublessIdentities.splice(identityIndex, 1);116        subsOnRelay.push(constructSubInfo(key, value, supersOfSubs));117      }118119      // mark the rest of sub-identities for deletion with empty arrays120      /*for(const [account, _identity] of sublessIdentities) {121        subsOnRelay.push([account, ['0', []]]);122      }*/123    } catch (error) {124      console.error(error);125      throw Error('Error during fetching identities');126    }127  }, relayUrl);128129  await usingPlaygrounds(async (helper, privateKey) => {130    if (helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) console.error('pallet-identity is not included in parachain.');131    try {132      const superuser = await privateKey(key);133      const ss58Format = helper.chain.getChainProperties().ss58Format;134      const paraIdentities = await getIdentities(helper);135      const identitiesToAdd: any[] = [];136      const paraAccountsRegistrators: {[name: string]: number} = {};137138      // cross-reference every account for changes139      for (const [key, value] of identitiesOnRelay) {140        const encodedKey = encodeAddress(key, ss58Format);141142        // only update if the identity info does not exist or is changed143        const identity = paraIdentities.find(i => i[0] === encodedKey);144        if (identity) {145          const registratorId = identity[1].judgements[0][0];146          paraAccountsRegistrators[encodedKey] = registratorId;147          if (isCurrentChainDataPriority(helper, registratorId, value.judgements[0][0])148            || JSON.stringify(value.info) === JSON.stringify(identity[1].info)) {149            continue;150          }151        }152153        identitiesToAdd.push([key, value]);154        // exercise caution - in case we have an identity and the realy doesn't, it might mean one of two things:155        // 1) it was deleted on the relay;156        // 2) it is our own identity, we don't want to delete it.157        // identitiesToRemove.push((key as any).toHuman()[0]);158      }159160      if (identitiesToRemove.length != 0)161        await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [identitiesToRemove]);162      if (identitiesToAdd.length != 0)163        await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identitiesToAdd]);164165      console.log(`Tried to upload ${identitiesToAdd.length} identities`166        + ` and found ${identitiesToRemove.length} identities for potential removal.`167        + ` Now there are ${(await helper.getApi().query.identity.identityOf.keys()).length}.`);168169      // fill sub-identities170      const paraSubs = await getSubs(helper);171      const supersOfSubs = await getSupers(helper);172      const subsToUpdate: any[] = [];173174      for (const [key, value] of subsOnRelay) {175        const encodedKey = encodeAddress(key, ss58Format);176        const sub = paraSubs.find(i => i[0] === encodedKey);177        if (sub) {178          // only update if the sub-identity info does not exist or is changed179          if (isCurrentChainDataPriority(helper, paraAccountsRegistrators[encodedKey], relaySS58Prefix)180            || JSON.stringify(value) === JSON.stringify(constructSubInfo(sub[0], sub[1], supersOfSubs)[1])) {181            continue;182          }183        } else if (value[1].length == 0)184          continue;185186        subsToUpdate.push([key, value]);187      }188189      if (subsToUpdate.length != 0)190        await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsToUpdate]);191192      console.log(`Also tried to update ${subsToUpdate.length} identities with their sub-identities.`193        + ` Now there are ${(await helper.getApi().query.identity.subsOf.keys()).length} identities with subs.`);194    } catch (error) {195      console.error(error);196      throw Error('Error during setting identities');197    }198  }, paraUrl);199};200201if (process.argv[1] === module.filename)202  forceInsertIdentities().catch(() => process.exit(1));
after · tests/src/util/identitySetter.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.03//4// Pulls identities and sub-identities from a chain and then makes a preimage to later force upload them into another.5// Only changed or previously non-existent data are inserted.6//7// Usage: `yarn setIdentities [relay WS URL] [parachain WS URL] [user key]8// Example: `yarn setIdentities wss://polkadot-rpc.dwellir.com ws://localhost:9944 escape pattern miracle train sudden cart adapt embark wedding alien lamp mesh`910import {encodeAddress} from '@polkadot/keyring';11import {IKeyringPair} from '@polkadot/types/types';12import {usingPlaygrounds, Pallets} from './index';13import {ChainHelperBase} from './playgrounds/unique';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}4647// whether the existing chain data is more important than the coming48function isCurrentChainDataPriority(helper: ChainHelperBase, currentChainId: number | undefined, relayChainId: number) {49  if (!currentChainId) return false;50  // information has come from local chain, and is automatically superior51  if (currentChainId == helper.chain.getChainProperties().ss58Format) return true;52  // the lower the id, the more important it is (Polkadot has ss58 prefix = 0, Kusama has ss58 prefix = 2)53  return currentChainId < relayChainId;54}5556// construct an object with all data necessary for insertion from storage query results57export 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}9697// The utility for pulling identity and sub-identity data98const 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      // iterate over every identity107      for(const [key, value] of await getIdentities(helper, (key, _value) => identitiesToRemove.push((key as any).toHuman()[0]))) {108        // if any of the judgements resulted in a good confirmed outcome, keep this identity109        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        // replace the registrator id with the relay chain's ss58 format116        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      // iterate over every sub-identity124      for(const [key, value] of await getSubs(helper)) {125        // only get subs of the identities interesting to us126        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      // mark the rest of sub-identities for deletion with empty arrays133      /*for(const [account, _identity] of sublessIdentities) {134        subsOnRelay.push([account, ['0', []]]);135      }*/136    } 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      // cross-reference every account for changes154      for (const [key, value] of identitiesOnRelay) {155        const encodedKey = encodeAddress(key, ss58Format);156157        // only update if the identity info does not exist or is changed158        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        // exercise caution - in case we have an identity and the realy doesn't, it might mean one of two things:170        // 1) it was deleted on the relay;171        // 2) it is our own identity, we don't want to delete it.172        // identitiesToRemove.push((key as any).toHuman()[0]);173      }174175      console.log(identitiesToAdd[0][1]);176177      if (identitiesToRemove.length != 0)178        await uploadPreimage(179          helper,180          preimageMaker,181          helper.constructApiCall('api.tx.identity.forceRemoveIdentities', [identitiesToRemove]).method.toHex(),182        );183      if (identitiesToAdd.length != 0)184        await uploadPreimage(185          helper,186          preimageMaker,187          helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex(),188        );189190      console.log(`Tried to push ${identitiesToAdd.length} identities`191        + ` and found ${identitiesToRemove.length} identities for potential removal.`192        + ` Currently there are ${(await helper.getApi().query.identity.identityOf.keys()).length} identities on the chain.`);193194      // fill sub-identities195      const paraSubs = await getSubs(helper);196      const supersOfSubs = await getSupers(helper);197      const subsToUpdate: any[] = [];198199      for (const [key, value] of subsOnRelay) {200        const encodedKey = encodeAddress(key, ss58Format);201        const sub = paraSubs.find(i => i[0] === encodedKey);202        if (sub) {203          // only update if the sub-identity info does not exist or is changed204          if (isCurrentChainDataPriority(helper, paraAccountsRegistrators[encodedKey], relaySS58Prefix)205            || JSON.stringify(value) === JSON.stringify(constructSubInfo(sub[0], sub[1], supersOfSubs)[1])) {206            continue;207          }208        } else if (value[1].length == 0)209          continue;210211        subsToUpdate.push([key, value]);212      }213214      if (subsToUpdate.length != 0)215        await uploadPreimage(216          helper,217          preimageMaker,218          helper.constructApiCall('api.tx.identity.forceSetSubs', [subsToUpdate]).method.toHex(),219        );220221      console.log(`Also tried to push ${subsToUpdate.length} identities with their sub-identities.`222        + ` Currently there are ${(await helper.getApi().query.identity.subsOf.keys()).length} identities with subs.`);223    } catch (error) {224      console.error(error);225      throw Error('Error during setting identities');226    }227  }, paraUrl);228};229230if (process.argv[1] === module.filename)231  forceInsertIdentities().catch(() => process.exit(1));