雪花之书 (Snowblossom) v2021.09.13

English: https://tradingt.com/book-of-snowblossom/ 作者: Joseph Gleason / Fireduck

背景介绍 #

2012年,我为Satoshidice创建了后端交易处理和可证明的公平程序。

2013年,我创建了一个比特币矿池实现,SockThing。 当然,还有一个矿池,htt

在2014年,我开始为当时表现不佳的参考电子书服务器jelectrum做一个java的替代品。

通过这些项目,我对比特币的内部结构和粗糙的边缘有了一个非常好的了解。 一些关键的收获。

● 为什么字节排序的事情会如此奇怪?

● 为什么有这么多方法来构建对一个地址的付款?

● 这段C++代码相当难读

目标 #

我对Snowblossom的目标是做一个纯粹的加密货币,更简单,有一个更干净的代码基础。

改进措施 #

雪花辫(分片)/ Snowblossom Braid (Sharding) #

概述 #

一般来说,加密货币以单一的顺序区块链运作。 只有在充分了解币的状态(特别是UTXO集)和顺序的情况下才能进行验证。 这大多限制了任何加密货币,使其数据集足够小,适合在一台计算机上使用,而且交易率低到可以由一台计算机处理。 即使你试图使用多台计算机,区块链的顺序性使得验证任务无法进行。

Snowblossom Braid是一种升级,使一组相互关联的顺序区块链,这样的工作可以被分割开来,由多台计算机处理。 这将使交易率大大增加,但要付出一些开销。 这通常被称为分片。

重要的加密货币行为 #

在讨论任何分片方案时,必须强调用户所依赖的单链加密货币的行为,以讨论分片方案如何维持这些行为。

  • 交易的终结性

    用户似乎大多接受这样的概念,即一项交易首先是待定的或有风险的,然后稍后它将被确认,然后更多的确认将在随后的区块中堆积,直到用户满意地认为该交易不会被逆转(通过区块链重新组织),并且可以被指望。

    在这个Snowblossom Braid中,这一切仍然是真实的,但最终的评估要更复杂一些。 我们不只是问一个交易有多少个确认,而是要问哪些分片包括了交易的区块。 将会有一些客户端工作来使用户清楚地了解这一点。

  • Fire-and-Forget

    当用户在点对点加密货币网络上发送交易,并且该交易被接受到mempool中时,用户可以相当自信地认为该交易最终会被确认。 他们不需要做任何其他事情。 当然,在交易被确认之前,这并不是一种保证,但在大多数情况下,用户可以简单地发送交易,然后断开与网络的连接,去种植一些花。

    这种行为在Snowblossom Braid工作中得到了保持,但有一个例外。 在辫子系统中,一个用户可能在多个分片上有未使用的资金。 这意味着如果他们想发送,但在一个分片上没有足够的资金,他们将不得不为所需的发送做(实际上他们的客户端软件会这样做)多个交易。 这可以通过两种方式实现。

    1) 根据需要从每个分片中发送部分付款。 这样一来,收件人就能尽快得到资金,而且 “火烧眉毛 “的效果也很好。

    2) 用户可以做一个交易,将资金整合到一个分片上,然后再发送交易,将其发送到目的地。 如果没有一些额外的工作,比如为等待输入的交易建立一个特殊的内存池,这在 “先斩后奏 “中是行不通的。

  • 无双花/Consistent State View

    这与上面的 “Fire-and-Forget “有关,但更多的是在收款人方面。 当你看到一个待定的传入交易时,你希望能够知道该交易很可能会被确认。 你至少应该有足够的信心让付款人带着咖啡或烤面包机离开,但也许不能带着汽车。 对于汽车,你可能想等待一些确认。

    这部分是由标准的 “先见先得 “行为完成的。 这意味着第一个使用特定交易输出的有效交易可以获得它,其他使用该输出的交易将不被接受进入mempool。 这并不是一种保证,因为不同的节点可能对mempool的状态有不同的看法,或者节点可能被重新启动而失去mempool的状态。 然而,在大多数情况下,这工作得很好,可以依靠小交易。 这继续与Snowblossom Braid一起工作,因为每个输出在创建时(当交易进行时)被绑定到一个分片上,所以正常的mempool规则适用于从该分片上花费它的交易。 没有其他分片可以花费它。

  • 用户不关心细节

    虽然用户应该总是被赋予检查细节的选项,但在大多数情况下他们并不关心。 他们不想做UTXO管理。 他们不关心他们的产出在什么分片上,他们不应该知道。 虽然还没有完成,但Snowblossom Braid的面向用户的客户端代码应该考虑到这一点。

开发和部署 #

Snowblossom Braid在testnet上运行,来自snowblossom git的一个名为’shardo’的分支。 它已经在高达128个分片的网络中进行了大量的测试,代码运行良好。

很快我们就会讨论将其引入主网的问题。

如果它确实进入了主网,总的区块奖励将是相同的。 它更复杂,但最终的总和将是相同的。 与其说一个区块的奖励是简单的50SNOW,不如说是50SNOW分散在当时所有的区块高度的分片中。 为了获得更多的乐趣,奖励的一部分是包括来自其他分片的区块。 但它的总和仍然是与单一区块链的每个区块高度相同的奖励。 因此,币的供应将保持不变。

分区是由使用量触发的,所以最初主网将只是一个单一的分区(就像现在一样)。 此外,所有现有的历史,交易和地址将被保留。 这将是一个到位的协议升级,而不是一个新币。

结构 #

辫子结构之所以被称为辫子,是因为像头发的辫子一样,有一些股在某些方面是独立的,但也相互联系,形成一个单元。 它是一组交织在一起的区块链。 每个分片都会有一个像其他区块链一样的区块序列,但有以下变化。

● 每个区块可能包括来自其他分片的区块的标题。

● 一个事务只能从当前分片的输入中支出。 他们可以把输出写到任何其他分片上。 输出被标记为交易数据的一部分,以便交易创建者可以在哪个分片上花费。

● 每个分片只能领先其他分片这么远,这将是一个定义的最大距离。 例如,如果我们将最大距离设置为4,那么为了让一个分片做出一个高度为1000的有效块,它必须包括其他分片的头,至少高度为996。

● 其他分片的包含头必须形成一个连续的区块链。 这意味着如果我们包含了另一条链上的区块的头,我们必须已经包含了该区块的父块。 这就是我们管理UTXO交接的方式,确保我们从其他链上获得每个块,以便导入相关的UTXO。

  • UTXO管理

    当一个区块在一个分片上被创建时,除了它自己的内部UTXO管理外,任何去往其他分片的事务输出都会形成一个导出集。 这些是当其他分片包括这个区块时需要被编码的UTXO。

    当一个区块被包括在内时,从该区块到该分片的导出集被整合到该分片的UTXO中。

    这样,我们就有了一个连贯的方法来将UTXO从一个分片区安全地转移到另一个分片区。 源分片正好包括一次输出。 UTXO只有在目标分片中包括有它的块时才会被导入。

  • 分区ID和创建

    每个区都有自己的PoW难度,只基于该区本身的区块率。

    我们没有预先决定分片的数量,因为每个分片都有一些额外的开销,我们决定按需制作分片,只在协议中定义分片的最大数量。 为了使其发挥作用,每个分片都有一个运行的交易规模值,表明最近的区块有多满。 当分片超过协议定义的满度阈值时,分片将分叉。 这个分片将停止获得新的区块,两个新的分片将开始使用旧分片的最后一个区块作为父区。 新分片将拥有一半的PoW难度,一半的父分片的区块奖励。 其中一个分片将继承父分片的UTXO。 另一个将从一个空的UTXO开始。 继承父方UTXO的分片也将导入任何UTXO出口到父分片的ID。

    例如,当分片2分裂时,它创建了分片5和6。 分区5将继承分区2的UTXO。 任何未来对分片2的出口都将由分片5导入。

    此外,一个分片将把UTXO导入到任何未来的子分片。 例如,如果在分片2分裂之前,有一个输出到分片5,它将被分片2导入。

    这意味着,一旦网络上启用了分片,事务将能够向任何有效的分片ID写入输出。 这些将被映射到当前存在的分片。

    Shard ID结构是在ShardUtil中定义的。 一般来说,其形式是,分片N的子女是。

    N*2+1(继承UTXO)和N*2+2

    这里是树的前几层。

    0

    1 2

    3 4 5 6

    7 8 9 10 11 12 13 14

    注意:由于分片根据它们自己的内部负荷决定分裂,它们可能不会同时扩展。 例如,该辫子可能由分片组成。{1,5,6}或{1,2}或{3,4,5,6}。

  • 块状奖励

    区块奖励比单一区块链的情况要复杂一些,而总和仍为相同的数字。

    一个分区内的区块奖励是。

    让shard_faction成为这个分片所代表的整个树的一部分。 例如,分片0将是1/1(整个树)。 分片1是(½)。 分片5将是(1/4)。

    让direct_faction = 0.75

    让间接派=0.25

    区块奖励 = general_block_reward * shard_faction * direct_faction

    • general_block_reward * shard_faction * indirect_faction *

    shard_faction

    • shard_faction * sum( general_block_reward * indirect_faction *

    included_shard_faction)

    换句话说,区块本身有一个片断,然后为我们包括的另一个分片的每个区块有一个片断。 这就产生了一个激励机制,让我们尽可能多地包括其他分片,形成一个紧密联系的辫子。

    下面是它的代码。ShardUtil.getBlockReward

