Skip to content

Commit 33954ca

Browse files
authored
Harden network CLI, blob integrity, and RPC operations (#21)
1 parent 0f9a0bf commit 33954ca

25 files changed

Lines changed: 981 additions & 255 deletions

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ jobs:
3333
- name: Test network targets
3434
run: cargo test --all-targets --features net --locked
3535

36+
- name: CLI contract tests
37+
run: bash scripts/test_cli.sh
38+
39+
- name: RPC publication-gate tests
40+
run: python3 scripts/test_rpc_check.py
41+
3642
- name: Reproduce sparse conformance vectors
3743
run: |
3844
cargo run --example conformance_vectors

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@
55
*.identity
66
/boot*.anchor
77
/funding_service/target/
8-
/infra/systemd/*.service
98
/infra/ops_hosts.toml
109
/infra/.tmp_*
1110
/sample.bin
1211
/.soldeps/
1312
/artifacts/
1413
powerhouse/
15-
powerhouse-boot1.service
16-
powerhouse-boot2.service
1714
boot1.anchor
1815
boot2.anchor
1916
*.ed25519

docker-compose.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
version: "3.8"
21
services:
32
node:
43
build: .

docs/ops.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Copy the examples from `infra/systemd/` and fill in real values.
4444
The node wrappers read these files and start `/usr/local/bin/julian` using
4545
`/usr/local/bin/powerhouse-boot.sh`.
4646

47+
The deployment script installs refreshed `.env.example` files but refuses to
48+
start a node until the two live environment files already exist. This prevents
49+
an upgrade from silently replacing identities, peer addresses, or secrets.
50+
4751
Recommended production flags:
4852

4953
- `--blob-dir /var/lib/powerhouse/<node>/blobs`
@@ -138,7 +142,7 @@ Use versioned releases under `/opt/powerhouse/releases`:
138142
## 10. Blob/DA endpoints
139143

140144
- Health: `curl http://<host>:8181/healthz`
141-
- Submit: `curl -X POST http://<host>:8181/submit_blob -H 'X-Namespace: default' -H 'X-Fee: 10' --data-binary @file.bin`
145+
- Submit: `curl -X POST http://<host>:8181/submit_blob -H 'X-Namespace: default' -H 'X-Fee: 0' --data-binary @file.bin`
142146
- Commitment: `curl http://<host>:8181/commitment/default/<hash>`
143147
- Sample: `curl "http://<host>:8181/sample/default/<hash>?count=2"`
144148
- Prove storage: `curl http://<host>:8181/prove_storage/default/<hash>/0`
@@ -147,7 +151,23 @@ Use versioned releases under `/opt/powerhouse/releases`:
147151
If `--blob-auth-token` is set, add:
148152
- `Authorization: Bearer <token>` or `x-api-key: <token>`
149153

150-
## 10.1 External DA publisher (optional)
154+
Nonzero fees require a funded `X-Publisher` account and its matching
155+
`X-Publisher-Sig`; use the stake CLI to provision balances before testing fees.
156+
157+
## 10.1 JSON-RPC publication gate
158+
159+
Before publishing an EVM-compatible endpoint in ChainList, run:
160+
161+
```bash
162+
python3 scripts/check_rpc.py https://rpc.example.org --expected-chain-id 177155 --require-cors
163+
```
164+
165+
The probe requires working DNS/TLS, consistent `eth_chainId` and
166+
`net_version`, a valid latest block response, and browser CORS when requested.
167+
It is an endpoint integrity check, not a substitute for consensus-state audits.
168+
See `docs/rpc_operations.md`.
169+
170+
## 10.2 External DA publisher (optional)
151171

152172
Power-House can push DA commitments to an external API (Celestia/Ethereum-compatible
153173
gateway, or a custom relay). Configure via environment:

docs/rpc_operations.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Power-House RPC Operations
2+
3+
An RPC URL is ready for public wallets only when it serves canonical state from
4+
the same finalized network observed by every public node. A process that invents
5+
block numbers, stores balances only on one host, or acknowledges transfers
6+
before network finality must not be advertised as the chain RPC.
7+
8+
## Publication gate
9+
10+
Run the repository probe from an independent machine:
11+
12+
```bash
13+
python3 scripts/check_rpc.py \
14+
https://rpc.example.org \
15+
--expected-chain-id 177155 \
16+
--require-cors
17+
```
18+
19+
The command fails on:
20+
21+
- DNS, TCP, TLS, HTTP, or JSON decoding errors
22+
- JSON-RPC error responses or mismatched request IDs
23+
- chain ID disagreement between `eth_chainId` and `net_version`
24+
- malformed or inconsistent latest-block metadata
25+
- missing browser CORS headers when `--require-cors` is set
26+
27+
Run the probe after every RPC deployment and continuously from external
28+
monitoring. Do not update ChainList until it passes.
29+
30+
## Consensus requirements
31+
32+
A production RPC adapter must read finalized blocks, account state, and
33+
transaction results from Power-House consensus. Every write must enter the
34+
network transaction path, survive validation and quorum finality, and return
35+
the same receipt from multiple RPC replicas. Contract methods must either have
36+
a real execution engine or return a standards-compliant unsupported-method
37+
error; fabricated success responses are not acceptable.
38+
39+
## Incident response
40+
41+
If the probe fails, remove the endpoint from public discovery or return a clear
42+
maintenance response. Preserve node and reverse-proxy logs, compare finalized
43+
anchor IDs across replicas, and restore service only after DNS, TLS, chain ID,
44+
latest block, and replica state agree.

infra/systemd/powerhouse-boot1.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ PH_LOG_DIR=/var/lib/powerhouse/boot1/logs
33
PH_LISTEN=/ip4/0.0.0.0/tcp/7001
44
PH_KEY=ed25519://boot1-seed
55
PH_BLOB_DIR=/var/lib/powerhouse/boot1/blobs
6-
PH_BOOTSTRAPS="/ip4/146.190.126.101/tcp/7002/p2p/12D3KooWRLM7PJrtjRM6NZPX8vmdu4YGJa9D6aPoEnLcE1o6aKCd /ip4/146.190.126.101/tcp/7002/p2p/12D3KooWRLM7PJrtjRM6NZPX8vmdu4YGJa9D6aPoEnLcE1o6aKCd"
6+
PH_BOOTSTRAPS="/ip4/146.190.126.101/tcp/7002/p2p/12D3KooWRLM7PJrtjRM6NZPX8vmdu4YGJa9D6aPoEnLcE1o6aKCd"
77
PH_SERVICE_NAME=powerhouse-boot1
88
PH_BACKUP_SOURCES="/var/lib/powerhouse/boot1 /etc/powerhouse/blob_policy.json /etc/powerhouse/governance.json /etc/powerhouse/stake_state.json"
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[Unit]
2+
Description=Power-House JULIAN bootstrap node (boot1)
3+
After=network-online.target
4+
Wants=network-online.target
5+
StartLimitIntervalSec=120
6+
StartLimitBurst=5
7+
8+
[Service]
9+
Type=simple
10+
User=root
11+
Group=root
12+
WorkingDirectory=/var/lib/powerhouse/boot1
13+
StateDirectory=powerhouse/boot1
14+
StateDirectoryMode=0750
15+
LogsDirectory=powerhouse
16+
LogsDirectoryMode=0750
17+
Environment=RUST_LOG=info
18+
EnvironmentFile=/etc/powerhouse/powerhouse-common.env
19+
EnvironmentFile=/etc/powerhouse/powerhouse-boot1.env
20+
ExecStartPre=/usr/bin/install -d -m 0750 /var/lib/powerhouse/boot1/logs /var/lib/powerhouse/boot1/blobs
21+
ExecStart=/usr/local/bin/powerhouse-boot.sh
22+
Restart=on-failure
23+
RestartSec=5
24+
TimeoutStopSec=30
25+
KillSignal=SIGINT
26+
LimitNOFILE=65536
27+
NoNewPrivileges=true
28+
PrivateTmp=true
29+
ProtectHome=true
30+
ProtectSystem=strict
31+
ReadWritePaths=/var/lib/powerhouse/boot1 /var/log/powerhouse
32+
33+
[Install]
34+
WantedBy=multi-user.target

infra/systemd/powerhouse-boot2.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ PH_LOG_DIR=/var/lib/powerhouse/boot2/logs
33
PH_LISTEN=/ip4/0.0.0.0/tcp/7002
44
PH_KEY=ed25519://boot2-seed
55
PH_BLOB_DIR=/var/lib/powerhouse/boot2/blobs
6-
PH_BOOTSTRAPS="/ip4/137.184.33.2/tcp/7001/p2p/12D3KooWLASw1JVBdDFNATYDJMbAn69CeWieTBLxAKaN9eLEkh3q /ip4/137.184.33.2/tcp/7001/p2p/12D3KooWLASw1JVBdDFNATYDJMbAn69CeWieTBLxAKaN9eLEkh3q"
6+
PH_BOOTSTRAPS="/ip4/137.184.33.2/tcp/7001/p2p/12D3KooWLASw1JVBdDFNATYDJMbAn69CeWieTBLxAKaN9eLEkh3q"
77
PH_SERVICE_NAME=powerhouse-boot2
88
PH_BACKUP_SOURCES="/var/lib/powerhouse/boot2 /etc/powerhouse/blob_policy.json /etc/powerhouse/governance.json /etc/powerhouse/stake_state.json"
99
PH_LOG_SHIP_HOST=137.184.33.2
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[Unit]
2+
Description=Power-House JULIAN bootstrap node (boot2)
3+
After=network-online.target
4+
Wants=network-online.target
5+
StartLimitIntervalSec=120
6+
StartLimitBurst=5
7+
8+
[Service]
9+
Type=simple
10+
User=root
11+
Group=root
12+
WorkingDirectory=/var/lib/powerhouse/boot2
13+
StateDirectory=powerhouse/boot2
14+
StateDirectoryMode=0750
15+
LogsDirectory=powerhouse
16+
LogsDirectoryMode=0750
17+
Environment=RUST_LOG=info
18+
EnvironmentFile=/etc/powerhouse/powerhouse-common.env
19+
EnvironmentFile=/etc/powerhouse/powerhouse-boot2.env
20+
ExecStartPre=/usr/bin/install -d -m 0750 /var/lib/powerhouse/boot2/logs /var/lib/powerhouse/boot2/blobs
21+
ExecStart=/usr/local/bin/powerhouse-boot.sh
22+
Restart=on-failure
23+
RestartSec=5
24+
TimeoutStopSec=30
25+
KillSignal=SIGINT
26+
LimitNOFILE=65536
27+
NoNewPrivileges=true
28+
PrivateTmp=true
29+
ProtectHome=true
30+
ProtectSystem=strict
31+
ReadWritePaths=/var/lib/powerhouse/boot2 /var/log/powerhouse
32+
33+
[Install]
34+
WantedBy=multi-user.target

powerhouse-boot1.service

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)