以太坊智能合约客户端简介(Web3js库)

在最后两篇文章(此处和此处)中讨论了固态智能合约设计和问题之后,我们将研究如何将智能合约与企业客户应用程序集成。有多种技术可以与以太坊节点(以太坊区块链客户端)进行交互.

运行智能合约的EVM(以太坊虚拟机)的基本体系结构是,对合约的所有调用都作为事务执行,其中执行合约方法所需的以太币从调用账户地址转移到合约账户地址。合同代码位于区块链上的合同地址上,并期望这些调用作为携带方法参数数据的交易以及作为“输入”的交易进入。要为所有客户端启用标准格式,需要以推荐的格式对方法名称和参数进行编组.

以太坊智能合约客户端简介(Web3js库)

JSON-RPC

以太坊标准客户端公开了一个接口,用于使RPC(远程过程调用)与部署在区块链上的合同代码进行交互。这称为RPC接口,用作go,c ++和奇偶校验客户端的默认端口8545上的HTTP发布请求。通常可以将其定制为命令参数或配置文件属性:

–rpc –rpcaddr <ip> –rpcport <端口号>

流行的RPC格式结构 JSON-RPC 格式。该格式非常复杂,尤其是对于基于类型的参数值编组。必须遵循建议的编码方案,并使用正确的填充进行定义,以确保EVM能够对其进行解码.

由于JSON_RPC格式的底层复杂性,因此有许多包装程序库可简化调用格式。最古老的是JavaScript包装器 web3.js 在浏览器和nodejs实例中均可使用。本讨论并非旨在取代所有API定义的参考文档,请参阅上面的链接以获取特定的API调用。在这里,我们将使用一组特定的API来创建建议,以实现针对智能合约的基于浏览器的客户端.

安装web3.js

要将web3安装为节点,浏览器或流星软件​​包,请遵循上述github指令。如果使用-g安装节点模块,则将其安装在路径/ usr / lib / node_modules / web3中。请确保此目录存在以下结构中的依赖项(这是经过测试的Linux操作系统,请参阅您的OS特定的nodejs文档以获取特定于OS的路径),这对于nodejs运行时查找所有依赖项很重要图书馆.

/ usr / lib / node_modules / web3

├──bower.json

├──bundled.js

├──circle.yml

├──coder.js

├──dist

│├──web3.js

│├──web3.js.map

│├──web3-light.js

│├──web3-light.min.js

│└──web3.min.js

├──例子

│├──balance.html

│├──contract_array.html

│├──contract.html

│├──event_inc.html

│├──icap.html

│├──namereg.html

│└──node-app.js

├──gulpfile.js

├──index.js

├──lib

│├──合约

││├──GlobalRegistrar.json

││├──ICAPRegistrar.json

││└──SmartExchange.json

│├──坚固

││├──address.js

││├──bool.js

││├──bytes.js

││├──coder.js

││├──dynamicbytes.js

││├──formatters.js

││├──int.js

││├──param.js

││├──real.js

││├──string.js

││├──type.js

││├──uint.js

││└──ureal.js

│├──公用程式

││├──browser-bn.js

││├──browser-xhr.js

││├──config.js

││├──sha3.js

││└──utils.js

│├──version.json

│├──web3

││├──allevents.js

││├──batch.js

││├──contract.js

││├──errors.js

││├──event.js

││├──extend.js

││├──filter.js

││├──formatters.js

││├──function.js

││├──httpprovider.js

││├──iban.js

││├──ipcprovider.js

││├──jsonrpc.js

││├──method.js

││├──方法

│││├──db.js

│││├──eth.js

│││├──net.js

│││├──personal.js

│││├──shh.js

│││├──swarm.js

│││└──watchs.js

││├──namereg.js

││├──property.js

││├──requestmanager.js

││├──settings.js

││├──syncing.js

││└──transfer.js

│└──web3.js

├──许可

├──node_modules

│├──bignumber.js

││├──bignumber.js

││├──bignumber.js.map

││├──bignumber.min.js

││├──bower.json

││├──文件

│││└──API.html

││├──许可

││├──package.json

││└──README.md

