中移鏈合約常用開發介紹(四)工程樹目錄

BSN研習社發表於2023-05-15

01

目的

本文件介紹了工程化開發智慧合約專案的工程樹目錄,介紹了各個資料夾及檔案的含義和用途。本文件將沿用之前文章中實現的地址簿合約內容,以初始化專案為例展開介紹,適合剛接觸合約開發的開發人員用來了解智慧合約專案,幫助其快速瞭解以及上手智慧合約。

02

智慧合約介紹

區塊鏈作為一種分散式可信計算平臺,去中心化是其最本質的特徵。每筆交易的記錄不可篡改地儲存在區塊鏈上。智慧合約中定義可以在區塊鏈上執行的動作action和交易transaction的程式碼。可以在區塊鏈上執行,並將合約執行狀態作為該區塊鏈例項不可變歷史的一部分。

因此,開發人員可以依賴該區塊鏈作為可信計算環境,其中智慧合約的輸入、執行和結果都是獨立的,不受外部影響。

03

術語解釋

WebAssembly(WASM)

用於執行可移植二進位制程式碼格式的虛擬機器,託管在nodeos中。

應用程式二進位制介面(ABI)

定義如何將資料編組進出WebAssembly虛擬機器的介面。

CMake

CMake是一個跨平臺的安裝(編譯)工具,可以用簡單的語句來描述所有平臺的安裝(編譯過程)。它能夠輸出各種各樣的makefile或者project檔案,能測試編譯器所支援的C++特性,組態檔取名為CMakeLists.txt。熟悉某個整合開發環境(IDE)的開發者可以透過CMake用標準的方式建構軟體。

04

目錄樹詳解

(一)綜述

中移鏈合約常用開發介紹(二)多索引表的使用一文中,介紹瞭如何在智慧合約中編寫程式碼使用多索引表,完成一個可以增刪改查的地址簿合約。該合約透過一個addressbook.cpp檔案完成了所有程式碼,並不符合工程化開發的要求。

在本文中,我們將以工程化開發的方式重寫這一合約,方便介紹各目錄的含義和用途。

首先依舊是使用eosio-init命令建立addressbook專案。

eosio-init --path=. --project=addressbook

初次被建立的專案結構如下:

├── CMakeLists.txt c++編譯描述檔案
├── README.txt 引導檔案
├── include
│   └── addressbook.hpp 專案標頭檔案,包含表結構定義和介面定義
├── ricardian
│   └── addressbook.contracts.md 李嘉圖合約,合約的數字文件
└── src
    ├── CMakeLists.txt c++編譯描述檔案
    └── addressbook.cpp 專案原始檔,包含介面實現

(二)標頭檔案目錄include

智慧合約以C++程式呈現,資料夾也大多遵循C++專案的命名習慣。其中include資料夾用於存放標頭檔案,即字尾為.hpp的檔案,可稱為標頭檔案目錄。

標頭檔案中編寫了合約動作(函式)的宣告、表格(結構體)等。

在addressbook專案中,合約的建構函式、兩個動作upsert和erase的宣告、多索引表people,都應寫在addressbook.hpp檔案中並放置於標頭檔案目錄include.

addressbook.hpp內容如下:

#include <eosio/eosio.hpp>
using namespace eosio; 
class [[eosio::contract("addressbook")]] addressbook : public eosio::contract { 
public:
   addressbook(name receiver, name code,  datastream<const char*> ds):
   contract(receiver, code, ds) {}
   
   ACTION upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state);
   
   ACTION erase(name user);
   
private:
    TABLE person {
     name key;  
     std::string first_name;  
     std::string last_name;   
     uint64_t age;    
     std::string street;    
     std::string city;    
     std::string state;     
     
     uint64_t primary_key() const { return key.value; }    
     uint64_t get_secondary_1() const { return age; }   
     
    };   
    
    using address_index = eosio::multi_index<"people"_n, person, indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>>; 
    
    };

(三)原始檔目錄src

src是source的縮寫,在目錄中是原始檔的意思。src資料夾用於存放原始檔,即字尾為.cpp的檔案,可稱為原始檔目錄。

1、原始檔

原始檔中編寫了合約動作(函式)的實現。

在addressbook專案中,合約的兩個動作upsert和erase的實現,都寫在addressbook.cpp檔案中並放置於原始檔目錄src.

addressbook.cpp內容如下:

#include <addressbook.hpp>
ACTION addressbook::upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {   
require_auth( user );   
address_index addresses(get_first_receiver(),get_first_receiver().value);   
auto iterator = addresses.find(user.value);   
if( iterator == addresses.end() )   
{  
   addresses.emplace(user, [&]( auto& row ) {      
   row.key = user;      
   row.first_name = first_name;      
   row.last_name = last_name;      
   row.age = age;      
   row.street = street;      
   row.city = city;      
   row.state = state;     
   });   
   }  
   else {   
    addresses.modify(iterator, user, [&]( auto& row ) {       
    row.key = user;       
    row.first_name = first_name;       
    row.last_name = last_name;       
    row.age = age;       
    row.street = street;       
    row.city = city;       
    row.state = state;     
    });   
    }
    } 
    ACTION addressbook::erase(name user) {   
    require_auth(user);
      
      address_index addresses(get_self(), get_first_receiver().value); 
      
      auto iterator = addresses.find(user.value);   
      check(iterator != addresses.end(), "Record does not exist");   
      addresses.erase(iterator);
      }

2、CMakeLists.txt

CMake透過CMakeLists.txt配置專案的構建系統,配合使用cmake命令列工具生成構建系統並執行編譯、測試,相比於手動編寫構建系統要高效許多。

由eosio-init自動生成的CMakeLists.txt檔案內容如下:

project(addressbook) 
set(EOSIO_WASM_OLD_BEHAVIOR "Off")
find_package(eosio.cdt) 
add_contract( addressbook addressbook addressbook.cpp )
target_include_directories( addressbook PUBLIC ${CMAKE_SOURCE_DIR}/../include )
target_ricardian_directory( addressbook ${CMAKE_SOURCE_DIR}/../ricardian )
  • project 專案名

  • add_contract 用於構建智慧合約並生成ABI

  • 第一個引數是合約名稱;

  • 第二個引數是cmake目標名稱;

  • 其餘是構建合約所需的CPP檔案(如本例中的addressbook.cpp)。

  • target_include_directories用於將標頭檔案所在的目錄新增到特定的cmake目標,指向include資料夾

  • target_ricardian_directory用於將李嘉圖合約所在的目錄新增到特定的cmake目標,指向ricardian資料夾

(四)李嘉圖合約目錄ricardian

在基於EOSIO的區塊鏈環境中,李嘉圖合約是一個伴隨智慧合約的數字文件,定義了智慧合約與其使用者之間互動的條款和條件,以人類可讀的文字編寫,然後對其進行加密簽署和驗證。對於人和程式來說,它都很容易閱讀,並有助於為智慧合約和其使用者之間的互動中可能出現的任何情況提供清晰的理解。

本例中存在upsert和erase兩個動作,可以按如下編寫addressbook.contracts.md檔案:

<h1 class="contract">upsert</h1>
---
spec-version: 0.0.1
title: Upsert
summary: This action will either insert or update an entry in the address book. If an entry exists with the same name as the specified user parameter, the record is updated with the first_name, last_name, street, city, and state parameters. If a record does not exist, a new record is created. The data is stored in the multi index table. The ram costs are paid by the smart contract.
icon: 
<h1 class="contract">erase</h1>
---
spec-version: 0.0.1
title: Erase
summary: This action will remove an entry from the address book if an entry in the multi index table exists with the specified name.
icon:

描述了每個動作的具體解釋。

(五)CMakeLists.txt檔案

根目錄下自動生成的CMakeLists.txt檔案內容如下:

include(ExternalProject)
# if no cdt root is given use default path
if(EOSIO_CDT_ROOT STREQUAL "" OR NOT EOSIO_CDT_ROOT)
   find_package(eosio.cdt)
endif()
   
ExternalProject_Add( 
  addressbook_project   
  SOURCE_DIR ${CMAKE_SOURCE_DIR}/src   
  BINARY_DIR ${CMAKE_BINARY_DIR}/addressbook   
  CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${EOSIO_CDT_ROOT}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake   
  UPDATE_COMMAND ""   
  PATCH_COMMAND ""   
  TEST_COMMAND ""   
  INSTALL_COMMAND ""   
  BUILD_ALWAYS 1
  )

檔案中包含對eosio.cdt的匯入,以及專案原始檔、資原始檔目錄的導航。

(六)README.txt檔案

--- addressbook Project --- 
 - How to Build -   
 - cd to 'build' directory   
 - run the command 'cmake ..'   
 - run the command 'make'  
 - After build -   
 - The built smart contract is under the 'addressbook' directory in the 'build' directory   
 - You can then do a 'set contract' action with 'cleos' and point in to the './build/addressbook' directory  
 
 - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt

該文件的初始化內容中描述瞭如何編譯並部署合約專案,根據實際的開發情況,可以在README.txt檔案中對專案的結構、主要功能、使用方法進行描述,供參與開發或使用專案程式碼的人參考。

05

開發中的操作

(一)編譯部署

在終端中使用如下命令:

cd ~/biosboot/genesis/addressbook
cd build/
cmake ..
make

得到的最終結果後有如下提示,則為編譯成功:

[100%] Linking CXX executable addressbook.wasm
[100%] Built target addressbook
[ 77%] No install step for 'addressbook_project'
[ 88%] No test step for 'addressbook_project'
[100%] Completed 'addressbook_project'
[100%] Built target addressbook_project

此時,bulid資料夾中已生成該合約的.wasm和.abi檔案,使用cleos set contract部署合約:

cleos set contract addressbook /home/xxx/biosboot/genesis/addressbook/build/addressbook -p addressbook@active
    Reading WASM from /home/xxx/biosboot/genesis/addressbook/build/addressbook/addressbook.wasm...
    Skipping set abi because the new abi is the same as the existing abi
    Publishing contract...
    executed transaction: 19d0acfa59ba196c4d355c95c7fd420f0e2343967540cff6ef4c5aa73c25cc33  17672 bytes  3566 us
    #         eosio <= eosio::setcode               {"account":"addressbook","vmtype":0,"vmversion":0,"code":"0061736d01000000019a022a60000060037f7f7f01...
    <4>warn  2023-01-18T07:16:08.250 cleos     main.cpp:615                  print_rwarning: transaction executed locally, but may not be confirmed by the network yet

    (二)新增原始檔

    如果專案中宣告的方法增多,且隸屬不同種類的功能,可能會用到多個原始檔。將同型別或共同實現一類功能的方法實現編寫在同一個原始檔當中。

    當專案有多個原始檔時,應當按照如下方法進行新增:

    • 將.cpp檔案放入src資料夾中

    • 修改src資料夾中的CMakeLists.txt檔案,在add_contract後增加新的.cpp檔案。

    例如:

    add_contract( addressbook addressbook addressbook.cpp xxx.cpp)

    (三)新增標頭檔案

    如果專案中宣告的方法增多,且隸屬不同種類的功能,或者引入了單獨的工具方法,可能會用到多個標頭檔案。

    當專案有多個標頭檔案時,只需要將.hpp檔案放入include資料夾中即可。src資料夾中的CMakeLists.txt中有如下語句:

    target_include_directories( addressbook PUBLIC ${CMAKE_SOURCE_DIR}/../include )

    該語句會將include資料夾中的所有檔案作為標頭檔案資源。

    電腦訪問DDC網路門戶

    ddc.bsnbase.com

    -END-


    來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70012206/viewspace-2952162/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章