场景 #

  • 坏块

    这几乎是最坏的情况。 这是令人讨厌的,但如果矿工们很小心(而且小心会让他们赚更多的钱),这将永远不会发生。

    假设有6个区块,A、B、C、D、E、F。 一个矿工在A区创建了一个高度为100的区块(我们将其记为A100)。 A100有一个有效的头,但有一个无效的交易。 其他矿工得到了A100的头,头是有效的,所以他们使用了它(矿工不应该这样做,如果他们包括没有完全验证的区块,他们有可能会有大量的无主区块)。 但他们这样做了。 因此,分片B-F都得到了新的区块,包括A100。 但A100的整个区块没有得到验证,所以没有矿工制作A101,因为他们不能。 网络的其他部分并不关心,我们得到了B105到F105的全部数据。 在这一点上,他们不能到106的高度,因为A100太老了,没有A101他们就不能再制造任何区块。

    因此,B-F上的任何采矿都停止了。 他们没有有用的工作可以做。 矿工们不能从A100上制造A101,因为它是无效的。 所以矿工们制造了一个新的有效的A100。 然而,B-F 100-106都包括坏的A100。 矿工们不想让自己的区块成为孤儿,所以他们拖着脚步试图制造任何新的B-F区块,直到A到了A105,如果不在其他分片上制造更多的区块就无法继续。 因此,他们最终开始制造新的B100-F100,重填所有这些区块,网络继续运行。

    这很糟糕,但网络将重新组织并继续前进。 希望矿工们不会愚蠢到把他们自己没有验证过的区块包括进来,但即使他们这样做,也会有结果的。

  • 重组一个区块

    基于PoW的加密货币的一个担忧是所谓的51%攻击问题。 这个问题简单来说就是,一个控制了一半以上挖矿权的实体可以随意改写区块链的内容。 那么有了分片系统,重写一个分片就会容易得多吗? 想象一下,有10个难度大致相同的PoW的分片。 一个只有5%散列能力的攻击者可以重写一个分片,因为只有大约10%的网络PoW在任何特定的分片上,对吗? 在Snowblossom Braid的情况下则不然。 如果攻击者在一个分片上重新创建一些区块,矿工会忽略它,因为预先存在的区块已经被编入其他分片。 他们会通过不把自己的区块变成孤儿来跟随某个区块的重新分叉来赚取更多的钱,即使这个重新分叉看起来是被攻击的区块目前最好的。

    而且,由于矿工通过在他们的区块中包括其他区块来赚取更多的钱,这些区块几乎总是紧密地交织在一起。

信任/确认 #

在传统的加密货币中,对交易的信心是基于确认的,即一个交易有多少个区块深。

这个概念仍然是一样的,但措辞是:已经开采了多少个区块,必须丢弃才能删除一个交易。

例如,假设一个交易被包含在一个分片区块中,然后该区块被包含在另外两个分片中。 所有这三个区块都必须成为孤儿,该交易才不会发生。 因此,尽管该交易在自己的区块中只有一个确认,但从整体上看,它可以被视为3个确认。 然而,在传统的加密货币中,3次确认意味着在总网络哈希率下的三个区块。 而三个分片只是这三个分片的哈希率。

也许确认将成为一种浮动。 因此,当一半的分片包括你交易的区块时,你有0.5个确认。 当所有的分片都有,而且其中一些分片上有两个区块,那么就有1.2个确认。

深度阻隔证明 #

假设有一些节点A是分片S的完全验证者,意味着它已经摄取了

