編寫使用數據庫的智能合約
前面一直在搗鼓EOS網絡搭建的相關東西。然而今天比較不走運的是,興致勃勃的把源碼版本升到4.0,在編譯的時候如我所猜想的出現了一系列問題,正一籌莫展的時候,導師突然問了我一個關于合約如何操作數據庫的問題。沒辦法,前面沒怎么關注這一塊,于是乎吞吞吐吐沒能回答老師的問題。心想,反正現在源碼有問題,搭不了網絡,干脆花點時間看看合約的內容。
于是乎,就有了今天的學習筆記,內容如下:
直接上實例合約源碼
addressbook.cpp源碼:
include <eosiolib/eosio.hpp>
include
using eosio::indexed_by;
using eosio::const_mem_fun;
using std::string;
class addressbook : public eosio::contract {
public:
//構造函數
explicit addressbook(action_name self) : contract(self) {}
//添加聯系人
//@abi action
void add(const account_name account, const string& name, uint64_t phone) {//獲取授權,如果沒有授權,Action調用會中止,事務會回滾require_auth(account);//eosio::multi_index(多索引表)可以用來讀取和修改EOS數據庫//address_index是自己定義的eosio::multi_index//實例化address數據表(multi_index),參數用于建立對表的訪問權限//如果訪問自己的合約則具有讀寫權限,訪問其他人的合約則具有只讀權限address_index addresses(_self, _self);//multi_index的find函數通過主鍵(primary_key)查詢數據,返回迭代器itr//auto關鍵字會自動匹配類型auto itr = addresses.find(account);//如果判斷條件不成立,則終止執行并打印錯誤信息eosio_assert(itr == addresses.end(), "Address for account already exists");//添加數據//使用存儲需要付費,第一個參數account是付費的賬戶addresses.emplace(account, [&](auto& address){address.account = account;address.name = name;address.phone = phone;});
}//修改聯系人信息
//@abi action
void update(const account_name account, const string& name, uint64_t phone) {require_auth(account);address_index addresses(_self, _self);auto itr = addresses.find(account);//如果沒有找到account,打印錯誤信息并終止eosio_assert(itr != addresses.end(), "Address for account not found");addresses.modify(itr, account, [&](auto& address){address.account = account;address.name = name;address.phone = phone;});
}//刪除聯系人
//@abi action
void remove(const account_name account) {require_auth(account);address_index addresses(_self, _self);auto itr = addresses.find(account);eosio_assert(itr != addresses.end(), "Address for account not found");//刪除addresses.erase(itr);
}//設置聯系人為特別關注
//@abi action
void like(const account_name account) {//無需獲取授權,每個人都可以調用like Actionaddress_index addresses(_self, _self);auto itr = addresses.find(account);eosio_assert(itr != addresses.end(), "Address for account not found");//修改相應的liked字段addresses.modify(itr, 0, [&](auto& address){//打印提示信息eosio::print("Liking: ", address.name.c_str(), "\n");address.liked++;});
}//功能和like()相同,但通過phone查詢數據,而不是主鍵
//@abi action
void likebyphone(uint64_t phone) {address_index addresses(_self, _self);//獲取自定義索引auto phone_index = addresses.get_index<N(phone)>();auto itr = phone_index.lower_bound(phone);for(; itr != phone_index.end() && itr->phone == phone; ++itr) {phone_index.modify(itr, 0, [&](auto& address){eosio::print("Liking: ", address.name.c_str(), "\n");address.liked++;});}
}
private:
//定義address表,i64表示索引使用默認的uint64_t類型
//@abi table address i64
struct address {
uint64_t account;
string name;
uint64_t phone;
uint64_t liked;
//定義address表的主鍵,address表是一個multi-index表uint64_t primary_key() const { return account; }uint64_t get_phone() const {return phone; }EOSLIB_SERIALIZE(address, (account)(name)(phone)(liked));
};//默認通過主鍵索引,使用indexed_by,可以通過自定義函數進行索引
//這里是get_phone,即通過phone字段進行索引
typedef eosio::multi_index< N(address), address,indexed_by<N(phone), const_mem_fun<address, uint64_t, &address::get_phone>>>
address_index;
};
EOSIO_ABI(addressbook, (add)(update)(remove)(like)(likebyphone))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
該合約業務邏輯是實現一個通訊錄的功能,其中包括增加聯系人、更新聯系人信息、刪除聯系人以及將聯系人標記為特別關注。
接下來我們來一步步來看該合約是如何實現的。
創建表格
1)定義結構體
該結構體的成員變量為表的字段,成員函數primary_key()定義主鍵,get_phone()定義二級索引,EOSLIB_SERIALIZE宏定義序列化表字段如下:
struct address {uint64_t account;string name;uint64_t phone;uint64_t liked;//定義address表的主鍵,address表是一個multi-index表uint64_t primary_key() const { return account; }uint64_t get_phone() const {return phone; }EOSLIB_SERIALIZE(address, (account)(name)(phone)(liked));
};
1
2
3
4
5
6
7
8
9
10
11
12
其中宏EOSLIB_SERIALIZE定義如下
#define EOSLIB_SERIALIZE( TYPE, MEMBERS ) template friend DataStream& operator << ( DataStream& ds, const TYPE& t ){ return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS ); } template friend DataStream& operator >> ( DataStream& ds, TYPE& t ){ return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS ); }