使用JavaScript 来开发 DApp时,很多时候需要使用到 web3.js。当然,也可以选择使用ethers.js
整个合约代码的执行需要一个虚拟机环境,所以选择安装一个实现了以太坊虚拟机的节点,EtherumJS TestRPC 它在执行交易时是实时返回,可以快速验证新写的代码,当出现错误时,也能即时反馈
npm install -g ethereumjs-testrpc
通过testrpc
命令来启动了,启动与大多数以太坊节点一样,运行在localhost:8545
将 web3.js 引入到项目中
//npm
npm install web3
//yarn
yarn add web3
//js
dist/web3.min.js
首先创建一个 web3 的实例,设置一个 provider,可以支持MetaMask(小狐狸),会有提供一个web3.currentProvider
检查 Web3.givenProvider
,如果属性为 null
再连接本地或远程的节点
mist也有一个内置,
需要先检查是否web3
实例已存在,这样是为了避免重复设置的情况
//引入web3
const Web3 = require('web3');
//检查方法1 Web3.givenProvider 当前环境的原生 provider 会被浏览器设置
//web3.givenProvider 将返回浏览器设置的原生 provider 集,返回 null 再连接本地或远程的节点
const web3 = new Web3(Web3.givenProvider || "ws://localhost:8545");
//检查方法2
if (typeof web3 !== 'undefined') {
//创建一个 web3 的实例,返回值 Object: 当前在用的 provider 或者 null;
web3 = new Web3(web3.currentProvider);
} else {
//因为不能用于订阅,HTTP provider 官方已经**不推荐使用**
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
//3
if(!web3.currentProvider)
web3.setProvider(new web3.providers.HttpProvider("http://localhost:8545"));
所有函数默认使用同步的HTTP的请求,如果你想发起一个异步的请求。大多数函数允许传一个跟在参数列表后的可选的回调函数来支持异步。回调函数支持error first callback的风格
web3.eth.getBlock(48, function(error, result){
if(!error)
console.log(result)
else
console.error(error);
})
大多数的 web3 对象允许将一个回调函数作为最后一个函数参数传入,同时会返回一个promise 用于链式函数调用。以太坊作为区块链具有不同级别的确定性,因此需要返回一个动作的多个“阶段”,为了满足要求 web3.eth.sendTransaction 函数返回一个“promiEvent” ,PromiEvents 的工作方式与添加了on
,once
和off
功能的普通 Promise 类似。通过这种方式,开发人员可以监听其他事件,例如“receipt”或“transactionHash”
web3.eth.sendTransaction({from: '0x123...', data: '0x432...'})
.once('transactionHash', function(hash){ ... })
.once('receipt', function(receipt){ ... })
.on('confirmation', function(confNumber, receipt){ ... })
.on('error', function(error){ ... })
.then(function(receipt){
// will be fired once the receipt is mined
});
json 接口是描述以太坊智能合约的应用程序二进制接口 (ABI)的 json 对象。
使用这个 json 接口 web3.js 能够使用 web3.eth.Contract 对象创建表示智能合约及其方法和事件的JavaScript 对象
可以允许将多个请求放入队列,并一次执行
注意:批量请求并不会更快,在某些情况下,同时发起多个请求,由于是异步的,会变得更快。但这里的批量请求主要目的是用来保证请求的串行执行
//1
var batch = web3.createBatch();
batch.add(web3.eth.getBalance.request('0x0000000000000000
000000000000000000000000 ', '
latest ', callback));
batch.add(web3.eth.contract(abi).at(address).balance.request(a ddress, callback2)); batch.execute();
//2
var contract = new web3.eth.Contract(abi, address);
var batch = new web3.BatchRequest();
batch.add(web3.eth.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback));
batch.add(contract.methods.balance(address).call.request({from: '0x0000000000000000000000000000000000000000'}, callback2));
batch.execute();
布隆过滤器是一种概率性的、节省空间的数据结构,用于快速检查集合成员。型数据集中能够快速测试某个元素当前是否在该集中,可以大大减少我们必须进行的数据库查询的数量
该包为以太坊 dapps 和其他 web3.js 包提供实用功能。是Web3类的静态可访问属性也是Web3实例的属性
//源码来源于:http://me.tryblockchain.org/
let Web3 = require('web3');
let web3;
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
let from = web3.eth.accounts[0];
//编译合约
let source = "pragma solidity ^0.4.0;contract Calc{ /*区块链存储*/ uint count; /*执行会写入数据,所以需要`transaction`的方式执行。*/ function add(uint a, uint b) returns(uint){ count++; return a + b; } /*执行不会写入数据,所以允许`call`的方式执行。*/ function getCount() constant returns (uint){ return count; }}";
let calcCompiled = web3.eth.compile.solidity(source);
console.log(calcCompiled);
console.log("ABI definition:");
console.log(calcCompiled["info"]["abiDefinition"]);
//得到合约对象
let abiDefinition = calcCompiled["info"]["abiDefinition"];
let calcContract = web3.eth.contract(abiDefinition);
//2. 部署合约
//2.1 获取合约的代码,部署时传递的就是合约编译后的二进制码
let deployCode = calcCompiled["code"];
//2.2 部署者的地址,当前取默认账户的第一个地址。
let deployeAddr = web3.eth.accounts[0];
//2.3 异步方式,部署合约
let myContractReturned = calcContract.new({
data: deployCode,
from: deployeAddr
}, function(err, myContract) {
if (!err) {
// 注意:这个回调会触发两次
//一次是合约的交易哈希属性完成
//另一次是在某个地址上完成部署
// 通过判断是否有地址,来确认是第一次调用,还是第二次调用。
if (!myContract.address) {
console.log("contract deploy transaction hash: " + myContract.transactionHash) //部署合约的交易哈希值
// 合约发布成功后,才能调用后续的方法
} else {
console.log("contract deploy address: " + myContract.address) // 合约的部署地址
//使用transaction方式调用,写入到区块链上
myContract.add.sendTransaction(1, 2,{
from: deployeAddr
});
console.log("after contract deploy, call:" + myContract.getCount.call());
}
// 函数返回对象`myContractReturned`和回调函数对象`myContract`是 "myContractReturned" === "myContract",
// 所以最终`myContractReturned`这个对象里面的合约地址属性也会被设置。
// `myContractReturned`一开始返回的结果是没有设置的。
}
});
//注意,异步执行,此时还是没有地址的。
console.log("returned deployed didn't have address now: " + myContractReturned.address);
//使用非回调的方式来拿到返回的地址,但你需要等待一段时间,直到有地址,建议使用上面的回调方式。
/*
setTimeout(function(){
console.log("returned deployed wait to have address: " + myContractReturned.address);
console.log(myContractReturned.getCount.call());
}, 20000);
*/
//如果你在其它地方已经部署了合约,你可以使用at来拿到合约对象
//calcContract.at(["0x50023f33f3a58adc2469fc46e67966b01d9105c4"]);