并检查了所有区块。

假设有一些节点B不是分片S的完全验证者,它只是在寻找

在和存储头文件。

假设B接受分片S上的块N是有效的,由于网络共识。

A可以做一个证明,证明块N+1对B有效。

这可以通过A提供区块N+1来实现。 此外,A将提供

足够多的UTXO内部节点,以证明该区块所花费的所有交易输出

是在块N UTXO哈希中。 A还将提供其他内部节点来证明

块N+1中的UTXO的变化,突变为块N+1中的UTXO散列。

这将是UTXO树的一个重要部分,但不是几乎所有的。

B,使用这个数据来验证区块,然后可以丢弃而不是存储验证的数据。

数据。

这将是一些紧张的代码,但它是非常可行的。

生态系统 #

我猜想,大多数想要有竞争力的矿池会在所有分片上运行验证节点。 这样一来,如果有意义的话,他们可以在任何区块上挖矿。 此外,他们还可以在所有分片上验证区块,以便能够将最有效的其他区块纳入他们开采的区块中,从而获得最多的区块奖励。

没有那么多硬件的矿工可以与受信任的同行合作进行区块验证或使用第三方验证服务。

我也可以看到第三方服务存在的地址查询,因为钱包软件不一定知道哪些分片可能包含其地址的输出。

舞蹈 #

当我为这个辫子编程时,遇到了许多形成辫子的问题。 由于重复的区块,一些分片跟随一条链子,而另一些则跟随其他链子,它最终处于难以取得进展的状态,链子停滞不前。 应该指出的是,进展总是可能的,即使它必须是一些块的孤儿,但这并不意味着找到前进的道路是容易的。

总之,在比我更聪明的人解决这个问题之前,舞蹈是一种旁敲侧击的方式。

舞蹈不会*被编码在验证规则中,一个节点可以在不破坏协议的情况下建立不遵循舞蹈的区块,他们只是在其他节点坚持遵循舞蹈创建区块的情况下有可能成为孤儿。 这样一来,如果有些人想出了更好的方法,就不会破坏改善网络的工作。

总之,随着舞蹈的进行,目前继承utxos的分片0的分片应是协调者。

当制作新区块时,协调者分片可以包括来自其他分片的任何区块,这些区块遵循舞蹈(和所有其他网络规则)。

非协调人只能包括来自的区块。

● 协调者分片

● 已经被协调者分片包括的其他区块

这样一来,代码就简单多了。 与其在金集上打转,并试图找到难以解决的问题的解决方案,协调者只是。

● 寻找从现有包含的区块中延伸出来的区块,只要它们跟随舞蹈并包含它们。

对于非协调人区块,他们简单。

● 包括最新的已知协调者分片区块和协调者区块所包括的任何区块。

其弊端如下:假设有四个分片。{3,4,5,6}. 3号分片将是协调人分片。 假设第6区正在为第5区输出一些UTXO。 为了使这些UTXO能够被花费。

● 第6区必须开采一个区块

● 第3区必须开采一个区块,并包括新的第6区块。

● Shard 5必须开采包括新的Shard 3区块和新的Shard 6区块的区块。

在没有舞蹈的情况下,只有分片6和5需要开采一个区块。 有了舞蹈,就必须有这三个,按这个顺序。 这增加了转移UTXO的时间,但这似乎是一个合理的妥协。

UTXO的改进 #

UTXO在地址,txid,out_idx上有索引。 #

在Snowblossom中,UTXO的索引是由收件人地址,然后是交易ID,最后是交易中的输出索引。 这使得UTXO trie可以用来为轻型客户快速生成UTXO证明。服务器可以将证明任何给定地址的UTXO的完整性或缺乏性所需的trie节点一起发送。 为了使其发挥作用,需要有一种统一的方式来表达地址,并且能够为任何交易的输入或输出获得准确的地址。 这是AddressSpec模型的一个优势,相对于比特币OP-code方法,它可以用不同的方式表达地址。

区块头中的UTXO根哈希值 #

由于UTXO根哈希值是区块链中的一个关键组成部分,将其纳入区块头是有意义的。 这样一来,轻型客户端UTXO证明可以直接链接到区块头。

UTXO存储在散列的三角形中 #

