difftreelog
fix file path
in: master
1 file changed
tests/src/migrations/942057-appPromotion/lockedToFreeze.tsdiffbeforeafterboth1// import { usingApi, privateKey, onlySign } from "./../../load/lib";2import * as fs from 'fs';3import {usingPlaygrounds} from '../../util';4import path from 'path';5import {isInteger, parse} from 'lossless-json';678const WS_ENDPOINT = 'ws://localhost:9944';9const DONOR_SEED = '//Alice';10const UPDATE_IF_VERSION = 942057;1112export function customNumberParser(value: any) {13 return isInteger(value) ? BigInt(value) : parseFloat(value);14}1516export const migrateLockedToFreeze = async(options: { wsEndpoint: string; donorSeed: string } = {17 wsEndpoint: WS_ENDPOINT,18 donorSeed: DONOR_SEED,19}) => {20 await usingPlaygrounds(async (helper, privateKey) => {21 const api = helper.getApi();22 // 1. Check version equal 942057 or skip23 console.log((api.consts.system.version as any).specVersion.toNumber());24 if((api.consts.system.version as any).specVersion.toNumber() != UPDATE_IF_VERSION) {25 console.log("Version isn't 942057.");26 return;27 }2829 // 2. Get sudo signer30 const signer = await privateKey(options.donorSeed);31 console.log('2. Getting sudo:', signer.address);3233 // 3. Parse data to migrate34 console.log('3. Parsing chainql results...');35 const parsingResult = parse(fs.readFileSync(path.resolve('output.json'), 'utf-8'), undefined, customNumberParser);3637 const chainqlImportData = parsingResult as {38 address: string;39 balance: string;40 account: {41 fee_frozen: string,42 free: string,43 misc_frozen: string,44 reserved: string,45 },46 locks: {47 amount: string,48 id: string,49 }[],50 stakes: object,51 unstakes: object,52 }[];53 testChainqlData(chainqlImportData);5455 const stakers = chainqlImportData.map((i) => i.address);5657 // 3.1 Split into chunks by 10058 console.log('3.1 Splitting into chunks...');59 const stakersChunks = chunk(stakers, 100);60 console.log('3.1 Done, total chunks:', stakersChunks.length);6162 // 4. Get signer/sudo nonce63 console.log('4. Getting sudo nonce...');64 const signerAccount = (65 await api.query.system.account(signer.address)66 ).toJSON() as any;6768 let nonce: number = signerAccount.nonce;69 console.log('4. Sudo nonce is:', nonce);7071 // 5. Only sign upgradeAccounts-transactions for each chunk72 console.log('5. Signing transactions...');73 const signedTxs = [];74 for(const chunk of stakersChunks) {75 const tx = api.tx.sudo.sudo(api.tx.appPromotion.upgradeAccounts(chunk));76 const signed = tx.sign(signer, {77 blockHash: api.genesisHash,78 genesisHash: api.genesisHash,79 runtimeVersion: api.runtimeVersion,80 nonce: nonce++,81 });82 signedTxs.push(signed);83 }8485 // 6. Send all signed transactions86 console.log('6. Sending transactions...');87 const promises = signedTxs.map((tx) => api.rpc.author.submitAndWatchExtrinsic(tx));88 // 6.1 Wait all transactions settled89 console.log('6.1 Waiting all transactions settled...');90 const res = await Promise.allSettled(promises);9192 console.log('Wait 5 blocks for transactions to be included in a block...');93 await helper.wait.newBlocks(5);94 // 6.2 Filter failed transactions95 console.log('6.2 Getting failed transactions...');96 const failedTx = res.filter((r) => r.status == 'rejected') as PromiseRejectedResult[];97 console.log('6.2. total failedTxs:', failedTx.length);9899 // 6.3 Log the reasons of failed tx100 for(const tx of failedTx) {101 console.log(tx.reason);102 }103104 // 7. Check balances for 10 blocks:105 console.log('7. Check balances...');106 let blocksLeft = 10;107 let notMigrated = stakers;108 const suspiciousAccounts = [];109 do {110 console.log('blocks left:', blocksLeft);111 const _notMigrated: string[] = [];112 console.log('accounts to migrate...', notMigrated.length);113 for(const accountToMigrate of notMigrated) {114 let accountMigrated = true;115 // 7.0 get data from chainql:116 const oldAccount = chainqlImportData.find(acc => acc.address === accountToMigrate);117 if(!oldAccount) {118 console.log('Cannot find old account data for', accountMigrated);119 accountMigrated = false;120 _notMigrated.push(accountToMigrate);121 continue;122 }123124 // 7.1 system.account125 const balance = await api.query.system.account(accountToMigrate) as any;126 // new balances127 const free = balance.data.free;128 const reserved = balance.data.reserved;129 const frozen = balance.data.frozen;130 // old balances131 const oldFree = oldAccount.account.free;132 const oldReserved = oldAccount.account.reserved;133 const oldFrozen = oldAccount.account.fee_frozen;134 // asserts new = old135 if(oldFree.toString() !== free.toString()) {136 console.log('Old free !== New free, which is probably not a problem', oldFree.toString(), free.toString());137 suspiciousAccounts.push(accountToMigrate);138 }139 if(oldFrozen.toString() !== frozen.toString()) {140 console.log('Old frozen !== New frozen, which is probably not a problem', oldFrozen.toString(), frozen.toString());141 suspiciousAccounts.push(accountToMigrate);142 }143 if(oldReserved.toString() !== reserved.toString()) {144 console.log('Old reserved !== New reserved, which is probably not a problem', oldReserved.toString(), reserved.toString());145 suspiciousAccounts.push(accountToMigrate);146 }147148 // 7.2 balances.locks: no id appstake149 const locks = await helper.balance.getLocked(accountToMigrate);150 const appPromoLocks = locks.filter(lock => lock.id === 'appstake');151 if(appPromoLocks.length !== 0) {152 console.log('Account still has app-promo lock');153 accountMigrated = false;154 }155156 // 7.3 balances.freezes set...157 let freezes = await api.query.balances.freezes(accountToMigrate) as any;158 freezes = freezes.map((freez: any) => ({id: freez.id.toString(), amount: freez.amount.toString()}));159 if(!freezes) {160 console.log('Account does not have freezes');161 accountMigrated = false;162 } else {163 const oldAppPromoLocks = oldAccount.locks.filter(l => l.id === '0x6170707374616b65'); // get app promo locks164 // should be only one freez for each account165 if(freezes.length !== 1) {166 console.log('freezes.length !== 1 and old appPromoLocks.length', freezes.length, oldAppPromoLocks.length);167 accountMigrated = false;168 } else {169 const appPromoFreez = freezes[0];170 // freez-amount should be equal to migrated lock amount171 if(appPromoFreez.amount.toString() !== oldAppPromoLocks[0].amount.toString()) {172 console.log('freezes amount !== old appPromoLocks amount', appPromoFreez.amount.toString(), oldAppPromoLocks[0].amount.toString());173 accountMigrated = false;174 }175 // freez id should be correct176 if(appPromoFreez.id !== '0x6170707374616b656170707374616b65') {177 console.log('Got freez with incorrect id:', appPromoFreez.id);178 accountMigrated = false;179 }180 }181 }182183 // 7.4 Stakes number the same184 const stakesNumber = await helper.staking.getStakesNumber({Substrate: accountToMigrate});185 const oldStakesNumber = oldAccount.stakes ? Object.keys(oldAccount.stakes).length : 0;186 if(stakesNumber.toString() !== oldStakesNumber.toString()) {187 console.log('Old stakes number !== New stakes number', oldStakesNumber, stakesNumber);188 accountMigrated = false;189 }190191 // 7.5 Total pendingUnstake + total staked = old locked192 const pendingUnstakes = await helper.staking.getPendingUnstake({Substrate: accountToMigrate});193 const totalStaked = await helper.staking.getTotalStaked({Substrate: accountToMigrate});194 const totalBalanceInAppPromo = pendingUnstakes + totalStaked;195 if(totalBalanceInAppPromo.toString() !== oldAccount.balance.toString()) {196 console.log('totalBalanceInAppPromo !== old locked in app promo', totalBalanceInAppPromo.toString(), oldAccount.balance.toString());197 accountMigrated = false;198 }199200 // 8 Add to not-migrated201 if(!accountMigrated) {202 console.log('Add to not migrated:', accountToMigrate);203 _notMigrated.push(accountToMigrate);204 }205 }206207 blocksLeft--;208 notMigrated = _notMigrated;209 await helper.wait.newBlocks(1);210 } while(blocksLeft > 0 && notMigrated.length !== 0);211212 console.log('Not migrated accounts...', notMigrated.length);213 if(suspiciousAccounts.length > 0) {214 console.log('Saving suspicious accounts to suspicious.json:');215 fs.writeFileSync('./suspicious.json', JSON.stringify(suspiciousAccounts));216 }217 if(notMigrated.length > 0) {218 console.log('Saving not migrated list to failed.json:');219 notMigrated.forEach(console.log);220 fs.writeFileSync('./failed.json', JSON.stringify(notMigrated));221 process.exit(1);222 } else {223 console.log('Migration success');224 }225 }, options.wsEndpoint);226};227228const chunk = <T>(arr: T[], size: number) =>229 Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>230 arr.slice(i * size, i * size + size));231232const testChainqlData = (data: any) => {233 const wrongData = [];234 for(const account of data) {235 try {236 if(account.address == null) throw Error('no address in data');237 if(account.balance == null) throw Error('no balance in data');238 if(account.account == null) throw Error('no account in data');239 if(account.account.fee_frozen == null) throw Error('no account.fee_frozen in data');240 if(account.account.misc_frozen == null) throw Error('no account.misc_frozen in data');241 if(account.account.free == null) throw Error('no account.free in data');242 if(account.account.reserved == null) throw Error('no account.reserved in data');243 if(account.locks == null) throw Error('no locks in data');244 if(account.locks[0].amount == null) throw Error('no locks.amount in data');245 if(account.locks[0].id == null) throw Error('no locks.id in data');246 } catch (error) {247 wrongData.push(account.address);248 console.log((error as Error).message, account.address);249 }250 if(wrongData.length > 0) {251 console.log(data);252 throw Error('Chainql data not correct');253 }254 }255 console.log('Chainql data correct');256};1// import { usingApi, privateKey, onlySign } from "./../../load/lib";2import * as fs from 'fs';3import {usingPlaygrounds} from '../../util';4import path from 'path';5import {isInteger, parse} from 'lossless-json';678const WS_ENDPOINT = 'ws://localhost:9944';9const DONOR_SEED = '//Alice';10const UPDATE_IF_VERSION = 942057;1112export function customNumberParser(value: any) {13 return isInteger(value) ? BigInt(value) : parseFloat(value);14}1516export const migrateLockedToFreeze = async(options: { wsEndpoint: string; donorSeed: string } = {17 wsEndpoint: WS_ENDPOINT,18 donorSeed: DONOR_SEED,19}) => {20 await usingPlaygrounds(async (helper, privateKey) => {21 const api = helper.getApi();22 // 1. Check version equal 942057 or skip23 console.log((api.consts.system.version as any).specVersion.toNumber());24 if((api.consts.system.version as any).specVersion.toNumber() != UPDATE_IF_VERSION) {25 console.log("Version isn't 942057.");26 return;27 }2829 // 2. Get sudo signer30 const signer = await privateKey(options.donorSeed);31 console.log('2. Getting sudo:', signer.address);3233 // 3. Parse data to migrate34 console.log('3. Parsing chainql results...');35 const parsingResult = parse(fs.readFileSync(path.resolve('src', 'migrations', '942057-appPromotion', 'output.json'), 'utf-8'), undefined, customNumberParser);3637 const chainqlImportData = parsingResult as {38 address: string;39 balance: string;40 account: {41 fee_frozen: string,42 free: string,43 misc_frozen: string,44 reserved: string,45 },46 locks: {47 amount: string,48 id: string,49 }[],50 stakes: object,51 unstakes: object,52 }[];53 testChainqlData(chainqlImportData);5455 const stakers = chainqlImportData.map((i) => i.address);5657 // 3.1 Split into chunks by 10058 console.log('3.1 Splitting into chunks...');59 const stakersChunks = chunk(stakers, 100);60 console.log('3.1 Done, total chunks:', stakersChunks.length);6162 // 4. Get signer/sudo nonce63 console.log('4. Getting sudo nonce...');64 const signerAccount = (65 await api.query.system.account(signer.address)66 ).toJSON() as any;6768 let nonce: number = signerAccount.nonce;69 console.log('4. Sudo nonce is:', nonce);7071 // 5. Only sign upgradeAccounts-transactions for each chunk72 console.log('5. Signing transactions...');73 const signedTxs = [];74 for(const chunk of stakersChunks) {75 const tx = api.tx.sudo.sudo(api.tx.appPromotion.upgradeAccounts(chunk));76 const signed = tx.sign(signer, {77 blockHash: api.genesisHash,78 genesisHash: api.genesisHash,79 runtimeVersion: api.runtimeVersion,80 nonce: nonce++,81 });82 signedTxs.push(signed);83 }8485 // 6. Send all signed transactions86 console.log('6. Sending transactions...');87 const promises = signedTxs.map((tx) => api.rpc.author.submitAndWatchExtrinsic(tx));88 // 6.1 Wait all transactions settled89 console.log('6.1 Waiting all transactions settled...');90 const res = await Promise.allSettled(promises);9192 console.log('Wait 5 blocks for transactions to be included in a block...');93 await helper.wait.newBlocks(5);94 // 6.2 Filter failed transactions95 console.log('6.2 Getting failed transactions...');96 const failedTx = res.filter((r) => r.status == 'rejected') as PromiseRejectedResult[];97 console.log('6.2. total failedTxs:', failedTx.length);9899 // 6.3 Log the reasons of failed tx100 for(const tx of failedTx) {101 console.log(tx.reason);102 }103104 // 7. Check balances for 10 blocks:105 console.log('7. Check balances...');106 let blocksLeft = 10;107 let notMigrated = stakers;108 const suspiciousAccounts = [];109 do {110 console.log('blocks left:', blocksLeft);111 const _notMigrated: string[] = [];112 console.log('accounts to migrate...', notMigrated.length);113 for(const accountToMigrate of notMigrated) {114 let accountMigrated = true;115 // 7.0 get data from chainql:116 const oldAccount = chainqlImportData.find(acc => acc.address === accountToMigrate);117 if(!oldAccount) {118 console.log('Cannot find old account data for', accountMigrated);119 accountMigrated = false;120 _notMigrated.push(accountToMigrate);121 continue;122 }123124 // 7.1 system.account125 const balance = await api.query.system.account(accountToMigrate) as any;126 // new balances127 const free = balance.data.free;128 const reserved = balance.data.reserved;129 const frozen = balance.data.frozen;130 // old balances131 const oldFree = oldAccount.account.free;132 const oldReserved = oldAccount.account.reserved;133 const oldFrozen = oldAccount.account.fee_frozen;134 // asserts new = old135 if(oldFree.toString() !== free.toString()) {136 console.log('Old free !== New free, which is probably not a problem', oldFree.toString(), free.toString());137 suspiciousAccounts.push(accountToMigrate);138 }139 if(oldFrozen.toString() !== frozen.toString()) {140 console.log('Old frozen !== New frozen, which is probably not a problem', oldFrozen.toString(), frozen.toString());141 suspiciousAccounts.push(accountToMigrate);142 }143 if(oldReserved.toString() !== reserved.toString()) {144 console.log('Old reserved !== New reserved, which is probably not a problem', oldReserved.toString(), reserved.toString());145 suspiciousAccounts.push(accountToMigrate);146 }147148 // 7.2 balances.locks: no id appstake149 const locks = await helper.balance.getLocked(accountToMigrate);150 const appPromoLocks = locks.filter(lock => lock.id === 'appstake');151 if(appPromoLocks.length !== 0) {152 console.log('Account still has app-promo lock');153 accountMigrated = false;154 }155156 // 7.3 balances.freezes set...157 let freezes = await api.query.balances.freezes(accountToMigrate) as any;158 freezes = freezes.map((freez: any) => ({id: freez.id.toString(), amount: freez.amount.toString()}));159 if(!freezes) {160 console.log('Account does not have freezes');161 accountMigrated = false;162 } else {163 const oldAppPromoLocks = oldAccount.locks.filter(l => l.id === '0x6170707374616b65'); // get app promo locks164 // should be only one freez for each account165 if(freezes.length !== 1) {166 console.log('freezes.length !== 1 and old appPromoLocks.length', freezes.length, oldAppPromoLocks.length);167 accountMigrated = false;168 } else {169 const appPromoFreez = freezes[0];170 // freez-amount should be equal to migrated lock amount171 if(appPromoFreez.amount.toString() !== oldAppPromoLocks[0].amount.toString()) {172 console.log('freezes amount !== old appPromoLocks amount', appPromoFreez.amount.toString(), oldAppPromoLocks[0].amount.toString());173 accountMigrated = false;174 }175 // freez id should be correct176 if(appPromoFreez.id !== '0x6170707374616b656170707374616b65') {177 console.log('Got freez with incorrect id:', appPromoFreez.id);178 accountMigrated = false;179 }180 }181 }182183 // 7.4 Stakes number the same184 const stakesNumber = await helper.staking.getStakesNumber({Substrate: accountToMigrate});185 const oldStakesNumber = oldAccount.stakes ? Object.keys(oldAccount.stakes).length : 0;186 if(stakesNumber.toString() !== oldStakesNumber.toString()) {187 console.log('Old stakes number !== New stakes number', oldStakesNumber, stakesNumber);188 accountMigrated = false;189 }190191 // 7.5 Total pendingUnstake + total staked = old locked192 const pendingUnstakes = await helper.staking.getPendingUnstake({Substrate: accountToMigrate});193 const totalStaked = await helper.staking.getTotalStaked({Substrate: accountToMigrate});194 const totalBalanceInAppPromo = pendingUnstakes + totalStaked;195 if(totalBalanceInAppPromo.toString() !== oldAccount.balance.toString()) {196 console.log('totalBalanceInAppPromo !== old locked in app promo', totalBalanceInAppPromo.toString(), oldAccount.balance.toString());197 accountMigrated = false;198 }199200 // 8 Add to not-migrated201 if(!accountMigrated) {202 console.log('Add to not migrated:', accountToMigrate);203 _notMigrated.push(accountToMigrate);204 }205 }206207 blocksLeft--;208 notMigrated = _notMigrated;209 await helper.wait.newBlocks(1);210 } while(blocksLeft > 0 && notMigrated.length !== 0);211212 console.log('Not migrated accounts...', notMigrated.length);213 if(suspiciousAccounts.length > 0) {214 console.log('Saving suspicious accounts to suspicious.json:');215 fs.writeFileSync('./suspicious.json', JSON.stringify(suspiciousAccounts));216 }217 if(notMigrated.length > 0) {218 console.log('Saving not migrated list to failed.json:');219 notMigrated.forEach(console.log);220 fs.writeFileSync('./failed.json', JSON.stringify(notMigrated));221 process.exit(1);222 } else {223 console.log('Migration success');224 }225 }, options.wsEndpoint);226};227228const chunk = <T>(arr: T[], size: number) =>229 Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>230 arr.slice(i * size, i * size + size));231232const testChainqlData = (data: any) => {233 const wrongData = [];234 for(const account of data) {235 try {236 if(account.address == null) throw Error('no address in data');237 if(account.balance == null) throw Error('no balance in data');238 if(account.account == null) throw Error('no account in data');239 if(account.account.fee_frozen == null) throw Error('no account.fee_frozen in data');240 if(account.account.misc_frozen == null) throw Error('no account.misc_frozen in data');241 if(account.account.free == null) throw Error('no account.free in data');242 if(account.account.reserved == null) throw Error('no account.reserved in data');243 if(account.locks == null) throw Error('no locks in data');244 if(account.locks[0].amount == null) throw Error('no locks.amount in data');245 if(account.locks[0].id == null) throw Error('no locks.id in data');246 } catch (error) {247 wrongData.push(account.address);248 console.log((error as Error).message, account.address);249 }250 if(wrongData.length > 0) {251 console.log(data);252 throw Error('Chainql data not correct');253 }254 }255 console.log('Chainql data correct');256};