Skip to content

feat(operator): DVT node-registration wizard (CC-17 / aastar-sdk#279)#424

Merged
jhfnetboy merged 4 commits into
masterfrom
feat/dvt-register-wizard
Jul 6, 2026
Merged

feat(operator): DVT node-registration wizard (CC-17 / aastar-sdk#279)#424
jhfnetboy merged 4 commits into
masterfrom
feat/dvt-register-wizard

Conversation

@jhfnetboy

Copy link
Copy Markdown
Member

What

Guided operator onboarding for DVT signing-node registration — turns the manual registerWithProof script into a 5-step wizard under app/operator/dvt-register/.

Flow: connect → eligibility → key & PoP → register → done. Reuses the existing operator deploy-wizard scaffolding (StepCard / WizardButton / WizardProgress / FormField / useTxStep) and the Track-C browser-signing path (operator's own EOA signs; no backend key).

Highlights

  • Eligibility short-circuit: operatorNode(operator) non-zero → jump to done showing the bound nodeId.
  • BLS key stays local: generated (crypto.getRandomValues) or imported in-browser, held only in in-memory wizard state — never persisted, never sent to the backend. Red warning + offline-backup prompt. nodeId previewed from the PoP before any tx.
  • SDK boundary in one file (lib/sdk/dvtOperator.ts): all chain/crypto calls funnel through it.

SDK wiring

@aastar/sdk 0.38.0 shipped buildDvtPop + dvtOperatorActions (aastar-sdk#288, E2E LIVE PASS on Sepolia). Wiring = flip DVT_SDK_READY, add the import, fill the WIRE-HERE bodies. (Done in a follow-up commit on this branch.)

Test

  • type-check + eslint green.

Coordination: CC-17.

https://claude.ai/code/session_01RajETCvboSvhadpqMbekNx

…-sdk#279)

Guided operator onboarding for DVT signing-node registration, reusing the
existing operator deploy wizard scaffolding (StepCard / WizardButton /
WizardProgress / FormField / useTxStep) and the Track-C browser-signing path.

Flow: connect -> eligibility -> key & PoP -> register -> done. The eligibility
step short-circuits to done when the operator already runs a node. The BLS
secret key is generated/imported in-browser and never persisted or sent to the
backend; nodeId is previewed from the PoP before any tx.

All chain/crypto calls sit behind lib/sdk/dvtOperator.ts, stubbed with
DVT_SDK_READY=false until @aastar/sdk 0.37.4/0.38.0 (PR #288) publishes
dvtOperatorActions + buildDvtPop. Wiring is a one-file change (flip the flag,
add the import, fill the WIRE-HERE bodies). Adds a DVT-registration entry card
to the operator hub and zh/en i18n. Also adds .goutou.json (repoId: yaaa).

Claude-Session: https://claude.ai/code/session_01RajETCvboSvhadpqMbekNx
@jhfnetboy jhfnetboy requested a review from fanhousanbu as a code owner July 6, 2026 15:15
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

…-17)

@aastar/sdk 0.38.0 ships buildDvtPop + dvtOperatorActions + DVT_VALIDATOR_ADDRESS
(aastar-sdk#288, on-chain registerWithProof E2E LIVE PASS on Sepolia, tx
0x216a7ed5…, Codex APPROVE). Fill in the lib/sdk/dvtOperator.ts boundary:

- flip DVT_SDK_READY, drop the pending-stub scaffolding
- buildDvtPop -> sdk buildDvtPop; eligibility/register/isRegistered ->
  dvtOperatorActions(DVT_VALIDATOR_ADDRESS)(client): reads on a public client,
  register on the operator's wallet client
- validator address from the SDK canonical DVT_VALIDATOR_ADDRESS (post
  ensureSdkConfig), never hardcoded

Bump @aastar/sdk ^0.35.0 -> ^0.38.0 in aastar-frontend (surgical lockfile
version/resolved/integrity; deps unchanged 0.35->0.38 so no tree churn; backend
range ^0.35.0 still satisfied by the hoisted 0.38.0). Frontend + backend
type-check, frontend eslint, and backend build all pass.

Claude-Session: https://claude.ai/code/session_01RajETCvboSvhadpqMbekNx

@clestons clestons left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#424 — APPROVE

PK: 1 round (Codex) · 2 confirmed · 1 challenged (F3 rejected) · 1 MISSED (Low) · head 9c3aeee7

DVT 节点注册向导结构清晰,BLS 私钥全程仅驻留浏览器内存,未持久化也未传后端。DVT_SDK_READY 机制保证 0.38.0 前 UI 可走完但链上步骤被明确 stub,二次 commit 的 wiring 也正确:readActions()getPublicClient() 读,writeActions(walletClient) 用 operator 钱包写。


[Confirmed, Medium] F1 — generateBlsSecretKey() 约 55% 生成无效密钥,注释严重错误

lib/sdk/dvtOperator.ts:86-95

BLS12-381 标量域阶 r = 0x73eda753…,约 0.45 × 2^256,因此均匀随机 256-bit 值超过 r 的概率约 55%。每次点"生成新密钥"约每隔一次 buildDvtPop 就会抛出 invalid BLS secret key: out of range,用户看到错误并需要重试。注释声称 "~2^-128 chance" 系错误估算,实际差了约 2^127 倍。

建议在生成循环内拒绝越界值:

export function generateBlsSecretKey(): Hex {
  while (true) {
    const bytes = new Uint8Array(32);
    crypto.getRandomValues(bytes);
    const hex = Array.from(bytes, b => b.toString(16).padStart(2, "0")).join("");
    const key = `0x${hex}` as Hex;
    try { buildDvtPop(key); return key; } catch { /* out of range, retry */ }
  }
}

或直接用 BigInt(rand) % r + 1n 生成均匀标量。


[Confirmed, Low] F2 — isDvtNodeRegistered 返回值未检查,注册失败可能被静默吞掉

aastar-frontend/app/operator/dvt-register/steps/Step4Register.tsx:52-58

try {
  if (nodeId) await isDvtNodeRegistered(walletClient, nodeId);  // bool 被丢弃
} catch (err) {
  setConfirmError(...)
}
onNext();  // 无论 isRegistered 是否为 true

isRegistered 返回 false(链上确认延迟或 RPC 抖动),向导静默前进到 "Registration complete",实际节点未注册。建议:

const isReg = await isDvtNodeRegistered(walletClient, nodeId);
if (!isReg) setConfirmError("Node ID not yet visible on-chain — please refresh eligibility.");

[PK-added, Low] M1 — applyKeybuildDvtPop 抛错后仍将无效 key 写入 wizard state

aastar-frontend/app/operator/dvt-register/steps/Step3KeyPoP.tsx:46-53

const applyKey = (secret: Hex) => {
  setError(undefined);
  let pop: DvtPop | undefined;
  if (DVT_SDK_READY) {
    try {
      pop = buildDvtPop(secret);
    } catch (err) {
      setError(...);
      // ← 没有 return
    }
  }
  update({ blsSecretKey: secret, pop });  // 越界 key 也被写入
};

buildDvtPop 抛出时 pop = undefinedblsSecretKey = secret 被写入。hasKey = !!data.blsSecretKey 为 true → Continue 按钮可用,用户可带无效 key 进入 Step4,Step4 的 register 调用会再次失败。建议 catch 内 return,不调用 update()


Rejected

  • F3(fetchDvtEligibility 参数名变更为非下划线):diff 中实际未发生重命名,_walletClient 依然保留,系审查侧误读。

PK Summary

Finding Verdict
F1 generateBlsSecretKey ~55% 越界 [CONFIRM] Medium
F2 isDvtNodeRegistered bool 被丢弃 [CONFIRM] Low
F3 参数名重命名误读 Rejected
M1 applyKey 越界 key 写入 state [PK-added] Low

APPROVE

…ey commit)

- F1 [Medium] generateBlsSecretKey: a single 256-bit draw is ≥ the BLS12-381
  scalar order ~55% of the time (r ≈ 0.453·2^256), so "Generate" produced a key
  buildDvtPop rejects roughly half the time. Rejection-sample until the draw is
  in [1, r-1]; fix the bogus "~2^-128" comment.
- F2 [Low] Step4: isDvtNodeRegistered's boolean was awaited but ignored — a
  false read-back now surfaces a warning (tx already confirmed, so still advance).
- M1 [Low] Step3 applyKey: an out-of-range imported key was still written to
  wizard state (Continue enabled) despite buildDvtPop throwing. Commit the key
  only when its PoP derives; clear it on failure.

Frontend type-check + eslint green.

Claude-Session: https://claude.ai/code/session_01RajETCvboSvhadpqMbekNx

@clestons clestons left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#424 — APPROVE(增量)

增量 scope:9c3aeee7..d99a5af1(1 commit: fix 上轮 review)
PK: 1 round · 3 confirmed · 0 challenged · 0 MISSED · head d99a5af1

上轮三个 findings 均已正确修复:

  • F1 generateBlsSecretKey 改用 rejection-sampling,BLS12_381_R 常量正确,循环边界 [1, r-1] 无误,注释更新为"~2 draws on average"。✓
  • F2 isDvtNodeRegistered 返回值已检查,false 时触发 confirmFailed i18n 提示(EN/ZH 均已添加),onNext() 仍调用(tx 已确认,设计正确)。✓
  • M1 applyKey 成功路径才持久化 key + pop;失败路径同步清空两者,无效 key 不再使 Continue 按钮可用。✓

APPROVE

The prior commit bumped only aastar-frontend to ^0.38.0. For 0.x versions
`^0.35.0` means >=0.35.0 <0.36.0, so the backend's untouched ^0.35.0 no longer
matched the hoisted 0.38.0 — `npm ci` failed the lockfile sync check ("Missing:
@aastar/sdk@0.35.0"), taking every CI job down at the install step. Bump the
backend range (+ its lockfile stanza) to ^0.38.0; backend already type-checks
and builds against 0.38.0. `npm ci --dry-run` sync gate passes.

Claude-Session: https://claude.ai/code/session_01RajETCvboSvhadpqMbekNx
@jhfnetboy jhfnetboy merged commit eeda0af into master Jul 6, 2026
14 checks passed
@jhfnetboy jhfnetboy deleted the feat/dvt-register-wizard branch July 6, 2026 16:16
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants