在 CKB 上设计一个 UDT 标准的方法:Part 1

2019-12-03 19:10 栏目:经验之谈 来源: 查看()
本文基于《关于UDT标准评价标准的讨论》(https://Talk)一文中提出的可能存在的问题和可行的解决方案。在《神经谈话》上发表。 本文主要讨论哪些不同类型的用户将使用UDT接口,应该在哪个抽象层建立UDT接口,我们应该支持哪些操作和查询功能,以及为什么我们的标准要求我们建立一套明确的体系结构和一系列所需的单元,而不是提供像ERC20这样简单的功能性应用程序接口。然后,我将简要讨论一些架构方案,并提供一个关于单元格的初步、非正式和高级描述性文档,支持UDT操作和查询功能。 作者:Tannr,Nervos工程师,有分布式和P2P网络的开发经验,喜欢学习分析哲学和形式系统。 原始链接:https://talk . nervos . org/t/approach-to-design-a-user-defined-token-standard-on-ckb-part-1/3855 译者:史迪仔 抽象和编程接口 CKB的编程模式与大多数其他智能合同平台非常不同,因为国家生成不会发生在CKB链上。在CKB,合同只是用来验证执行合同的转让是否有效的脚本。对于UDT标准设计,有两点值得注意: 含义1:查询接口→标准化数据位置 第一个影响是契约没有提供可以在外部调用的请求-响应或基于事件的接口。这些合同不会被用作返回查询信息的查询接口,也不会被用作产生连锁副作用的传递接口。这意味着在CKB建立智能合同查询界面是没有意义的。毫无疑问,查询令牌信息的功能至关重要,因此提出了一个问题:如果它不是智能契约提供的应用编程接口,应该是什么?查询程序可以访问由节点提供的RPC应用编程接口,并且节点可以访问链接数据,只要它向这些RPC提供参数并且通知应用编程接口服务器特定的搜索位置。因此,有必要对智能合同的逻辑进行标准化,但这不足以支持UDT对CKB的查询:我们必须对关键UDT数据的存储位置进行标准化,以便服务器能够轻松找到数据。 为了标准化UDT数据的存储位置,我们必须标准化由单元组成的最低必要架构。在这个设计过程中,我们应该记住标准应该是可扩展的,以便适应不同的用例。在ERC20这样的标准中,智能合同的功能签名和预期返回值是指定的,而实现细节几乎完全由开发人员决定。相比之下,CKB-UDT标准要求我们至少指定一个基础设施(和一些具体的实现细节),这限制了开发人员构建定制令牌。灵活性和可伸缩性是Nervos Network非常重视的价值,因此虽然基本的架构设计规范是必要的,但应该给予高度重视,并且不应该尽可能牺牲灵活性和可伸缩性。 含义2:编程接口→传输规则集 第二个影响是CKB的智能合同,虽然是用单元格写的,但它实际上是在传输级别设置的规则。从现在开始,这些合同——将被称为“脚本”——,在传输环境中执行。他们可以访问有关传输的所有信息,而不仅仅是他们所连接的单元。当然,传输可以在其不同的单元格中包含多个脚本。因此,脚本可以被视为整个规则集的一个特定子集进行传输,其中规则集是每个脚本中的一组规则。在网络上实现状态更改的是传输,而不是脚本。 当开发人员想要在以太网上部署定制编程行为时,他们的重点是智能契约的行为。在CKB,更有意义的是关注转移行为(转移描述一组状态变化或行为),然后提供开发脚本来执行转移规则。换句话说,尽管许多智能契约平台关注于实现定制编程行为的智能契约,但CKB采用了先转移的方法。转移的设计是最重要的。脚本的存在只是为了确保符合交易转移设计的规则。因此,尽管典型智能合同平台上的自定义令牌标准将定义智能合同的编程接口,并通过不同的合同功能与令牌操作相关联,但CKB的自定义令牌标准将定义具有传输优先级的接口,并被关联 设计CKB-UDT标准的第一步是知道谁将使用它以及为什么。这将告诉我们需要支持哪些特定的操作和查询功能。特定操作将映射到传输规则集,而查询将映射到标准化的数据位置、大小和格式。由于传输受规则集的约束,这些规则集是传输执行过程中结构和内容上的规则,因此需要指定最小的必要结构来指定传输规则集。正如我在前面提到的,考虑到CKB的编程模型,指定标准化的结构是不可避免的。 用户 用户主要是代表最终用户执行状态生成或查询的DApp开发商、钱包、交易所和其他服务。我在这里没有提到霍尔德或DApp用户,因为前者和后者都通过其他界面使用UDT。因此,事实上,只有令牌、DApp和离线软件服务的开发人员将直接与CKB-UDT互动。 用户进一步分为三种不同类型中的一种或多种:开发人员、生成器和查询者。在这种情况下,开发人员是直接参与定制令牌的人员。生成器是指提交UDT特定传输的任何外部服务,而查询者是指查询UDT特定信息的任何外部服务。 在进一步讨论UDT标准应该支持的实际查询和状态更改之前,重要的是要理解神经网络上提出的任何特定规则都需要受到整个系统的约束。 成本限额 执行UDT特定传输所需的脚本的计算开销。 在链上存储UDT特定状态的容量成本。 转移成本是指执行一项操作需要转移多少次以及每次转移的规模(这将影响转移费用)。 可用性限制 可扩展性使开发人员能够在标准兼容性的前提下构建和定制他们的令牌。 查询复杂性由查询者用来收集和分析相关信息,包括要包含在传输中的信息。 UDT的采用程度取决于需要做多少工作来增加新功能来支持一个新的UDT。 我们在UDT标准中支持的操作和查询功能最终需要满足各种用例,包括定制货币政策、定制产品发布计划以及与其他DApp的互操作性。 注意:考虑到CKB的编程模型,特定于UDT的传输执行规则的脚本与用户实际持有的令牌分离。用户在单元中持有的实际令牌将被称为“UDT实例”,而负责存储系统级信息和执行传输规则集的元数据和脚本集将被统称为“UDT定义”。这将在后面详细描述。 查询和操作 询问 查询地址下的UDT余额 获取UDT元数据 获取UDT传输依赖关系 获得UDT实例的实际用户 获取UDT定义的实际创建者 从定义中获取UDT实例的实际创建者 组装保存此UDT实例的地址 操作(状态更改) 发送UDT实例 批准UDT实例的用户 烧毁UDT实例 创建新的UDT实例 更新UDT定义 使用初始UDT实例资源调配创建新的UDT定义 架构规范 设计这个规范的挑战之一是每个决策都限制了以下决策。基本框架规范对于解释传输结构和规则以及如何查找和查询数据非常重要。我们需要架构规范来提出传输生成和查询规则(因为传输和查询并不意味着需要指定所涉及的单元),但是我们还需要事务生成和查询规则来从一开始就理解哪些架构决策最有意义.这似乎是圆形的。 因此,我想做的是确定一些初步框架,使用这个初步框架来设计传输规则集和查询操作,然后指出这个框架的哪些部分可以被修改以更好地支持实际的规则。 CKB编程模型的第一个架构决策——或者架构特征——是状态改变的逻辑和受逻辑约束的实际状态的分离。对于状态的任何组件(例如,单元或单元集),将来可能会改变,必须有另一个包含验证逻辑的状态组件。请注意,“状态组件”是一个逻辑组件,因为它指的是一个或多个单元。 因此,如果我们有UDT实例供人们转账,那么我们必须有第二个单元格,其中包含这些UDT实例的验证逻辑。我称之为UDT定义。因为我们希望能够更新身份验证逻辑来缓解某些情况(例如安全漏洞或允许我们在UDT用户批准的情况下进行策略更改),所以我们必须有第三个单元,其中包含更新这些UDT定义的身份验证逻辑,我称之为“UDT标准” 除了元数据:正如我上面提到的,UDT定义不仅是验证逻辑,还包括所有不属于UDT实例的元数据。问题是:在哪里存储这些元数据?元数据应该有自己的单元格吗?它是否应该作为agr存储在UDT定义的脚本中(即“UDT标准”)?即使一些UDT的元数据和验证逻辑被分成单独的单元,这些单元仍然被统称为“UDT定义”。因此,我使用的UDT分类法不一定将1:1映射到实际的单元格;这是一种逻辑分类,而不是物理分类。 因此,该框架分为三层: UDT实例 UDT定义 UDT标准 UDT标准限制了涉及UDT定义的有效转让,而UDT定义限制了各自UDT实例的有效转让。 Nervos提供开发人员提供的UDT标准电池。 在UDT标准水平上,UDT标准有许多UDT定义。在UDT定义级别,UDT定义将有许多UDT实例。 问题是:如果开发人员负责实现UDT定义,他们是否也负责构建UDT标准,还是应该由神经网络提供? 我们的目标是允许灵活的货币、治理和发行政策,因此有两种前进的方式。第一种方法是为社区开发人员提供一个UDT标准单元,并通过参数进行配置。第二种方法是提供UDT标准必须执行的最小规则集,然后开发人员可以以任何他们想要的方式构建UDT标准单元,只要它满足必要的规则。 如果我们最终想要将元数据存储为参数并将其发送到DUT标准单元,那么参数的顺序和含义需要标准化,以便其他服务器可以检索元数据。如果标准单元格是由Nervos网络提供的,这就更容易了,因为参数可以通过编程实现。但是,如果允许开发人员构建自己的UDT标准单元,他们可以省略一些可选功能,而不必通过参数将它们配置为禁用。 想象以下场景:由Nervos网络提供的UDT标准单元允许在初始供应后铸造新的令牌,通过启用或禁用布尔参数,并设置铸造的附加参数(例如,有多少次,是否有利益相关者投票,批准一些铸造作为签署者,等等)。)。他们确实需要可升级性,所以他们将可升级性设置为true,并使用另一个参数进行额外配置。 现在,每当UDT定义升级时,UDT标准单元都包含这个冗余代码,从而增加了不必要的传输大小。然而,如果他们构建自己的UDT标准单元,他们可以省略任何与用例无关的功能。一个可能的解决方案是标准化参数,不管UDT标准脚本中实际包含什么代码。因此,即使标准脚本不将第三个参数视为“可擦除标志”,它们仍然需要在那里包含一个“假”值来指示它是不可擦除的,并且必须编写脚本来忽略该标志。然而,这是一个“陈旧”的解决方案。 元数据作为元数据单元的UDT定义和参数 但是,想象一下元数据(例如总供应量)存储在元数据单元而不是脚本中的另一种情况。脚本需要一些元数据。例如,在增加或减少供应(铸造或销毁)的情况下,访问脚本以获得总供应非常重要。因此,将总供应量作为参数包含在脚本中比将其存储在完全不同的单元格中更容易。 对此有两种解决方案。第一种是创建元数据单元格,并通过参数为脚本提供输出。那么转移必须将此外迁设置为deps字段中的dep。脚本将以这种方式加载元数据,并执行验证更新或创建。这方面的问题是加载数据需要额外的计算开销。幸运的是,CKB编程支持部分数据加载。 第二种解决方案是分割元数据。有些存储在参数中,有些存储在元数据单元格中。参数将存储对状态更改逻辑至关重要的元数据,而其他元数据将存储在元数据单元格中。然而,这使整个事情变得复杂,因为元数据现在存储在两个地方,一些与一个脚本的验证逻辑相关的元数据可能与其他脚本的验证逻辑相关。例如,totalSupply对于铸造和销毁很重要,但是销毁也可以由Holder执行。在单元格中存储元数据还提供了更大的可伸缩性,因为开发人员可以在更复杂的数据结构中存储额外的元数据。因此,对包含脚本相关数据的单元格(元数据单元格)的引用可以作为参数传递。 在设计元数据单元的结构时,我们需要确保脚本相关字段被序列化,这样脚本可以部分加载数据,而不必加载元数据单元的全部内容,因为一些元数据片段将与某些特定脚本相关,而另一些则不相关。例如,如果数据存储为键到值的映射,脚本必须加载整个映射才能加载一个或两个键。列表结构允许部分加载,但是我们必须确定如何处理可选数据。在映射中,可以省略键。在列表结构中,省略的键会改变其他元数据的字节地址,因此整个列表仍然需要加载。 一种解决方案是标准化字节地址及其含义(例如,第一个x位专用于名称),并省略由“空字节序列”表示的可选元数据片段这里的权衡是,如果开发人员想要从元数据单元中省略部分数据,他们仍然需要占用相当于存储每部分元数据所需容量的容量,而不管某些部分是否被认为是可选的。 哈希表从一开始就占据了更多的空间。具有两个键值对的哈希表比具有两个元素的数组占用更多的空间。因此,在最坏的情况下,当包含所有可选元数据时,基于数组的结构占用的空间更少,并且支持部分加载,而映射则不支持。我们必须决定使用哪种数据结构,无论是列表、映射还是其他数据结构。正确的序列化方法可以解决其中的一些问题,但是在这种情况下,脚本和查询程序会有额外的反序列化开销。 作为锁和类型脚本的UDT标准 UDT标准单元用于为在UDT定义上执行的操作提供验证逻辑。包括权限管理和确保有效的状态更改和数据一致性。根据CKB的编程模型,有效的状态更改由类型脚本处理,而权限由锁定脚本处理。因此,UDT标准实际上由两个单元格——、一个锁脚本和一个类型脚本组成。 不幸的是,这使得开发人员的工作变得复杂,因为他们需要存储的单元越多,他们开发的UDT越多,他们首先需要的容量就越多。但是,允许他们开发自己的UDT标准单元可以删除冗余代码,从而节省容量。所以这是一种权衡。也许最好的解决方案是为想要使用它的开发人员提供一个标准单元(因为它也节省了开发时间),并且开发人员可以自由地开发满足他们想要支持的可选操作的UDT标准单元,只要所需的规则集由他们的自定义脚本强制执行。 迄今为止架构概述 UDT实例 UDT定义了——型脚本单元格;元数据单元 UDT标准——型脚本单元;锁定脚本单元格 第一部分总结 在本文中,我解释了传输是CKB开发的主要编程接口,而不是脚本。我提出了一组UDT标准应该支持的操作和查询,解释了为什么我们的UDT标准需要为社区开发的UDT指定一个特定的体系结构,然后描述了一个上层UDT体系结构,它只是支持所需操作和查询所需的一组单元。 在下一篇文章中,我将深入研究传输规则集,然后基于这些规则集更深入地描述UDT架构。例如,如果更新了UDT定义,对UDT定义的UDT实例引用不应保持有效,因此UDT标准必须实施类似于类型标识函数的操作。作为另一个例子,UDT的定义应该提供防伪保护,但最初提供的UDT作品必须绕过这一点。如何设计UDT创建操作(通过提供特殊权限、使用一次性授权等)。)哪些参数将受到影响并传递给哪些脚本,等等。
微信二维码
售前客服二维码

文章均源于网络收集编辑侵删

提示:仅接受技术开发咨询!

郑重申明:资讯文章为网络收集整理,官方公告以外的资讯内容与本站无关!
NFT开发,NFT交易所开发,DAPP开发 Keywords: NFT开发 NFT交易所开发 DAPP开发