為了學習數據持久化,我們寫壹個簡單的智能合約,把它當作地址簿。雖然這個例子不是很實用,但是卻是學習數據持久化的好例子,這個例子不會涉及太多的業務邏輯。
Step 1: 創建壹個新的文件夹
之前,妳創建了壹個合約文件夾,切換到這個文件夾.
cd CONTRACTS_DIR
創建壹個新的文件夾,然後切換到這個文件夾。
mkdir addressbook cd addressbook
Step 2: 創建壹個新文件,並打開它
touch addressbook.cpp
使用妳喜歡的編輯器打開這個文件。
Step 3: 新建壹個標準類,並引入EOSIO
在之前的教程中,妳創建了壹個hello world合約。下面的代碼妳應該不陌生,類名被相應修改成了addressbook 。
#include <eosio/eosio.hpp> using namespace eosio; class [[eosio::contract(“addressbook”)]] addressbook : public eosio::contract { public: private: };
Step 4: 為數據庫表創建數據結構
在配置和實例化壹個數據庫表之前,要先創建代表地址簿的數據結構。這個地址簿的表應該包含有人,所以創建壹個“person”結構。
struct person {};
要定義壹個多索引表的結構,妳需要壹個唯壹值來做primary key。
對於這個合約來說,我們使用壹個key字段,類型為name。對於每個用戶,這個合約擁有壹個唯壹的入口,所以這個key是不變的,並且值是唯壹的。
struct person { name key; };
作為地址簿,它應該存儲壹些相關的細節信息。
struct person { name key; std::string first_name; std::string last_name; std::string street; std::string city; std::string state; };
很好。基本的數據結構就完成了。
接著,定義壹個 primary_key方法。每個多索引結構都需要設定壹個primary key。根據妳多索引實例化指定的索引來使用這個方法。EOSIO包裝了boost::multi_index
創建壹個方法primary_key() ,並返回壹個結構成員,在這個例子中,我們返回之前討論的key 成員。
struct person { name key; std::string first_name; std::string last_name; std::string street; std::string city; std::string state; uint64_t primary_key() const { return key.value;} };
Step 5:配置多索引表
現在表的數據結構被定義成了struct,我們需要來配置表了。
需要命名並配置eosio::multi_index構造器,這樣才能使用我們之前定義的結構。
typedef eosio::multi_index<"people"_n, person> address_index;
在之前的多索引配置中,有壹個people表,它:
- 使用_n操作符定義壹個eosio::name類型,使用它來命名這個表。這個表包含來很多不同的“person”,所以把這個表命名為“people”。
- 在之前定義的person結構中傳遞。
- 表明了這個表的類型。這個類型會在之後實例化這個表的時候使用。
- 還有壹些額外的配置,比如配置索引,我們會在後面談到這些內容。
到目前為止,我們到文件看起來會是這樣的。
#include <eosio/eosio.hpp> using namespace eosio; class [[eosio::contract("addressbook")]] addressbook : public eosio::contract { public: private: struct [[eosio::table]] person { name key; std::string first_name; std::string last_name; std::string street; std::string city; std::string state; uint64_t primary_key() const { return key.value;} }; typedef eosio::multi_index<"people"_n, person> address_index; };
Step 6: 構造器
寫C++類時,第壹個公共方法就是構造器。
我們的構造器主要負責對合約的初始設置。
EOSIO合約繼承自contract 類。使用合約的code name 和receiver初始化我們合約的父類contract 。其中,code 參數非常重要,它是合約被部署到的區塊鏈上的帳號。
addressbook(name receiver, name code, datastream<const char*> ds):contract(receiver, code, ds) {}
Step 7:添加内容到表裏
之前,我們定義了多索引表的primary key,保證了這個合約對每個用戶只會存儲壹條記錄。在這之前,我們需要先設定壹些條件。 - 唯壹被授權修改地址簿的是這個用戶。
- 我們表的primary key是唯壹的,它基於用戶名創建。
- 為保證可用性,合約應該擁有創建和修改表的能力。
在eosio中,壹條鏈擁有壹個唯壹的帳號,所以name就是作為primary key的理想選擇。Name 的類型是uint64_t。
然後,定義壹個action,能讓用戶條件或更新記錄。這個action能接受它所需要的任意值。
為了提高用戶體驗,簡化界面,需要有壹個方法來創建和修改行內容。我們把它命名為“upsert”,“update”和“insert”的結合。
void upsert( name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state ) {}
之前,我們提過只有用戶擁有它記錄內容的控制權。為了做到這點,使用eosio.cdt提供的require_auth 方法。這個方法接收壹個name類型的參數,並驗證執行轉賬的帳號等於提供的值,並擁有相關的權限