Skip to content

Commit

Permalink
Format + introduce CI
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanwhit committed Jan 18, 2024
1 parent 41bcb23 commit a706ee7
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 39 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"editor.tabSize": 2
"editor.tabSize": 2,
"prettier.enable": false
}
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
{
Expand All @@ -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
Expand Down
12 changes: 6 additions & 6 deletions account-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type AccountStorageKey = {

export abstract class AccountFetcher {
abstract fetchAccounts(
startKey?: AccountStorageKey
startKey?: AccountStorageKey,
): Promise<[AccountStorageKey, BalanceData][]>;
}

Expand All @@ -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,
Expand Down Expand Up @@ -63,21 +63,21 @@ export class ApiAccountFetcher extends AccountFetcher {
};

return [mappedKey, mappedData] as const;
}
},
);
}
}

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));
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function toEndpoint(endpoint: ApiEndpointTy): string {

function makeApi(
endpoint: ApiEndpointTy = KnownEndpoint.LOCAL,
initWasm = true
initWasm = true,
): Promise<ApiPromise> {
const endpointUrl = toEndpoint(endpoint);
return ApiPromise.create({
Expand All @@ -43,7 +43,7 @@ function makeApi(
export async function withApi<T>(
endpoint: ApiEndpointTy,
f: (api: ApiPromise) => Promise<T>,
initWasm = true
initWasm = true,
): Promise<T> {
await cryptoWaitReady();
const api = await makeApi(endpoint, initWasm);
Expand Down
43 changes: 43 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 ?? []);

Expand Down Expand Up @@ -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
Expand All @@ -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<BlockHash>();
Expand All @@ -146,20 +146,20 @@ export async function migrateBalances(
fetcher,
inputSpec,
config,
options.merge
options.merge,
);

if (options.outputSpec) {
// write the output spec
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),
);
}
}
Expand Down Expand Up @@ -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 <path:string>",
"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,
Expand All @@ -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:string>", "Endpoint to connect to", {
default: "wss://rpc.testnet.creditcoin.network/ws",
Expand Down
8 changes: 4 additions & 4 deletions main_test.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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,
);
}

Expand Down
4 changes: 2 additions & 2 deletions util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit a706ee7

Please sign in to comment.