Truffle 官網文件–與你的合約互動

Truffle 官網文件–與你的合約互動

簡介

許多情況下,我們想要與我們的合約進行互動,但是許多操作需要一些比較底層的技術積累,而且就算你自己寫出來了(肯定不止一兩條命令吧),你也會發現,管理這些命令也是相當麻煩的—比如你發現你的一條命令或者操作具有很好的擴充套件性,你打算擴充套件它,但是操蛋的是,你發現擴充套件後與其他的命令衝突…鬱悶不!Truffle注意到了這個問題的複雜度,並整合相關技術來幫助大家。

讀寫資料

以太坊認為將資料寫入網路和讀取資料是有區別的,並且他們也是這樣做的。事實上,這種區別在你編寫應用程式的過程中起著重要的作用。一般來說,編寫資料稱為 transaction,而讀取資料則稱為 calltransactioncall的處理方式非常不同,並且具有以下特徵。

  • TRANSACTIONS(交易)

       交易可以說從根本上改變了網路的狀態,一條交易可以像傳送以太到另一個帳戶一樣簡單,也可以像執行合約功能或向網路新增新合約一樣複雜。交易的特徵是它寫入(或更改)了資料。交易需要花費以太執行,我們稱之為‘gas’,同時交易的完成也是需要的時間的(事實上,目前的去中心的交易花費時間都是比較長的,不過也有相關技術發展旨在解決該問題,比如閃電網路與IPFS等等)。另一方面,當你通過一筆交易來執行合約裡面的某個函式時,你不能接收該函式的返回值,因為交易沒有被立即處理。一般來說,通過交易執行的函式不會返回一個值;相反的,他們將返回一個事務id。所以總的來說,交易:

  1. 花費gas(以太)
  2. 改變了網路的狀態
  3. 不能被立即處理(起碼現在是這樣)
  4. 不會暴露返回值(只有交易的id)

  • CALLS(呼叫)

       呼叫,對比於交易來說,非常不同。呼叫可以用於在網路上執行程式碼,但不會永久改變資料。與交易相比,呼叫是免費執行的,他們的特徵就是讀取資料。當你通過呼叫來執行合約函式時,你會立即收到返回值。所以總的來說,呼叫:

  1. 免費(不花費gas)
  2. 不改變網路的狀態。
  3. 立即處理
  4. 將會有返回值(萬歲!)

在事務和呼叫之間進行選擇與決定是否要讀取資料或寫入資料一樣簡單。

引入抽象

這些來自Javascript的合約抽象,相當於在與以太坊合約互動的過程中撒上了黃油與麵包。簡而言之,抽象就是包裝了一些程式碼,使得我們與合約的互動變得容易。打個比方,抽象使我們忘記在引擎蓋下執行的發動機與許多齒輪。truffle通過truffle-contract模組使用自己的合約抽象,下面描述的就是我們所講的合約抽象。

還是老話,是騾子是馬,咱是不是需要牽出來遛一遛啊,別說的那麼好,結果操作起來垃圾的要死。所以為了讓大家更好的理解抽象,我們需要一個合約來解釋。通過truffle unbox metacoin命令,我們可以利用現有的模板,建立一個MetaCoin合約。

首先在控制檯輸入命令:

mkdir metacoin

cd metacoin/

truffle unbox metacoin

就像下面這張圖片一樣:

如果出現我這張圖片,就說明你這一步成功了,然後輸入命令:

atom ./

就會跳轉到我們的atom軟體裡面。如圖:

在上面這張圖片中,我們可以從左邊看到整個metacoin的結構。

右邊程式碼區域就是下面的程式碼(除了我翻譯了英文註釋,哈哈)

pragma solidity ^0.4.2;
import "./ConvertLib.sol";
// 這只是一個類似硬幣的合約的簡單例子。
// 它不是與標準相容的,所以不要指望它能與以太產生交流。
// coin/token contracts. 如果你想建立一個符合標準的
// 通證, 參見: https://github.com/ConsenSys/Tokens. 感謝!
contract MetaCoin {
mapping (address => uint) balances;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
function MetaCoin() {
balances[tx.origin] = 10000;
}
function sendCoin(address receiver, uint amount) returns(bool sufficient) {
if (balances[msg.sender] < amount) return false;
balances[msg.sender] -= amount;
balances[receiver]  = amount;
Transfer(msg.sender, receiver, amount);
return true;
}
function getBalanceInEth(address addr) returns(uint){
return ConvertLib.convert(getBalance(addr),2);
}
function getBalance(address addr) returns(uint) {
return balances[addr];
}
}

這個合約包含三個方法(sendCoingetBalanceInEth, and getBalance),沒有建構函式(合約一般都會有建構函式),這三個方法都可以作為交易或者呼叫來執行。