│├──crypto-js

││├──aes.js

││├──bower.json

││├──cipher-core.js

││├──CONTRIBUTING.md

││├──core.js

││├──crypto-js.js

││├──文档

│││└──QuickStartGuide.wiki

││├──enc-base64.js

││├──enc-hex.js

││├──enc-latin1.js

││├──enc-utf16.js

││├──enc-utf8.js

││├──evpkdf.js

││├──format-h​​ex.js

││├──format-openssl.js

││├──hmac.js

││├──hmac-md5.js

││├──hmac-ripemd160.js

││├──hmac-sha1.js

││├──hmac-sha224.js

││├──hmac-sha256.js

││├──hmac-sha384.js

││├──hmac-sha3.js

││├──hmac-sha512.js

││├──index.js

││├──lib-typedarrays.js

││├──许可

││├──md5.js

││├──mode-cfb.js

││├──mode-ctr-gladman.js

││├──mode-ctr.js

││├──mode-ecb.js

││├──mode-ofb.js

││├──package.json

││├──pad-ansix923.js

││├──pad-iso10126.js

││├──pad-iso97971.js

││├──pad-nopadding.js

││├──pad-pkcs7.js

││├──pad-zeropadding.js

││├──pbkdf2.js

││├──rabbit.js

││├──Rabbit-legacy.js

││├──rc4.js

││├──README.md

││├──maturemd160.js

││├──sha1.js

││├──sha224.js

││├──sha256.js

││├──sha384.js

││├──sha3.js

││├──sha512.js

││├──Tripledes.js

││└──x64-core.js

│├──utf8

││├──LICENSE-MIT.txt

││├──package.json

││├──README.md

││└──utf8.js

│├──xhr2

││├──Cakefile

││├──CONTRIBUTING.md

││├──lib

│││├──browser.js

│││└──xhr2.js

││├──LICENSE.txt

││├──package.json

││├──README.md

││├──src

│││├──000-xml_http_request_event_target.coffee

│││├──001-xml_http_request.coffee

│││├──错误。咖啡

│││├──progress_event.coffee

│││└──xml_http_request_upload.coffee

││└──测试

││├──固定装置

│││├──hello.json

│││├──hello.txt

│││└──xhr2.png

││├──html

│││└──browser_test.html

││└──src

││├──events_test.coffee

││├──event_target_test.coffee

││├──headers_test.coffee

││├──帮手

│││├──browser_mocha_runner.coffee

│││├──browser_mocha_setup.coffee

│││├──setup.coffee

│││└──xhr_server.coffee

││├──nodejs_set_test.coffee

││├──redirect_test.coffee

││├──response_type_test.coffee

││├──回应url_test.coffee

││├──send_test.coffee

││├──status_test.coffee

││└──xhr_test.coffee

│└──xmlhttprequest

│├──lib

││└──XMLHttpRequest.js

│├──许可

│├──package.json

│└──README.md

├──package-init.js

├──package.js

├──package.json

├──README.md

├──styleguide.md

└──纱线锁

Nodejs Web3js运行

Nodejs是一种流行的服务器端javascript运行时框架。它支持许多中间件项目,使nodejs与智能合约进行交互是有意义的。请参考一些节点文档,了解如何在平台上安装nodejs.

用节点环境测试您的web3安装。请将以下代码保存到js文件中,并在您的节点运行时中运行它。请确保在本地计算机上的端口8545上运行了一个以太坊节点(或将其更改为已配置的以太坊节点-请参阅前面有关设置私有节点的文章).

console.log("开始…");

var Web3 = require(’/ usr / lib / node_modules / web3’);

