【一步步一起学DApp开发】(四)web3.js 基本使用 | 连接geth | 创建web客户端

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【一步步一起学DApp开发】(四)web3.js 基本使用 | 连接geth | 创建web客户端

概述

web3.js内部使用JSONRPC与geth通信。它把所有JSON-RPC API当作JavaScript API,也就是说,它不仅支持所有与以太坊相关的API,还支持与Whisper和Swarm相关的API。

相关链接

web3.js托管地址

web3.js文档

导入web3.js

为了在node.js中使用web3.js,可以在项目目录中运行npm install web3,且在源代码中可以使用require("web3")导入它。

与节点连接

web3.js可以与使用HTTP或者IPC的节点通信。我们将使用HTTP与节点建立通信。web3.js允许与多个节点建立连接。一个web3实例代表与节点的一个连接。

当在Mist中运行一个App时,它自动使一个连接到mist节点的web3实例可用。实例变量名是web3。

连接到节点所使用的基础代码:

if(typeof web3!=='undefined'){
  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}

解释:

首先,通过检查web3是否是undefined,来确定代码是否在Mist中运行。如果web3被定义了,则使用已经可用的实例;否则,通过连接至自定义节点创建一个实例。

Web3.providers对象使用多种协议显示构造函数(在此称为providers),以建立连接和传输信息。Web3.providers.HttpProvider允许建立HTTP连接,Web3.providers.IpcProvider允许建立IPC连接。

web3.currentProvider属性被自动分配给当前的provider实例。在创建web3实例之后,可使用web3.setProvider()方法改变provider。它有一个实参,即新provider的实例。

注意

  • geth默认禁用HTTP-RPC。所以在运行geth时通过–rpc选项以使用HTTP-RPC。HTTP-RPC默认在8545端口运行。
  • web3显示isConnected()方法,可用于查询是否已经与节点连接。
    根据连接状态的不同,返回true或者false。

API 结构

  • web3包含一个eth对象(web3.eth),专门用于以太坊区块链交互;
  • 一个shh对象(web3.shh),用于whisper交互;
  • 所有API都是默认同步的。如果想发出异步请求,可以把一个可选回调函数作为最后的参数传送给大多数函数。所有回调函数都采用错误优先(error-first)回调方式。

BigNumber.js

由于JS本身对于处理大数字不在行,所以,web3.js依赖BigNumber.js进行大数字的处理与计算。

如:

web3.eth.getBalance("0x27E829fB34d14f338464F938165dfcD30FfB7c").toString();//使用web3.eth.getBalance()方法获取地址余额,该方法返回一个BigNumber对象

需要在BigNumber对象上调用toString(),把它转换成数字字符串。

注意:

BigNumber.js不能正确处理有超过20个浮点数位的大数字,因此推荐以wei为单位存储余额,在显示时再转换成其他单位。web3.js自身总是以wei为单位返回和调取余额。

单位换算

web3.js提供了把wei余额转换成任何其他单位和把任何其他单位余额转换成wei的API。

  • web3.fromWei()方法用于将wei转换成其他单位
  • web3.toWei()方法用于将以其他单位表示的数字转化成以wei为单位的数字

如:

web3.fromWei("1000000000000000","ether");//将wei转换为ether
web3.toWei("0.0000000000000001","ether");//将ether转换为wei

第二个实参可以是以下字符串之一:

  • kwei/ada
  • mwei/babbage
  • gwei/shannon
  • szabo
  • finney
  • ether
  • kether/grand/einstein
  • mether
  • gether
  • tether

检索gas价格、余额和交易细节

  • web3.eth.gasPrice():由x个最新区块的gas价格中位数决定gas价格。
  • web3.ethgetBalance():返回任何给定地址的余额,给定的地址应当是十六进制的字符串。
  • web3.eth.getTransactionReceipt():获取交易使用其哈希的细节。如果在区块链中发现交易,则返回交易数据对象;否则,返回null。

交易数据对象包含下列属性:

  • blockHash:该交易所在区块的哈希地址。
  • blockNumber:该交易所在区块的序号。
  • transactionHash:交易哈希。
  • transactionIndex:区块中交易索引位置的整数部分
  • from:发起人地址。
  • to:接收者地址,如果是合约创建交易,则为null。
  • cumulativeGasUsed:在区块中执行该交易时使用的gas总量。
  • gasUsed:这个特定交易独自使用的gas量。
  • contractAddress:如果交易是合约创建,表示被创建的合约地址,否则,为null。
  • logs:该交易生成的日志对象数组。

发送以太币

为了发送以太币,需要使用web3.eth.sendTransaction()方法。

