跳转至

潜入区块链-所有权的证明

在本章中,我们将通过创建一个所有权证明应用程序来介绍区块链的更广泛的应用。在本章中,我们将讨论区块链内部的智能合同的概念,以便实现这个应用程序。由于我们已经在本书的前几章介绍了区块链的概念,本章将主要关注智能合同的高级细节,即所有权证明和分散应用程序的创建。

在本章中,我们将重点讨论以下主题:

  • 创建所有权证明应用程序
  • 区块链智能合同的概念
  • 如何选择智能合约平台
  • 探索近地天体区块链平台
  • 在新区块链系统中创建分散式应用程序(所有权证明)
  • 探索以太坊区块链平台
  • 在区块链以太坊创建一个分散的应用程序(所有权证明)

在资产的世界里,如果你想要求并证明对它们的所有权,就有必要跟踪它们中的每一个。但是资产是由世界上不同地方的不同实体创建的,并且不存在管理资产的单一协议,因为每个实体都有自己的资产管理系统。例如,如果爱丽丝在一个城市有一套房子和一辆车,她想把房子和车都卖给鲍勃,因为她打算搬出这个城市,她必须通过不同的程序把所有权转移给鲍勃-她必须为房子办理土地注册,为汽车办理道路运输部门。

此外,她还指定了一名律师,因为程序相当复杂。她只有在与登记处、律师和公证处交涉后,才能最终将汽车和房子的所有权转让给鲍勃。不同资产的注册和管理所涉及的协议意味着 Alice 必须与不同的实体打交道来执行一个简单的任务。

当前的资产管理系统需要某些可信机构的批准。可信机构参与的主要原因是资产存在于不可信的社会中。不同的实体创建自己的一套处理资产的程序。一些实体可能正在使用过时的技术,使其难以使用,因为用户必须处理一些传统的程序。

本章中提出的所有权证明解决方案将使用区块链来构建一个分散的应用程序,以减轻集中式资产管理系统所面临的所有问题。在区块链技术的帮助下,我们将使用数字身份、资产和智能合同来创建一个完全分散的资产管理系统。

数字资产和身份

数字资产是以数字格式存在的可编程资产。这些资产可以有自己的价值(数字令牌),也可以虚拟地代表现有的物理资产(车辆所有权)。自数字时代开始以来,数字资产就一直在使用,但直到现在,它们一直存在于集中管理的环境中。区块链的发明允许数字资产存在于一个分散的网络中,在这个网络中,不需要任何可信的中介来注册或交易资产。取消中介意味着用户在交易资产时不必支付任何额外费用。

在处理资产所有权时,数字身份对数字资产至关重要。它以数字格式表示任何个人或组织的身份。数字身份基于公钥基础设施 ( PKI )为用户提供准确的身份管理。与容易被伪造的传统身份文件不同,数字身份要求用户通过数字签名进行认证,以证明他们的身份。该系统通常使用安全的密钥基础设施,这是不容易被破坏的。

我们在前面的章节中讨论了数字资产的声明;您还记得,我们讨论过为用户创建一个身份,用户可以用这个身份使用一个密钥来要求资产。这里将使用类似的方法来创建和管理平台中用户的数字身份,我们将使用该平台来构建本章中的应用程序。

所有权证明

世界上的每一项资产都由某个实体所拥有。部分资产的所有权可能无法证明,原因可能是部分所有权记录缺失,或者是现有记录的数据模糊不清。尽管所有权是由实体以数字方式或其他方式证明的,但在大多数情况下,所有权信息在所有系统中并不一致。通过保留数字记录来证明所有权是最好的解决方案,而数字资产和身份在其中发挥着巨大的作用。

数字资产和数字身份提供了一种便捷的方式来主张任何商品的所有权,因为资产是随着用户的身份以数字方式注册的。每当用户需要验证和证明资产的所有权时,他们可以提供他们的身份详细信息以及他们试图要求的资产。用户可能经常需要通过提供一些秘密信息或使用秘密信息进行身份验证来验证他们的身份。身份验证过程依赖于构建资产管理系统的第三方。在我们前面的例子中,Alice 想把她的房子和汽车卖给 Bob,她需要向土地注册和运输部门提供身份信息,然后通过与他们系统中的记录进行比较来验证这些信息。这种所有权证明系统的缺点是没有跨不同组织维护的适当协议。这就是为什么身份管理并非在每个系统中都是安全的,也是为什么组织仍然使用传统系统(如用户身份的硬拷贝)来验证身份,而没有适当的身份认证机制,这很容易被不良行为者利用。

一个完全安全的所有权证明系统可以通过使用数字身份来创建,它使用强认证来证明用户的身份。大多数实现这种所有权证明模型的现有系统是集中式的,这要求集中式主体是可信的。这种出处模型虽然解决了问题,但是需要用户完全信任第三方机构来证明和验证所有权。使用区块链创建一个分散的所有权证明系统是唯一众所周知的解决方案,可以解决所有关于资产管理和所有权证明的问题。由于其不变性和可追溯性,区块链是最适合资产管理的技术,因为一旦关于资产的一些信息被附加到区块链,就无法撤消。可追溯性使验证任何交易变得容易,如果担心隐私问题,还允许使用专门的区块链来限制交易。

虽然在分散网络中可以使用区块链来证明所有权,但在某些情况下,交易参与者之间可能存在一些复杂的协议。这些协议是双方通过订立合同而形成的。一个被称为智能合同的概念被用来在一个分散的网络中执行这一任务。我们将使用它来创建一个分散的所有权证明应用程序。

