智能合約能夠簡單的理解爲一段可執行的程序片斷,具體的代碼通過 Solidity 編寫以後,發佈到區塊鏈上。而以太坊的智能合約也能夠理解爲一個特殊的交易(包括可執行代碼的),被髮送出去後會被礦工打包記錄在某一個區塊中,當須要調用這個智能合約的方法時只須要向這個智能合約的地址發送一筆交易便可。 由於觸發的條件和打錢地址都已經被編寫在代碼裏,存儲在區塊鏈上,因此能夠最大程度的排除人爲因素的干擾。git
程序版本(Version Pragma):Solidity 大多都是開源的程序,在代碼中加上程序版本是爲了方便社區合做。描述程序版本的規則和 npm 的同樣。github
pragma solidity ^0.4.19;
合同(contract)聲明:合同相似於面嚮對象語言中的類(Class)。npm
contract SimpleStorage { }
狀態變量(State variable)聲明:狀態變量是永久存儲在合同存儲中的值。安全
contract SimpleStorage { uint storedData; // State variable }
函數(function)聲明:函數是合約內代碼的可執行單元。網絡
contract SimpleStorage { function simpleFn() { } }
// 返回一個值 function oneParameter() returns(uint){ return 1; } // 返回多個返回值 function twoParameters() returns(uint, uint) { return (1,2); } // 命名參數直接賦值 function namedParameter() returns(uint foo, uint bar) { foo = 1; bar = 2; } // 獲取返回值 function get() { uint one = oneParameter(); var (two1, two2) = twoParameters(); var (named1, named2) = namedParameter(); }
bool:false
/ true
oracle
操做符:!
, &&
, ||
, ==
, !=
編輯器
uinit/int:無符整型、有符整型函數
操做符:學習
<=
, <
, ==
, >=
, >
&
, |
, ^
, ~
+
, -
, *
, /
, %
, **
注意:區塊鏈
int x = 7/4 // 報錯。計算出來的值是有理數,但 solidity 根本沒有浮點數等類型來表示有理數,更不能將有理數轉換爲 int 類型。 // 正確方法,需先定義類型 int a =7; int b = 4; int c = a/b; c == 1.75 // 報錯。根本沒有浮點數。 c == 1 // true。捨去小數位
address:在以太坊中帳戶有兩種類型:普通帳戶和智能合約帳戶。普通帳戶只存儲 ETH 的帳戶,智能合約帳戶不只存儲 ETH,同時也有能夠運行的代碼。
以太坊地址是 20 字節的十六進制的值,該值範圍在 2^256 之內。能夠經過isValidAddress檢測是否有效。
address x = 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF function isValidAddress(address) { return /^0x[0-9a-fA-F]{40}$/.test(address) } isValidAddress(x)
成員:
address.banlance
(uint256
):地址餘額,單位 Wei。banlance 的值是 readonly
的,調用 payable
函數入帳,調用 address.transfer()
等出帳,以太坊自動計算新的餘額。address.transfer(uint256 value)
:給 address 轉帳 value(Wei),且調用異常會拋出。address.send(value)
:和 transfer 相似,但調用後的異常將不會被返回,只會返回一個 false。address.call
, address.callcode
, address.delegatecall
:智能合約相互調用時使用注意:在 solidity 源碼中,address 不須要加雙引號。但在 Remix 的對話界面中輸入 address 時,務必加上雙引號,不然會報錯,且報錯的消息很是詭異。
ether 變量:1 ether 表明數字 1*10^x18 ,而不是幣的單位。
wei
== 1szabo
== 10^12 wei
finney
== 10^15 wei
ether
== 10^18 wei
時間變量:1 seconds 表明數字 1,而不是時間的單位。同理 1 years 表明的是數字 3652460*60, 而不是現實世界中的一年,由於現實世界中有會有 閏秒。如合同中需用到準確的一年,須要外部預言機(oracle)。
seconds
== 1minutes
== 60 seconds
hours
== 60 minutes
days
== 24 hours
weeks
== 7 days
years
== 365 days
block:塊
block.blockhash(uint blockNumber) returns (bytes32)
: 傳入 blockNumber,返回塊的哈希值block.coinbase
(address
): 挖到當前塊礦工的地址block.difficulty
(uint
): 當前塊的難度block.gaslimit
(uint
): 當前塊最多的 gasblock.number
(uint
): 當前塊是第幾個block.timestamp
(uint
): 當前塊建立的時間戳now
(uint
): block.timestamp 的別名msg: 當執行某一個函數的時候,函數想要知道調用函數的數據信息
msg.data
(bytes
): 包括函數名字等等,一些沒有通過加工的信息。msg.gas
(uint
): 函數調用方攜帶的 gasmsg.sender
(address
): 函數調用方的地址msg.sig
(bytes4
): 整個 msg.data
的前 4 個 byte
msg.value
(uint
): 函數調用方攜帶的 gas
,以 wei
爲單位計價。constant
用於變量: 代表當前變量不可修改。若是修改,編輯器會報錯。constant
用於函數: 代表當前函數中,不該該修改狀態。但要十分當心,由於即使修改了,編譯器也不會報錯。view
: 和 constant 用於函數時功能同樣。另外使用 Remix 時,能夠方便查看函數返回值。使用 view
時,Remix 會把調用函數的輸出值放在函數右邊顯示,而不是在 details 裏。payable
: 代表調用函數能夠接受以太幣。this
: 指向的是當前合同的 address
。revert()
: 函數執行失敗,須要經過調用 revert()
拋異常告訴函數調用方。調用後恢復合同狀態,並將剩餘 gas 返還。等同於 throw
。當你激活一個智能合約的時候,你在要求整個網絡內的每一個礦工個體分別執行裏面的運算。這會花費他們的時間和精力,Gas是你爲這項服務向礦工們支付的機制。 報酬是小額的以太幣,想要運行智能合約的人的須要支付報酬來使合約工做。付款款項(單位以太幣)= Gas數量(單位Gas) x Gas price(單位以太幣/Gas) 智能合約越複雜(計算步驟的數量和類型,佔用的內存等),用來完成運行就須要越多Gas。
Gas是由一開始發起transaction的地址進行支付。再好比"合約A調用合約B再調用合約C"這個過程當中所產生的全部計算步驟所消耗的Gas也都是由調用合約A的人來承擔的。
fn()
代替 this.fn()
:經過 this.fn()
調用函數,在 EVM 底層是經過 msg
來調用合約函數的。相對於直接調用 fn()
花費的 gas 更多。function(int a, int b){ // 錯誤。應該使用 int x = a + b 減小重複計算 if(a + b > 0) { int y = a + b; } }
frank.transfer(salary); // 錯誤,應該將先修改內部變量,再 transfer。 lastPayday = lastPayday + payDuration;
val
聲明變量。contract SimpleStorage { function set(uint data){ if (true) { uint temp = 1; // 本地狀態變量 } uint temp; // 報錯,由於聲明本地狀態變量的做用域是函數,而不是 {}。 } }
代碼見/payroll.sol
參考資料: