[internal] Fixes and Checks: separate into consistency and sanity (#3197)

* rename to sanityFix
* Infra for consistency checks and Fixes.
* Whitelist check moved to consistency check only.

Co-authored-by: Catenocrypt <catenocrypt@users.noreply.github.com>
This commit is contained in:
Adam R 2020-08-10 10:56:41 +02:00 committed by GitHub
parent c2807fad5b
commit 294d8bcb5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 250 additions and 69 deletions

View File

@ -1,9 +1,9 @@
name: Fixes and Consistency Updates - Dry run name: Fixes (sanity and consistency) - Dry run
on: on:
pull_request: pull_request:
branches: [master] branches: [master]
jobs: jobs:
fix-dryrun: fix-all-dryrun:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View File

@ -1,11 +1,11 @@
name: Fixes and Consistency Updates name: Fixes
on: on:
push: push:
# This runs on fork branches too # This runs on fork branches too
branches: [ '*' ] branches: [ '*' ]
workflow_dispatch: workflow_dispatch:
jobs: jobs:
fix: fix-all:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout (trustwallet repo, secret token) - name: Checkout (trustwallet repo, secret token)
@ -25,8 +25,12 @@ jobs:
node-version: 12 node-version: 12
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: npm ci
- name: Run fix script - name: Run fix script (trustwallet repo, sanity and consistency)
if: github.repository_owner == 'trustwallet'
run: npm run fix run: npm run fix
- name: Run fix script (fork repo, sanity only)
if: github.repository_owner != 'trustwallet'
run: npm run fix-sanity
- name: Show fix result (diff); run 'npm run fix' locally - name: Show fix result (diff); run 'npm run fix' locally
run: | run: |
git status git status
@ -42,4 +46,4 @@ jobs:
with: with:
commit_user_name: trust-wallet-merge-bot commit_user_name: trust-wallet-merge-bot
commit_user_email: mergebot@trustwallet.com commit_user_email: mergebot@trustwallet.com
commit_message: Fixes and Consistency Updates commit_message: Fixes (sanity and consistency, auto)

View File

@ -19,9 +19,11 @@ jobs:
run: npm ci run: npm ci
- name: Run scripts - name: Run scripts
run: npm run update run: npm run update
- name: Show fix result (diff); run 'npm run fix' locally - name: Show update result (diff)
if: success() if: success()
run: git status run: |
git status
git diff
- name: Run check - name: Run check
run: npm run check run: npm run check
- name: Run test - name: Run test

View File

@ -16,7 +16,7 @@ jobs:
with: with:
node-version: '12.x' node-version: '12.x'
- uses: bahmutov/npm-install@v1 - uses: bahmutov/npm-install@v1
- name: Run check - name: Run check (sanity only)
run: npm run check run: npm run check-sanity
- name: Run test - name: Run test
run: npm t run: npm t

View File

@ -6,7 +6,9 @@
"scripts": { "scripts": {
"test": "jest", "test": "jest",
"check": "ts-node ./script/main/check", "check": "ts-node ./script/main/check",
"check-sanity": "ts-node ./script/main/check-sanity",
"fix": "ts-node ./script/main/fix", "fix": "ts-node ./script/main/fix",
"fix-sanity": "ts-node ./script/main/fix-sanity",
"update": "ts-node ./script/main/update" "update": "ts-node ./script/main/update"
}, },
"repository": { "repository": {

View File

@ -5,7 +5,7 @@ import { isChecksum } from "../../script/common/eth-web3";
import { isTRC10, isTRC20 } from "../../script/action/tron"; import { isTRC10, isTRC20 } from "../../script/action/tron";
import { retrieveAssetSymbols } from "../../script/action/binance"; import { retrieveAssetSymbols } from "../../script/action/binance";
export function getChecks(): CheckStepInterface[] { export function getSanityChecks(): CheckStepInterface[] {
const cmcMap: mapTiker[] = JSON.parse(readFileSync("./pricing/coinmarketcap/mapping.json")); const cmcMap: mapTiker[] = JSON.parse(readFileSync("./pricing/coinmarketcap/mapping.json"));
return [ return [
{ {

View File

@ -1,13 +1,17 @@
import { ActionInterface, CheckStepInterface } from "../../script/action/interface"; import { ActionInterface, CheckStepInterface } from "../../script/action/interface";
import { run } from "./script"; import { run } from "./script";
import { getChecks } from "./check"; import { getSanityChecks } from "./check";
export class Coinmarketcap implements ActionInterface { export class Coinmarketcap implements ActionInterface {
getName(): string { return "Coinmarketcap mapping"; } getName(): string { return "Coinmarketcap mapping"; }
getChecks(): CheckStepInterface[] { return getChecks(); } getSanityChecks(): CheckStepInterface[] { return getSanityChecks(); }
getConsistencyChecks = null;
fix = null; sanityFix = null;
consistencyFix = null;
async update(): Promise<void> { async update(): Promise<void> {
await run(); await run();

View File

@ -101,7 +101,7 @@ async function fetchMissingImages(toFetch: any[]): Promise<string[]> {
export class BinanceAction implements ActionInterface { export class BinanceAction implements ActionInterface {
getName(): string { return "Binance chain"; } getName(): string { return "Binance chain"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Binance chain; assets must exist on chain"}, getName: () => { return "Binance chain; assets must exist on chain"},
@ -120,8 +120,12 @@ export class BinanceAction implements ActionInterface {
}, },
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
async update(): Promise<void> { async update(): Promise<void> {
// retrieve missing token images; BEP2 (bep8 not supported) // retrieve missing token images; BEP2 (bep8 not supported)

View File

@ -6,7 +6,7 @@ import { isLowerCase } from "../common/types";
export class CosmosAction implements ActionInterface { export class CosmosAction implements ActionInterface {
getName(): string { return "Cosmos chain"; } getName(): string { return "Cosmos chain"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Cosmos validator assets must have correct format"}, getName: () => { return "Cosmos validator assets must have correct format"},
@ -32,7 +32,11 @@ export class CosmosAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -68,7 +68,7 @@ async function checkAddressChecksums() {
export class EthForks implements ActionInterface { export class EthForks implements ActionInterface {
getName(): string { return "Ethereum forks"; } getName(): string { return "Ethereum forks"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
var steps: CheckStepInterface[] = []; var steps: CheckStepInterface[] = [];
ethForkChains.forEach(chain => { ethForkChains.forEach(chain => {
steps.push( steps.push(
@ -105,10 +105,14 @@ export class EthForks implements ActionInterface {
return steps; return steps;
} }
async fix(): Promise<void> { getConsistencyChecks = null;
async sanityFix(): Promise<void> {
await formatInfos(); await formatInfos();
await checkAddressChecksums(); await checkAddressChecksums();
} }
consistencyFix = null;
update = null; update = null;
} }

View File

@ -22,7 +22,7 @@ const foundChains = readDirSync(chainsPath)
export class FoldersFiles implements ActionInterface { export class FoldersFiles implements ActionInterface {
getName(): string { return "Folders and Files"; } getName(): string { return "Folders and Files"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Repository root dir"}, getName: () => { return "Repository root dir"},
@ -94,7 +94,11 @@ export class FoldersFiles implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -8,8 +8,18 @@ export interface CheckStepInterface {
// An action for a check, fix, or update, or a combination. // An action for a check, fix, or update, or a combination.
export interface ActionInterface { export interface ActionInterface {
getName(): string; getName(): string;
// return check steps for check (0, 1, or more) // return check steps for sanity check (0, 1, or more)
getChecks(): CheckStepInterface[]; getSanityChecks(): CheckStepInterface[];
fix(): Promise<void>; // return check steps for consistenct check (0, 1, or more)
getConsistencyChecks(): CheckStepInterface[];
sanityFix(): Promise<void>;
consistencyFix(): Promise<void>;
update(): Promise<void>; update(): Promise<void>;
} }
export enum FixCheckMode {
CheckSanityOnly = 1,
CheckAll,
FixSanityOnly,
FixAll
}

View File

@ -7,7 +7,7 @@ import * as bluebird from "bluebird";
export class JsonAction implements ActionInterface { export class JsonAction implements ActionInterface {
getName(): string { return "Json files"; } getName(): string { return "Json files"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Check all JSON files to have valid content"}, getName: () => { return "Check all JSON files to have valid content"},
@ -29,7 +29,11 @@ export class JsonAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -6,7 +6,7 @@ import { isLowerCase } from "../common/types";
export class KavaAction implements ActionInterface { export class KavaAction implements ActionInterface {
getName(): string { return "Kava chain"; } getName(): string { return "Kava chain"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Kava validator assets must have correct format"}, getName: () => { return "Kava validator assets must have correct format"},
@ -32,7 +32,11 @@ export class KavaAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -75,7 +75,7 @@ async function checkDownsize(chains, checkOnly: boolean): Promise<string> {
export class LogoSize implements ActionInterface { export class LogoSize implements ActionInterface {
getName(): string { return "Logo sizes"; } getName(): string { return "Logo sizes"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Check that logos are not too large"}, getName: () => { return "Check that logos are not too large"},
@ -91,10 +91,14 @@ export class LogoSize implements ActionInterface {
]; ];
} }
async fix(): Promise<void> { getConsistencyChecks = null;
async sanityFix(): Promise<void> {
const foundChains = readDirSync(chainsPath); const foundChains = readDirSync(chainsPath);
await checkDownsize(foundChains, false); await checkDownsize(foundChains, false);
} }
consistencyFix = null;
update = null; update = null;
} }

View File

@ -6,7 +6,7 @@ import { isLowerCase } from "../common/types";
export class TerraAction implements ActionInterface { export class TerraAction implements ActionInterface {
getName(): string { return "Terra chain"; } getName(): string { return "Terra chain"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Terra validator assets must have correct format"}, getName: () => { return "Terra validator assets must have correct format"},
@ -32,7 +32,11 @@ export class TerraAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -78,7 +78,7 @@ async function gen_validators_tezos() {
export class TezosAction implements ActionInterface { export class TezosAction implements ActionInterface {
getName(): string { return "Tezos"; } getName(): string { return "Tezos"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Tezos validator assets must have correct format"}, getName: () => { return "Tezos validator assets must have correct format"},
@ -96,7 +96,11 @@ export class TezosAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
async update(): Promise<void> { async update(): Promise<void> {
await gen_validators_tezos(); await gen_validators_tezos();

View File

@ -20,7 +20,7 @@ export function isTRC20(address: string): boolean {
export class TronAction implements ActionInterface { export class TronAction implements ActionInterface {
getName(): string { return "Tron chain"; } getName(): string { return "Tron chain"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Tron assets should be TRC10 or TRC20, logo of correct size"; }, getName: () => { return "Tron assets should be TRC10 or TRC20, logo of correct size"; },
@ -56,7 +56,11 @@ export class TronAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -54,13 +54,13 @@ async function checkStepList(steps: CheckStepInterface[]): Promise<number> {
return returnCode; return returnCode;
} }
async function checkActionList(actions: ActionInterface[]): Promise<number> { async function sanityCheckByActionList(actions: ActionInterface[]): Promise<number> {
console.log("Running checks..."); console.log("Running sanity checks...");
var returnCode = 0; var returnCode = 0;
await bluebird.each(actions, async (action) => { await bluebird.each(actions, async (action) => {
try { try {
if (action.getChecks) { if (action.getSanityChecks) {
const steps = action.getChecks(); const steps = action.getSanityChecks();
if (steps && steps.length > 0) { if (steps && steps.length > 0) {
console.log(` Action '${action.getName()}' has ${steps.length} check steps`); console.log(` Action '${action.getName()}' has ${steps.length} check steps`);
const ret1 = await checkStepList(steps); const ret1 = await checkStepList(steps);
@ -76,23 +76,64 @@ async function checkActionList(actions: ActionInterface[]): Promise<number> {
returnCode = 3; returnCode = 3;
} }
}); });
console.log(`All checks done, returnCode ${returnCode}`); console.log(`All sanity checks done, returnCode ${returnCode}`);
return returnCode; return returnCode;
} }
async function fixByList(actions: ActionInterface[]) { async function consistencyCheckByActionList(actions: ActionInterface[]): Promise<number> {
console.log("Running fixes..."); console.log("Running consistency checks...");
var returnCode = 0;
await bluebird.each(actions, async (action) => { await bluebird.each(actions, async (action) => {
try { try {
if (action.fix) { if (action.getConsistencyChecks) {
console.log(`Fix '${action.getName()}':`); const steps = action.getConsistencyChecks();
await action.fix(); if (steps && steps.length > 0) {
console.log(` Action '${action.getName()}' has ${steps.length} check steps`);
const ret1 = await checkStepList(steps);
if (ret1 != 0) {
returnCode = ret1;
} else {
console.log(`- ${chalk.green('✓')} Action '${action.getName()}' OK, all ${steps.length} steps`);
}
}
}
} catch (error) {
console.log(`- ${chalk.red('X')} '${action.getName()}' Caught error: ${error.message}`);
returnCode = 3;
}
});
console.log(`All consistency checks done, returnCode ${returnCode}`);
return returnCode;
}
async function sanityFixByList(actions: ActionInterface[]) {
console.log("Running sanity fixes...");
await bluebird.each(actions, async (action) => {
try {
if (action.sanityFix) {
console.log(`Sanity fix '${action.getName()}':`);
await action.sanityFix();
} }
} catch (error) { } catch (error) {
console.log(`Caught error: ${error.message}`); console.log(`Caught error: ${error.message}`);
} }
}); });
console.log("All fixes done."); console.log("All sanity fixes done.");
}
async function consistencyFixByList(actions: ActionInterface[]) {
console.log("Running consistency fixes...");
await bluebird.each(actions, async (action) => {
try {
if (action.consistencyFix) {
console.log(`Sanity fix '${action.getName()}':`);
await action.consistencyFix();
}
} catch (error) {
console.log(`Caught error: ${error.message}`);
}
});
console.log("All consistency fixes done.");
} }
async function updateByList(actions: ActionInterface[]) { async function updateByList(actions: ActionInterface[]) {
@ -110,12 +151,20 @@ async function updateByList(actions: ActionInterface[]) {
console.log("All updates done."); console.log("All updates done.");
} }
export async function checkAll(): Promise<number> { export async function sanityCheckAll(): Promise<number> {
return await checkActionList(actionList); return await sanityCheckByActionList(actionList);
} }
export async function fixAll() { export async function consistencyCheckAll(): Promise<number> {
await fixByList(actionList); return await consistencyCheckByActionList(actionList);
}
export async function sanityFixAll() {
await sanityFixByList(actionList);
}
export async function consistencyFixAll() {
await consistencyFixByList(actionList);
} }
export async function updateAll() { export async function updateAll() {

View File

@ -33,7 +33,7 @@ function isValidatorHasAllKeys(val: ValidatorModel): boolean {
export class Validators implements ActionInterface { export class Validators implements ActionInterface {
getName(): string { return "Validators"; } getName(): string { return "Validators"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
var steps = [ var steps = [
{ {
getName: () => { return "Make sure tests added for new staking chain"}, getName: () => { return "Make sure tests added for new staking chain"},
@ -94,9 +94,13 @@ export class Validators implements ActionInterface {
return steps; return steps;
} }
async fix(): Promise<void> { getConsistencyChecks = null;
async sanityFix(): Promise<void> {
formatValidators(); formatValidators();
} }
consistencyFix = null;
update = null; update = null;
} }

View File

@ -13,7 +13,7 @@ export function isWavesAddress(address: string): boolean {
export class WavesAction implements ActionInterface { export class WavesAction implements ActionInterface {
getName(): string { return "Waves chain"; } getName(): string { return "Waves chain"; }
getChecks(): CheckStepInterface[] { getSanityChecks(): CheckStepInterface[] {
return [ return [
{ {
getName: () => { return "Waves validator assets must have correct format"}, getName: () => { return "Waves validator assets must have correct format"},
@ -31,7 +31,11 @@ export class WavesAction implements ActionInterface {
]; ];
} }
fix = null; getConsistencyChecks = null;
sanityFix = null;
consistencyFix = null;
update = null; update = null;
} }

View File

@ -8,7 +8,7 @@ import {
makeUnique makeUnique
} from "../common/types"; } from "../common/types";
import { ActionInterface, CheckStepInterface } from "./interface"; import { ActionInterface, CheckStepInterface } from "./interface";
import { formatSortJson, formatUniqueSortJson } from "../common/json"; import { formatSortJson } from "../common/json";
import * as bluebird from "bluebird"; import * as bluebird from "bluebird";
async function checkUpdateWhiteBlackList(chain: string, checkOnly: boolean ): Promise<[boolean, string]> { async function checkUpdateWhiteBlackList(chain: string, checkOnly: boolean ): Promise<[boolean, string]> {
@ -55,11 +55,22 @@ async function checkUpdateWhiteBlackList(chain: string, checkOnly: boolean ): Pr
wrongMsg += `Some elements should be removed from blacklist for chain ${chain}: ${bDiff2.length} ${bDiff2[0]}\n`; wrongMsg += `Some elements should be removed from blacklist for chain ${chain}: ${bDiff2.length} ${bDiff2[0]}\n`;
} }
// additionally check for nice formatting, sorting:
const newWhiteText = formatSortJson(newWhite);
const newBlackText = formatSortJson(newBlack);
if (newWhiteText !== currentWhitelistText) {
wrongMsg += `Whitelist for chain ${chain}: not formatted nicely \n`;
}
if (newBlackText !== currentBlacklistText) {
wrongMsg += `Blacklist for chain ${chain}: not formatted nicely \n`;
}
if (wrongMsg.length > 0) { if (wrongMsg.length > 0) {
// sg wrong, may need to fix
if (!checkOnly) { if (!checkOnly) {
// update // update
writeFileSync(whitelistPath, formatSortJson(newWhite)); writeFileSync(whitelistPath, newWhiteText);
writeFileSync(blacklistPath, formatSortJson(newBlack)); writeFileSync(blacklistPath, newBlackText);
console.log(`Updated white and blacklists for chain ${chain}`); console.log(`Updated white and blacklists for chain ${chain}`);
} }
} }
@ -69,7 +80,9 @@ async function checkUpdateWhiteBlackList(chain: string, checkOnly: boolean ): Pr
export class Whitelist implements ActionInterface { export class Whitelist implements ActionInterface {
getName(): string { return "Whitelists"; } getName(): string { return "Whitelists"; }
getChecks(): CheckStepInterface[] { getSanityChecks = null;
getConsistencyChecks(): CheckStepInterface[] {
const steps: CheckStepInterface[] = []; const steps: CheckStepInterface[] = [];
chainsWithBlacklist.forEach(chain => { chainsWithBlacklist.forEach(chain => {
steps.push( steps.push(
@ -88,8 +101,9 @@ export class Whitelist implements ActionInterface {
return steps; return steps;
} }
sanityFix = null;
async fix(): Promise<void> { async consistencyFix(): Promise<void> {
await bluebird.each(chainsWithBlacklist, async (chain) => await checkUpdateWhiteBlackList(chain, false)); await bluebird.each(chainsWithBlacklist, async (chain) => await checkUpdateWhiteBlackList(chain, false));
} }

View File

@ -0,0 +1,13 @@
import { sanityCheckAll } from "../action/update-all";
export async function main() {
try {
const returnCode = await sanityCheckAll();
process.exit(returnCode);
} catch(err) {
console.error(err);
process.exit(1);
}
}
main();

View File

@ -1,13 +1,29 @@
import { checkAll } from "../action/update-all"; import { sanityCheckAll, consistencyCheckAll } from "../action/update-all";
export async function main() { export async function main() {
var returnCode: number = 0;
try { try {
const returnCode = await checkAll(); const ret1 = await sanityCheckAll();
process.exit(returnCode); if (ret1 != 0) {
returnCode = ret1;
}
} catch(err) { } catch(err) {
console.error(err); console.error(err);
process.exit(1); returnCode = 1;
} }
try {
const ret1 = await consistencyCheckAll();
if (ret1 != 0) {
returnCode = ret1;
}
} catch(err) {
console.error(err);
returnCode = 1;
}
process.exit(returnCode);
} }
main(); main();

12
script/main/fix-sanity.ts Normal file
View File

@ -0,0 +1,12 @@
import { sanityFixAll, consistencyFixAll } from "../action/update-all";
export async function main() {
try {
await sanityFixAll();
} catch(err) {
console.error(err);
process.exit(1);
}
}
main();

View File

@ -1,8 +1,15 @@
import { fixAll } from "../action/update-all"; import { sanityFixAll, consistencyFixAll } from "../action/update-all";
export async function main() { export async function main() {
try { try {
await fixAll(); await sanityFixAll();
} catch(err) {
console.error(err);
process.exit(1);
}
try {
await consistencyFixAll();
} catch(err) { } catch(err) {
console.error(err); console.error(err);
process.exit(1); process.exit(1);