Files
mtgodot-poc/audit/contracts/social.exchange-safebox.md
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

14 KiB
Raw Blame History

social.exchange_safebox

Scope

审计玩家面对面交易、交易确认/防调包、仓库(Safebox)、仓库密码与分页、商城(Mall)只读取出、金币变化和窗口距离/关闭清理。判断标准是当前端是否复现 40250 的客户端请求门控、服务器回包权威状态、物品 socket/属性传递、错误分支和窗口时序;本地脚本能够独立完成一次交易或仓库存取,不能作为与 40250 实现统一的证明。

Reference call chain

  • UserInterface/PythonNetworkStreamPhaseGame.cpp
    • RecvExchangePacket 按 START/ITEM_ADD/ITEM_DEL/ELK_ADD/ACCEPT/END 更新 CPythonExchange,每个物品同时保存 socket 与 attribute,并在物品变化后刷新交易和背包窗口。
    • SendExchangeStartPacket、SendExchangeElkAddPacket、SendExchangeItemAddPacket、SendExchangeAcceptPacket、SendExchangeExitPacket 均先经过 __CanActMainInstance(),再发送 CG_EXCHANGE 并追加 sequence;客户端不直接结算交易。
  • UserInterface/PythonExchange.cpp / Client/Eternexus/root/uiexchange.py
    • CPythonExchange 保存双方姓名、12 个展示槽、socket/attribute、金币和接受状态;交易结束由 GC_END 驱动 EndExchange,成功/失败详情通过服务器聊天提示提供。
    • 交易 UI 只提交物品、金币、接受或退出请求,等待服务器回包刷新;物品源位置、anti flag、背包和金币结果由服务端确认。
  • UserInterface/PythonNetworkStreamPhaseGameItem.cpp
    • Safebox checkin/checkout/move、密码错误、大小、金币变化和 Mall open/set/del/checkout 都是协议路径;Safebox/Mall item set 回包复制 vnum/count/flags/anti_flags、socket 和 attribute 后刷新窗口。
    • Safebox 金币主动修改包在该版本明确未启用;Mall checkout 还触发对应掉落音效。
  • Client/Eternexus/root/uisafebox.py / game.py
    • 仓库由服务器返回页数和物品状态,5×9 每页 45 格;拖放/右键发送 checkin、checkout 或 move,关闭和密码命令走服务器流程。商城只允许取出,不允许向 Mall 存入。

Current call chain

  • native M2Client/ClassicSession 已提供 exchange start/item/gold/accept/cancel、safebox checkin/checkout/move/password/change/close、mall checkout/password,以及 EntityStore 的 exchange/safebox/mall parser、dirty 标记和 signal。
  • EntityStore 能保存交易双方 12 槽、金币、接受标志、notice,能够复制交易物品 socket/attribute;Safebox/Mall parser 能复制 item flags、anti_flags、socket 和 attribute,并处理 open/set/del/close/wrong-password 基础事件。
  • project/ui/exchange_ui.gd、safebox_ui.gd、mall_ui.gd 已提供 12 槽交易 UI、45 格分页仓库、商城只读出、tooltip、密码和距离自动关闭;主要 UI 已从 native getter/signal 刷新,而不是只依赖本地物品列表。
  • project/player_trade_exchange_system.gd 和 project/safebox_storage_keeper_system.gd 是另外一套本地状态机:它们直接保存玩家字典、交易物品、金币、仓库密码、库存和金条熔铸结果。这些 helper 可用于单元测试,但不是 40250 客户端的网络 authority 链。

Branch matrix

