Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0a8b632
feat(core): L1 反滥用共识内核——消息防刷底线(随长度递增)+ 质押式匿名身份(纯锁仓无罚没)
v0id-byte Jul 3, 2026
092665e
feat(node,cli,web): 质押式匿名身份下游接线——API/CLI/Web 面板
v0id-byte Jul 3, 2026
b637cc3
test: 两个新 selftest——message-burn-floor-selftest.ts / identity-selftes…
v0id-byte Jul 3, 2026
9665dec
fix(smoke): 加密私信场景补足挖矿本金 + 检查 addTransaction 返回值;ci: 纳入两个新 selftest
v0id-byte Jul 3, 2026
fc6e292
fix(core): isProtocolMemo 收紧为精确校验,堵住套壳绕过消息防刷底线的漏洞
v0id-byte Jul 3, 2026
4f019dc
fix(core): 补 IDENTITY_ESCROW_ADDRESS 进 SYSTEM_ADDRESSES
v0id-byte Jul 3, 2026
3ebcc54
fix(node,cli,web): 消息默认烧币值真正按长度计算,而非在更早的调用点就被扁平默认值锁死
v0id-byte Jul 3, 2026
deeec7a
fix(core): isProtocolMemo 补 from/to/amount 语境校验,堵住第二层套壳绕过
v0id-byte Jul 3, 2026
af2321f
fix(node): claimIdentity() 补节点内部激活高度守卫,防止提前认领永久锁死押金
v0id-byte Jul 3, 2026
5bc702e
fix(core): addBlock 后清理 mempool 里被判负的排他性交易,防止身份认领竞态卡死钱包
v0id-byte Jul 3, 2026
f01071b
fix(core): isProtocolMemo 补 from/to/amount 语境校验,堵住第二层套壳绕过
v0id-byte Jul 3, 2026
84ebb92
perf(core): revalidateMempool 复用单份 computeState,避免每次出块全量重放 mempool×链
v0id-byte Jul 3, 2026
ed7d487
fix(core): isMemoSpamCandidate 扩大消息防刷候选范围,堵住「自转夹带」绕过(关键修复)
v0id-byte Jul 3, 2026
37bb6f1
fix(node): revalidateMempool 补 onMempoolDropped 回调,同步清理 seenTx 去重缓存
v0id-byte Jul 3, 2026
1ff7fe5
fix(core): computeIdentityState 跳过 coinbase,防止恶意矿工伪造身份认领的只读展示
v0id-byte Jul 3, 2026
5760699
fix(core): isProtocolMemo 补 DEL 撤单豁免 + IDRELEASE 的 amount 依赖条件
v0id-byte Jul 3, 2026
f00f5d6
fix(core): browser.ts 补 identity.js 导出,补全浏览器端身份质押能力
v0id-byte Jul 4, 2026
80a713b
fix(core): isProtocolMemo 补 ROOM| 房间发布豁免,堵住消息防刷底线漏判
v0id-byte Jul 4, 2026
4539273
fix(core): isProtocolMemo 堵住数字/字符串字段填充套壳绕开消息防刷底线
v0id-byte Jul 4, 2026
71c284c
fix(core): isProtocolMemo 补 PET/FISH/LAND 缺失的 burn>0 校验
v0id-byte Jul 4, 2026
12d9798
fix(core): IDRELEASE 未激活守卫补 burn=0 条件,防历史消息被 retroactive 判非法
v0id-byte Jul 4, 2026
b7d3154
fix(core): isProtocolMemo 保留字符串入参兼容,不静默破坏公共出口签名
v0id-byte Jul 4, 2026
ebef92a
fix(core): 消息门槛补免费备注额度,封堵双钱包接力绕过(#1,维护者选定方案)
v0id-byte Jul 4, 2026
15546e4
fix(core): isProtocolMemo 补集市 BUY 豁免 + 字符串入参恢复历史纯前缀语义
v0id-byte Jul 4, 2026
8d2b0fd
feat(node): 送币路径支持 burn——长备注付款可补足消息门槛所需销毁额(#4)
v0id-byte Jul 4, 2026
d93edf7
fix(core): parsePets 送崽须 amount>0,与 isProtocolMemo 分类对齐(#2)
v0id-byte Jul 4, 2026
13fbe1e
perf(test): identity-selftest 锁定期等待改用 forgeTo + forge 时间戳钳到 now(#5)
v0id-byte Jul 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ jobs:
- name: Relay anti-replay test
run: pnpm exec tsx scripts/antireplay-test.ts

- name: Message burn floor selftest
run: pnpm exec tsx scripts/message-burn-floor-selftest.ts

- name: Identity staking selftest
run: pnpm exec tsx scripts/identity-selftest.ts
Comment on lines +43 to +47

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 Keep the new selftests within the CI timeout

Both added selftests forge to very high activation heights (40000 and 45000) by repeatedly calling the real PoW mineBlock; I checked the workflow context and a local 70s run of the same forge helper only reached height 5000, so these two new steps alone are likely to exceed the check job's 15-minute timeout and make PR CI fail before tests complete. Use a cheaper deterministic block builder for these activation-height tests or lower the heights under test.

Useful? React with 👍 / 👎.


docker:
name: docker image builds
runs-on: ubuntu-latest
Expand Down
52 changes: 47 additions & 5 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
MINT_DEPOSIT_PREFIX,
MINT_ADDRESS,
MINT_ACTIVATION_HEIGHT,
IDENTITY_STAKE_MIN,
type RelayDescriptor,
} from '@v0idchain/core';

Expand Down Expand Up @@ -337,27 +338,31 @@ txCmd(program.command('send'))
.argument('<amount>', '金额')
.option('--memo <text>', '附带一段备注(上链可查)', '')
.option('--fee <n>', `手续费(gas;省略则自动算:max(${MIN_FEE}, 金额×0.1%))`)
.description('转账(需付 金额 + 手续费/gas)')
.option('--burn <n>', '为超长备注附带的销毁额(消息门槛激活后长备注付款需要;省略则按备注长度自动补足)')
.description('转账(需付 金额 + 手续费/gas;长备注还需按门槛销毁)')
.action(async (to, amount, o) => {
const amt = Number(amount);
const fee = o.fee !== undefined ? Number(o.fee) : minFeeFor(amt);
const r = await api(o,'POST', '/send', { to, amount: amt, memo: o.memo, fee });
const burn = o.burn !== undefined ? Number(o.burn) : undefined; // 省略 → 节点按备注长度自动补足
const r = await api(o,'POST', '/send', { to, amount: amt, memo: o.memo, fee, burn });
console.log(c.green('✅ 交易已广播'), c.dim('txid='), r.txid, c.dim(`手续费=${fee}`));
if (o.wait) await waitConfirm(o, r.txid);
});

txCmd(program.command('msg'))
.argument('<to>', '收件人地址')
.argument('<text...>', '消息正文')
.option('--burn <n>', `烧进虚空的 $V0ID(永久销毁;默认 ${MESSAGE_BURN},越多越壕)`, String(MESSAGE_BURN))
.option('--burn <n>', `烧进虚空的 $V0ID(永久销毁;不指定则按正文长度自动算,默认起步 ${MESSAGE_BURN}、越长烧越多,越多越壕)`)
.option('--fee <n>', `手续费(gas,给打包矿工,至少 ${MIN_FEE})`, String(MIN_FEE))
.option('-e, --encrypt', '端到端加密(只有收件人能解;发件人也能解自己发的)', false)
.description('给一个地址发链上消息(不转币,烧掉一点 $V0ID;-e 加密)')
.action(async (to, text, o) => {
const burn = Number(o.burn);
// 不传 --burn 时保持 undefined(而非拼一个固定默认值):让节点按最终 memo 长度(加密则是密文长度)自动算,
// 消息防刷底线激活后固定默认值对长消息会不够烧、被拒收。
const burn = o.burn === undefined ? undefined : Number(o.burn);
const r = await api(o, 'POST', '/message', { to, text: text.join(' '), burn, fee: Number(o.fee), encrypt: !!o.encrypt });
const lock = o.encrypt ? c.cyan(' 🔒加密') : '';
console.log(c.green('✉️ 消息已广播') + lock, c.dim('txid='), r.txid, c.dim(`🔥烧=${burn} 手续费=${Number(o.fee)}`));
console.log(c.green('✉️ 消息已广播') + lock, c.dim('txid='), r.txid, c.dim(`🔥烧=${burn ?? '(按长度自动)'} 手续费=${Number(o.fee)}`));
console.log(c.dim('(打包确认后,对方 `v0id inbox` 即可看到)'));
if (o.wait) await waitConfirm(o, r.txid);
});
Expand Down Expand Up @@ -546,6 +551,43 @@ txCmd(red.command('refund'))
if (o.wait) await waitConfirm(o, r.txid);
});

// ---- identity 质押身份(纯资金锁仓反女巫,无罚没、无仲裁者)----
const identity = program.command('identity').description('质押身份:纯资金锁仓反女巫,押金须持续持有才算拥有身份');
txCmd(identity.command('claim'))
.argument('<pseudonym>', '想认领的假名(1~20 位 小写字母/数字/_/-)')
.description(`认领一个身份(转给托管地址 ${IDENTITY_STAKE_MIN} 押金 + memo;挖进区块后生效)`)
.action(async (pseudonym, o) => {
const r = await api(o, 'POST', '/identity/claim', { pseudonym });
console.log(c.green('🪪 已提交认领'), c.dim('txid='), r.txid, c.dim(`(押金 ${IDENTITY_STAKE_MIN};打包确认后生效)`));
if (o.wait) await waitConfirm(o, r.txid);
});
txCmd(identity.command('release'))
.argument('<claimTxid>', '认领交易 txid(IDCLAIM 交易 txid)')
.description('解锁:过锁定期后取回全部押金(无罚没);解锁后该假名立刻可被别人重新认领')
.action(async (claimTxid, o) => {
const r = await api(o, 'POST', '/identity/release', { claimTxid });
console.log(c.green('🔓 已提交解锁'), c.dim('txid='), r.txid);
if (o.wait) await waitConfirm(o, r.txid);
});
apiOpt(identity.command('list'))
.description('看本节点自己的身份质押')
.action(async (o) => {
const list = (await api(o, 'GET', '/identity')) as any[];
if (!list.length) return console.log(c.dim('(暂无身份质押)'));
for (const claim of list) {
const tag = claim.released ? c.dim('[已解锁]') : c.green('[活跃]');
console.log(`${tag} ${c.cyan('#' + claim.pseudonym)} 押金 ${claim.amount} ${SYMBOL} 锁至 #${claim.lockedUntil}`);
console.log(` ${c.dim('id ' + claim.id.slice(0, 12) + '…')}`);
}
});
apiOpt(identity.command('resolve'))
.argument('<pseudonym>', '假名')
.description('查某假名当前属于哪个地址')
.action(async (pseudonym, o) => {
const r = await api(o, 'GET', `/identity/resolve?pseudonym=${encodeURIComponent(pseudonym)}`);
console.log(r.owner ? `${c.cyan('#' + pseudonym)} → ${c.green(r.owner)}` : c.dim(`#${pseudonym} 当前无人持有`));
});

// ============================================================================
// 中继激励链下工具(Phase 3A-2/3/4):度量者 measure / 奖励 reward-epoch / 罚没 slash-epoch
// —— 全部链下:measure 探测出 attestation;reward-epoch 默认只预览(有限国库池,--send 才真发);
Expand Down
Loading
Loading