【區塊鏈】以太坊Solidity編程:合約調用與web3.js

以太坊Solidity編程:合約調用與Web3.js

合約部署方法

合約的編譯

  • 使用瀏覽器編譯器Remix
  • 使用truffle編譯,目前是最常用的編譯方式
  • Solc或者Web3.js編譯合約,使用相對較少

基於Remix的編譯部署

  • Remix直接編譯即可
  • 部署使用remix的web3 provider形式
  • 部署也可用remix+metamask,但metamask安裝需要科學上網
  • Remix訪問的時候,建議使用http,而不是https

Truffle編譯

  • 合約應該位於./contracts目錄
  • 編譯合約命令:truffle compile
  • Truffle僅僅默認自上次編譯後被修改過的文件,來減少不必要的編譯。如果想要編譯全部文件,可以使用–compile-all選項。

Truffle編譯約定

  1. Truffle需要定義的合約名稱和文件名準確匹配,如文件名爲MyContract.sol,那麼合約文件須爲如下兩者之一:
  • contract MyContract {…}
  • library MyContract {…}
  1. Truffle文件名匹配是區分大小寫的,也就是說大小寫也要一致。
  2. 可以通過使用import來聲明依賴。Truffle將會按正確順序依次編譯合約,並在需要的時候自動關聯庫。
  3. 編譯的輸出位於./build/contracts目錄。如果目錄不存在會自動創建。

Truffle部署

Truffle通過truffle.js指定的以太坊網絡來部署,部署命令爲truffle deploy,如果truffle.js有多個網絡,可以使用networkc參數來指定。

Truffle配置文件

配置文件是truffle.js。位於項目的根目錄下。這個文件是Javascript文件,支持執行代碼來創建配置:

  • BUILD:這個是前端的構建配置。默認調用默認構建器。
  • NETWORKS:指定在部署時使用哪個網絡。
  • RPC:關於如何連接到以太坊客戶端的一些細節。host和port是必須的。還包括gas(部署時的Gas限制),gasPrice(部署時的Gas價格),from(移植時使用的源地址,默認是你的以太坊客戶端第一個可用賬戶).

Truffle配置文件示例:

module.export = {
	networks:{
		development:{
			host:"localhost",
			port:8545,
			network_id:"*" //匹配任何network id
		}
	}
};

Truffle deployer部署參數示例:

var Hello = artifacts.require("./Hello.sol");
var Multi = artifacts.require("./Multi.sol");

module.exports = function(deployer){
	//部署單個合約,不帶任何構造參數
	deployer.deploy(Hello)//部署單個合約帶有構造參數
	deployer.deploy(Multi,11);
	
	//部署多個合約,一些有參數,一些沒有參數
	/*
		deployer.deploy([
			[A,arg1,arg2,...],
			B,
			[C,arg1]
	]);
	*/
}

合約調用與web3.api

智能合約調用

以太坊支持通過各種方式與節點進行交互:

  • JSON-RPC
  • JavaScript Console
  • web3

JSON RPC

  • JSON RPC可以理解爲一個rest服務
  • 大部分客戶端均通過JSON RPC調功能、傳數據
  • JSON RPC只是一個傳輸通道,以太坊還有IPC的接口。
RPC調用客戶端命令

假設我們要調用客戶端命令eth.getBalance(),查詢地址爲0x407的賬號的餘額,命令如下:

curl --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407","latest"],"id":1}' localhost:8123

其中,jsonrpc字段指定JSON-RPC版本號,method字段指定需要調用的api方法名,params字段爲傳送的參數,id爲消息標識字段;

RPC調用智能合約

假設目前有部署的智能合約,地址爲0x6ff93,我們要調用的合約方法簽名multiply(uint256),傳入的參數值爲6,那麼調用命令的格式如下:

curl --data
{
"jsonrpc":"2.0",
"method":"eth_sendtransaction",
"param":[{
	"from":"0xeb85a5",
	"to":"0x6ff93",
	"data":"0xcddddd"
	}],
"id":8
}
localhost:8123

其中,from爲扣除GAS賬戶地址,to爲智能合約部署的地址,data爲調用方法的簽名和傳入參數,編碼方式爲“0x”+sha3(“multiply(uint256)”).substring(0,8)+to_32bit_Hex_str(6)

RPC合約調用

直接使用RPC對智能合約的調用需要進行復雜的編碼。具體規則可以參考Ethereum Contract ABI文檔。實際編程中,基本都使用web3等方式,對RPC進行了友好封裝。

Web3概述

  • 與合約交互,最常用的方式就是使用web3.js library提供的web3
  • 底層實現上,它通過RPC調用與本地節點通信
  • web3.js可以與任何暴露了RPC接口的以太坊節點連接。
  • Web3已隨truffle安裝。

Web3調用合約

  • web3.js封裝了合約調用的方法。
  • 使用可以直接使用web3.eth.contract的裏的sendTransaction來修改區塊鏈數據
  • 調用合約,可能需要from等參數,否則可能出現調用異常。

Web3 API體系

  • Web3-eth:以太坊區塊鏈基本操作和智能合約相關操作。
  • Web3-ssh:實現whisper相關操作,包括p2p和廣播操作。
  • Web-bzz:swarm協議相關,分佈式存儲
  • web3-utils:Dapp 開發輔助功能

