iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 5
0
Blockchain

30天30個Smart contract 系列 第 5

Day4-User

導言

本次範例將會解釋如何透過solidity寫出會員管理系統,user可以將自己的資料放在contract上,並且可以更新自己的資料,不過update function,會先判斷user address 是否已經創建過資料,如果user沒有創建過資料會顯示錯誤。

此範例沒有實際做出應用,所以邏輯設計上,不代表每一個環節和元素都得依靠smart contract來處理,或許有更好的解決方法

程式碼

pragma solidity^0.4.25;
contract USER{

    struct User{
        string name;
        string email;
        int gender; // 0= male 1= female
        int age; 
        address addr;
    }
    address[] allUser;
    uint userId; //User[] users 會面臨到一個問題,就是id如何確認,就算用一個參數來記錄id,會是從1開始,而不是從0開始,除非有處理差異值
    mapping (address => uint) userToId;
    mapping (uint => address) idToAddr;
    mapping (address => User) public users;
    
    
    function create(string _name,string _email,int _gender,int _age) public returns(bool){
        userId++;
        idToAddr[userId] = msg.sender;
        userToId[msg.sender] = userId;
        users[msg.sender] =  User({
            name: _name,
            email: _email,
            gender: _gender,
            age: _age,
            addr: msg.sender
        });
        return true;
        
    }

    function readAll() public returns(address[]){
        delete allUser;
        for(uint i = 1; i <= userId ; i++){
            address userAddr = idToAddr[i];
            allUser.push(userAddr); //memory type的array不支援push,只有storage才可以
        }
        return allUser;
        
    }
    
    function update
    (
        string _name,
        string _email,
        int _gender,
        int _age
    ) 
        public 
        returns(bool)
    {
        require(userToId[msg.sender] != 0 ,"Can not find your Id");
        users[msg.sender] = User({
            name: _name,
            email: _email,
            gender: _gender,
            age: _age,
            addr: msg.sender
        });
        return true;
    }

    function deletes() public returns(bool){
        delete users[msg.sender];
        return true;
    }
    
}

解說

struct User{
        string name;
        string email;
        int gender; 
        int age; 
        address addr;
    }
  • 宣告User變數為struct type。

struct在solidity 裡可以當作是宣告object,其中value的命名,也需要將type放在第一位再來才命名變數名稱

address[] allUser;
int userId; 
mapping (address => int) userToId;
mapping (int => address) idToAddr;
mapping (address => User) public users;

這邊有兩個mapping type userToIdidToAddr,裡面的key-value是顛倒的,看起來好像能做得事情差不多,不過目的卻不相同,userToId一個可以判斷address有沒有在記錄過資料,idToAddr可以搭配int userId目前累積的user總量透過迴圈將所有在contract儲存過資料的address放在address[] allUser顯現出來

function create(string _name,string _email,int _gender,int _age) public returns(bool){...}
  • 輸入參數name、email、gender、age,將輸入的參數記錄在contract。

只要執行create() function都會累計userId記錄目前user總數量,並且和執行function的address,分別放進userToId[msg.sender] = userIdidToAddr[userId] = msg.sender,再來,msg.sender也就是執行function的address,會放在key的位置,輸入的參數則放進在value位置的User Struct,完成資料儲存,成功後回傳true。

function readAll() public returns(address[]){...}
  • 回傳所有在contract儲存過資料的address,透過回傳的address,可以使用mapping users來查看該address的資料。

比較特別的是,在function body 裏頭的for迴圈i的宣告,在javascript可能習慣使用var,不過在solidity是要宣告數字的type,所以寫法是for(uint i = 0; i < 99;i++),將所有找到的address都push到address[] allUser,最後再回傳目前已經填過資料的address list。只要每次執行readAll() function allUser的狀態都會是有value的狀態,所以readAll() function執行後第一件事是要先將allUser清空,好讓後面填入資料不會有重複的狀態發生。

function update
    (
        string _name,
        string _email,
        int _gender,
        int _age
    ) 
        public 
        returns(bool){...}
  • 修改執行合約的address,所記錄在contract裡的User資料,成功後回傳true。

require(condition,"return err msg")在solidity為判斷的語法,只要條件不符合require內的設定,EVM就會回傳ERROR,以當前的合約例子解釋require(userToId[msg.sender] != 0 ,"Can not find your Id" ),是判斷mapping userToId[msg.sender]的value不應該為0,如果執行function的address還沒將資料輸入進這個contract,ID會是0,接著EVM會回傳錯誤並加入提示訊息Can not find your Id,然後回傳剩餘的gas。在solidity,更改struct type內的資料,以小弟目前所知,是以覆蓋的方式進行更改,而且不能只更改struct內某一個數值,在更改過程一樣得輸入其他欄位的資料;以這個合約例子來看,如果只想要更改age,除了要針對age的欄位輸入新的數值,也必須針對其他欄位輸入不會更動的舊數值。這個部分小弟覺得是比較麻煩的,或許有更好的方法,如果有找到,會在補充。

function deletes() public returns(bool){...}}
  • 刪除執行合約的adress,所記錄在contract裡的User資料,成功後回傳true。

delete會將所有變數的值初始化,以目前的例子來看delete users[msg.sender] users[msg.sender]這個msg.sender會保留,value的User struct資料結構也會保留,不過struct的內部數值就會初始化。


上一篇
Day3-Todo
下一篇
Day5- Guess Number Game
系列文
30天30個Smart contract 20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言