在区块链中存储UTXO根哈希值的一个困难是你需要一个绝对一致的方式来表达和存储它。 正常的方式是使用 trie,一种具有特定规则的树状结构,这样,同一组数据将始终具有相同的树状结构。 这样一来,树可以被散列,并在所有节点上产生一个单一的散列。 然而,在一个可以有重新排序的区块链中,这可能是一个数据库的挑战。 传统上,要进行重组,你需要回滚已删除的区块,然后应用新的区块。 然而,如果你还没有验证新的区块UTXO根哈希,你不想做这种数据库的改变。 你还不能确定新区块是否有效。 因此,我发明了一种新的数据结构,Hashed Trie。 在这个结构中,Trie中的每个节点都被存储在一个底层的键值存储中,节点(和所有子节点)的哈希值是键值。 使用这种方法,每个UTXO根被存储和保留,数据库事实上可以同时跟踪多个区块链。 另外,如果客户愿意,可以查询之前任何区块的UTXO。

  • 散列三部曲

    我认为这很新颖,但如果我错了,请让我知道。

    实施–哈希三联体源测试 雪花三联体测试

    • 定义

      哈希Trie是一个结构,它是一个Trie,每个节点都有一个基于其内容的哈希值。在我的实现中,有一个哈希值到节点的底层映射。Map<Hash,Node>。树的状态被保存为一个哈希值,它简单地指向该状态的根节点。每个节点的子节点是通过它们的哈希值来引用的。任何节点都不会被覆盖(除了可能被重写成完全相同的数据),如果它被改变,哈希值也会改变,并被保存在新的哈希值下。这使得它成为一个空间效率高的写时复制(CoW)结构。

      每个操作都被赋予根哈希值作为一个参数。任何修改操作都会为新树返回一个新的根哈希值。

      根哈希值代表树的内容。由于树的结构有固定的规则,相同的键和值总是会产生相同的根哈希值。

    • 优势

      ● 节省空间。尽管我们最终存储了同一棵树的许多变化,但我们只重复了不同的节点。

      ● 只要你有以前的根哈希值,以前版本的树是可读的。

      ● 任何突变都可以从以前的任何根节点进行。不需要回退任何变化,只需使用以前的根哈希值。

      ● 写入时不需要锁定。读取和写入可以同时发生。

    • 劣势

      ● 任何写入都会涉及到重写从根节点到叶节点的所有节点,需要进行log(n)操作。可以通过分批更新来帮助。

      ● 读取涉及读取路径上的所有节点,需要进行log(n)操作(很可能通过缓存得到很大帮助)。

      ● 由于每次突变都涉及到提取旧的根哈希值并返回新的根哈希值,如果在树中有两个你想要的写法,你需要分批或按顺序进行。

      ● 所有以前的节点总是被保留。不存在修剪问题。

    • 为什么它对区块链来说是可怕的

      ● 根哈希值可以在共识中共享,以确保节点在树上有相同的数据。例如,在Snowblossom中,UXTO的根哈希值来自UTXO的哈希三角形。

      ● 然后,共享的根哈希和中间节点可以用来向轻型客户或只有头的节点证明树中任何数据的存在和完备性。

      ● 由于结构有固定的规则,证明也可以证明数据不在那里。例如:通过显示数据所在的父节点,如果它存在的话。

      ● 如果有一个重组,或潜在的重组,新的根哈希值可以根据以前的块的根哈希值来更新。不需要回退变化或选择一个链,只需将所有合理的区块应用于哈希值的三角。使用任何最终获胜的东西。例如,让我们说三角形是存储已确认的交易,截至最近的区块。假设我们在10000区块上。假设有一个重组,所以一个新的区块9997进来了。我们只需从9996区块中提取根哈希值,并从那里进行变异,就可以为其建立交易三角。然后,新的分叉链可以独立于现有的分叉链被导入。

      ● 如果我们保存了以前区块的根哈希值,我们就可以在树上查询我们想要的任何以前区块的状态。这样一来,一个正在对一堆东西进行长时间读取的客户可以挑选一个块,并查询与之相关的所有东西,即使新的块正在进入。

      ● 因为对于区块链账本来说,我们通常不想丢弃数据,所以没有任何东西被修剪的事实是没有问题的。

线路信息和网络协议 #

所有的Snowblossom消息和点对点的网络互动都是用protobuf定义的,并使用gRPC。 这使得系统的关键互动得到很好的定义和一致。

原版文件