场景 40250 当前端 结论
开始交易 __CanActMainInstance→CG_EXCHANGE START→服务器 GC_START native 能发 start,UI/helper 能打开交易 PARTIAL:native 缺同等动作门控和 active/partner 状态限制;helper 可绕开服务器
放入物品 客户端只发源位置和展示槽,服务器回 GC_ITEM_ADD;变化时双方接受状态由服务器清除 UI 做 anti-give/重复源位置检查后立即记录 _offered_cells,native 只做位置边界 PARTIAL:本地 optimistic 集合没有按 GC_ITEM_ADD/ITEM_DEL 重建,拒绝或删除后可能仍阻塞源物品
放入金币 SendExchangeElkAddPacket 只负责请求,服务器决定金额并回包 UI 限制 1..9,999,999,native 只做 u32/in-game 检查 PARTIAL:本地上限和已放金币判断不是 40250 客户端 authority;native 缺交易 active/拥有金币/动作门控
接受/取消/结束 接受和退出发包,窗口等 GC_END 关闭;交易结果由服务器聊天和回包提供 接受有本地 pending;取消和距离超限会发包后立即 close() PARTIAL:取消/距离分支不等待权威 GC_END,真实拒绝、断线和乱序关闭未覆盖
交易安全/原子结算 客户端不计算交换、不改双方背包/金币;服务端负责锁定、空间、金额和最终交付 player_trade_exchange_system.gd 本地计算 ready、金币、空间和原子转移 GAP(本地 helper):这不是 40250 客户端实现,不能作为 live parity 依据
Safebox 打开/关闭 GC_SAFEBOX_SIZE 打开,服务端控制大小;关闭走 /safebox_close,窗口状态由服务端同步 native/UI 有 open/close、页数和 10m 自动关闭;close 后本地立即隐藏 PARTIAL:基础链存在,但本地先隐藏/请求失败回滚、乱序重开和真实服务端错误缺测试
Safebox 存取/移动 checkin/checkout/move 请求后由 GC_SAFEBOX_SET/DEL 更新 拖放使用目标槽,移动/右键取出存在;移动端 deposit 先找本地首个空位并记录 pending PARTIAL:pending 没有与回包关联;本地 helper 直接存取/堆叠,不能证明服务器拒绝、堆叠和物品属性结果一致
Safebox 密码/金币 wrong-password 和 size/money change 由服务器回包;客户端不保存真实密码 native 通过命令发送密码;本地 safebox_storage_keeper_system.gd 保存密码、冷却、锁定和金条规则 PARTIAL/GAP:helper 的密码/冷却/金条熔铸是自定义本地 authority,不能替代 40250 server command/GC 结果
Mall 打开/取出 GC_MALL_OPEN/SET/DEL 驱动只读窗口,checkout 后服务器更新背包/Mall native parser/UI/getter/checkout 存在,UI 禁止插入 PARTIAL:主路径接近,但服务端失败、背包回包、重连清理和掉落音效没有端到端证据

Implementation-equivalence matrix

项目 状态 证据/限制
Preconditions PARTIAL 位置、展示槽、u32、窗口和部分 anti flag 检查存在;exchange native 缺 __CanActMainInstance 等阶段/动作门控,真实库存/交易 active/拥有金币由服务端决定且未在客户端等价复现
Branch structure PARTIAL exchange/safebox/mall 的协议分支和 UI 分支基本存在;取消立即关闭、移动端首空位 deposit、local helper 结算和密码/金条旁路与参考客户端不一致
Algorithms/formulas GAP 40250 客户端不实现交易结算、库存空间、仓库密码存储或金条熔铸公式;当前本地 helper 复制这些服务器职责,不能宣称与客户端统一
State transition order PARTIAL native store 大体是请求→GC→dirty/signal→UI;交易 _offered_cells、safebox pending 和 close 先隐藏造成本地 optimistic 状态,拒绝/乱序时序尚未闭合
Constants/units PARTIAL 12 交易槽、45 格/页、socket/attribute 槽和距离限制存在;金币 9,999,999 UI 上限、helper 45 格/单页和自定义冷却/金条常量需避免冒充 40250 client 常量
Timing/event sources PARTIAL exchange/safebox/mall dirty signal、10m 距离关闭和密码错误 UI 存在;真实 GC_END、GC_ITEM_SET/DEL、断线、重复请求和重新打开时序缺回归
Resource/data sources PARTIAL live item tooltip 使用协议 item 数据并保留 socket/attribute;本地交易/仓库 helper 使用脚本 Dictionary,移动端 pending/首空位选择可能在服务器结果前改变显示
Protocol side effects PARTIAL CG exchange、safebox、mall 基础布局和 store parser 存在;exchange 的动作门控、完整错误结果、商城掉落音效和实际服务器回包副作用不完整
Interruption/failure/cleanup GAP helper 可无服务器回包直接成功;UI 的本地关闭、optimistic 源物品/pending 集合、密码失败、背包满、断线和乱序恢复没有完整回滚/重放证明

Regression evidence

  • project/test_player_trade_exchange_parity.gd:28/28 通过;覆盖的是本地交易 helper 的距离、不可交易物品、双方锁定、金币、空间和原子交付,不是 GC_EXCHANGE live 回包。
  • project/test_safebox_mall_parity.gd:37/37 通过;覆盖 fake client 的 45 格、距离、socket/attribute、checkin/checkout/move、商城禁止插入和密码命令。
  • project/test_safebox_storage_keeper_parity.gd:37/37 通过;覆盖本地密码/冷却、库存堆叠、移动、金条熔铸/承兑和非法格位,不能证明 40250 server authority。
  • project/shop_cube_mall_test.gd、project/test_mall_affect_parity.gd、project/popup_windows_parity_test.gd、project/test_security_lock_parity.gd、build/extension/net_entity_test、build/extension/net_classic_session_test:通过;主要验证 UI/helper、item-mall 辅助效果或基础 packet/store,没有完整 exchange/safebox/mall 服务器拒绝、乱序、断线和回包回滚。
  • project/complex_item_drop_test.gd:当前 1 项失败(购买模式仍允许把物品拖到出售目标),说明统一拖放门控仍有可复现差异;该失败属于相邻商店合同,但会影响交易/仓库共用拖放边界审计。

