1. 程式人生 > >以太坊智能合約入門項目-眾籌項目

以太坊智能合約入門項目-眾籌項目

工作區 aca rec 查看 手動 count 相關信息 ext 入門

一、智能合約
智能合約(英語:Smart Contract)是一種旨在以信息化方式傳播、驗證或執行合同的計算機協議。智能合約允許在沒有第三方的情況下進行可信交易。這些交易可追蹤且不可逆轉。智能合約概念於1994年由Nick Szabo首次提出。

以上解釋來自於維基百科

由於缺少可信的執行環境,智能合約並沒有被應用到實際產業中,自比特幣誕生後,人們認識到比特幣的底層技術區塊鏈天生可以為智能合約提供可信的執行環境,以太坊首先看到了區塊鏈和智能合約的契合,發布了白皮書《以太坊:下一代智能合約和去中心化應用平臺》,並一直致力於將以太坊打造成最佳智能合約平臺,所以比特幣引領區塊鏈,以太坊復活智能合約。

在區塊鏈上運行的程序,通常稱之為"智能合約",所以通常我們將區塊鏈程序稱之為智能合約,在區塊鏈上,由事件驅動,以代碼形式存在,可執行的特殊交易合同,它是代碼與數據的集合,是以太坊的核心。

1. Solidity語言

Solidity是以太坊智能合約的編程語言,語法接近於JavaScript,是一種面向對象的語言,用於智能合約的開發,並能夠編程成以太坊虛擬機(EVM)字節碼部署到以太坊底層區塊鏈網絡上,文件擴展名以.sol結尾,一般用於:

  • 投票
  • 眾籌
  • 封閉拍賣
  • 多重簽名錢包

等對信任,安全和持久性要求較高的應用場景。

2.EVM

類似於JVM,EVM是以太坊虛擬機(Ethereum Virtual Machine),是以太坊智能合約的運行環境,每個以太坊節點中都包含EVM,EVM是一個隔離的環境,在EVM內部運行的代碼與外部沒有關聯,EVM運行在以太坊節點上,我們將智能合約部署到以太坊區塊鏈網絡後,合約就可以在以太坊網絡環境中運行了。

3. 運行步驟

  • 編譯

    以太坊虛擬機上運行的是字節碼,需要我們在部署之前對合約進行編譯轉成字節碼和ABI(二進制接口,是智能合約的接口說明)

  • 部署

    合約部署就是講編譯好的合約字節碼,通過外部賬號以發送交易的形勢部署到以太坊的區塊鏈網絡上,有實際礦工出塊之後,才算真正部署成功。

  • 運行

  • 合約部署後,當需要調用這個智能合約的方式時,只需要向這個合約賬戶發送消息(交易)即可,通過消息觸發後智能黑夜的代碼就會在EVM中執行。

二、開發環境

目前而言,還沒有特別完善的Solidity開發工具,現在可選性並不多,用的最多的是Remix,大家暫且先用這個吧

技術分享圖片

  • 文件夾

    最左邊是文件夾管理,裏面列出了當前的工作區裏的文件,remix可以支持從本地文件夾讀取文件。

  • 工作區

    正中間是工作區,工作區上半部是代碼編輯區,在這裏可以寫solidity合約。
    下半部是日誌區,在執行智能合約時,會顯示transaction相關的信息。在輸出日誌的時候還可以查看Details和Debug信息。

  • 功能區
    最右邊的是功能區,裏面有編譯,運行,設置和分析以及調試器和支持。

    在編譯器點擊Details可以查看編譯細節,裏面有NAME,METADATA,BYTECODE,ABI 等一些相關信息。

    在設置裏面可以選擇我們的編譯器版本,和一些IDE的使用設置。

    功能區提供了三個運行環境

    • JavaScript VM: 模擬環境
    • Injected Web3: 可以通過Mist或者MetMask錢包提供
    • Web3 Provider: 通過IPC配置獲取

在下面的眾籌項目中,我們采用的是JavaScript VM,在該環境中,Remix由5個以太坊賬戶組成,每個賬戶存有100個以太幣用於合約的測試

三、眾籌項目

在該眾籌項目中,包含了兩個角色,關系為多對多。

  • Investor: 眾籌贊助方
  • BySponsor:眾籌發起方

為了對代碼進行比較全面的解讀,直接將註釋寫到代碼中,不再單獨取出代碼塊進行說明

// 聲明solidity版本為0.4.24
pragma solidity ^0.4.24;
// 創建合約CrowFunding
contract CrowFunding {
//定義眾籌贊助方結構體
    struct Investor{
        address addr; //贊助地址
        uint count ;  //贊助數量
    }
//定義眾籌發起方結構體 
    struct BySponsor{
        address addr;       //接收地址
        uint goalCount;     //眾籌金額
        uint receiveCount;  //已經眾籌到的金額
        uint investorNum;   //眾籌次數
        mapping (uint =>Investor) investors; //用於保存多個眾籌贊助方信息
    }

    uint bySponsorNum = 0 ;  //定義眾籌發起方的ID號
    mapping (uint=>BySponsor) bySponsors; //定義映射用於保存多個合作發起方信息

//定義函數,用於生成眾籌發起方對象
    function newBySponsor() payable {
        // 將合約發起方ID號增加1
        bySponsorNum++;
        /* 創建合約發起方對象
        眾籌地址為:當前Accout地址
        眾籌金額為:通過Value值設置
        */
        BySponsor memory bySponsor = BySponsor(msg.sender,msg.value,0,0);
        //將該眾籌對象保存至映射bySponsors中
        bySponsors[bySponsorNum] = bySponsor;

    }
 /*定義函數,用於查看創建的眾籌金額    
 傳入參數: bySponsorId   眾籌發起方ID
 返回值:   goalCount    創建的眾籌金額 
 */
    function getGoalCount(uint bySponsorId) constant returns (uint){
         // 通過bySponsorId從映射bySponsors中取出對應的bySponsor對象
        BySponsor memory bySponsor = bySponsors[bySponsorId];
        //返回bySponsor對象的goalCount屬性值
        return bySponsor.goalCount;
    }

 //定義函數,用於實現眾籌贊助方的贊助功能,傳入參數為眾籌發起方ID號,並定義函數類型為payable
    function sponsor(uint bySponsorId)payable {
        // 通過bySponsorId從映射bySponsors中取出對應的bySponsor對象
        BySponsor storage bySponsor = bySponsors[bySponsorId];
        //設置合約代碼可執行條件是贊助的金額必須>0
        require(msg.value >0);
        // 將贊助金額加入到bySponsor對象的receiveCount屬性中
        bySponsor.receiveCount += msg.value;
        //眾籌次數累加
        bySponsor.investorNum++;
        //將本次眾籌贊助方信息保存至映射investors中
        bySponsor.investors[bySponsor.investorNum] = Investor(msg.sender,msg.value);
        //實現轉賬,從當前地址(眾籌贊助方地址)轉入bySponsor(眾籌接收方地址),金額為Value中定義的值
        bySponsor.addr.transfer(msg.value);
    }

 //定義函數,用於獲取已經眾籌到的金額,傳入參數為眾籌發起方ID號  
    function getReceiveCount(uint bySponsorId) constant returns (uint){
         // 通過bySponsorId從映射bySponsors中取出對應的bySponsor對象
        BySponsor memory bySponsor = bySponsors[bySponsorId];
        //返回bySponsor對象的receiveCount屬性值
        return bySponsor.receiveCount;
    }    
//定義函數,用於檢查是否眾籌金額是否達標,傳入參數為眾籌發起方ID號 
    function checkComplete(uint bySponsorId) constant returns (bool){
         // 通過bySponsorId從映射bySponsors中取出對應的bySponsor對象
        BySponsor bySponsor = bySponsors[bySponsorId];
        // 判斷設定的眾籌金額是否有效(不為0),並且已經眾籌到的金額是否大於等於創建的眾籌金額
        if (bySponsor.receiveCount >= bySponsor.goalCount && bySponsor.goalCount >0){
            return true;
        }else {
            return false;
        }
    }
}

四、項目測試

智能合約運行步驟已在上文提到

1. 編譯合約

技術分享圖片

  • 此處選擇了自動編譯,無需手動編譯
  • 選擇合約為CrowFunding

2. 部署合約

技術分享圖片

  • 點擊Run標簽
  • 選擇JavaScript VM環境,賬戶隨意選擇一個即可
  • 選擇對應的合約CrowFunding
  • 選擇Deploy按鈕進行合約部署

3. 運行合約

  • 運行newBySponsor函數創建眾籌信息

技術分享圖片

調用方法

  • 查看被贊助前相關信息

技術分享圖片

調用方法查看眾籌設定金額,已經眾籌到的金額,是否眾籌完成等信息,註意此時ID為1

  • 執行捐助函數

技術分享圖片

切換Account =>定義捐助金額 =>填寫捐助對象(ID為1) =>執行sponsor

技術分享圖片

日誌信息

  • 查看捐助後相關信息

技術分享圖片

再次執行捐助100後,查看結果

技術分享圖片

至此,該眾籌案例代碼測試完畢

文中代碼已上傳至github中

https://github.com/DiaboFong/constractDemos/blob/master/demoCrowFunding.sol

以太坊智能合約入門項目-眾籌項目