血浆现金区块链状态的数据结构



您好,尊敬的Habr用户! 本文是关于Web 3.0-分散式Internet。 Web 3.0引入了分散化的概念,将其作为现代Internet的基础。 许多计算机系统和网络需要安全性和分散功能才能满足其需求。 使用区块链技术的分布式注册表为去中心化提供了有效的解决方案。

区块链是一个分布式注册表。 您可以将其视为一个永久存在的庞大数据库,并且不会随着时间的流逝而改变。 区块链为分散的Web应用程序和服务提供了基础。

但是,区块链不仅仅是一个数据库。 它用于提高网络成员之间的安全性和信任度,从而增强在线业务交易。

拜占庭共识提高了网络可靠性并解决了一致性问题。

DLT提供的可伸缩性改变了现有的业务网络。

区块链提供了新的非常重要的好处:

  1. 防止代价高昂的错误。
  2. 确保透明的交易。
  3. 数字化真实商品。
  4. 强制执行智能合约。
  5. 提高付款速度和安全性。

我们已经开发了一种特殊的PoE,以研究密码协议并改善现有的DLT和区块链解决方案。

大多数公共注册系统缺乏可伸缩性,因此其吞吐量相当低。 例如,以太坊仅处理〜20 tx / s。

开发了许多解决方案以增加可伸缩性,同时又保持分散性。 但是,只能同时实现三分之二的优势-可伸缩性,安全性和分散性。

侧链的使用提供了最有效的解决方案之一。

等离子概念


等离子的概念可以归结为根链处理来自子链的少量提交的想法,从而充当存储所有中间状态的最安全也是最后一层。 每个子链都具有自己的共识算法,作为自己的区块链,但是有一些重要的警告。

  • 智能合约是在根链中创建的,并充当根链中子链的检查点。
  • 创建子链,并以自己的共识将其用作自己的区块链。 子链中的所有州都受到欺诈证据的保护,这些欺诈证据可确保州之间的所有过渡有效且适用退出协议。
  • 可以在子链中部署特定于DApp的智能合约或子链应用逻辑。
  • 资金可以从根链转移到子链。

向验证者提供经济诱因,使其诚实行事并向根链(即最终交易结算层)发送承诺。

结果,在子链中工作的DApp用户根本不必与根链进行交互。 此外,即使子链遭到黑客入侵,他们也可以随时将其资金放在根链中。 子链的这些出口使用户可以使用Merkle证明安全地存储他们的资金,从而确认一定数量的资金的所有权。

Plasma的主要优势与其能够显着促进使主链过载的计算能力有关。 此外,以太坊区块链可以处理更广泛和并行的数据集。 从根链中删除的时间也转移到以太坊节点,这些节点的处理和存储要求较低。

Plasma Cash为在线令牌分配唯一的序列号。 该方案的优点包括无需确认,对所有类型的令牌(包括不可替代令牌)的更简单支持以及对子链大量退出的缓解。

子链的“大量出口”的概念是Plasma面临的一个问题。 在这种情况下,协调地从子链中同时提取可能会导致计算能力不足以提取所有资金。 结果,用户可能会损失资金。

实施等离子的选项




基本等离子有很多实现选项。

主要区别在于:

  • 归档有关状态存储和表示方法的信息;
  • 令牌类型(可分割,不可分割);
  • 交易安全;
  • 共识算法类型。

等离子的主要变化包括:

  • 基于UTXO的等离子-每个事务都由输入和输出组成。 可以进行交易并花费。 未花费的交易清单是子链本身的状态。
  • 基于帐户的等离子-此结构包含每个帐户的反映和平衡。 它在以太坊中使用,因为每个帐户可以有两种类型:用户帐户和智能合约帐户。 简单性是基于帐户的血浆的重要优势。 同时,缺乏可伸缩性是一个缺点。 特殊属性“ nonce”用于防止两次执行事务。

为了了解Plasma Cash区块链中使用的数据结构以及承诺如何工作,有必要阐明Merkle Tree的概念。

默克尔树及其在等离子中的用途


Merkle Tree是区块链世界中极其重要的数据结构。 它使我们可以捕获特定的数据集并隐藏数据,但可以证明其中包含一些信息。 例如,如果我们有十个数字,则可以为这些数字创建证明,然后证明此集合中有某个特定数字。 该证明将具有较小的恒定大小,这使其在以太坊中发布的成本不高。

您可以将此原理用于一组事务,并证明该组中有特定事务。 这正是操作员要做的。 每个块由一个事务集组成,该事务集变成Merkle树。 这棵树的根是与每个等离子区块一起发布在以太坊中的证明。

用户应能够从等离子链中提取资金。 为此,他们向以太坊发送“退出”交易。

Plasma Cash使用特殊的Merkle树,无需验证整个区块。 仅验证与用户令牌相对应的那些分支就足够了。

要传输令牌,必须分析其历史记录并仅扫描特定用户需要的那些令牌。 转移令牌时,用户只需将整个历史记录发送给另一个用户,该用户便可以对整个历史记录进行身份验证,最重要的是,可以非常快速地进行身份验证。



用于状态和历史记录存储的等离子现金数据结构


建议仅使用选定的Merkle树,因为有必要为区块中的交易获取包含和不包含证明。 例如:

  • 稀疏的默克尔树
  • 帕特里夏树