点对点通信(和轻型客户端连接)支持带有实际证书的TLS。 这是通过客户端知道服务器节点的密钥ID来实现的,而不需要由证书颁发机构颁发的证书的麻烦。 p2p网络流言将密钥ID与节点流言数据一起发送。 硬编码的种子节点有硬编码的密钥ID。 这使得不依赖任何证书机构的MITM攻击成为可能。

客户端检查服务器的证书,以确保它是由预期的签署密钥签署的。

TLS来源

StoatPOW - 基于存储的IO访问PoW #

  • 概念

    这个工作证明的概念是,各种通用计算用例都喜欢快速访问大型存储。 例如:游戏、数据库、媒体编辑

    因此,在快速访问大型存储方面的任何进展都会相对较快地进入商品部件,从而被普遍使用并发挥作用。 因此,Snowblossom的工作证明是基于对大型存储的快速访问。

  • 雪场和难度

    雪场是大型的确定性数据文件。 最小的是1GB,目前的场是256GB。 字段大小随着哈希率的上升而增加,哈希率每增加4倍,雪域大小就增加一倍。 一旦字段大小增加,它就不会减少。

    对于这些大文件,我们没有让每一个只验证区块的节点或客户端都需要访问它们。 所以字段的merkle根是硬编码的。 作为采矿过程的一部分,矿工包括他们从雪域中读取的数据段的证明,证明这些数据段是正确的,在正确的位置,并产生正确的哈希值。

  • 斯诺菲尔德一代

    雪场的生成很复杂,因为它们必须具有以下特性。

    ● 确定性的–任何人都应该能够再生它们

    ● 不可并行–应该不可能按要求只建造雪场的一部分

    为此,创建雪场的程序被称为snowfall。 它对文件进行了多次prng传递。 从本质上讲,你可以把它看作是一个具有绝对巨大状态空间的伪随机数发生器。 这可以防止任何人有效地对生成状态进行检查。 我们希望避免这样一种情况,即矿工可以按需生成雪场的一部分,而不需要从存储中加载页面。

多种签名算法 #

所有的地址都是多符号的(在常见的简单地址情况下是1的1)。 #

客户端钱包格式超级安全 #

我总是怀疑那些我无法轻易检查的二进制文件格式。 特别是对于像加密货币钱包这样的关键事物。 幸运的是,由于加密货币钱包是一个小的数据集,所有的操作都可以被认为是追加操作,我们可以做出一些不错的决定,使其比传统的 “wallet.dat “方法更安全。 对于一个单一的文件,我总是害怕一些事情,比如如果我用一个新的软件版本打开钱包,我还能使用旧的软件吗? 如果我不小心导致新的密钥产生怎么办? 那么我需要更新我的备份。 如果我把钱包装在两台不同的电脑上,如何合并它们?这有可能吗? Snowblossom的方法解决了这一切。

在Snowblossom CLI客户端以及IceLeaf GUI客户端,钱包数据被保存在一个目录中,而不是一个单一的文件。 每次写入都是以随机生成的文件名写成一个新的文件。 在钱包加载时,所有的文件在内存中被读取和合并,然后写入一个新的合并文件,只有在新文件被写入和刷新后,源文件才被删除。

保存文件本身是protobuf WalletDatabase的实例。 这使得字段可以在功能需要时被添加。 有一个版本字段,如果它高于源代码WALLET_DB_VERSION,那么当数据库文件被合并时,原始文件不会被删除。 假设可能有新的字段,当前的源代码不知道如何正确合并。 所以在新旧软件版本混合的情况下,有可能出现数据库文件堆积的情况,但一切都应该正常。

在Snowblossom CLI中,有一个导出为json的操作。 它并不漂亮,但它可以让用户检查正在发生的事情。

鉴于上述合并和文件命名行为,钱包的使用选择是广泛的。

效果很好的东西。

● 通过NFS或共享文件系统在计算机之间进行实时同步,或仅仅在一台计算机上运行多个客户端

● 最终像Dropbox或unison之类的东西进行同步

● 合并钱包,只需将文件复制到一个目录即可

● 混合新老雪花客户

通常特征 #

● 块状时间 10分钟的平均数

● Child-pays-for-parent (CPFP)

● 交易的不可更改性

● 双重消费保护

● 有弹性的点对点网络

● 分散的设计

● 随着时间的推移,半截式的奖励

● 先看先加