web3 =新的Web3(新的Web3.providers.HttpProvider(’http:// localhost:8545’));

console.log(web3.eth.accounts);

如果安装中没有问题,将显示以下输出:

local @ local-Lenovo-G50-70:/ nodeinstall / node $节点eth.js

开始…

[‘0x81c95efa213ed798cc99e80f79eece314f76fbe8’]

local @ local-Lenovo-G50-70:/ nodeinstall / node $

这将打印以太坊节点可用的账户数组。 (目前,在这种情况下只有一个) .

我们将在以下各节中讨论的所有web3功能也将在节点环境中可用。从现在开始,我们将专注于基于浏览器的执行,如果您在节点实例中遇到任何特定问题,请与我联系。.

在–浏览器中运行Web3js

可以将Web3导入浏览器html代码中,以创建合同的UI。不建议使用此方法,因为您不会为客户端浏览器计算机提供与之连接的RPC接口。通常,您将有一个企业应用程序连接到您的以太坊节点,而不是浏览器。这就是我们使用nodejs进行测试很重要的原因。还有其他诸如Java之类的传统技术需要与以太坊智能合约连接。如果我们遵循规定的JSON-RPC格式,则有多种方法可以在每种技术中创建包装器库。但是,我们将坚持使用浏览器内的javascript环境,以查看以太坊客户端提供的所有设施和功能。.

让我们看一个简单的HTML页面,该页面可导入web3 js并进行简单的合同调用.

&lt; html&gt;

&头&gt;

&lt;标题&gt; eth web3测试器&lt; /标题&gt;

&lt;脚本src ="https://static.blockgeeks.com/usr/lib/node_modules/web3/lib/web3.js"&gt;&lt; /脚本&gt;

&lt;脚本&gt;

&nbsp;

函数start(){

var Web3 = require(’web3’);

var web3 = new Web3();

web3.setProvider(new web3.providers.HttpProvider(’http:// localhost:8545’));

var abi = […];

var corecontractContract = web3.eth.contract(abi);

var corecontractContractInst = corecontractContract

.在(’0x0e22a4f27c2fc3b47e66b70fada85e1c4ca33681’); console.log(corecontractContract.createCustomer(287187,“ custName”,13243244,1213334));

}

&lt; /脚本&gt;

&lt; /头&gt;

&lt; body onload ="开始();"&gt;

&机身&gt;

&lt; / html&gt;

可以直接从节点模块安装中的lib文件夹导入web3.js。建议使用压缩版本,但是我使用扩展版本进行测试,以便能够从浏览器中调试到库中。请不要在不更改代码的情况下复制粘贴上面的代码,并添加合同ABI并将事务对象添加到createCustomer方法调用中.

合约ABI

我们应该快速了解一下合同 阿比 (应用程序二进制接口)。合同ABI规范是合同方法和变量签名的JSON数组。 ABI定义每种参数类型所需的编码,因为它构成触发合同方法的交易输入的一部分.

如您所见,在上一篇文章中,您使用Remix浏览器应用程序来编译合同,该应用程序创建了一个ABI。对于数据合同,ABU看起来像这样:

[{"持续的":真的,"输入":[],"姓名":"数数","输出":[{"姓名":"","类型":"uint256"}],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"候选人","类型":"地址"},{"姓名":"方法","类型":"细绳"}],"姓名":"isUserAuthorized","输出":[{"姓名":"","类型":"布尔"}],"应付款":错误的,"类型":"功能"},{"持续的":真的,"输入":[{"姓名":"","类型":"uint256"}],"姓名":"使用者","输出":[{"姓名":"","类型":"地址"}],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[],"姓名":"杀","输出":[],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"用户","类型":"地址"}],"姓名":"添加用户","输出":[],"应付款":真的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"候选人","类型":"地址"},{"姓名":"方法","类型":"细绳"}],"姓名":"isUser","输出":[{"姓名":"","类型":"布尔"}],"应付款":错误的,"类型":"功能"},{"持续的":真的,"输入":[{"姓名":"一世","类型":"uint256"}],"姓名":"getIthUser","输出":[{"姓名":"","类型":"地址"}],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"指数","类型":"uint256"},{"姓名":"姓名","类型":"细绳"}],"姓名":"updateCustomer","输出":[],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"一世","类型":"uint256"}],"姓名":"deleteIthUser","输出":[],"应付款":错误的,"类型":"功能"},{"持续的":真的,"输入":[],"姓名":"所有者","输出":[{"姓名":"","类型":"地址"}],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"指数","类型":"uint256"},{"姓名":"状态","类型":"uint256"}],"姓名":"updateCustomerStatus","输出":[],"应付款":错误的,"类型":"功能"},{"持续的":错误的,"输入":[{"姓名":"ID","类型":"uint256"},{"姓名":"姓名","类型":"细绳"},{"姓名":"出生日期","类型":"uint256"},{"姓名":"社会的","类型":"uint256"}],"姓名":"createCustomer","输出":[],"应付款":错误的,"类型":"功能"},{"持续的":真的,"输入":[],"姓名":"getUserCount","输出":[{"姓名":"","类型":"uint256"}],"应付款":错误的,"类型":"功能"},{"持续的":真的,"输入":[{"姓名":"指数","类型":"uint256"}],"姓名":"getCustomer","输出":[{"姓名":"ID","类型":"uint256"},{"姓名":"姓名","类型":"细绳"},{"姓名":"出生日期","类型":"uint256"},{"姓名":"社会的","类型":"uint256"},{"姓名":"状态","类型":"uint256"}],"应付款":错误的,"类型":"功能"},{"持续的":真的,"输入":[{"姓名":"ID","类型":"uint256"}],"姓名":"getCustomerById","输出":[{"姓名":"idRet","类型":"uint256"},{"姓名":"姓名","类型":"细绳"},{"姓名":"出生日期","类型":"uint256"},{"姓名":"社会的","类型":"uint256"},{"姓名":"状态","类型":"uint256"}],"应付款":错误的,"类型":"功能"},{"匿名的":错误的,"输入":[{"索引":错误的,"姓名":"事件类型","类型":"细绳"},{"索引":错误的,"姓名":"ID","类型":"uint256"}],"姓名":"警报","类型":"事件"},{"匿名的":错误的,"输入":[{"索引":真的,"姓名":"经过","类型":"地址"},{"索引":真的,"姓名":"访问时间","类型":"uint256"},{"索引":错误的,"姓名":"方法","类型":"细绳"},{"索引":错误的,"姓名":"描述","类型":"细绳"}],"姓名":"日志访问","类型":"事件"}]

