摘要:語句以分號結尾狀態變量狀態變量是被永久地保存在合約中。中,實際上是代名詞,一個位的無符號整數。下面的語句被認為是修改狀態修改狀態變量。事件事件是合約和區塊鏈通訊的一種機制。一旦它被發出,監聽該事件的都將收到通知。
Solidity是以太坊的主要編程語言,它是一種靜態類型的 JavaScript-esque 語言,是面向合約的、為實現智能合約而創建的高級編程語言,設計的目的是能在以太坊虛擬機(EVM)上運行。合約本文基于CryptoZombies,教程地址為:https://cryptozombies.io/zh/
Solidity 的代碼都包裹在合約里面. 一份合約就是以太應幣應用的基本模塊, 所有的變量和函數都屬于一份合約, 它是你所有應用的起點.
一份名為 HelloWorld 的空合約如下:
contract HelloWorld { }hello world
首先看一個簡單的智能合約。
pragma solidity ^0.4.0; contract SimpleStorage { uint storedData; // 聲明一個類型為 uint (256位無符號整數)的狀態變量,叫做 storedData function set(uint x) public { storedData = x; // 狀態變量可以直接訪問,不需要使用 this. 或者 self. 這樣的前綴 } function get() public view returns (uint) { return storedData; } }
所有的 Solidity 源碼都必須冠以 "version pragma" — 標明 Solidity 編譯器的版本. 以避免將來新的編譯器可能破壞你的代碼。
例如: pragma solidity ^0.4.0; (當前 Solidity 的最新版本是 0.4.0).
關鍵字 pragma 的含義是,一般來說,pragmas(編譯指令)是告知編譯器如何處理源代碼的指令的(例如, pragma once )。
Solidity中合約的含義就是一組代碼(它的 函數 )和數據(它的 狀態 ),它們位于以太坊區塊鏈的一個特定地址上。
該合約能完成的事情并不多:它能允許任何人在合約中存儲一個多帶帶的數字,并且這個數字可以被世界上任何人訪問,且沒有可行的辦法阻止你發布這個數字。當然,任何人都可以再次調用 set ,傳入不同的值,覆蓋你的數字,但是這個數字仍會被存儲在區塊鏈的歷史記錄中。
Solidity 語句以分號(;)結尾狀態變量
狀態變量是被永久地保存在合約中。也就是說它們被寫入以太幣區塊鏈中,想象成寫入一個數據庫。
contract HelloWorld { // 這個無符號整數將會永久的被保存在區塊鏈中 uint myUnsignedInteger = 100; }
在上面的例子中,定義 myUnsignedInteger 為 uint 類型,并賦值100。
uint 無符號數據類型, 指其值不能是負數,對于有符號的整數存在名為 int 的數據類型。Solidity中, uint 實際上是 uint256代名詞, 一個256位的無符號整數。
程序有時需要對不同類型的數據進行操作,因為 Solidity 是靜態類型語言,對不同類型的數據進行運算會拋出異常,比如:
uint8 a = 5; uint b = 6; // 將會拋出錯誤,因為 a * b 返回 uint, 而不是 uint8: uint8 c = a * b;
a * b 返回類型是 uint, 但是當我們嘗試用 uint8 類型接收時, 就會造成潛在的錯誤。這時,就需要顯式的進行數據類型轉換:
// 我們需要將 b 轉換為 uint8: uint8 c = a * uint8(b);
把它的數據類型轉換為 uint8, 就可以了,編譯器也不會出錯。
Solidity 支持多種數據類型,比如:
string(字符串):字符串用于保存任意長度的 UTF-8 編碼數據
fixedArray(靜態數組):固定長度的數組
dynamicArray(動態數組):長度不固定,可以動態添加元素的數組
enum(枚舉)
mapping
等
數學運算在 Solidity 中,數學運算很直觀明了,與其它程序設計語言相同:
加法: x + y
減法: x - y,
乘法: x * y
除法: x / y
取模 / 求余: x % y (例如, 13 % 5 余 3, 因為13除以5,余3)
乘方: x ** y
結構體Solidity 提供了 結構體,用來表示更復雜的數據類型。
struct Person { uint age; string name; }
結構體允許你生成一個更復雜的數據類型,它有多個屬性。
創建結構體方式為:
// 創建一個新的Person: Person satoshi = Person(172, "Satoshi");數組
Solidity 提供兩種類型的數組:靜態數組和動態數組。
// 固定長度為2的靜態數組: uint[2] fixedArray; // 固定長度為5的string類型的靜態數組: string[5] stringArray; // 動態數組,長度不固定,可以動態添加元素: uint[] dynamicArray;
使用 push 函數向數組中添加值:
fixedArray.push[123] fixedArray.push[234] // fixedArray 值為 [123, 234]
array.push() 在數組的 尾部 加入新元素 ,所以元素在數組中的順序就是添加的順序
array.push() 會返回數組的長度。
Solidity 數組支持多種類型,比如結構體:
struct Person { uint age; string name; } Person[] people; // dynamic Array, we can keep adding to it
結構體類型的數組添加值的方式為:
people.push(Person(16, "Vitalik")); // 也可以使用下面的方式,推薦使用上述一行簡潔的方式 Person satoshi = Person(172, "Satoshi"); people.push(satoshi);公共數組
也可以使用public定義公共數組,Solidity 會自動創建getter方法。語法如下:
struct Person { uint age; string name; } Person[] public people; // dynamic Array, we can keep adding to it
公共數組支持其它的合約讀取數據(但不能寫入數據),所以這在合約中是一個有用的保存公共數據的模式。(有點像全局變量,所有合約共享同一個“內存空間“,厲害了!)函數
Solidity 中,函數定義如下:
function eatHamburgers(string _name, uint _amount) { }
Solidity 習慣上函數里的變量都是以(_)開頭 (但不是硬性規定) 以區別全局變量。
這是一個名為 eatHamburgers 的函數,它接受兩個參數:一個 string類型的 和 一個 uint類型的。現在函數內部還是空的。
函數調用如下:
eatHamburgers("vitalik", 100);私有/公共函數
Solidity 函數分為私有函數和共有函數。
Solidity 定義的函數的屬性默認為公共。 這就意味著任何一方 (或其它合約) 都可以調用你合約里的函數。
顯然,不是什么時候都需要這樣,而且這樣的合約易于受到攻擊。所以將自己的函數定義為私有是一個好的編程習慣,只有當你需要外部世界調用它時才將它設置為公共。
可以把所有的函數都顯式的聲明 public和private來規避這個問題。
定義私有函數比較簡單,只需要在函數參數后添加 private關鍵字即可。示例如下:
uint[] numbers; function _addToArray(uint _number) private { numbers.push(_number); }
這意味著只有我們合約中的其它函數才能夠調用這個函數,給 numbers數組添加新成員。
和函數的參數類似,私有函數的名字用(_)起始。
注意:在智能合約中你所用的一切都是公開可見的,即便是局部變量和被標記成 private 的狀態變量也是如此。返回值
和其它語言一樣,Solidity 函數也有返回值,示例如下:
string greeting = "What"s up dog"; function sayHello() public returns (string) { return greeting; }
返回值使用 returns關鍵字標注。(已經是非常奇怪的寫法了。。)
修飾符constant 是 view 的別名
string greeting = "What"s up dog"; function sayHello() public returns (string) { return greeting; }
像 sayHello 函數這種實際上沒有改變合約中數據內容的情況,可以把函數定義為view,這意味著此函數只讀不修改數據。可以使用以下聲明方式:
function sayHello() public view returns (string) {}
可以將函數聲明為 view 類型,這種情況下要保證不修改狀態。
下面的語句被認為是修改狀態:
修改狀態變量。
產生事件。
創建其它合約。
使用 selfdestruct。
通過調用發送以太幣。
調用任何沒有標記為 view 或者 pure 的函數。
使用低級調用。
使用包含特定操作碼的內聯匯編。
pure 比 view 更輕量,使用這個修飾符修飾的函數甚至都不會讀取合約中的數據,例如:
function _multiply(uint a, uint b) private pure returns (uint) { return a * b; }
這個函數沒有讀取應用里的狀態,它的返回值只和它輸入的參數相關。
Solidity 編輯器會給出提示,提醒你使用 pure/view修飾符。
函數可以聲明為 pure ,在這種情況下,承諾不讀取或修改狀態。
除了上面解釋的狀態修改語句列表之外,以下被認為是從狀態中讀取:
讀取狀態變量。
訪問 this.balance 或者 .balance。
訪問 block,tx, msg 中任意成員 (除 msg.sig 和 msg.data 之外)。
調用任何未標記為 pure 的函數。
使用包含某些操作碼的內聯匯編。
payable 關鍵字用來說明,這個函數可以接受以太幣,如果沒有這個關鍵字,函數會自動拒絕所有發送給它的以太幣。
事件事件 是合約和區塊鏈通訊的一種機制。你的前端應用“監聽”某些事件,并做出反應。例如:
// 這里建立事件 event IntegersAdded(uint x, uint y, uint result); function add(uint _x, uint _y) public { uint result = _x + _y; //觸發事件,通知app IntegersAdded(_x, _y, result); return result; }
用戶界面(當然也包括服務器應用程序)可以監聽區塊鏈上正在發送的事件,而不會花費太多成本。一旦它被發出,監聽該事件的listener都將收到通知。而所有的事件都包含了 from , to 和 amount 三個參數,可方便追蹤事務。 為了監聽這個事件,你可以使用如下代碼(javascript 實現):
var abi = /* abi 由編譯器產生 */; var ClientReceipt = web3.eth.contract(abi); var clientReceipt = ClientReceipt.at("0x1234...ab67" /* 地址 */); var event = clientReceipt.IntegersAdded(); // 監視變化 event.watch(function(error, result){ // 結果包括對 `Deposit` 的調用參數在內的各種信息。 if (!error) console.log(result); }); // 或者通過回調立即開始觀察 var event = clientReceipt.IntegersAdded(function(error, result) { if (!error) console.log(result); });代碼示例
下面是一個完整的代碼示例:
pragma solidity ^0.4.19; contract ZombieFactory { // 建立事件 event NewZombie(uint zombieId, string name, uint dna); uint dnaDigits = 16; // 定義狀態變量 uint dnaModulus = 10 ** dnaDigits; struct Zombie { // 定義結構體 string name; uint dna; } Zombie[] public zombies; // 定義動態數組 // 創建私有函數,私有函數命名使用 _ 前綴 function _createZombie(string _name, uint _dna) private { // 函數參數命名 使用 _ 作為前綴 // arrays.push() 將元素加入到數組尾部,并且返回數組的長度 uint id = zombies.push(Zombie(_name, _dna)) - 1; // 觸發事件 NewZombie(id, _name, _dna); } // view 為函數修飾符,表示此函數不需要更新或創建狀態變量 // pure 表示函數不需要使用狀態變量 function _generateRandomDna(string _str) private view returns (uint) { // 使用 keccak256 創建一個偽隨機數 uint rand = uint(keccak256(_str)); return rand % dnaModulus; } function createRandomZombie(string _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } }
Ethereum 內部有一個散列函數keccak256,它用了SHA3版本。一個散列函數基本上就是把一個字符串轉換為一個256位的16進制數字。參考鏈接
在智能合約中使用隨機數很難保證節點不作弊, 這是因為智能合約中的隨機數一般要依賴計算節點的本地時間得到, 而本地時間是可以被惡意節點偽造的,因此這種方法并不安全。 通行的做法是采用 鏈外off-chain 的第三方服務,比如 Oraclize 來獲取隨機數)。
Solidity 文檔: https://solidity-cn.readthedocs.io/zh/develop/index.html
cryptozombie-lessons: https://cryptozombies.io/zh/
最后,感謝女朋友支持和包容,比??
也可以在公號輸入以下關鍵字獲取歷史文章:公號&小程序 | 設計模式 | 并發&協程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/24264.html
摘要:函數和可用于檢查條件并在條件不滿足時拋出異常。函數只能用于測試內部錯誤,并檢查非變量。函數和狀態變量僅在當前定義它們的合約中使用,并且不能被派生合約使用。派生合約可以訪問所有非私有成員,包括內部函數和狀態變量,但無法通過來外部訪問。 Solidity是以太坊的主要編程語言,它是一種靜態類型的 JavaScript-esque 語言,是面向合約的、為實現智能合約而創建的高級編程語言,設計...
摘要:什么是以太坊是一種面向智能合約的高級語言,其語法與類似。如果希望快速進行以太坊開發,那請看我們精心打造的教程以太坊入門教程,主要介紹智能合約與應用開發,適合入門。 這篇關于Solidity教程的博客展示了很多Solidity特性。本教程假定你對以太坊虛擬機和編程有一定的了解。 以太坊,世界計算機提供了一個非常強大的全球共享基礎設施,使用名為Solidity的編程語言構建去中心化應用程序...
摘要:什么是以太坊是一種面向智能合約的高級語言,其語法與類似。如果希望快速進行以太坊開發,那請看我們精心打造的教程以太坊入門教程,主要介紹智能合約與應用開發,適合入門。 這篇關于Solidity教程的博客展示了很多Solidity特性。本教程假定你對以太坊虛擬機和編程有一定的了解。 以太坊,世界計算機提供了一個非常強大的全球共享基礎設施,使用名為Solidity的編程語言構建去中心化應用程序...
摘要:本文首發于深入淺出區塊鏈社區原文鏈接智能合約語言教程系列結構體與映射原文已更新,請讀者前往原文閱讀教程系列第篇結構體與映射。不能聲明一個同時將自身作為成員,這個限制是基于結構體的大小必須是有限的。 本文首發于深入淺出區塊鏈社區原文鏈接:智能合約語言Solidity教程系列6 - 結構體與映射原文已更新,請讀者前往原文閱讀 Solidity 教程系列第6篇 - Solidity 結構體與...
閱讀 3308·2021-09-30 09:54
閱讀 3804·2021-09-22 15:01
閱讀 3110·2021-08-27 16:19
閱讀 2578·2019-08-29 18:39
閱讀 2164·2019-08-29 14:09
閱讀 634·2019-08-26 10:23
閱讀 1343·2019-08-23 12:01
閱讀 1873·2019-08-22 13:57