待字閨中開發(fā)了一門區(qū)塊鏈方面的課程:《深入淺出ETH原理與智能合約開發(fā)》,馬良老師講授。此簡書文集記錄我的學(xué)習(xí)筆記。
課程共8節(jié)課。其中,前四課講ETH原理,后四課講智能合約。
第五課分為三部分:
- Dapp用例
- 合約結(jié)構(gòu)
- Solidity語法
這篇文章是第五課第二部分的學(xué)習(xí)筆記:合約結(jié)構(gòu) 。
這節(jié)課主要講解了智能合約結(jié)構(gòu)、ERC20、ERC721規(guī)范。
1、智能合約結(jié)構(gòu)
1.1 智能合約的結(jié)構(gòu)
智能合約的源代碼由以下7個部分組成。
版本聲明
在以太坊的solidity編程語言中,各個大版本之間不具有兼容性,所以需要在開頭聲明版本號。不能在之前或之后的版本中運行,如pragma solidity ^0.4.x,不能在0.3或0.5的系統(tǒng)中運行。包含其它代碼文件:import
可以引入其它文件或者庫。合約的定義
使用關(guān)鍵字contract,后面跟上合約的名字。contract 合約名存儲狀態(tài)變量
這部分內(nèi)容需要存儲在Storage Root中。(第3課)構(gòu)造函數(shù)
它是一類很特殊的函數(shù),它在合約被創(chuàng)建的交易中被執(zhí)行一次,函數(shù)名需要與合約名相同。(與C++的構(gòu)造函數(shù)類似)調(diào)用接口函數(shù)
提供給其它賬戶調(diào)用。事件
用于記錄關(guān)鍵這個步驟與信息。
1.2 智能合約的ABI
開發(fā) DApp 時要調(diào)用在區(qū)塊鏈上的 Ethereum 智能合約,就需要智能合約的 ABI。ABI(Application Binary Interface)主要是規(guī)范外部賬戶與合約之間二進(jìn)制數(shù)據(jù)的編碼規(guī)范。
要調(diào)用一個合約特定的接口,首先要有合約的地址。在這個合約眾多的接口中,怎么找到需要調(diào)用的那一個,這就要用到函數(shù)簽名。函數(shù)的簽名由函數(shù)名與所有參數(shù)類型組成(返回值類型不算在內(nèi)),編碼的前四個字節(jié)是函數(shù)簽名的Keccak256 單向散列值的前四字節(jié)。如:function baz(uint32 x, bool y)這個函數(shù),其編碼的前四個字節(jié)是baz(uint32,bool)經(jīng)過Keccak256計算后,再取前四個字節(jié)0xcdcd77c0。從第五字節(jié)開始對輸入的實際調(diào)用參數(shù)進(jìn)行編碼,并補(bǔ)齊32字節(jié)。比如例子中的x, y分別取值0x88,0x1,補(bǔ)齊32字節(jié)。
1.3 通過 remix 介紹合約結(jié)構(gòu)
1.3.1 一個小例子
打開remix網(wǎng)站,自帶一個例子程序。→Remix

此外,老師的例子開頭處,比我的多了兩行,導(dǎo)入其它文件。分別是導(dǎo)入github上的文件,和導(dǎo)入本地的文件。
import "github.com/ethereum/dapp-bin/library/iterable-mapping.sol";
import "./test.sol";
1.3.2 solidity中的注釋
有三種。
/*注釋*/,類似于C語言中的注釋;
//注釋,類似于C++中的注釋;
///注釋,也可以三個斜杠,主要用于函數(shù)前,說明函數(shù)作用。
1.3.3 remix的使用
remix是一個強(qiáng)大的IDE(Integrated Development Environment ,集成開發(fā)環(huán)境)。
中間是代碼區(qū),右邊有六個表單。
- Compile
編譯,可以設(shè)置為自動編譯,修改后自動執(zhí)行。
Detail按鈕可以查看該程序的詳細(xì)信息。點開彈出。其中,METADATA是該程序的元數(shù)據(jù),含有編譯器的版本,和其它的一些數(shù)據(jù)等。這里關(guān)注一下ABI數(shù)據(jù)。它是關(guān)于接口的,點開具體的接口,可以看到接口的名字,輸入和輸出等。
- Run
運行代碼。
它提供了三種運行環(huán)境,自己練習(xí)可以選用JavaScript VM,在本地運行,速度快。它自動提供了5個賬號,每個都含有100ETH。Gas limit是發(fā)起合約的Gas上限;Value是發(fā)送以太幣到一個合約時發(fā)送的數(shù)量。
Deploy布署一個合約。代碼區(qū)的下面,有控制臺可以看到合約執(zhí)行情況。
Settings
設(shè)置。主要是設(shè)置編譯器的版本。Analysis
分析。主要是一些安全性的分析,比如Gas的數(shù)量,使用情況;還有一些雜項。Debugger
調(diào)試。后面在具體的例子中再介紹。Support
2、ERC 20 規(guī)范
前面介紹的DApp例子中,大部分使用了ERC 20 規(guī)范。
官方文檔:ERC20規(guī)范
這個規(guī)范有六個接口是強(qiáng)制必須實施的。
- totalSupply()總的供給量
- balanceOf(address tokenOwner)查詢某一地址的余額
- approve(address spender, uint tokens) 代幣擁有者授權(quán)某地址,可以在未來多次從擁有者的賬戶使用代幣。它有一點安全問題,即授權(quán)數(shù)量要改變時,需要先改為零,再改為更改的值。
- allowance(address tokenOwner,address spender)查詢操作,查詢一個代幣的擁有者,還可以允許支出者花費多少代幣。這個跟前面的approve有關(guān)。
- transferFrom(address from, address to,uint tokens) 授權(quán)的地址從擁有者那里花費代幣,也和approve結(jié)合使用?;ㄙM的數(shù)量要小于授權(quán)的數(shù)量,如果大于則失??;地址輸入錯誤,也會失敗。
- transfer(address to, uint tokens) 轉(zhuǎn)移代幣,把自己的代幣移給目標(biāo)地址。
還有三個可選操作。name() , symbol(), decimals(),分別是名稱,符號,可以分割的程度,如18,1ETH可以分割為10^18份。
還有兩個事件。event Transfer(address from, address to, uint256 value),event Approval(address owner, address spender, uint256 value),分別是記錄Transfer和Approval的操作。