该方法可用于发送任意种类的交易,但主要用于发送以太币,原因是使用这种方法部署合约或者调用合约方法比较麻烦——它要求生成交易数据而不是自动生成交易数据。

该方法的交易对象包含下列属性:

  • from 发送账户地址
  • to 可选项。信息目的地的地址,对于合约创建交易。
  • value 可选项。通常在转账中单位为wei
  • gas 可选,交易使用的gas量
  • gasPrice 可选,交易中以wei为单位的gas价格,默认为网络平均gas价格
  • data 可选,包含信息相关数据的字节字符串
  • nonce 可选,是个整数,每个交易都有一个相关计数nonce。该数字表示交易发起人发送的交易数量。如果未提供nonce,则自动确定。它的作用是防止重播攻击。如果使用的nonce大于交易应当有的nonce,则交易被放入一个队列直到其他交易数量到达。例如,如果下一个交易的nonce应该是4,而nonce被设为10,则geth在广播这个交易之前将等待之间的6个交易。nonce为10的交易称为排队交易,而不是待定交易。

示例-向一个地址发送以太币

var txnHash = web3.eth.sendTransaction({
  from: web3.eth.accounts[0],
  to : web3.eth.accounts[1],
  value: web3.toWei("1","ether")
});

解释:

这里从账户0向账户1发送一个以太币。

处理合约

若要部署一个新合约或者获取一个已部署合约的引用,首先需要使用web3.eth.contract()方法创建一个合约对象。该方法以合约ABI作为一个实参,并返回合约对象。

例如:创建合约对象

var proofContract = web3.eth.contract([{
  //
}])

部署合约的示例:

var proof = proofContract.new({
  from: web3.eth.accounts[0],
  data: "0x606060405261068",
  gas:"4700000"
},
function(e,contract){
  if(e){
    console.log("Error"+e);
  }else if(contract.address!=undefined){
    console.log("Contract Address:"+contract.address);
  }else {
    console.log("Txn Hash:"+Contract.transactionHash)
  }
})

其中,new方法的调用是异步的,所以如果成功创建和广播交易,回调函数将被调用两次。第一次,广播交易之后调用它;第二次,挖出交易之后调用它。如果不提供回调函数,则proof变量的address属性被设成undefined。挖出交易之后,address属性将被设置。

在proof合约中,没有构造函数,但是如果有构造函数,则构造函数实参应当放在new方法的开头。传送的对象包含from地址、合约字节码和使用的gas上限。这三个属性必须存在,否则无法创建交易。该对象可以有被传送给sendTransaction方法的对象所展示的属性,但是这里,data是合约字节码,且to属性被忽略。

可以用at方法引用一个已经部署的合约:

var proof = proofContract.at("0xd45e43df3234sdfsdfa32423423432dfsf232");

如何发送交易以调用合约方法:

proof.set.sendTransaction("Owner Name",
"e3jksdfk234j32k4j23l4234jkdsjfkdsjfkj989898989234mkdf",{
from: web3.eth.account[0],
},function(error,transactionHash){
  if(!err)
  console.log(transactionHash);
})

解释:

这里调用方法同名对象的sendTransaction方法。被传送给这个sendTransaction方法的对象属性与web3.eth.sendTransaction()相同,只是data和to属性被忽略了

如果想调用节点本地的方法,而非创建交易并广播,则可使用call而非sendTransaction。

var returnValue = proof.get.call("e3jksdfk234j32k4j23l4234jkdsjfkdsjfkj989898989234mkdf");

找到调用方法所需的gas,以便决定是否调用:estimateGas()方法

var returnValue = proof.get.estimateGas("e3jksdfk234j32k4j23l4234jkdsjfkdsjfkj989898989234mkdf");

检索和监听合约事件

在了解如何检索和监听事件之前,我们需要学习事件的索引参数。一个事件最多有三个参数可以有被索引(indexed)属性。该属性用于提示节点对它进行索引,这样应用客户端可以用匹配返回值来检索事件。如果不使用indexed属性,则必须检索所有事件,并筛选出需要的那些事件。

监听合约事件示例:

var event = proof.logFileAddedStatus(null,{
fromBlock:0,
toBlock:"latest"
});
event.get(function(error,result){
  if(!error){
    console.log(result)
  }
  else {
    console.log(error)
  }
})
event.watch(function(error,result){
  if(!error){
    console.log(result.args.status)
  }else {
    console.log(error)
  }
})
setTimeout(function(){
  event.stopWatching();
},60000)
var events = proof.allEvents({
  fromBlock:0,
  toBlock:"latest"
});
events.get(function(error,result){
  if(!error){
    console.log(result)
  }else {
    console.log(error)
  }
})
events.watch(function(error,result){
  if(!error){
    console.log(result.args.status);
  }else {
    console.log(error)
  }
})
setTimeout(function(){
  events.stopWatching();
},60000);