分散所有权证明应用程序的一个最好的例子是 Everledger ,它为钻石市场的供应链构建了一个所有权证明模型(https://diamonds . ever ledger . io)。Everledger 提供了一个全球数字区块链分类账,以跟踪资产的所有权历史。它试图防止钻石行业的欺诈行为,据估计,该行业每年的欺诈金额高达数十亿美元。

智能合同

合同是在各方之间创建的,以执行协议并确保参与者不能在以后否认协议。智能合约是一种协议,允许以自动执行的方式验证和执行合约。简而言之,只要合同条件得到满足,它就会执行双方商定的合同,而无需任何人的干预。智能合同这个术语是由密码学家 Nick Szabo 在 1994 年创造的。尽管智能合约在 20 世纪 90 年代初被概念化,以自动化传统合约的执行,但直到采用比特币的底层区块链技术后,它才在公共网络中实现。

正是拜占庭容错共识算法使得智能合约在分散的公共网络中的执行成为可能。许多现有的区块链平台提供了对图灵完整编程语言的支持,这使得创建构建智能契约所需的逻辑变得更加容易。

如果一种程序设计语言可以用来模拟图灵机,则称它是图灵完备的。比特币的脚本语言是故意让图灵不完整的,以保持比特币交易尽可能简单。

由于智能合同是在区块链创建和部署的,它们将受益于区块链提供的所有功能。由于其不变性,一旦被各方接受和部署,存储在区块链的任何联系人都不能被任何人篡改。除此之外,在区块链中部署智能合约提供了完全的透明性,因为任何人都可以随时验证合约的存在。

智能合约还有其他一些好处:

  • 更快的部署和执行:以传统方式准备合同需要用户花费数小时的时间来准备和处理文书工作。智能合约不过是自动化这些任务的一组指令,它删除了许多不必要的步骤。
  • 经济高效的部署和执行:在区块链上创建和执行智能合同比传统合同更便宜,传统合同需要中介的参与才能处理。
  • 安全管理:在区块链中创建的所有合同都得到安全管理。这是区块链的固有性质。
  • 复制证明:由于网络中分散的公共账本,每个合同驻留在网络的每个节点上,提供多个备份。在区块链网络上丢失合同是不可能的。
  • 精确执行:智能合同是由一组在区块链网络的每个节点上一致执行的指令创建的。这可以确保智能合约始终准确运行。由于区块链的拜占庭容错性质,网络将忽略任何有错误的合同执行。

选择智能合约平台

智能合约是自动执行的合约,可以使用任何支持在其事务中执行基本脚本的区块链应用程序进行部署。大多数区块链平台支持特定于领域的语言。我们已经接触过比特币交易中使用的语言,叫做脚本,一种基于堆栈的语言,能力有限。虽然 Script 是一种图灵不完全语言,但它只有几个选项可以用来创建复杂的事务。它可以创建多签名交易、支付通道和原子跨链交易。除此之外,比特币还可以创建一个带有锁定时间的交易。可以创建一个事务,但要锁定一段时间,以防创建者希望在锁定时间到期之前使事务无效。尽管比特币的脚本语言为创建复杂的交易提供了足够的灵活性,但它不适合创建复杂的合同。

从那以后,许多区块链平台被创建出来,它们使用自己特定领域的语言提供高级脚本功能,比如以太坊的 Solidity 和卡尔达诺的普路托斯。除此之外,大多数平台都有自己的运行时环境,编译后的智能契约就是在这里执行的。运行时环境类似于 Java 等通用编程语言中使用的环境。智能合同将在一个虚拟机上运行,这个虚拟机类似于一个 Java 虚拟机 ( JVM )。区块链虚拟机提供了一种在公共网络中执行不可信代码的方式。这些虚拟机还提供针对攻击的安全性,例如拒绝服务 ( DoS )攻击,这是执行不可信代码的系统中的必要功能。

提供这些服务的一些区块链平台如下:

  • EOS:一个智能合约平台和分散式操作系统,旨在通过每秒处理数百万次交易来解决区块链的可伸缩性问题。
  • 以太坊:这是最突出的智能合约平台。它在区块链上实现了一种接近图灵完全的语言。它使用一种叫做 Solidity 的领域特定语言,在以太坊虚拟机 ( EVM )上编译执行。
  • Hyperledger Fabric :这是由 Linux 基金会托管的 Hyperledger 项目下的一个许可的区块链项目。它允许执行名为链码的智能合约。它还允许将共识机制作为一个组件插入。
  • 这是一个区块链平台,允许用多种通用编程语言编写智能合同,如 C#、Python 和 JavaScript。我们将在下一节详细介绍新区块链。
  • NXT :这是一个公共的区块链平台,为智能合约执行有限的模板选择。它没有太多的空间来创建复杂的契约。

选择创建智能合约的平台取决于需要构建的应用程序的类型、所需的性能、智能合约语言以及许多其他因素。在选择平台之前,考虑所有要求是很重要的。就我们的所有权证明应用程序而言,它需要一个能够处理数字资产和数字身份的平台。

新区块链提供了一种便捷的方式来处理数字身份和资产。除此之外,智能合同可以用通用编程语言进行编码,以构建分散的应用程序。我们将用 Python 编程语言创建我们的智能契约,这样我们就不需要掌握任何额外的编程语言。以太坊是又一个可以方便地实现各种用例的平台。我们将在这两个平台上实现我们的所有权证明用例,因为它们是使用最广泛的区块链平台,对这两个平台的介绍将为分散式应用程序开发提供坚实的基础。

在接下来的部分,我们将深入 NEO 和以太坊区块链平台,以及所有权实现的证明。

新区块链

NEO 是一个区块链平台和加密货币,有助于创建和管理数字资产和智能合同。近地天体项目最初于 2014 年以 AntShares 的名义启动,直到 2017 年 6 月更名。所有的开发资源都是由创始人达·洪飞从他的商业区块链解决方案公司 Onchain 提供的。NEO 项目的主要动机是借助分布式网络中的数字资产、数字身份和智能合同,实现智能经济

该平台使用两种令牌,称为 NEO 和 GAS。与比特币不同,NEO 令牌是不可分割的令牌,这意味着 NEO 的最小单位是 1。持有 NEO 令牌可在共识机制期间获得投票权,这将在共识算法一节中进行说明。持有 NEO 令牌会生成一个名为 GAS 的新令牌,用于支付交易费用。如果你想在区块链部署和执行任何智能合同,汽油令牌就像是必不可少的燃料。创世纪区块总共产生了 1 亿个近地天体令牌。但相应的 1 亿个气代币将在 22 年左右逐步产生。

新区块链的建筑材料

新区块链使用分散网络的两个重要元素来创建分散应用程序,从而构建智能经济。这些是数字资产和数字身份,是任何区块链应用程序的组成部分。正如本章前面提到的,这些概念以及智能契约对于创建任何所有权证明应用程序都是必不可少的。

近地天体为在分散的近地天体区块链网络中创建和管理数字资产提供了一种便捷的方式。NEO 提供两种不同类型的资产:

  • 全球资产
  • 合同资产

全球资产记录在系统中,可由所有客户端和智能合约识别。NEO 和气体令牌是全球资产。合同资产与特定合同绑定,不能被其他合同识别。只有某些兼容的客户端将能够访问合同资产。基于 NEP-5 的资产是合同资产的一个例子。

NEP-5 a 是 NEO 指定的创建加密令牌的标准。该标准有助于开发人员在构建与令牌相关的应用程序时维护模板。NEP-5 代币类似于以太坊中使用的 ERC-20 代币。我们稍后将在第 12 章区块链用例中使用 NEP-5 令牌实现一个用例。

NEO 提供了一种借助数字身份处理区块链中物理和数字资产之间联系的方法。NEO 实施 X.509 公钥证书颁发标准来创建数字身份。在区块链的帮助下,NEO 可以代替在线证书状态协议 ( OCSP )来管理和记录 X.509 证书撤销列表 ( CRL )。

新技术

NEO 提供了几项功能,作为可扩展的区块链平台。这里讨论了 NEO 中使用的一些技术。

一致性算法

NEO 使用委托拜占庭容错 ( dBFT ),一种改进的拜占庭容错一致性算法。这是一种允许所有区块链参与者通过代理投票达成共识的机制。一组称为簿记员的特殊节点达成共识,以便在网络中生成新的块。这些簿记员由近地天体令牌持有者通过投票选举产生。dBFT 算法的容错度为 f =(n-1) / 3 ⌋的 n 个节点,也就是大致 33%的节点。一旦冻结和交易产生并得到确认,几乎不可能撤销。

在 NEO 中生成一个数据块大约需要 15 到 20 秒,每秒钟可处理 1,000 个事务,这与基于工作证明的实施相比是非常高的。由于 NEO 应用程序具有较高的事务吞吐量,因此可以轻松扩展。

NEO 智能合同

智能合约是新区块链的突出特色之一。与其他智能合同平台相比,在 NEO 区块链系统中编写智能合同是一个相当简单的过程,这主要是因为它支持大量通用语言,可以用这些语言创建智能合同。与以太坊不同,NEO 不需要特定领域的语言来创建和执行智能合约。

NEO 有一个类似于 JVM for Java 的轻量级虚拟机。NEO 的虚拟机按顺序执行智能合约指令。NEO 虚拟机仅执行由 NEO 编译器编译的指令。NEO 计划支持 C#、Java、C、C++、Go、JavaScript、Python、Ruby 等语言的编译器;虽然并不是所有的都已经实现,但是正在进行开发以提供对大多数语言的支持。除了这些编译器,NEO 目前还支持 Java 和 C#的 IDE 插件。这有助于开发人员在不改变其开发生态系统的情况下创建智能合约。

其他近地天体项目

NEO 是一个成长中的社区,在它的路线图中有很多项目;你可以在下面的列表中找到一些最受欢迎的例子:

  • NeoX:NEO 的这一特性将允许跨不同链的资产交换。它将提供原子资产交换协议,以确保交易要么被完全处理,要么被完全拒绝。即使是不兼容的区块链也能够通过 NeoX 进行通信,只要它提供一些基本的智能合约功能。由于 NeoX 将有助于实现跨链协作,单个智能合同可以在两个链上执行操作。
  • NeoFS :这是一种分布式存储机制,将使用分布式哈希表 ( DHT )技术。每个文件都将按其内容的摘要编制索引。大型文档被分成块,分布在区块链节点上。NeoFS 计划用令牌来激励节点存储需要更高可靠性的文档。NeoFS 节点可用于存储来自近地天体区块链的旧数据块,以减少完整节点上的负载。
  • NeoQS : NEO 计划解决量子计算对密码算法提出的挑战。NeoQS 计划开发量子安全的加密机制。

虽然所有这些项目都在开发中,但 NEO 的路线图看起来非常有希望。NeoFS 和 NeoQS 都将在 2018 年第三季度提供研究更新,而 NeoX 预计将在 2018 年第四季度进行初步测试。

NEO 节点

像任何其他区块链平台一样,近地天体也有保存区块链完整历史的节点,这些节点被称为完整节点。这些完整的节点构成了网络的主干,它们使用 P2P 协议进行通信。

入门指南

NEO 支持完整节点的两种变体,一种具有图形用户界面,另一种仅支持命令行。名为 NEO-GUI 的图形用户界面变体提供了最终用户需要的所有功能。 NEO-CLI 面向希望使用基本钱包功能和 API 的开发人员。开始使用这两种方法都很简单。我们将主要讨论 NEO-CLI,因为它对开发人员更友好。

设置完整节点

最初的 NEO-CLI 实现是用 C#编写的,源代码可以在https://github.com/neo-project/neo-cli找到。此实现需要一个带有的用户节点。NET 核心来运行编译后的二进制文件。该存储库解释了如何设置。不同环境下的 NET Core。运行 NEO-CLI 需要执行源代码中的一个动态链接库 ( DLL )文件。一次。NET Core,以下命令将启动 NEO-CLI 完整节点进程:

$ dotnet neo-cli.dll 

完整节点使用三个不同的端口用于 JSON-RPC ( 10332)、通过 TCP 的 P2P(10333)和通过 WebSocket 的 P2P(10334)。除此之外,JSON-RPC 还有一个 HTTPS 版本(10331)。NEO 为测试网络和专用网络使用一组不同的端口。它使用类似的端口,测试网络的首字母“1”替换为“2”,专用网络的首字母“3”替换为“3”。在本章中,我们将主要讨论私有网络节点,因为我们将创建自己的网络来部署应用程序。

可以通过运行以下带有/rpc标志的命令来公开节点的 JSON-RPC 接口:

$ dotnet neo-cli.dll /rpc 

NEO-CLI 打开了一个交互式界面,用户可以在其中执行所有区块链节点和 wallet 操作:

NEO-CLI Version: 2.7.4.0 
neo> 

在执行任何命令来管理 wallet 或节点之前,用户必须创建一个 wallet 或打开一个现有的 wallet。shell 中的以下命令在 NEO-CLI shell 中创建和打开一个 wallet:

create wallet neo_wallet.db3 
password: *** 
address: ASxUka4WqmEkD2mJtGy37J9NeuTe8bTtYF 
pubkey: 0374c66e892d7a8cbbbd4c8bd5b7b71ec83819a90c2327d7057b1234072291b5d8 

open wallet neo_wallet.db3 

用户需要提供一个密码来保护钱包,这个密码将在每次解锁钱包时使用。用户可以在打开钱包后执行任何钱包、交易或阻止操作。

您可以在 http://docs.neo.org/en-us/node/cli/cli.html查阅所有命令的 NEO-CLI 文档。

NEO-CLI 支持在区块链中测试、构建和部署智能合约,但目前它不支持以各种编程语言编写的智能合约。NEO-CLI 只为提供编译器。NET 和 Java。我们需要第三方编译器来创建任何其他编程语言的智能契约。neo-python 就是这样一个项目。它得到了锡安城组织的支持,该组织由一群积极参与的开发者组成。在本章中,我们将使用 neo-python 项目来构建我们的应用程序。

设置新 python 环境

neo-python 项目提供了一个 neo 节点和一个 SDK,使开发人员能够使用 python 在 NEO 区块链上创建、测试、部署和执行智能合同。该项目支持管理钱包和区块链节点中的资产所需的所有功能。该项目旨在完全移植 NEO-CLI 实施。

要设置 neo-python,您需要安装 Python 3.6 解释器。neo-python 可以安装在任何平台上,尽管它需要执行一些特定于平台的步骤。neo-python 需要在安装自己之前安装leveldbopenssl库。

从快速入门到构建复杂的智能合约,neo-python 的完整文档可以在https://neo-python . readthedocs . io找到。

neo-python 包可以从 PyPI 安装,就像任何其他 python 包一样,或者从源代码库中安装。安装完成后,可以使用np-prompt命令启动 neo-python 的交互式 shell。其外壳界面与 NEO-CLI 的外壳界面相似,如下块所示:

$ np-prompt 
NEO cli. Type 'help' to get started 
neo> 

neo-python 也可以从源代码安装,方法是从 https://github.com/CityOfZion/neo-python 的克隆存储库,并在开发模式下安装 neo-python 包。然后可以用一个np-prompt命令或者简单地通过运行 python 脚本neo/bin/prompt.py来启动 neo-python shell。

打开钱包后,可以在 shell 上执行任何命令,方式与 NEO-CLI 类似。

尽管在 NEO-CLI 上执行的所有操作也可以在 neo-python 中执行,但一些命令语法与 NEO-CLI 命令不同。在 neo-python shell 中键入help列出所有命令。

为节点设置 JSON-RPC 接口

如前一节在设置节点时所述,NEO 节点充当 JSON-RPC 服务器,因此它可以使用 RPC 接口进行通信。如前所述,可以通过添加/rpc标志在 NEO-CLI 中实例化 JSON-RPC 服务器。您需要启动一个不同的过程来在 neo-python 中创建 RPC 服务器:

$ np-api-server --port-rpc 10332 

就像比特币的 JSON-RPC 接口一样,NEO 为其每个 API 提供了一个 RPC 端点:

$ curl -X POST http://localhost:10332 -H 'Content-Type: 
 application/json' -d '{ "jsonrpc": "2.0", "id": 5, "method": 
 "getversion", "params": [] }' 

{"jsonrpc": "2.0", "id": 5, "result": {"port": 8080, "nonce": 
 1439440988, "useragent": "/NEO-PYTHON:0.6.6/"}} 

大多数前端应用程序使用 JSON-RPC 与分散的应用程序和区块链本身进行通信。

neon-js, maintained by City of Zion, provides JavaScript libraries that use the RPC interface exposed by the NEO node to communicate with the blockchain.

近地天体网络

NEO 使用网络协议建立连接,并以双工模式与每个节点通信。网络中的节点根据其职责分为两类:验证节点(簿记节点)和普通对等节点。对等节点帮助广播已经验证的块和未确认的事务,而簿记节点生成新的块。NEO 遵循与比特币类似的网络协议来启动连接,并在对等体之间交换数据块。

当我们通过 NEO-CLI 或 neo-python 启动 NEO shell 时,节点将加入默认配置中指定的网络。neo-python 节点可以属于主网络、测试网络或专用网络。如果近地天体节点在启动时没有指定网络,它将加入一个测试网络。以下命令启动专用网络协议配置文件中指定的专用网络中的节点,该文件可在neo/data/中找到:

$ np-prompt -p 

我们将使用一个专用网络来执行本章中所有的新 python 操作。也可以通过用-c标志明确指定网络配置文件来启动节点。

测试网络

近地天体测试网络类似于 mainnet。在测试网络中,用户可以开发、部署和执行程序。用户可以使用测试代币,而不是花费真实的气体和 NEO 代币,这些代币没有真实的价值。在 testnet 上执行的所有其他操作都与 mainnet 上的相同。因此,这是开发人员在 mainnet 上部署应用程序之前测试它们的完美环境。由于测试网是一个活跃的网络,参与者来自世界各地,近地天体和气体令牌的供应是有限的,加入网络时不会向您提供任何令牌,就像在 mainnet 中一样。由于部署智能合同至少需要 500 个 GAS,用户可以从其他 testnet 用户那里获得,也可以在https://neo.org/Testnet/Create申请。一旦用户有足够的汽油,智能合同就可以部署到网络中。

专用网

一个专用网络是一个近地天体节点的集合,这些节点自行达成区块链国家共识。这些近地天体节点与主网或测试网的公共节点完全断开。专用网络非常适合在组织内部创建区块链网络。

一个专用的近地天体网络至少需要四个节点才能达成共识。可以在局域网中部署专用的近地天体网络,也可以通过创建虚拟机在单个设备上部署多个节点。即使是私有网络的节点也需要 GAS 在私有区块链中创建和部署智能合同。私有节点可以通过从所有共识节点创建多方签名地址来从网络中提取所有 NEO 和 GAS 令牌。然后,NEO 和 GAS 可以从联系地址转移到正常地址。

通过部署托管在https://hub.docker.com/r/cityofzion/neo-privatenet的交钥匙 Docker 镜像,可以创建具有有限共识节点的小型专用网络。这张 Docker 图像部署了四个近地天体验证节点,它已经预占了所有 1 亿个近地天体和 16,600 个气体令牌。任何加入网络的用户都可以使用包含所有令牌的钱包来部署智能合约。只需几个命令就可以启动专用网络:

$ docker pull cityofzion/neo-privatenet
$ docker run --rm -d --name neo-privatenet -p 20333-20336:20333-
 20336/tcp -p 30333-30336:30333-30336/tcp cityofzion/neo-privatenet 

Docker 映像将创建一个具有四个节点的容器,公开 P2P (20333-20336)端口和 RPC 端口(30333-30336)。

同一网络中的任何 neo-python 节点都可以添加这四个节点作为其种子节点,并开始同步专用网络区块链。然后,用户可以使用包含所有网络令牌的钱包来创建交易和部署智能合约。

NEO 交易记录

近地天体网络上的每个节点都可以在近地天体区块链中创建交易和执行操作。节点必须打开钱包以创建事务并广播它:

open wallet neo_wallet.db3
wallet 

neo-python 中的wallet命令为您提供关于已打开钱包的完整信息:

{ 
  "path": "neo_wallet.db3", 
  "addresses": [ 
    { 
      "version": 0, 
      "script_hash": "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y", 
      "frozen": false, 
      "votes": [], 
      "balances": { 
        "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74
 a6daff7c9b": "100000000.0", 
        "0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee
 7969282de7": "16024.0" 
      }, 
      "is_watch_only": false 
    } 
  ], 
  "height": 20066, 
  "percent_synced": 100, 
  "synced_balances": [ 
    "[NEO]: 100000000.0 ", 
    "[NEOGas]: 16024.0 " 
  ], 
  "public_keys": [ 
    { 
      "Address": "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y", 
      "Public Key": "031a6c6fbbdf02ca351745fa86b9ba5
 a9452d785ac4f7fc2b7548ca2a46c4fcf4a" 
    } 
  ], 
  "tokens": [], 
  "claims": { 
    "available": "143992.0", 
    "unavailable": "480.0" 
  } 
} 

在每一笔交易确认后,电子钱包都会保留更新的详细信息。addresses字段包含钱包持有的所有钥匙的详细信息。打开的钱包只有一把钥匙,公开地址是AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8yaddresses字段内的balances字段显示了该节点所声称的当前近地天体和气体令牌。在balances字段中,0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b代表 NEO 令牌的交易 ID,0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7代表汽油令牌。NEO 使用这些作为 NEO 和气体令牌的标准 id。

与比特币节点不同,NEO 节点可以创建几种不同类型的交易,以支持在区块链中执行的所有操作。下表描述了可以在 NEO 网络中创建的不同类型的事务:

| 名称 | 描述 | | MinerTransaction | 分配字节费用 | | IssueTransaction | 资产发行 | | ClaimTransaction | 认领新硬币 | | EnrollmentTransaction | 验证程序的注册 | | VotingTransaction | 投票给验证者 | | RegisterTransaction | 资产登记册 | | ContractTransaction | 合同交易 | | AgencyTransaction | 订单交易 |

桌子。7.1.NEO 中的交易类型

每种类型的交易都有专门的字段来存储关于交易的更多信息。例如,MinerTransaction有一个额外的字段来存储nonce,它是一个随机数。

转移资产

节点可以使用事务对近地天体资产执行操作。交易由节点使用其私钥创建,私钥位于钱包中。钱包打开后,用户可以对资产执行任何操作。neo-python 中的send命令通过获取资产 ID、接收方地址和金额来转移资产。send命令创建一个事务并将其转发给网络,以便将其包含在区块链中:

send NEO AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU 100 
[Password]> *** 
Relayed Tx: 53b72dbce63a28a01432c1ddcc82aed8c28fb1fa338cab812c979
 d56cc8e4410 

创建的交易是一个ContractTransaction,细节显示它包含了voutvin字段,它们的功能类似于比特币交易中的字段。vin字段指向其未用输出被引用的事务,而vout由新创建的未用输出组成。第一个输出是用户交易的金额,第二个输出是输出的变化。与比特币交易不同,验证脚本位于单独的脚本字段下:

{ 
  "txid": "0x53b72dbce63a28a01432c1ddcc82aed8c28fb1fa338cab812
 c979d56cc8e4410", 
  "type": "ContractTransaction", 
  "version": 0, 
  "attributes": [ 
    { 
      "usage": 32, 
      "data": "23ba2703c53263e8d6e522dc32203339dcd8eee9" 
    } 
  ], 
  "vout": [ 
    { 
      "n": 0, 
      "asset": "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930
 faebe74a6daff7c9b", 
      "value": "100", 
      "address": "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU" 
    }, 
    { 
      "n": 1, 
      "asset": "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930
 faebe74a6daff7c9b", 
      "value": "99999900", 
      "address": "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y" 
    } 
  ], 
  "vin": [ 
    { 
      "txid": "2b8907db07ebbc3ea2244162ff3d696e7b80874d3ddc3f1fc52
 e427d91cd91c3", 
      "vout": 0 
    } 
  ], 
  "sys_fee": "0", 
  "net_fee": "0", 
  "scripts": [ 
    { 
      "invocation": "40f6b2e5c2ca932a536284136c254119096813ee35
 d494c939d9e26a7b6247f0801284a34c39e0194c35d1db68bf54fa1de2852
 b86182d86a673a206dcf64c6f04", 
      "verification": "21031a6c6fbbdf02ca351745fa86b9ba5a9452d785
 ac4f7fc2b7548ca2a46c4fcf4aac" 
    } 
  ], 
  "height": 20594, 
  "unspents": [ 
    { 
      "n": 0, 
      "asset": "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930
 faebe74a6daff7c9b", 
      "value": "100", 
      "address": "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU" 
    }, 
    { 
      "n": 1, 
      "asset": "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930
 faebe74a6daff7c9b", 
      "value": "99999900", 
      "address": "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y" 
    } 
  ] 
} 

创建分散的应用程序

现在,我们已经了解了近地天体平台的一些基本功能,我们准备使用近地天体区块链创建我们的第一个分散式应用程序。智能契约是使用 NEO 创建去中心化应用程序的基础。在创建分散所有权证明应用程序之前,我们将通过创建 hello world 应用程序来熟悉智能合约。

基本智能合同

首先,我们将创建一个简单的 Python 脚本,它返回一个串联的字符串来问候用户:

from boa.builtins import concat 

def main(name): 
  return concat("Hello ", name) 

契约脚本使用由boa提供的concat方法来连接两个字符串。每个智能合约都应该有一个名为main的功能,这将是切入点。智能合约需要编译成字节码,可以在 NeoVM 中执行。合同可以由 neo-python shell 使用 neo-boa 编译器进行编译,如下所示:

build hello.py test 07 07 False False Alice 

build命令带有一个test参数,用于测试样本结果。紧跟在test标志之后的代码表示参数的数据类型和返回类型。前面的代码规定契约函数接受一个字符串参数并返回一个字符串值。下表列出了所有可用的数据类型及其代码:

| 数据类型 | 代码 | | 签名 | 0x00 | | 布尔代数学体系的 | 0x01 | | 整数 | 0x02 | | 哈希 160 | 0x03 | | 哈希 256 | 0x04 | | ByteArray | 0x05 | | 公共密钥 | 0x06 | | 线 | 0x07 | | 排列 | 0x10 | | 互操作接口 | 0xf0 | | 空的 | 0xff |

表 7.2。合同参数使用的数据类型

数据类型后面的第一个布尔值规定协定是否需要本地存储,第二个布尔值指示协定是否对其他智能协定进行动态调用,这些智能协定的地址只有在执行期间才知道。在构建过程中,对协定的任何输入都遵循这些参数。测试调用将显示结果,以及调用契约所需的 GAS。结果显示输出是一个string类型,以及值。最重要的是,build调用通过创建一个 AVM 文件来生成字节码形式的契约指令,该文件将存储在同一个目录中:

Calling hello.py with arguments ['Alice'] 
Test deploy invoke successful 
Used total of 19 operations 
Result [{'type': 'String', 'value': 'Hello Alice'}] 
Invoke TX gas cost: 0.0001 

生成的 AVM 文件需要导入到 NeoVM,然后转发到区块链网络。下面的import调用执行合同导入。import命令采用的参数与构建过程中指定的参数相似:

import contract hello.avm 07 07 False False Alice 

在创建智能合约并将其转发到网络之前,用户需要输入智能合约的详细信息:

Please fill out the following contract details: 
[Contract Name] > Hello World 
[Contract Version] > 1.0.0 
[Contract Author] > Alice 
[Contract Email] > alice@neotest.com 
[Contract Description] > Basic smart contract 
Creating smart contract.... 
{ 
  "hash": "0x6ed9fabe179b236ca7c22deb72a02bdf65b57b84", 
  "script": 
 "54c56b6a00527ac40648656c6c6f206a00c37e6c75665ec56b6a00527ac46a515
 27ac46a51c36a00c3946a52527ac46a52c3c56a53527ac4006a54527ac46a00c36
 a55527ac461616a00c36a51c39f6433006a54c36a55c3936a56527ac46a56c36a5
 3c36a54c37bc46a54c351936a54527ac46a55c36a54c3936a00527ac462c8ff616
 1616a53c36c7566", 
  "parameters": "07", 
  "returntype": "07" 
} 
Used 100.0 Gas 

创建智能协定后,将生成一个脚本哈希和协定脚本。脚本哈希表示契约,网络中的每个人都可以使用它来调用智能契约。

事务中使用的 GAS 取决于智能合约操作的类型以及智能合约中使用的系统调用。创建智能合同的成本是 100 GAS 加上系统调用的额外费用。如果智能合约需要一个存储区,需要额外花费 400 气。我们早期的智能合约部署仅使用 100 GAS 来创建智能合约,因为不需要本地存储。

neo-python 提供了一个testinvoke命令,可以用来测试已经在区块链部署的契约散列。testinvoke呼叫不会被中继到网络,除非它被用户接受。它只接受协定及其参数的脚本哈希:

testinvoke 0x6ed9fabe179b236ca7c22deb72a02bdf65b57b84 Alice 

一旦节点更新了它的本地区块链以包含早先创建的中继契约,就可以执行testinvoke调用。以下是输出:

Test invoke successful 
Total operations: 19 
Results ['48656c6c6f20416c696365'] 
Invoke TX GAS cost: 0.0 
Invoke TX fee: 0.0001 

testinvoke从区块链调用契约,并以十六进制字符串数组的形式返回计算结果。十六进制结果'48656c6c6f20416c696365'翻译成“Hello Alice”,这是期望的输出。

所有权证明申请

我们已经在本章前面探讨了在分散式应用程序中创建所有权证明应用程序的好处;现在,我们将继续使用 NEO smart contracts 创建一个所有权证明应用程序,以便在分散式网络中执行资产管理。

我们创建了一个存在证明应用程序来证明第六章潜入区块链——存在证明中某个文档的存在。在本节中,我们将创建一个资产管理系统来登记和证明本节中文档的所有权。目标是创建以下资产管理功能:

  • 资产登记
  • 资产查询
  • 资产移除
  • 资产转移

我们将在智能合约中实现所有功能,以证明文档的所有权。

创建智能合同

使用 Python 创建的智能契约包含一个作为入口点的main函数。该函数接受两个参数。第一个参数接受操作的类型,所有附加的参数都传递给列表中的第二个参数。operation参数接受registerquerydeletetransfer,以便执行资产管理功能。

智能合约的main函数解析operation参数,并调用智能合约中的相应函数来对资产执行操作。main函数解析args参数,将列表的第一项分配给asset_id,其他项分配给owner:

from boa.interop.Neo.Runtime import Log, Notify 
from boa.interop.Neo.Storage import Get, Put, GetContext 
from boa.interop.Neo.Runtime import GetTrigger,CheckWitness 
from boa.builtins import concat 

def main(operation, args): 
  nargs = len(args) 
  if nargs == 0: 
    print("No asset id supplied") 
    return 0 

  if operation == 'query': 
    asset_id = args[0] 
    return query_asset(asset_id) 

  elif operation == 'delete': 
    asset_id = args[0] 
    return delete_asset(asset_id) 

  elif operation == 'register': 
    if nargs < 2: 
      print("required arguments: [asset_id] [owner]") 
      return 0  
    asset_id = args[0] 
    owner = args[1] 
    return register_asset(asset_id, owner) 

  elif operation == 'transfer': 
    if nargs < 2: 
      print("required arguments: [asset_id] [to_address]") 
      return 0 
    asset_id = args[0] 
    to_address = args[1] 
    return transfer_asset(asset_id, to_address) 

register_asset函数获取asset_id和所有者地址,并在区块链中创建一个所有权条目。CheckWitness是 NEO 运行时功能检查,检查所有者的地址是否与调用合同的用户的地址相匹配。如果要注册的资产所有者与调用合同的用户不同,则合同返回False。契约通过调用 NEO 存储库Get方法来验证asset_id是否已经注册。最后,通过使用Put存储方法将资产 id 和所有者详细信息存储在键/值对中,将资产注册给所有者:

def register_asset(asset_id, owner): 
  msg = concat("RegisterAsset: ", asset_id) 
  Notify(msg) 

  if not CheckWitness(owner): 
    Notify("Owner argument is not the same as the sender") 
    return False 

  context = GetContext() 
  exists = Get(context, asset_id) 
  if exists: 
    Notify("Asset is already registered") 
    return False 

  Put(context, asset_id, owner) 
  return True 

NEO 通过将数据存储在键/值对中,在区块链中提供存储功能。智能协定必须指定脚本在部署期间是否需要协定存储空间。使用存储会在部署过程中消耗额外的汽油。

query_asset函数查询本地存储器以检查用户是否已经注册了资产。如果找到资产,它将返回所有者地址:

def query_asset(asset_id): 
  msg = concat("QueryAsset: ", asset_id) 
  Notify(msg) 

  context = GetContext() 
  owner = Get(context, asset_id) 
  if not owner: 
    Notify("Asset is not yet registered") 
    return False 

  Notify(owner) 
  return owner 

以下函数需要asset_id和资产接收方的地址,以便转移资产。作为第一步,它通过使用Get方法检查存储来验证资产的存在。然后,它检查资产所有者是否与调用者相同。该合同还验证收件人地址是有效的地址。最后,使用Put存储方法,资产被更新为新的所有者:

def transfer_asset(asset_id, to_address): 
  msg = concat("TransferAsset: ", asset_id) 
  Notify(msg) 

  context = GetContext() 
  owner = Get(context, asset_id) 
  if not owner: 
    Notify("Asset is not yet registered") 
    return False 

  if not CheckWitness(owner): 
    Notify("Sender is not the owner, cannot transfer") 
    return False 

  if not len(to_address) != 34: 
    Notify("Invalid new owner address. Must be exactly 34 
 characters") 
    return False 

  Put(context, asset_id, to_address) 
  return True 

delete_asset方法实现了与transfer_asset相似的功能,不同之处在于它删除资产而不是更新资产。Delete函数调用用于从存储器中删除存储的键/值对:

def delete_asset(asset_id): 
  msg = concat("DeleteAsset: ", asset_id) 
  Notify(msg) 

  context = GetContext() 
  owner = Get(context, asset_id) 
  if not owner: 
    Notify("Asset is not yet registered") 
    return False 

  if not CheckWitness(owner): 
    Notify("Sender is not the owner, cannot transfer") 
    return False 

  Delete(context, asset_id) 
  return True 

既然我们已经实现了资产管理的所有基本功能,我们将在下一节中使用 neo-python shell 来执行契约。

执行智能合同

智能合约的执行步骤与前面部署基本智能合约的小节中所示的步骤相似。唯一的区别是提供给协定的参数和相应的返回数据。

如前所述,我们将创建一个所有权证明应用程序来跟踪文档。每个文档都可以通过其摘要来唯一标识。我们将使用文档的 SHA256 哈希值作为资产 ID。让我们考虑一个包含以下内容的文件。这些文件通常存储有一个额外的新行字符,在原始文本输出中不可见:

This document was created by Alice. 

下面的摘要表示文件的 SHA256 哈希值:

f572f8ce40bf97b56bad1c6f8d62552b8b066039a9835f294ea4826629278df3 

让我们使用哈希值作为资产 ID 来惟一地标识每个文档。使用以下命令在 neo-python shell 中构建契约:

build poo.py test 0710 05 True False query 
 ["f572f8ce40bf97b56bad1c6f8d62552b8b066039a9835f294ea4826629278
 df3"] 

Test deploy invoke successful 
Used total of 113 operations 
Result [{'type': 'ByteArray', 'value': ''}] 
Invoke TX gas cost: 0.0001 

build过程将0710作为参数类型,这表示它将一个字符串(07)和一个数组(10)作为参数。而05表明它有一个返回类型byte array

在成功构建之后,可以使用创建的 AVM 文件部署协定:

import poo.avm 0710 05 True False 
{ 
  "hash": "0x60a7ed582c6885addf1f9bec7e413d01abe54f1a", 
  "script": "....", 
  "parameters": "0710", 
  "returntype": "05" 
} 
Used 500.0 Gas 

该交易需要额外的 400 GAS,因为智能合约需要本地存储。总气体消耗量为500,如前面的代码块所示。

一旦合同交易记录包含在区块链中并与当地区块链同步,就可以执行合同。让我们使用testinvoke命令来测试我们创建的智能契约。

让我们使用前面提到的相同的 SHA256 值作为资产 ID 来注册一个文档。使用由散列值和调用智能契约的用户地址组成的参数列表来调用register操作:

testinvoke 0x60a7ed582c6885addf1f9bec7e413d01abe54f1a register 
 ["f572f8ce40bf97b56bad1c6f8d62552b8b066039a9835f294ea4826629278
 df3", "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"] 

一旦事务被调用并中继到网络,就可以对资产执行其他操作。现在,让我们通过调用transfer操作并在列表中指定收件人地址,将文档的所有权转移给新的所有者:

testinvoke 0x60a7ed582c6885addf1f9bec7e413d01abe54f1a transfer 
 ["f572f8ce40bf97b56bad1c6f8d62552b8b066039a9835f294ea4826629278
 df3", "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"] 

通过调用查询操作并传递资产 ID,可以随时验证文档所有权:

testinvoke 0x60a7ed582c6885addf1f9bec7e413d01abe54f1a query 
 ["f572f8ce40bf97b56bad1c6f8d62552b8b066039a9835f294ea4826629278
 df3"] 

Test invoke successful 
Total operations: 118 
Results ['415a3831483331444d577a62536e46444c466b7a683976487761444
 c617956376655'] 
Invoke TX GAS cost: 0.0 
Invoke TX fee: 0.0001 

该查询返回一个包含十六进制字符串的字节数组。十六进制结果代表地址AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU。因为文档的所有权被转移给了新的所有者,所以结果显示了文档的更新所有者。

我们现在已经创建了一个智能契约来演示所有权证明系统,该系统跟踪文档的所有权。一旦智能合同部署到区块链中,它将永远留在那里。用户只需处理智能合约调用。近地天体节点的 RPC 接口提供了一种与区块链通信的便捷方式。我们现在将研究如何通过创建接口来方便地与区块链通信。

应用程序的接口

NEO 社区创建了一些 JavaScript 库来与 NEO 区块链接口。我们将使用一个名为 neon-js(https://github.com/CityOfZion/neon-js)的流行库,它由锡安城社区提供支持。

下面的脚本创建了一个接口,为我们的所有权证明应用程序查询资产的所有者:

queryAsset(assetID) {
  const props = { 
    scriptHash: '60a7ed582c6885addf1f9bec7e413d01abe54f1a', 
    operation: 'query', 
    args: [assetID.hexEncode()]
  }; 
  const Script = Neon.create.script(props); 

  rpc.Query.invokeScript(Script).execute('http://localhost:30333')
 .then((res) => { 
    return res.result.stack[0].value.hexDecode() 
  }); 
} 

使用 neon-js 库创建的接口使用Neon.create.script方法为智能合约构建一个脚本。然后,它使用 RPC 接口调用智能合约脚本。之后,queryAsset返回拥有文档资产的用户的地址。

创建区块链智能合约的接口是构建成熟的分散式应用程序的关键部分。该界面还创建了一种与区块链节点通信的便捷方式,从而增强了用户体验。

Ethereum 区块链

以太坊是一个公共区块链,由 Vitalik Buterin 于 2013 年末提出,并于 2015 年向公众发布。以太坊是最初的区块链平台之一,创建该平台是为了帮助程序员使用智能合约开发和部署去中心化的应用程序。以太坊有一套丰富的框架和库来开发、测试和部署应用程序。在这一节中,我们将介绍使用以太坊平台开发和部署所有权证明应用程序。参考第八章区块链项目,了解更多关于以太坊生态系统的细节。

以太坊节点

与比特币和 NEO 类似,有几种不同语言的客户端软件实现可以用作以太坊完整节点。以太坊客户端实现可以在 Java、JavaScript、Python、Go 和许多其他语言中找到。以太坊的 Golang 实现称为 Go 以太坊Geth 是其中最受欢迎的。

入门指南

在开始应用程序开发之前,设置节点是重要的一步。尽管任何以太坊客户端都可以用来设置一个完整的节点,但是我们将设置 Geth 客户端来与公共区块链进行同步和交互。与近地天体区块链类似,Geth 客户端可以连接到 mainnet、testnet 或专用网络。

设置节点

我们将建立一个 Geth 客户端,可用于同步整个区块链事务。它还提供了 JSON-RPC 接口来调用客户机软件支持的任何方法。JSON-RPC 接口可用于执行多种操作,包括部署和调用智能契约。

Geth 客户端可以使用大多数平台上的包来构建或安装。不同平台的安装说明可以在https://github . com/ether eum/go-ether eum/wiki/Building-ether eum找到。

Geth 提供了一个命令行界面,可用于启动节点。一旦 Geth 安装了所有的依赖项,就可以启动它来将本地区块链数据与公共区块链同步。Geth 客户机可以通过为链、事务池、性能调优、帐户、网络、miner 等提供几个参数来配置。下面的命令用几个参数实例化一个以太坊节点:rpc(启用 RPC 服务器)、rpcapi(通过 RPC 接口访问的 API 列表)、cache(为内部缓存分配的内存)、rpcport (RPC 服务器端口)和rpcaddr (RPC 服务器地址):

$ geth --rpc --rpcapi db,eth,net,web3,personal --cache=2048 
 --rpcport 8545 --rpcaddr 127.0.0.1 

实例化的以太坊节点将尝试通过连接到 mainnet 对等体来同步区块链。或者,Geth 可以配置为连接到任何以太坊测试网( RinkebyKovanRopsten )。以下命令使用 Rinkeby testnet 区块链实例化一个节点:

$ geth -rinkeby 

一组 Geth 客户端也可以形成他们自己的私有以太网,而不是连接到现有的 mainnet 或 testnet。

使用 Geth client 设置私有网络的说明可以在这里找到:https://github . com/ether eum/go-ether eum/wiki/Setting-up-private-network-or-local-cluster

在这一章中,我们将借助于 Truffle 套件框架中提供的一个名为 Ganache CLI 的工具来创建一个私有区块链,这是一个 JavaScript 包,可以使用节点包管理器来安装。在执行以下命令之前,确保系统中安装了nodenpm:

$ npm install -g ganache-cli 

可以通过启动 Ganache CLI 来实例化私有区块链。Ganache CLI 可以通过指定几个参数来配置,也可以不带参数启动,如以下命令所示:

$ ganache-cli 

一次成功的发射将创建一个私人区块链以及几个装有乙醚的账户,这些账户可用于支付所创建的任何交易的交易费。Ganache CLI 还将创建一个客户端应用程序,默认情况下,该应用程序将侦听端口 8545。在接下来的部分中,我们将使用私有区块链和在端口 8545 上运行的应用程序来部署和查询智能合约。

设置开发环境

既然我们已经用私有区块链实例化了一个本地节点,我们将设置开发环境来简化分布式应用程序的创建和部署。因为我们必须创建一个完全成熟的分散式应用程序,所以我们需要使用脚本语言(比如 JavaScript)与以太坊区块链进行通信。以太坊提供了一个名为 web3.js 的 JavaScript 库,其中包含了与以太坊区块链交互的 API。

web3.js 利用 RPC 调用与公开 RPC 接口(应用程序端口 8545)的以太坊节点通信。因此,web3.js 可以调用以太坊节点提供的任何方法。可以在节点终端上执行以下代码片段:

Web3 = require('web3') 
web3 = new Web3(new 
 Web3.providers.HttpProvider("http://localhost:8545")); 
web3.eth.getBlockNumber(console.log); 

这段代码将创建一个web3实例,然后添加本地节点作为提供者。当 web3.js 应用程序在 web 浏览器中执行时,web3对象可以通过 MetaMask 等桥注入。这些web3实例已经有了在web3.currentProvider中指定的提供者。我们将在构建所有权证明应用程序时使用元掩码。

尽管web3.js提供了与区块链交互所需的所有方法,但它并没有建立一个完整的开发环境。这可以通过名为 Truffle 的以太坊开发框架来实现。Truffle 提供了一个完整的开发环境,以及智能合约的方便测试、部署和迁移。Truffle 框架可以使用节点包管理器安装:

$ npm install -g truffle 

Truffle 项目可以在一个空目录中启动,以构建应用程序开发所需的初始文件:

$ truffle init 

这将创建三个目录- contracts(智能合同)、migrations(部署脚本)和test(测试脚本)以及一个配置文件truffle.js。我们需要将以下配置添加到truffle.js文件中,以将创建的 Truffle 项目指向我们的私有区块链:

module.exports = { 
  networks: { 
    development: { 
      host: '127.0.0.1', 
      port: 8545, 
      network_id: '*' } 
  } 
}; 

可以从 Truffle 项目目录启动一个交互式的 Truffle 控制台:

$ truffle console 

web3对象已经在 Truffle 控制台中被实例化了,任何 web3 APIs 都可以使用这个对象来访问。在下一节中,我们将使用 Truffle 控制台来查询已部署的契约。

创建分散的应用程序

我们现在可以在 Ethereum 平台上创建我们的第一个分布式应用程序,因为我们已经设置了我们的开发环境。我们将通过创建和部署 hello world 应用程序来熟悉以太坊智能合约。

基本智能合同

以太坊使用一种称为 Solidity 的特定领域语言来编码智能合约的逻辑。Solidity 是一种高级编程语言,可以编译产生字节码,然后在 EVM 上执行。

Solidity 是一种静态类型的编程语言,最初由 Gavin Wood 提出。它被设计成类似于 ECMAScript 语法,这样它就可以很容易地被 web 开发人员社区采用。关于 Solidity 编程语言的更多细节可以在https://Solidity . readthedocs . io找到。

我们将使用 Solidity 编程语言创建一个简单的 hello world 智能合约:

pragma solidity ^0.4.23; 

contract Hello { 

  function greetUser(bytes user) view public returns (bytes) { 
    return abi.encodePacked("Hello ", user); 

  } 
} 

solidity 脚本的第一行是版本pragma,表示 Solidity 程序的版本。上述脚本不应在版本低于 0.4.23 的 Solidity 编译器上编译。每个协定都被定义到一个类似的类中,并以协定名作为文件名。所有的功能都在契约中定义。还可以创建一个与契约同名的构造函数。函数greetUser接受一个bytes类型的字符串,并返回一个bytes字符串。该函数还具有公共可见性,这意味着可以从任何地方调用它。greetUser函数将连接并返回两个字符串。

我们将使用 Truffle 框架来部署和调用智能契约。我们需要将智能合约文件指向 Truffle 框架,方法是在migrations文件夹内的新 JavaScript 文件(2_deploy_contracts.js)中包含以下代码片段,或者更新现有的1_initial_migration.js文件:

var Hello = artifacts.require("./Hello.sol"); 
module.exports = function(deployer) { 
  deployer.deploy(Hello); 
}; 

可以使用以下 Truffle 命令编译智能合约:

$ truffle compile 

它会在build/contracts文件夹中生成一个名为应用二进制接口 ( ABI )的接口文件。生成的 ABI 文件将是 JSON 格式的,它提供了与以太坊生态系统中的契约进行交互的接口。

然后,通过迁移该合同,将其部署到区块链:

$ truffe migrate 
Deploying Hello... 
  ... 0x4d85f83c2ffcf1405eb7b610e0f34c99f42b4189f11fbb5ffb782b6eb4d96316 
  Hello: 0x149cd2285f8b8a72a5f8b7286aceb94fb54c1aee 

部署的契约将生成一个可用于与之交互的契约地址。我们将使用 Truffle 控制台与合同进行交互:

$ truffle console 
truffle(development)> 
Hello.deployed().then((instance) => instance.greetUser("Alice")); 

当前面的代码片段在 Truffle 控制台上执行以Alice为参数调用契约的greetUser函数时,契约将返回0x48656c6c6f20416c696365,这是“Hello Alice”的十六进制字符串

所有权证明申请

我们将创建一个具有资产管理功能的应用程序来注册、查询、删除和转移资产。

创建智能合同

应用程序逻辑类似于 NEO 智能合同中使用的逻辑。但是由于虚拟机提供的功能,用于存储资产信息的数据结构是不同的。NEO 和以太坊契约的一个主要区别是以太坊契约中的功能可以在 ABI 的帮助下直接调用。

ProofOfOwnership智能契约使用映射数据结构将资产所有权信息存储在键/值对中。bytes32类型的资产信息被映射到资产所有者的以太坊地址:

pragma solidity ^0.4.23; 

contract ProofOfOwnership { 
  mapping (bytes32 => address) public assetOwners; 

registerAsset函数使用映射数据结构将调用合同的用户的地址映射到资产 ID:

  function registerAsset(bytes32 asset) public { 
    if (address(assetOwners[asset]) == address(0))
      {
        assetOwners[asset] = msg.sender;
      }
  } 

借助于资产 ID,可以从映射数据结构中存储的信息中检索资产的所有者:

  function queryAsset(bytes32 asset) view public returns (address) 
  { 
    return assetOwners[asset]; 
  } 

transferAsset函数在验证资产的当前所有者与调用合同的所有者相同后,将所有权转移到新地址:

  function transferAsset(bytes32 asset, address owner) public { 
    if (assetOwners[asset] == msg.sender) 
    { 
      assetOwners[asset] = owner; 
    } 
  } 

当资产的所有者调用合同时,deleteAsset函数将为资产分配一个空地址:

  function deleteAsset(bytes32 asset) public { 
    if (assetOwners[asset] == msg.sender) 
    { 
      assetOwners[asset] = 
 0x0000000000000000000000000000000000000000; 
    } 
  } 
} 

与之前的智能合约部署类似,应该在migrations文件夹内的新 JavaScript 文件(2_deploy_contracts.js)中创建以下配置,或者应该更新现有的1_initial_migration.js文件:

var ProofOfOwnership= artifacts.require("./ProofOfOwnership.sol"); 
module.exports = function(deployer) { 
  deployer.deploy(ProofOfOwnership); 
}; 

然后可以使用 Truffle 框架编译和迁移智能合约,如前面的示例所示:

$ truffle migrate 
Deploying ProofOfOwnership... 
  ... 0x0902a793d20a3846935fffa9558fb8a2f59f74edd2ef811189c9dcdd0a0aedcc 
  ProofOfOwnership: 0xc58b4e456b840ca924ddc1c971932febec717e95 

执行智能合同

让我们考虑我们之前在 NEO 应用程序中使用的跟踪文档所有权的同一个例子。我们还将使用包含以下内容的相同文件作为资产:

This document was created by Alice. 

我们将使用 md5 (32 个字符)哈希算法来计算文件的资产 ID,而不是 SHA256 (64 个字符)。这是因为我们契约的映射数据结构中的键(bytes32)只能接受 32 个字符。以下是由 md5 算法生成的文件的 32 个字符或 128 位哈希值:

c9f50a3bdd2efccb7e34fbd8b42e9675 

一旦所有权证明智能合约部署到区块链,就可以从 Truffle 控制台调用它。让我们使用registerAsset函数注册资产:

$ truffle console 
truffle(development)> 
ProofOfOwnership.deployed().then((instance)=>
 instance.registerAsset("c9f50a3bdd2efccb7e34fbd8b42e9675", 
 {from: "0xebe41ec4c574fde7a1d13d333d17267ca93df491"})); 

如果调用节点有多个帐户,可以在函数调用中包含一个from地址,以标识调用契约的用户。由于registerAsset函数执行写操作,因此在执行过程中需要 GAS。交易创建后,将显示消耗的总气体量。

transferAsset将资产 ID 和新所有者地址作为参数:

ProofOfOwnership.deployed().then((instance)=>
 instance.transferAsset("c9f50a3bdd2efccb7e34fbd8b42e9675", 
 "0xfda013eecad647a2593aacbb3c18445f051d0f52", 
 {from: "0xebe41ec4c574fde7a1d13d333d17267ca93df491"})); 

我们可以随时查询资产,以检查文档的所有者:

ProofOfOwnership.deployed().then((instance)=>
 instance.queryAsset("c9f50a3bdd2efccb7e34fbd8b42e9675")); 

如果查询返回0xfda013eecad647a2593aacbb3c18445f051d0f52作为当前所有者,我们就成功执行了transferAsset函数。

应用程序的接口

通过将前端应用程序与以太坊区块链集成,可以创建一个完全成熟的分散式应用程序。我们可以利用web3.js库提供的 API 与区块链网络进行交互。我们已经使用了 Truffle 开发环境来部署和调用智能合约。在这一节中,我们将利用 Truffle 库与合同进行交流。

下面的代码可以在任何 JavaScript 运行时环境下执行,比如 Node.js,参考该书的 GitHub 库,查找使用 React 库的实现。

ProofOfOwnership.json是在合同编译期间创建的 ABI 文件。此 ABI 对于与智能合约通信至关重要:

import Web3 from 'web3'; 
import { default as contract } from 'truffle-contract'; 
import contract_artifacts from 
 './contracts/ProofOfOwnership.json'; 

如果代码在安装了桥接应用程序(如 MetaMask)的浏览器中执行,web3 对象将与提供程序一起被注入浏览器。还可以通过将提供程序设置为本地或任何其他远程 RPC 服务器节点来创建 web3 对象。

MetaMask 浏览器插件可以从 https://metamask.io 安装。一旦安装了附加组件,就必须创建一个帐户。用户必须将元掩码指向用于开发的私有区块链。由私人区块链(通过 Ganache CLI)创建的帐户可以导入到 MetaMask 钱包中,以便用于支付交易汽油。

const web3 = window.web3; 
if (typeof web3 !== 'undefined') 
{ 
  this.web3 = new Web3(web3.currentProvider); 
  this.user_address = this.web3.eth.accounts[0] 
} 
else 
{ 
  this.web3 = new Web3
 (new Web3.providers.HttpProvider("http://localhost:8545")); 
} 

可以从导入的 ABI 创建合同实例。然后,此契约实例可用于调用任何契约功能:

this.poo = contract(contract_artifacts); 
this.poo.setProvider(this.web3.currentProvider); 

下面的函数将调用契约的registerAsset函数,将assetID作为参数传递。当从浏览器执行该函数时,MetaMask 将弹出一个窗口,要求确认交易。合同功能将在交易确认后执行:

registerAsset(assetID) 
{ 
  try { 
    let user_address = this.user_address; 
    this.poo.deployed().then(function(contractInstance) { 

      contractInstance.registerAsset(assetID, {gas: 1400000, from: user_address}).then(function(c) { 
        console.log(c.toLocaleString()); 
      }); 
    }); 
  } 
  catch (err) { 
    console.log(err); 
  } 
} 

同样,查询函数将调用智能合约的queryAsset函数。由于queryAsset没有写入区块链,元掩码不会创建新的事务:

  queryAsset(assetID) 
  { 
    try { 
      let user_address = this.user_address; 
      this.poo.deployed().then(function(contractInstance) { 

        contractInstance.queryAsset
 (assetID, {gas: 1400000, from: user_address}).then(function(c) { 
          console.log(c.toLocaleString()); 
        }); 
      }); 
    } 
    catch (err) { 
      console.log(err); 
    } 
  } 

所有权证明应用程序的所有其他功能都可以以类似的方式实现。请参考 GitHub 存储库(https://GitHub . com/packt publishing/Foundations-of-block chain)了解应用程序的完整前端实现。

现在我们已经使用 NEO 和以太坊区块链平台实现了所有权证明应用程序,我们有足够的信息在这些平台上构建其他应用程序。由于我们也比较了两个平台的功能,我们可以根据需求决定最适合实现任何用例的平台。

摘要

在这一章中,我们深入探讨了智能合约的创建和使用,以及使用 NEO 和 Ethereum 平台来构建一个去中心化的应用程序。在创建了 NEO 和以太坊区块链的基础之后,我们创建了一个所有权证明系统来证明资产的所有权。

这一章希望通过向你介绍智能契约来激励你开发分散的应用程序。在下一章中,我们将通过探索不同领域的项目来探索区块链技术的实际应用。


我们一直在努力

apachecn/AiLearning

【布客】中文翻译组