說明一下ERC20規(guī)范的本質(zhì)。它其實是維護(hù)了兩張表。
一張是每個地址對應(yīng)了多少代幣,如左圖。所有余額加起來就是總的供給量。轉(zhuǎn)移代幣是把一個地址的余額減少一定的數(shù)值,另一個地址增加相應(yīng)的數(shù)值。查詢余額就是從這張表中查詢。
另一張表是如右圖的樣子,包含了許可的賬戶及許可額。再說明一下許可(Approval)的意義。假如合約A調(diào)用合約B,如果在調(diào)用前直接把代幣打到B,B收到幣后會有不執(zhí)行合約的風(fēng)險,因此不能先直接給B轉(zhuǎn)移代幣。ERC20的做法是分為兩步,先授權(quán)B一定額度的代幣,B執(zhí)行時,從A那里支取代幣。因為額度預(yù)先分配了,所以轉(zhuǎn)移會成功。
3、ERC 721 規(guī)范
官方文檔:ERC721規(guī)范
ERC 20 和ERC 721 的不同,可以做一個類比。ERC 20 可以類比為現(xiàn)實中的錢幣,你的5塊錢和我的5塊錢是等價的,沒有什么不同。我們的錢還都可以再細(xì)分。而ERC 721,主要是用在游戲中的道具,比如以太坊中的加密貓游戲,你的貓和我的貓是不一樣的。我們的貓也不能分割為半只貓。每只貓都有不同的特性,是非同質(zhì)的。
在數(shù)據(jù)結(jié)構(gòu)上,其本質(zhì)與ERC 20 沒有太大的區(qū)別,也是維護(hù)兩張表。具體內(nèi)容如下。
- balanceOf(address tokenOwner) 一個地址下的余額;
- ownerOf(uint256 tokenId) 從一個ID查詢其主人是誰;
- safeTransferFrom(address from, address to, uint256 tokenId, bytes data) 轉(zhuǎn)換操作,把代幣轉(zhuǎn)移到合約;
- safeTransferFrom(address from, address to, uint256 tokenId) 轉(zhuǎn)換操作,把代幣轉(zhuǎn)移到地址;
- transferFrom(address from, address to, uint256 tokenId) 傳統(tǒng)的轉(zhuǎn)移方式;
3、4和5兩種方式的區(qū)別,5不檢查接收者是否為一個合約地址,而3和4會檢查接收者是否為合約地址,還會校驗地址。
approve(address approved, uint256 tokenId) 授權(quán)某一地址一定的代幣;
METADATA (Name, SYM, URI) 元數(shù)據(jù):名稱,符號,超鏈接。鏈接可以指向一張圖片,如加密貓的外觀圖。
setApprovalForAll(address operator, bool approved) external; 允許一個地址完全控制自己的代幣;
getApproved(uint256 tokenId) 查詢哪個賬戶有一個ID的許可權(quán);
isApprovedForAll(address owner, address operator) 查詢一個地址是否擁有一個地址所有的操作權(quán)。
還有三個事件,對應(yīng)操作發(fā)生時負(fù)責(zé)記錄下日志。
- event Transfer(address indexed from, address indexed to, uint256 tokenId)
- event Approval(address owner, address _approved, uint256 _tokenId)
- evnet ApprovalForAll(address owner, address operator, bool approved)
總結(jié)一下,這節(jié)課主要介紹了智能合約結(jié)構(gòu)、ERC20、ERC721規(guī)范,還簡要介紹了Remix的使用。
不足之處,請批評指正,感謝。