Web3版本說明

  • npm ls web3,使用該命令查看版本
  • npm update web3,如果版本過低,請升級

版本文檔以此爲準:
https://web3.js.readthedocs.io/en/1.0/web3-eth.html

Web3初始化

// 引入web3
// in node.js use: var Web3=require('web3');

//如果瀏覽器按照了MetaMask,則會提供一個默認的web3.currentProvider
//如果爲空,則連接遠程/本地節點
var web3 = new Web3(Web3.givenProvider || "ws://localhost:8545";

Web3常用API

web3.setProvider,設置Provider

  • 參數:無
  • 返回值:無
  • 示例:web3.setProvider(new web3.providers.HttpProvider(‘http://localhost:8545’));

web3.toWei

  • 按對應貨幣轉爲以wei爲單位。最常用的單位爲ether。
  • 示例:var value = web3.toWei(‘1’,‘ether’);
    console.log(value); // “10000000000000000000”

web3.eth.account,以太坊賬號

  • 示例:web3.eth.getAccounts([callback])
    web3.eth.getBalance(address[,defaultBlock] [,callback])

web3.eth.contract, 創建一個Solidity的合約對象,用來在某個地址上初始化合約。

  • 參數:Array,一到多個描述合約的參數,事件的API對象。
  • 返回值:Object,一個合約對象。
  • 示例:var MyContract = new web3.eth.Contract(abiArray);

合約對象的方法

  • 顯示對象call。myContract.methods.myMethod([param1[,param2[,…]]]).call(options[,callback]);(不修改數據)
  • 顯示調用send。myContract.methods.myMethod([param1[,params[,…]]]).send(options[,callback]);(修改數據,消耗gas)

合約調用方法代碼示例:

//合約實例
var contract = new web3.eth.Contract(abi,address);

//callback
contract.methods.helloWorld().call(function(error,result){
	colsole.log(result);
});

//promise
contract.methods.helloWorld().call().then(
	function(result)(
		console.log(result);
	)
);

合約對象的事件

  • 參數:
    1. Object, 你想返回的索引值(過濾哪些日誌)。如{‘valueA’,1,‘valueB’:[myFirstAddress,mySecondAddress]}。默認情況下,所有過濾項被設置爲null。意味着默認匹配的是合約所有的日誌。
    1. OBject,附加的過濾選項。參見web3.eth.filter的第一個參數。默認情況下,這個對象會設置address爲當前合約地址,同時第一個主題爲事件的簽名。
    1. Function,(可選)傳入一個回調函數,將立即開始監聽,這樣就不用主動調。

合約對象的事件,回調返回值:

  • OBject,事件對象,如下:
    1. address:String,32字節,日誌產生的合約地址
    1. args:Object,事件的參數
    1. blockHash:String,32字節,日誌所在塊的哈希。如果是pending的日誌,則爲null。
    1. blockNumber:Number,日誌所在塊的塊號。如果是pending的日誌,則爲null。
    1. logIndex:Number,日誌在區塊中的序號。如果是pending的日誌,則爲null。
    1. event:String,事件名稱
    1. removed:bool,標識產生事件的這個交易是否被一處(因爲孤塊),或從未生效(被拒絕的交易)。
    1. transactionIndex:Number,產生日誌的交易在區塊中的序號。如果是pending的日誌,則爲null。
    1. transactionHash:String,32字節,產生日誌的交易哈希值。

Web3.js的使用與案例

合約調用的基本流程

  • 初始化web3,連接以太坊節點rpc服務,獲得一個provider對象
  • 初始化合約的對象。
  • 合約對象的provider設置爲已知初始化的web3對象。
  • 調用合約
  • 監聽合約

合約調用

  • 合約調用可以使用call或者send。
  • myContract.methods.myMethod([param1[,param2[,…]]]).call/send(options[,callback])
  • options可以包括from,gasPrice,gas,value。分別代表調用者地址,gas價格,消耗的最低gas,發送的以太幣數量。

Web3調用合約的例子

var Web3 = require('web3');
console.log(Web3.version)//設置web3對象
var web3 = new Web3('http://localhost:8545');
var json = require("../build/contracts/Hello.json");
var abi = json["abi"];

var address = "0x91ab99f3983y798cenu9eh49erjj88q3u4rjeqd903q4uytr04";

//合約實例
var contract = new web3.eth.Contract(abi,address);

//callback
contract.methods.helloWorld().call(function(error,result){
	console.log(result);
});

Truffle對Web3的封裝

// 1.引用編輯好的合約文件結果
var json = require("./build/contracts/MyContract.json");

// 2.將合約轉爲合約抽象層實例
var contract = require("truffle-contract");
var MyContract = contract(json);

// 3. 設置合約抽象層實例的web3 provider
MyContract.setProvider(new Web3.providers.HttpProvider("http://localhost:8545"));

// 4. 開始使用
MyContract.deployed().then(function(deployed){
	return deployed.someFunction();
});

Truffle封裝web3的優點

  • 對以太坊的智能合約做了更好的抽象,使用簡單
  • 同步的交易:可以確保在交易生效之後再繼續執行其他操作。
  • 返回Promise:每個封裝的合約函數會返回Promise,可以對它進行.then操作,避免了回調地獄(callback hell)問題。
  • 爲交易提供了默認參數:例如from或gas。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章