自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

智能合約編寫之Solidity的基礎(chǔ)特性

區(qū)塊鏈
智能合約編寫階段將從 Solidity 基礎(chǔ)特性、高級(jí)特性、設(shè)計(jì)模式以及編程攻略分別展開,帶讀者認(rèn)識(shí) Solidity 并掌握其運(yùn)用,更好地進(jìn)行智能合約開發(fā)。本篇將圍繞 Solidity 的基礎(chǔ)特性,帶大家上手開發(fā)一個(gè)最基本的智能合約。

[[324359]]

前篇介紹,目前大部分的聯(lián)盟鏈平臺(tái),包括 FISCO BCOS,都采用 Solidity 作為智能合約開發(fā)語言,因此熟悉并上手 Solidity 十分必要。

作為一門面向區(qū)塊鏈平臺(tái)設(shè)計(jì)的圖靈完備的編程語言,Solidity 支持函數(shù)調(diào)用、修飾符、重載、事件、繼承等多種特性,在區(qū)塊鏈社區(qū)中,擁有廣泛的影響力和踴躍的社區(qū)支持。但對(duì)于剛接觸區(qū)塊鏈的人而言,Solidity 是一門陌生的語言。

智能合約編寫階段將從 Solidity 基礎(chǔ)特性、高級(jí)特性、設(shè)計(jì)模式以及編程攻略分別展開,帶讀者認(rèn)識(shí) Solidity 并掌握其運(yùn)用,更好地進(jìn)行智能合約開發(fā)。 

本篇將圍繞 Solidity 的基礎(chǔ)特性,帶大家上手開發(fā)一個(gè)最基本的智能合約。

智能合約代碼結(jié)構(gòu)

任何編程語言都有其規(guī)范的代碼結(jié)構(gòu),用于表達(dá)在一個(gè)代碼文件中如何組織和編寫代碼,Solidity 也一樣。

本節(jié),我們將通過一個(gè)簡單的合約示例,來了解智能合約的代碼結(jié)構(gòu)。

  1. pragma solidity ^0.4.25;
  2. contract Sample{
  3.  
  4. //State variables
  5. address private _admin;
  6. uint private _state;
  7.  
  8. //Modifier
  9. modifier onlyAdmin(){
  10. require(msg.sender == _admin, "You are not admin");
  11. _;
  12. }
  13.  
  14. //Events
  15. event SetState(uint value);
  16.  
  17. //Constructor
  18. constructor() public{
  19. _admin = msg.sender;
  20. }
  21.  
  22. //Functions
  23. function setState(uint value) public onlyAdmin{
  24. _state = value;
  25. emit SetState(value);
  26. }
  27.  
  28. function getValue() public view returns (uint){
  29. return _state;
  30. }
  31.  
  32. }

上面這段程序包括了以下功能:

  • 通過構(gòu)造函數(shù)來部署合約

  • 通過 setValue 函數(shù)設(shè)置合約狀態(tài)

  • 通過 getValue 函數(shù)查詢合約狀態(tài)

整個(gè)合約主要分為以下幾個(gè)構(gòu)成部分:

  • 狀態(tài)變量 - _admin_state,這些變量會(huì)被永久保存,也可以被函數(shù)修改

  • 構(gòu)造函數(shù) - 用于部署并初始化合約

  • 事件 - SetState, 功能類似日志,記錄了一個(gè)事件的發(fā)生

  • 修飾符 - onlyAdmin, 用于給函數(shù)加一層“外衣”

  • 函數(shù) - setState、 getState,用于讀寫狀態(tài)變量

下面將逐一介紹上述構(gòu)成部分。

狀態(tài)變量

狀態(tài)變量是合約的骨髓,它記錄了合約的業(yè)務(wù)信息。用戶可以通過函數(shù)來修改這些狀態(tài)變量,這些修改也會(huì)被包含到交易中;交易經(jīng)過區(qū)塊鏈網(wǎng)絡(luò)確認(rèn)后,修改即為生效。

  1. uint private _state;

狀態(tài)變量的聲明方式為:[類型]  [訪問修飾符-可選] [字段名]。

構(gòu)造函數(shù)

構(gòu)造函數(shù)用于初始化合約,它允許用戶傳入一些基本的數(shù)據(jù),寫入到狀態(tài)變量中。 

在上述例子中,設(shè)置了 _admin 字段,作為后面演示其他功能的前提。

  1. constructor() public{
  2. _admin = msg.sender;
  3. }

 和 Java 不同的是,構(gòu)造函數(shù)不支持重載,只能指定一個(gè)構(gòu)造函數(shù)。

