一位 CKBuilder 的思考:你的以太坊账户并不存在
《一位 CKBuilder 的思考》第一篇:通过 CKB 的 Cell 模型,重新思考账户、所有权和状态。
New to Nervos? Start here.
Explore the guide
《一位 CKBuilder 的思考》是记录我在 CKBuilders 学习历程中的一组实践笔记,从首次使用 CKB 进行构建的人的视角,解读 CKB 的概念。
现在打开 MetaMask,看看你的余额。假设上面显示 1.4 ETH。
有一个大多数人从未问过的问题:这个数字在哪里?
不是哲学意义上的,而是字面意义上的。这个 1.4 究竟存在哪里?哪台计算机保存着它?谁把它写下来的?
答案是,没有哪台机器上有一个名为 your_balance = 1.4 的变量。实际存在的,是一个覆盖全球、名为世界状态(World State)的庞大数据结构。它是一个巨型键值存储,你的地址在其中映射到一个数字。全球每个以太坊节点都保存着这套结构的副本。你发送 ETH 时,以太坊虚拟机(EVM)从你的条目中减去金额,再加到别人的条目上,也就是对共享数据库进行两次修改。
这套方式行得通。以太坊是一个价值 3,000 亿美元的网络,显然行得通。
但这种设计也伴随着一组非常具体的取舍。作为开发者,你想实现的东西越复杂,这些取舍就越让人难受。一旦看清它们,就能开始理解 Nervos CKB 为什么会采用如今这样的设计。
天空中的账本
以太坊之前有比特币。比特币没有账户,从来没有。
当你“收到”比特币时,实际发生的是:一笔交易被写入区块链,其中有一个输出锁定到你的公钥。这个输出称为未花费交易输出(Unspent Transaction Output,UTXO),它就在那里,留在链上等待。它有一个价值,比如 0.5 BTC;也有一把锁,也就是任何人花费它之前必须满足的条件,通常是针对你的密钥进行签名检查。
你在比特币中的“余额”,不是存放在某处的一个数字,而是你的密钥可以解锁的所有 UTXO 的总和。钱包扫描区块链,找到你能够为之签名的每个未花费输出,将它们加起来,再把总额显示给你。
这是一种根本不同的模型。你的钱不是账本里的一条记录,而是散布在链上的一组上锁的盒子。花钱时,你不是修改一个数字,而是消耗一个盒子,再创建新的盒子。
正因如此,比特币交易是无状态且可并行处理的。两笔不涉及相同 UTXO 的交易,可以由不同处理器同时、完全独立地验证。这里没有需要围绕它串行处理的共享可变全局状态。
以太坊有意放弃了这一性质,换取表达能力强得多的编程模型。你可以编写循环、存储任意数据、构建复杂合约。但一切都通过一个全局 EVM 顺序执行,每次状态变化都进入同一个共享世界状态。
这是经典的取舍:表达能力与并行性。
CKB 看着这个取舍,提出了一个问题:如果不必二选一呢?
Cell 是成长后的 UTXO
CKB 的核心数据结构称为 Cell。如果你理解比特币 UTXO,就已经理解了 Cell 的 80%。
Cell 是区块链上独立的一份状态,包含:
- 容量(Capacity): 它持有多少 CKB,也由此决定它被允许占用多少字节的链上空间
- 锁定脚本(Lock Script): 花费它必须满足的条件,就像比特币的锁定脚本
- 类型脚本(Type Script): 可选的第二层逻辑,用来约束 Cell 的数据
- 数据(Data): 任意字节,即你想存储的内容
与比特币 UTXO 一样,Cell 要么未被花费,要么已经被花费。你不会修改它。“更新”一个 Cell 时,你将它作为交易输入消耗掉,再生成新的 Cell 作为输出。旧 Cell 被销毁,新 Cell 开始存在,没有原地修改。
你在 CKB 中的“余额”与比特币完全一样:将所有你能满足其锁定脚本的 Cell 加总。
但接下来,CKB 与比特币的分野,会改变开发者所面对的一切。
锁定脚本是一个程序
在比特币中,锁定脚本就是比特币脚本(Bitcoin Script),一种刻意限制功能、基于栈的语言。它能检查签名、处理部分多重签名,却不能执行循环。设计限制是有意的,因为比特币开发者希望避免复杂逻辑造成不可预测的状态,或阻碍区块生产。
在 CKB 中,锁定脚本是一个完整的 RISC-V 二进制程序。
RISC-V 是一种硬件指令集,与嵌入式系统、以及越来越多服务器芯片所采用的架构属于同一类。它不是专为区块链设计的,而是真正的 CPU 架构。CKB-VM 则是运行在节点内部的完整 RISC-V 处理器。
这意味着,CKB Cell 上的锁定脚本,可以是任何你能用 Rust 或 C 编写,并编译为 RISC-V 的程序。想要一个要求五把密钥中至少三把签名的多重签名方案?写出来即可。想要一个在区块高度 1,000,000 之后才能打开的时间锁金库?写出来即可。想要一个使用 WebAuthn、基于通行密钥(passkey)的认证流程?JoyID 钱包就是如此。它只是一个验证 WebAuthn 签名、而非 secp256k1 签名的锁定脚本。
在以太坊上,如果想使用一种新的签名方案,就需要预编译合约(precompiled contract),即在协议层硬编码进 EVM 的快捷执行路径;添加它需要硬分叉。在 CKB 上,你只需将 RISC-V 二进制程序部署为链上的一个 Cell,再引用它,无需硬分叉,也无需许可。
这就是“自带密码学方案”(bring your own cryptography)的实际含义。CKB 没有将 secp256k1 硬编码为其签名方案。大多数 CKB 地址所使用的标准 Secp256k1Blake160 锁,本身也只是存放在系统 Cell 中的一个 RISC-V 程序。你可以编写一个替代实现,部署后,人们今天就能使用。
所有权究竟是什么?
刚开始在 CKB 上构建时,最让我震撼的是这个概念:
CKB 上的所有权不是数据库记录,而是程序。
在以太坊上,你拥有 1.4 ETH 这件事,是以太坊节点同意维护的数据库中的一行。它的安全模型是:只要网络中的多数参与者诚实,就没有人能未经你许可修改这一行。
在 CKB 上,拥有一个 Cell,意味着这个 Cell 关联着一个 RISC-V 程序,即你的锁定脚本。任何消耗该 Cell 的交易,只有满足这个程序才可能有效。安全模型不仅依靠网络的诚实性,还通过每个节点独立运行脚本,并拒绝无法通过脚本的交易来执行。
实际区别在于灵活性。如果你想改变资产访问规则,比如增加社交恢复或轮换密钥,在以太坊上就需要一个带有升级机制、且需要有人维护的智能合约。在 CKB 上,只需创建一个使用新锁定脚本的新 Cell。规则直接内置于资产本身的结构中。
存储作为一等概念
CKB 设计中还有一点让我觉得十分精妙,它来自容量模型。
每个 Cell 的 capacity 字段必须足够大,能够覆盖 Cell 自身占用的字节数。准确公式是:Cell 序列化后的字节大小,决定了创建它必须存入的最低 CKB 数量。
1 CKB = 1 字节。 这不是比喻,而是状态租金模型。
在以太坊上,写入存储是免费的。你只需为执行交易支付一次 gas 费,数据就会永久留在链上,由网络中每个节点维护,而你无需持续付费。这正是以太坊状态多年来不断增长、却没有机制阻止的原因。它提高了运行全节点(full node)的硬件要求,悄然且持续地侵蚀去中心化。
CKB 从结构上解决了这一问题。想在链上存储 100 字节?锁定 100 CKB 作为押金即可。这些 CKB 不会被销毁,而是锁在 Cell 内。等你不再需要数据、销毁 Cell 时,就能取回这 100 CKB,原先占用的空间也得到释放。
这对应用的影响很显著。Spore 协议是一种 CKB NFT 标准,直接将内容存储在 Cell 数据中。一张图片、一份文本文档、一件生成艺术作品,都留在链上的 Cell 内,而不是 IPFS 或某台服务器上。由于 Cell 持有与自身大小成比例的 CKB,这个 NFT 自身就携带了存储成本。转移 Spore NFT 时,可以用 Cell 自身容量中很小的一部分支付矿工费。资产为自己的转移出钱。
你可以将 Spore NFT 发给一个钱包里没有任何 CKB 的人。试试在以太坊上这样做。
我实际构建了什么
过去三周,我一直通过 CKBuilders 项目学习构建,从阅读文档,到在本地开发网上运行交易,再到编写首个面向 RISC-V 的 Rust 锁定脚本。
仅本地开发网的体验就值得一提。在以太坊上,本地开发通常意味着模拟环境。Hardhat 即时出块,并模拟了大量网络行为。OffCKB 则在你的机器上运行真正的工作量证明(Proof-of-Work)节点。区块确实经过挖矿产生,交易也确实必须通过脚本验证。环境是真实的,因此你在本地发现的 bug 也是真实 bug,而非本地环境制造的假象。
在开发网上铸造 xUDT 同质化代币时,我必须手动构造类型脚本,将代币数量编码为 Cell 数据中的 128 位小端序整数,并在交易的 cellDeps 中包含 xUDT 系统脚本,让 CKB-VM 知道从哪里加载验证逻辑。这比在 ERC-20 上调用 mint() 繁琐,但每一步发生了什么,我都一清二楚,没有抽象层向我隐藏底层机制。
搭建第一个 Rust 锁定脚本时,也就是每个 CKB 脚本开发者入门都会写的经典“always-success”二进制程序,我意识到,自己写的并不是以太坊意义上的智能合约,而是一个验证程序(validator)。它接收一个提出的状态转换(也就是一笔交易),检查后返回 0(有效)或错误码。它的全部工作就是如此:没有存储,没有内部状态,只判断这笔交易是否遵守规则。
这种区别,也就是合约本身就是状态,而脚本验证状态,带来了思维转变,改变了你构建 CKB 应用的方式。
谁应该关注
如果你是比特币开发者,羡慕以太坊的表达能力,却对全局状态模型心存疑虑,那么 CKB 值得认真了解。你熟悉的 UTXO 模型仍然完整,你一直期待的可编程性也在这里,而且没有你一直想避开的共享全局状态。
如果你是以太坊开发者,已经碰到 EVM 的边界,例如复杂存储操作的 gas 成本、添加新密码学原语的困难,以及升级模式的不便,CKB 提供了值得理解的另一种架构。这种转变是真切的,你对“合约”究竟做什么的整套认识都需要改变。但跨过这一步,你得到的是一个程序之间不共享状态、天然支持并行、且明确体现存储真实成本的系统。
区块链领域不断追问,为什么这个行业总是换着不同的代币,重复构建相同的东西。CKB 的回答来自架构:如果存储状态、定义所有权的基础模型根本不同,就不可能构建同样的东西。你会构建不同的东西,而有时,它们确实更好。
本文属于持续记录我在 CKBuilders 项目中学习进展的系列文章。
More from CKB
CKBuilder 随想:比特币不知道自己有智能合约
CKBuilder 随想第三篇:RGB++ 如何在无需比特币许可的情况下,赋予它原本设计范围之外的可编程能力。

ABI 在哪里?还有,我的 Cell 为什么死了?
一位 CKBuilder 对以太坊思维习惯、CKB Cell、类型脚本、见证,以及与证明绑定的状态转换的思考。

构建器不是链
在 Nervos CKB 上,每笔交易中最重要的参与者,你从未看见。理解这一点,会彻底改变你对开发的认识。