如您所见,它具有超级合约和当前合约中的方法,并带有签名,参数和返回类型。这需要直接作为json数组传递到合同(abi)构造函数中,以创建合同的蓝图或类.

var abi = […];

var corecontractContract = web3.eth.contract(abi);

这种机制确保可以直接在合同类的实例上调用任何方法。下一条语句创建合同类corecontractContract的实例

var corecontractContractInst = corecontractContract

.在(’0x0e22a4f27c2fc3b47e66b70fada85e1c4ca33681’);

现在,合同已绑定到“安装”合同代码的地址。现在我们可以调用合同中的方法.

corecontractContract.createCustomer(287187,“ custName”,13243244,1213334);

该调用将返回提交给合同的交易的交易哈希.

附加参数:

与方法参数一起,该调用允许在方法调用内传递其他非功能性参数.

事务对象(这是参考文档中事务对象定义的副本,带有一些其他注释):

from:字符串-发送帐户的地址。使用 web3.eth.default帐户 属性(如果未指定)。默认帐户属性在初始化阶段指定为web3.eth.defaultAccount = web3.eth.accounts [0];。这表示我们将使用帐户数组中的第一个帐户,交易所需的费用将从该帐户中扣除.

to:字符串–(可选)消息的目标地址,对于合同创建交易未定义。因此,对于我们将交易对象用于智能合约调用的情况,则不需要.

