Solidity 教程系列2 - 地址型別介紹
地址型別(Address)
地址型別address是一個值型別,
地址: 20位元組(一個以太坊地址的長度),地址型別也有成員,地址是所有合約的基礎
支援的運算子:
§ <=, <, ==, !=, >= 和 >
注意:從0.5.0開始,合約不再繼承自地址型別,但仍然可以顯式轉換為地址。
地址型別的成員
§ balance 屬性及transfer() 函式
這裡是地址型別相關成員的快速索引
balance用來查詢賬戶餘額,transfer()用來傳送以太幣(以wei為單位)。
如:
1. address x = 0x123;
2. address myAddress = this;
3. if (x.balance < 10 &&myAddress.balance >= 10) x.transfer(10);
註解:如果x是合約地址,合約的回退函式(fallback 函式)會隨transfer呼叫一起執行(這個是EVM特性),如果因gas耗光或其他原因失敗,轉移交易會還原並且合約會拋異常停止。
關於回退函式(fallback 函式),簡單來說它是合約中無函式名函式,下面程式碼事例中,進進一步講解回退函式(fallback)的使用。
send() 函式
end 與transfer對應,但更底層。如果執行失敗,transfer不會因異常停止,而send會返回false。
警告:send() 執行有一些風險:如果呼叫棧的深度超過1024或gas耗光,交易都會失敗。因此,為了保證安全,必須檢查send的返回值,如果交易失敗,會回退以太幣。如果用transfer會更好。
call(), callcode() 和delegatecall() 函式
為了和非ABI協議的合約進行互動,可以使用call() 函式, 它用來向另一個合約傳送原始資料,支援任何型別任意數量的引數,每個引數會按規則(ABI協議)打包成32位元組並一一拼接到一起。一個例外是:如果第一個引數恰好4個位元組,在這種情況下,會被認為根據ABI協議定義的函式器指定的函式簽名而直接使用。如果僅想傳送訊息體,需要避免第一個引數是4個位元組。如下面的例子:
1. address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
2. nameReg.call("register", "MyName");
3. nameReg.call(bytes4(keccak256("fun(uint256)")), a);
call函式返回一個bool值,以表明執行成功與否。正常結束返回true,異常終止返回false。但無法獲取到結果資料,因為需要提前知道返回的資料的編碼和資料大小(因不知道對方使用的協議格式,所以也不會知道返回的結果如何解析)。還可以提供.gas()修飾器進行呼叫:
1. namReg.call.gas(1000000)("register", "MyName");
類似還可以提供附帶以太幣:
1. nameReg.call.value(1 ether)("register", "MyName");
修飾器可以混合使用,修飾器呼叫順序無所謂。
1. nameReg.call.gas(1000000).value(1 ether)("register", "MyName");
註解:目前還不能在過載函式上使用gas或value修飾符,A workaround isto introduce a special case for gas and value and just re-check whether theyare present at the point of overload resolution.(這句我怕翻譯的不準確,引用原文)
同樣我們也可以使用delegatecall(),它與call方法的區別在於,僅僅是程式碼會執行,而其它方面,如(儲存,餘額等)都是用的當前的合約的資料。delegatecall()方法的目的是用來執行另一個合約中的庫程式碼。所以開發者需要保證兩個合約中的儲存變數能相容,來保證delegatecall()能順利執行。在homestead階段之前,僅有一個受限的callcode()方法可用,但callcode未提供對msg.sender,msg.value的訪問許可權。
上面的這三個方法call(),delegatecall(),callcode()都是底層的訊息傳遞呼叫,最好僅在萬不得已才進行使用,因為他們破壞了Solidity的型別安全。
.gas() 在call(), callcode() 和 delegatecall() 函式下都可以使用, delegatecall()不支援.value()
註解:所有合約都繼承了address的成員,因此可以使用this.balance查詢餘額。
callcode不鼓勵使用,以後會移除。
警告:上述的函式都是底層的函式,使用時要異常小心。當呼叫一個未知的,可能是惡意的合約時,當你把控制權交給它,它可能回撥回你的合約,所以要準備好在呼叫返回時,應對你的狀態變數可能被惡意篡改的情況。
地址常量(Address Literals)
一個能通過地址合法性檢查(address checksumtest)十六進位制常量就會被認為是地址,如0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF。而不能通過地址合法性檢查的39到41位長的十六進位制常量,會提示一個警告,被視為普通的有理數常量。
地址合法性檢查定義在EIP-55
合約例項講解
合約程式碼
pragma solidity ^0.4.0;
contract AddrTest{
event logdata(bytes data);
function() payable {
logdata(msg.data);
}
function getBalance() returns (uint) {
return this.balance;
}
uint score = 0;
function setScore(uint s) public {
score = s;
}
function getScore() returns ( uint){
return score;
}
}
contract CallTest{
function deposit() payable {
}
event logSendEvent(address to, uint value);
function transferEther(address towho) payable {
towho.transfer(10);
logSendEvent(towho, 10);
}
function callNoFunc(address addr) returns (bool){
return addr.call("tinyxiong", 1234);
}
function callfunc(address addr) returns (bool){
bytes4 methodId = bytes4(keccak256("setScore(uint256)"));
return addr.call(methodId, 100);
}
function getBalance() returns (uint) {
return this.balance;//0
}
}
程式碼執行及講解
和型別介紹篇一樣,開啟Remix - Solidity IDE,帖入程式碼,依次建立合約AddrTest及CallTest,如圖:
建立合約後,可以看到,AddrTest合約內沒有命令的函式,顯示fallback。
AddrTest合約主要是用來說明轉入以太幣及呼叫函式式回退函式的呼叫情況,CallTest合約是作為AddrTest合約的呼叫者。
CallTest合約的函式說明:
§ transferEther(address towho): 用來給指定合約地址轉賬(如果一個函式需要進行貨幣操作,必須要帶上payable關鍵字),轉賬時填入AddrTest的地址(加雙引號)作為引數
§ deposit(): 函式上增加payable標識,可接收ether,並會把ether存在當前合約,(transferEther轉賬前需要先存款)。
§ callfunc() : 呼叫函式,使用指定的是函式簽名。
§ callNoFunc(): 呼叫不存在的函式,這時被呼叫的合約的fallback函式會執行。
關於fallback函式用法可進一步參考這一篇:Ethereum-Development-Best-Practices及問答
下面截圖演示下,存款和轉賬,其他的呼叫請讀者動手練習。
存款操作如圖:
完成後,可以在左下角區域檢視日誌Details->value。
然後進行轉賬,如圖:
完成後,可以在左下角區域檢視日誌Details->logs資料,可以看到fallback函式被呼叫。
還可以呼叫AddrTest的getBalance檢視餘額資料。
參考文件
相關文章
- 智慧合約語言Solidity教程系列2 - 地址型別介紹Solid型別
- Solidity教程系列1 - 型別介紹Solid型別
- 智慧合約語言 Solidity 教程系列1 – 型別介紹Solid型別
- 以太坊Solidity型別介紹+實戰Solid型別
- 智慧合約語言 Solidity 教程系列5 - 陣列介紹Solid陣列
- 智慧合約語言 Solidity 教程系列3 - 函式型別Solid函式型別
- 以太坊智慧合約 Solidity 的常用資料型別介紹Solid資料型別
- Vapor系列教程 - 介紹Vapor
- 2 Day DBA-介紹-安裝型別型別
- string型別介紹型別
- 【EASYDOM系列教程】之Node介紹
- 在 Solidity 中將地址型別轉換為 IERC20 介面型別Solid型別
- postgreSQL 索引(二)型別介紹SQL索引型別
- 【Redis】資料型別介紹Redis資料型別
- http代理型別格式介紹HTTP型別
- Rust 資料型別介紹Rust資料型別
- Oracle資料型別介紹Oracle資料型別
- iOS核心動畫型別介紹iOS動畫型別
- SQL | JOIN 型別使用介紹SQL型別
- Python 入門系列 —— 5. 三大變數型別介紹Python變數型別
- C++ 列舉型別介紹C++型別
- java浮點型別案例介紹Java型別
- 次級成本要素型別介紹型別
- WCF系列教程地址
- shiro教程(2): shiro介紹
- 智慧合約語言 Solidity 教程系列8 – Solidity APISolidAPI
- 智慧合約語言 Solidity 教程系列8 - Solidity APISolidAPI
- Go 複合型別之字典型別介紹Go型別
- 語言型別介紹及其Python的語言型別型別Python
- C#學習 [型別系統] 基本型別介紹(10)C#型別
- C 語言之布林型別介紹型別
- 常見的代理IP型別介紹型別
- 介紹PostgreSQL的陣列型別FUSQL陣列型別
- javascript Object型別物件簡單介紹JavaScriptObject型別物件
- Mycat的負載均衡型別介紹負載型別
- javascript節點型別詳細介紹JavaScript型別
- PHP中的型別約束介紹PHP型別
- Tuxedo資料buffer基本型別介紹UX型別