<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://cookbook.ckbdapps.com/blog</id>
    <title>CKB Cookbook Blog</title>
    <updated>2024-02-22T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://cookbook.ckbdapps.com/blog"/>
    <subtitle>CKB Cookbook Blog</subtitle>
    <icon>https://cookbook.ckbdapps.com/img/favicon.jpeg</icon>
    <entry>
        <title type="html"><![CDATA[RGB++ 深入讨论(1): 安全性分析]]></title>
        <id>https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis</id>
        <link href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis"/>
        <updated>2024-02-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[PoW 比你想象的更安全]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="pow-比你想象的更安全">PoW 比你想象的更安全<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#pow-%E6%AF%94%E4%BD%A0%E6%83%B3%E8%B1%A1%E7%9A%84%E6%9B%B4%E5%AE%89%E5%85%A8" class="hash-link" aria-label="Direct link to PoW 比你想象的更安全" title="Direct link to PoW 比你想象的更安全">​</a></h2>
<p>PoW 的安全性风险在于区块 revert/reorg，从而导致双花。只要有一个诚实矿工，用户的状态/资产就不会计算错误，只有可能出现因区块重整导致的双花交易损失。因此 PoW 的核心安全假设就是 N 个区块后交易就几乎不会被 revert 了，例如 Bitcoin 普遍认为 6 区块甚至更少即可。</p>
<p>显然，6确认的 BTC 肯定比1确认更安全，那么 PoW 确认数和安全性是线性关系吗？并不是，<strong>推翻区块的难度随着区块深度指数增长</strong>，这个指数增长具体的参数已经有几十篇论文在讨论了。随着时间的推移，大家发现“NC比从前以为的更安全”。</p>
<p>根据 <a href="https://scholar.google.com/citations?hl=en&amp;user=JB1uRvQAAAAJ" target="_blank" rel="noopener noreferrer">Ren Zhang </a> 博士的计算，假设敌手算力占比30%，要实现比特币中孤块率为0、6个块确认的安全性，当 CKB 的孤块率设定成 2.5% 的时候，需要23.29个块确认即可达到相同的安全性 。通过这样的等价关系，我们可以在后续的讨论中方便地讨论 RGB++ 协议中各种典型操作的安全性。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-c8af664a1e2a579ed7c7022ea21dce18.png" width="1034" height="712" class="img_ev3q"></p>
<p><em>PoW 安全性的示意图（非理论计算</em>）</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="rgb-的安全性">RGB 的安全性<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#rgb-%E7%9A%84%E5%AE%89%E5%85%A8%E6%80%A7" class="hash-link" aria-label="Direct link to RGB 的安全性" title="Direct link to RGB 的安全性">​</a></h2>
<p>RGB 通过一次性密封和客户端验证的方式实现了在 Bitcoin UTXO 上绑定 RGB 的状态和合约，为 Bitcoin 提供了图灵完备的扩展。交易安全性有两类，一类是状态计算的正确性；一类是交易确定性，即双花风险。客户端验证确保了状态计算的正确性，每个人负责自己的状态，不依赖任何第三方。而基于 BTC UTXO 的一次性密封确保了双花 RGB 的难度和双花 BTC 的难度相同。因此，我们可以说 <strong>RGB 100% 继承了 Bitcoin 的安全性</strong>。用户需要多安全，就按照比例等待多少个 BTC 确认即可。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="rgb-的安全性-1">RGB++ 的安全性<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#rgb-%E7%9A%84%E5%AE%89%E5%85%A8%E6%80%A7-1" class="hash-link" aria-label="Direct link to RGB++ 的安全性" title="Direct link to RGB++ 的安全性">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="l1-交易安全性">L1 交易安全性<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#l1-%E4%BA%A4%E6%98%93%E5%AE%89%E5%85%A8%E6%80%A7" class="hash-link" aria-label="Direct link to L1 交易安全性" title="Direct link to L1 交易安全性">​</a></h3>
<p>RGB++ 的 L1 交易指的是 RGB++ 交易的 UTXO 的"持有人" 是 Bitcoin 的 UTXO。即只有消费 Bitcoin UTXO 才能操作或更新 RGB++ UTXO。这种情况下，虽然每一笔 RGB++ 交易都同步发起一笔 CKB 交易，但其安全性和 CKB 没有关系，CKB 仅作为 DA 和状态公示来使用。<strong>这种情况下，RGB++ L1 的交易安全性和 RGB 交易相同，也是完全继承了 BTC 的安全性</strong>。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="l2-交易安全性">L2 交易安全性<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#l2-%E4%BA%A4%E6%98%93%E5%AE%89%E5%85%A8%E6%80%A7" class="hash-link" aria-label="Direct link to L2 交易安全性" title="Direct link to L2 交易安全性">​</a></h3>
<p>L2 交易即 100% 发生在 CKB 上的交易，显然它的安全性 100% 由 CKB 负责。但由于开篇提出的 PoW 安全的非线性特性，24个区块的 ckb 确认即可等价于 6 确认的 BTC 确认，因此我们也可以说 L2 交易安全性与 L1 交易安全性等价（需要更多区块确认，但事实上更短确认时间）。</p>
<p>能做到这一点的前提是 RGB++ 的同构映射链必须是 PoW 的，如果它是 PoS 的链，无论等待多少个区块，它安全性上限都是 PoS 的 stake 量，无法与 Bitcoin 安全性等价。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="jump-操作">Jump 操作<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#jump-%E6%93%8D%E4%BD%9C" class="hash-link" aria-label="Direct link to Jump 操作" title="Direct link to Jump 操作">​</a></h3>
<p>RGB++ 协议中用户的资产既可以在 Bitcoin 上流转，也可以随时到 CKB 上流转，或者反向操作。在切换的过程不需要跨链桥，更不需要信任任何多签方。我们将资产或状态在 Bitcoin 上和 CKB 上流转的切换称为 Jump。Jump 操作前后，影响 RBG++ 协议安全性的核心点在于：</p>
<ul>
<li>一次性密封条，从使用 Bitcoin UTXO 变为使用 CKB UTXO，或相反</li>
<li>客户端验证所需要的数据保持不变，都是 CKB 上的同构绑定交易</li>
</ul>
<p>Jump 操作时，用户需要在两条链上分别等待足够的区块数，以获得安全性。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="兼顾用户体验">兼顾用户体验<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#%E5%85%BC%E9%A1%BE%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C" class="hash-link" aria-label="Direct link to 兼顾用户体验" title="Direct link to 兼顾用户体验">​</a></h2>
<p>根据上面的讨论，等待足够多的区块数确实可以获得足够的安全性，但用户体验实在太差了。考虑平庸的方案，每个 RGB++ L1 交易要等待 6 个 BTC 确认再进行下一次操作，每个 L2 交易要等待 24 个 CKB 确认再进行下一次操作，而 Jump 操作则需要等待 6 BTC + 24 CKB 确认。能否对这个方案进行优化呢？</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="rgb-收款方-utxo-的优化">RGB 收款方 UTXO 的优化<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#rgb-%E6%94%B6%E6%AC%BE%E6%96%B9-utxo-%E7%9A%84%E4%BC%98%E5%8C%96" class="hash-link" aria-label="Direct link to RGB 收款方 UTXO 的优化" title="Direct link to RGB 收款方 UTXO 的优化">​</a></h3>
<p>考虑原 RGB 协议，为了实现交易隐私性，Bitcoin 上发起的 RGB 交易的收款方（以一个 Bitcoin utxo 表达）和这笔 Bitcoin 交易的 output 并不一致。这使得观察者无法通过追踪 bitcoin 交易的方式来追踪 RGB 交易。</p>
<p>但在 RGB++ 协议中，所有的 RGB++ 层交易都同构绑定并公示在 CKB 上，尽管极大地简化了用户的交易验证难度，也较为遗憾地损失了 RGB 协议的隐匿性（RGB++ 协议可以利用 CKB 的隐私层引入<a href="https://forum.grin.mw/t/a-draft-design-of-mimblewimble-on-nervos-ckb/7695" target="_blank" rel="noopener noreferrer">更为强大的隐私属性 </a>）。所以 RGB++ 协议在收款人方面做了调整，它不要求收款方预先提供一个自己的 UTXO，而只需要提供一个收款地址，RGB++ 交易本身在构造 BTC 交易时会生成一个 UTXO 指向该收款人地址。这样就可以完成非交互式转账，大幅简化了用户的操作流程。注意下面的示意图做了一些简化，为了实现同构绑定，某些包含在 BTC TX 和 CKB TX 中的字段不会被包含在 commitment 中，以防止出现互相包含的矛盾。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-1-a24f43c3b742d61c16440fbb36f8096c.png" width="882" height="750" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="交易串接">交易串接<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#%E4%BA%A4%E6%98%93%E4%B8%B2%E6%8E%A5" class="hash-link" aria-label="Direct link to 交易串接" title="Direct link to 交易串接">​</a></h3>
<p>上面的 RGB 非交互式转账的优化不仅仅有利于提升用户体验，对于交易确认的优化也有本质的作用。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-2-29cbf4a7722c7edf244e02547cda2265.png" width="1034" height="686" class="img_ev3q"></p>
<p>首先对于一个诚实的用户，尽管区块 reorg 经常发生，但只要该用户不主动进行双花交易，BTC 链上打包的用户交易是不变的，因此不会影响到 CKB 链上的 RGB++ 资产和状态。</p>
<p>考虑一笔 L1 RGB++ 交易，假设为了用户体验我们允许单块 BTC 交易确认即可发起同构交易，即在 CKB 构造同步的 RGB++ 资产交易。此时，对于恶意用户，TA 可能构造一笔新的 BTC 交易，取代之前的 BTC TX B，使得 CKB TX B‘ 找不到对应的 BTC 交易，但这时 CKB TX B’ 已经上链。这里的后果是，在 BTC 上被双花的 btc_utxo#2 在 CKB 上的同构映射 cell 已经在 CKB TX B’ 中消耗了，即使用户双花了 BTC 上的 utxo，他也无法双花 RGB++ 的资产，同时先前交易生成的 RGB++ cell 输出（ lock 为 btc_utxo#3）也因为链式交易的失效而被用就锁定。所以恶意用户在 BTC 上做双花交易不会有任何收益，还会导致自己的资产失效。</p>
<p>考虑一笔 L2 RGB++ 交易，它 100% 运行在 CKB 上，因此我们只需要符合原来的交易逻辑即可，即也可以在 dapp 中获得连续操作的体验。</p>
<p>最后考虑一笔 Jump 操作，用户将 RGB++ 资产从一个 Bitcoin UTXO 中转到一个 CKB 地址上，后续的操作会持续发生在 CKB 上，此时我们需要考虑因 Bitcoin TX revert 造成的 CKB 上资产复制的问题。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-3-47d7b1c5992e6dc2dda81211369d51a2.png" width="1034" height="606" class="img_ev3q"></p>
<p>考虑上面的交易，BTC_TX_A 和 CKB_TX_B 同构绑定，之后 BTC_TX_A 被重构成 BTC_TX_A’，此时同构绑定的交易 CKB_TX_B’ 无法通过 ckb 共识上链，因为它依赖的 input (lock= btc_utxo#1)已经在 CKB_TX_B 中被使用了。这就导致 BTC 上的交易和 CKB 的交易同构绑定失败。但注意，如果同构绑定失败，但相关的所有资产均被锁定，那么我们不认为出现了安全性问题。因为这种失败源自交易发起人主观攻击协议，那么TA的所有资产被永久锁定不是问题。</p>
<p>但图示的操作中，我们发现 CKB 上的两个输出，RGB++ cell 的 lock 是 btc_utxo#2，它依赖被 revert 的旧的 BTC 交易，因此被永久锁定，没问题。单另一个 ckb cell 则不受影响。这就造成了安全风险。</p>
<p>因此，我们引入一个新的 lock，暂定名为 btc_time_lock 通过提供额外的锁定逻辑来解决这个问题。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="btc-time-lock">BTC Time Lock<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#btc-time-lock" class="hash-link" aria-label="Direct link to BTC Time Lock" title="Direct link to BTC Time Lock">​</a></h3>
<p>btc_time_lock 的核心参数有三个，分别是 <code>lock_hash</code>，<code>after</code>，和 <code>bitcoin_tx</code>。它具体的含意是：“仅当在参数中指定的 <code>bitcoin_tx</code> 被超过 <code>after</code> 个 btc 区块确认后，本 cell 才可以被解锁，且解锁后需要换成 <code>lock_hash</code> 指定的 lockscript(ckb 地址)”。 我们以上面的例子看一下 btc_time_lock 是如何工作的。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-4-09ddd04b222a42dc97e946d3a0133773.png" width="1034" height="672" class="img_ev3q"></p>
<p>和之前的讨论相同，如果 BTC_TX_A 被 revert 了，对应的 RGB++ Cell 被永久锁定，而其他的 CKB cell 则按照要求被放置自啊 btc_time_lock 中，且他们被解锁的条件是 BTC_TX_A 经过了 6 个区块确认。那么显然由于 BTC_TX_A 不存在而因此被永久锁定。反过来讲，如果 6 个 btc 确认后，BTC_TX_A 仍然存在，那么该 CKB Cell 就可以正常使用。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="总结">总结<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="Direct link to 总结" title="Direct link to 总结">​</a></h2>
<p>总结来说，RGB++ 不论在 L1 还是在 L2 上都可以获得与 Bitcoin 相同级别的安全性，在 L1 和 L2 Jump 时，RGB++ 协议额外要求资产锁定 6 个或更多的 BTC 区块，以获得在跨层使用时一致的安全性。RGB++ 协议在不妥协安全性的前提下为 BTC 网络进行了图灵完备的补充和性能的扩展。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="致谢">致谢<a href="https://cookbook.ckbdapps.com/blog/rgbpp-security-analysis#%E8%87%B4%E8%B0%A2" class="hash-link" aria-label="Direct link to 致谢" title="Direct link to 致谢">​</a></h2>
<blockquote>
<p>Special thanks to <a href="https://scholar.google.com/citations?hl=en&amp;user=JB1uRvQAAAAJ" target="_blank" rel="noopener noreferrer">Ren Zhang </a> , <a href="https://github.com/doitian" target="_blank" rel="noopener noreferrer">Ian </a>, and <a href="https://talk.nervos.org/u/c4605/summary" target="_blank" rel="noopener noreferrer">c4605</a> for feedback and discussion.</p>
<p>The RGB receiver optimization approach is inspired by <a href="https://twitter.com/CryptoStwith" target="_blank" rel="noopener noreferrer">Jason Cai </a>.</p>
</blockquote>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/rgb-1/7798" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Cipher</name>
            <uri>https://twitter.com/crypcipher</uri>
        </author>
        <category label="RGB" term="RGB"/>
        <category label="Bitcoin" term="Bitcoin"/>
        <category label="Security" term="Security"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[理解 CKB 的 Cell 模型]]></title>
        <id>https://cookbook.ckbdapps.com/blog/understanding-cell-model</id>
        <link href="https://cookbook.ckbdapps.com/blog/understanding-cell-model"/>
        <updated>2019-03-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在设计CKB的时候，我们想要解决三个方面的问题：]]></summary>
        <content type="html"><![CDATA[<p>在设计CKB的时候，我们想要解决三个方面的问题：</p>
<ol>
<li><a href="https://talk.nervos.org/t/topic/1515" target="_blank" rel="noopener noreferrer">状态爆炸 </a> 引起的公地悲剧及去中心化的丧失；</li>
<li><a href="https://talk.nervos.org/t/layer-1/1486" target="_blank" rel="noopener noreferrer">计算和验证耦合在了一起 </a> 使得无论是计算还是验证都失去了灵活性，难以扩展；</li>
<li><a href="https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0015-ckb-cryptoeconomics/0015-ckb-cryptoeconomics.md#3-preservational-and-transactional-smart-contract-platforms" target="_blank" rel="noopener noreferrer">交易与价值存储这两个目标的内在矛盾 </a>，Layer 2和跨链的出现将放大这种矛盾，并对Layer 1的经济产生非常负面的影响；</li>
</ol>
<p>对这些问题没有回答，Layer 1就无法长久运行，区块链给我们的种种承诺自然也是无从谈起。这三个问题根植于区块链架构和协议设计的最深处，很难通过打补丁的方式来解决，我们必须从最基本的数据结构开始，重新审视问题的根源，寻找更合适的地基。</p>
<p>幸运的是，这个更合适的地基简单得令人感到幸福，而且一直就摆在我们眼前。</p>
<p>（本文会包含一些非常简单的代码，应该不会影响非技术读者阅读…）</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="从bitcoin我们学到了什么">从Bitcoin我们学到了什么<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#%E4%BB%8Ebitcoin%E6%88%91%E4%BB%AC%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88" class="hash-link" aria-label="Direct link to 从Bitcoin我们学到了什么" title="Direct link to 从Bitcoin我们学到了什么">​</a></h2>
<p><a href="https://github.com/bitcoin/bitcoin/blob/master/src/primitives/transaction.h#L18" target="_blank" rel="noopener noreferrer">Bitcoin把整个账本分割保存在了一个个UTXO里面 </a>，UTXO是未花费交易输出(Unspent Transaction Output)的简写，实际上是交易中包含的输出(CTxOut)。CTxOut的结构非常非常的简单，只有两个字段：</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    class CTxOut</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        CAmount nValue;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        CScript scriptPubKey;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>每一个<code>CTxOut</code>代表了一个面值不同的硬币（Yay bit-”Coin”），其中<code>nValue</code>代表这个硬币的面值是多少，<code>scriptPubKey</code>是一段表示这个硬币的所有者是谁的脚本（通常包含了所有者的公钥），只有能提供正确的参数使这个脚本运行成功的人，才能把这个硬币“转让”给另外一个人。</p>
<p>为什么要给“转让”打引号？因为在转让的时候，并不是简单的把硬币中的<code>scriptPubKey</code>修改或是替换掉，而是会销毁和创造新的硬币（毕竟在数字的世界中销毁和创造虚拟硬币的成本很低）。每一个Bitcoin交易，都会销毁一批硬币，同时又创造一批硬币，新创造的硬币会有新的面值和新的所有者，但是被销毁的总面值总是大于等于新创造的总面值，以保证没有人可以随意增发。交易表示的是账本状态的变化。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-cf4ec833cdcf0896cfaf189535b4c3c7.png" width="1018" height="628" class="img_ev3q"></p>
<p>这样一个模型的特点是：</p>
<ol>
<li>硬币（资产）是第一性的；</li>
<li>所有者是硬币的属性，每一枚硬币有且仅有一个所有者；</li>
<li>硬币不断的被销毁和创建；</li>
</ol>
<p>是不是很简单？如果你觉得自己已经理解了Bitcoin和UTXO，恭喜你，你也已经理解了CKB和Cell!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="cell">Cell<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#cell" class="hash-link" aria-label="Direct link to Cell" title="Direct link to Cell">​</a></h2>
<p><a href="https://talk.nervos.org/t/layer-1/1486" target="_blank" rel="noopener noreferrer">Layer 1的关注点在状态 </a>，以Layer 1为设计目标的CKB设计的关注点很自然就是状态。Ethereum将交易历史和状态历史分为两个维度，区块和交易表达的是触发状态迁移的事件而不是状态本身，而Bitcoin协议中的交易和状态融合成了一个维度，交易即状态，状态即交易，正是一个以状态为核心的架构。</p>
<p>同时，CKB想要验证和长久保存的状态，不仅仅是简单的数字（<code>nValue</code>)，而是任何人们认为有价值的、经过共识的数据。显然Bitcoin的交易输出结构满足不了这个需求，但是它已经给了我们足够的启发：只需要将<code>nValue</code>一般化，把它从一个存放整数的空间变成一个可以存放任意数据的空间，我们就得到了一个更加一般化的”<code>CTxOut</code>"，<a href="https://github.com/nervosnetwork/ckb/blob/develop/core/src/transaction.rs#L96" target="_blank" rel="noopener noreferrer">或者叫Cell </a>:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    pub struct CellOutput {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        pub capacity: Capacity,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        pub data: Vec&lt;u8&gt;,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        pub lock: Script,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        pub type_: Option&lt;Script&gt;,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>在Cell里面，<code>nValue</code>变成了<code>capacity</code>和<code>data</code>两个字段，这两个字段共同表示一块存储空间，<code>capacity</code>是一个整数，表示这块空间有多大（以字节数为单位），<code>data</code>则是保存状态的地方，可以写入任意的一段字节；<code>scriptPubKey</code>变成了<code>lock</code>，只是换了一个名字而已，表达的是这块共识空间的所有者是谁 - 只有能提供参数（例如签名）使得<code>lock</code>脚本成功执行的人，才能“更新”这个Cell中的状态。整个<code>CellOutput</code>占用的字节数必须小于等于<code>capacity</code>。CKB中存在着许许多多的Cells，所有这些Cell的集合形成了CKB完整的当前状态，在CKB的当前状态中存储的是任意的共同知识，不再仅仅是某一种数字货币。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-1-775bed24f7d235a82686fd32147cf564.png" width="1025" height="421" class="img_ev3q"></p>
<p>交易依然表示状态的变化/迁移。状态的变化，或者说Cell内容的“更新”实际上也是通过销毁和创建来完成的（并不是真的去修改原有Cell中的内容）。每一笔交易实际上都会销毁一批Cells，同时创建一批新的Cells；新创造的Cells会有新的所有者，也会存放新的数据，但是被销毁的<code>capacity</code>总和总是大于等于新创建的<code>capacity</code>总和，由此保证没有人可以随便增发<code>capacity</code>。因为<code>capacity</code>可以转让，无法增发，拥有<code>capacity</code>等于拥有相应数量的共识状态空间，<code>capacity</code>是CKB网络中的原生资产。Cell的销毁只是把它标记为”已销毁“，类似Bitcoin的UTXO从未花费变为已花费，并不是从区块链上删掉。每一个Cell只能被销毁一次，就像每一个UTXO只能被花费一次。</p>
<p>这样一个模型的特点是：</p>
<ol>
<li>状态是第一性的；</li>
<li>所有者是状态的属性，每一份状态只有一个所有者；</li>
<li>状态不断的被销毁和创建；</li>
</ol>
<p>所以说，Cell是UTXO的一般化(generalized)版本。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="verify">Verify<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#verify" class="hash-link" aria-label="Direct link to Verify" title="Direct link to Verify">​</a></h2>
<p>仅仅有一块可以保存任意状态的空间还不够。Bitcoin之所以有价值，是因为<a href="https://talk.nervos.org/t/dont-trust-verify/335" target="_blank" rel="noopener noreferrer">网络中的全节点会对每一笔交易进行验证 </a>，使得所有用户都相信（并且知道别人也相信）Bitcoin协议中写下的规则（例如2100万的上限）会得到保证。共同知识之所以能成为共同知识，是因为<a href="https://en.wikipedia.org/wiki/Common_knowledge_(logic)" target="_blank" rel="noopener noreferrer">每个人都知道其他人认可这些知识 </a>，区块链之所以能让知识变成共同知识，是因为每个人都知道其他人都能独立验证这些知识并由此产生认可。<a href="https://mp.weixin.qq.com/s?__biz=MzUzNjEyNjMzMw==&amp;mid=2247484123&amp;idx=2&amp;sn=3b8e7e44fa01274f18feee038ef5c1e0&amp;chksm=fafbb4c9cd8c3ddf5ec60e98747824598544d8d94d879a58eb00f26f7067eed305b84e382038&amp;scene=7&amp;ascene=0&amp;devicetype=android-27&amp;version=2700033b&amp;nettype=WIFI&amp;abtest_cookie=BAABAAoACwASABMABQAjlx4AXZkeAMaZHgDRmR4A3JkeAAAA&amp;lang=zh_CN&amp;pass_ticket=Nwl0spbFDxbms6ptGi2JBtXd85cd4LTdSk8DR3nyRnk%3D&amp;wx_header=1" target="_blank" rel="noopener noreferrer">任何共识的过程都包含了一系列的验证以及相互之间的反复确认，这个过程正是网络中共同知识形成的过程 </a>。（需要注意的是，验证知识是相对事先确定的验证规则来说的，通过验证的知识不代表命题为真。）</p>
<p>我们如何验证Cell中保存的数据呢？这时候就需要Cell中的另一个字段<code>type</code>发挥作用了。<code>type</code>与<code>lock</code>一样，也是一段脚本，<code>type</code>定义了在<code>data</code>字段中保存的数据在状态迁移过程中必须要遵守的规则，是对状态的约束。CKB网络在共识的过程中，会在CKB-VM虚拟机中执行<code>type</code>脚本，验证新生成的Cell中保存的状态符合<code>type</code>中预先定义好的规则。满足同一种<code>type</code>约束的所有Cell，保存的是同一种<a href="https://en.wikipedia.org/wiki/Type_system" target="_blank" rel="noopener noreferrer">类型 </a>的数据。</p>
<p>举个例子，假设我们想定义一个叫做SatoshiCoin的代币（UDT，UserDefinedToken），它的状态迁移必须满足的约束是什么？只有两条：</p>
<ol>
<li>用户必须证明自己是输入代币的所有者；</li>
<li>每一次转账的时候，输入的代币数量必须大于等于输出的代币数量；</li>
</ol>
<p>第一条约束可以通过<code>lock</code>脚本来表达，<a href="https://github.com/nervosnetwork/ckb-ruby-scripts/blob/a75b5df8fdf833b7316bbd9213f73436401c86a5/udt/unlock.rb" target="_blank" rel="noopener noreferrer">如果有兴趣可以查看这里的示例代码 </a>，与Bitcoin的<code>scriptPubKey</code>原理相同；第二条约束，在Bitcoin中是在底层硬编码实现的，在CKB中则是通过<code>type</code>脚本来实现。每个Cell代表的SatoshiCoin数量是一种状态，我们首先定义其状态结构，即每个<code>type等于SatoshiCoin的Cell在</code>data`保存的状态为一个长度为8的字节串，代表的是序列化过后的数量：</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "amount": "Bytes[8]" // serialized integer</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>type</code>脚本在执行中，<a href="https://github.com/nervosnetwork/ckb-ruby-scripts/blob/a75b5df8fdf833b7316bbd9213f73436401c86a5/udt/contract.rb#L74" target="_blank" rel="noopener noreferrer">需要读入交易中所有同类型的Cells（根据<code>type</code>字段可以判断），然后检查同一类型下的输入Cells中保存的<code>amount</code>之和大于等于输出Cells中保存的<code>amount</code>之和 </a>。于是通过<code>lock</code>和<code>type</code>两个脚本，我们就实现了一个最简单的代币。</p>
<p><code>lock</code>和<code>type</code>脚本不仅可以读取自身Cell中保存的状态，也能够引用和读取其它Cell中保存的状态，所以CKB的编程模型是一个<a href="https://en.wikipedia.org/wiki/State_(computer_science)" target="_blank" rel="noopener noreferrer">有状态的编程模型 </a>。值得指出的是，Ethereum的编程模型之所以强大，更多是因为它有状态，而不是因为它的有限图灵完备。我们可以把<code>type</code>脚本保存在一个独立的Cell里面，然后在每一个SatoshiCoin Cell的<code>type</code>字段引用它，这样做的好处是相同的<code>type</code>脚本只需要一份空间保存，像这样<a href="https://talk.nervos.org/t/first-class-asset/405" target="_blank" rel="noopener noreferrer">保存数字资产定义的Cell我们把它叫做ADC（Asset Definition Cell） </a>。SatoshiCoin的另一个特点是，具体的资产与所有者之间的记录，分散保存在多个独立的Cell里面，这些Cell可以是开发者提供给用户的，也可以是用户自己拥有的，甚至是租来的。只有在共识空间所有权明确的情况下，所有者才能真正拥有共识空间里面保存的资产（任何数据都是资产）。在CKB上，因为用户可以真正拥有共识空间，所以用户可以真正拥有数字资产（当你能真正拥有土地的时候，才能真正拥有土地上的房子）。</p>
<p>Cell是抽象的状态验证模型，Cell提供的存储(<code>data</code>)没有任何内部结构，Cell支持任意的状态验证规则(<code>type</code>)和所有权验证规则（<code>lock</code>)，我们可以在Cell模型上模拟UTXO模型（就像上面的SatoshiCoin），也可以在Cell模型上构建Account模型。<code>lock</code>脚本在验证交易输入的时候执行，确保用户对输入有所有权，有权销毁输入的Cells；<code>type</code>脚本在验证交易输出的时候执行，确保用户生成的新状态符合类型约束，正确生成了新的Cells。由于状态模型迥异，以及计算和验证分离，CKB的编程模型与Ethereum的编程模型有非常大的不同，什么是CKB编程模型上的最佳实践还需要大量的探索。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-2-ed15474819318093822b8c3dcf5dc9f4.png" width="1119" height="514" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="通用验证网络">通用验证网络<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#%E9%80%9A%E7%94%A8%E9%AA%8C%E8%AF%81%E7%BD%91%E7%BB%9C" class="hash-link" aria-label="Direct link to 通用验证网络" title="Direct link to 通用验证网络">​</a></h2>
<p>Bitcoin是一个验证网络（Verification Network）。在转账时，用户告诉钱包/本地客户端转账的数量和收款人，钱包根据用户提供的信息进行计算，在本地找出用户拥有的数量合适的硬币（UTXO），同时产生一批新的硬币，这些硬币有些归收款人所有，有些是找零。之后钱包将这些花费掉的硬币和新生成的硬币打包到一个交易里面，将交易广播，网络对交易验证后将交易打包到区块里面，交易完成。在这个过程中，网络中的节点并不关心老的状态（被销毁的硬币）是怎样被搜索出来的，也不关心新的状态（新硬币）是怎样生成出来的，只关心这些硬币的面值总和在交易前后没有改变。在转账过程中，计算在用户端完成，因此用户在交易发送时就能确定计算结果（新状态）是什么。</p>
<p>Ethereum是一个通用计算网络（General Computation Network）。在使用DApp的时候，用户告诉钱包/本地客户端想要进行的操作，钱包将用户的操作请求原样打包到交易里面，并将交易广播。网络节点收到交易之后，根据区块链的当前状态和交易包含的操作请求进行计算，生成新的状态。在这个过程中，计算在远端完成，交易结果（新状态）只有在交易被打包到区块之后才能确定，用户在交易发送的时候并不能完全确定计算结果。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-3-b6d15b097918a4afbe6d1942fbe475ea.png" width="1250" height="1000" class="img_ev3q"></p>
<p>（图中，上面是Ethereum的流程，交易中包含的是用户请求或者说事件/Event；下面是Bitcoin/CKB的流程，交易中包含的是链下生成的状态/State。）</p>
<p>CKB是一个通用验证网络（General Verification Network）。在使用DApp的时候，用户告诉钱包/本地客户端想要进行的操作，钱包根据当前状态和用户的操作请求进行计算，生成新的状态。在这个过程中，计算在用户端完成，计算结果（新状态）在交易发出的时候就已经确定了。</p>
<p>换句话说，Bitcoin和CKB都是先计算再共识，而Ethereum是先共识再计算。有趣的是，在许可链架构里面也有同样派别之分：<a href="https://www.hyperledger.org/projects/fabric" target="_blank" rel="noopener noreferrer">Fabric </a> 是先计算再共识，而<a href="https://github.com/cryptape/cita" target="_blank" rel="noopener noreferrer">CITA </a> (实际上不仅仅是许可链)是先共识再计算。（思考题：那一种架构更适合许可链？）</p>
<p>计算与验证的分离同时也使得Layer 2与Layer 1自然分开了。Layer 1关心的是新的状态是什么，并不关心新的状态是如何得到的。无论是state channel，plasma还是其他Layer 2方案，其实质都是在链外进行计算，在特定时候将最终状态提交到Layer 1上进行验证。</p>
<table><thead><tr><th></th><th>General</th><th>Verification Only</th></tr></thead><tbody><tr><td>Bitcoin</td><td>No</td><td>Yes</td></tr><tr><td>Ethereum</td><td>Yes</td><td>No</td></tr><tr><td>CKB</td><td>Yes</td><td>Yes</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="为什么更好">为什么更好？<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9B%B4%E5%A5%BD" class="hash-link" aria-label="Direct link to 为什么更好？" title="Direct link to 为什么更好？">​</a></h2>
<p>现在我们得到了一个非常不同的基础数据结构，在这个结构之上我们设计了独特的经济模型，这个结果真的更好吗？回顾一开始的三个问题也许能给我们一些启示。</p>
<p><code>capacity</code>是原生资产，受到预先确定的发行规则约束，其总量有限。<code>capacity</code>同时又是状态的度量，有多少<code>capacity</code>，CKB上就能放多少数据，CKB状态空间的最大值与<code>capacity</code>总量大小相等，CKB上保存的状态不会超过<code>capacity</code>总量。这两点决定了，CKB不会有状态爆炸的问题。在<code>capacity</code>发行规则适当的情况下，网络应该可以长久的保持去中心化的状态。每一个Cell都是独立状态，有明确的所有者，<a href="https://en.wikipedia.org/wiki/Tragedy_of_the_commons#Privatization" target="_blank" rel="noopener noreferrer">原本属于公共资源的状态空间被私有化 </a>，宝贵的共识空间可以被更有效的使用。</p>
<p>CKB是一个通用验证网络，计算和验证得到了分离，各自的灵活性和扩展性都得到了提高。<a href="https://en.wikipedia.org/wiki/Edge_computing" target="_blank" rel="noopener noreferrer">更多的计算被推到了用户端执行 </a>，计算发生在离场景和数据更近的地方，数据处理的方式更灵活，工具更多样。这也意味着，在CKB架构中，钱包是一个能做的事情更多，能力更大的入口。在验证端，由于计算结果已经完全确定，交易的依赖分析变得非常轻松，交易的并行处理也就更加容易。</p>
<p>在基于Cell建立的经济模型中，存储的使用成本与占用空间大小和占用时间成正比，矿工可以为提供共识空间获得相应的收益。CKB提供的Utility是安全的共识空间，价值来自于其安全性和可用性（accessability），并不是来自于交易处理能力（TPS），与Layer 2负责交易的特点相辅相成，在分层网络和跨链网络中具有更好的价值捕获能力。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ckb-is-not-">CKB is NOT …<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#ckb-is-not-" class="hash-link" aria-label="Direct link to CKB is NOT …" title="Direct link to CKB is NOT …">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ipfs">IPFS<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#ipfs" class="hash-link" aria-label="Direct link to IPFS" title="Direct link to IPFS">​</a></h3>
<p>CKB是一种存储这一点可能会使人感到迷惑：”这不就是IPFS/Filecoin/[任何分布式存储]吗？“</p>
<p>CKB不是分布式存储，关键的区别在于，分布式存储只有存储，没有验证，也就不会对其存储的数据形成共识。分布式存储的容量可以随着存储技术的增长而等比例的增长，而CKB的容量则收到形成全球共识效率的限制。</p>
<p>CKB也不需要担心容量不够。在Layer 2以及分层技术成熟的阶段，极端情况下，Layer 1上可能只需要放一个merkle root就足够了。在Layer 1上进行验证所需要的状态，也可以通过交易提交给节点，节点通过merkle proof验证状态是有效的，在此基础之上再验证状态迁移是有效的，这个方向已经有一些研究。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="qtum">Qtum<a href="https://cookbook.ckbdapps.com/blog/understanding-cell-model#qtum" class="hash-link" aria-label="Direct link to Qtum" title="Direct link to Qtum">​</a></h3>
<p>Qtum是尝试在UTXO模型上引入更强大的智能合约的先行者之一，具体做法是保持Bitcoin原有的UTXO模型不变，在其上引入账户抽象层（Account Abstraction Layer），支持EVM或是X86虚拟机。在Qtum中，Bitcoin的验证是第一层，EVM的计算是第二层（注意这是一个区块连协议内部的分层，不是Layer 1和Layer 2）。Qtum对UTXO中<code>scriptPubKey</code>的处理逻辑进行修改，以实现在交易打包后，将Bitcoin Transaction中携带的请求传递给EVM进行执行的效果。Qtum将Bitcoin和Ethereum的执行模型桥接到了一起，网络节点先验证交易输入部分（同Bitcoin），再调用合约进行计算（同Ethereum），状态分散在UTXO模型和EVM自己的状态存储两个地方，整体架构比较复杂。</p>
<p>CKB所做的是继承Bitcoin的架构思路，对UTXO模型进行一般化(Generalization)处理得到Cell模型，整体架构保持了一致性以及Bitcoin的简洁。CKB上的所有状态都在Cell里面，计算在链下完成（类似Bitcoin），网络节点只做验证。</p>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/ckb-cell/1562" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Jan Xie</name>
            <uri>https://twitter.com/busyforking</uri>
        </author>
        <category label="Cell-Model" term="Cell-Model"/>
        <category label="CKB" term="CKB"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[区块链与状态爆炸]]></title>
        <id>https://cookbook.ckbdapps.com/blog/blockchain-and-state</id>
        <link href="https://cookbook.ckbdapps.com/blog/blockchain-and-state"/>
        <updated>2019-03-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[如果Layer 1的关注点应该是状态而不是计算 , 在设计Layer 1区块链的时候，我们就需要先理解什么是区块链的状态。理解了状态是什么，我们才能理解状态爆炸是什么。]]></summary>
        <content type="html"><![CDATA[<p>如果<a href="https://talk.nervos.org/t/layer-1/1486/4" target="_blank" rel="noopener noreferrer">Layer 1的关注点应该是状态而不是计算 </a>, 在设计Layer 1区块链的时候，我们就需要先理解什么是区块链的状态。理解了状态是什么，我们才能理解状态爆炸是什么。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="状态">状态<a href="https://cookbook.ckbdapps.com/blog/blockchain-and-state#%E7%8A%B6%E6%80%81" class="hash-link" aria-label="Direct link to 状态" title="Direct link to 状态">​</a></h2>
<p>区块链网络中的每一个全节点，在网络中运行一段时间之后都会在本地存储上留下一些数据，我们可以按照历史和现在把它们分为两类：</p>
<ul>
<li>历史 - 区块数据和交易数据都是历史，历史是从Genesis到达当前状态的路径。</li>
<li>状态（即现在） - 节点在处理完从Genesis到当前高度的所有区块和交易后形成的最终结果。状态随着区块的增加一直处于变化之中，交易是造成变化的原因。</li>
</ul>
<p>共识协议的作用是通过一系列的消息交换，保证每一个节点看到的当前状态是相同的，而实现这个目标的方式是保证每一个节点看到的历史是相同的。只要历史相同（即所有交易的排序相同），处理交易的方式相同（把交易放在相同的确定性虚拟机里面执行），最后看到的当前状态就是相同的。当我们说“区块链具有不可篡改性”的时候，指的是区块链历史不可篡改，相反，状态是一直在变化的。</p>
<p>有趣的是，不同的区块链保存历史和状态的方式不同的，其中的差异使得不同的区块链形成了各自的特点。由于这篇文章讨论的话题是状态，而影响状态的历史数据主要是交易（而不是区块头），接下来的讨论历史的时候会侧重交易，忽略区块头。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bitcoin的历史和状态">Bitcoin的历史和状态<a href="https://cookbook.ckbdapps.com/blog/blockchain-and-state#bitcoin%E7%9A%84%E5%8E%86%E5%8F%B2%E5%92%8C%E7%8A%B6%E6%80%81" class="hash-link" aria-label="Direct link to Bitcoin的历史和状态" title="Direct link to Bitcoin的历史和状态">​</a></h3>
<p>Bitcoin的状态，指的是Bitcoin账本当前的样子。Bitcoin的状态是由一个个UTXO（尚未花费的交易输出）构成的，每个UTXO代表了一定数量的Bitcoin，每个UTXO上面写了一个名字（scriptPubkey），记录这个UTXO的所有者是谁。如果要做一个比喻的话，Bitcoin的当前状态是一个装满了金币的袋子，每个金币上刻着所有者的名字。</p>
<p>Bitcoin的历史由一连串的交易构成，交易内部的主要结构是输入和输出。交易更改状态的方法是，把当前状态中包含的一些UTXO（交易输入引用的那些）标记为已花费，从UTXO集合中移出，然后把一些新的UTXO（这个交易的输出）添加到UTXO集合里面去。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-cf4ec833cdcf0896cfaf189535b4c3c7.png" width="1018" height="628" class="img_ev3q"></p>
<p>可以看出，Bitcoin交易的输出（TXO，Transaction Output）正是上面说的UTXO，UTXO只不过是一种处于特殊阶段（尚未花费）的TXO。因为构成Bitcoin状态的组件(UTXO)，同时也是构成交易的组件(TXO)。由此Bitcoin有一个奇妙的性质：<strong>任意时刻的状态都是历史的一个子集，历史和状态包含的数据类型是同一维度的</strong>。交易的历史（所有被打包的交易的集合，即所有产生过的TXO的集合）即状态的历史（每个区块对应的UTXO集合的集合，也是所有产生过的TXO的集合），Bitcoin的历史只包含交易。</p>
<p>在Bitcoin网络中，每一个区块，每一个UTXO都要持续占用节点的存储空间。目前Bitcoin<a href="https://www.blockchain.com/en/charts/blocks-size" target="_blank" rel="noopener noreferrer">整个历史的大小（所有区块加起来的大小）大约是200G </a>，而<a href="https://statoshi.info/dashboard/db/unspent-transaction-output-set" target="_blank" rel="noopener noreferrer">状态的大小只有<del>3G(由</del>5000万个UTXO组成) </a>。Bitcoin通过对区块大小的限制很好的管理了历史的增长速度，由于其历史和状态之间的子集关系，状态数据大小必然远小于历史数据大小，因此状态增长也间接的受到区块大小的管理。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ethereum的历史和状态">Ethereum的历史和状态<a href="https://cookbook.ckbdapps.com/blog/blockchain-and-state#ethereum%E7%9A%84%E5%8E%86%E5%8F%B2%E5%92%8C%E7%8A%B6%E6%80%81" class="hash-link" aria-label="Direct link to Ethereum的历史和状态" title="Direct link to Ethereum的历史和状态">​</a></h3>
<p>Ethereum的状态，也叫做“世界状态”，指的是Ethereum账本当前的样子。Ethereum的状态是由账户构成的一棵Merkle树（账户是叶子），账户里面不仅记录了余额（代表一定数量的ether），还有合约的数据（例如每一只加密猫的数据）。Ethereum的状态可以看作一个大账本，账本的第一列是名字，第二列是余额，第三列是合约数据。</p>
<p>Ethereum的历史同样由交易构成，交易内部的主要结构是</p>
<ul>
<li>to - 另一个账户，代表交易的发送对象</li>
<li>value - 交易携带的ether数量</li>
<li>data - 交易携带的任意信息</li>
</ul>
<p>交易更改状态的方法是，EVM找到交易发送的目标账户，</p>
<ol>
<li>根据交易的value计算目标账户的新余额；</li>
<li>将交易携带的data作为参数传递给目标账户的智能合约，运行智能合约的逻辑，在运行中可能会修改任意账户的内部状态生成新的状态；</li>
<li>构造新的叶子存放新的状态，更新状态Merkle树</li>
</ol>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-1-6fc7c77eb62a585a8d282536fcb8b391.png" width="1042" height="658" class="img_ev3q"></p>
<p>可以看出，Ethereum的历史和交易结构与Bitcoin相比有非常大的不同。Ethereum的状态是由账户构成的，而交易是由触发账户变动的信息构成，状态和交易中记录的是完全不同类型的数据，二者之间没有超集和子集的关系，<strong>历史和状态所包含的数据类型是两个维度的</strong>，交易历史大小与状态大小之间没有必然的联系。交易修改状态后，不仅会产生新的状态（图中实线框的叶子），而且会留下旧的状态（图中虚线框的叶子）成为历史状态，因此Ethereum的历史不仅仅包含交易，还包含历史状态。因为历史和状态属于不同的维度，Ethereum区块头中不仅仅包含交易的merkle root, 也需要显式包含状态的merkle root。（思考题：EOS使用了类似Ethereum的账户模型，却没有在区块头中包含状态的Merkle Tree Root，这是好还是不好？）</p>
<p>Ethereum中每一个区块，每一个账户都会持续占用节点的存储空间。Ethereum节点在同步的时候有多种模式，在Archive模式下所有的历史和状态都会保存下来，其中历史包括历史交易和历史状态，<a href="https://etherscan.io/chartsync/chainarchive" target="_blank" rel="noopener noreferrer">所有数据加起来大小超过了2TB </a>；在Default模式下，历史状态会被裁剪掉，本地只保留历史交易和当前状态，<a href="https://etherscan.io/chartsync/chaindefault" target="_blank" rel="noopener noreferrer">所有数据加起来大约是170G </a>，其中<a href="http://webcache.googleusercontent.com/search?q=cache:http://didtheethereumblockchainreach1tbyet.5chdn.co/" target="_blank" rel="noopener noreferrer">交易历史大小是150G，当前状态大小是10G </a>。Ethereum中所有的开销管理都被统一到gas计费模型之下，<a href="https://ethereum.stackexchange.com/questions/1106/is-there-a-limit-for-transaction-size" target="_blank" rel="noopener noreferrer">交易的大小需要消耗对应的gas </a>，而每一条EVM指令消耗的gas，不仅考虑了计算开销，<a href="https://medium.com/coinmonks/storing-on-ethereum-analyzing-the-costs-922d41d6b316" target="_blank" rel="noopener noreferrer">也将存储开销考虑在内 </a>。通过每个区块的gaslimit，间接限制了历史和状态的增长速度。</p>
<p>ps. 常见的一个误解是，Ethereum的“区块链大小”已经超过1T了。从上面的分析我们可以看到，“区块链大小”是一个非常模糊的定义，如果把历史状态算进去，确实超过了，但是对于全节点来说，把历史状态删掉没有任何问题，因为只要有Genesis和交易历史，任意时刻的历史状态都可以重新被计算出来（不考虑计算需要的时间）。真正有意义的数据，是全节点必须的数据的大小，Bitcoin是200G，Ethereum是170G，两者是基本相同的，而且在平均配置的云主机上都能装下，因此人们观察到的<a href="https://www.trustnodes.com/2019/01/09/bitcoin-overtakes-ethereum-in-node-numbers" target="_blank" rel="noopener noreferrer">Ethereum全节点减少 </a> 并不是由于存储增加导致的（根本原因是同步时的计算开销，这里不展开了）。考虑到Ethereum的历史长度（当前区块的timestamp减去genesis的timestamp）不到Bitcoin的一半，可以看出Ethereum的历史和状态大小增长更快。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="区块链版本的公地悲剧">区块链版本的公地悲剧<a href="https://cookbook.ckbdapps.com/blog/blockchain-and-state#%E5%8C%BA%E5%9D%97%E9%93%BE%E7%89%88%E6%9C%AC%E7%9A%84%E5%85%AC%E5%9C%B0%E6%82%B2%E5%89%A7" class="hash-link" aria-label="Direct link to 区块链版本的公地悲剧" title="Direct link to 区块链版本的公地悲剧">​</a></h2>
<p><a href="https://en.wikipedia.org/wiki/Tragedy_of_the_commons" target="_blank" rel="noopener noreferrer">公地悲剧 </a> 所指的是这样一种情况，有限的共享资源在不受任何限制的使用下被人们过度消耗。区块链节点为保存历史和状态付出的存储，正是这样一种共享资源。</p>
<p>区块链节点为处理交易所花费的资源有三种，CPU，存储和网络带宽。CPU和带宽都是每个区块会刷新的资源，我们可以认为每个区块间隔内都用同样多的CPU和带宽可供使用，上个区块消耗掉的CPU和带宽不会让下个区块可用的CPU和带宽变少。对于可刷新的资源，我们可以通过一次性支付的交易手续费来补偿节点（手续费与计算复杂度和交易大小的相关性可参考<a href="https://github.com/nervosnetwork/rfcs/blob/0015-crypto/rfcs/0015-ckb-cryptoeconomics/0015-ckb-cryptoeconomics.md" target="_blank" rel="noopener noreferrer">RFC0015 Appendix </a>）。</p>
<p>与CPU和带宽不同，存储是一种占用资源，在一个区块中被占用了的存储，除非使用者主动释放，否则无法在后面的区块中被其它使用者使用。节点需要为存储持续的付出成本，而使用者却不需要为存储持续的支付手续费（记住交易手续费只需要支付一次）。使用者只需要在往区块链写数据的时候支付一点点手续费，就可以永久使用一个可用性超过Amazon S3的存储，其无限大的永久存储成本需要区块链网络中的所有全节点来承担。</p>
<p>Ethereum上由于各种DApp的存在，The Tragedy of (Storage) Commons相对更加严重。例如，<a href="https://github.com/Mine77/eth-storage-analyze/blob/master/data/first200_on5700001.csv" target="_blank" rel="noopener noreferrer">在区块5700001（May 30, 2018）的时候，使用状态最多的5个合约 </a> 是：</p>
<ol>
<li>EtherDelta, 5.09%</li>
<li>IDEX, 4.17%</li>
<li>CryptoKitties, 3.05%</li>
<li>ENS, 1.92%</li>
<li>EOS Sale, 1.73%</li>
</ol>
<p>比较有趣的是最后一个，EOS Sale。虽然EOS的众筹已经完成，EOS代币已经在EOS链上流转，EOS众筹的记录却永远留在了Ethereum的节点上，消耗Ethereum全节点的存储资源。</p>
<p>可以看到，在缺乏管理的情况下，区块链的存储资源会被有意或者无意的滥用。在一个设计合理的经济模型中，使用者必须承担存储占用的成本，这个成本不仅仅与占用存储空间的大小成正比，还与占用时间的长度成正比。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="状态爆炸">状态爆炸<a href="https://cookbook.ckbdapps.com/blog/blockchain-and-state#%E7%8A%B6%E6%80%81%E7%88%86%E7%82%B8" class="hash-link" aria-label="Direct link to 状态爆炸" title="Direct link to 状态爆炸">​</a></h2>
<p>无论是历史还是状态数据都会占用存储资源。通过上面对Bitcoin和Ethereum的分析（其他区块链的状态模型基本都可以归纳为二者之一）可以看到，虽然它们对历史和状态的增长进行了管理，但是对历史和状态的总大小却没有任何控制，这些数据会持续的无休止的累积下去，使得运行全节点需要的存储资源越来越大，<a href="https://talk.nervos.org/t/dont-trust-verify/335" target="_blank" rel="noopener noreferrer">提高全节点的运行门槛，使网络的去中心化程度越来越低 </a>，这是我们不愿意看到的。</p>
<p>你也许会说，有没有可能硬件平均水平的提高会超过历史和状态的积累速度？我的回答是可能性很低：</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-2-cb409c4232de7e478019bcd9dc34332b.png" width="1280" height="720" class="img_ev3q"></p>
<p>从这张图中我们可以看到，随着Ethereum网络的发展，状态数据累积的数量呈指数式的增长。Bitcoin的状态数据从0积累到3G，用了10年；Ethereum的状态数据从0积累到10G，用了4年；而这是在我们还没有解决Scalability问题，区块链仍然是小众技术的情况下的增长速度。当我们解决了scalability问题，区块链真正获得mass adoption，DApp和用户数量都爆炸式增长的时候，区块链历史和状态数据会以什么速度累积呢？</p>
<p>这就是状态爆炸问题，我们把它归类为post-scalability problem，因为它在解决scalability问题之后会非常明显。我们最早是在做<a href="https://www.citahub.com/" target="_blank" rel="noopener noreferrer">许可链场景落地 </a> 时注意到了这个问题，因为<a href="https://mp.weixin.qq.com/s/nKcM4G9plxZLneFtea6Lpg" target="_blank" rel="noopener noreferrer">许可链的性能远高于公有链 </a>，刚好处于post-scalability的阶段。（思考题：许可链怎么解决状态爆炸问题？）</p>
<p>历史数据的累积相对容易处理，未来可以通过去中心化的Checkpoint或是零知识证明等技术来压缩，在那之前全节点甚至可以把历史直接丢掉，依然可以正常运行。 状态数据的累积则麻烦许多，因为它是全节点运行必须的数据。</p>
<p>不少区块链项目已经看到了这个问题，并提出了一些解决方案。EOS RAM是解决状态爆炸问题的一个有益尝试：RAM代表了超级节点服务器可用的内存资源，无论是账户、合约状态还是代码，都需要占用一定的RAM才能运行。RAM的设计也有很多问题，它需要通过内置的交易市场购买，不可转让，无法租用，将合约执行过程中的短期内存需求和合约状态的长期存储需求混在了一起，而且RAM的总量的设定没有确定的规则，更多取决于超级节点可以承受的硬件配置，而非<a href="https://talk.nervos.org/t/nervos-bitcoin/1372/50" target="_blank" rel="noopener noreferrer">共识空间的成本 </a>。</p>
<p>Ethereum社区也看到了这个问题并提出了<a href="https://github.com/ethereum/EIPs/pull/1682" target="_blank" rel="noopener noreferrer">Storage Rent的方案 </a>：要求使用者为存储资源的使用预支付一笔租金，占用存储资源会持续消耗这笔租金，占用时间越长，使用者需要支付的租金越多。Storage Rent方案存在两个问题：1. 预支付的租金终有一天会用完，这时候如何处理占用的状态？正是为解决这个问题，Storage Rent需要诸如resurrection的机制来补充，<a href="https://github.com/ledgerwatch/eth_state/blob/master/State_Fees_3.pdf" target="_blank" rel="noopener noreferrer">增加了设计的复杂度 </a>，使智能合约的immutability大打折扣，也为<a href="https://ethresear.ch/t/improving-ux-for-storage-rent/3994" target="_blank" rel="noopener noreferrer">使用体验带来了麻烦 </a>；2. Ethereum的状态模型是一种共享状态的模型，<a href="https://talk.nervos.org/t/first-class-asset/405" target="_blank" rel="noopener noreferrer">而不是First-class State </a>。以ERC20 Token为例，所有用户的资产记录都存放在单个ERC20合约的存储里面，在这种情况下，应该由谁来支付租金？</p>
<p>解决状态爆炸问题也是Nervos CKB的设计目标之一，为此CKB走了一条完全不同的、更为彻底的变革之路。</p>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/topic/1515" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Jan Xie</name>
            <uri>https://twitter.com/busyforking</uri>
        </author>
        <category label="L1" term="L1"/>
        <category label="CKB" term="CKB"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Layer 1 应该做什么]]></title>
        <id>https://cookbook.ckbdapps.com/blog/what-layer1-do</id>
        <link href="https://cookbook.ckbdapps.com/blog/what-layer1-do"/>
        <updated>2019-03-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Nervos Approach]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="nervos-approach">Nervos Approach<a href="https://cookbook.ckbdapps.com/blog/what-layer1-do#nervos-approach" class="hash-link" aria-label="Direct link to Nervos Approach" title="Direct link to Nervos Approach">​</a></h2>
<p>Nervos Network的技术目标是设计一个<a href="https://talk.nervos.org/t/topic/336" target="_blank" rel="noopener noreferrer">分层的加密经济网络 </a>。这样一个出发点带来的是一个与众不同的设计思路，我们自己把它称为[Nervos Approach]:</p>
<p><strong>如果我们认为分层是未来的发展方向，我们应该从一开始就考虑到上层协议和分层网络的需求，在分层的大框架下去设计区块链协议。</strong></p>
<p>换句话说，从分层的角度来看，现有的区块链设计方式都是过时的。现有的区块链在设计时考虑的是特定的功能（例如支付，或者是运行DApp），并希望在运行一段时间后让上层协议来适应自己。然而如果我们阅读互联网的历史就知道，今天互联网的协议分层不是这样打补丁打出来的，相反是在吸收过去经验之后<a href="https://en.wikipedia.org/wiki/Internet_protocol_suite" target="_blank" rel="noopener noreferrer">基于分层的思路重新设计出来的 </a>（是的，互联网协议也是分层的，这是我们为什么总是说 TCP/IP，它们实际上是两个协议的名字）。Nervos Approach是向互联网学习的产物。</p>
<p>这是为什么区块链并不天然是Layer 1，Layer 1是需要设计的。这也是为什么我们选择设计CKB这样一个新的区块链协议。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="layer-1-vs-layer-2">Layer 1 vs. Layer 2<a href="https://cookbook.ckbdapps.com/blog/what-layer1-do#layer-1-vs-layer-2" class="hash-link" aria-label="Direct link to Layer 1 vs. Layer 2" title="Direct link to Layer 1 vs. Layer 2">​</a></h2>
<p>要弄清Layer 1应该做什么，先要弄清楚它和上层协议的区别。Layer 2起源与我们发现公有链（这里指permissionless blockchain）的性能不足，很难扩容到满足整个加密经济体需求的水平，同时我们又非常迷恋公有链提供的可用性和极大的服务范围，因此慢慢演化出了一系列可以由区块链来保证安全的Layer 2协议，例如支付通道(payment channel), plasma, etc.</p>
<p>这些协议的共同特点是牺牲共识范围来换取性能。公有链最让人惊艳的地方是通过开放网络提供不间断的覆盖全球的服务，这意味着全球共识，也意味着性能底下。解决这个问题的最好方式是将大部分交易转移到共识范围更小但是性能更好的上层协议中，并且保证上层协议的参与者总是可以<a href="https://en.wikipedia.org/wiki/Exit,_Voice,_and_Loyalty" target="_blank" rel="noopener noreferrer">在不满意的时候退回到区块链上来解决问题 </a>，代价仅仅是一些时间成本。</p>
<p>因此作为Layer 1的区块链，关注点显然不应该是性能，因为Layer 2会承担这个职责。Layer 1是保障上层协议参与者的最后防线，它的关注点应该是安全和去中心化（安全和去中心化是两个东西，有时间再展开）。如果我们观察Layer 2协议与Layer 1交互的模式，我们还会发现，Layer 1负责的是状态共识（存储），Layer 2负责的是状态生成（计算）。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="计算与状态">计算与状态<a href="https://cookbook.ckbdapps.com/blog/what-layer1-do#%E8%AE%A1%E7%AE%97%E4%B8%8E%E7%8A%B6%E6%80%81" class="hash-link" aria-label="Direct link to 计算与状态" title="Direct link to 计算与状态">​</a></h2>
<p>程序员的世界中有一个流传甚广的公式：<a href="https://en.wikipedia.org/wiki/Algorithms_%2B_Data_Structures_%3D_Programs" target="_blank" rel="noopener noreferrer">程序 = 算法 + 数据结构 </a>。这个等式指出了程序设计的两个核心关注点，计算（算法即计算的步骤）与数据（计算的对象）。而数据又可以分为两种，程序输入（外部数据）和状态（内部数据）。</p>
<p>计算机科学中的”状态“一词可以理解为程序在运行时某个特定时刻可访问的一切数据。程序中有变量，变量通常代表着内存中的一个可以存放数据的位置，这个位置的内容就是程序的状态。一段程序的输出完全取决于它的输入和其开始执行时的状态。计算（CPU）、输入/输出（IO）与状态（内存）构成了完整的<a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture" target="_blank" rel="noopener noreferrer">冯诺依曼体系 </a>，今天最流行的计算架构。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-97705b7af5ba5a8f5ef809b740f6f9d2.png" width="510" height="295" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="以支付通道为例">以支付通道为例<a href="https://cookbook.ckbdapps.com/blog/what-layer1-do#%E4%BB%A5%E6%94%AF%E4%BB%98%E9%80%9A%E9%81%93%E4%B8%BA%E4%BE%8B" class="hash-link" aria-label="Direct link to 以支付通道为例" title="Direct link to 以支付通道为例">​</a></h2>
<p>在支付通道中，Layer 2的共识范围缩小到两人之间，这是最小范围的共识。参与通道的两人进行的操作如下：</p>
<ol>
<li>向Layer 1发送交易建立通道，锁定特定的状态，锁定的状态只有用Alice和Bob双方的签名才能更新</li>
<li>例如Alice锁定1 BTC，Bob锁定1 BTC，我们用(1, 1)表示在Layer 1锁定的状态</li>
<li>双方通过链外的网络连接(Layer 2)，产生并交换新的状态，各自签名</li>
<li>Alice → Bob 0.5 BTC，Alice/Bob在本地保存的新状态为(0.5, 1.5)</li>
<li>Bob → Alice 0.1 BTC, Alice/Bob在本地保存的新状态为(0.6, 1.4)</li>
<li>…</li>
<li>最后一次交换后，Alice/Bob在本地保存的新状态为(0.2, 1.8)，而且双方都对该状态进行了签名</li>
<li>向Layer 1发送最终的状态，Layer 1验证最终提交的状态有Alice/Bob双方的签名，更新锁定的状态为(0.2, 1.8)并解锁</li>
</ol>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-1-6b685a06571f54997c53c238aaea668d.png" width="870" height="411" class="img_ev3q"></p>
<p>从这个例子我们很容易看到，在整个过程中，我们通常讨论的计算分成了两个部分进行：新状态的生成，新状态的验证。前者发生在Layer 2，而后者发生在Layer 1。如果我们观察其他的Layer 2协议，例如Plasma或者是TrueBit，很容易得到类似的结论。正因为Layer 1会验证Layer 2产生的状态，我们才能够做到通过Layer 1保证Layer 2的安全，因为Layer 2的用户在遇到问题的时候，总是可以请求Layer 1来做某种形式的验证（这是为什么Layer 1可以看作”Crypto Court”，因为它是一个能识别密码学证明的“法院”）。</p>
<p>因此在分层架构下，Layer 1的关注点应该是状态的验证（和存储），Layer 2的关注点应该是状态的生成。通过将状态的生成转移到Layer 2，将生成和验证分离，我们的分层网络兼顾了性能（Layer 2）、安全和去中心化（Layer 1）。</p>
<p>任何程序都有计算和状态，区块链上运行的程序（DApp）自然也不例外，在分层架构上构建应用时，需要考虑在哪里产生状态，在哪里验证状态，在哪里保存状态。由于状态的生成和验证分离，状态生成的方法可以和验证解耦，状态生成不必被Layer 1的编程模型绑定，具有更大的自由度。只要能通过Layer 1验证，状态的生成甚至可以是中心化的（事实上大部分Plasma协议中只有一个Operator!）。</p>
<p><img decoding="async" loading="lazy" alt="layered-architecture.png" src="https://cookbook.ckbdapps.com/assets/images/layered-architecture-cbb31a237a85ef8d5ae9b3535f750283.png" width="1274" height="708" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="layer-1应该做什么">Layer 1应该做什么<a href="https://cookbook.ckbdapps.com/blog/what-layer1-do#layer-1%E5%BA%94%E8%AF%A5%E5%81%9A%E4%BB%80%E4%B9%88" class="hash-link" aria-label="Direct link to Layer 1应该做什么" title="Direct link to Layer 1应该做什么">​</a></h2>
<p>我们在说“计算”的时候，实际上说的是“状态生成”。在一般的计算模型里面，不存在信任和安全问题（我的CPU不会用假的结果骗我），所以生成就好，不考虑验证；但是在区块链网络里面，我们不仅需要生成，还需要验证。Layer 1的关注点应该是状态的验证和存储，而不是状态生成（希望你没有被绕晕…）。</p>
<p>由此我们终于可以推出Layer 1应该做什么：</p>
<ul>
<li>1、<strong>需要一个安全的共识协议，范围越大越好。</strong> 基于PoW的Nakamoto Consensus正是这样一个协议，这是唯一一个在现实环境中经过验证的全球共识。</li>
<li>2、<strong>需要可编程能力，以支持各种状态验证逻辑，这意味着我们需要一个强大的编程模型（状态模型+虚拟机）。</strong></li>
<li>3、<strong>需要能够理解各种密码学证明，因为区块链协议是基于密码学构建的，Layer 1与Layer 2之间传递的证明是密码学证明。</strong></li>
<li>4、<strong>需要管理好状态，因为经过验证的状态会留在Layer 1上。</strong> 这意味着我们需要一个<a href="https://github.com/nervosnetwork/rfcs/pull/78" target="_blank" rel="noopener noreferrer">关注状态的经济模型 </a>。</li>
</ul>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/layer-1/1486" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Jan Xie</name>
            <uri>https://twitter.com/busyforking</uri>
        </author>
        <category label="L1" term="L1"/>
        <category label="Bitcoin" term="Bitcoin"/>
        <category label="CKB" term="CKB"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[First-class Asset]]></title>
        <id>https://cookbook.ckbdapps.com/blog/first-class-asset</id>
        <link href="https://cookbook.ckbdapps.com/blog/first-class-asset"/>
        <updated>2018-12-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[喜欢函数式编程的工程师应该很熟悉一个名词：First-class Function，翻译成中文应该叫“头等函数”或者“一等函数”。First-class Function指的是一类编程语言，在这些语言中函数是一个完全独立的概念：函数可以被当作值赋给一个变量，可以被当作参数传递给其他函数，也可以被当作返回值从其它函数传出来。在这样的语言中我们可以像操纵数据一样操纵函数，所以在这些语言中函数和数据一样是“一等公民”（First-class citizen）。First-class Function是函数式语言的一个关键特性，很多函数式编程的强大能力来源于此。]]></summary>
        <content type="html"><![CDATA[<p>喜欢函数式编程的工程师应该很熟悉一个名词：First-class Function，翻译成中文应该叫“头等函数”或者“一等函数”。First-class Function指的是一类编程语言，在这些语言中函数是一个完全独立的概念：函数可以被当作值赋给一个变量，可以被当作参数传递给其他函数，也可以被当作返回值从其它函数传出来。在这样的语言中我们可以像操纵数据一样操纵函数，所以在这些语言中函数和数据一样是“一等公民”（First-class citizen）。First-class Function是函数式语言的一个关键特性，很多函数式编程的强大能力来源于此。</p>
<p>Nervos CKB使用Cell模型来构建整个共同知识库的状态。Cell模型是一个非常简单但是与现有区块链设计非常不同的状态模型，我们在设计Cell模型的时候已经意识到，基于Cell模型的DApp将拥有一些非常不同的性质，就像函数式编程和面向对象编程会产生风格迥异的设计模式和程序特性一样。在这篇文章中，我想阐述Cell模型可以支持的一种非常有趣的DApp设计模式，我们把它叫做First-class Asset，因为通过它我们可以将用户自定义的加密资产变成区块链中的“一等公民”。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="状态模型的快速入门">状态模型的快速入门<a href="https://cookbook.ckbdapps.com/blog/first-class-asset#%E7%8A%B6%E6%80%81%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8" class="hash-link" aria-label="Direct link to 状态模型的快速入门" title="Direct link to 状态模型的快速入门">​</a></h2>
<p>在Cell模型之前，各种区块链使用的状态模型基本上就是两种：UTXO模型和Account模型。</p>
<p>使用UTXO模型的代表是比特币。UTXO是未被花费的交易输出（Unspent Transaction Output）的缩写，一个UTXO可以简单的理解为是一个比特币，然而和一般的硬币不同，每一个UTXO的面值都是不一样的。每个UTXO中都通过一段锁脚本（lock script）记录了这枚硬币的所有者是谁，同时保证只有所有者能够花费这枚硬币。每一个比特币全节点都会维护当前所有UTXO的集合，这个集合我们就称为比特币账本的当前状态（即当前的账本）。每一次比特币转账都是一个从UTXO集合中删除几个硬币（属于付款方）然后又增加几个新硬币（属于收款方和/或付款方）的过程。由于整个账本状态是基于UTXO这个最小单元构建的，我们把它叫做UTXO模型。</p>
<p><img decoding="async" loading="lazy" alt="First-class Asset _ UTXO Model.png" src="https://cookbook.ckbdapps.com/assets/images/image-20929f48b6c94ca328955ade618d72ec.png" width="838" height="392" class="img_ev3q"></p>
<p>使用Account模型的代表是以太坊。Account就是账户，和银行账户类似，代表了资产的所有者，账户里面最重要的数据是余额（Balance），记录这个账户持有的以太币的数量。账户是资产所有者的代表，所有者可以是人（对应外部账户）或者智能合约（对应合约账户），外部账户通过私钥签名来验证资产所有权，合约账户的所有权通过合约代码来确定，合约代码和状态都保存合约账户内部。外部账户要转账的时候，用户在交易中指明转账数量，账本中的付款方账户余额和收款方账户余额就会做相应的减少和增加。由于整个账本状态是基于账户（Account）这个最小单元构建的，我们把它叫做Account模型。</p>
<p><img decoding="async" loading="lazy" alt="First-class Asset _ Account Model.png" src="https://cookbook.ckbdapps.com/assets/images/image-1-42064694431284f9219c6c8227dc1243.png" width="838" height="392" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="first-class-coin">First-class Coin<a href="https://cookbook.ckbdapps.com/blog/first-class-asset#first-class-coin" class="hash-link" aria-label="Direct link to First-class Coin" title="Direct link to First-class Coin">​</a></h2>
<p>UTXO模型和Account模型代表了构建账本状态的两种思路。账本是所有者与资产之间关系的集合。UTXO模型以资产为基础建模，先构建出“硬币”的概念，再给硬币赋予所有者的属性；Account模型以所有者为基础建模，先构建出“账户”的概念，再给账户赋予余额的属性。以哪种方式作为基础模型决定了系统中的操作的基本对象是资产还是账户（所有者）。</p>
<p>所以我们说，硬币（Coin）是UTXO模型中的First-class citizen，每一个UTXO都是一个具有独立标识符的对象（Transaction ID + Output Index），coin是用户直接操作的对象（用户在构造的交易中包含utxo），账户是基于coin建立的上层概念（只存在于钱包中）。因此UTXO是First-class Coin。</p>
<p><img decoding="async" loading="lazy" alt="First-class Asset_UTXO Transaction" src="https://cookbook.ckbdapps.com/assets/images/image-2-1d9ac07d6d4bd2de167c0ce849ef53b2.png" width="514" height="322" class="img_ev3q"></p>
<p>在Account模型中，账户是First-class citizen，聚合在账户余额中的硬币没有独立的标识符。账户是用户直接操作的对象，资产的转移是由账户作为用户的代理实现的，这一点在接受方是合约账户时体现的最为明显。在这样的模型下，用户定义加密资产（例如ERC20）更像是通过第三方记账的方式，而非点对点的方式转移，这个差异会将第三方（这里的第三方指的是托管加密资产的智能合约）引入资产转移流程，增加智能合约的设计复杂度（我们可以把智能合约看作在资产转移时会自动执行的逻辑）。为了降低这种复杂度，Account模型中的交易需要加入特殊的逻辑（value字段），但是这样的特殊逻辑只有助于原生资产，同时造成对原生资产和用户自定义资产的不同代码路径。对于这些问题，Kelvin Fitcher写过一篇<a href="https://medium.com/@kelvinfichter/looking-at-ownership-in-the-evm-6e6914d341d" target="_blank" rel="noopener noreferrer">Looking at ownership in the EVM </a>进行了很好的分析，在此不再赘述。</p>
<p><img decoding="async" loading="lazy" alt="First-class Asset_Account Transaction" src="https://cookbook.ckbdapps.com/assets/images/image-3-602d2a64531ec2124049127ba3659f0a.png" width="514" height="322" class="img_ev3q"></p>
<p>有了这些背景，我们应该更容易理解CKB的这一设计理念了：</p>
<p><strong>有了Cell模型，我们能够简化设计，并在Nervos CKB上实现作为“一等公民”的用户定义资产（User Defined Assets），简称 First-class Assets.</strong></p>
<p>First-class Assets与UTXO一样，具有独立标识符，可以被用户及脚本直接引用和操作。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="first-class-state">First-class State<a href="https://cookbook.ckbdapps.com/blog/first-class-asset#first-class-state" class="hash-link" aria-label="Direct link to First-class State" title="Direct link to First-class State">​</a></h2>
<p>如何实现First-class Assets呢？</p>
<p>无论用何种方式，我们都需要记录所有者和资产之间的关系。这些关系记录，本质上是经过共识的状态。要有First-class Assets, 必须先有First-class State，而这正是Cell模型的出发点。</p>
<p>Nervos CKB的名字来自于Common Knowledge Base（共同知识库）的缩写。我们之所以把Nervos网络中的区块链称为“共同知识库“，是因为它的责任是持续不断的对网络的共同状态形成全球共识，换句话说，CKB是一个由全球共识维护的状态库。一个状态库的基本模型，很自然的是将整个状态划分为更小的状态单元组织起来。这些更小的状态单元，就是Cell。</p>
<p>由于Cell是一种状态单元，有独立的标识符（Transaction ID + Cell Output Index），可以被直接引用，作为参数传递给脚本，它是CKB中的“一等公民”，也就是说状态是CKB中的“一等公民”。Cell不仅仅是一种First-class State，而且是最简单的一种First-class State：一个Cell中只有Capacity，Data，Lock以及Type（可选，Type可以是一段代码或者指向一个Code Cell的Reference）四个字段。如下图所示，Cell的所有者可以直接更新Cell中保存的状态，不需要经过任何中间方，而在Account模型中用户只能通过合约代码（账户中的code）来操作账户内的状态，状态实际上是托管在合约手中的。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-4-df15af5141502620a0eb49d07698a4dd.png" width="1213" height="589" class="img_ev3q"></p>
<p>值得指出的是，有了Cell，CKB实际上就获得了一种有状态的编程模型。一种普遍的观点是，以太坊编程模型的表达能力来自图灵完备的虚拟机，实际上通过账户使得智能合约能够保存计算状态是一个大过EVM的优点（<a href="https://en.wikipedia.org/wiki/Total_functional_programming" target="_blank" rel="noopener noreferrer">图灵不完备的语言也有很强大的表达能力 </a>）。CKB通过Cell和CKB-VM（Simple Yet Powerful! 这得另外写一篇文章了）的组合实现了一种新的有状态的智能合约编程模型。这个编程模型更加适合Layer 2，因为通过分析Layer 2协议的共同模式我们可以看到，协议层之间的交互对象应该是状态对象（State Transaction）而不是事件对象（Event Transaction），Layer 1应该是一个状态层而不是计算层。</p>
<p>CKB编程模型的另一个特点是，不区分数据（状态）和代码。这句话的意思是，与Account模型不同，合约的状态和代码都可以储存在Cell的data字段中，保存代码的Cell可以被其它Cell引用（因为它们是First-class State!），合约的状态和代码不需要绑定在一起，存放在一个地方。开发者可以通过一条简单的指令把代码Cell或者数据Cell的内容载入运行时内存，然后根据需要自行将其解释为代码执行或者数据来读写。</p>
<p><img decoding="async" loading="lazy" alt="alt text" src="https://cookbook.ckbdapps.com/assets/images/image-5-966285f21f4571b65dcb99cc02239437.png" width="1187" height="653" class="img_ev3q"></p>
<p>有了这些底层支持，我们就可以将一个合约的代码和状态分开保存在不同的地方：Code Cell的code (data)字段存放代码，而State Cell的state (data)的字段则保存状态；在State Cell中通过type ref引用Code Cell来建立对自身保存的state的业务逻辑约束，通过lock ref引用另外一个Code Cell来表达State Cell的所有权。每一个State Cell可以属于不同的用户，因此在Cell模型下独立的用户状态是非常容易实现的模式（在Account模型下，合约状态往往由多个用户状态混合构成，例如在一个ERC20合约中，Alice和Bob的Token余额都记录在同一个合约的内部状态里面）。</p>
<p>如果想对CKB-VM上的合约编写有更多了解，请看<a href="https://medium.com/nervosnetwork/an-introduction-to-ckb-vm-9d95678a7757" target="_blank" rel="noopener noreferrer">这篇文章 </a>和<a href="https://medium.com/nervosnetwork/hello-ckb-17b8c8fdfba2" target="_blank" rel="noopener noreferrer">这篇文章 </a></p>
<p>有了这样一种编程模型，我们就能构造First-class Asset了。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="first-class-asset">First-class Asset<a href="https://cookbook.ckbdapps.com/blog/first-class-asset#first-class-asset" class="hash-link" aria-label="Direct link to First-class Asset" title="Direct link to First-class Asset">​</a></h2>
<p>CKB中的用户定义资产（User Defined Asset）可以这样来构造：</p>
<ol>
<li>设计资产定义合约（Asset Definition），规定资产的主要约束（例如总数量，发行者，交易前后数量不变等）。</li>
<li>保存合约代码到Asset Definition Cell中。</li>
<li>在满足发行权限的情况下，发行者发行资产，并将资产状态保存在另外的State Cell中。State Cell的Type字段引用保存了资产定义的Code Cell，保证State Cell的变化受到资产定义的约束。</li>
<li>Asset Cell的持有者可以通过更新Lock来改变Asset Cell的所有者。</li>
</ol>
<p><img decoding="async" loading="lazy" src="https://cookbook.ckbdapps.com/assets/images/image-6-d5c81910959cc73e2c75ff6f398587c2.png" width="1189" height="635" class="img_ev3q"></p>
<p>可以看到，在这样的设计中，用户定义的资产是作为独立对象存在于系统中的，每一份资产都是一个Cell，每一份资产都拥有自己的标识符。我们完全可以认为Asset Cell是UTXO的通用化版本。这样的First-class Asset有如下优点：</p>
<ul>
<li>Asset Cell可以被引用，可以直接作为其它合约的参数传入。只要引用Asset Cell的input有正确的用户授权，合约就可以正常的使用用户的Asset Cell。</li>
<li>资产定义与资产状态分离。Asset Definition Cell的所有者是资产的发行者，而Asset Cell是属于每个用户的。Asset Cell的授权逻辑和业务逻辑分离，所有权完全由自己的lock决定，与Asset Definition的逻辑无关，这意味着First-class Asset不是托管在资产发行者、开发者或是资产定义合约的手中，而是<strong>真正完全属于用户的</strong>。</li>
<li>用户的资产相互隔离，用户资产状态独立。CKB的经济模型关注状态存储激励问题：用户在区块链上保存状态不仅需要支付写入费用，而且应该承担与存储时间成正比的存储成本。如果用户的资产状态混合在一个地方保存（例如ERC20），这些状态的存储成本有谁来支付将是一个问题。（CKB Economics Paper正在努力写作中…）</li>
<li>只要Asset Definition Cell的lock逻辑允许，资产定义可以独立更新。</li>
</ul>
<p>上面的示意图只是在CKB上实现 First-class Asset的一种方式。除了上面讨论的方面，还有一些有趣的细节，例如，Asset Definition Cell是不是可以有属于自己的状态？Asset Definition Cell以及Asset Cell的capacity应该由谁来提供？对于这些问题，我们已经有了一些非常漂亮的想法。这些细节的设计、讨论和实现是我们现在正在进行的工作。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://cookbook.ckbdapps.com/blog/first-class-asset#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>Cell模型是一个高度抽象的模型，事实上，你不仅可以在Cell上实现First-class Asset，也可以在Cell上模拟Account. 通过这篇文章的介绍我们可以看出，Cell模型是一个不同于UTXO模型和Account模型的新设计。除了状态模型的不同，CKB还将计算（也就是状态生成）转移到了链外，在链上只需要对状态进行验证的逻辑。独特的状态模型和计算验证分离这两点决定了CKB的编程模型上必然会出现新的DApp范式和设计模式。</p>
<p>从CKB白皮书完成到现在将近一年的时间中，我们看到越来越多的人开始关注和讨论First-class State和First-class Asset这两种新的思路（虽然大家用的名词各自都不一样），这些进展让我们非常兴奋。如果你有兴趣对First-class State和First-class Asset进行更多的探讨，或是在CKB的编程模型上有什么有趣的想法，欢迎联系我们讨论～</p>
<p>CKB的代码已经完全开源，这篇文章介绍的内容在代码中都已经实现。欢迎给我们的代码提出各种意见：</p>
<ul>
<li><a href="https://github.com/nervosnetwork/ckb-demo-ruby-sdk" target="_blank" rel="noopener noreferrer">https://github.com/nervosnetwork/ckb-demo-ruby-sdk </a> (ckb上用ruby脚本编程的示例，理解ckb上编程模型的最佳入口）</li>
<li><a href="https://github.com/nervosnetwork/ckb" target="_blank" rel="noopener noreferrer">https://github.com/nervosnetwork/ckb </a></li>
<li><a href="https://github.com/nervosnetwork/ckb-vm" target="_blank" rel="noopener noreferrer">https://github.com/nervosnetwork/ckb-vm </a></li>
</ul>
<p>感谢Ian Yang, Xuejie Xiao，Kevin Wang在CKB和Cell模型设计中提供的帮助～</p>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/first-class-asset/405" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Jan Xie</name>
            <uri>https://twitter.com/busyforking</uri>
        </author>
        <category label="L1" term="L1"/>
        <category label="Cell-Model" term="Cell-Model"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[An Introduction to Nervos CKB-VM]]></title>
        <id>https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm</id>
        <link href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm"/>
        <updated>2018-11-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[CKB-Virtual Machine (CKB-VM) is a RISC-V instruction set based VM for executing smart contracts on Nervos CKB, written in Rust.]]></summary>
        <content type="html"><![CDATA[<p>CKB-Virtual Machine (CKB-VM) is a RISC-V instruction set based VM for executing smart contracts on Nervos CKB, written in Rust.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="introduction"><strong>Introduction</strong><a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#introduction" class="hash-link" aria-label="Direct link to introduction" title="Direct link to introduction">​</a></h3>
<p>We considered the features that the CKB-VM will require during virtual machine (VM) selection for our layer 1 blockchain (Nervos CKB).</p>
<p>For a VM to be used on a blockchain, it must meet the following conditions:</p>
<ol>
<li><strong>Certainty:</strong> For a fixed program and input, the VM must always return the same output result. The result must not be dependant on external conditions such as time or the running environment.</li>
<li><strong>Security:</strong> The VM must not affect the operation of its host.</li>
</ol>
<p>Above we have listed mandatory conditions, though we have considered the design of a VM that will best serve the CKB’s objectives. After our research, <strong>we propose the following features</strong> :</p>
<ol>
<li><strong>Flexibility:</strong> It is our goal to design a VM flexible enough to run for years or decades, allowing the CKB to evolve along with the field of cryptography. Current cryptographic primitives such as secp256k1 may no longer be used and valuable new primitives and techniques (such as Schnorr or post-quantum signatures) will continue to emerge. New innovations should be made available to programs running on the VM and primitives that are no longer used should be able to be disregarded.
To demonstrate our requirement, we can examine Bitcoin. Currently Bitcoin makes use of SIGHASH for transaction signing and for consensus utilizes the SHA-256 hash algorithm. Can we say with certainty that SIGHASH will be best after several years or that SHA-256 will be suitable as a stable hash algorithm as computing capabilities increase over time? Currently a hard fork is required to implement new cryptographic primitives in all blockchain protocols we have examined. <strong>In designing the CKB, we explored the possibility of reducing this hard fork requirement through the design of the VM layer.</strong>
The question we ask is, can we allow the update of cryptographic algorithms or addition of new transaction verification logic to the VM? While secp256k1 is still used, would the implementation of signature verification become more efficient if driven by economic incentives? If someone finds out a better way to implement algorithms used on CKB or just need a new cryptographic primitive, can we enable he/she to do so freely?
We hope the VM layer of the CKB will provide maximum flexibility and broad implementation support to enable the exploration of these type of questions. With the CKB-VM’s design, users will not need to wait for implementation of a hard fork to utilize new cryptographic innovations.</li>
<li><strong>Runtime Visibility:</strong> After conducting research on the VM of existing blockchains, we have observed a problem. We will illustrate using Bitcoin as an example again: the VM layer of Bitcoin only provides one stack (and this VM does not know the amount of data that can be stored on the stack, or the stack depth). VMs implemented in stack mode also exhibit this issue.
Though the consensus layer may provide the stack depth definition or indirectly provide the stack depth (based on the code length or gas restriction), programs running on the VM cannot obtain the stack depth. Because developers of programs running on the VM must guess the program running status, programs running on the VM cannot use all potential capabilities of the VM.
Based on this thought, we have considered preferentially defining the restrictions of all resources during VM operation, including the gas restrictions and stack space size, and providing programs running on the VM the ability to query resource usage. This will allow programs running on the VM to utilize different algorithms based on resource availability. With this design, programs can utilize the VM’s full potential.
With this construction, we see more VM flexibility enabled in the following scenarios:
a) Different policies can be selected for contracts that store data, based on cell capacity. When there is sufficient cell capacity, a program can directly store data to reduce the number of CPU cycles used, or when cell capacity is constrained, the program can compress data to fit the smaller capacity, simply by utilizing more CPU cycles.
b) Different handling mechanisms can be selected for contracts according to the amount of cell data and size of remaining memory. When there is a small amount of cell data or substantial remaining memory, all cell data can be read to memory for handling. When there is a large amount of cell data or little remaining memory, a portion of memory can be read for each operation, an operation similar to swap memory.
c) For some common contracts, hash algorithms for example, different handling methods can be selected based on the number of CPU cycles provided by the user. For example, SHA3–256 is secure enough to meet most requirements, however, a contract may utilize the SHA3–512 algorithm to meet different security requirements by using more CPU cycles.</li>
<li><strong>Runtime overhead:</strong> The gas mechanism in the Ethereum virtual machine (EVM) is a brilliant design. It solves the halting problem in the context of a blockchain VM, and allows for turing-complete computation on a fully decentralized virtual machine. However, we have observed that it is difficult to design a proper gas computation method for different EVM opcodes.
We have found that the EVM has adjusted the gas computation mechanism in almost every version update. We wonder: can we ensure more efficient overhead calculation through VM design?</li>
</ol>
<p>We have considered the design of a VM that can deliver all of these features and have found that there is not an existing solution that can achieve our vision of the CKB.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="inspiration"><strong>Inspiration</strong><a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#inspiration" class="hash-link" aria-label="Direct link to inspiration" title="Direct link to inspiration">​</a></h3>
<p>We can design a VM that has advanced language features. For example: a VM for static verification or a VM that supports advanced data structures or various cryptographic algorithms. However, all blockchain projects must run under a Von Neumann CPU architecture (x86, x86_64, ARM) and all advanced VM features must be mapped to assembly instructions on current generation of CPU architecture, there is no way around this restriction.</p>
<p>For example, <a href="https://en.wikipedia.org/wiki/Chrome_V8" target="_blank" rel="noopener noreferrer">V8</a> might maintain the illusion that an infinite amount of memory is available, but deep down in V8, a sophisticated garbage collection algorithm must be implemented to support this behavior on a limited amount of linear memory space. Similarly, Haskell or Idris might have advanced static type checking that can prove (in a way) that software works correctly, but after type checking is done, there will still be a layer to translate type checked operations to unchecked raw x86_64 assembly instructions.</p>
<p>The main takeaway here is that we cannot deviate much from current system architectures. In other words, any VM will be implemented via plain assembly instructions at the very bottom of the software stack.</p>
<blockquote>
<p><strong>An obvious point comes to mind:</strong> Why not use a real CPU instruction set that complies with the current system architecture for our VM?</p>
</blockquote>
<p>In this way, we will not lose any possibility for adding static verification, advanced data structures or cryptographic algorithms and we can maximize VM flexibility regardless of the data structures or algorithms that we provide in the VM. In addition, with a real CPU instruction set, we can really enable developers to develop any contracts that suit their needs, providing the maximum level of flexibility with the CKB.</p>
<p>It might appear that a higher level VM would make implementing certain things easier, but we believe this is not the case: any higher level VM, no matter how flexible, will inevitably introduce certain semantic constraints in its design. As a consequence, a higher level VM might embrace a variety of languages with different syntaxes, but these languages almost always share the same semantics underneath for performance reasons. The flexibility of a VM will be limited this way, which is not something we want to see in CKB.</p>
<p>Additionally, a higher level VM will most likely include higher level data structures and algorithms. We understand that as CKB developers, we can never imagine all of the different possible ways people might use the CKB. So any higher level data structures and algorithms we build may be suitable for one set of applications, but not for other applications. These embedded data structures or algorithms might slowly become a burden, serving no purpose beyond compatibility.</p>
<p>In addition to flexibility, <strong>a VM with real CPU instruction set</strong> will provide additional benefits:</p>
<ol>
<li><strong>Stability:</strong> In contrast to instruction sets designed for VM implemented as software, CPU instruction sets designed for hardware are hard to modify once finalized and used in chips, which makes for a very stable base compared to software VM instruction sets. This property coincides with the requirement of a layer 1 blockchain VM, because a stable instruction set will mean less hard forks, without sacrificing flexibility.</li>
<li><strong>Runtime visibility:</strong> A physical CPU only requires registers and a memory block to run and space in memory is conventionally specified as it is used in the stack during operation. By specifying the memory space size during VM operation, we can obtain the stack space usage during program execution based on the stack pointer within the VM, maximizing visibility of runtime status.
CKB VM programs can adjust the stack pointer, change area allocation in memory and even enlarge or shrink the stack area size as needed, providing increased VM flexibility. Current CPU instruction sets also provide a count of elapsed cycles, allowing a running overhead status query for the VM.</li>
<li><strong>Runtime overhead:</strong> For a VM with real CPU instruction set, runtime overhead is easily managed.
When a CPU is provided, the number of cycles required for each instruction execution (without considering the pipeline) is fixed. We can use a real CPU as the implementation base for the VM of the CKB.
We can design the overhead requirements for the CKB VM based on the number of cycles required for running each instruction on a real CPU. Data obtained in this way will accurately reflect the required overhead of new algorithms when they are implemented.</li>
</ol>
<p>Utilization of a real CPU instruction set has one key disadvantage when compared to VMs that implement cryptographic algorithms through opcodes or native VM instruction sets: performance.</p>
<p>However, according to our research and test results, we can optimize the cryptographic algorithms running on a VM based on real CPU instruction set to meet CKB application needs through proper optimization and just-in-time (JIT) compiler implementation. In approaching JIT, our starting point is an underlying instruction set, not an advanced language such as JavaScript, yielding a lower workload and better performance.</p>
<p>After the decision has been made to go with a real CPU instruction set, the next step is to choose which set to use. Commonly used instruction sets include x86 or ARM instruction sets. According to our evaluation, we consider RISC-V instruction set to be the best choice for the CKB VM.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="risc-v"><strong>RISC-V</strong><a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#risc-v" class="hash-link" aria-label="Direct link to risc-v" title="Direct link to risc-v">​</a></h3>
<p><a href="https://riscv.org/" target="_blank" rel="noopener noreferrer">RISC-V</a> is an open-source RISC instruction set architecture (ISA) designed by professors of the University of California, Berkeley in 2010. The aim of RISC-V is to provide a common CPU ISA that enables the next generation of system architecture development for several decades without the burden of legacy architecture issues.</p>
<p>RISC-V can meet implementation requirements ranging from small-sized microprocessors with low power consumption to high-performance data center (DC) processors in all scenarios. Compared with other CPU instruction sets, the RISC-V instruction set has the following advantages:</p>
<ol>
<li><strong>Openness:</strong> Both the core design and implementation of RISC-V are provided under a BSD license. All companies and agencies can utilize the RISC-V instruction set and create new hardware/software without restriction.</li>
<li><strong>Simplicity:</strong> As a RISC instruction set, the 32-bit integer core instruction set of RISC-V has only 41 instructions. Adding support for 64-bit integers, the instruction set only has about 50 instructions. An x86 instruction set may have thousands of instructions, compared to this, the RISC-V instruction set is easily implemented and prevents bugs while providing the same functionality.</li>
<li><strong>Modular mechanism:</strong> With a simplified core, RISC-V also provides a modular mechanism to provide more extended instruction sets. For example, the CKB might choose to implement the V extension defined in the RISC-V core to support vector computing or add extended instruction sets for 256-bit integer computing, providing the possibility of high-performance cryptographic algorithms.</li>
<li><strong>Wide support:</strong> The RISC-V instruction set is supported by compilers such as GCC and LLVM. Rust and Go language implementations based on RISC-V are being developed. The VM implementation of CKB will use the widely implemented ELF format, CKB VM contracts can be developed using any language that can be compiled to RISC-V instructions.</li>
<li><strong>Maturity:</strong> The RISC-V core instruction set has been finalized and frozen, all RISC-V implementations in the future need to be backward compatible. This removes the possibility of a CKB hard fork resulting from a VM instruction update. Additionally, the RISC-V instruction set has hardware implementations and has been verified in real-world application scenarios. RISC-V does not have the potential risks that may exist in other less-supported instruction sets.</li>
</ol>
<p>Even though other instruction sets may have some of the qualities listed above, the RISC-V instruction set is the only one that delivers all of them according to our evaluation. Based on this, we have chosen to implement CKB VM with the RISC-V instruction set and utilize the ELF format for smart contracts to ensure wide language support.</p>
<p>In addition, we will add dynamic linking for CKB VM to ensure cell sharing. Even though the official CKB implementation will provide popular cryptographic primitives, we encourage the community to provide more optimized cryptographic algorithm implementations to reduce runtime overhead (CPU cycles).</p>
<p>The topic of developer incentives to improve cryptographic primitives on CKB is interesting and has been frequently discussed among the CKB team. It is our hope that the CKB VM will develop and improve with the evolution of cryptography and community, without the need for hard forks to upgrade the protocol.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="example-contract"><strong>Example Contract</strong><a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#example-contract" class="hash-link" aria-label="Direct link to example-contract" title="Direct link to example-contract">​</a></h3>
<p>The following example shows a minimal contract that can run on the CKB VM:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">int main()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">return 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The following command can be used to compile the code with GCC:</p>
<p><code>riscv64-unknown-elf-gcc main.c -o main</code></p>
<p>A CKB contract is a binary file that complies with traditional Unix invocation methods. Input parameters can be provided through argc/argv, and the output result is presented by the return value of the main function.</p>
<p>A value of <strong>0</strong> indicates that contract invocation was successful, other values indicate contract invocation failure.</p>
<p>To simplify the example, we have implemented the contract above in C. However, any language that can be compiled to the RISC-V instruction set can be used for CKB contract development.</p>
<ul>
<li>The RISC-V instruction set for the Rust language is being developed, with support for the RISC-V 32-bit instruction set being incorporated nightly. 64-bit instruction set support in LLVM is under development.</li>
<li>The <a href="https://github.com/golang/go/issues/27532" target="_blank" rel="noopener noreferrer">RISC-V instruction set for the Go language </a> is also being developed.</li>
<li>For higher level languages, we can directly compile their C implementations to RISC-V binaries and leverage “VM on top of VM” techniques to enable contracts written in these languages on CKB. For example, mruby can be compiled into RISC-V binaries to enable Ruby based contract development. This method can be utilized with the micropython-based Python language and the duktape-based JavaScript language as well.
Even contracts compiled to EVM bytecode or Bitcoin Script can be compiled to CKB VM bytecode. These contracts may have heavier running overhead (CPU cycles) than contracts implemented using lower level languages. The development time saved here and security benefits might be more valuable than incurring cycle costs in some scenarios, though we see clear advantages in legacy contract migration to more efficient bytecode.</li>
</ul>
<p>Outside of the simplest contracts, the CKB also provides a system library to meet the following requirements:</p>
<ul>
<li>Support the libc core library</li>
<li>Support dynamic linking to reduce the space occupied by the current contract. For example, a library can be provided by loading a system cell in to the VM via dynamic link.</li>
<li>Read transaction content, the CKB VM will have Bitcoin’s SIGHASH-like functions within the VM to maximize contract flexibility.</li>
</ul>
<p>The following figure shows the CKB contract verification model based on a preceding system library:</p>
<p><img decoding="async" loading="lazy" src="https://talk.nervos.org/uploads/default/original/1X/40a6fa6979be42ecf6df203a3db1f95bfb47e05d.png" alt="" class="img_ev3q"></p>
<p>As shown in the preceding figure, a CKB transaction consists of inputs and outputs. While the transaction may also contain Deps (dependencies that contain data or code needed when running a contract), these only affect contract implementation and are omitted from the transaction model.</p>
<p>Each input to the transaction references an existing cell. A transaction can overwrite, destroy or generate a cell. Consensus rules enforce that the capacity of all output cells in the transaction cannot exceed the capacity of all input cells.</p>
<p>The CKB VM uses the following criteria to verify contracts:</p>
<ul>
<li>Each input contains an unlock script, allowing for validation that the transaction originator can utilize the cell referenced by that input. The CKB uses the VM to run the unlock script for verification.
The unlock script will usually specify the signature algorithm (for example: SIGHASH-ALL-SHA3-SECP256K) and contain the signature generated by the transaction originator. A CKB contract can use an API to read transaction content to implement SIGHASH-related computing, providing maximum flexibility.</li>
<li>Each cell may contain a validation script to check whether the cell data meets the previously specified conditions. For example, we can create a cell to save user-defined tokens. After the cell is created, we verify the number of tokens in input cells is greater than or equal to the number of tokens in the output cells to ensure that no additional tokens have been created in the transaction.
To enhance security, CKB contract developers can also leverage special contracts to ensure the validation scripts of a cell cannot be modified after the cell has been created.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="input-cell-validation-example">Input Cell Validation Example<a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#input-cell-validation-example" class="hash-link" aria-label="Direct link to Input Cell Validation Example" title="Direct link to Input Cell Validation Example">​</a></h3>
<p>Based on the above description of the CKB VM security model, we will first implement a complete SIGHASH-ALL-SHA3-SECP256K1 contract to verify the provided signature and prove the transaction originator has the ability to consume the current cell.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// For simplicity, we are keeping pubkey in the contract, however this</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// solution has a potential problem: even though many contracts might share</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// the very same structure, keeping pubkey here will make each contract</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// quite different, preventing common contract sharing. In CKB we will</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// provide ways to share common contract while still enabling each user</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// to embed their own pubkey.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">char* PUBKEY = "this is a pubkey";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">int main(int argc, char* argv[])</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   // We need 2 arguments for this contract</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  // * The first argument is contract name, this is for compatibility issue</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // * The second argument is signature for current contract input</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (argc &amp;lt; 2) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">return -1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// This function loads current transaction into VM memory, and returns the</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // pointer to serialized transaction data. Notice ckb_mmap might preprocess</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // the transaction a bit, such as removing signatures in all tx inputs to</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // avoid chicken-egg problem when signing signature.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> int length = 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> char* tx = ckb_mmap(CKB_TX, &amp;amp;length);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> if (tx == NULL) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   return -2;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// This function dynamically links sha3 library to current VM memory space</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> void *sha3_handle = ckb_dlopen("sha3");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> void (*sha3_func)(const char*, int, char*) = ckb_dlsym("sha3_256");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Here we run sha3 on all the transaction data, simulating a SIGHASH_ALL process,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  // a different contract might choose to deserialize and only hash certain part</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  // of the transaction</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  char hash[32];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  sha3_func(tx, length, hash);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Now we load secp256k1 module.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  void *secp_handle = ckb_dlopen("secp256k1");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  int (*secp_verify_func)(const char*, int, const char*, int, const char*, int) =</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       ckb_dlsym("secp256k1_verify");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">int result = secp_verify_func(argv[1], strlen(argv[1]),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                       PUBKEY, strlen(PUBKEY),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                       hash, 32);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (result == 1) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Verification success, we are returning 0 to indicate contract succeeds</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    return 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  } else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Verification failure</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    return -3;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In this example, we first read all of the transaction content into the VM to obtain a SHA3 hash of the transaction data, and will verify that the public key specified in the contract has signed this data. We provide this SHA3 transaction data hash, the specified public key and the signature provided by the transaction originator to the secp256k1 module to verify the specified public key has signed the proposed transaction data.</p>
<p>If this verification is successful, the transaction originator can use the cell referenced by the current input and the contract is executed successfully. If this verification is not successful, the contract execution and transaction verification fail.</p>
<p>User Defined Token (UDT) Example</p>
<p>This example shows a cell validation script that implements an ERC20-like user defined token. In the interest of simplicity, only the transfer function of UDT is included, though a cell validation script could also implement other UDT functions.</p>
<p><img decoding="async" loading="lazy" src="upload://2KFRVvEVdHnzOLmVNmeykkyiGJt" alt="2" class="img_ev3q"></p>
<p>In this example, we first call the system library to read the content of the input and output cells. Then, we load a UDT implementation dynamically and use the transfer method to convert the input.</p>
<p>After conversion, the content in the input and the output cells should completely match. Otherwise, we conclude that the transaction does not meet conditions specified in the validation script and the contract execution will fail.</p>
<p><em>The preceding example is only used to present the VM functions of the CKB and does not indicate best practices for UDT implementation in the CKB.</em></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="unlock-script-example-in-ruby">Unlock Script Example (in Ruby)<a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#unlock-script-example-in-ruby" class="hash-link" aria-label="Direct link to Unlock Script Example (in Ruby)" title="Direct link to Unlock Script Example (in Ruby)">​</a></h3>
<p>Though the preceding examples have been written in C, the CKB VM is not limited to contracts written in C. For example, we can compile mruby, a Ruby implementation target embedded system to RISC-V binary and provide it as a common system library. In this way, Ruby can be used to write contracts such as the following unlock script:</p>
<p><img decoding="async" loading="lazy" src="upload://yqqO7DVQu7ktNH2KMCq8SaYdkRZ" alt="3" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="webassembly"><strong>WebAssembly</strong><a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#webassembly" class="hash-link" aria-label="Direct link to webassembly" title="Direct link to webassembly">​</a></h3>
<p>In reviewing what we have detailed in this paper, some may ask the question: why does the CKB not use WebAssembly, given the interest it has attracted in the blockchain community?</p>
<p>WebAssembly is a great project and we hope it will be successful. The blockchain and broader software industry would benefit greatly from a sandbox environment that has wide support. Though WebAssembly has the potential to implement most of the features we have discussed, it does not deliver all of the benefits RISC-V can bring to the CKB VM. For example: WebAssembly is implemented using JIT and lacks a reasonable running overhead computing model.</p>
<p>RISC-V design began in 2010, the first version was released in 2011, and hardware began to emerge in 2012. However, WebAssembly emerged much later in 2015, with an MVP released in 2017. While we acknowledge WebAssembly has the potential to become a better VM, RISC-V currently has the advantage over WebAssembly.</p>
<p>We do not completely discard the use of WebAssembly in the CKB VM. Both WebAssembly and RISC-V are underlying VMs which shared similar design and instruction sets. We believe we can provide a binary translator from WebAssembly to RISC-V to ensure that WebAssembly-based blockchain innovation can be leveraged by the CKB.</p>
<p>For languages that only compile to WebAssembly (for example, <a href="https://github.com/forest-lang/forest-compiler" target="_blank" rel="noopener noreferrer">Forest</a>) we can also support these languages in the CKB.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="summary"><strong>Summary</strong><a href="https://cookbook.ckbdapps.com/blog/an-introduction-to-nervos-ckb-vm#summary" class="hash-link" aria-label="Direct link to summary" title="Direct link to summary">​</a></h3>
<p>With the design of CKB VM, we aim to build a community around CKB that grows and adapts to new technology advancements freely and where manual intervention (such as hard forks) can be minimized. We believe CKB-VM can achieve this vision.</p>
<p><em>NOTICE: CKB-VM is an open source project like CKB which also respects open standards such as official RISC-V instruction sets. Although most of the CKB-VM design is settled, CKB-VM is still in heavy development and the design can be improved in future. This article is to give our community a taste of CKB-VM so everyone can play with it and contribute!</em></p>
<p>If you have any questions/feedbacks, we would love to hear from you! Feel free to reach out to us here（<a href="https://talk.nervos.org/" target="_blank" rel="noopener noreferrer"><strong>Nervos Talk</strong></a>)or via:</p>
<p><a href="https://github.com/nervosnetwork/ckb-vm" target="_blank" rel="noopener noreferrer"><strong>Nervos CKB-VM Github</strong> </a></p>
<p><a href="https://t.me/nervos_ckb_dev" target="_blank" rel="noopener noreferrer"><strong>Nervos Dev Telegram</strong> </a></p>
<p>Thanks for the input from <a href="https://medium.com/@janhxie" target="_blank" rel="noopener noreferrer">Jan Xie</a> and <a href="https://medium.com/@matthew.t.quinn" target="_blank" rel="noopener noreferrer">Matt Quinn</a>!</p>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/an-introduction-to-nervos-ckb-vm/537" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Xuejie Xiao</name>
            <uri>https://xuejie.space/</uri>
        </author>
        <category label="L1" term="L1"/>
        <category label="CKB-VM" term="CKB-VM"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[CKB，加密经济的信任引擎]]></title>
        <id>https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto</id>
        <link href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto"/>
        <updated>2018-11-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[区块链需要成为世界计算机吗?]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="区块链需要成为世界计算机吗">区块链需要成为世界计算机吗?<a href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto#%E5%8C%BA%E5%9D%97%E9%93%BE%E9%9C%80%E8%A6%81%E6%88%90%E4%B8%BA%E4%B8%96%E7%95%8C%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%90%97" class="hash-link" aria-label="Direct link to 区块链需要成为世界计算机吗?" title="Direct link to 区块链需要成为世界计算机吗?">​</a></h2>
<p>如果抛开区块链的概念，就字面意思理解“世界计算机”，那应该是一台全世界用户可以共同使用的计算机。在世界计算机中，我们应该可以搭建和部署自己的应用，由世界计算机帮我们执行；我们可以在世界计算机上保存各自的数据；不仅如此，应用之间还能够完美的协作，共同完成我们交待的任务。我很喜欢这个想法。</p>
<p>其实在区块链出现之前，我们已经拥有了这样的世界计算机，我们称呼它为“云计算”。云计算提供的服务可以被全世界的用户访问，通过这些服务我们可以搭建和部署自己的应用，保存应用数据；应用可以使用诸如HTTP这样的通讯协议和公开的API接口进行协作，共同完成某一个任务。这些年，云计算也没有停止进化的脚步，从IaaS到PaaS再到FaaS，抽象层次越来越高，能力越来越强大，使用越来越方便。</p>
<p>如果要当作世界计算机来用，不得不说，区块链与云计算平台相比劣势明显：云计算平台可以支撑无限的吞吐量，可以提供完美的用户间隐私保护。但是我们知道，区块链之所以会有这些劣势，并不是由于设计的疏漏。恰恰相反，中本聪想请楚了Ta想要的是什么，在Ta看来，为了那个目标放弃一些东西是值得的。</p>
<p>世界计算机不应该是区块链的目标，设计者不应该被这个错误的目标误导，设计者必须有自己的权衡。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ask-the-right-question">Ask the Right Question<a href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto#ask-the-right-question" class="hash-link" aria-label="Direct link to Ask the Right Question" title="Direct link to Ask the Right Question">​</a></h2>
<p>如果跳出区块链的深井来观察，我们提出的问题不应该是“如何打造一台世界计算机”，也不应该是”如何解决区块链面临的性能和隐私两大难题“。区块链只是一种技术工具。我们可以清楚看到的是，人们想要的不是区块链，而是加密经济。作为Nervos的设计者，我们试图回答的是这样一个问题：</p>
<p><strong>如何为未来的加密经济设计基础设施？</strong></p>
<p>问题的答案可以是区块链，也可以不是区块链，但无论如何，它必须支持自我保障协议，这是加密经济的基础，同时也必须解决它在今天遇到的问题，比如交易性能，以及交易隐私 - 没错，我们依然要解决性能和隐私的问题，但问题的主体是加密经济，不是区块链这把在我们的工具箱中闪闪发亮的扳手。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="自我保障协议与加密经济">自我保障协议与加密经济<a href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto#%E8%87%AA%E6%88%91%E4%BF%9D%E9%9A%9C%E5%8D%8F%E8%AE%AE%E4%B8%8E%E5%8A%A0%E5%AF%86%E7%BB%8F%E6%B5%8E" class="hash-link" aria-label="Direct link to 自我保障协议与加密经济" title="Direct link to 自我保障协议与加密经济">​</a></h2>
<p>加密经济（Cryptoeconomics）是区块链发展多年以后形成的全新经济体。这个经济体与其他的虚拟经济相比较时显得鹤立鸡群，因为她是我们迄今为止创造出的最活跃的市场：她与互联网一般大，跨越不同的国家和地区，吸引了成千上万来自不同国家的市场参与者；她将个人创造和交易数字资产（Cryptoassets）的成本降到极低，正如当年博客与微博将传播的成本降到极低然后汇聚了前所未有的注意力一样，她也汇聚了前所未有的流动性；她永不停转，7*24小时不间断的为用户提供服务。</p>
<p>维护这样一个跨越地域的自发市场运行的，不可能是受到地缘限制的传统制度，只能是在任何时间、任何空间都能够成立的普遍规律：数学、理性、博弈，等等。加密经济的大厦正是建立在密码学和博弈论之上，通过精心设计的自运行制度激励用户共同保障市场中各种协议（即合约）的执行，进而保证市场参与者的资产所有权和交易执行，维护市场的稳定运行。由于加密经济中的协议是由一种去中心化的机制，而非参与者以外的第三方来保证实施，我把它称为<strong>自我保障协议（Self Enforcing Protocol）</strong>。</p>
<p><strong>自我保障协议是加密经济的基础，也是一种前所未见的新物种。</strong>“古典”互联网所依赖的网络协议是一种乐观的协议，设计者总是假设参与方会遵循协议的规定，按照协议规定的步骤行动。而现实与理想截然相反，互联网协议的参与方往往无意甚至有意的不按照步骤行动，其后果就是协议的执行被任意的破坏和中止，遵循协议的参与者只能重试或是更换协作者。这一类协议打造的互联网是一个充满了不确定的网络，一个无法为数字经济提供原生支持的网络。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="信任的创造和传导">信任的创造和传导<a href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto#%E4%BF%A1%E4%BB%BB%E7%9A%84%E5%88%9B%E9%80%A0%E5%92%8C%E4%BC%A0%E5%AF%BC" class="hash-link" aria-label="Direct link to 信任的创造和传导" title="Direct link to 信任的创造和传导">​</a></h2>
<p>在2015年给区块链取过一个十分恰当的名字，“The Trust Machine”。我喜欢把这个名字翻译为“创造信任的机器”，正如Candy Machine是制造糖果的机器。作为一个喜欢动手创造软(shi)件(jie)的开发者，“创造信任”是我能想到的最酷炫的一个目标了（于是我司的Slogan是We Build Trust）。有趣的是三年过去后的今天，区块链真的变成了可以凭空变出”糖果”的Candy Machine，一系列五花八门的功能被注入区块链，也不在乎“古典”技术方案会不会是更恰当的选择。</p>
<p>从架构的观点来看，将一个系统的整体功能分层或分解，交给不同的功能层或是功能组件去处理，是一种优于将所有功能都耦合在一个单体中的设计模式。我们甚至可以说解耦是所有复杂系统设计的核心。UNIX的管道设计，在传统桌面软件和互联网服务都有应用的Model/View/Controller模式，插件架构的编辑器VIM都是很好的例子。互联网同样通过不同的网络协议实现数据传输、邮件递送等不同的功能，在这一组协议中也包括由PKI（Public Key Infrastructure）和TLS（Transport Layer Security）等与身份和加密有关的协议，它们共同构建了互联网的信任体系。</p>
<p>PKI体系负责创造、管理、分配、使用、存储以及撤销数字证书，解决数字身份与物理身份对应的问题。数字证书颁发机构(CA)负责管理和发放数字证书，将用户/企业的身份与公开密钥链接在一起。数字证书颁发机构可以给其它数字证书中介机构颁发证书，形成层层相连的证书链。基于数字证书，互联网上的网站与网站之间，用户与网站之间，以及用户与用户之间可以建立安全保密的信息交换通道。比如说，当用户访问电商或者银行网站时，就是通过数字证书以及HTTPS（HTTP over TLS）协议来建立安全链接。</p>
<p>这是一个分工协作的系统：PKI只关心身份和数字证书的管理，数据的加密传输由HTTPS来完成。PKI本身又是一个分层的架构，处于系统最底层的是根证书颁发机构，是整个信任链的起点，根证书颁发机构本身的数字证书被默认内置在浏览器等软件中，受到所有互联网用户的信任，这种信任通过证书链被层层传递上去，最终被注入这个体系中所有的互联网服务。根证书颁发机构只做证书管理这一件事情，它们不关心电商、游戏或是其他任何具体场景的业务逻辑，这些场景中发生的数据交互也不需要经过根证书颁发机构。根证书颁发机构为互联网创造信任，它们是整个互联网信任体系的“引擎”。之所以“引擎”两个字要加引号，是因为根证书颁发机构终究还是人来管理的企业而不是机器。</p>
<p>互联网建立了一个非常成功的信任网络，而且运转良好，没有遇到性能或是隐私的麻烦。究其原因，是因为互联网采用了一个分层和解耦的架构。这个古典信任网络唯一的问题，在于其可信等级还不够高，因为我们需要相信根证书颁发机构的实力和人品（根证书颁发机构发生的安全事故并不少）；在于它缺乏对自我保障协议的内在支持，我们无法在其中定制和实现能够自我保障执行的协议。我们需要解决这些问题。因此， <strong>我们理想中的加密经济网络基础设施，同样应该是分层和解耦的架构，通过一组协议而不仅仅是一个协议来定义，对自我保障协议提供原生支持，并且有一个无需依赖任何第三方的信任链的根</strong>。</p>
<p>是时候让闪闪发亮的扳手登场了。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ckb-nervos的信任引擎">CKB: Nervos的信任引擎<a href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto#ckb-nervos%E7%9A%84%E4%BF%A1%E4%BB%BB%E5%BC%95%E6%93%8E" class="hash-link" aria-label="Direct link to CKB: Nervos的信任引擎" title="Direct link to CKB: Nervos的信任引擎">​</a></h2>
<p>区块链是创造信任的机器，是一个不依赖任何第三方的由算法和经济激励维护的的网络。区块链刚好是我们想要的那个无需依赖任何第三方的信任链的根。</p>
<p>我们为Nervos网络打造的信任引擎叫做CKB（Common Knowledge Base），共同知识库。这个名字源于<a href="https://zhuanlan.zhihu.com/p/51502507" target="_blank" rel="noopener noreferrer">我们对区块链的认识 </a>，在<a href="https://docs.ckb.dev/docs/rfcs/0002-ckb/0002-ckb.zh" target="_blank" rel="noopener noreferrer">CKB白皮书 </a>的附录中有详细描述，这里不再赘述。CKB位于Nervos网络的最底层（我们称为Layer1），是一个全新设计的公有链协议，是Nervos网络信任链的根，是整个Nervos网络的安全之锚。在CKB之外，Nervos还要定义Layer1与Layer2之间的信任传递协议，将CKB建立的信任传递到上层，保障Layer2 DApp的执行，保障整个Nervos加密经济的运行。这是一个类似PKI体系的分层信任网络，绝大部分的计算、存储、网络传输发生在Layer2，只有在Layer2的运营节点作恶，产生信任问题时，用户才需要与Layer1交互，提交密码学证据给CKB，CKB根据证据和事先确定的规则进行仲裁，由此保障Layer2上协议的执行。<strong>Layer1的目标是安全，Layer2的目标是计算。</strong></p>
<p>CKB自身使用PoW共识，通过PoW将CKB与现实世界中的能量锚定。选择PoW是因为这是目前已知的最为可靠的开放网络共识协议。Nervos网络由此形成一个树状的信任传递网络：</p>
<blockquote>
<p>能量 → Layer1(CKB) → Layer2(AppChain etc.) → DApp</p>
</blockquote>
<p>需要特别指出的是，这样的分层架构对Layer1会产生完全不同的要求，我们没有看到能满足这样要求的公有链设计。这样的目标和现状要求我们必须重新设计Layer1。因此，CKB与其他的公有链有着完全不同的设计目标，具体来说：<em>我们希望尽可能的最小化CKB的职责</em>，专注于安全的共识，为上层建筑创造信任，而不是最大化CKB，让它能够支持各种通用的业务场景。正如PKI体系中的根证书颁发公司无需关心具体的应用场景。优美的设计产生于简单和平衡而不是叠加。</p>
<p>因此CKB只需要保留两个功能：一是简单安全的共识算法，二是支持Layer1与Layer2之间的信任传递协议。</p>
<p>我们的研究与工程团队正在设计和实现一个新的PoW共识，目标是在保证安全的前提下，尽可能的挖掘PoW的潜力，提高CKB的吞吐量，缩短交易确认时间。由于Nervos网络中的大部分交易将发生在Layer2，我相信通过新的PoW算法和对并行计算友好的Cell模型（见Nervos白皮书）所实现的性能可以支撑Nervos网络前期的需求。</p>
<p>为了支持Layer1与Layer2之间的信任传递，CKB选择了以状态为中心的设计，提出了Cell模型这样一个不同于账户模型和UTXO模型的新状态模型。Cell模型是UTXO模型的最小自然扩展，将只关心数字的UTXO扩展为可以保存任意数据类型的Cell。Cell是实现Layer1和Layer2之间的信任传递协议的基础，因为我们必须有方法来保存状态，同时这个保存状态的方法应该是一个恰到好处的程度，不多不少(e.g. 我们不需要一个KV或是SQL DB)。我们需要一个做状态验证的虚拟机，这个虚拟机不需要支持太多的场景，最好也是刚刚好。状态在Layer2上生成，在Layer1上记录和验证。</p>
<p>由于不仅仅要考虑自身的安全，还需要考虑如何支持信任传递协议和Layer2，CKB的经济机制也面临着更大的挑战。CKB代币将是Layer2的抵押物，是Nervos网络默认的价值存储手段（SoV）。这方面我们需要更多的研究，幸运的是有非常棒的经济学家在帮助我们。</p>
<p>可以看到，Nervos从整体出发的设计思路，使CKB在设计初始就以Layer2的需求为优先。在多个方面。这将使得在Nervos网络中实现Layer2方案会更容易。这是Nervos独特的方法论。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-better-world">A Better World<a href="https://cookbook.ckbdapps.com/blog/trust-engine-of-crypto#a-better-world" class="hash-link" aria-label="Direct link to A Better World" title="Direct link to A Better World">​</a></h2>
<p>加密经济网络是互联网发展到成熟的阶段的自然延伸。互联网经历了自己的1.0和2.0，成就了GAFA（Google/Apple/Facebook/Amazon）与BATX（Baidu/Alibaba/Tencent/Xiaomi），也颠覆了我们的生活。发展到今天，互联网平台已经渡过了需要吸引用户和第三方合作伙伴的成长期，行业的增长天花板就在眼前，平台与平台参与者之间的关系从非零和博弈转向零和博弈，平台必须与第三方争抢用户和利润，即使所有人都知道，抑制了第三方的参与积极性也就抑制了创新。这是互联网模式的困境。</p>
<p>在这样无法创新的困境下，区块链和加密经济的出现也就成为了一种必然，我们正处于互联网下一次蜕变的起点。让我们仔细的思考加密经济需要什么，虚心的向古典互联网学习，创造我们所向往的美好世界。</p>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/topic/336" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Jan Xie</name>
            <uri>https://twitter.com/busyforking</uri>
        </author>
        <category label="L1" term="L1"/>
        <category label="CKB" term="CKB"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Nervos：为了更好的世界]]></title>
        <id>https://cookbook.ckbdapps.com/blog/nerovs-for-the-better-world</id>
        <link href="https://cookbook.ckbdapps.com/blog/nerovs-for-the-better-world"/>
        <updated>2018-06-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[你们的白皮书我看过了，你们只提出了问题，但是你们根本没有解决方案！别告诉我你们想要解决以太坊的问题，以太坊的方案在我眼里根本不 work！]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>你们的白皮书我看过了，你们只提出了问题，但是你们根本没有解决方案！别告诉我你们想要解决以太坊的问题，以太坊的方案在我眼里根本不 work！</p>
</blockquote>
<p>3 个月前，在一家机构的会议室，Terry 和我，我们正在向对方 Pitch 我们的 Nervos 项目。不确定对方有没有真的看过我们的白皮书，也许怀疑一个本土的团队是否真的有能力写出这样的白皮书，也许怀疑我们提出了一个没有验证过的技术方案，也许团队没有能力真的能把这样的项目做出来……</p>
<p>记得当时我跟 Terry 是这样回答的：</p>
<blockquote>
<p>也许您现在只能理解您现在能够理解的东西，我们来您在这里，就是要给你介绍我们的团队的背景，能力，以及我们要解决的问题，而你看到的白皮书只包含了我们底链的设计。
Nervos 还处于非常早期，也许您现在看不懂，或许还有所怀疑，不过这都没有关系，您可以再等一等，看一看，等我们有更多的信息释放出来，甚至东西做出来后再买都是不晚的。</p>
</blockquote>
<p>2017 年年底，我们发起了 Nervos Network 项目，目标是做下一代区块链基础设施（严格来讲 Nervos 是一个网络，这一点后续文章会详细阐述），并以开源基金会的方式运作。然后我们马上组建了开发团队，基于之前两年多的联盟链和公链开发经验，结合我们对下一代区块链基础设施架构的设计思想，我们的团队用了三个月时间做了若干个概念验证和迭代，基于这些工作，我们正式发布了 Nervos CKB 白皮书，即 Nervos Network 的底层基础公链设计。然后我们紧锣密鼓的开始了 token 的 private sale 工作，为了找到全世界最优质的资源，我们几乎拜访了能联系到的所有国内外机构。 总的来讲整个 private sale 还算顺利，我们取得非常多国内和世界范围内绝对的一线机构的信任和追捧，这既是情理之中，又是意料之外。我们没有想到这么快就能被如此多的一线机构所认同，这不得不归功于我们团队在世界一线的区块链项目（BTC, Ethereum）中长期积累，以及 Nervos 本身的卓越设计。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="我们对以太坊的理解是全中国最深刻的"><strong>我们对以太坊的理解是全中国最深刻的</strong><a href="https://cookbook.ckbdapps.com/blog/nerovs-for-the-better-world#%E6%88%91%E4%BB%AC%E5%AF%B9%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E7%90%86%E8%A7%A3%E6%98%AF%E5%85%A8%E4%B8%AD%E5%9B%BD%E6%9C%80%E6%B7%B1%E5%88%BB%EF%BF%BD%E7%9A%84" class="hash-link" aria-label="Direct link to 我们对以太坊的理解是全中国最深刻的" title="Direct link to 我们对以太坊的理解是全中国最深刻的">​</a></h2>
<p>最初接触以太坊是在 2015 年底，当时以太坊横空出世，给了整个区块链社区一个方向，并吸引到了大量的像我们一样的开发者加入其中。我们创立了 <strong>Ethfans</strong> — 以太坊爱好者社区，之后 Ethfans 成了在国内事实上的第一以太坊技术社区。我们还帮助 Ethfans 孵化了 <strong>星火矿池</strong> ，现在星火矿池算力规模排到了世界前三。我们还组织了无数国内的技术 Meetup，参与并组织以太坊开发者大会，不胜枚举。</p>
<p>我们的首席架构师谢晗剑 （Jan Xie）之前在以太坊核心团队（Research Team）工作有两年之久，跟 Vitalik 一起做了 Casper – 以太坊下一代核心协议早期研究和开发，并且一直是 pyethereum 和 ruby-ethereum 的主要维护者。而我则曾经以联合创始人兼 CTO 的身份，参与过 imToken 的第一版实现，而 imToken 是国内最流行的以太坊钱包。</p>
<p>可是以太坊的区块链应用真的爆发了么？其实并没有。大家都还在等，在等扩展方案落地，等处理速度和吞吐量可以支持真实的商业应用落地，等开发语言，环境，工具变得更安全，成熟。其实以太坊基础设施有太多问题需要解决：</p>
<ul>
<li>性能扩展问题，以太坊通过两种方案解决扩展问题，但是他们都有各自的问题。<!-- -->
<ul>
<li>第一种是通过分片的方式，将基础设施的性能和吞吐量提升 10 倍，100 倍，甚至更高。这种试图在全球第二市值的系统上实现底层协议的大幅更替，从技术和社区方面都面临巨大的挑战，这不是在飞机的飞行当中更换引擎，而是在飞行的火箭上更换喷射器，必须小心翼翼，否则火箭会爆。</li>
<li>第二种是将交易从主链剥离，放到链外，即第二层扩展方案。第二层方案必须充分得到主链的支持，但是主链本身作为通用基础设施的一部分，从优先级上很难对二层方案给予最好最直接的支持，这是为什么雷电网络，状态通道，从论文提出到现在都已经五年过去了，已然难以实施普及。</li>
</ul>
</li>
<li>安全相关的问题，我亲自经历了两次大规模的安全事件，一次是 TheDAO 攻击事件，另一次是 Parity 多签钱包导致大量的以太币和资产被冻结。两次安全事件先后给整个社区上了重要的一课，安全性问题被摆在了极高的位置，但是即使如此，整个开发社区仍然在需要等待更好更安全的编程范式和检测工具。</li>
<li>经济模型问题，以太坊用 Gas 限制你的合约单次执行的复杂度，本质上 Gas 是在计算时间维度上的度量，也就是计算量的度量，而 GasLimit 是一个区块上对可容纳的计算量总和，如果我们需要增加合约执行的复杂度，我们需要在出块时间尽量短，每个块可容纳的计算量尽可能高。假设我们已经进入了后性能扩展时代，扩展问题被解决之后，节点维护者将面对另外一个难题：状态数据量爆炸。这是一个无法逃避的问题，但是目前的扩展方案在针对这个问题是没有考虑的，即以太坊的经济模型缺乏对空间维度的考量。</li>
<li>治理问题，以太坊并没有采用线上治理或者协调机制，未来的治理机制会随着共识协议的更替而改变。但是目前我们所能观察到的以太坊主要依靠创始人和核心团队的影响力，以及有限的激励方式来激励核心开发者，换句话说，以太坊的每一次协议的演进正在变得越来越慢，在治理工具，协调和激励方面，我们应该鼓励更多的尝试。</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="对区块链的本质思考从未停止"><strong>对区块链的本质思考从未停止</strong><a href="https://cookbook.ckbdapps.com/blog/nerovs-for-the-better-world#%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E7%9A%84%E6%9C%AC%E8%B4%A8%E6%80%9D%E8%80%83%E4%BB%8E%E6%9C%AA%E5%81%9C%E6%AD%A2" class="hash-link" aria-label="Direct link to 对区块链的本质思考从未停止" title="Direct link to 对区块链的本质思考从未停止">​</a></h2>
<p>为什么应用需要先把业务逻辑改造成去中心化模式，并通过智能合约实现，并且开发者需要掌握一门叫做 Solidity 的编程语言，才能实现应用上链？但是世界上大量在区块链这个词还没有被发明之前，就已经存在的中心化，半中心化的场景和应用，就已经被用户信任并且达成了局部的共识，为什么这些应用要花费很高的成本，并且牺牲性能为代价，将局部的共识变为全球的共识？</p>
<p>为什么需要全球所有的节点全部执行相同的计算并交叉验证，通过得到相同的结果，这样才能消除智能合约执行的不确定性，区块链的本质是以最低成本，高效建立全局的信任。但是随着共识规模的扩大，建立信任的交易成本，也就是说矿工费越来越贵，难道没有更好的建立信任的机制？或者对用户更友好的信任成本支付模型？</p>
<p>为什么所有希望实现下一代区块链基础设施的团队，大多选择了单点突破这个方向，比如更高效的共识算法，或者更好的分片机制作为切入点，在不牺牲安全性和去中心化的前提下，尽量将性能做到最优，而不去考虑从整体架构上实现整体突破？
为什么现有的第二层扩展方案，包括 state channel，Plasma，Truebit，Teechan 等，不论从理论研究到工程实现，都慢慢趋向成熟，无论从工程，还是可靠性方面，都要比扩展主链这个方向耗费的成本更低，耗时更少，但是依然很难得到在任何一条主链上的更好支持？</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="用技术改变世界是我们的信仰"><strong>用技术改变世界，是我们的信仰</strong><a href="https://cookbook.ckbdapps.com/blog/nerovs-for-the-better-world#%E7%94%A8%E6%8A%80%E6%9C%AF%E6%94%B9%E5%8F%98%E4%B8%96%E7%95%8C%EF%BF%BD%EF%BF%BD%E6%98%AF%E6%88%91%E4%BB%AC%E7%9A%84%E4%BF%A1%E4%BB%B0" class="hash-link" aria-label="Direct link to 用技术改变世界是我们的信仰" title="Direct link to 用技术改变世界是我们的信仰">​</a></h2>
<p>下一代的区块链应该是什么样子，这个问题我们想了整整两年，Nervos Network 的整体设计，就是我们的答案。我们已经正式对外发布了 Nervos CKB 白皮书，未来对经济模型的设计，共识算法的设计，以及其他核心组件的设计白皮书会陆续放出。既然我们已经想清楚了下一代区块链基础设施的，与其继续等待，不如我们自己来，我们过去交付过的成果可能比这个世界上任何的区块链团队都要多。我们要做的 Nervos Network 是：</p>
<ul>
<li>是一组协议，而不是一个协议定义的网络</li>
<li>以 Common Knowledge Base 作为核心的信任基础设施，承载各种网络上的可信组件</li>
<li>为所有可信任组件之间的协同和互操作提供支持</li>
<li>围绕 Common Knowledge Base 设计的经济激励模型，兼顾了计算时间，空间的考量</li>
<li>分层设计的架构思想，在不同的层次为了不同的目标做取舍，兼顾性能，安全，以及去中心化特性</li>
<li>为所有第二层扩展方案充分优化，最大限度为第二层扩展方案提供安全性保障，状态验证，以及必要的时候提供仲裁</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="绝不让环境成为你追求卓越的障碍"><strong>绝不让环境成为你追求卓越的障碍</strong><a href="https://cookbook.ckbdapps.com/blog/nerovs-for-the-better-world#%E7%BB%9D%E4%B8%8D%E8%AE%A9%E7%8E%AF%E5%A2%83%E6%88%90%E4%B8%BA%E4%BD%A0%E8%BF%BD%E6%B1%82%E5%8D%93%E8%B6%8A%E7%9A%84%E9%9A%9C%E7%A2%8D" class="hash-link" aria-label="Direct link to 绝不让环境成为你追求卓越的障碍" title="Direct link to 绝不让环境成为你追求卓越的障碍">​</a></h2>
<p>在刚刚结束的北美之行，我们见了许多北美一线的机构，团队，讨论的话题自然包括我们双方怎么看中国的许多其他项目，在讨论过程中，有个词组是我们绕不开的，就是 “pump and down"，意思就是项目没有实质，只是为了发币，然后炒作，这种类型的项目在中国数量不少。</p>
<p>其实要证明我们的项目和团队能力给一个不熟悉我们，不熟悉中国环境，甚至带有一点点偏见的投资机构是很不简单的事情。但是我们要证明的不仅仅是这些，在任何情况下，我们都有勇气选择自己的态度，选择自己的道路，我们要代表中国，做出可以代表中国的世界级区块链基础设施项目。</p>
<p>肯尼迪在 1961 年的总统就职典礼上的演讲，他向全人类展现的是未来的美好前景，探索太空，治愈绝症，消除贫困等等，大家在激动之余，会问这些真的都能实现么？最后肯尼迪说：</p>
<blockquote>
<p><strong>问心无愧是我们唯一稳得的报酬。</strong></p>
</blockquote>
<hr>
<p>🔗👉<a href="https://talk.nervos.org/t/nervos/2967" target="_blank" rel="noopener noreferrer">查看原文</a>，获得更多精彩留言。</p>]]></content>
        <author>
            <name>Daniel Lv</name>
            <uri>https://twitter.com/lgn21st</uri>
        </author>
        <category label="Nervos" term="Nervos"/>
        <category label="CKB" term="CKB"/>
        <category label="Vision" term="Vision"/>
    </entry>
</feed>