1. 程式人生 > >【一步步一起學DApp開發】(四)web3.js 基本使用 | 連線geth | 建立web客戶端

【一步步一起學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

為所有權合約建立客戶端

首要我們要知道這是什麼樣個客戶端?

在客戶端中,使用者從中選擇一個檔案,輸入所有者細節,然後按下Submit按鈕廣播交易,用檔案雜湊和所有者的細節呼叫合約的set方法。一旦交易被成功廣播,將顯示交易雜湊。使用者還能夠選擇一個檔案,並從智慧合約中得到所有者的細節。客戶端還將實時顯示最新挖出的set交易。

思路:

在前端使用sha1.js獲取檔案雜湊,使用jQuery進行DOM操縱,並使用Bootstrap 4建立一個反應層(responsive layout)。在後端使用express.js和web3.js。我們將使用socket.io,這樣不需要前端間隔相等的時間請求資料,後端就把最近挖出的交易推到前端。