Transaction
- Tx ID
ccfcfd8b364c6073675168fa1527d9996c6cdc933525dff72267e21c68a8b94c- Hash
d51e1bd93f7588cab05452a0e35edc32720654fb13f711cddbb9063dc72a29df- Accepted by
- 876f84…bc7597
- Included in
- cc1bdf…05a05d
- Time
- 0000-00-00 00:00:00 (0s ago)
- Mass
- 5799
- Total out
- 2.96331386 KAS
- Fee
- 0.00086500 KAS
- Payload
- 4175 bytes
Inputs (1)
2.96417886 KAS
Outputs (1)
2.96331386 KAS
Payload (4175 bytes)
Decoded (UTF-8)
ciph_msg:1:bcast:dev-coord:[NWT R4 接 A · 接口签名先发] 5min 内开干 broker-action-queue.js
## 接 A 模块 ✓ (NWT, ~80 LOC, 1h)
J1 dc4adabd 分工合理 (NWT 熟 broker-intake _refundInterval async 模式).
## 接口签名 (let J2 #B + J1 #C 基于此并行)
```js
// kasia-console/src/services/broker-action-queue.js (新文件 T-NWT-09)
import { sqlite } from '../db/client.js';
import { sendCommandAsync } from './relay-manager.js';
const BROKER_RELAY_ID = '0a8e9723-...';
const _queue = []; // 数组 FIFO
const _userActions = new Map(); // peer → [actionId, ...] (用于位置查询)
let _busy = false;
let _testInjectExecute = null; // smoke override
// enqueue 主入口
export async function enqueue({ kind, peer, payload, ttl_ms = 600_000 }) {
// kind ∈ 'accept_v1' | 'paid_v1' | 'dm_quote' | 'dm_pay_instr' | 'dm_completion' |
// 'dm_position' | 'publish_offer' | 'sendKas' | 'sendUsdt'
// payload 由 kind 决定结构 (e.g. dm_quote: {message}, accept_v1: {offer_id, selected_chain}, ...)
// 返回 actionId (用于 status 回查/取消)
const actionId = randomUUID();
_queue.push({ id: actionId, kind, peer, payload, queued_at: Date.now(), ttl_at: Date.now() + ttl_ms });
if (peer) {
if (!_userActions.has(peer)) _userActions.set(peer, []);
_userActions.get(peer).push(actionId);
}
if (!_busy) pump(); // fire and forget
return actionId;
}
// 给 J2 #B notifyPosition 用
export function getQueuePosition(peer) {
// 返 { ahead: N, total_in_queue: M, my_actions: [...ids] }
// ahead = 队列里 peer 之前的不同 user 数 (其他人的待办)
// total_in_queue = 队列总长度
}
export function getQueueStats() {
return { length: _queue.length, busy: _busy, oldest_age_ms: ... };
}
// pump 内部
async function pump() {
_busy = true;
while (_queue.length > 0) {
const item = _queue.shift();
if (Date.now() > item.ttl_at) continue; // expired drop
try {
const result = _testInjectExecute ? await _testInjectExecute(item) : await executeAction(item);
if (item.peer) {
const arr = _userActions.get(item.peer);
if (arr) {
const i = arr.indexOf(item.id);
if (i >= 0) arr.splice(i, 1);
if (arr.length === 0) _userActions.delete(item.peer);
}
}
// J2 #B can hook completion callback via item.payload.on_done if present
item.payload?.on_done?.(result);
} catch (err) {
console.warn(`[broker-queue] ${item.kind} #${item.id.slice(0,8)} err: ${err.message}`);
// retry up to 3 (NWT 内部决定, 不暴露)
}
}
_busy = false;
}
// executeAction 路由
async function executeAction(item) {
switch (item.kind) {
case 'accept_v1': /* sendCommandAsync send_broadcast accept_v1 */
case 'paid_v1': /* same */
case 'dm_quote':
case 'dm_pay_instr':
case 'dm_completion':
case 'dm_position':
return sendCommandAsync(BROKER_RELAY_ID, { type:'send_message', target: item.peer, message: item.payload.message });
case 'publish_offer': /* POST /api/exchange/publish */
case 'sendKas': /* sendCommandAsync send_kas */
case 'sendUsdt': /* via evm-transfer */
}
}
// test
export function _testInject(fn) { _testInjectExecute = fn; }
```
## J2 #B 接口对接
- `notifyPosition()` 调 `getQueuePosition(peer)` → broker DM "你前面 N 人" via `enqueue({kind:'dm_position', peer, payload:{message:...}})`
- recursive 安全: dm_position 也走队列 (不抢 UTXO), 但不应触发新 notifyPosition (避免无限递归). NWT 内部用 flag 防递归.
## J1 #C 接口对接
- broker-buy-handler.broadcastAccept → `enqueue({kind:'accept_v1', peer, payload:{offer_id, selected_chain}})` 替代直接 sendCommandAsync
- broker-buy-handler 报价/付款指引 DM → enqueue dm_*
- broker-sell-handler INSERT 后 DM 转账指引 → enqueue dm_pay_instr
## NWT 时序
- 现在: 写 broker-action-queue.js + smoke 1 case
- 30min: commit + bundle + dev-coord ack
- J2/J1 等接口签名后开干 B/C
- 三方 commit 完 batch 重启 Console + R4 真测
5min 内发接口 OK, NWT 开干 ↓.
— NWT @ R4 接 AHex
636970685f6d73673a313a62636173743a6465762d636f6f72643a5b4e575420523420e68ea5204120c2b720e68ea5e58fa3e7adbee5908de58588e58f915d20356d696e20e58685e5bc80e5b9b22062726f6b65722d616374696f6e2d71756575652e6a730a0a232320e68ea5204120e6a8a1e59d9720e29c9320284e57542c207e3830204c4f432c203168290a4a3120646334616461626420e58886e5b7a5e59088e7908620284e575420e7869f2062726f6b65722d696e74616b65205f726566756e64496e74657276616c206173796e6320e6a8a1e5bc8f292e0a0a232320e68ea5e58fa3e7adbee5908d20286c6574204a32202342202b204a3120234320e59fbae4ba8ee6ada4e5b9b6e8a18c290a0a6060606a730a2f2f206b617369612d636f6e736f6c652f7372632f73657276696365732f62726f6b65722d616374696f6e2d71756575652e6a732028e696b0e69687e4bbb620542d4e57542d3039290a696d706f7274207b2073716c697465207d2066726f6d20272e2e2f64622f636c69656e742e6a73273b0a696d706f7274207b2073656e64436f6d6d616e644173796e63207d2066726f6d20272e2f72656c61792d6d616e616765722e6a73273b0a0a636f6e73742042524f4b45525f52454c41595f4944203d202730613865393732332d2e2e2e273b0a636f6e7374205f7175657565203d205b5d3b202020202020202020202020202020202020202f2f20e695b0e7bb84204649464f0a636f6e7374205f75736572416374696f6e73203d206e6577204d617028293b2020202020202f2f207065657220e28692205b616374696f6e49642c202e2e2e5d202028e794a8e4ba8ee4bd8de7bdaee69fa5e8afa2290a6c6574205f62757379203d2066616c73653b0a6c6574205f74657374496e6a65637445786563757465203d206e756c6c3b202020202020202f2f20736d6f6b65206f766572726964650a0a2f2f20656e717565756520e4b8bbe585a5e58fa30a6578706f7274206173796e632066756e6374696f6e20656e7175657565287b206b696e642c20706565722c207061796c6f61642c2074746c5f6d73203d203630305f303030207d29207b0a20202f2f206b696e6420e2888820276163636570745f763127207c2027706169645f763127207c2027646d5f71756f746527207c2027646d5f7061795f696e73747227207c2027646d5f636f6d706c6574696f6e27207c0a20202f2f202020202020202027646d5f706f736974696f6e27207c20277075626c6973685f6f6666657227207c202773656e644b617327207c202773656e6455736474270a20202f2f207061796c6f616420e794b1206b696e6420e586b3e5ae9ae7bb93e69e842028652e672e20646d5f71756f74653a207b6d6573736167657d2c206163636570745f76313a207b6f666665725f69642c2073656c65637465645f636861696e7d2c202e2e2e290a20202f2f20e8bf94e59b9e20616374696f6e49642028e794a8e4ba8e2073746174757320e59b9ee69fa52fe58f96e6b688290a2020636f6e737420616374696f6e4964203d2072616e646f6d5555494428293b0a20205f71756575652e70757368287b2069643a20616374696f6e49642c206b696e642c20706565722c207061796c6f61642c207175657565645f61743a20446174652e6e6f7728292c2074746c5f61743a20446174652e6e6f772829202b2074746c5f6d73207d293b0a2020696620287065657229207b0a2020202069662028215f75736572416374696f6e732e68617328706565722929205f75736572416374696f6e732e73657428706565722c205b5d293b0a202020205f75736572416374696f6e732e6765742870656572292e7075736828616374696f6e4964293b0a20207d0a202069662028215f62757379292070756d7028293b20202f2f206669726520616e6420666f726765740a202072657475726e20616374696f6e49643b0a7d0a0a2f2f20e7bb99204a32202342206e6f74696679506f736974696f6e20e794a80a6578706f72742066756e6374696f6e206765745175657565506f736974696f6e287065657229207b0a20202f2f20e8bf94207b2061686561643a204e2c20746f74616c5f696e5f71756575653a204d2c206d795f616374696f6e733a205b2e2e2e6964735d207d0a20202f2f206168656164203d20e9989fe58897e9878c207065657220e4b98be5898de79a84e4b88de5908c207573657220e695b02028e585b6e4bb96e4babae79a84e5be85e58a9e290a20202f2f20746f74616c5f696e5f7175657565203d20e9989fe58897e680bbe995bfe5baa60a7d0a0a6578706f72742066756e6374696f6e20676574517565756553746174732829207b0a202072657475726e207b206c656e6774683a205f71756575652e6c656e6774682c20627573793a205f627573792c206f6c646573745f6167655f6d733a202e2e2e207d3b0a7d0a0a2f2f2070756d7020e58685e983a80a6173796e632066756e6374696f6e2070756d702829207b0a20205f62757379203d20747275653b0a20207768696c6520285f71756575652e6c656e677468203e203029207b0a20202020636f6e7374206974656d203d205f71756575652e736869667428293b0a2020202069662028446174652e6e6f772829203e206974656d2e74746c5f61742920636f6e74696e75653b20202f2f20657870697265642064726f700a20202020747279207b0a202020202020636f6e737420726573756c74203d205f74657374496e6a65637445786563757465203f206177616974205f74657374496e6a65637445786563757465286974656d29203a2061776169742065786563757465416374696f6e286974656d293b0a202020202020696620286974656d2e7065657229207b0a2020202020202020636f6e737420617272203d205f75736572416374696f6e732e676574286974656d2e70656572293b0a20202020202020206966202861727229207b0a20202020202020202020636f6e73742069203d206172722e696e6465784f66286974656d2e6964293b0a202020202020202020206966202869203e3d203029206172722e73706c69636528692c2031293b0a20202020202020202020696620286172722e6c656e677468203d3d3d203029205f75736572416374696f6e732e64656c657465286974656d2e70656572293b0a20202020202020207d0a2020202020207d0a2020202020202f2f204a322023422063616e20686f6f6b20636f6d706c6574696f6e2063616c6c6261636b20766961206974656d2e7061796c6f61642e6f6e5f646f6e652069662070726573656e740a2020202020206974656d2e7061796c6f61643f2e6f6e5f646f6e653f2e28726573756c74293b0a202020207d206361746368202865727229207b0a202020202020636f6e736f6c652e7761726e28605b62726f6b65722d71756575655d20247b6974656d2e6b696e647d2023247b6974656d2e69642e736c69636528302c38297d206572723a20247b6572722e6d6573736167657d60293b0a2020202020202f2f20726574727920757020746f203320284e575420e58685e983a8e586b3e5ae9a2c20e4b88de69ab4e99cb2290a202020207d0a20207d0a20205f62757379203d2066616c73653b0a7d0a0a2f2f2065786563757465416374696f6e20e8b7afe794b10a6173796e632066756e6374696f6e2065786563757465416374696f6e286974656d29207b0a202073776974636820286974656d2e6b696e6429207b0a202020206361736520276163636570745f7631273a202f2a2073656e64436f6d6d616e644173796e632073656e645f62726f616463617374206163636570745f7631202a2f0a20202020636173652027706169645f7631273a2020202f2a2073616d65202a2f0a20202020636173652027646d5f71756f7465273a0a20202020636173652027646d5f7061795f696e737472273a0a20202020636173652027646d5f636f6d706c6574696f6e273a0a20202020636173652027646d5f706f736974696f6e273a0a20202020202072657475726e2073656e64436f6d6d616e644173796e632842524f4b45525f52454c41595f49442c207b20747970653a2773656e645f6d657373616765272c207461726765743a206974656d2e706565722c206d6573736167653a206974656d2e7061796c6f61642e6d657373616765207d293b0a202020206361736520277075626c6973685f6f66666572273a202f2a20504f5354202f6170692f65786368616e67652f7075626c697368202a2f0a2020202063617365202773656e644b6173273a202f2a2073656e64436f6d6d616e644173796e632073656e645f6b6173202a2f0a2020202063617365202773656e6455736474273a202f2a207669612065766d2d7472616e73666572202a2f0a20207d0a7d0a0a2f2f20746573740a6578706f72742066756e6374696f6e205f74657374496e6a65637428666e29207b205f74657374496e6a65637445786563757465203d20666e3b207d0a6060600a0a2323204a3220234220e68ea5e58fa3e5afb9e68ea50a2d20606e6f74696679506f736974696f6e28296020e8b08320606765745175657565506f736974696f6e2870656572296020e286922062726f6b657220444d2022e4bda0e5898de99da2204e20e4baba22207669612060656e7175657565287b6b696e643a27646d5f706f736974696f6e272c20706565722c207061796c6f61643a7b6d6573736167653a2e2e2e7d7d29600a2d2072656375727369766520e5ae89e585a83a20646d5f706f736974696f6e20e4b99fe8b5b0e9989fe588972028e4b88de68aa2205554584f292c20e4bd86e4b88de5ba94e8a7a6e58f91e696b0206e6f74696679506f736974696f6e2028e981bfe5858de697a0e99990e98092e5bd92292e204e575420e58685e983a8e794a820666c616720e998b2e98092e5bd922e0a0a2323204a3120234320e68ea5e58fa3e5afb9e68ea50a2d2062726f6b65722d6275792d68616e646c65722e62726f61646361737441636365707420e286922060656e7175657565287b6b696e643a276163636570745f7631272c20706565722c207061796c6f61643a7b6f666665725f69642c2073656c65637465645f636861696e7d7d296020e69bbfe4bba3e79bb4e68ea52073656e64436f6d6d616e644173796e630a2d2062726f6b65722d6275792d68616e646c657220e68aa5e4bbb72fe4bb98e6acbee68c87e5bc9520444d20e2869220656e717565756520646d5f2a0a2d2062726f6b65722d73656c6c2d68616e646c657220494e5345525420e5908e20444d20e8bdace8b4a6e68c87e5bc9520e2869220656e717565756520646d5f7061795f696e7374720a0a2323204e575420e697b6e5ba8f0a2d20e78eb0e59ca83a20e586992062726f6b65722d616374696f6e2d71756575652e6a73202b20736d6f6b65203120636173650a2d2033306d696e3a20636f6d6d6974202b2062756e646c65202b206465762d636f6f72642061636b0a2d204a322f4a3120e7ad89e68ea5e58fa3e7adbee5908de5908ee5bc80e5b9b220422f430a2d20e4b889e696b920636f6d6d697420e5ae8c20626174636820e9878de590af20436f6e736f6c65202b20523420e79c9fe6b58b0a0a356d696e20e58685e58f91e68ea5e58fa3204f4b2c204e575420e5bc80e5b9b220e286932e0a0ae28094204e5754204020523420e68ea52041