cosmos sdk
In late 2019, the Interchain Foundation and Katalysis agreed to bring the Cosmos SDK to Swift. We aim to enable the building of a fully fledged blockchain application using the Tendermint consensus in Swift. For our use case, the specific target platform is Linux, however, our intent is also to also eventually provide support for iOS.
在2019年末, Interchain Foundation和Katalysis同意将Cosmos SDK引入Swift。 我们旨在使用Swift中的Tendermint共识来构建完整的区块链应用程序。 对于我们的用例,特定的目标平台是Linux,但是,我们的目的也是最终也为iOS提供支持。
The project leverages our ABCI Server implementation as well as our partial Amino implementation in Swift¹.
该项目利用了我们的ABCI服务器实施以及Swift¹中的部分Amino实施 。
The porting of the Cosmos SDK to Swift has been planned in three parts, each of which builds one the previous ones.
已计划将Cosmos SDK移植到Swift的三个部分,每个部分都构建了以前的版本。
The first milestone is all about developing the structures to store the state. This is provided by Merkle trees. In Tendermint, and by extension the Cosmos SDK, the state is stored on iAVL+ trees². iAVL+ trees are AVL trees with two additional properties: (1) they are merkelized³, and (2) the nodes are immutable allowing their full history to be kept.
第一个里程碑是关于开发用于存储状态的结构。 这是由Merkle树提供的。 在Tendermint中(通过扩展Cosmos SDK),状态存储在iAVL +树²中。 iAVL +树是具有两个附加属性的AVL树:(1)它们是merkelized³,以及(2)节点是不可变的,可以保留其完整历史记录。
The second milestone aims to implement the higher level building blocks for CosmosSwift, such as the framework connecting the various modules comprising a blockchain app (Framework, Store, Bech32) and some basic modules as well (Auth, Params).
第二个里程碑旨在为CosmosSwift实现更高级别的构建块,例如连接框架的框架,这些模块包括一个区块链应用程序(Framework, Store , Bech32 )和一些基本模块( Auth , Params )。
The final milestone will look at implementing more complex modules (Bank, Mint, Supply), and aims to implement an IBC (InterBlockain Communication) protocol module as well⁴.
最后的里程碑将着眼于实现更复杂的模块( 银行 , 薄荷 , 供应 ),并旨在实现IBC( 跨区块链通信 )协议模块。
第一个里程碑的具体目标 (Specific goals for the first milestone)
While designing the implementation of the first milestone, we set ourselves the following goals:
在设计第一个里程碑的实现时,我们为自己设定了以下目标:
- Think about the “Swiftiness” of the implementation as much as replicating a set APIs. In particular, refrain from mapping one to one the Swift implementation to the Go implementation. 考虑实现的“快速性”,就像复制一组API一样。 特别要避免将Swift实现一对一映射到Go实现。
- The implementation should allow (1) flexibility to choose Storage for our iAVL tree, (2) flexibility in the Encoding for serialisation/deserialisation of tree nodes and proofs between nodes, and last but not least, (3) flexibility in the keys, values and hashing functions used for our tree payloads. 该实现应允许(1)灵活地为我们的iAVL树选择存储,(2)树节点的序列化/反序列化和节点之间的证明的编码灵活性,以及最后但并非最不重要的,(3)密钥,值的灵活性和用于树有效负载的哈希函数。
- It should have strong typing and avoid optionals as much as possible, as well as provide strong immutable semantics. 它应具有强类型,并尽可能避免使用可选元素,并提供强不变的语义。
Some of the design decisions deriving from these goals will likely evolve as we start using the artefacts of this first milestone to build the core parts of the framework as part of our next milestone.
当我们开始使用第一个里程碑的构件来构建框架的核心部分作为下一个里程碑的一部分时,源自这些目标的一些设计决策可能会演变。
节点和树 (Nodes and Trees)
In order to provide the flexibility of storage type and behaviour on the one hand and the flexibility of encoding on the other hand, we make heavy use of Swift protocols. In fact, we define two central protocols, the ` NodeStorageProtocol
and the NodeProtocol
.
为了一方面提供存储类型和行为的灵活性,另一方面为提供编码的灵活性,我们大量使用了Swift协议。 实际上,我们定义了两个中心协议,即NodeStorageProtocol
和NodeProtocol
。
The NodeProtocol
defines how tree nodes make the tree and allow navigation through the tree. Nodes are intended to be immutable such that the integrity of the hashes is preserved by design. A root node is therefore the entry point to an immutable tree structure, equivalent to the Go
ImmutableTree
structure.
NodeProtocol
定义树节点如何制作树并允许在树中导航。 节点是不可变的,以便通过设计保留哈希的完整性。 因此,根节点是不可变树结构的入口,等效于Go
ImmutableTree
结构。
The NodeStorageProtocol
defines how a tree is built and maintains its iAVL properties of being balanced and properly secured through its hashes. In fact, custom storage implementations are not expected to implement any of the logic for adding or removing nodes from the tree, nor any balancing logic.
NodeStorageProtocol
定义了如何构建树并维护其iAVL属性,以通过其哈希来平衡和适当地保护它。 实际上,自定义存储实现不希望实现任何用于在树中添加或删除节点的逻辑,也不希望实现任何平衡逻辑。
Implementing these two connected protocols allows us to provide a variety of storage implementations for specific use cases. As a starting point, two storage implementations are currently provided.
实现这两个连接的协议使我们能够为特定用例提供各种存储实现。 作为起点,当前提供了两种存储实现。
The first one is an in memory implementation of the tree, where sequential versions of the tree are committed. While the two core protocols NodeStorageProtocol
and NodeProtocol
comply to Codable
and could be stored on disk as a file, the InMemoryNodeStorage
and corresponding InMemoryNode
classes are not intended for persistent storage.
第一个是树的内存实现,其中提交了树的顺序版本。 尽管两个核心协议NodeStorageProtocol
和NodeProtocol
符合Codable
并可以文件形式存储在磁盘上,但是InMemoryNodeStorage
和相应的InMemoryNode
类并不打算用于持久存储。
The second one is an SQLite backed storage, either in memory or persisted to disk, and it provides lazy access to (partial) versions of the tree stored on disk. The SQLiteNodeStorage
and SQLiteNode
classes do not provide any elaborate node cache management nor any pruning strategies. However, such features are very simple to add to these classes.
第二个是由SQLite支持的存储,可以存储在内存中,也可以存储在磁盘上,并且可以懒惰地访问存储在磁盘上的树的(部分)版本。 SQLiteNodeStorage
和SQLiteNode
类不提供任何详细的节点缓存管理或任何修剪策略。 但是,将这些功能添加到这些类非常简单。
节点协议 (NodeProtocol)
The NodeProtocol
describes the structure of iAVL+ nodes (both leaves and inner nodes) and how nodes tie to one another conceptually. We define two levels of primitives. At the lowest level, we have the following core primitives:
NodeProtocol
描述了iAVL +节点(叶子和内部节点)的结构以及节点之间的概念联系。 我们定义了两个级别的基元。 在最低级别上,我们具有以下核心原语:
We then use them to implement higher level primitives⁵ to access the intrinsic properties of leaves (hash, key, value) or inner nodes (hash, height, size, balance, left node, right node), to traverse and iterate over the tree or to find nodes in the tree.
然后,我们使用它们来实现更高级别的基元-访问叶子(哈希,键,值)或内部节点(哈希,高度,大小,平衡,左节点,右节点)的固有属性,以遍历并迭代树或在树中找到节点。
This allows us to enforce how nodes describe the tree structure and the tree changes over its lifetime.
这使我们能够强制节点如何描述树结构以及树在其生命周期中的变化。
A node instance is expected to be immutable. Any change to the structure of the tree happens by “orphaning” a node and replacing it with another one. Given that this may require performing certain storage operations (due for instance to caching changes before storing them to disk), all operations related to constructing or updating the tree are delegated to the NodeStorageProtocol
.
节点实例是不可变的。 通过“孤立”一个节点并将其替换为另一个节点,可以对树的结构进行任何更改。 鉴于这可能需要执行某些存储操作(例如,由于在将更改存储到磁盘之前缓存更改),所有与构建或更新树相关的操作都委托给NodeStorageProtocol
。
While the protocol does not enforce immutability of the structures conforming to the protocol, we expect that a node’s hash
, height
and size
are set upon creation of the node.
尽管该协议并未强制遵守该协议的结构保持不变,但我们希望在创建节点时设置节点的hash
, height
和size
。
A NodeProtocol
compliant structure also benefits from the implementation of the Merkle proof for a given leaf node or a range of leg nodes.
符合NodeProtocol
结构还受益于针对给定的叶节点或一系列分支节点的Merkle证明的实现。
NodeStorage协议 (NodeStorageProtocol)
The NodeStorageProtocol
lives hand in hand with the NodeProtocol
. It abstracts how the tree is built and maintained, and by implication how and when the nodes are created and stored. There are three important tree level operations which are provided for structures conforming to the NodeStorageProtocol
:
NodeStorageProtocol
与NodeProtocol
。 它抽象化了树的构建和维护方式,并暗示了如何以及何时创建和存储节点。 为符合NodeStorageProtocol
结构提供了三个重要的树级操作:
recursiveSet()
and recursiveRemove()
are respectively setting (adding or updating) or removing nodes.
recursiveSet()
和recursiveRemove()
分别是设置(添加或更新)或删除节点。
balance()
performs the balancing of the tree upon setting or removing of nodes. It is interesting to note that the balancing algorithm has been unrolled (we do not factor out leftRotate()
and rightRotate()
functions) to remove the need for creation of temporary nodes⁶.
balance()
在设置或删除节点时执行树的平衡。 有趣的是,已经取消了平衡算法(我们不考虑leftRotate()
和rightRotate()
函数),从而消除了创建临时节点的必要。
Having these primitives as part of the NodeStorageProtocol
instead of the NodeProtocol
allows that structure to keep track of the changes to the tree between versions.
将这些原语作为NodeStorageProtocol
一部分而不是NodeProtocol
一部分,使该结构可以跟踪版本之间树的更改。
A structure complying to the NodeStorageProtocol
is the entry point to versioned iAVL+ trees. Therefore the protocol provides ways to access the root node at a specific version. The protocol also provides, as syntactic sugar, access to the underlying node primitives to search and traverse the tree (which are provided by the Node
associated type implementation).
符合NodeStorageProtocol
结构是版本化iAVL +树的入口点。 因此,该协议提供了访问特定版本的根节点的方法。 该协议还提供对底层节点原语的访问(作为语法糖),以搜索和遍历树(由Node
关联的类型实现提供)。
键,值和哈希 (Keys, Values and Hashers)
The NodeStorageProtocol
and the NodeProtocol
make use of three associated types. These types are Key
, Value
and Hasher
.
NodeStorageProtocol
和NodeProtocol
使用三种关联的类型。 这些类型是Key
, Value
和Hasher
。
Providing associated types gives us the flexibility to allow specialisation of the Storage and Node implementations to the specific uses cases we are working with. In particular, it gives us the capability to delay the choice of specific data structures until we have the need to optimise them.
提供关联的类型使我们可以灵活地将存储和节点实现专门化为正在使用的特定用例。 特别是,它使我们能够延迟选择特定数据结构,直到我们需要对其进行优化为止。
键和值 (Keys and Values)
We require Key
s to be Comparable
, so that we can decide where a new value will be added in the tree.
我们要求Key
为Comparable
,以便我们可以决定将新值添加到树中的何处。
Compliance to the Codable
protocol for both Key
s and Value
s is to allow serialisation and deserialisation of the tree for the purpose of sharing the tree or parts of it across blockchain nodes.
对Key
和Value
都遵循Codable
协议的目的是允许对树进行序列化和反序列化,以便在整个区块链节点之间共享树或树的一部分。
Finally, compliance to the DataProtocol & InitialisableProtocol
is required to allow both Key
s and Value
s to be implemented using optimised bytes type of structures if needed. We basically want to leave the specific choice of structure for bytes to the implementer of the tree.
最后,需要符合DataProtocol & InitialisableProtocol
的要求,以允许在需要时使用优化的字节类型的结构来实现Key
和Value
。 我们基本上希望将树的字节结构的特定选择留给树的实现者。
哈舍尔 (Hasher)
The Hasher
complies to the HasherProtocol
which encapsulates the hashing function required to calculate the Merkle hashes for each node (depending on whether the node is a leaf or an inner node).
Hasher
遵循HasherProtocol
,后者封装了计算每个节点的Merkle哈希所需的哈希函数(取决于该节点是叶节点还是内部节点)。
The HasherProtocol
also provides a Hash
associated type. Between Key
, Value
and Hash
, this allows us to clearly express and statically check the different types used throughout the tree implementation.
HasherProtocol
还提供了与Hash
相关的类型。 在Key
, Value
和Hash
,这使我们可以清楚地表达和静态检查整个树实现中使用的不同类型。
A default implementation (as provided as part of the test suite) uses a SHA256 hash, however, moving to any other implementation is a trivial specialisation of the Node (and therefore Storage) using the relevant structure implementing the HasherProtocol
.
默认实现(作为测试套件的一部分提供)使用SHA256哈希,但是,使用实现HasherProtocol
的相关结构,转移到任何其他实现是对Node(并因此对Storage)的HasherProtocol
。
将所有这些放在一起 (Putting all of this together)
To bring this all together, we will show in an upcoming post how to implement a custom Storage. For instance, one which provides a configurable caching strategy. As part of the caching strategy, we could envisage limiting the amount of memory used, or providing a sparse persistent storage of versions of the tree.
综上所述,我们将在下一篇文章中展示如何实现自定义存储。 例如,提供了一种可配置的缓存策略。 作为缓存策略的一部分,我们可以设想限制使用的内存量,或者提供树的版本的稀疏持久存储。
The code lives in the CosmosSwift github organisation, and is released with an Apache License.
该代码位于CosmosSwift github组织中 ,并与Apache许可证一起发布。
We welcome contributions from anyone, so long as they respect the rules set forth in each repository. However, in the next few months we expect the code to evolve rapidly⁷ and would request contributors to bear with us until we can freeze the APIs.
我们欢迎任何人的贡献,只要他们尊重每个存储库中规定的规则即可。 但是,在接下来的几个月中,我们希望代码会Swift发展⁷,并要求贡献者与我们合作,直到我们冻结API。
In the meantime, feel free to reach out to us with questions, suggestions, and feedback. We will be delighted to hear your views!
同时,请随时与我们联系以提出问题,建议和反馈。 我们很高兴听到您的意见!
You can contact us via our dedicated Github repos, or by email at CosmosSwift [_a_t_] katalysis.io.
您可以通过我们专用的Github存储库或通过CosmosSwift [_a_t_] katalysis.io发送电子邮件与我们联系。
—
-
[1]: The implementation is partial due to the uncertainty around Amino over the last months. In itself for a fresh implementation, we do not believe it is a problem as Amino is used for two purposes: 1. Hash generation for the tree nodes, 2. Serialization and deserialization of internal structures. The former is important for tree consistency and the later for inter node communications.
[1]:部分实施是由于最近几个月Amino周围存在不确定性。 就Amino的两个目的而言,我们本身并不认为这是一个问题,因为Amino用于两个目的:1.为树节点生成哈希; 2.内部结构的序列化和反序列化。 前者对于树的一致性很重要,而后者对于节点间的通信很重要。
[2]: The Tendermint implementation can be found here: [https://github.com/tendermint/iavl]
[2]:Tendermint实现可在以下位置找到:[ https://github.com/tendermint/iavl ]
[3]: A merkelized tree is a tree where each node contains a hash based on its direct children in the case of an inner node and its payload in the case of a leaf. (see Wikipedia/Merkletree)
[3]:merkelized树是一棵树,其中每个节点在内部节点的情况下基于其直接子节点,在叶子情况下根据其有效载荷包含哈希。 (请参阅 Wikipedia / Merkletree )
[4]: The specifics of which parts of the IBC protocol are dependent on where the IBC specification is at time of implementation.
[4]:IBC协议哪些部分的细节取决于IBC规范在实施时的位置。
[5]: The current implementation mostly discourages own implementations of the primitives we provide as they are defined as static dispatch. Depending on the use cases, we are open to moving them in the main protocol requirement at a later stage.
[5]:当前的实现通常不鼓励我们提供的原语的自己实现,因为它们被定义为静态分派。 根据使用情况,我们愿意在以后的阶段将它们移到主要协议要求中。
[6]: Furthermore, it allows us to enforce the calculation of the hash, height and size on creation of the node rather than delay until we know that the node is really part of the final tree.
[6]:此外,它使我们能够在创建节点时强制进行哈希,高度和大小的计算,而不必延迟直到知道该节点确实是最终树的一部分。
[7]: Our current target for completing milestone 2 is Q320, and for completing milestone 3, Q420.
[7]:我们目前的目标2是Q320,而目标3是Q420。
翻译自: https://medium.com/katalysis-io/bringing-the-cosmos-sdk-to-swift-65d5fed5136d
cosmos sdk