函數(shù)

函數(shù)被用來讀寫狀態(tài)變量。對(duì)變量的修改將會(huì)被包含在交易中,經(jīng)區(qū)塊鏈網(wǎng)絡(luò)確認(rèn)后才生效。生效后,修改會(huì)被永久的保存在區(qū)塊鏈賬本中。

函數(shù)簽名定義了函數(shù)名、輸入輸出參數(shù)、訪問修飾符、自定義修飾符。

  1. function setState(uint value) public onlyAdmin;

函數(shù)還可以返回多個(gè)返回值:

  1. function functionSample() public view returns(uint, uint){
  2. return (1,2);
  3. } 

在本合約中,還有一個(gè)配備了 view 修飾符的函數(shù)。這個(gè) view 表示了該函數(shù)不會(huì)修改任何狀態(tài)變量。 

view 類似的還有修飾符 pure,其表明該函數(shù)是純函數(shù),連狀態(tài)變量都不用讀,函數(shù)的運(yùn)行僅僅依賴于參數(shù)。

  1. function add(uint a, uint b) public pure returns(uint){
  2. return a+b;
  3. }

如果在 view 函數(shù)中嘗試修改狀態(tài)變量,或者在 pure 函數(shù)中訪問狀態(tài)變量,編譯器均會(huì)報(bào)錯(cuò)。

事件 

事件類似于日志,會(huì)被記錄到區(qū)塊鏈中,客戶端可以通過 web3 訂閱這些事件。

定義事件:

event SetState(uint value);

構(gòu)造事件:

emit SetState(value);

這里有幾點(diǎn)需要注意:

  • 事件的名稱可以任意指定,不一定要和函數(shù)名掛鉤,但推薦兩者掛鉤,以便清晰地表達(dá)發(fā)生的事情。

  • 構(gòu)造事件時(shí),也可不寫 emit,但因?yàn)槭录秃瘮?shù)無論是名稱還是參數(shù)都高度相關(guān),這樣操作很容易筆誤將事件寫成函數(shù)調(diào)用,因此不推薦不寫。 

    1. function setState(uint value) public onlyAdmin{
    2. _state = value;
    3. emit SetState(value);
    4. // 下面這樣寫也可以,但不推薦,因?yàn)楹苋菀坠P誤寫成 setState
    5. // SetState(value);
    6. }
  • Solidity 編程風(fēng)格應(yīng)采用一定的規(guī)范。關(guān)于編程風(fēng)格,建議參考:https://learnblockchain.cn/docs/solidity/style-guide.html#id16 

修飾符

修飾符是合約中非常重要的一環(huán)。它掛在函數(shù)聲明上,為函數(shù)提供一些額外的功能,例如檢查、清理等工作。

在本例中,修飾符 onlyAdmin 要求函數(shù)調(diào)用前,需要先檢測函數(shù)的調(diào)用者是否為函數(shù)部署時(shí)設(shè)定的那個(gè)管理員(即合約的部署人)。

  1. //Modifer
  2. modifier onlyAdmin(){
  3. require(msg.sender == _admin, "You are not admin");
  4. _;
  5. }
  6.  
  7. ...
  8. //Functions
  9. function setState(uint value) public onlyAdmin{
  10. ...
  11. }

值得注意的是,定義在修飾符中的下劃線 “_”,表示函數(shù)的調(diào)用,指代的是開發(fā)者用修飾符修飾的函數(shù)。在本例中,表達(dá)的是 setState 函數(shù)調(diào)用的意思。

智能合約的運(yùn)行 

了解了上述的智能合約示例的結(jié)構(gòu),就可以直接上手運(yùn)行,運(yùn)行合約的方式有多種,大家可以任意采取其中一種:

  • 方法二:使用 FISCO BCOS 開源項(xiàng)目 WeBASE 提供的在線 ide WEBASE-front 運(yùn)行 

  • 方法三:通過在線 ide remix 來進(jìn)行合約的部署與運(yùn)行,remix 的地址為:http://remix.ethereum.org/

本例中使用 remix 作為運(yùn)行示例。

編譯

首先,在 remix 的在線 ide 中鍵入代碼后,通過編譯按鈕來編譯。成功后會(huì)在按鈕上出現(xiàn)一個(gè)綠色對(duì)勾: 

 

部署

編譯成功后就可進(jìn)行部署環(huán)節(jié),部署成功后會(huì)出現(xiàn)合約實(shí)例。 

 

setState

