
6月10日是我们在香港适应环境的第三天。 在过去的26个小时中,我们几乎没有睡觉,就在EOS Global黑客马拉松的第一阶段开发了一个名为SensorPay的原型项目,总奖池达到了一百五十万美元。 评委们临近之前,该项目的示范时刻。
如果您想了解这个故事的结局,请立即查看最后一部分。 同时,我们将开始系统地讨论EOS技术以及如何将IoT的付款与EOS链接的想法。 之后,将详细介绍该项目的技术填充。
0.背景
EOS是新一代区块链,甚至有人认为它是以太坊杀手。 如果突然之间您不知道什么是区块链或以太坊,谷歌将提供帮助。 碰巧的是,大约一年前,我们开始研究EOS,包括研究其作者BitShares和Steem的先前产品。
与以太坊相比,EOS的优势:交易吞吐量高出三个数量级; 开发智能合约许可系统; 恢复丢失的访问并修复区块链中的错误的能力; 链上网络管理。 弱点:集中化问题,可能更脆弱的DPoS共识,原始代码以及对开发人员而言更陡峭的学习曲线。
由于我们很久以来一直喜欢这项技术,并认为它很有希望,因此我们不能忽视EOS作者支持的一系列黑客马拉松。 我们只是想在那里,在这个鼓舞人心的环境中实现我们的想法,并与广大观众分享。 当然,赢得好钱的机会也成为了另一个令人愉悦的动力。
因此,EOS是我们知道在哪里可以进行许多交易的公共区块链唯一可行的解决方案。 在哪里需要? 当然在物联网! 的确,如果每个烤面包机变成小额付款,它将为冰箱中的每块面包付款(根据您的了解,默认情况下这很酷),将会有很多交易。 更不用说在医学,工业和日常生活中的各种其他应用。
黑客马拉松的前几周,另类的想法定期出现,并进行了小型头脑风暴。 我们根据著名的裁判标准对概念进行了比较:EOS功能的使用,创造力,公共影响力和可扩展性。 结果,我们选择了IoT + EOS-一种可以从传感器中获取数据并将大量付款交易发送到EOS的解决方案。
顺便说一句,我们真的很想在这里讲述我们如何提高EOS的Block Producer。 他们计划如何为他刷新类似于ERC721的令牌的构造函数并支持常量函数; 他们如何提交Merkle Root ACL协议。 但是所有这些都不适合本文,因此我们将返回到主要项目。

1.准备
1.1。 物联网
准备项目的物联网部分是选择正确的硬件。 在RFID阅读器的作用下,选择了在SPI总线上运行的RC522:它很流行且易于使用。

在搜索计数器时,我们专注于脉冲输出的存在,因为它使您可以非常简单地读取数据:一个脉冲为X kW·h(其中X取决于型号),因此,我们在Mercury 201.5计数器处停止了运行。

最困难的事情是决定控制器,该控制器应从传感器收集数据,进行交易,使用私钥对其进行签名并将其发送到网络。 因此,我们需要一种带有网络模块的设备,该设备可以使用ECDSA签名交易(在这种情况下,在椭圆曲线secp256k1上,因为它在EOS中用于签名)。
最初,选择权在于ESP8266微控制器,它具有Wi-Fi模块和用于连接传感器的所有必需接口。 同时,它非常紧凑。 但是,没有一个固件具有椭圆基元的本地实现。 可以编写您自己的实现,但这不是黑客马拉松的任务。 结果,选择了Raspberry Pi 3 B作为原型,并使用eosjs库生成和签名事务。

1.2。 基础设施
在黑客马拉松的前几天,我们在本地和eos-hackathon.smartz.io服务器上准备了一个EOS程序集( 源 )。 对于这样一个年轻的项目(使用文档 ),依赖项的安装,组装和测试非常顺利。 没有足够的时间来准备其他基础结构,在黑客马拉松期间我已经不得不处理它。
1.3。 建筑学
在黑客马拉松的前夕,我们讨论了体系结构并阐明了产品详细信息。 我们将实现以下主要情况:用电付款和用RFID标签标记的购货付款。 他们还计划使该产品易于扩展,并在其他领域使用。

