From a706ee7b094a76e00e1e27341ed7c275b40e99cc Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Wed, 17 Jan 2024 17:46:25 -0800 Subject: [PATCH] Format + introduce CI --- .github/workflows/ci.yaml | 41 +++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 3 ++- README.md | 30 +++++++++++++++------------ account-fetch.ts | 12 +++++------ api.ts | 4 ++-- deno.lock | 43 +++++++++++++++++++++++++++++++++++++++ main.ts | 22 ++++++++++---------- main_test.ts | 8 ++++---- util.ts | 4 ++-- 9 files changed, 128 insertions(+), 39 deletions(-) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..747c685 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,41 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + check: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v3 + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + - name: "Check format" + run: deno fmt --check --ignore=interfaces + - name: "Lint" + run: deno lint --ignore=interfaces + - name: "Typecheck" + run: deno check main.ts + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v3 + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + - name: "Run unit tests" + run: deno test -A diff --git a/.vscode/settings.json b/.vscode/settings.json index 78664b2..150665f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "editor.tabSize": 2 + "editor.tabSize": 2, + "prettier.enable": false } diff --git a/README.md b/README.md index 856321c..d02a5b5 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,14 @@ A tool to migrate balances from CC2 to CC3. ### Install dependencies -The only dependency is `deno` ([installation instructions](https://docs.deno.com/runtime/manual/getting_started/installation)). +The only dependency is `deno` +([installation instructions](https://docs.deno.com/runtime/manual/getting_started/installation)). ### Run The tool has a CLI, run it using the `deno` CLI. -For example, here's running the script -with the `-h` flag to see the help page. +For example, here's running the script with the `-h` flag to see the help page. ```shell deno run -A main.ts -h @@ -36,17 +36,19 @@ Commands: help [command] - Show this help or the help of a sub-command. migrate [input-spec] - Migrate balances. If no input spec is provided, a new spec will be created with - only the migrated balances. - + only the migrated balances. ``` -(Note: `deno` runs in a sandbox, and by default will request permission to each resource used by the script as needed. The `-A` flag here allows all permissions, and effectively disables that sandbox. If you'd prefer to control exactly what external resources the script uses, just drop the `-A` flag). +(Note: `deno` runs in a sandbox, and by default will request permission to each +resource used by the script as needed. The `-A` flag here allows all +permissions, and effectively disables that sandbox. If you'd prefer to control +exactly what external resources the script uses, just drop the `-A` flag). #### Balance migration -To actually migrate the balances, use the `migrate` command. For example, -this would migrate balances from CC2 testnet and output a pretty-printed file `out.json` with the balances -(note, the output will be in the chainspec format). +To actually migrate the balances, use the `migrate` command. For example, this +would migrate balances from CC2 testnet and output a pretty-printed file +`out.json` with the balances (note, the output will be in the chainspec format). ```bash deno run -A main.ts migrate -o out.json --pretty @@ -76,9 +78,9 @@ Commands: help [command] - Show this help or the help of a sub-command. ``` -You can also pass a configuration with a list of blocked accounts and an account to -act as the holder for the funds of those blocked accounts. For example, if we have a file -`config.json` with the contents: +You can also pass a configuration with a list of blocked accounts and an account +to act as the holder for the funds of those blocked accounts. For example, if we +have a file `config.json` with the contents: ```json { @@ -89,7 +91,9 @@ act as the holder for the funds of those blocked accounts. For example, if we ha } ``` -Then if we add the `--config` (or `-c`) flag, the funds from `5DL96c7qhqyqFwV5N4ZWYdr3sFatNiB5gz5H9fbXcVPrQ4ME` will be redirected to `5EP7rG2EKSKfm8xhCsUrwEKqSZK9EWtnXZo5VwBz1pGmt7rp` in the output: +Then if we add the `--config` (or `-c`) flag, the funds from +`5DL96c7qhqyqFwV5N4ZWYdr3sFatNiB5gz5H9fbXcVPrQ4ME` will be redirected to +`5EP7rG2EKSKfm8xhCsUrwEKqSZK9EWtnXZo5VwBz1pGmt7rp` in the output: ```bash deno run -A main.ts migrate --pretty -o out.json --config config.json diff --git a/account-fetch.ts b/account-fetch.ts index e343b08..059af97 100644 --- a/account-fetch.ts +++ b/account-fetch.ts @@ -17,7 +17,7 @@ export type AccountStorageKey = { export abstract class AccountFetcher { abstract fetchAccounts( - startKey?: AccountStorageKey + startKey?: AccountStorageKey, ): Promise<[AccountStorageKey, BalanceData][]>; } @@ -30,7 +30,7 @@ export class ApiAccountFetcher extends AccountFetcher { } async fetchAccounts( - startKey?: AccountStorageKey + startKey?: AccountStorageKey, ): Promise<[AccountStorageKey, BalanceData][]> { const accounts = await this.api.query.system.account.entriesPaged< FrameSystemAccountInfo, @@ -63,7 +63,7 @@ export class ApiAccountFetcher extends AccountFetcher { }; return [mappedKey, mappedData] as const; - } + }, ); } } @@ -71,13 +71,13 @@ export class ApiAccountFetcher extends AccountFetcher { export class LocalAccountFetcher extends AccountFetcher { constructor( public accounts: [AccountStorageKey, BalanceData][], - public pageSize = 1000 + public pageSize = 1000, ) { super(); } fetchAccounts( - startKey?: AccountStorageKey + startKey?: AccountStorageKey, ): Promise<[AccountStorageKey, BalanceData][]> { if (!startKey) { return Promise.resolve(this.accounts.slice(0, this.pageSize)); @@ -88,7 +88,7 @@ export class LocalAccountFetcher extends AccountFetcher { return Promise.resolve([]); } return Promise.resolve( - this.accounts.slice(startKey.key + 1, startKey.key + 1 + this.pageSize) + this.accounts.slice(startKey.key + 1, startKey.key + 1 + this.pageSize), ); } throw new Error("Invalid startKey " + startKey); diff --git a/api.ts b/api.ts index 743e59b..d6db21d 100644 --- a/api.ts +++ b/api.ts @@ -30,7 +30,7 @@ function toEndpoint(endpoint: ApiEndpointTy): string { function makeApi( endpoint: ApiEndpointTy = KnownEndpoint.LOCAL, - initWasm = true + initWasm = true, ): Promise { const endpointUrl = toEndpoint(endpoint); return ApiPromise.create({ @@ -43,7 +43,7 @@ function makeApi( export async function withApi( endpoint: ApiEndpointTy, f: (api: ApiPromise) => Promise, - initWasm = true + initWasm = true, ): Promise { await cryptoWaitReady(); const api = await makeApi(endpoint, initWasm); diff --git a/deno.lock b/deno.lock index b137cff..96e6fce 100644 --- a/deno.lock +++ b/deno.lock @@ -1,5 +1,16 @@ { "version": "3", + "packages": { + "specifiers": { + "npm:@types/node": "npm:@types/node@18.16.19" + }, + "npm": { + "@types/node@18.16.19": { + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", + "dependencies": {} + } + } + }, "redirects": { "https://esm.sh/v135/@types/bn.js@^5/index.d.ts": "https://esm.sh/v135/@types/bn.js@5.1.5/index.d.ts", "https://esm.sh/v135/@types/json-bigint@~1.0/index.d.ts": "https://esm.sh/v135/@types/json-bigint@1.0.4/index.d.ts" @@ -11,6 +22,38 @@ "https://deno.land/std@0.196.0/console/_rle.ts": "56668d5c44f964f1b4ff93f21c9896df42d6ee4394e814db52d6d13f5bb247c7", "https://deno.land/std@0.196.0/console/unicode_width.ts": "10661c0f2eeab802d16b8b85ed8825bbc573991bbfb6affed32dc1ff994f54f9", "https://deno.land/std@0.196.0/fmt/colors.ts": "a7eecffdf3d1d54db890723b303847b6e0a1ab4b528ba6958b8f2e754cf1b3bc", + "https://deno.land/std@0.211.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", + "https://deno.land/std@0.211.0/assert/_diff.ts": "6a2d68f2c42d73a1e31818a4195f40598d672c7f02ac75c7f1b1e6789852c2bc", + "https://deno.land/std@0.211.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", + "https://deno.land/std@0.211.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", + "https://deno.land/std@0.211.0/assert/assert_almost_equals.ts": "648ea72678296a5ad86d3bbb66904335fa97de3133223f44ca4596b225cdcbef", + "https://deno.land/std@0.211.0/assert/assert_array_includes.ts": "dbb461c20681807a884ad84d873f9e4daead380859531b1e7f27fa4e8f8bf431", + "https://deno.land/std@0.211.0/assert/assert_equals.ts": "b3b33ae8a85ae22a0754c61a7486d4ae870e8938830a94f5cacecba3a9b0442a", + "https://deno.land/std@0.211.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9", + "https://deno.land/std@0.211.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769", + "https://deno.land/std@0.211.0/assert/assert_greater.ts": "8dfcf082d2bcffcaab3bd0dab48d41e41c26266529567246de47bd6864936f6d", + "https://deno.land/std@0.211.0/assert/assert_greater_or_equal.ts": "9e02ef89f32563f539f7e66556930033418728847aefcca4e3806a735b5f122e", + "https://deno.land/std@0.211.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444", + "https://deno.land/std@0.211.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2", + "https://deno.land/std@0.211.0/assert/assert_less.ts": "91a6fed705f9c39bbd683b62aa9dfc42547bc886c29f696997e681cafb886b16", + "https://deno.land/std@0.211.0/assert/assert_less_or_equal.ts": "7a3c2e554eb20aa6af9dd4a410e550bcee9e8a28102d51f5f40cb1b8d141e4e1", + "https://deno.land/std@0.211.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1", + "https://deno.land/std@0.211.0/assert/assert_not_equals.ts": "cb78bf9a4357d69673c87b634491bc6b840412c8b55efe472af9877ef6f0a29b", + "https://deno.land/std@0.211.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931", + "https://deno.land/std@0.211.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f", + "https://deno.land/std@0.211.0/assert/assert_not_strict_equals.ts": "89ba25e1da5233404ac4c01651c088759b7977c51034eefc6050fe3fc2d10c46", + "https://deno.land/std@0.211.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49", + "https://deno.land/std@0.211.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54", + "https://deno.land/std@0.211.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366", + "https://deno.land/std@0.211.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7", + "https://deno.land/std@0.211.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7", + "https://deno.land/std@0.211.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", + "https://deno.land/std@0.211.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2", + "https://deno.land/std@0.211.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c", + "https://deno.land/std@0.211.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b", + "https://deno.land/std@0.211.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd", + "https://deno.land/std@0.211.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145", + "https://deno.land/std@0.211.0/fmt/colors.ts": "be082d6a6bbb2980ae7b2bf8c23c6bb2811ba90a06a9bcb861344a71784c5a99", "https://deno.land/x/cliffy@v1.0.0-rc.3/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004", "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead", "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_errors.ts": "12d513ff401020287a344e0830e1297ce1c80c077ecb91e0ac5db44d04a6019c", diff --git a/main.ts b/main.ts index a972af4..a88f4a4 100644 --- a/main.ts +++ b/main.ts @@ -14,7 +14,7 @@ import { RateLogger, Ss58AccountId } from "./util.ts"; async function fetchAccounts( fetcher: AccountFetcher, - startKey?: AccountStorageKey + startKey?: AccountStorageKey, ) { const accounts = await fetcher.fetchAccounts(startKey); return accounts; @@ -59,7 +59,7 @@ function makeBalancesConfig(balances: BalanceMap) { async function mapBalances( fetcher: AccountFetcher, initial?: [string, bigint][], - blocked?: BlockedAccounts + blocked?: BlockedAccounts, ) { const balances: BalanceMap = new Map(initial ?? []); @@ -101,13 +101,13 @@ export async function doMigrateBalances( fetcher: AccountFetcher, inputSpec: JsonAny, config: Config, - merge = false + merge = false, ) { // map balances const mapped = await mapBalances( fetcher, merge ? inputSpec.genesis.runtime.balances.balances : undefined, - config.blocked + config.blocked, ); // put the balances into the spec's expected format @@ -130,7 +130,7 @@ type Options = { export async function migrateBalances( api: ApiPromise, options: Options, - inputSpec: JsonObject + inputSpec: JsonObject, ) { const config = options.config ? await parseConfig(options.config) : {}; const finalized = await api.rpc.chain.getFinalizedHead(); @@ -146,7 +146,7 @@ export async function migrateBalances( fetcher, inputSpec, config, - options.merge + options.merge, ); if (options.outputSpec) { @@ -154,12 +154,12 @@ export async function migrateBalances( console.log(`writing output to ${options.outputSpec}`); await Deno.writeTextFile( options.outputSpec, - jsonStringify(inputSpec, undefined, options.pretty ? 2 : undefined) + jsonStringify(inputSpec, undefined, options.pretty ? 2 : undefined), ); } else { // print the output spec console.log( - jsonStringify(inputSpec, undefined, options.pretty ? 2 : undefined) + jsonStringify(inputSpec, undefined, options.pretty ? 2 : undefined), ); } } @@ -218,14 +218,14 @@ async function main() { .command("help", new HelpCommand().global()) .command( "migrate [input-spec:string]", - "Migrate balances. If no input spec is provided, a new spec will be created with only the migrated balances." + "Migrate balances. If no input spec is provided, a new spec will be created with only the migrated balances.", ) .option( "--output-spec -o ", "Output spec file path. If omitted, output will be printed to the console", { required: false, - } + }, ) .option("-p --pretty", "Pretty print the output spec", { default: false, @@ -235,7 +235,7 @@ async function main() { "Merge balances from input spec into the result, instead of ignoring them", { default: false, - } + }, ) .option("--endpoint -e ", "Endpoint to connect to", { default: "wss://rpc.testnet.creditcoin.network/ws", diff --git a/main_test.ts b/main_test.ts index 9760058..3de6d82 100644 --- a/main_test.ts +++ b/main_test.ts @@ -1,10 +1,10 @@ import { doMigrateBalances } from "./main.ts"; import { - LocalAccountFetcher, AccountStorageKey, BalanceData, + LocalAccountFetcher, } from "./account-fetch.ts"; -import { encodeAddress, blake2AsHex } from "@polkadot/util-crypto/mod.ts"; +import { blake2AsHex, encodeAddress } from "@polkadot/util-crypto/mod.ts"; import { Ss58AccountId } from "./util.ts"; import { assertEquals } from "std/assert/mod.ts"; @@ -66,11 +66,11 @@ class AccountsBuilder { } function expected( - accounts: [AccountStorageKey, BalanceData][] + accounts: [AccountStorageKey, BalanceData][], ): [string, bigint][] { return accounts.map( ([key, { free, reserved }]) => - [key.accountId().value, free + reserved] as const + [key.accountId().value, free + reserved] as const, ); } diff --git a/util.ts b/util.ts index be8d446..aa86052 100644 --- a/util.ts +++ b/util.ts @@ -9,14 +9,14 @@ export class RateLogger { private lastCount = 0, private start = performance.now(), private count = 0, - private freq = 1000 + private freq = 1000, ) {} log() { if (this.count - this.lastCount >= this.freq) { const now = performance.now(); console.log( - `rate: ${this.count / ((now - this.start) / 1000)} ${this.itemsName}/s` + `rate: ${this.count / ((now - this.start) / 1000)} ${this.itemsName}/s`, ); this.lastCount = this.count; }