@freedomofpress/cometbft 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/auto-bump.yml +81 -0
- package/.github/workflows/publish.yml +60 -0
- package/.github/workflows/test.yml +56 -0
- package/Readme.md +54 -0
- package/buf.gen.yaml +12 -0
- package/buf.yaml +4 -0
- package/dist/.gitkeep +0 -0
- package/eslint.config.js +31 -0
- package/localnet.sh +219 -0
- package/package.json +39 -0
- package/src/commit.ts +210 -0
- package/src/encoding.ts +37 -0
- package/src/lightclient.ts +214 -0
- package/src/tests/commit.test.ts +278 -0
- package/src/tests/encoding.test.ts +45 -0
- package/src/tests/fixtures/commit-12.json +64 -0
- package/src/tests/fixtures/validators-12.json +41 -0
- package/src/tests/fixtures/webcat.json +71 -0
- package/src/tests/lightclient.test.ts +317 -0
- package/src/tests/validators.test.ts +238 -0
- package/src/tests/webcat.test.ts +114 -0
- package/src/types.ts +63 -0
- package/src/validators.ts +84 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: Auto Bump Dependencies
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 4 * * *"
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
auto-bump:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
pull-requests: write
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: 20
|
|
23
|
+
|
|
24
|
+
- name: Install npm-check-updates
|
|
25
|
+
run: npm install -g npm-check-updates
|
|
26
|
+
|
|
27
|
+
- name: Bump dependencies
|
|
28
|
+
run: |
|
|
29
|
+
ncu -u --peer
|
|
30
|
+
# ncu -u --reject '/^typescript$/'
|
|
31
|
+
|
|
32
|
+
- name: Setup Buf
|
|
33
|
+
uses: bufbuild/buf-setup-action@v1
|
|
34
|
+
with:
|
|
35
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
36
|
+
# buf_token: ${{ secrets.BUF_TOKEN }} # uncomment if you need auth to buf.build
|
|
37
|
+
|
|
38
|
+
- name: Cache Buf modules
|
|
39
|
+
uses: actions/cache@v4
|
|
40
|
+
with:
|
|
41
|
+
path: ~/.cache/buf
|
|
42
|
+
key: ${{ runner.os }}-buf-${{ hashFiles('buf.yaml', 'buf.gen.yaml', 'buf.lock') }}
|
|
43
|
+
restore-keys: |
|
|
44
|
+
${{ runner.os }}-buf-
|
|
45
|
+
|
|
46
|
+
- name: Generate protobufs
|
|
47
|
+
run: npm run proto:gen
|
|
48
|
+
|
|
49
|
+
- name: Install updated deps
|
|
50
|
+
run: npm install
|
|
51
|
+
|
|
52
|
+
- name: Run npm audit fix
|
|
53
|
+
run: npm audit fix || true
|
|
54
|
+
|
|
55
|
+
- name: Commit changes (bump + audit fix)
|
|
56
|
+
run: |
|
|
57
|
+
git config user.name "github-actions[bot]"
|
|
58
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
59
|
+
git add package.json package-lock.json
|
|
60
|
+
git diff --cached --quiet || git commit -m "chore: bump dependencies and apply audit fix"
|
|
61
|
+
continue-on-error: true
|
|
62
|
+
|
|
63
|
+
- name: Run tests on updated deps
|
|
64
|
+
id: test
|
|
65
|
+
run: npm test
|
|
66
|
+
continue-on-error: true
|
|
67
|
+
|
|
68
|
+
- name: If tests pass, push to main
|
|
69
|
+
if: steps.test.outcome == 'success'
|
|
70
|
+
run: git push origin HEAD:main
|
|
71
|
+
|
|
72
|
+
- name: If tests fail, create PR
|
|
73
|
+
if: steps.test.outcome == 'failure'
|
|
74
|
+
uses: peter-evans/create-pull-request@v5
|
|
75
|
+
with:
|
|
76
|
+
branch: bump-deps-failed
|
|
77
|
+
title: "chore: bump dependencies and audit fix (tests failed)"
|
|
78
|
+
body: |
|
|
79
|
+
Dependencies were updated and `npm audit fix` was run, but tests failed.
|
|
80
|
+
Please investigate and merge manually.
|
|
81
|
+
commit-message: "chore: bump dependencies and audit fix (tests failed)"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: Publish Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
run-tests:
|
|
10
|
+
uses: ./.github/workflows/test.yml
|
|
11
|
+
|
|
12
|
+
publish:
|
|
13
|
+
needs: run-tests
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
|
|
16
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
packages: write
|
|
21
|
+
id-token: write
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: 20
|
|
29
|
+
registry-url: "https://registry.npmjs.org"
|
|
30
|
+
|
|
31
|
+
- name: Update npm
|
|
32
|
+
run: npm install -g npm@latest
|
|
33
|
+
|
|
34
|
+
- name: Install deps
|
|
35
|
+
run: npm ci
|
|
36
|
+
|
|
37
|
+
- name: Setup Buf
|
|
38
|
+
uses: bufbuild/buf-setup-action@v1
|
|
39
|
+
with:
|
|
40
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
+
|
|
42
|
+
- name: Cache Buf modules
|
|
43
|
+
uses: actions/cache@v4
|
|
44
|
+
with:
|
|
45
|
+
path: ~/.cache/buf
|
|
46
|
+
key: ${{ runner.os }}-buf-${{ hashFiles('buf.yaml', 'buf.gen.yaml', 'buf.lock') }}
|
|
47
|
+
restore-keys: |
|
|
48
|
+
${{ runner.os }}-buf-
|
|
49
|
+
|
|
50
|
+
- name: Generate protobufs
|
|
51
|
+
run: npm run proto:gen
|
|
52
|
+
|
|
53
|
+
- name: Build
|
|
54
|
+
run: npm run build
|
|
55
|
+
|
|
56
|
+
- name: Dry-run publish
|
|
57
|
+
run: npm publish --dry-run
|
|
58
|
+
|
|
59
|
+
- name: Publish to npm
|
|
60
|
+
run: npm publish --access public
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Lint, Test, Proto Gen and Coverage
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
workflow_call:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint-test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: 20
|
|
23
|
+
cache: npm
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm ci
|
|
27
|
+
|
|
28
|
+
- name: Run ESLint
|
|
29
|
+
run: npm run lint
|
|
30
|
+
|
|
31
|
+
- name: Setup Buf
|
|
32
|
+
uses: bufbuild/buf-setup-action@v1
|
|
33
|
+
with:
|
|
34
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
35
|
+
|
|
36
|
+
- name: Cache Buf modules
|
|
37
|
+
uses: actions/cache@v4
|
|
38
|
+
with:
|
|
39
|
+
path: ~/.cache/buf
|
|
40
|
+
key: ${{ runner.os }}-buf-${{ hashFiles('buf.yaml', 'buf.gen.yaml', 'buf.lock') }}
|
|
41
|
+
restore-keys: |
|
|
42
|
+
${{ runner.os }}-buf-
|
|
43
|
+
|
|
44
|
+
- name: Generate protobufs
|
|
45
|
+
run: npm run proto:gen
|
|
46
|
+
|
|
47
|
+
- name: Ensure generated code is up to date
|
|
48
|
+
run: |
|
|
49
|
+
if ! git diff --quiet; then
|
|
50
|
+
echo "Generated protobufs are not up-to-date. Run 'npm run proto:gen' and commit the changes."
|
|
51
|
+
git --no-pager diff
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
- name: Run tests
|
|
56
|
+
run: npm run test
|
package/Readme.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# cometbft-ts
|
|
2
|
+
|
|
3
|
+
_Note: this library has not been audited, thus its security has not been independently verified._
|
|
4
|
+
|
|
5
|
+
`cometbft-ts` is a small TypeScript library for verifying CometBFT commits in the browser. It takes the JSON you get from CometBFT ABCI/RPC for a `commit` and its `validators`, constructs canonical sign-bytes via protobuf, and verifies Ed25519 signatures and >2/3 quorum. It is verification-only and throws on any cryptographic or format error. It uses the native [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). The library is developed as part of [WEBCAT](https://github.com/freedomofpress/webcat) and is **not audited**.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { importCommit } from "./src/commit";
|
|
11
|
+
import { importValidators } from "./src/validators";
|
|
12
|
+
import { verifyCommit } from "./src/lightclient";
|
|
13
|
+
|
|
14
|
+
// JSON from CometBFT RPC: /commit and /validators
|
|
15
|
+
const sh = importCommit(commitJson);
|
|
16
|
+
const { proto: vset, cryptoIndex } = await importValidators(validatorsJson);
|
|
17
|
+
|
|
18
|
+
const result = await verifyCommit(sh, vset, cryptoIndex);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Tests
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
$ npm run coverage
|
|
25
|
+
|
|
26
|
+
> cometbft@0.1.0 coverage
|
|
27
|
+
> vitest run --coverage
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
RUN v3.2.4 /Users/g/cometbft-ts
|
|
31
|
+
Coverage enabled with v8
|
|
32
|
+
|
|
33
|
+
✓ src/tests/encoding.test.ts (6 tests) 2ms
|
|
34
|
+
✓ src/tests/commit.test.ts (27 tests) 7ms
|
|
35
|
+
✓ src/tests/validators.test.ts (18 tests) 13ms
|
|
36
|
+
✓ src/tests/lightclient.test.ts (19 tests) 11ms
|
|
37
|
+
|
|
38
|
+
Test Files 4 passed (4)
|
|
39
|
+
Tests 70 passed (70)
|
|
40
|
+
Start at 20:45:26
|
|
41
|
+
Duration 377ms (transform 133ms, setup 0ms, collect 222ms, tests 33ms, environment 0ms, prepare 241ms)
|
|
42
|
+
|
|
43
|
+
% Coverage report from v8
|
|
44
|
+
----------------|---------|----------|---------|---------|-------------------
|
|
45
|
+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
46
|
+
----------------|---------|----------|---------|---------|-------------------
|
|
47
|
+
All files | 100 | 100 | 100 | 100 |
|
|
48
|
+
commit.ts | 100 | 100 | 100 | 100 |
|
|
49
|
+
encoding.ts | 100 | 100 | 100 | 100 |
|
|
50
|
+
lightclient.ts | 100 | 100 | 100 | 100 |
|
|
51
|
+
types.ts | 0 | 0 | 0 | 0 |
|
|
52
|
+
validators.ts | 100 | 100 | 100 | 100 |
|
|
53
|
+
----------------|---------|----------|---------|---------|-------------------
|
|
54
|
+
```
|
package/buf.gen.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
version: v1
|
|
2
|
+
plugins:
|
|
3
|
+
- plugin: buf.build/community/stephenh-ts-proto:v2.6.1
|
|
4
|
+
out: src/proto
|
|
5
|
+
opt:
|
|
6
|
+
- env=browser
|
|
7
|
+
- esModuleInterop=true
|
|
8
|
+
- useOptionals=messages
|
|
9
|
+
- forceLong=bigint
|
|
10
|
+
- snakeToCamel=true
|
|
11
|
+
- outputServices=none
|
|
12
|
+
- useDate=false
|
package/buf.yaml
ADDED
package/dist/.gitkeep
ADDED
|
File without changes
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
|
2
|
+
import * as tseslint from "typescript-eslint";
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
...tseslint.configs.recommended,
|
|
6
|
+
|
|
7
|
+
{
|
|
8
|
+
files: ["**/*.{js,ts}"],
|
|
9
|
+
languageOptions: {
|
|
10
|
+
ecmaVersion: 2022,
|
|
11
|
+
sourceType: "module",
|
|
12
|
+
},
|
|
13
|
+
plugins: {
|
|
14
|
+
"simple-import-sort": simpleImportSort,
|
|
15
|
+
},
|
|
16
|
+
rules: {
|
|
17
|
+
"simple-import-sort/imports": "error",
|
|
18
|
+
"simple-import-sort/exports": "error",
|
|
19
|
+
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
20
|
+
"@typescript-eslint/no-unused-vars": [
|
|
21
|
+
"error",
|
|
22
|
+
{
|
|
23
|
+
argsIgnorePattern: "^_",
|
|
24
|
+
varsIgnorePattern: "^_",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
|
|
28
|
+
"no-delete-var": "off",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
];
|
package/localnet.sh
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# ===================== config =====================
|
|
5
|
+
COMETBFT_BIN="${COMETBFT_BIN:-cometbft}" # path to cometbft binary
|
|
6
|
+
HOME_ROOT="${HOME_ROOT:-./mytestnet}"
|
|
7
|
+
NODES=4
|
|
8
|
+
|
|
9
|
+
# base ports (node0 uses these; others add STEP)
|
|
10
|
+
RPC_BASE=26657
|
|
11
|
+
P2P_BASE=26656
|
|
12
|
+
PPROF_BASE=6060
|
|
13
|
+
STEP=3
|
|
14
|
+
|
|
15
|
+
node_home() { echo "${HOME_ROOT}/node$1"; }
|
|
16
|
+
rpc_port() { echo $((RPC_BASE + ($1 * STEP))); }
|
|
17
|
+
p2p_port() { echo $((P2P_BASE + ($1 * STEP))); }
|
|
18
|
+
pprof_port(){ echo $((PPROF_BASE+ ($1 * STEP))); }
|
|
19
|
+
|
|
20
|
+
die() { echo "error: $*" >&2; exit 1; }
|
|
21
|
+
has() { command -v "$1" >/dev/null 2>&1; }
|
|
22
|
+
|
|
23
|
+
# ===================== portable sed =====================
|
|
24
|
+
# GNU vs BSD sed inline edit
|
|
25
|
+
sedi() {
|
|
26
|
+
if sed --version >/dev/null 2>&1; then
|
|
27
|
+
sed -i -e "$@"
|
|
28
|
+
else
|
|
29
|
+
sed -i '' -e "$@"
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# set TOML key within a section [section]; quoted value
|
|
34
|
+
toml_set_q() {
|
|
35
|
+
local file="$1" section="$2" key="$3" value="$4"
|
|
36
|
+
sedi "/^\[${section}\]\$/,/^\[/{ s|^${key}[[:space:]]*=.*$|${key} = \"${value}\"|; }" "$file"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# set TOML key within a section [section]; raw (booleans/numbers)
|
|
40
|
+
toml_set_raw() {
|
|
41
|
+
local file="$1" section="$2" key="$3" value="$4"
|
|
42
|
+
sedi "/^\[${section}\]\$/,/^\[/{ s|^${key}[[:space:]]*=.*$|${key} = ${value}|; }" "$file"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# ===================== generation & patching =====================
|
|
46
|
+
ensure_tools() {
|
|
47
|
+
has "$COMETBFT_BIN" || die "cometbft not found; set COMETBFT_BIN or add to PATH"
|
|
48
|
+
has curl || die "curl required"
|
|
49
|
+
has jq || die "jq required (brew install jq)"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
gen_testnet() {
|
|
53
|
+
# nuke old, generate, THEN make logs/run dirs so they survive
|
|
54
|
+
rm -rf "$HOME_ROOT"
|
|
55
|
+
"$COMETBFT_BIN" testnet --v "$NODES" --o "$HOME_ROOT" >/dev/null
|
|
56
|
+
mkdir -p "${HOME_ROOT}/_logs" "${HOME_ROOT}/_run"
|
|
57
|
+
echo "Generated ${NODES}-node testnet in $HOME_ROOT"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
patch_node_config() {
|
|
61
|
+
local i="$1"
|
|
62
|
+
local cfg="$(node_home "$i")/config/config.toml"
|
|
63
|
+
|
|
64
|
+
toml_set_q "$cfg" rpc laddr "tcp://127.0.0.1:$(rpc_port "$i")"
|
|
65
|
+
toml_set_q "$cfg" p2p laddr "tcp://127.0.0.1:$(p2p_port "$i")"
|
|
66
|
+
toml_set_q "$cfg" instrumentation pprof_laddr "localhost:$(pprof_port "$i")"
|
|
67
|
+
|
|
68
|
+
# localhost-friendly P2P
|
|
69
|
+
toml_set_raw "$cfg" p2p addr_book_strict false
|
|
70
|
+
toml_set_raw "$cfg" p2p allow_duplicate_ip true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
wire_peers() {
|
|
74
|
+
# gather ids
|
|
75
|
+
local -a ids
|
|
76
|
+
for i in $(seq 0 $((NODES-1))); do
|
|
77
|
+
ids[$i]=$("$COMETBFT_BIN" show-node-id --home "$(node_home "$i")")
|
|
78
|
+
done
|
|
79
|
+
# set persistent_peers (everyone else)
|
|
80
|
+
for i in $(seq 0 $((NODES-1))); do
|
|
81
|
+
local peers=""
|
|
82
|
+
for j in $(seq 0 $((NODES-1))); do
|
|
83
|
+
[ "$i" -eq "$j" ] && continue
|
|
84
|
+
local addr="${ids[$j]}@127.0.0.1:$(p2p_port "$j")"
|
|
85
|
+
peers="${peers:+$peers,}$addr"
|
|
86
|
+
done
|
|
87
|
+
toml_set_q "$(node_home "$i")/config/config.toml" p2p persistent_peers "$peers"
|
|
88
|
+
done
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# ===================== lifecycle =====================
|
|
92
|
+
start_nodes() {
|
|
93
|
+
for i in $(seq 0 $((NODES-1))); do
|
|
94
|
+
local home log pidfile
|
|
95
|
+
home="$(node_home "$i")"
|
|
96
|
+
log="${HOME_ROOT}/_logs/node${i}.log"
|
|
97
|
+
pidfile="${HOME_ROOT}/_run/node${i}.pid"
|
|
98
|
+
|
|
99
|
+
if [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
|
|
100
|
+
echo "node${i} already running (pid $(cat "$pidfile"))"
|
|
101
|
+
continue
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
echo "Starting node${i} (RPC :$(rpc_port "$i"), P2P :$(p2p_port "$i")) ..."
|
|
105
|
+
nohup "$COMETBFT_BIN" node \
|
|
106
|
+
--home "$home" \
|
|
107
|
+
--proxy_app=persistent_kvstore \
|
|
108
|
+
>"$log" 2>&1 &
|
|
109
|
+
echo $! >"$pidfile"
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
# wait for RPC to be responsive
|
|
113
|
+
for i in $(seq 0 $((NODES-1))); do
|
|
114
|
+
local port; port=$(rpc_port "$i")
|
|
115
|
+
printf "Waiting for node%s RPC :%s " "$i" "$port"
|
|
116
|
+
for _ in $(seq 1 60); do
|
|
117
|
+
if curl -sf "http://127.0.0.1:${port}/status" >/dev/null; then
|
|
118
|
+
echo "✓"
|
|
119
|
+
break
|
|
120
|
+
fi
|
|
121
|
+
sleep 0.2; printf "."
|
|
122
|
+
done
|
|
123
|
+
echo
|
|
124
|
+
if ! curl -sf "http://127.0.0.1:${port}/status" >/dev/null; then
|
|
125
|
+
echo "node${i} failed to start; last 50 log lines:"
|
|
126
|
+
tail -n 50 "${HOME_ROOT}/_logs/node${i}.log" || true
|
|
127
|
+
exit 1
|
|
128
|
+
fi
|
|
129
|
+
done
|
|
130
|
+
echo "All nodes up."
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
stop_nodes() {
|
|
134
|
+
local any=0
|
|
135
|
+
for i in $(seq 0 $((NODES-1))); do
|
|
136
|
+
local pidfile="${HOME_ROOT}/_run/node${i}.pid"
|
|
137
|
+
if [ -f "$pidfile" ]; then
|
|
138
|
+
local pid; pid="$(cat "$pidfile")"
|
|
139
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
140
|
+
echo "Stopping node${i} (pid $pid)"
|
|
141
|
+
kill "$pid" || true
|
|
142
|
+
any=1
|
|
143
|
+
fi
|
|
144
|
+
rm -f "$pidfile"
|
|
145
|
+
fi
|
|
146
|
+
done
|
|
147
|
+
[ "$any" -eq 0 ] && echo "No nodes appeared to be running."
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
status_nodes() {
|
|
151
|
+
for i in $(seq 0 $((NODES-1))); do
|
|
152
|
+
local pidfile="${HOME_ROOT}/_run/node${i}.pid"
|
|
153
|
+
local state="stopped"
|
|
154
|
+
if [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
|
|
155
|
+
state="RUNNING (pid $(cat "$pidfile"))"
|
|
156
|
+
fi
|
|
157
|
+
local port; port=$(rpc_port "$i")
|
|
158
|
+
local h="n/a"
|
|
159
|
+
if curl -sf "http://127.0.0.1:${port}/status" >/dev/null 2>&1; then
|
|
160
|
+
h=$(curl -s "http://127.0.0.1:${port}/status" | jq -r .result.sync_info.latest_block_height)
|
|
161
|
+
fi
|
|
162
|
+
echo "node${i}: ${state}, RPC :$port, height=${h}"
|
|
163
|
+
done
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
logs_node() {
|
|
167
|
+
local i="${1:-0}"
|
|
168
|
+
tail -f "${HOME_ROOT}/_logs/node${i}.log"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
clean_all() {
|
|
172
|
+
stop_nodes || true
|
|
173
|
+
rm -rf "$HOME_ROOT"
|
|
174
|
+
echo "Cleaned $HOME_ROOT"
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
send_tx() {
|
|
178
|
+
local port="${1:-26657}"
|
|
179
|
+
local data="${2:-a=1}"
|
|
180
|
+
curl -s "http://127.0.0.1:${port}/broadcast_tx_commit?tx=\"${data}\"" | jq .
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
snapshot() {
|
|
184
|
+
local port="${1:-26657}"
|
|
185
|
+
local H="${2:-$(curl -s 127.0.0.1:${port}/status | jq -r .result.sync_info.latest_block_height)}"
|
|
186
|
+
curl -s "http://127.0.0.1:${port}/commit?height=${H}" > "commit-${H}.json"
|
|
187
|
+
curl -s "http://127.0.0.1:${port}/validators?height=${H}" > "validators-${H}.json"
|
|
188
|
+
echo "Wrote commit-${H}.json and validators-${H}.json"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# ===================== CLI =====================
|
|
192
|
+
case "${1:-}" in
|
|
193
|
+
start)
|
|
194
|
+
ensure_tools
|
|
195
|
+
gen_testnet
|
|
196
|
+
for i in $(seq 0 $((NODES-1))); do patch_node_config "$i"; done
|
|
197
|
+
wire_peers
|
|
198
|
+
start_nodes
|
|
199
|
+
;;
|
|
200
|
+
stop) stop_nodes ;;
|
|
201
|
+
status) status_nodes ;;
|
|
202
|
+
logs) logs_node "${2:-0}" ;;
|
|
203
|
+
clean) clean_all ;;
|
|
204
|
+
tx) send_tx "${2:-26657}" "${3:-a=1}" ;;
|
|
205
|
+
snapshot) snapshot "${2:-26657}" "${3:-}" ;;
|
|
206
|
+
*)
|
|
207
|
+
cat <<EOF
|
|
208
|
+
Usage: $0 {start|stop|status|logs [i]|clean|tx [rpc_port [kv]]|snapshot [rpc_port [height]]}
|
|
209
|
+
|
|
210
|
+
start Generate & start 4-node localhost net (in-process kvstore)
|
|
211
|
+
stop Stop all nodes
|
|
212
|
+
status Show PID / RPC / height
|
|
213
|
+
logs [i] Tail logs for node i (default 0)
|
|
214
|
+
clean Stop & remove the testnet directory
|
|
215
|
+
tx [p d] Broadcast kv tx to RPC port p (default 26657) with data d (default "a=1")
|
|
216
|
+
snapshot [p H] Export commit-H.json and validators-H.json from RPC port p (defaults to latest)
|
|
217
|
+
EOF
|
|
218
|
+
;;
|
|
219
|
+
esac
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@freedomofpress/cometbft",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A CometBFT light client for the browser.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/freedomofpress/cometbft-ts"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/client.js",
|
|
10
|
+
"types": "dist/client.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"proto:gen": "buf generate buf.build/cometbft/cometbft --path cometbft/types/v1/types.proto --path cometbft/types/v1/canonical.proto --path cometbft/types/v1/validator.proto --path cometbft/version/v1/types.proto",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"coverage": "vitest run --coverage",
|
|
16
|
+
"lint": "npx eslint --ignore-pattern '**/*.test.ts' . --fix && npx prettier --write ."
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"cometbft",
|
|
20
|
+
"ed25519",
|
|
21
|
+
"p2p",
|
|
22
|
+
"browser",
|
|
23
|
+
"typescript"
|
|
24
|
+
],
|
|
25
|
+
"author": "Giulio B",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"homepage": "https://github.com/freedomofpress/cometbft-ts#readme",
|
|
28
|
+
"bugs": "https://github.com/freedomofpress/cometbft-ts/issues",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@vitest/coverage-v8": "^4.0.13",
|
|
31
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
32
|
+
"typescript": "^5.9.3",
|
|
33
|
+
"typescript-eslint": "^8.48.0",
|
|
34
|
+
"vitest": "^4.0.13"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@bufbuild/protobuf": "^2.10.1"
|
|
38
|
+
}
|
|
39
|
+
}
|