值:Number | String | BigNumber –(可选)在Wei中为交易转移的值,如果是合同创建交易,则为捐赠。由于我们未创建合同(合同已经部署.

gas:Number | String | BigNumber –(可选,默认值:待定)用于交易的天然气量(未使用的天然气将退还)。在我们的情况下这很重要,因为我们需要传递一些气体,因此合同更新方法会获得完成执行所需的气体。混合应用程序中提供了每种方法的估算气量,我们需要使用增加到整数的值,以确保我们的交易不会因“气量不足”错误而失败.

gasPrice:Number | String | BigNumber –(可选,默认值:待定)此交易中以wei为单位的天然气价格,默认为平均网络天然气价格.

数据:字符串–(可选) 字节串 包含消息的相关数据,或者在进行合同创建交易的情况下,包含初始化代码。在我们的情况下,这不是必需的,因为我们不是部署调用.

随机数:数字–(可选)随机数的整数。这样可以覆盖使用相同随机数的未决事务.

合约常数调用Vs。交易电话

合同可以具有两种通过其实体代码实现的调用。持续调用不会更改合同状态,它只会读取区块链并返回其根据其逻辑过滤掉的值。这种类型的调用不需要任何以太币来执行,因此我们不需要在合约方法调用中传递任何gas参数。例如.

console.log(corecontractContractInst.getCustomer(0));

这将为uint返回一个BigNumbers数组:

[BigNumber, "客户", BigNumber,BigNumber,BigNumber]

要将BigNumbers转换为小数,请使用toDecimal(BigNumber)实用程序方法:

console.log(web3.toDecimal(corecontractContractInst.getCustomer(0)[0]));

此调用不会在区块链上创建交易.

交易调用旨在更新合同状态,例如在DataContract中的客户映射上创建记录.

corecontractContract.createCustomer(287187,“ custName”,13243244,1213334);

该调用将导致交易并消耗一些汽油。可以使用交易对象随交易提供天然气:

console.log(corecontractContractInst.createCustomer(133423,’aCust’,3334,454545),{gas:20000});

这里的20000是任意的,请使用从Remix应用程序执行方法估算的气体。如果气体量低于EVM的预期,则您将收到错误消息:

未捕获的错误:交易气体过低。没有足够的资金来支付最小的交易成本(最低:22680,获得:20000)。尝试增加供应的气体.

在Object.InvalidResponse(web3.js:3120)

在RequestManager.send(web3.js:6043)

0});

筛选条件:

我们可以从Solidity Contract生成的事件可以在Web3层上收听。该库遵循一种轮询机制来查找记录在区块链上的事件,并将其冒泡到web3层(如果生成了任何事件).

我们已经在ACLContract代码中创建了一些与访问控制有关的事件。通过使用allEvents()API订阅事件,我们可以侦听任何客户端调用生成的事件.

var events = corecontractContractInst.allEvents();

//注意变化

events.watch(function(error,event){

如果(!错误)

console.log(JSON.stringify(event));

});

这将输出如下事件:

{"地址":"0x969f563858ddef891e32de8d8c9232f6f74103d0","区块哈希":"0x9c44f138a2f1b3aa4a6457252e62fff56257329d17261901048b1d50176e39b4","blockNumber":47,"logIndex"0:,"transactionHash":"0xb4ca62b604c9cd43a0125703c07c8a1624963a8fd399b38f943357549f96c90a","transactionIndex"0:,"transactionLogIndex":"0x0","类型":"开采的","事件":"日志访问","args":{"经过":"0x81c95efa213ed798cc99e80f79eece314f76fbe8","访问时间":"1494178629","方法":"createCustomer","描述":"成功访问"}}

{"地址":"0x969f563858ddef891e32de8d8c9232f6f74103d0","区块哈希":"0x9c44f138a2f1b3aa4a6457252e62fff56257329d17261901048b1d50176e39b4","blockNumber":47,"logIndex"0:,"transactionHash":"0xb4ca62b604c9cd43a0125703c07c8a1624963a8fd399b38f943357549f96c90a","transactionIndex"0:,"transactionLogIndex":"0x0","类型":"开采的","事件":"日志访问","args":{"经过":"0x81c95efa213ed798cc99e80f79eece314f76fbe8","访问时间":"1494178629","方法":"createCustomer","描述":"成功访问"}}

上面是两次调用createCustomer时创建的两个事件。可以从单个订户接收事件,而多个源则可以通过JSON-RPC调用使用协定调用来生成事件。这样就可以创建一个用于捕获审核数据的应用程序.

在以上讨论中,我们介绍了javascript客户端的一些非常基础的知识。在下一个中,我们将研究一些高级概念,例如如何通过web3库编写功能的测试代码,如何使用松露框架创建完整的Dapp,以及其他内容。.

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me