就像我们没有区块链

我们如何使用智能合约构建用于选择IT MTS中最佳技术项目的系统?我们陷入了什么“陷阱”,但是能够摆脱困境,最终证明可以在移动设备上维护分布式注册表!



为什么需要基于区块链的系统?


让我们从头开始。MTS有着悠久的传统-选择一年中最好的技术项目并奖励其团队。该团队获得了奖项,尊重和名望。多年来,各种项目已成为赢家:从高负载的电信系统到人工智能系统。

最佳项目的选择总是分几个阶段进行:

  • 团队申请
  • 投票选举受人尊敬的技术专家
  • 经过专家,项目由经理选择
  • 在所有阶段完成后,大老板选择最佳项目。

我们认为该方案对参与者而言不够透明,并认为:为什么不给公司中的所有专家提供选择最佳技术项目的机会? 


如果我们在电话上实现此机会,我们将看到项目的当前评级以及谁投票给谁-这将确保流程的完全透明性。

我们阅读了几篇有关区块链的文章,关于构建分布式注册表系统的想法牢牢地扎根于我们的脑海。但是,如果我们在此处应用智能合约该怎么办?

以下属性吸引了我们:

  • 开放性-没有单个服务器可以在其中操纵信息;
  • 放置在分布式注册表中的信息将永远保留在那里;
  • 信息不能伪造(嗯...实际上)

不是区块链




不应将区块链本身用于此类选举。但是,如果我们采用在分布式系统中建立共识的协议并将其应用于在人际关系中达成共识的情况呢?

鉴于我们将不得不在开放的网络中工作,我们需要保护自己免受非拜占庭式攻击和用户设备信息的替代。

有哪些选择


最著名的协议是PAXOS。它缺少明确的领导者,所有更改都经过两阶段提交。在每次更改的开始,都会发生提议。如果成功,则发送接受。


该算法的一个特征可以称为以下事实:它使用全局计时器来确定较早生成的请求,并且进行更改的节点应与网络的所有节点进行通信。在此处阅读有关算法的更多信息

该算法已在许多地方使用,例如在Cassandra DBMS中。就该任务的实现复杂性而言,我们不喜欢该协议。但是第二个选择是我们-RAFT。实际上,这是PAXOS协议的发展,具有明显的领导者。

简化的协议可以描述如下:
·正在建立彼此了解的设备网络;
·设备在他们之间选择做出“重要决定”的领导者(例如,向注册表添加条目或更改网络的组成);
·领导者设备负责在整个网络中分发信息,以便在任何地方都是相同的;
·领导不再履行职责时,请选择新的领导。

这里阅读该协议

我们的实施


我们在做什么,为什么世界上又有一辆自行车? 


我们注册表的几乎所有用户都拥有几乎始终在线且始终在线的移动设备,并且实际上几乎总是在使用它们,因此我们决定在移动设备上而不是在服务器基础结构上运行分发注册表算法,就像其他众所周知的实现一样。

让我们看看我们陷入了什么“陷阱”,但是我们设法摆脱了……

陷阱1:“我的地址不是住所也不是街道”


“突然”事实证明,要构建一个使用RAFT协议实现分布式注册表的P2P网络以进行数据复制,每个设备都可以彼此通信,这意味着它既是客户端又是服务器。因此,我们需要为每个手机提供一个公共的“白色” IP地址(可能不是)。

实际IPv4的数量非常有限,因此电信运营商在PAT(端口地址转换)模式下使用NAT(网络地址转换)技术,将内部网络的多个IP地址(分配给订户)转换为一个外部公共IP地址。因此,排除了接受来自Internet的传入连接的能力。

好消息是有很多IPv6! 


基本软件包中包含IPv6支持。而且,所有现代电话都支持IPv6,并且运营商为订户分配了一个公用的“白色” v6地址。我们的选择是IPv6。

陷阱二:每个人都去睡觉


与服务器不同,手机有时仍会关闭。我们在测试第一个原型时发现了这一点。另外,运营商提供的IPv6地址是公共的,但不是静态的,每个新的通信会话都是一个新的地址。移动设备的地址可以随时更改。而且,如果在网络上没有一个电话具有我们已知的地址,它就不复存在了(没有任何连接可以“增加”它)。因此,我们不得不在某种程度上违反我们的“无服务器”规则。我们在云中创建了一个带有静态已知地址的特殊节点。它的任务是记住/更新网络的组成而不关闭。也就是说,这是一个普通站点,没有人会投票,然后转到它,您始终可以获取所有网络参与者的当前地址列表。

3: 