我们为客户开发了自己的稀疏Merkle树和Patricia树实现。

稀疏Merkle树类似于标准Merkle树,不同之处在于其数据已建立索引,并且每个数据点都位于与该数据点的索引相对应的叶上。

假设我们有一棵四叶默克尔树。 让我们用字母A和D填充这棵树,以进行演示。 字母A是第一个字母,因此我们将其放置在第一片叶子上。 同样,我们将D放置在第四片叶子上。

那么第二和第三片叶子会发生什么呢? 他们应该留空。 更确切地说,使用特殊值(例如零)代替字母。

树最终看起来像这样:



包含证明的工作方式与常规Merkle树中的工作方式相同。 如果我们想证明C不是此默克尔树的一部分,会发生什么? 小学的! 我们知道,如果C是树的一部分,它将在第三片叶子上。 如果C不是树的一部分,则第三片叶子应为零。

所有需要的是标准的Merkle包含证明,该证明表明第三片叶子为零。

稀疏Merkle树的最大特点是它为Merkle树内的键值提供了存储库!

PoE协议代码的一部分构造了稀疏Merkle树:

class SparseTree { //... buildTree() { if (Object.keys(this.leaves).length > 0) { this.levels = [] this.levels.unshift(this.leaves) for (let level = 0; level < this.depth; level++) { let currentLevel = this.levels[0] let nextLevel = {} Object.keys(currentLevel).forEach((leafKey) => { let leafHash = currentLevel[leafKey] let isEvenLeaf = this.isEvenLeaf(leafKey) let parentLeafKey = leafKey.slice(0, -1) let neighborLeafKey = parentLeafKey + (isEvenLeaf ? '1' : '0') let neighborLeafHash = currentLevel[neighborLeafKey] if (!neighborLeafHash) { neighborLeafHash = this.defaultHashes[level] } if (!nextLevel[parentLeafKey]) { let parentLeafHash = isEvenLeaf ? ethUtil.sha3(Buffer.concat([leafHash, neighborLeafHash])) : ethUtil.sha3(Buffer.concat([neighborLeafHash, leafHash])) if (level == this.depth - 1) { nextLevel['merkleRoot'] = parentLeafHash } else { nextLevel[parentLeafKey] = parentLeafHash } } }) this.levels.unshift(nextLevel) } } } } 

这段代码很简单。 我们有一个包含/不包含证明的键值存储库。

在每次迭代中,将从最后一棵树开始,填充特定级别的最终树。 根据当前叶子的键是偶数还是奇数,我们取两个相邻的叶子并计算当前级别的哈希值。 如果到达末尾,我们将写下一个merkleRoot-普通哈希。

您必须了解,此树最初填充了空值。 如果我们存储了大量的令牌ID,则树的大小将很大,而且很长!

对于这种非优化,有很多补救措施,但是我们决定将其更改为Patricia树。

帕特里夏树是基数树和默克尔树的组合。

基数树数据键存储数据本身的路径,这使我们能够为内存创建优化的数据结构。



这是为我们的客户开发的实现:

 buildNode(childNodes, key = '', level = 0) { let node = {key} this.iterations++ if (childNodes.length == 1) { let nodeKey = level == 0 ? childNodes[0].key : childNodes[0].key.slice(level - 1) node.key = nodeKey let nodeHashes = Buffer.concat([Buffer.from(ethUtil.sha3(nodeKey)), childNodes[0].hash]) node.hash = ethUtil.sha3(nodeHashes) return node } let leftChilds = [] let rightChilds = [] childNodes.forEach((node) => { if (node.key[level] == '1') { rightChilds.push(node) } else { leftChilds.push(node) } }) if (leftChilds.length && rightChilds.length) { node.leftChild = this.buildNode(leftChilds, '0', level + 1) node.rightChild = this.buildNode(rightChilds, '1', level + 1) let nodeHashes = Buffer.concat([Buffer.from(ethUtil.sha3(node.key)), node.leftChild.hash, node.rightChild.hash]) node.hash = ethUtil.sha3(nodeHashes) } else if (leftChilds.length && !rightChilds.length) { node = this.buildNode(leftChilds, key + '0', level + 1) } else if (!leftChilds.length && rightChilds.length) { node = this.buildNode(rightChilds, key + '1', level + 1) } else if (!leftChilds.length && !rightChilds.length) { throw new Error('invalid tree') } return node } 

我们以递归方式移动并构建了单独的左右子树。 在此树中已将密钥构建为路径。

此解决方案更为简单。 它经过优化,运行速度更快。 实际上,可以通过引入新的节点类型(扩展节点,分支节点等)来进一步优化Patricia树,就像在以太坊协议中所做的那样。 但是当前的实现可以满足我们的所有要求-我们拥有快速且内存优化的数据结构。

通过在客户项目中实施这些数据结构,我们使等离子现金扩展成为可能。 这使我们能够检查令牌的历史记录以及是否将令牌包含在树中,从而大大加快了对区块和等离子儿童链本身的验证。

友情链接:


  1. 白皮书等离子
  2. Git中心
  3. 用例和架构描述
  4. 闪电网纸

Source: https://habr.com/ru/post/zh-CN455988/


All Articles