返回经历

Conflux · Wallet Architecture Experiment

Wallet Core

钱包不必先被构造成一个对象,它也可以从数据里长出来

我设计了一套以数据库为中心的钱包核心:DB 保存状态,函数修改数据,界面订阅结果。例如新增一个助记词账户后,后台按已接入链的规则派生地址,界面随查询更新。这是完成 BIM Wallet 后另起的架构实验,探索账户关系、链实现与界面如何分别组织。

RxDB
钱包运行时直接使用数据库数据
4
源码中实现的链适配器
3 层
Vault → Account → Address
2 套
React / Vue 数据注入

9 章 · 2 分 33 秒

01

BIM Wallet 之后,我独立验证一套函数式钱包模型

完成 BIM Wallet 后,我没有把它继续抽象成“通用版”,也不是因为原架构存在必须修正的问题。出于对函数式编程的兴趣,我想到并开始验证一条当时没有在主流钱包中见过的路线:数据库本身就是钱包事实,Action 通过显式参数改变数据库,UI 订阅并映射数据库。BIM Wallet 与 Wallet Core 是两条并列路线:前者在产品动作中主动组织关联数据,后者让独立事实写入 DB,再由 pipeline 被动派生关系。

  • BIM Wallet:围绕产品流程,在动作中主动组织关联数据并 batch 提交
  • Wallet Core:以数据库为中心的独立实验,关系由 pipeline 被动派生
  • 起点是对函数式编程的兴趣,不是对 BIM Wallet 的纠错或升级

02

传统钱包先有对象;Wallet Core 先有数据库

对象式钱包通常先在 Controller / Store 的内存中保存账户、网络和余额等状态,界面读取它,再把需要的数据写入存储。Wallet Core 把顺序反过来:RxDB 中的数据就是钱包状态。操作函数直接修改数据库,UI 通过 observe 层订阅查询结果,因此不会再维护一份与数据库平行的账户或余额状态;WalletClass 只在初始化时创建数据库、柯里化 methods、注册 chains 和启动 pipeline。

  • 对象式钱包:内存对象保存主状态,存储负责落盘
  • Wallet Core:数据库保存主状态,操作和界面都围绕数据库工作
  • 两者都能响应式更新;区别是谁保存最终数据
  • 我用 React / Vue 的心智模型差异作类比:理解 API 之前,先理解数据在哪里、怎样变化

03

Vault、Account、Address 分别解决三个问题

Vault 记录密钥从哪里来,例如助记词或私钥;Account 用 hdIndex 表示这个 Vault 下的第几个账户;Address 把一个 Account 与一条 Chain 连接起来,保存该链上的地址。Wallet Core 将三者放在独立 collection 中,所以可以按 Vault、Account、Chain 或 Address 查询。代价是这些引用必须保持完整,不能漏建或重复生成 Address。

  • 以同一助记词为例,一个 Vault 下可以创建多个不同索引的 Account
  • 每个 Account 按已接入链的派生规则生成 Address,矩阵展示的是可派生的组合
  • 导入私钥只关联兼容的链;不被该链接受的私钥不会生成 Address
  • 新增 Account 或 Chain 后,由 pipeline 补齐可派生的 Address

04

加网络和接新链族,是两件不同的事

在已经支持 EVM 的前提下,新增一条 EVM 网络只需要写入新的 Chain 配置;接入 Solana、TON 这类新链族,才需要实现并注册 ChainMethods。无论哪一种,新增或删除 Account、Chain 后,RxDB pipeline 都会生成或清理对应 Address。BIM Wallet 完成同一任务时,会在 createAccount / createNetwork 中主动算完并一次 database.batch 提交;Wallet Core 把 Address 当作稍后派生的数据,因此还要处理重试、去重和修复。

05

数据库能运行到哪里,钱包核心就能运行到哪里

对象式钱包换到浏览器、手机或桌面端时,需要分别处理内存状态怎样保存、多个进程怎样同步。Wallet Core 的账户、链、地址和当前选择本来就在 RxDB 中;换平台时,为 RxDB 选择该平台可用的存储实现,账户关系、操作函数、pipeline 和 observe 查询就可以继续使用。各端仍要实现自己的界面和进程通信;同时,如果某个平台的 RxDB 存储性能或能力不足,Wallet Core 也会直接受到限制。

06

账户关系已经实现,资产层还只是设计

当前源码已经能确定“哪个 Account 在哪条 Chain 上使用哪个 Address”,但还没有 Asset / Transaction collection,也没有可运行的资产管理器。原设计准备支持两种取数方式:由中心化索引服务一次返回完整资产,或者只查询用户添加的链上 Token。无论数据来自哪里,结果都会先转换成统一余额列表,再按账户、链或 Token 展示。这里描述的是后续设计,不是已经交付的能力。

07

一份状态,动作可以不经过 UI 验证

对象式钱包通常把内存对象当作主状态,再把其中一部分写入存储,所以需要保证两边不会不一致。Wallet Core 直接把数据库当作运行时主状态:Schema、索引、关联和查询都作用在同一份数据上,动作通过参数接收依赖。现有 addChain 测试直接调用 addChain({ database }, chain),验证返回的链配置与生成的 ID,再验证重复添加会报 UniquePrimaryKeyError,全程不需要界面。测试仍需初始化数据库,动作也会写入数据;可测试性来自依赖明确,而不是把有副作用的操作称为纯函数。

08

代价是所有压力都落到数据库和 pipeline

内存对象适合高频、短暂的数据更新,也能在一个方法里同时修改多项状态。Wallet Core 把这些工作交给 RxDB:高频数据可能需要额外缓存;新增账户或链后,Address 不会在同一次操作中完成,而是由异步 pipeline 稍后补齐;失败时还需要重试、去重、修复和运行状态监控。同一条规则也可能分散在 Schema、操作函数和 pipeline 中。

09

这是可运行的架构骨架,不是完整钱包

当前源码已经跑通 Vault、Account、Address、Chain 的关系,Conflux、EVM、Solana、TON 四类链,响应式查询、React / Vue 适配和两种密码交互。数据库迁移、缓存、pipeline 失败恢复与监控仍需补强;资产、交易、BTC / Cosmos、Svelte、硬件钱包和 WalletConnect 在这个源码快照中没有实现。它证明的是这套心智模型可以运行,不代表完整钱包已经完成。

原始架构材料

Wallet Core 原始总架构图
原始总架构图:Database、methods、chain methods、WalletClass 与 framework inject 的关系。
Wallet Core Vault Account Address Chain 关系图
原始账户 ER 图:Vault、Account、Address 与 Chain 的关系。

资料与实现范围

本页对 Wallet Core 架构、账户关系、链适配和完成度的判断,来自源码、测试、样例、VitePress 文档与《钱包心智模型》;BIM Wallet 只用于对照“动作内主动编排”和“写入后由 pipeline 被动派生”。资产与交易按文档明确标为设计方向。对象式钱包以 MetaMask 的 Controller + Storage 设计作参照,不把它概括成不能跨端。