本文由【區(qū)塊鏈研習社】優(yōu)質內容計劃支持,更多關于區(qū)塊鏈的深度好文妨马,請點擊【區(qū)塊鏈研習社】簡書專欄:區(qū)塊鏈研習社簡書專欄
合約的基本結構
程序版本(Version Pragma):Solidity 大多都是開源的程序咐熙,在代碼中加上程序版本是為了方便社區(qū)合作弱恒。描述程序版本的規(guī)則和 npm 的一樣。
pragma solidity ^0.4.19;
合同(contract)聲明:合同類似于面向對象語言中的類(Class)棋恼。
contract SimpleStorage {
}
狀態(tài)變量(State variable)聲明:狀態(tài)變量是永久存儲在合同存儲中的值返弹。
contract SimpleStorage {
uint storedData; // State variable
}
函數(function)聲明:函數是合約內代碼的可執(zhí)行單元锈玉。
contract SimpleStorage {
function get () {
}
}
類型
bool:false
/ true
操作符:!
, &&
, ||
, ==
, !=
uinit/int:無符整型、有符整型
操作符:
- 比較:
<=
,<
,==
,>=
,>
- 位計算:
&
,|
,^
,~
- 計算:
+
,-
,*
,/
,%
,**
注意:solidity 暫時沒有浮點數义起,有定點數但也支持性不好拉背。
address:用于表示以太坊地址,
address x = 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF
成員:
-
address.banlance
(uint256
):地址余額默终,單位 Wei椅棺,, -
address.transfer(uint256 value)
:給 address 轉賬 value(Wei)齐蔽。 -
address.send(value)
:和 transfer 類似两疚,transfer 更常用。 -
address.call
,address.callcode
,address.delegatecall
:智能合約相互調用時使用
注意:在 solidity 源碼中含滴,address 不需要加雙引號诱渤。但在 Remix 的對話界面中輸入 address 時,務必加上雙引號蛙吏,否則會報錯源哩,且報錯的消息非常詭異。
全局變量
ether 變量:1 ether 代表數字 1*10^x18 鸦做,而不是幣的單位励烦。
-
wei
== 1 -
szabo
== 10^12wei
-
finney
== 10^15wei
-
ether
== 10^18wei
時間變量:1 seconds 代表數字 1,而不是時間的單位泼诱。同理 1 years 代表的是數字 3652460*60坛掠, 而不是現(xiàn)實世界中的一年,因為現(xiàn)實世界中有會有 閏秒治筒。如合同中需用到準確的一年屉栓,需要外部預言機(oracle)。
- 1
seconds
== 1 - 1
minutes
== 60seconds
- 1
hours
== 60minutes
- 1
days
== 24hours
- 1
weeks
== 7days
- 1
years
== 365days
block:塊
-
block.blockhash(uint blockNumber) returns (bytes32)
: 傳入 blockNumber耸袜,返回塊的哈希值 -
block.coinbase
(address
): 挖到當前塊礦工的地址 -
block.difficulty
(uint
): 當前塊的難度 -
block.gaslimit
(uint
): 當前塊最多的 gas -
block.number
(uint
): 當前塊是第幾個 -
block.timestamp
(uint
): 當前塊創(chuàng)建的時間戳 -
now
(uint
): block.timestamp 的別名
msg: 當執(zhí)行某一個函數的時候友多,函數想要知道調用函數的數據信息
-
msg.data
(bytes
): 包括函數名字等等,一些沒有經過加工的信息堤框。 -
msg.gas
(uint
): 函數調用方攜帶的 gas -
msg.sender
(address
): 函數調用方的地址 -
msg.sig
(bytes4
): 整個msg.data
的前 4 個byte
-
msg.value
(uint
): 函數調用方攜帶的gas
域滥,以wei
為單位計價。
關鍵詞:
-
constant
用于變量: 表明當前變量不可修改蜈抓。如果修改启绰,編輯器會報錯。 -
constant
用于函數: 表明當前函數中沟使,不應該修改狀態(tài)委可。但要十分小心,因為即便修改了腊嗡,編譯器也不會報錯着倾。 -
view
: 和 constant 用于函數時功能一樣拾酝。 -
payable
: 表明調用函數可以接受以太幣。 -
this
: 指向的是當前合同的address
屈呕。 -
revert
: 函數執(zhí)行失敗微宝,需要通過調用revert()
拋異常告訴函數調用方。調用后恢復合同狀態(tài)虎眨,并將剩余 gas 返還蟋软。throw
已被廢棄。
其他
合約是中介:由于調用函數的動作是在挖礦時執(zhí)行的嗽桩,所以Solidity 沒有原生定時器岳守,不通過合約本身自動觸發(fā)函數執(zhí)行。應該將合約看做一個中介碌冶,需要外部來觸發(fā)合約函數的執(zhí)行湿痢。
本地狀態(tài)變量聲明提升:類似于 JS 用
val
聲明變量。
contract SimpleStorage {
function set(uint data){
if (true) {
uint temp = 1; // 本地狀態(tài)變量
}
uint temp; // 報錯扑庞,因為聲明本地狀態(tài)變量的作用域是函數譬重,而不是 {}。
}
}
省幣秘訣
用
fn()
代替this.fn()
:通過this.fn()
調用函數罐氨,在 EVM 底層是通過msg
來調用合約函數的臀规。相對于直接調用fn()
花費的 gas 更多。減少重復計算栅隐。Solidity 編譯器沒有對重復計算做優(yōu)化塔嬉,需開發(fā)者手動使用臨時變量保存重復計算的值。
function(int a, int b){
// 錯誤租悄。應該使用 int x = a + b 減少重復計算
if(a + b > 0) {
int y = a + b;
}
}
安全
- 一定要把內部變量修改完成之后谨究,再給外部錢。
frank.transfer(salary);
// 錯誤泣棋,應該將先修改內部變量胶哲,再 transfer。
lastPayday = lastPayday + payDuration;