必须以某种方式解决问题,以便不是每个人都可以投票支持项目,而是需要的人。第一个想法是:维护专家电话号码数据库。但是他们拒绝了,因为他们不想授予应用程序访问此信息的权利。
结果,他们使一切变得简单:他们决定提供每个声音,每个注册表项在时尚的椭圆曲线上都带有数字签名,这将决定记录的真实性。将WEB服务放置在公司网络上,公司服务通过域授权确定专家,并使用公共和私有加密密钥(当然是在客户端)为他生成唯一的QR码。专家扫描了应用程序中的代码并进行了连接。此后,当前版本的注册表在他的手机上“汇总”,出现了投票的机会。

4: Android 
 



在测试期间,几乎“突然”发现一些用户是运行iOS操作系统的移动设备的知名模型的所有者。很明显,我们的注册软件应在不同的平台上运行。我们使用Kotlin编程语言,它不仅“时髦,时尚,青春”,而且具有多种平台

Kotlin中的多平台概念意味着存在一部分通用代码和特定于平台的代码,但是由于我们团队的资源有限,我们为自己设定了一个艰巨的任务,那就是在所有平台上使用单一版本的源代码!当然,每个平台的可执行模块都必须是本地的。 Kotlin有能力做到这一点

说到做到!我们只有一个带有源代码的SourceSet,使用“ depends” fitOn从中收集所有平台的二进制代码(!)凉?很酷!

陷阱5:移动通讯并非免费 



我们如何才能最有效地实现网络节点之间的交互,以免花费所有订户的流量,又不会耗尽移动设备的电量?我们假设网络可能包含1000个或更多设备!最明显的选择是,例如,在“领导者”选择过程中或发送无数据的心跳信号时,使用UDP而不是TCP。 UDP更经济,因为它使用简单的数据传输模型,而无需“握手”和确认。精细!还有什么?当然是异步I / O!

我们仔细阅读了Kotlin Native的文档。

对于所有基于Unix或Windows的目标(包括Android和iPhone),我们提供posix平台库。它包含对平台的POSIX标准实现的绑定。

然后,我们还仔细阅读POSIX标准文档,并找到了一个惊人的功能该功能使我们能够以非阻塞模式处理套接字事件!投入了协程,套接字和C Interop的美好世界之后,我们得以实现非常高效的运输。超!

并以什么形式发送数据? 



当然可以!

幸运的是,紧凑的二进制数据格式已在多平台库kotlinx.serialization中实现太棒了!

陷阱六:序列化 



这次,确实意外地发现kotlinx.serialization不在androidNative下(当然,在androidJvm下)。来自JetBrains的亲爱的同事们已经确认,目前他们还没有为androidNative构建库,并且在Kotlin 1.4发行之前,路线图中不再有此任务。 


该怎么办?如果山不去穆罕默德,穆罕默德就去山!

我们自己为所有平台(包括androidNative)编译了kotlinx.serialization!最神奇的是,它起作用了! 


陷阱7:将日志存储在哪里? 



显然,在嵌入式键值存储中,但是在哪?我们选择lmdbx的原因在于代码的紧凑性,速度,多平台以及缺少WAL文件。该库是由Positive Technologies的人员开发的,并且源于OpenLDAP Howard Chu一位作者的传奇LMDB反过来,这又是基于Martin Hedenfalk的B +树的实现。顺便说一句,开箱即用,该库不是为androidNative构建的。我们仔细收集了所有错误,作者迅速提供了修复程序-特别感谢他们!

陷阱八:C互操作 



事实证明,将所有内容放在一起并不是一件容易的事。除了lmdbx和posix套接字,我们还集成了用于生成/验证椭圆曲线上的数字签名以及使用令人惊叹的C Interop机制计算SHA256的库。用简单的话来说-从Kotlin上的本机应用程序中,您可以调用C库函数,包括带有指针的指针和其他魔术,这一切看起来有些奇怪。

例如,调用getaddrinfo以获取sockaddr。



您如何喜欢Ilon Mask?

将C库链接到Kotlin Native可执行文件是一个单独的任务,我们也设法解决了这个问题,但并非没有cru脚。我们直接在构建脚本中动态形成def文件,以指示相对于项目根目录的库的正确路径,然后在cinterops部分中替换其(def文件)描述符。在def文件本身中,仅确定绝对路径,如果在不同的OS下执行汇编,则不仅可以具有不同的格式,而且实际上在开发人员的本地计算机上也可能有所不同,这显然会导致链接期间出错。

关于选举


我们白天举行的主要选举。大约有20多位专家参加了使用我们网络的测试。在5个类别中对21个项目进行了评估,也就是说,将100多个具有项目投票的条目添加到了注册表中。

结论


由于这项小型研究项目,我们能够证明在移动设备上维护分布式注册表是可能的!这为在物联网设备上使用此技术组织边缘计算计算开辟了许多可能性。我们前面的人仍在等待负载测试,易受攻击和容错能力。但是我们相信我们会成功!

本文作者:MTS Dmitry Dzyuba,Alexey Vasilenko和Semen Nevrev研发中心的架构师和开发人员

All Articles