合約部署后,我們來調(diào)用 setState(4)。在執(zhí)行成功后,會(huì)產(chǎn)生一條交易收據(jù),里面包含了交易的執(zhí)行信息。

在這里,用戶可以看到交易執(zhí)行狀態(tài)(status)、交易執(zhí)行人(from)、交易輸入輸出(decoded input、decoded output)、交易開銷(execution cost)以及交易日志(logs)。

在交易日志中,我們看到 SetState 事件被拋出,里面的參數(shù)也記錄了事件傳入的值 4。

如果我們換一個(gè)賬戶來執(zhí)行,那么調(diào)用會(huì)失敗,因?yàn)?onlyAdmin 修飾符會(huì)阻止用戶調(diào)用。

 

getState 

調(diào)用 getState 后,可以直接看到所得到的值為 4,正好是我們先前 setState 所傳入的值:

 

Solidity 數(shù)據(jù)類型

在前文的示例中,我們用到了 uint 等數(shù)據(jù)類型。由于 Solidity 類型設(shè)計(jì)比較特殊,這里也會(huì)簡單介紹一下 Solidity 的數(shù)據(jù)類型。

整型系列

Solidity 提供了一組數(shù)據(jù)類型來表示整數(shù), 包含無符號(hào)整數(shù)與有符號(hào)整數(shù)。每類整數(shù)還可根據(jù)長度細(xì)分,具體細(xì)分類型如下。

類型

長度(位)

有符號(hào)

uint

256

uint8

8

uint16

16

...

...

uint256

256

int

256

int8

8

int16

16

...

...

int256

256

定長字節(jié)系列

Solidity 提供了 bytes1bytes32 的類型,它們是固定長度的字節(jié)數(shù)組。

用戶可以讀取定長字節(jié)的內(nèi)容。 

  1. function bytesSample() public{
  2. bytes32 barray;
  3. //Initialize baarray
  4. //read brray[0]
  5. byte b = barray[0];
  6. }

并且,可以將整數(shù)類型轉(zhuǎn)換為字節(jié)。 

  1. uint256 s = 1;
  2. bytes32 b = bytes32(s);

這里有一個(gè)關(guān)鍵細(xì)節(jié),Solidity 采取大端序編碼,高地址存的是整數(shù)的小端。例如,b[0] 是低地址端,它存整數(shù)的高端,所以值為 0;取 b[31] 才是 1。 

  1. function bytesSample() public pure returns(byte, byte){
  2. uint256 value = 1;
  3. bytes32 b = bytes32(value);
  4. //Should be (0, 1)
  5. return (b[0], b[31]);
  6. }

變長字節(jié)

從上文中,讀者可了解定長字節(jié)數(shù)組。此外,Solidity 還提供了一個(gè)變長字節(jié)數(shù)組:bytes。使用方式類似數(shù)組,后文會(huì)有介紹。 

字符串 

Solidity 提供的字符串,本質(zhì)是一串經(jīng) UTF-8 編碼的字節(jié)數(shù)組,它兼容于變長字節(jié)類型。

目前 Solidity 對(duì)字符串的支持不佳,也沒有字符的概念。用戶可以將字符串轉(zhuǎn)成字節(jié)。

  1. function stringSample() public view returns(bytes){
  2. string memory str = "abc";
  3. bytes memory b = bytes(str);
  4. //0x616263
  5. return b;
  6. }

要注意的是,當(dāng)將 string 轉(zhuǎn)換成 bytes 時(shí),數(shù)據(jù)內(nèi)容本身不會(huì)被拷貝,如上文中,strb 變量指向的都是同一個(gè)字符串 "abc"。

地址類型  

address 表示賬戶地址,它由私鑰間接生成,是一個(gè) 20 字節(jié)的數(shù)據(jù)。同樣,它也可以被轉(zhuǎn)換為 bytes20。

  1. function addressSample() public view returns(bytes20){
  2. address me = msg.sender;
  3. bytes20 b = bytes20(me);
  4. return b;
  5. }

映射 

mapping 表示映射,是極其重要的數(shù)據(jù)結(jié)構(gòu)。它與 Java 中的映射存在如下幾點(diǎn)差別:

  • 它無法迭代鍵名,因?yàn)樗槐4骀I的哈希,而不保存鍵值,如果想迭代,可以用開源的可迭代哈希類庫

  • 如果一個(gè)鍵名未被保存在映射中,一樣可以正常讀取到對(duì)應(yīng)的鍵值,只是值是空值(字節(jié)全為 0)。所以它也不需要 put、get 等操作,用戶直接去操作它即可。

  1. contract Sample{
  2. mapping(uint=>string) private values;
  3. function mappingSample() public view returns(bytes20){
  4. //put a key value pair
  5. values[10] = "hello";
  6. //read value
  7. string value = values[10];
  8. }
  9. }