(跳過compilemigrate階段–這一部分就不講了,開啟truffle console

通過truffle我們獲得了一個稱之為MetaCoin的Javascript物件

就像下面這段程式碼一樣:

// 列印已經部署的MetaCoin“版本”
// 需要注意的是,我們要獲得MetaCoin版本需要一個承諾,輸入:
// 下面的instance就是我們的合約物件
MetaCoin.deployed().then(function(instance) {
console.log(instance);
});
// 將會輸出:
//
// Contract
// - address: "0xa9f441a487754e6b27ba044a5a8eb2eec77f6b92"
// - allEvents: ()
// - getBalance: ()
// - getBalanceInEth: ()
// - sendCoin: ()
// ...

請注意,抽象包含與我們的合約中存在的完全相同的函式。同時它還包含一個地址,這個地址就是我們合約的地址(紫色的雜湊地址)。

執行合約方法

利用這些抽象,你可以很方便的在以太坊網路(事實上,除了主網以外的網路同樣也可以)中執行合約包含的方法。

  • 做一筆交易

       我們知道在MetaCoin合約裡面我們有三個方法可以執行。如果你仔細分析一下,你就會發現是sendCoin唯一寫入資料、改變資料的方法。這個方法的目的是傳送Meta幣從一個賬戶到別的賬戶。

       當我們呼叫方法時,我們將把這樣的操作當做一筆交易。在接下來的示例中,我們將從一個賬戶傳送10個Meta幣到另一個賬戶,以一種持續改變網路的方式。

var account_one = "0x1234..."; // 一個地址
var account_two = "0xabcd..."; // 另一個地址
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.sendCoin(account_two, 10, {from: account_one});
}).then(function(result) {
// 如果這個回撥函式被呼叫,表明交易成功。
alert("Transaction successful!")
}).catch(function(e) {
// 有一個錯誤!需要處理。
})

        在上面的程式碼中有一些有趣的地方:

  1. 我們直接呼叫了抽象的sendCoin函式。這將預設產生一筆交易(i.e,寫資料)而不是呼叫(call)。
  2. 當交易成功時,回撥函式直到交易被處理時才會被觸發。這讓生活變得簡單,也意味著您不必自己檢查交易的狀態。
  3. 我們傳遞了一個物件作為sendCoin函式的第三個引數。但是我們同時也注意到sendCoin函式裡面根本就沒有第三個引數啊。你在上面看到的是一個特殊的物件,它總是可以作為最後一個引數傳遞給一個函式,該函式允許你編輯交易的具體細節。在這裡,我們設定了from 地址確保該交易來自account_one。
  • 產生一個呼叫

       我們接著繼續,注意getBalance函式是一個很好的從網路讀取資料的方法。它不需要做任何更改,因為它只返回傳遞給它的地址的MetaCoin餘額。那就讓我們試試看吧:

var account_one = "0x1234..."; // 一個地址
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.getBalance.call(account_one, {from: account_one});
}).then(function(balance) {
// 如果這個回撥函式被呼叫,則表明呼叫成功。
// 注意這個返回是立即、馬上的,沒有等待。
// 讓我們列印返回值。
console.log(balance.toNumber());
}).catch(function(e) {
// 有一個錯誤!需要處理。
})

       一些有趣的事情:

  1. 我們必須顯式地執行.call()函式,以便讓Ethereum網路知道我們不打算儲存任何更改。
  2. 我們獲得了一個返回值,而不是成功執行的交易的id。 注意,由於乙太網絡可以處理非常大的數字,所以我們建立了一個 BigNumber 物件,可以將它轉換成一個數字。

警告:我們把返回值轉換成一個數字,因為在這個例子中,數字很小。但是,如果您試圖轉換一個大於Javascript支援的最大整數的BigNumber,您很可能會遇到錯誤或意外的提示。

  • 捕捉事件(Events)

       你的合約可以觸發事件,通過捕捉這些事件,我們可以更好的瞭解合約在做什麼。處理事件的最簡單方法—是處理觸發事件的交易的結果物件,例如:

var account_one = "0x1234..."; // 一個地址
var account_two = "0xabcd..."; // 另一個地址
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;  
return meta.sendCoin(account_two, 10, {from: account_one});
}).then(function(result) {
// 結果是一個具有以下值的物件:
//
// result.tx      => 交易的雜湊,字串。
// result.logs    => 在此交易中觸發的解碼事件陣列。
// result.receipt => 交易接受的物件,包括花費的gas。
// 我們可以對結果進行迴圈。檢視是否觸發了傳輸事件。
for (var i = 0; i < result.logs.length; i  ) {
var log = result.logs[i];
if (log.event == "Transfer") {
// 我們發現了事件!
break;
}
}
}).catch(function(err) {
// 有一個錯誤!需要處理。
});

  • 處理交易結果

      當你進行交易時,你會得到一個結果物件,它會給你提供有關交易的大量資訊。具體來說,您可以得到以下內容:

  1. result.tx (string) – 交易雜湊
  2. result.logs (array) – 解碼事件(日誌)
  3. result.receipt (object) – 交易收據

如果你想了解更多,請參見truffle-contract專案中的README

  • 向網路中新增新的合約 

      在上述描述的情況中,我們一直在使用已經部署的合約抽象。我們可以使用.new()函式將自己的版本部署到網路中:

MetaCoin.new().then(function(instance) {
// 列印新地址
console.log(instance.address);
}).catch(function(err) {
// 有一個錯誤!需要處理。
});

  • 在特定地址使用合約

     如果你已經有了一個合同的地址,您可以建立一個新的抽象來表示該地址的合約。

var instance = MetaCoin.at("0x1234...");

  • 向一個合約傳送以太

      你可能只想將以太直接傳送到合約,或觸發合約的 fallback function。你可以有兩個選擇來達成這一目標。

      選擇1:通過instance.sendTransaction()直接傳送一個交易到合約。這就像所有可用的合約例項函式一樣,                    具有與web3.eth.sendTransaction相同的API,但沒有回撥。如果沒有指定,將自動填充to值。

instance.sendTransaction({...}).then(function(result) {
// Same transaction result object as above.
});

      選擇2:也有直接傳送以太的簡化版    

instance.send(web3.toWei(1, "ether")).then(function(result) {
// Same result object as above.
});

延伸拓展

Truffle提供的合約抽象包含了大量的實用工具,可以讓你輕鬆地與合約進行互動。請檢視truffle-contrac文件,瞭解相關提示、技巧和見解。

(官方的一點希冀)

                      想讓這個頁面變得更好嗎? Edit here →