Skip to content

feat(gnode): difftx 封装 + 参数化 7702 模板 + 同块有序批量 (D2)#795

Closed
keanji-x wants to merge 3 commits into
mainfrom
feat/gnode-difftx-d2
Closed

feat(gnode): difftx 封装 + 参数化 7702 模板 + 同块有序批量 (D2)#795
keanji-x wants to merge 3 commits into
mainfrom
feat/gnode-difftx-d2

Conversation

@keanji-x

Copy link
Copy Markdown
Contributor

背景

「机制驱动攻击工具链」的 D2:把 gnode 攻击 CLI 接上 D1 的 Rust 差分预言机(见 Galxe/gravity-reth#399),并把内置的死场景升级成审计 agent 可搜索的参数化模板 —— 让红队从「只会发动内置 7702-halt」变成「能 craft 新变体」。

改了什么(仅 tools/gnode/,不碰其它)

1. gnode difftx / gnode difftx-exec —— D1 差分预言机的 gnode 封装

gnodelib/difftx.py:shell out 到兄弟 gravity-reth worktree 的 difftx / difftx_exec 二进制(cargo run --features …,路径由 GRAVITY_RETH_DIR 配),实时透传子进程输出、原样传播退出码(3=停链缺口/执行背离,0=干净),命中时指向 difftx-repro/*.json 复现工件。纯静态、无需集群;worktree/manifest/cargo 缺失都给一行干净错误(exit 2),绝不抛 traceback。

2. 7702-race —— 参数化的 7702 停链模板

scenarios/halt_7702_param.py(原 7702-halt 保留为稳定默认)。旋钮(全走 PARAMS 类型校验,坏值→干净 exit 2):cross_sender_action(cross_sender|self_sponsored)、nonce_offsetauth_countchain_id(correct|zero|mismatched)、delegate_chainattemptswindow。不可构造的组合(如 delegate_chain=abachain_id=mismatched 负对照)返回结构化 inconclusive/error,不伪造 halt

3. gnode send-batch —— 同块有序批量原语

ops.py 抽出 _build_signed_from_spec 共享给 send,新增 cmd_send_batch:先全签名,再按数组序背靠背 --no-wait 广播,回报 same_block/ordered_in_block/逐笔块+序。诚实标注排序边界:同发送者连续 nonce=确定序;跨发送者=尽力而为的 fee-priority(无更强 RPC 原语)。

验证

  • 离线(已跑):gnode scenarios 列出 7702-race;gnode difftx-exec 对 worktree 跑通(9 例 0 背离,exit 0);gnode difftx 命中 7702 自检(NonceTooLow{tx:1,state:2},写 repro,exit 3);各参数/环境错误路径 exit 2 无 traceback。
  • 未跑 live 集群:7702-race 真链注入与 send-batch 真链广播的 halt/alive 判决未验证 —— 无 live repro 声明。

依赖

gnode difftx* 封装依赖 Galxe/gravity-reth#399 的 difftx 二进制(通过 GRAVITY_RETH_DIR 指向该 worktree/仓库)。

🤖 Generated with Claude Code

把「机制驱动攻击工具链」的 gnode 侧接上 D1 的 Rust 差分预言机,并把内置死
场景升级成可搜索的参数化模板:

- gnode difftx / difftx-exec:shell out 到兄弟 gravity-reth worktree 的
  difftx / difftx_exec 二进制(cargo run,GRAVITY_RETH_DIR 可配),透传输出 +
  退出码(3=停链缺口/执行背离,0=干净),命中时指向 difftx-repro/*.json 复现
  工件。纯静态、无需集群;worktree/cargo 缺失给干净错误(exit 2)。

- 7702-race 参数化场景(halt_7702_param.py,原 7702-halt 保留为稳定默认):
  暴露旋钮 cross_sender_action(cross_sender|self_sponsored)/nonce_offset/
  auth_count/chain_id(correct|zero|mismatched)/delegate_chain/attempts/
  window,供红队 agent 搜索停链变体;不可构造的组合返回结构化
  inconclusive/error 而非伪造 halt。旋钮走 PARAMS 类型校验(坏值→干净 exit 2)。

- gnode send-batch:同块有序批量发送——先全签名再按数组序背靠背 --no-wait
  广播,回报 same_block/ordered_in_block/逐笔块+序。诚实标注排序边界(同发送者
  连续 nonce=确定序;跨发送者=尽力而为的 fee-priority,无更强 RPC 原语)。

离线验证:gnode scenarios 列出 7702-race;difftx-exec 对 worktree 跑通(9 例
0 背离,exit 0);difftx 命中 7702 自检(exit 3);各错误路径 exit 2 无 traceback。
未跑 live 集群注入(7702-race/send-batch 的真链 halt/broadcast 未验证)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f64dfabf3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

for i, spec in enumerate(specs):
if not isinstance(spec, dict):
raise ValueError(f"batch[{i}] 需为对象(tx 规格),得到 {type(spec).__name__}")
raw, sender, to = _build_signed_from_spec(w3, spec)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allocate pending nonces while preparing a batch

In gnode send-batch with two specs from the same account that omit nonce (allowed because each item is a normal gnode send spec and the default signer is the faucet), the pre-sign loop calls _build_signed_from_spec before any broadcast, so each call reads the same on-chain nonce via get_transaction_count. The batch then submits duplicate-nonce raw transactions; the second one is rejected or treated as an underpriced replacement instead of producing the advertised same-sender ordered batch. Minimal validation is a two-entry batch to different to addresses without explicit nonces; assign local per-sender nonces while preparing, or reject missing nonces for multi-tx senders.

AGENTS.md reference: AGENTS.md:L8-L8

Useful? React with 👍 / 👎.

Comment on lines +99 to +100
"顺序保证:同发送者连续 nonce = 块内序确定;跨发送者 = 靠 maxPriorityFeePerGas\n"
"小费定序(best-effort,非 100%)。示例:\n"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept the advertised fee-priority fields

For cross-sender batches, this help text tells operators to set maxPriorityFeePerGas, but those batch entries are still validated by _build_signed_from_spec, whose allowed field set does not include maxPriorityFeePerGas or maxFeePerGas; a batch that uses the documented ordering knob fails immediately as an unknown field before broadcasting. The cross-sender ordering mode therefore cannot be configured from gnode send-batch; either pass these EIP-1559 fields through for type 2/4 transactions or remove this documented mechanism.

AGENTS.md reference: AGENTS.md:L8-L8

Useful? React with 👍 / 👎.

race = _inject_self_sponsored(w3, faucet, A, node_chain_id, nonce_offset=nonce_offset)
tx0_key, tx1_key = "tx0_self_create", "tx1_from_A_stale"
else:
race = _inject_race(w3, faucet, A, node_chain_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply nonce_offset to cross-sender races

With the default cross_sender_action=cross_sender, gnode attack 7702-race --param nonce_offset=... records the requested offset in params_used but still calls the old _inject_race, which always signs tx1 at nonce N. That makes all cross-sender nonce-offset search variants execute the same transaction shape, so an audit agent can report coverage for offsets that were never tested; pass the offset into a parameterized cross-sender injector or reject nonce_offset unless self_sponsored is selected.

AGENTS.md reference: AGENTS.md:L8-L8

Useful? React with 👍 / 👎.

review nit 修复:
- difftx.py:非零退出码不再一律报「发现停链缺口/背离」——仅 rc==3 才是 gap;
  cargo 编译失败(101)/运行错误另给中性提示,避免 agent 把编译失败当停链。
- halt_7702_param.py:cross_sender 模式下 _inject_race 不吃 nonce_offset,过去
  静默忽略却仍记进 params_used(误导)。现显式拒绝该组合(usage_error),提示改用
  self_sponsored 或去掉 nonce_offset。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b10c0650fe

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

result.update({"verdict": Verdict.ERROR.value, "usage_error": True,
"detail": f"attempts 需 ≥1,得到 {attempts}"})
return result
window = float(params.get("window", 20))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject non-positive liveness windows

When 7702-race is run with --param window=0 or a negative value, this accepts the value and later passes it to probe_liveness, whose deadline is already expired so it skips polling and returns HALT; _evaluate then treats that as decisive before requiring the race to have formed. That can make a healthy node look like a successful halt finding from a bad parameter, so reject window <= 0 as a usage error before probing.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cca217c78c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

from pathlib import Path

# 兄弟 gravity-reth worktree 默认位置;可用环境变量 GRAVITY_RETH_DIR 覆盖。
DEFAULT_RETH_DIR = "/mnt/data2/kenji/galxe/gravity-reth-difftx"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid defaulting difftx to a developer-local path

When GRAVITY_RETH_DIR is unset in a fresh checkout or CI job, gnode difftx follows _dispatch -> cmd_difftx -> _reth_dir() to this hard-coded /mnt/data2/... location and returns the worktree-missing usage error before invoking cargo, so the new static oracle is unusable unless operators already know to set a private environment variable. Minimal validation is unset GRAVITY_RETH_DIR; gnode difftx; derive a repo-relative sibling/default or require an explicit path instead.

AGENTS.md reference: AGENTS.md:L8-L9

Useful? React with 👍 / 👎.

keanji-x added a commit that referenced this pull request Jul 24, 2026
移除 tools/gnode。集群攻击/PoC 工具(端到端攻击场景 + PoC 复现 harness)不宜
留在公开仓库,现迁往私有的审计工具库,与既有审计工具链并列归属。

Supersedes #795(其内容并入私有库)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@keanji-x

Copy link
Copy Markdown
Contributor Author

关闭:gnode 攻击/PoC 工具已整体迁往私有的审计工具库(集群攻击工具不再进公开链仓库),本 PR 的 D2 改动(difftx 封装 + 参数化 7702 模板 + 同块有序批量)一并并入私有库版本。

故本 PR 不再合入公开仓库。

@keanji-x keanji-x closed this Jul 24, 2026
keanji-x added a commit that referenced this pull request Jul 25, 2026
Removes `tools/gnode`.

The cluster attack / PoC tooling (end-to-end attack scenarios + a PoC
reproduction harness) does not belong in a public repository. It has
been relocated to a private audit-tooling repo, alongside the existing
audit toolchain; future attack capabilities will land there as well, not
in the public chain repo.

- Deletes `tools/gnode/` only; no other code is touched. Verified there
are no remaining references anywhere in the repo (`tools/` becomes empty
as a result).
- Supersedes #795 (the gnode changes are folded into the private-repo
version).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant