基於區塊鏈的去中心化、不可篡改、共識演算法、匿名性與跨平臺等特性,區塊鏈+遊戲將帶來如下變革:
1.去中心化運營
遊戲中的各系統設定使用智慧合約技術開發,遊戲資料儲存在區塊鏈上,不依賴中心化伺服器;
2.資料可信任
結合區塊鏈技術開發遊戲,重要的資料儲存在區塊鏈上,I8O系統2857開發8624遊戲運營方無法隨意篡改與刪除遊戲資料,稀有道具內容、數量及抽籤機率等演算法完全公開,使得遊戲資料透明化,可信任化,成為一個可信任的去中心化遊戲應用;
編輯
智慧合約的結構
合約就像一個類(class),其中包含:
狀態變數(state variable)
函式(function)
函式修改器(function modifier)
事件(event)
結構(structure)
列舉(enum)
示例:contract Sample
{
//狀態變數
uint256 data;
address owner;
//定義事件
event logData(uint256 dataToLog);
//函式修改器
modifier onlyOwner(){
if(msg.sender!=owner)throw;
}
//構造器,名字與合約名一致
function Sample(uint256 initData,address initOwner){
data=initData;
owner=initOwner;
}
//函式
function getData()returns(uint256 returnedData){
return data;
}
function setData()returns(uint256 newData)onlyOwner{
logData(newData);
data=newData;
}
}
程式碼註釋:
contract關鍵字:用於宣告一個合約
data和owner:是兩個狀態變數。data包含一些資料,owner包含所有者的以太坊錢包地址,即部署合約者的以太坊地址
event logData定義事件logData,用於通知客戶端:一旦data發生變化,將觸發這個事件。所有事件都儲存在區塊鏈中。
函式修改器:onlyOwner。修改器用於在執行一個函式之前自動檢測檔案。這裡的修改器用於檢測合約所有者是否在呼叫函式。如果沒有,則會丟擲異常。
合約函式構造器constructor:在部署合約時,構造器用於初始化狀態變數。
function,getData()用於得到data狀態變數的值,setData()用於改變data的值。
基本型別
除了陣列型別、字串型別、結構型別、列舉型別和map型別外,
其他型別均稱為基本型別。
無符號型:例如uint8,uint16,uint24,…,uint256分別用於儲存無符號的8位,16
位,24位,…,256位整數
有符號型:例如,int8,int16,…,int256分別用於儲存8位,16位,24位,…,256位整數
address型別:用於儲存以太坊地址,用16進製表示。address型別有兩個屬性:balance和send。balance用於檢測地址餘額,send用於向地址傳送以太幣。send方法拿出需要轉賬那
些數量的wei,並根據轉賬是否成功返回true或者false。
注意:
uint和int是uint256和int256的別名。
如果一個數字超過256位,則使用256位資料型別儲存該數字的近似值。
陣列:Solidity支援generic和byte兩種陣列型別。
陣列有length屬性,用於發現陣列的長度。
注意:不可以在記憶體中改變陣列大小,也不可以改變非動態陣列大小。
字串型別
有兩種方法建立字串:使用bytes和string。
bytes用於建立原始字串,而string用於建立UTF-8字串
示例:
contract sample{
string myString="";//string
bytes myRawString;
function sample(string initString,bytes rawStringInit){
myString=initString;
string storage myString2=myString;
string memory myString3="ABCDE";
myString3="imaginecode";
myRawString=rawStringInit;
myRawString.length++;
}
}
結構型別struct
示例
contract sample{
struct myStruct{
bool myBool;
string myString;
}
myStruct s1;
myStruct s2=myStruct{true,""};
function sample(bool initBool,string initString){
s1=myStruct(initBool,initString);
myStruct memory s3=myStruct(initBool,initString);
}
}
注意:函式引數不可以是結構型別,且函式不可以返回結構型別。
列舉型別enum
示例
contract sample{
enum OS{OSX,Linux,Unix,windows}
OS choice;
function sample(OS chosen){
choice=chosen;
}
function setLinux(){
choice=OS.Linux;
}
function getChoice return(OS chosenOS){
return choice;
}
}
mapping型別
mapping型別只可以存在於storage中,不存在於memory中,因此它們是作為狀態變數宣告的。
mapping型別包含key/value對,不是實際儲存key,而是儲存key的keccak256雜湊,用於查詢value。
mapping不可以被分配給另一個mapping。
constract sample{
mapping(int=>string)myMap;
function sample(){
myMap[key]=value;
mapping(int=>string)myMap2=myMap;
}
}
注意:如果想訪問mapping中不存在的key,返回的value為0。
delete運算子
可用於操作任何型別的變數。
對動態陣列使用delete運算子,則刪除所有元素,其長度變為0。
對靜態陣列使用delete運算子,則重置所有索引
對map型別使用delete運算子,什麼都不會發生,但是,對map型別的一個鍵使用delete運算子,則會刪除與該鍵相關的值
示例
contract sample{
struct Struct{
mapping(int=>int)myMap;
int myNumber;
}
int[]myArray;
Struct myStruct;
function sample(int key,int value,int number,int[]array){
myStruct=Struct(number);
myStruct=Struct(number);
myStruct.myMap[key]=value;//對某個鍵賦值
myArray=array;
}
function reset(){
delete myArray;//myArray陣列長度為0
delete myStruct;//myNumber為0,myMap不變
}
function deleteKey(int key){
delete myStruct.myMap[key];//刪除myMap中的某個鍵的值
}
}
基本型別之間的轉換
隱式轉換:常用。通常來說,如果沒有語義資訊丟失,值和型別之間可以進行隱式轉換:uint8可轉換為uint16,int128可轉換為int256,但是int8不可轉換為uint256(因為uint256不能儲存,例如-1)
Solidity也支援顯式轉換,如果編譯器不允許在兩種資料型別之間隱式轉換,則可以進行顯式轉換。建議儘量避免顯式轉換,因為可能返回難以預料的結果。
示例:
uint32 a=0x12345678;
uint16 b=uint16(a);//b=0x5678,將uint32型別顯式轉換為uint16,也就是說,把較大型別轉換為較小型別,因此高位被截掉了
var
使用關鍵字var宣告的變數,其變數型別根據分配給它的第一個值來動態確定。一旦分配了值,型別就固定了,所以如果給它指定另一個型別,將引起型別轉換。
int256 x=12;
var y=x;//此時y的型別是int256
uint256 z=9;
y=z;//此時,報出異常,因為uint256不能轉換為int256型別
但要注意的是:
在定義陣列array和map時不能使用var。var也不能用於定義函式引數和狀態變數
控制結構
if-else
while
for
breakcontinue
return
?:
等等
//結構上和其他語法沒有什麼差異
contract sample{
int a=12;
int[]b;
function sample(){
if(a==12){}
else if(a==34){}
else{}
var temp=10;
while(temp<20)
{
if(temp==17){break;}
else{continue;}
}
temp++;
}
for(var m=0;m<b.length;m++){
}
}
用new運算子建立合約
一個合約可以使用new關鍵字來建立一個新合約。
例如:
contract sample1{
int a;
function assign(int b){
a=b;
}
}
contract sample2{
function sample2(){
sample1 s=new sample1();//注意寫法
s.assign(12);
}
}
異常
異常的丟擲分為自動和手動。
若你想手動丟擲異常,可以使用throw手動丟擲。
注意,異常丟擲後,會撤銷對狀態和餘額的所有改變。
contract sample{
function myFunction(){
throw;
}
}
函式呼叫
內部函式呼叫:一個函式在同一個合約中呼叫另一個函式
外部函式呼叫:一個函式呼叫另一個合約的函式。