數(shù)組 

如果數(shù)組是狀態(tài)變量,那么支持 push 等操作:

  1. contract Sample{
  2. string[] private arr;
  3. function arraySample() public view {
  4. arr.push("Hello");
  5. uint len = arr.length;//should be 1
  6. string value = arr[0];//should be Hello
  7. }
  8. }

數(shù)組也可以以局部變量的方式使用,但稍有不同:

  1. function arraySample() public view returns(uint){
  2. //create an empty array of length 2
  3. uint[] memory p = new uint[](2);
  4. p[3] = 1;//THIS WILL THROW EXCEPTION
  5. return p.length;
  6. }

結(jié)構(gòu)

Solidity 允許開發(fā)者自定義結(jié)構(gòu)對(duì)象。結(jié)構(gòu)體既可以作為狀態(tài)變量存儲(chǔ),也可以在函數(shù)中作為局部變量存在。  

  1. struct Person{
  2. uint age;
  3. string name;
  4. }
  5.  
  6. Person private _person;
  7.  
  8. function structExample() {
  9. Person memory p = Person(1, "alice");
  10. _person = p;
  11. }

本節(jié)中只介紹了比較常見的數(shù)據(jù)類型,更完整的列表可參考 Solidity 官方網(wǎng)站:https://solidity.readthedocs.io/en/v0.6.3/types.html  

全局變量 

示例合約代碼的構(gòu)造函數(shù)中,包含 msg.sender。它屬于全局變量。在智能合約中,全局變量或全局方法可用于獲取和當(dāng)前區(qū)塊、交易相關(guān)的一些基本信息,如塊高、塊時(shí)間、合約調(diào)用者等。

比較常用的全局變量是 msg 變量,表示調(diào)用上下文,常見的全局變量有以下幾種: 

  • msg.sender:合約的直接調(diào)用者。由于是直接調(diào)用者,所以當(dāng)處于“用戶 A->合約 1->合約 2”調(diào)用鏈下,若在合約 2內(nèi)使用 msg.sender,得到的會(huì)是合約 1 的地址。如果想獲取用戶 A,可以用 tx.origin。

  • tx.origin:交易的"始作俑者",整個(gè)調(diào)用鏈的起點(diǎn)。

  • msg.calldata:包含完整的調(diào)用信息,包括函數(shù)標(biāo)識(shí)、參數(shù)等。calldata 的前 4 字節(jié)就是函數(shù)標(biāo)識(shí),與 msg.sig相同。 

  • msg.sigmsg.calldata 的前 4 字節(jié),用于標(biāo)識(shí)函數(shù)。 

  • block.number:表示當(dāng)前所在的區(qū)塊高度。

  • now:表示當(dāng)前的時(shí)間戳。也可以用 block.timestamp 表示。 

這里只列出了部分常見全局變量,完整版本請(qǐng)參考:https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html 。

結(jié)語 

本文以一個(gè)簡單的示例合約作為引入,介紹了運(yùn)用 Solidity 開發(fā)智能合約的基本知識(shí)。讀者可以嘗試運(yùn)行該合約,感受智能合約的開發(fā)。 

責(zé)任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2021-03-18 23:04:41

Solidity開發(fā)智能

2023-05-12 09:14:34

2023-10-12 09:05:11

2022-10-17 09:15:37

2023-02-24 08:00:00

2009-10-26 12:17:03

linux腳本編寫

2021-12-28 14:07:03

人工智能相似問機(jī)器人

2020-12-17 08:00:00

區(qū)塊鏈數(shù)據(jù)以太坊

2021-04-23 10:59:07

區(qū)塊鏈貨幣私鑰

2020-04-22 13:23:46

智能合約區(qū)塊鏈比特幣

2021-05-06 09:42:24

Truffle部署智能

2021-11-02 10:25:19

區(qū)塊鏈智能合約

2022-05-29 10:19:08

區(qū)塊鏈智能合約編程語言

2022-02-13 23:05:23

加密貨幣比特幣貨幣

2021-03-25 16:34:10

區(qū)塊鏈加密資產(chǎn)技術(shù)

2023-05-05 08:00:00

2021-04-20 12:53:34

Polkadot部署合約

2022-10-26 08:00:00

2019-01-18 05:22:39

區(qū)塊鏈智能合約網(wǎng)絡(luò)安全

2017-03-15 13:42:12

互聯(lián)網(wǎng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)