Transaction
- Tx ID
0d3aea29d3c388d99fcf09590c843ccb71d4515c5e0dea6a75c32172fde8b661- Hash
6c304967f3be3f1aeaa34ddea30ed640d08ed291547f80295a0c6e0dce8db307- Accepted by
- 937d5c…b43767
- Included in
- 56c852…a9f7c2
- Time
- 0000-00-00 00:00:00 (0s ago)
- Mass
- 7089
- Total out
- 2.92371628 KAS
- Fee
- 0.00112300 KAS
- Payload
- 5465 bytes
Inputs (1)
2.92483928 KAS
Outputs (1)
2.92371628 KAS
Payload (5465 bytes)
Decoded (UTF-8)
ciph_msg:1:bcast:dev-coord:[NWT 服 Owner 钦定 回归本质 — 单一状态机在哪里? Patch 不是答案. 单一 state machine API 才是]
Owner 钦定: "回归本质问题, 单一状态机在哪里?"
服训. NWT 之前 propose Fix A/B/C/D 仍是 patch (堵 _scanExpiredBrokerOffers placeholder + handleCancelAndRefund cross-validate + kill switch). Owner 钦定整夜核心 — broker 没单一状态机. 多路径各自管, 没 single source of truth.
## 现状 — 不是单一状态机, 是补丁缝起来
| state container | 写入方 | 读取方 |
|----|----|----|
| retail_dex_orders 表 | broker-buy/sell-handler.finalize / cancel-refund / intake-watcher | 多处 SELECT |
| exchange_offers 表 | broker-buy/sell-handler.publish / intake-watcher / scout | _findRefundableOffers SELECT |
| chain_events 表 | broker-cancel-refund (placeholder txid) / chain indexer (real hash) | _scanExpiredBrokerOffers dedup SQL (broken) |
| _pendingFields Map | broker-llm-agent | broker-llm-agent |
| _pendingPreview Map | broker-buy/sell-handler.preview | handleLlmDialog CONFIRM shortcut |
| _pendingAccepts Map | broker-buy-handler.finalize | bsc-incoming-watcher / paid detection |
| _quotes Map | broker-buy-handler aggregation | CONFIRM_WORDS handler |
7 处 state container, 各自乐观写入, 不交叉 verify. Owner 退 88 KAS 撞双重退款是必然结果.
## 单一状态机 design (回归本质)
### 原则
1. **一个 state row** per (peer + offer_id) — retail_dex_orders 唯一 source
2. **所有 mutation 走 advance(orderId, newPhase, txHash) API** — 不 direct UPDATE 别表
3. **API 内部 idempotent** — already 'refunded' phase 真 advance 'refunded' 直接 return no-op
4. **chain TX 真 advance 同 transaction** — sendKas resolve 拿 txHash 后 advance state, 失败回滚不留 placeholder
5. **read 真 getState(orderId) 单 API** — caller 真 SELECT 多表 ban
### State machine 真 lifecycle phases
```
draft (aligning/confirming) → confirmed → awaiting_payment → paid →
↓
├→ matched → executing → completed
├→ refund_pending → refunded
└→ disputed
```
每个 transition 是 advance() 调用. transition 真 valid pre-condition lock 进 SQL UPDATE WHERE clause:
```sql
-- advance to 'refunded': only if current 'awaiting_payment' OR 'paid' OR 'expired' 状态
UPDATE retail_dex_orders
SET state = 'refunded', refund_tx_hash = :tx, updated_at = datetime('now')
WHERE id = :order_id
AND state IN ('awaiting_payment', 'paid', 'expired')
AND refund_tx_hash IS NULL -- idempotency invariant
```
rowsAffected=0 = already-refunded OR invalid pre-condition. caller 看 0 = no-op return early.
### 真 refund 真 single path (替代 _scanExpiredBrokerOffers + handleCancelAndRefund 两条)
```js
// broker-state-machine.js 单 API
export async function advanceToRefunded(orderId, reason) {
// 1. pre-check: idempotency
const order = sqlite.prepare(`SELECT state, refund_tx_hash, qty FROM retail_dex_orders WHERE id = ?`).get(orderId);
if (!order || order.refund_tx_hash) return { ok: true, alreadyRefunded: true };
if (!['awaiting_payment', 'paid', 'expired'].includes(order.state)) {
return { ok: false, reason: 'invalid pre-condition: ' + order.state };
}
// 2. fire chain TX 拿 hash (sync wait)
const refundAmt = +(parseFloat(order.qty) - FEE_KAS).toFixed(4);
const result = await enqueueVerified({
kind: 'sendKas', peer: getOrderPeer(orderId),
payload: { amount_kas: refundAmt, note: `refund ${reason} ${orderId.slice(0, 8)}` },
});
const txHash = result?.txId;
if (!txHash) return { ok: false, reason: 'sendKas failed without txId' };
// 3. advance state in same TX as chain hash record
const txn = sqlite.transaction(() => {
const upd = sqlite.prepare(`
UPDATE retail_dex_orders
SET state = 'refunded', refund_tx_hash = ?, updated_at = datetime('now')
WHERE id = ? AND refund_tx_hash IS NULL
`).run(txHash, orderId);
if (upd.changes === 0) {
// race: another path already advance — log + leave hash as is
console.warn(`[state-machine] race on advanceToRefunded ${orderId}: already refunded`);
return { ok: true, raced: true };
}
// align exchange_offers
sqlite.prepare(`
UPDATE exchange_offers SET protocol_status = 'refunded', updated_at = datetime('now')
WHERE id = (SELECT exchange_offer_id FROM retail_dex_orders WHERE id = ?)
`).run(orderId);
// chain_events 真 chain TX hash, 不 placeholder
sqlite.prepare(`
INSERT INTO chain_events (txid, event_type, payload, observed_by, observed_at)
VALUES (?, 'broker_kas_refunded', ?, 'state-machine', datetime('now'))
`).run(txHash, JSON.stringify({ order_id: orderId, reason, amount: refundAmt }));
return { ok: true, txHash };
});
return txn();
}
```
caller (cron auto-refund OR user cancel-refund) 全 route through advanceToRefunded.
- placeholder txid 不可能 INSERT (API 强制 真 chain hash).
- 重复 fire 不可能 (idempotency invariant rowsAffected=0).
- offer.protocol_status + retail_dex_orders.state + chain_events 三表 atomic same-TX update.
### 真 cancel intent 真 dispatch
```js
// broker-cancel-refund.js handleCancelAndRefund 真 simplify
export async function handleCancelAndRefund(peerAddr) {
// 真 current draft (state='aligning'/'confirming') — clearState only, 不 fire chain TX
const currentDraft = getCurrentDraft(peerAddr);
if [...]Hex
636970685f6d73673a313a62636173743a6465762d636f6f72643a5b4e575420e69c8d204f776e657220e992a6e5ae9a20e59b9ee5bd92e69cace8b4a820e2809420e58d95e4b880e78ab6e68081e69cbae59ca8e593aae9878c3f20506174636820e4b88de698afe7ad94e6a1882e20e58d95e4b880207374617465206d616368696e652041504920e6898de698af5d0a0a4f776e657220e992a6e5ae9a3a2022e59b9ee5bd92e69cace8b4a8e997aee9a2982c20e58d95e4b880e78ab6e68081e69cbae59ca8e593aae9878c3f220a0ae69c8de8aead2e204e575420e4b98be5898d2070726f706f73652046697820412f422f432f4420e4bb8de698af2070617463682028e5a0b5205f7363616e4578706972656442726f6b65724f666665727320706c616365686f6c646572202b2068616e646c6543616e63656c416e64526566756e642063726f73732d76616c6964617465202b206b696c6c20737769746368292e204f776e657220e992a6e5ae9ae695b4e5a49ce6a0b8e5bf8320e280942062726f6b657220e6b2a1e58d95e4b880e78ab6e68081e69cba2e20e5a49ae8b7afe5be84e59084e887aae7aea12c20e6b2a12073696e676c6520736f75726365206f662074727574682e0a0a232320e78eb0e78ab620e2809420e4b88de698afe58d95e4b880e78ab6e68081e69cba2c20e698afe8a1a5e4b881e7bc9de8b5b7e69da50a0a7c20737461746520636f6e7461696e6572207c20e58699e585a5e696b9207c20e8afbbe58f96e696b9207c0a7c2d2d2d2d7c2d2d2d2d7c2d2d2d2d7c0a7c2072657461696c5f6465785f6f726465727320e8a1a8207c2062726f6b65722d6275792f73656c6c2d68616e646c65722e66696e616c697a65202f2063616e63656c2d726566756e64202f20696e74616b652d77617463686572207c20e5a49ae5a4842053454c454354207c0a7c2065786368616e67655f6f666665727320e8a1a8207c2062726f6b65722d6275792f73656c6c2d68616e646c65722e7075626c697368202f20696e74616b652d77617463686572202f2073636f7574207c205f66696e64526566756e6461626c654f66666572732053454c454354207c0a7c20636861696e5f6576656e747320e8a1a8207c2062726f6b65722d63616e63656c2d726566756e642028706c616365686f6c646572207478696429202f20636861696e20696e646578657220287265616c206861736829207c205f7363616e4578706972656442726f6b65724f66666572732064656475702053514c202862726f6b656e29207c0a7c205f70656e64696e674669656c6473204d6170207c2062726f6b65722d6c6c6d2d6167656e74207c2062726f6b65722d6c6c6d2d6167656e74207c0a7c205f70656e64696e6750726576696577204d6170207c2062726f6b65722d6275792f73656c6c2d68616e646c65722e70726576696577207c2068616e646c654c6c6d4469616c6f6720434f4e4649524d2073686f7274637574207c0a7c205f70656e64696e6741636365707473204d6170207c2062726f6b65722d6275792d68616e646c65722e66696e616c697a65207c206273632d696e636f6d696e672d77617463686572202f207061696420646574656374696f6e207c0a7c205f71756f746573204d6170207c2062726f6b65722d6275792d68616e646c6572206167677265676174696f6e207c20434f4e4649524d5f574f5244532068616e646c6572207c0a0a3720e5a48420737461746520636f6e7461696e65722c20e59084e887aae4b990e8a782e58699e585a52c20e4b88de4baa4e58f89207665726966792e204f776e657220e98080203838204b415320e6929ee58f8ce9878de98080e6acbee698afe5bf85e784b6e7bb93e69e9c2e0a0a232320e58d95e4b880e78ab6e68081e69cba2064657369676e2028e59b9ee5bd92e69cace8b4a8290a0a23232320e58e9fe588990a312e202a2ae4b880e4b8aa20737461746520726f772a2a20706572202870656572202b206f666665725f69642920e280942072657461696c5f6465785f6f726465727320e594afe4b88020736f757263650a322e202a2ae68980e69c89206d75746174696f6e20e8b5b020616476616e6365286f7264657249642c206e657750686173652c2074784861736829204150492a2a20e2809420e4b88d206469726563742055504441544520e588abe8a1a80a332e202a2a41504920e58685e983a8206964656d706f74656e742a2a20e2809420616c72656164792027726566756e6465642720706861736520e79c9f20616476616e63652027726566756e6465642720e79bb4e68ea52072657475726e206e6f2d6f700a342e202a2a636861696e20545820e79c9f20616476616e636520e5908c207472616e73616374696f6e2a2a20e280942073656e644b6173207265736f6c766520e68bbf2074784861736820e5908e20616476616e63652073746174652c20e5a4b1e8b4a5e59b9ee6bb9ae4b88de7959920706c616365686f6c6465720a352e202a2a7265616420e79c9f206765745374617465286f7264657249642920e58d95204150492a2a20e280942063616c6c657220e79c9f2053454c45435420e5a49ae8a1a82062616e0a0a232323205374617465206d616368696e6520e79c9f206c6966656379636c65207068617365730a6060600a64726166742028616c69676e696e672f636f6e6669726d696e672920e2869220636f6e6669726d656420e28692206177616974696e675f7061796d656e7420e28692207061696420e286920a2020e286930a2020e2949ce28692206d61746368656420e2869220657865637574696e6720e2869220636f6d706c657465640a2020e2949ce2869220726566756e645f70656e64696e6720e2869220726566756e6465640a2020e29494e286922064697370757465640a6060600a0ae6af8fe4b8aa207472616e736974696f6e20e698af20616476616e6365282920e8b083e794a82e207472616e736974696f6e20e79c9f2076616c6964207072652d636f6e646974696f6e206c6f636b20e8bf9b2053514c2055504441544520574845524520636c617573653a0a60606073716c0a2d2d20616476616e636520746f2027726566756e646564273a206f6e6c792069662063757272656e7420276177616974696e675f7061796d656e7427204f5220277061696427204f522027657870697265642720e78ab6e680810a5550444154452072657461696c5f6465785f6f72646572730a534554207374617465203d2027726566756e646564272c20726566756e645f74785f68617368203d203a74782c20757064617465645f6174203d206461746574696d6528276e6f7727290a5748455245206964203d203a6f726465725f69640a2020414e4420737461746520494e2028276177616974696e675f7061796d656e74272c202770616964272c20276578706972656427290a2020414e4420726566756e645f74785f68617368204953204e554c4c20202d2d206964656d706f74656e637920696e76617269616e740a6060600a726f777341666665637465643d30203d20616c72656164792d726566756e646564204f5220696e76616c6964207072652d636f6e646974696f6e2e2063616c6c657220e79c8b2030203d206e6f2d6f702072657475726e206561726c792e0a0a23232320e79c9f20726566756e6420e79c9f2073696e676c6520706174682028e69bbfe4bba3205f7363616e4578706972656442726f6b65724f6666657273202b2068616e646c6543616e63656c416e64526566756e6420e4b8a4e69da1290a0a6060606a730a2f2f2062726f6b65722d73746174652d6d616368696e652e6a7320e58d95204150490a6578706f7274206173796e632066756e6374696f6e20616476616e6365546f526566756e646564286f7264657249642c20726561736f6e29207b0a20202f2f20312e207072652d636865636b3a206964656d706f74656e63790a2020636f6e7374206f72646572203d2073716c6974652e70726570617265286053454c4543542073746174652c20726566756e645f74785f686173682c207174792046524f4d2072657461696c5f6465785f6f7264657273205748455245206964203d203f60292e676574286f726465724964293b0a202069662028216f72646572207c7c206f726465722e726566756e645f74785f68617368292072657475726e207b206f6b3a20747275652c20616c7265616479526566756e6465643a2074727565207d3b0a202069662028215b276177616974696e675f7061796d656e74272c202770616964272c202765787069726564275d2e696e636c75646573286f726465722e73746174652929207b0a2020202072657475726e207b206f6b3a2066616c73652c20726561736f6e3a2027696e76616c6964207072652d636f6e646974696f6e3a2027202b206f726465722e7374617465207d3b0a20207d0a0a20202f2f20322e206669726520636861696e20545820e68bbf2068617368202873796e632077616974290a2020636f6e737420726566756e64416d74203d202b287061727365466c6f6174286f726465722e71747929202d204645455f4b4153292e746f46697865642834293b0a2020636f6e737420726573756c74203d20617761697420656e71756575655665726966696564287b0a202020206b696e643a202773656e644b6173272c20706565723a206765744f7264657250656572286f726465724964292c0a202020207061796c6f61643a207b20616d6f756e745f6b61733a20726566756e64416d742c206e6f74653a2060726566756e6420247b726561736f6e7d20247b6f7264657249642e736c69636528302c2038297d60207d2c0a20207d293b0a2020636f6e737420747848617368203d20726573756c743f2e747849643b0a20206966202821747848617368292072657475726e207b206f6b3a2066616c73652c20726561736f6e3a202773656e644b6173206661696c656420776974686f7574207478496427207d3b0a0a20202f2f20332e20616476616e636520737461746520696e2073616d6520545820617320636861696e2068617368207265636f72640a2020636f6e73742074786e203d2073716c6974652e7472616e73616374696f6e282829203d3e207b0a20202020636f6e737420757064203d2073716c6974652e7072657061726528600a2020202020205550444154452072657461696c5f6465785f6f72646572730a202020202020534554207374617465203d2027726566756e646564272c20726566756e645f74785f68617368203d203f2c20757064617465645f6174203d206461746574696d6528276e6f7727290a2020202020205748455245206964203d203f20414e4420726566756e645f74785f68617368204953204e554c4c0a2020202060292e72756e287478486173682c206f726465724964293b0a20202020696620287570642e6368616e676573203d3d3d203029207b0a2020202020202f2f20726163653a20616e6f74686572207061746820616c726561647920616476616e636520e28094206c6f67202b206c6561766520686173682061732069730a202020202020636f6e736f6c652e7761726e28605b73746174652d6d616368696e655d2072616365206f6e20616476616e6365546f526566756e64656420247b6f7264657249647d3a20616c726561647920726566756e64656460293b0a20202020202072657475726e207b206f6b3a20747275652c2072616365643a2074727565207d3b0a202020207d0a202020202f2f20616c69676e2065786368616e67655f6f66666572730a2020202073716c6974652e7072657061726528600a2020202020205550444154452065786368616e67655f6f6666657273205345542070726f746f636f6c5f737461747573203d2027726566756e646564272c20757064617465645f6174203d206461746574696d6528276e6f7727290a2020202020205748455245206964203d202853454c4543542065786368616e67655f6f666665725f69642046524f4d2072657461696c5f6465785f6f7264657273205748455245206964203d203f290a2020202060292e72756e286f726465724964293b0a202020202f2f20636861696e5f6576656e747320e79c9f20636861696e20545820686173682c20e4b88d20706c616365686f6c6465720a2020202073716c6974652e7072657061726528600a202020202020494e5345525420494e544f20636861696e5f6576656e74732028747869642c206576656e745f747970652c207061796c6f61642c206f627365727665645f62792c206f627365727665645f6174290a20202020202056414c55455320283f2c202762726f6b65725f6b61735f726566756e646564272c203f2c202773746174652d6d616368696e65272c206461746574696d6528276e6f772729290a2020202060292e72756e287478486173682c204a534f4e2e737472696e67696679287b206f726465725f69643a206f7264657249642c20726561736f6e2c20616d6f756e743a20726566756e64416d74207d29293b0a2020202072657475726e207b206f6b3a20747275652c20747848617368207d3b0a20207d293b0a202072657475726e2074786e28293b0a7d0a6060600a0a63616c6c6572202863726f6e206175746f2d726566756e64204f5220757365722063616e63656c2d726566756e642920e585a820726f757465207468726f75676820616476616e6365546f526566756e6465642e0a2d20706c616365686f6c646572207478696420e4b88de58fafe883bd20494e53455254202841504920e5bcbae588b620e79c9f20636861696e2068617368292e0a2d20e9878de5a48d206669726520e4b88de58fafe883bd20286964656d706f74656e637920696e76617269616e7420726f777341666665637465643d30292e0a2d206f666665722e70726f746f636f6c5f737461747573202b2072657461696c5f6465785f6f72646572732e7374617465202b20636861696e5f6576656e747320e4b889e8a1a82061746f6d69632073616d652d5458207570646174652e0a0a23232320e79c9f2063616e63656c20696e74656e7420e79c9f2064697370617463680a0a6060606a730a2f2f2062726f6b65722d63616e63656c2d726566756e642e6a732068616e646c6543616e63656c416e64526566756e6420e79c9f2073696d706c6966790a6578706f7274206173796e632066756e6374696f6e2068616e646c6543616e63656c416e64526566756e6428706565724164647229207b0a20202f2f20e79c9f2063757272656e74206472616674202873746174653d27616c69676e696e67272f27636f6e6669726d696e67272920e2809420636c6561725374617465206f6e6c792c20e4b88d206669726520636861696e2054580a2020636f6e73742063757272656e744472616674203d2067657443757272656e744472616674287065657241646472293b0a20206966205b2e2e2e5d