账户与 Object 模型设计(单链)
日期:2026-07-19
类型:状态/账户模型设计
状态:已对齐需求
关联:2026-07-19-主分片共识-design.md(本模型作用于每一条链内部)
参考:lengzhao/vm docs(architecture / default_library / execution_environment)
1. 目标
在单条链内统一:
- 类 UTXO:用户拥有的 Object(含原生 Coin Object),修改需用户签名
- 全局账户:合约默认 Object(Owner=合约),类似 EVM 共享状态,冲突时串行
- 冻结:不另设类型,将 Owner 转为协议保留的 冻结地址
- 防状态爆炸:每个 Object 均有 有效期;到期移出活集;支付费用可续期
不另建「地址→余额」总账;原生币以 Coin Object 为主。
对象版本:活集与防双花以单调 version 为准(不用 content_hash 作活键)。
2. 核心模型(§1)
2.1 唯一状态载体:Object
每个 Object 至少包含(对齐 default_library Object):
| 字段 | 含义 |
|---|---|
id |
稳定 ObjectID |
owner |
用户地址 / 合约地址 / FREEZE_ADDR |
contract |
所属合约 |
content / 字段存储 |
Get/Set 的业务数据 |
version |
单调版本号;业务写入时 +1;创建时为 1(或 0,实现选定) |
expire_at |
有效期截止(区块时间或高度);到期后不再属于活集 |
updated_at |
上次业务更新时间(可选;续期可不改) |
账户 = Address(签名主体与 Owner),不是独立余额账本。
所有 Object(含默认 Object、Coin、已冻结 Object)都必须带有效期;冻结只禁止改内容/Owner,不免除续期义务。
2.2 Owner 决定语义(不设 Shared/Immutable 枚举)
| Owner | 行为 | 类比 |
|---|---|---|
| 用户地址 | 修改/转移需该用户签名 | UTXO / Sui Owned |
| 合约地址 | 仅在该合约执行上下文中可改 | Shared(合约门控) |
FREEZE_ADDR |
协议保留、无私钥;写入/再转移禁止 | Immutable(用转 Owner 实现) |
flowchart TD
O[任意 Object 必有 Owner]
O --> U{Owner?}
U -->|用户| A[需用户签名<br/>类 UTXO]
U -->|合约| B[仅合约可改<br/>类 Shared]
U -->|FREEZE_ADDR| C[冻结只读]
A -->|SetOwner 冻结地址| C
B -->|合约 SetOwner| C
2.3 与 vm 双模式的对应
- 统一账户:状态写入合约默认 Object(空 ID,Owner=合约)→ 易冲突 → 串行
- 并行路径:为用户创建独立 Object(Owner=用户)→ 无读写交集可 并行
权限(architecture §3.7):可写当且仅当 Owner 为交易发起方(已签名)或当前执行合约。
2.4 有效期与续期(防状态爆炸)
| 规则 | 说明 |
|---|---|
| 创建 | CreateObject / 部署默认 Object / 铸造 Coin 时写入初始 expire_at = now + TTL_default,version = 1 |
| 活集条件 | 仅当 now < expire_at 时对象可被 read/write;否则视为不存在(与错误 version 一样导致交易失败) |
续期 Renew |
任何人均可对任意 Object 支付续期费并延长 expire_at;不修改业务内容,version 不变 |
| 费用 | 续期费可与存储大小、延长时长成正比;从支付者 Coin 扣除(同 Gas 机制) |
| 过期后果 | 移出活集,节点可删除本地存储;不自动发回余额(Coin 过期等于该面额消失,除非另设宽限期认领——默认不做) |
| 与冻结 | Owner=FREEZE_ADDR 的对象仍可被任何人续期;无人续期则过期回收,避免「冻住即永久占存储」 |
| 与防双花 | 续期不是状态突变:活键仍为原 (object_id, version);仅延长 expire_at,不导致旧引用失效 |
stateDiagram-v2
[*] --> Alive: Create(expire_at, version)
Alive --> Alive: Renew(任何人付费)\nexpire_at 延长 / version 不变
Alive --> Alive: 业务写入\nversion+1
Alive --> Expired: now >= expire_at
Expired --> [*]: 移出活集/可GC
实现提示:expire_at 为侧车元数据(租金索引),不因续期而 bump version;仅业务 Set / SetOwner / Coin 拆并等改变内容时 version += 1。
3. Coin Object(§2)
原生币是一类特殊 Object,不维护地址余额表。
| 字段 | 含义 |
|---|---|
id / owner / contract / version / expire_at |
同普通 Object;contract 为系统币种合约 |
amount |
面额;变为 0 则删除对象 |
某地址余额 = 其拥有的同币种 Coin 的 amount 之和。
业务变更(Split/Merge/Transfer/扣 Gas)→ version + 1;纯 Renew → version 不变。
3.1 拆分 / 合并 / Transfer
| 操作 | 规则 |
|---|---|
| Split | 消耗输入 Coin(需授权),产出多个新 Coin,金额守恒;输入旧 version 失效,输出新 id+version |
| Merge | 同币种 Coin 合并(Owner 规则满足时) |
Transfer(from,to,amount) |
语法糖:选 Coin → Split/Merge → SetOwner(to) |
3.2 Gas
- 用原生 Coin Object 支付;Gas Coin ∈
write_list(带当前version) - Owner 须为发起方并签名
- 扣费通过减额/Split,找零留在发起方名下
3.3 冻结
SetOwner(FREEZE_ADDR)(业务写入 →version + 1)- 之后禁止
Set、禁止再SetOwner、禁止作 Gas - 默认不可解冻(治理特权另议)
- 仍须按 §2.4 续期;冻结≠永久免租金
3.5 Coin 与有效期
- Coin 同样有
expire_at;持币人需续期,否则过期后该 Coin 从活集消失 - 建议钱包在临近过期时自动
Renew;合并 Coin 时可取「各输入 expire_at 的保守策略」(例如取 min 再强制续期到统一截止)
3.4 存放边界
| 用途 | 放置 |
|---|---|
| 用户持币、并行转账 | Coin,Owner=用户 |
| 合约金库 | Coin,Owner=合约 |
| 合约 kv / 池参数 | 默认 Object,Owner=合约 |
| 永久只读 | 任意 Object → FREEZE_ADDR |
4. 交易、并行与防双花(§3)
4.1 交易声明
| 字段 | 含义 |
|---|---|
read_list |
只读 (object_id, version)* |
write_list |
将修改的 (object_id, version)* |
| 签名集 | 覆盖所有「Owner=用户」且出现在 write(及所需授权)中的地址 |
Gas Coin、默认 Object(若写入)必须出现在正确列表中。
引用对象时校验:活集中存在该 (id, version) 且 now < expire_at,否则按「对象不存在」失败。
Renew:不要求目标进入 write_list(version 不变);支付续期费的 Coin 仍进支付方 write_list。任何人可续期任意未过期 Object。
4.2 写授权
flowchart TD
W[Write 目标] --> O{Owner?}
O -->|用户| S{含该用户签名?}
S -->|否| F[拒绝]
S -->|是| OK[允许]
O -->|合约| C{在该合约上下文?}
C -->|否| F
C -->|是| OK
O -->|FREEZE_ADDR| F
4.3 冲突与并行
冲突:一笔的 write 与另一笔的 read∪write 有交集(按 object_id,或更严按 (id, version))。
| 模式 | 调度 |
|---|---|
| 不同用户 Coin/Object,write 无交 | 可并行 |
| 争用同一默认 Object | 串行 |
| 只读∩只读 | 不冲突 |
由链节点按 Read/WriteList 调度;VM 可被并行调用(execution_environment §6)。
4.4 防双花:ID + version(已定稿)
活对象键 = (object_id, version)。
- 交易输入必须引用当前活的
version - Object 一旦被业务写入,旧 version 立即从活集移除,新状态为
version + 1 - 双花第二笔仍带旧 version → 该版本对象不存在 → 交易失败
- 并行下同一
(id, version)至多被一笔交易写入 Renew不增加 version,故续期不会使已广播的(id, version)引用失效
sequenceDiagram
participant T1 as 交易1
participant S as 活对象集
participant T2 as 交易2双花
Note over S: O = id + version=5
T1->>S: 引用 id@v5 并修改
S->>S: 失效 v5,写入 id@v6
T2->>S: 引用 id@v5
S-->>T2: 版本不存在 → 失败
稳定的是
object_id;业务变更时递增的是version。双花失败是因为旧 version 不在活集,不是因为 ID 消失。
5. 地址、默认 Object 与链边界(§4)
5.1 地址类型
| 种类 | 说明 |
|---|---|
| 用户地址 | 由公钥派生,可签名 |
| 合约地址 | 部署生成;可作 Owner;不可「用户式」签名,靠调用上下文授权 |
FREEZE_ADDR |
协议常量,无私钥 |
5.2 合约默认 Object
- 部署时自动创建;空 ObjectID(或约定 ID)取得
- Owner = 合约地址;初始
version = 1 - 承载「全局账户」状态;多笔争用则串行
- 同样有有效期:可被任何人付费续期(version 不变),否则过期不可用
5.3 与主分片的关系
- 本模型 每条链一份 Object 状态;链间不共享 ObjectID 空间(或加
chain_id前缀) - 跨链资产移动走共识文档中的父子锚定 / 跨链消息,不在本文展开
- 创链、出块等见
2026-07-19-主分片共识-design.md
6. 决策记录
| 项 | 选择 |
|---|---|
| 状态内核 | lengzhao/vm Object(含 Owner) |
| 全局账户 | 合约默认 Object(Owner=合约) |
| UTXO 感 | Owner=用户 + 签名 + (id, version) 引用 |
| 冻结 | SetOwner(FREEZE_ADDR),不单列类型 |
| 原生币 | Coin Object 为主;Transfer 为语法糖 |
| 防双花 | 活键 (object_id, version);业务写则旧 version 失效 |
| 并行 | Read/WriteList + 对象隔离 |
| 状态租金 | 每 Object 必有 expire_at;任何人可付费 Renew;续期不改 version;过期移出活集 |
| 不用 content_hash 作活键 | 已否决;若将来要完整性证明可另加可选 digest,但不参与防双花主键 |
7. 待标定参数
version起始值(0 或 1)与溢出策略(u64 足够)FREEZE_ADDR常量取值- TTL_default、按字节计费的续期费率、单次续期上限(代付已定为任何人可续)
- 过期 Coin 是否提供短宽限期(默认无)
expire_at存储位置(侧车租金索引)- 原生币小数位、最小面额、Coin 合并上限
- 交易未声明却访问对象时的失败策略(严格拒绝 vs 执行期补查)
- 合约上下文嵌套调用时的 Owner 授权栈规则细节
与 vm 文档统一:Object + Owner + 默认 Object 双模式;防双花采用单调 version(类 Sui),续期与 version 解耦。