http://www.7klian.com

操作Merkle树低本钱实现可扩展付出池

这个想法是,与其让付出池打点收款人及其付款金额的帐本,不如成立一个生存收款人及其付款金额的[Merkle 树](https://learnblockchain.cn/tags/Merkle%E6%A0%91[5]),然后收款人通过提交 Merkle 证明来提取相应的金额。然后,Merkle 证明将成为仅合用于收款人的密钥,该密钥可在付出池中解锁收款人的通证。
我们举办了一些尝试,在当前的区块 gas limit 下,可以支持 200 多名收款人,再多就会超出 gas 限制,假设按 gas 价值为 35 gwei , gas 限额为 10,000,000,需要淹灭 0.35 个 ETH(当前约莫 1000 块),相当于存储每个收款人付出的 gas 费是 5 块。
我们最初对这种链上付出池智能合约的构思很是简朴。

Merkle 树付出池
· 假如收款人只想提取一部门通证怎么办?
在付出池智能合约中,我们维护一个映射属性,该属性将付款周期映射到打点该付款周期中在该付出池的 Merkle 根。这样,当用证明挪用paymentPool.withdraw()函数时,假如我们知道生成证明所依据的付款周期,则可以利用正确的 Merkle 根来验证证明。
改造
这是它的事情方法:正如我在上面提到的,证明实际上只是一系列已被序列化为十六进制名目标姑妈及叔叔哈希的数组。为了将元数据包罗在证明中,我们需要向该证明数组添加几个特另外项。
[3]ERC-20: https://learnblockchain.cn/tags/ERC20

我们可以将此列表转换为如下所示的数组:

[5]Merkle树: https://learnblockchain.cn/tags/Merkle树
这是为什么呢?这是这种特定要领的细微不同:我们为每个付款周期构建的 Merkle 树需要反应收款人的累计付款金额,而且应在付出池中保存取款额的映射,其差额是可以答允收款人提供的任何有效证据提取的部门(当差额为负时,显然不答允提取)。
另外,值得留意的是,在本文中提到的所有办理方案,并未涉及如何确保付出池中的资金已全部到位,从而使收款人可以持续举办提款。在我们提供的代码示例中,我们确实确保付出池有足够的资金,然后再实验将通证挪用payingPool.withdraw()成果时将通证转移到收款人。这里可以想到的一种要领是当付出池余额下降到特定阈值以下时发出付出池通证余额告诫事件。
在我们的 Tally 协议,协议通过“阐明”矿工孝敬的 GPU 周期来计较嘉奖,和流媒体场景很雷同,开始的想法是付出池智能合约将从各类通证收集智能合约吸收ERC-20[3]通证,通过阐明签名的应用措施利用日志和其他链上信号来确定付出池内的通证分派。阐明矿工迁就付出池中的付款金额告竣共鸣,并通过提交一系列收款人地点和付款金额的形式提交给付出池,这些地点和付款金额将写入付出池打点的帐本中。
[8]GitHub代码库: https://github.com/cardstack/merkle-tree-payment-pool
在寻找更好的要领时,我们受到这篇研究文章[4]的开导
Merkle 树
详细来说,要添加与 Merkle 根相对应的付款周期号(我们可以在将 Merkle 根提交给合约之前,在 PaymentPool 智能合约上挪用paymentPool.numPaymentCycles()来得到该值)以及收款人可提取的累计通证数量。在paymentPool.withdraw()函数中,需要从证明中剥离元数据,以便paymentPool.withdraw()函数知道证明所涉及的付出周期以及通证的数量是此收款人 Merkle 树中叶节点的一部门。
重要留意事项
因此,这种要领是一个好的开始。我们已经解锁了从付出池中付出收款人所需数量通证的成果,而不必发生大量的 gas 费,另外,这意味着我们付出池中收款人的数量和所需要的 gas 费解耦了。收款人的证明根基上就像钥匙一样,仅用于从收款人的地点提倡的生意业务,可用于从池中解锁该收款人的通证。
此办理方案最明明的缺点是,付出池处理惩罚的是无限的收款人及其付款金额,这意味着这种生意业务大概会超出 gas 限值。这将需要付出池能监控 gas 预算,并跟踪收款人列表,以便假如超出 gas 预算时,以便可以在后续生意业务中继承执行。
要降服的另一个挑战是如何提取少于建设证明时的通证数量。另外,我们如何利用户更容易将证明与特定付款周期相关联,以便可以利用正确的 Merkle 根来验证提款请求?
[9]Phala-Networkk 空投(]https://github.com/Phala-Network/prelaunch-token/blob/master/contracts/MerkleAirdrop.sol) 及 [Uniswap 空投: https://etherscan.io/address/0x090d4613473dee047c3f2706764f49e0821d256e#code
我们如安在付出池中操作 Merkle 树?
我们可以验证节点是否确实存在于 Merkle 树中的要领是添加带有其证明的节点,然后查察该功效是否便是根节点。OpenZepplin 有一个Solidity 库[7] 用来验证。

先看看:基于数组的付出池
付出池是一种通用机制,可用于模仿“一对多”或“多对多”付出通道。这个想法是,可以从各类来历将通证存放到池中,然后按照“法则”(在链上或链外实施)将池中的通证分派给很多吸收者。本质上,我们的要领有本领就按大量小额付款汇总到一个结算中,从而节减了大量的 gas 。
只要付出池跟踪每个收款人已提取几多通证,就可以确保从分派给该收款人的累计通证中减去已提取的通证数量。
· 多个付款周期呢?Merkle 根更新后,我们可以利用旧的证明吗?
付款周期
思路是paymentPool.withdraw()函数将通过msg.sender及通证数量重建叶子节点。withdraw函数可以哈希该叶节点并将哈希的叶节点添加到证明(这是组成证明的哈希的十六进制暗示)。假如哈希叶节点和提供的证明之和的哈希值便是合约所有者提交的 Merkle 根,那么paymentPool.withdraw()函数可以答允将通证从付出池转移到msg.sender。

[10]Cell Network: https://www.cellnetwork.io/?utm_souce=learnblockchain

显然,这种要领无法扩展。

· 我们可以通过将节点的哈希值及其“叔叔”节点加在一起,以确定它们是否与根节点匹配,来确定树中是否存在节点。

我们将体贴的数据放在 Merkle 树的叶节点中。有很多可用的代码库可以执行此操纵,给库中提供一个数组,库将对数组举办排序,并利用提供的已排序数组组成 Merkle 树的叶节点来构建 Merkle 树布局体。库会提供 Merkle 树的根,它也可觉得任何节点提供证明,个中证明是该节点的哈希与叔叔们 hash 列表,当与节点的哈希值加在一起时,就是默克尔根。
Merkle 树最重要的方面是:
译者注:假如你对空投感乐趣,还可以参考代码:[Phala-Networkk 空投(]https://github.com/Phala-Network/prelaunch-token/blob/master/contracts/MerkleAirdrop.sol) 及 Uniswap 空投[9]
[7]Solidity 库: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/MerkleProof.sol
· 每个节点是该节点的子级哈希值之和的哈希值

证明元数据

假如你以为此办理方案对你有用,接待在你本身的合约中利用它,改造它。
· 如何暗示链上某个地点可用的通证数量及证明?

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读