体系结构的思想是服务提供者(生产者)创建一个合同-供应商和消费者之间交互的中心点。 每个消费者都有自己的余额,可以补充该余额,并根据传感器信号从中扣除资金。 所有数据-用户,传感器,统计信息-都存储在供应商的合同中。
用户首选项与消费者或标志(例如,优先用户类别) user_meta
。 消费者可以连接多个传感器,每个传感器都标有合同和账单设置( billing_meta
)。 因此,您可以获得一份不变的无状态计费合同,该合同适用于大量消费者; 调用bill(payload, user_meta, billing_meta)
方法时将显示必要的数据bill(payload, user_meta, billing_meta)
。 另外,还提出了不同的计费逻辑,即不同的合同的可能性:例如,一个考虑电力,另一个考虑货物。 每个传感器都有一个计费指示器的“指针”。
假定消费者信任传感器制造商,但不一定信任服务提供商。 与传感器交互的界面非常简单:它是对带有数字参数的供应商合同方法的调用,该参数将被转移到开票。 服务提供商使用控制交易(原始设置程序)启动消费者,传感器,计费合同及其合同中的关系。 从传感器接收到交易后,将检查数据,生成用于计费的数据,调用计费,记录付款并记录统计信息。
也许最重要的是,我们讨论了以下对产品在现实世界中的适用性很重要的问题:
- 预付款还是后付款? 重新填充您的帐户并使用它(例如蜂窝连接)-还是使用它,然后还清(例如AWS)? 这里没有对与错的答案:不同的企业喜欢不同的模型。 为简单起见,我们决定收取预付款。
- 用户应该为每个供应商保留一个单独的帐户,还是所有费用都来自一个帐户? 再说一次-没有对与错的决定; 此外,答案与上一个问题的答案密切相关。 预付款是拥有个人消费者帐户的好朋友-他们被收取了。
- 收取EOS费用,服务提供商的代币或稳定的硬币(绑定法定货币)? 当然,由于价格波动,除了稳定币以外的其他选择对于消费者而言是不便的,并且在EOS框架内尚不存在稳定币。 那时,甚至没有主要的EOS网络! 为简单起见,他们采用了条件标记。
2.编码
首先,他们指定了API和供应商合同的框架,以便同时开始开发前端,设备代码,账单和主合同( 源 )。
2.1。 物联网
第一个实现用于从计数器读取脉冲的代码的人。 为了使用GPIO(通用引脚),使用了onoff JS库。 后来,为了清楚起见,在电路中添加了两个LED:第一个LED在从计数器接收到信号时闪烁,第二个LED在关于成功交易的答案来自EOS节点时闪烁。 同样,我们开发了一种读取RFID标签的方案和代码,唯一的区别是:使用MFRC522-python库在SPI总线上进行了读取。 事实证明,Raspberry Pi 3的SPI设置与早期主板型号的设置不同; 该说明有助于我们理解。
这些设备由移动电源供电,移动电源已成功呈现给所有黑客马拉松的参与者,而且它们必须与iPhone 5共享互联网本身,因为黑客马拉松的Wi-Fi仅在5 GHz上工作,这不适用于Raspberry Pi。
2.2。 基础设施和公用事业
组织者建议采用eos-dev的docker镜像,但是由于缺乏对该镜像的描述和文档,我们感到困惑。 在服务器上,他们继续使用准备好的程序集,并在本地使用eos-dev来避免系统地安装EOS。
迫切需要快速构建和测试的能力。 理想选择:构建并运行本地可执行文件。 但是,无法忽略这样的事实,即在组装之后,输出需要WebAssembly,并且在EOS环境中需要相应的boost,库,系统协定。 可以在eosiocpp.in中窥探必要的编译选项,但是,我们决定不玩此游戏。 预测结果,尽管稍慢一些,但比具有潜在耙的快速解决方案更为重要。 因此,对于组装,我们使用了eoscpp,它位于eos-dev容器中。
事实证明,发布变得更加困难,我不得不提升本地的EOS区块链,再次没有现成的解决方案。 仅软件。 因此,启动基础结构的第一个版本出现了。 这样做的想法是隐藏安装和配置的细微差别,并为典型的动作获得由四个到五个“按钮”组成的自洽集合。 更少的控制,但是出错的机会更少,并且节省了时间。
EOS的主要组件包括nodeos,keosd守护程序,cleos控制台实用程序和eoscpp编译器:
- nodeos-EOS节点,守护程序-网络参与者,提供对区块链的访问并可以选择生成新块;
- keosd-一个守护程序,用于管理存储密钥对的本地钱包;
- cleos提供从获取有关事务的信息到使用密钥的命令;它是基于nodeos和keosd中通过HTTP API的调用而实现的;
- eoscpp将合同编译为WebAssembly,还允许您基于源代码获取应用程序二进制接口。
立刻清楚的是,与keosd调用相关的cleos命令不起作用。 由于发布了表明keosd网络无法访问的错误,因此我们花了一些时间来诊断docker网络中的网络问题。 但是,strace显示它不是网络:cleos访问了错误的地址,始终是本地主机(对于我们的基础架构,不同的守护程序在单独的docker网络中具有不同的网络地址)。 在cleos中诊断出一个错误 :检查keosd可用性(该操作在与钱包相关的任何命令之前执行)都考虑了参数中传递的端口,但不考虑地址。 在黑客马拉松下,我们作为解决方法切换到了docker中的主机网络。
下一步是使用容器( commit )中的编译器的合同编译实用程序。 输入和输出目录已安装。 最后,可以将合同上传到区块链并发送交易( commit )。 再次-统一风格的实用程序,简单的“按钮”。 这就结束了基本的基础架构,但是惊喜仍然存在:我们偶然发现了用于处理内存的C函数的问题(下面将详细介绍)。
总而言之,他们开始在一个文件中建立账户(每个合同和参与者需要单独的账户),以及在区块链启动时自动创建的密钥对,以便一个团队可以提高测试环境。 此环境的一个副本已部署到eos-hackathon.smartz.io。
2.3。 智能合约
2.3.1。 供应商合同和电费账单
黑客马拉松开始后,我们开始按照上述方案布置合同的结构。 该系统由以下合同组成:
supplier
- supplier
合同;billing_electricity
用于计算电表的每个刻度的电费的合同。
在supplier
合同中,大部分工作是通过普通的CRUD操作执行的:添加用户,费率,柜台,增加或减少用户的余额。 更为复杂的方法负责从电表接收数据,调用合同以计算付款(计费),在从计费合同中收取回款后从用户的个人帐户中扣款。 根据用户的资费确定必要的计费合同。
在调用计费合同之后,计算了付款,并调用了从用户的个人帐户中扣除付款的方法。 抛开主要逻辑后,我们甚至考虑过是否做的合同太简单。 不久之后,在节点中部署了合同并对其进行了测试之后,很明显,合同可能很简单,但存在细微差别。 :)
部署之后,事实证明,彼此之间预期的合同调用不起作用。 权限不足。 与Ethereum中的智能合约不同,在EOS中,智能合约是从调用合约中以调用合约的名义被调用的,而整个链则始于交易的发起者。 从合同中调用合同时,将检查发起方是否允许合同执行此操作。
导师立即建议如何在一个简单的案例中采取行动。 权限添加如下(通过调用eosio系统智能合约):
./cleos push action eosio updateauth '{"account":"electricity","permission":"active","parent":"owner","auth":{"keys":[{"key":"EOS7oPdzdvbHcJ4k9iZaDuG4Foh9YsjQffTGniLP28FC8fbpCDgr5","weight":1}],"threshold":1,"accounts":[{"permission":{"actor":"supplier","permission":"eosio.code"},"weight":1}],"waits":[]}}' -p electricity
在这种情况下, electricity
账户允许supplier
合同代表其调用其他合同。 您可以在Technical WP EOS中阅读有关权利的更多信息。 在我们国家,由supplier
合同引起billing
合同,又又称supplier
。 用这种形式的权利类推添加无效:
./cleos push action eosio updateauth '{"account":"electricity","permission":"active","parent":"owner","auth":{"keys":[{"key":"EOS7oPdzdvbHcJ4k9iZaDuG4Foh9YsjQffTGniLP28FC8fbpCDgr5","weight":1}],"threshold":1,"accounts":[{"permission":{"actor":"supplier","permission":"eosio.code"},"weight":1},{"permission":{"actor":"billelectro","permission":"eosio.code"},"weight":1}],"waits":[]}}' -p electricity
发出错误:无效的权限。 在这里,导师不再能为我们提供帮助:他们说自己没有这样做。 和谁干的? 也许只有丹·拉里默(Dan Larimer)。 我们无法迅速找到EOS代码中的错误原因,并且已经开始考虑其他选择,而没有一系列的调用。 很好地防止了EOS中调用其他合约的机制也不同于以太。 调用另一个合同时,此调用将排队,并且仅在当前调用完成后才能完成。 调用合同以及调用后读取该合同记录的数据将无效。
毕竟,他们后来在EOS代码中发现了设置两个合同的权利时出错的原因。 事实证明,权限列表中的帐户应按帐户进行排序: 确保所有键都是唯一的并且已排序,并且所有帐户的权限都是唯一的并且已排序 ( Authority.hpp )。 更改帐户的顺序后,权利的更新开始了,我们的合同系统开始运作。
2.3.2。 带记忆的C功能问题
这太荒谬了,但是最后我们无法使用现成的函数来解析数字(!)来读取计费配置。 在std::istringstream
函数被拉起,这很奇怪。 而当使用atof
之类的东西以及sscanf
, env.realloc
拉紧了。 由于某些原因,在nodeos中的代码加载期间未找到上述与标准C库的内存一起使用的功能。 使用内存的C ++函数正常工作。
当然,在执行WebAssembly合同时,不使用标准的内存分配器,而是使用其自己的沙箱,该沙箱在特定条件下提供给每个事务。 此外,对在此沙箱顶部使用内存的C函数的支持已经实现了很长时间,它们的实现是在标准EOS合同中进行的 。 在链接阶段可能出了点问题。
在花了一个小时的时间寻找出路之后,包括在一位指导者的帮助下,我们决定不再继续并采取解决方法:编写自己的代码来解决解析数字的问题。 数据流EOS机制不适合我们:它需要具有将不同结构的数据包保存在一个字段中并手动形成它们的能力(非常计费的配置)。
2.3.3。 购物帐单
在第二轮风中,这是由电力工程师打开的或者是由早早餐打开的,他们写下了在商店购物的账单 。 总体工作方案如下:
- 供应商创建一个开票合同并在其总合同中对其进行规定。
- 在商店的商店,供应商建立了可以读取RFID,与EOS交互并在开票合同中规定自己帐户的框架。
- 商店中的每个产品都配备有RFID标签,所有标签均已在计费合同中进行了注册。
- 买方通过扫描RFID来支付商品费用,然后将商品从开票合同中删除。
- 在商店的出口处,框架还读取RFID采购信息。 如果货物仍在商店中,则交易不会通过,并且框架会发出警报(是的,实际上,您甚至无法发送交易,而只需阅读表格即可)。
仅仅关注合同代码本身是没有道理的:这是带有某些EOS特定结构和库的标准C ++ 14。 最好在EOSIO Wiki和EOSIO开发人员门户网站上说 。
2.3.4。 前端
该项目的前端部分是使用React实现的。 许多Redux决定使用MobX,而不是通常的做法,这大大加快了开发速度,并使您可以轻松管理全局状态。
前区块链整合阶段的进展不如预期的顺利。 eosjs包正在非常积极地定稿,随后是Scatter浏览器的EOS钱包。 在这一堆中,这经常会引起问题。 并不是昨天工作的代码今天能正常工作的事实。 我们踩到了这个耙子(不是第一次)。 一个小时的沉睡状态下尝试和调试-问题已解决。
考虑应用程序客户端与eos交互的简化图。 为此,您需要eosjs库和Scatter浏览器扩展。
我们提醒您! eosjs之后,Scatter会主动更新,不要忘记更新库。
接下来,简要阅读阅读和写作。 与EOS中的智能合约进行通信的方式有两种:发送交易(这会导致区块链被修改,没有提供返回值)和读取表(只读操作)。
考虑交易发送代码:
sendTransaction(funcName, data) { return this.scatter .suggestNetwork(this.network) .then(() => this.scatter.getIdentity({ accounts: [this.network] })) .then((identity) => { let accountName = this.getAccountName(identity); // wrap eos instance const eos = this.scatter.eos(this.network, Eos, this.configEosInstance); return eos.transaction(accountName, (contract) => { contract[funcName](data, { authorization: accountName }); }); }); }
输入参数:函数名称和对象,其值是该函数的参数。 第三行:我们确认与EOS交互的网络。 第四行:我们得到了identity
,参数是一个带有accounts
字段的对象(对于该网络)。 getAccountName
函数从接收到的帐户列表(在identity
对象中)返回第一个帐户。
在此示例中,Scatter用于签署交易。 Scatter是Eos
类实例的包装。 在第9行,我们调用eos
方法,其参数为:
this.network
具有网络参数的对象。Eos
是eosjs的一个实例。this.configEosInstance
一个带有Eos实例参数的对象(请参阅Dock eosjs)。
最后一种transaction
方法接受accountName
和callback
作为输入, callback
参数是位于accountName
的合同。 在callback
'e中,我们用对象调用接收到的合同的方法,其键是被调用方法的参数。
考虑读取表的方法:
readTable(data) { this.eos = this.scatter.eos(this.network, Eos, this.configEosInstance); return this.eos.getTableRows({ json: true, limit: 1, ...data, }); }
在这里阅读,我们只需要一个eos
实例。
为了设计界面,我们放弃了Materialize,Semantic和Ant,自行设计了样式。 在黑客马拉松的最后几个小时中,出现了一个想法,可以复兴UI,并添加可视化过程。 用绿色突出显示表格的新行两秒钟,并获得了不错的股票报价效果。 改进显着提高了项目的吸引力,并成为构建UI的最后阶段。
3.组装
在时间结束前三个小时,我们安装了带有Mercury电表的Raspberry Pi和与其相连的RFID阅读器,以及一个指示灯。 餐桌上的所有电能都通过了水星。 对于每花费0.3125 Wh / h以及每一次“购买”,Raspberry Pi将交易发送到我们的区块链,服务提供商可以管理用户,传感器,计费并查看消费统计信息。

又过了一个小时,我们冷静地进行了检查并添加了最后的修饰。 时间结束前两个小时,我们收到了完整的产品,其中包含两个已实现的案例,充分说明了该概念,甚至在最后几分钟内都没有提交!
4.示范
项目的演示(又称沥青)包括两个阶段。 在第一阶段,将69个参赛队分为四组,每组分别由两名评委组成,没有观众。 评委给出分数(四个标准,每个分数5分),并根据这些分数,选出前10名球队进入第二阶段。 这些团队有机会在观众和所有八位评委面前大型演出。
我们进入了第一组,我们的评委是Everipedia的首席执行官和总裁(我想知道这些职位有何不同)。 安排了三分钟的表演时间,并由计时器严格监控。 我们完成了前后矛盾,但要求提前30秒给讲话留下深刻印象。 法官们肤浅而短暂地提出了要求,示威活动已经结束。
天真的,我们感到惊讶的是,我们没有关注产品的实际工作能力,甚至没有关注法官的法规。 技术实施问题即使在丝毫程度上也没有引起他们的兴趣。 我们也可以在前面显示闪烁的Raspberry Pi灯泡和图片。
感觉到项目的介绍使我们失败了,因为我们希望给实际的解决方案,原型留下深刻的印象,而不仅仅是对一个具有社会意义和雄心勃勃的项目的丰富多彩的描述。 一切都像记笔记一样发挥作用:我们描述了问题,痛苦,解决方案,展示了其工作原理,并描述了该项目的开发计划。 事先了解判断方法,我们会做很多不同的事情。
比赛结束15分钟后,第一轮比赛的四支裁判降低了得分并交换了意见。 获奖者宣布后开始。 大厅里充斥着紧张的气氛:经过26小时的马拉松后,人们疲倦了,人们想要获胜,有很多强大的团队,他们知道自己可以赢得胜利。 我们知道这一点-等待结果。
为防止观众放松,结果分三部分宣布。 前四名决赛入围者,然后三名入围,再三名。 在公告与结尾之间-表演。 我们没有进入前十名,也没有机会进入大舞台。 两个说俄语的团队进入了前十名,其中一个最终成为了第三名。 祝贺获奖者,他们应得的奖品。
5.结论与计划
Hackathon的组织者AngelHack团队表现出色。黑客马拉松在最高级别举行,几乎没有抱怨。我们的奖品是一段愉快的旅程,有益的经验以及与强大的开发人员和导师的沟通。是的,我们希望有更多的技术裁判员,但是无论如何,我们完全理解获胜的机会只是一个机会。
在26小时内,我们设法通过EOS区块链为IoT支付框架准备了一个完整的工作模型。我们为这一结果感到自豪,并对它的价值,适用性和可扩展性充满信心。
— UI ( — -- Smartz ), . - , blockchain-ready , , — . :)

, , «», «» . . 5 . , 100 , . SensorPay !
:
Yuvasee (entrepreneur)
algs (hardware & backend developer)
therealal (architect, backend developer, devops)
bolbu (frontend developer)
quantum (blockchain & backend developer)