Deep audit round 2026-09-21

Fresh regression results

  • godot --headless --path project --script test_player_trade_exchange_parity.gd:退出码 0,28/28 通过;覆盖本地交易距离、anti-give、锁定、金币、空间、原子转移和取消 helper。
  • godot --headless --path project --script test_safebox_mall_parity.gd:退出码 0,37/37 通过;覆盖 fake client 的仓库/商城窗口、45 格、距离关闭、属性显示、存取移动和密码命令。
  • godot --headless --path project --script test_safebox_storage_keeper_parity.gd:退出码 0,37/37 通过;覆盖本地密码/冷却、堆叠、45 格和金条 helper。
  • godot --headless --path project --script shop_cube_mall_test.gd、test_mall_affect_parity.gd、popup_windows_parity_test.gd、test_security_lock_parity.gd:均退出码 0;商城效果、窗口和安全锁局部测试通过,其中安全锁为 48/48。
  • build/extension/net_entity_test 与 build/extension/net_classic_session_test:均退出码 0;基础 exchange/safebox/mall parser/session 通过。
  • godot --headless --path project --script complex_item_drop_test.gd:退出码 1;购买模式出售目标门控失败,属于相邻 shop/drag contract 的持续回归。

Static parity findings

  • 40250 交易请求全部先经过 __CanActMainInstance,客户端只发送源位置/金币/接受/退出,GC_EXCHANGE_* 决定展示和最终结束;当前 native exchange 请求主要做阶段/范围校验,player_trade_exchange_system.gd 仍可脱离网络直接完成双方金币、空间和物品转移。
  • 当前 exchange_ui.gd 的 _offered_cells、pending 和取消/距离关闭逻辑没有统一由 GC_ITEM_ADD/DEL、GC_ACCEPT、GC_END 重建;拒绝、乱序、断线和重新打开可能保留乐观状态。
  • 40250 Safebox/Mall item 回包保留 vnum/count/flags/anti_flags/socket/attribute,并由服务端决定页数、堆叠、空间和金币;当前 live native/store 路径能承接这些字段,但 safebox_storage_keeper_system.gd 仍保存密码、冷却、堆叠和金条 authority。
  • Safebox/Mall UI 的距离自动关闭、密码命令和商城只出路径有局部验证;没有真实 GC_SAFEBOX_SIZE/SET/DEL/WRONG_PASSWORD、GC_MALL_* 与背包回包的成功/失败/重连/断线顺序 fixture,也没有 Mall checkout 音效的端到端验证。
  • M2Client/ClassicSession 的 exchange/safebox/mall 包布局基础存在,但 native action gate、交易 active/partner/金币拥有量、服务器拒绝文案、SendSequence 和关闭幂等性未形成统一合同。

Round conclusion

本轮仍为 PARTIAL:交易/仓库/商城 native 骨架和局部 UI 测试通过,但本地结算/密码/库存 helper 旁路、乐观关闭/pending 状态、动作门控与真实 GC 回包回滚仍未与 40250 统一。本轮未修改实现代码。

Active UserInterface exchange, safebox and shop review

  • PythonExchange.h/PythonExchangeModule.cpp 的状态读取覆盖双方名称、金钱、接受状态、槽位 vnum/count、metin socket、attribute 和 elk mode;这些值由交易回包写入,UI getter 不承担结算。
  • PythonSafeBox.h 区分 safebox 与 mall 的打开尺寸、slot item、删除、金钱和当前大小;PythonShop.h 另外维护普通商店 tab/coin/name/item,以及私有商店 stock/display position/price/build/close,不能把它们合并为一个背包字典。
  • 当前 native/store 已覆盖部分字段,但交易、仓库和商城 helper 仍有本地 optimistic/persistent 状态;真实 GC 添加/删除/接受/错误、密码失败、页尺寸、私店重建、断线和重复关闭顺序没有逐包等价测试,合同保持 PARTIAL。

Static review evidence

已将 PythonExchange.h、PythonExchangeModule.cpp、PythonSafeBox.h、PythonShop.h 纳入 active source 证据;本轮确认了交易/仓库/商城的独立 owner 和回包字段边界,未修改实现。

Status

PARTIAL。当前端已经具备 exchange/safebox/mall 的 native 协议骨架、回包存储和主要 UI,交易物品属性与仓库商城的基本网络状态能够展示;但 native exchange 请求缺 40250 动作门控,交易/仓库 UI 存在 optimistic 状态和提前关闭,本地 helper 直接承担交易结算、密码、库存和金条 authority,且真实错误、乱序、断线和回包回滚证据不足。本轮完成审计并记录,未修改实现。