解析:

  • 调用一个合约实例的事件同名的方法获取事件对象。该方法用两个对象作为实参,用于筛选事件:

第一个对象用索引返回数值筛选事件。例如,{‘valueA’:1,‘valueB’:[myFirstAddress,mySecondAddress]}。所有筛选数值都默认设置为null。这意味着它们将匹配该合约发出的任意类型事件。

第二个对象可以包含三个属性,即fromBlock(搜索起始区块,默认为"latest")、toBlock(搜索截至区块,默认为"latest")和address(仅获取日志的地址列表;默认为合约地址)。

  • 事件对象显示三种方法:get、watch和stopWatching。get用于获取区块范围内的所有事件。watch与get类似,但是它在获取事件后还监听变化。stopWatching可以用于停止监听变化。
  • 合约实例的allEvents方法用于检索合约的所有事件。
  • 每一个事件由一个包含下列属性的对象代表。

args:一个带有来自事件的实参的对象。

event:用一个字符串表示事件名。

logIndex:用一个整数表示区块中的日志索引位置。

transactionIndex:用一个整数表示日志最初的交易索引位置。

transactionHash:用一个字符串表示日志最初的交易哈希。

address:用一个字符串表示日志最初的地址。

blockHash:用一个字符串表示日志所在区块的哈希。如待定,则为null。

blockNumber:日志所在区块的序号。如待定,则为null

web3.js提供web3.eth.filter API以检索和监听事件:

https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethfilter

为所有权合约创建客户端

首要我们要知道这是什么样个客户端?

在客户端中,用户从中选择一个文件,输入所有者细节,然后按下Submit按钮广播交易,用文件哈希和所有者的细节调用合约的set方法。一旦交易被成功广播,将显示交易哈希。用户还能够选择一个文件,并从智能合约中得到所有者的细节。客户端还将实时显示最新挖出的set交易。

思路:

在前端使用sha1.js获取文件哈希,使用jQuery进行DOM操纵,并使用Bootstrap 4创建一个反应层(responsive layout)。在后端使用express.js和web3.js。我们将使用socket.io,这样不需要前端间隔相等的时间请求数据,后端就把最近挖出的交易推到前端。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
15天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
101 44
|
3天前
|
JavaScript 前端开发 测试技术
探索现代JavaScript开发的最佳实践
本文探讨了现代JavaScript开发中的最佳实践,涵盖ES6+特性、现代框架使用、模块化与代码分割、测试驱动开发、代码质量与性能优化、异步编程、SPA与MPA架构选择、服务端渲染和静态站点生成等内容,旨在帮助开发者提升代码质量和开发效率。
|
6天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第36天】本文将引导您探索Node.js的世界,通过实际案例揭示其背后的原理和实践方法。从基础的安装到高级的异步处理,我们将一起构建一个简单的后端服务,并讨论如何优化性能。无论您是新手还是有经验的开发者,这篇文章都将为您提供新的视角和深入的理解。
|
11天前
|
Web App开发 存储 JavaScript
深入浅出Node.js后端开发
【10月更文挑战第31天】本文将引导你进入Node.js的奇妙世界,探索其如何革新后端开发。通过浅显易懂的语言和实际代码示例,我们将一起学习Node.js的核心概念、搭建开发环境,以及实现一个简单但完整的Web应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇通往高效后端开发的大门。
|
8天前
|
运维 监控 JavaScript
鸿蒙next版开发:分析JS Crash(进程崩溃)
在HarmonyOS 5.0中,JS Crash指未处理的JavaScript异常导致应用意外退出。本文详细介绍如何分析JS Crash,包括异常捕获、日志分析和典型案例,帮助开发者定位问题、修复错误,提升应用稳定性。通过DevEco Studio收集日志,结合HiChecker工具,有效解决JS Crash问题。
25 4
|
11天前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
26 1
|
12天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第30天】本文将通过一个Node.js的简单示例,引导你进入Node.js的世界。我们将从基础概念讲起,然后一步步深入到代码实现,最后总结Node.js在后端开发中的优势和应用场景。无论你是前端开发者还是后端新手,这篇文章都将为你打开一扇了解Node.js的大门。
26 2
|
13天前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
16天前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
29 2
|
9天前
|
Web App开发 JavaScript 前端开发
探索后端开发:Node.js与Express的完美结合
【10月更文挑战第33天】本文将带领读者深入了解Node.js和Express的强强联手,通过实际案例揭示它们如何简化后端开发流程,提升应用性能。我们将一起探索这两个技术的核心概念、优势以及它们如何共同作用于现代Web开发中。准备好,让我们一起开启这场技术之旅!
25 0