01 payments (EN+ZH) - idempotency gate is now a whitelist: only PENDING and a late-settled EXPIRED may enter fulfilment. Checking only for FULFILLED left the whole PROCESSING window open to a second queue push (consultant finding). - k-of-n -> two-tier: both chassis anchors (SMBIOS board UUID + CPU architectural signature) matching is sufficient; if one anchor changed, every auxiliary digest must match. Aux dimension moved off the volatile OS GUID onto permanent NIC MAC. - FSM diagram: RETRY_QUEUE branches from PROCESSING, not FULFILLED 02 comfyui covers (EN+ZH) - subscribe the WebSocket BEFORE queue_prompt, settimeout(120), try/finally ws.close(), /history fallback on timeout: fixes the lost-terminal-frame hang and the per-image socket leak - document Pillow half-wave rectified Laplacian (offset=0 clamps negative responses to 0) and why a signed float kernel would not work here - replace the unverifiable "89 covers in 48 minutes" with the filesystem evidence: 216 assets (108 banner+OG pairs) inside a 25.9-min window - ZH: drop the colloquial imperative; add self-bootstrapping note 03 traefik yaegi (ZH) - the .traefik.yml contract paragraph and scoreThreshold 120 had only landed in the EN file; both now applied to ZH - <summary> line counts corrected 29 -> 30 in both languages (verified programmatically for all eight code blocks) layout - standing provenance note in the site footer (sanitised client identifiers / production thresholds), per consultant Q7 ruling
This commit is contained in:
1 parent
a7077a3a1d
commit
bfcf61c7ea
8 files changed
+123
-50
No files matched your search
@@ -53,7 +53,7 @@ dynamicCta: true
|
||||
│
|
||||
├── (接收 Webhook: 校验数据签名与金额)
|
||||
▼
|
||||
[PROCESSING] ─── (获取数据库行级排他锁)
|
||||
[PROCESSING] ─── (获取行级排他锁 → 提交事务 → 入队)
|
||||
│
|
||||
├── (调用 Keygate API 签发专属机器码 License)
|
||||
▼
|
||||
@@ -97,8 +97,12 @@ public function callback(): ResponseInterface
|
||||
$this->db->transRollback();
|
||||
return $this->response->setStatusCode(404)->setBody('UNKNOWN_BILL');
|
||||
}
|
||||
if ($order['status'] === 'FULFILLED') {
|
||||
$this->db->transCommit(); // 重放风暴:吸收掉,绝不二次发码
|
||||
// 只有两种状态可以进入履约:全新的 PENDING,或银行延迟结算的 EXPIRED。
|
||||
// 其余状态(PROCESSING 已占一个队列位、FULFILLED 已完成、RETRY_QUEUE 在重试)
|
||||
// 都属于重放,必须在此吸收——只判 'FULFILLED' 会留下整个 PROCESSING 窗口,
|
||||
// 让第二次推送穿透幂等检查。
|
||||
if (!in_array($order['status'], ['PENDING', 'EXPIRED'], true)) {
|
||||
$this->db->transCommit();
|
||||
return $this->response->setStatusCode(200)->setBody('OK_IDEMPOTENT');
|
||||
}
|
||||
|
||||
@@ -149,9 +153,11 @@ private function toCents(string $amount): int
|
||||
|
||||
**逐组件摘要的存在,是为了让授权能扛住合法的硬件变更。** 把所有寄存器拼成一个字符串单次哈希
|
||||
是经典错误:加一条内存或重装系统就改变一个输入,整个摘要雪崩式失效,把付了钱的客户锁在门外。
|
||||
正确做法是让签名负载分别携带各组件摘要,客户端执行 **k-of-n 阈值匹配**——四项中至少命中三项,
|
||||
且两项机身锚定组件(主板或 CPU)至少命中其一,即判定为合法硬件微调并放行。换硬盘、重装系统
|
||||
属于正常升级;把授权移植到另一台机器会同时改变主板与 CPU,直接卡在阈值之外。
|
||||
正确做法是让签名负载分别携带各组件摘要,客户端按两级裁决:两项**机身锚定件**(SMBIOS 主板 UUID
|
||||
与 CPU 架构签名)具决定权,其余辅助寄存器(存储控制器 UUID、网卡永久 MAC)只做仲裁。两项锚定件
|
||||
同时命中即无条件放行——重装系统或换硬盘只会改变辅助寄存器,属于合法升级。若其中一项锚定件已变
|
||||
(换主板或换 CPU),只要其余辅助摘要全部命中,授权依然放行:既让付费客户扛过硬件翻新,又不会把
|
||||
口子开大到足够把授权移植到一台无关的机器上。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user