摘要:這里的是封裝的,返回中,當前索引的迭代器之后遍歷該迭代器,就可以獲得所有某個特定值的所有數(shù)據(jù)。
上一章我們細致地學習了
索引和迭代器的關(guān)系;
如何生成和使用索引以及迭代器
介紹了multi_index的相關(guān)操作
相信大家對multi_index已經(jīng)有了比較全面的理論理解以及掌握了一些基礎(chǔ)的操作。這一章將會教大家如何完整地構(gòu)建一個智能合約,并在合約中直觀地操作multi_index。
摘要這一章主要以實操為主,會有較大篇幅的代碼,希望大家最好可以照著文章自己操作一遍。
這一章將會以一個簡單的智能合約例子,簡單了解一個完整的EOS智能合約長什么樣。希望大家通過這一章的學習,不僅可以有能力構(gòu)建一個簡單的智能合約,并且對multi_index在EOS智能合約中的重要性,會有更加深刻的認識。
頭文件:*.hppC++的源代碼文件分為兩類:頭文件(Header file)和源文件(Source code file)。
頭文件用于存放對類型定義、函數(shù)聲明、全局變量聲明等實體的聲明,作為對外接口;
源程序文件存放類型的實現(xiàn)、函數(shù)體、全局變量定義;
我們先來看頭文件里的代碼:
#include#include #include using namespace eosio; using std::string;
最前面按慣例都是import,接著往下看:
class app : public contract { public: using contract::contract; app(account_name self) : contract(self) {} // @abi action void hello(const account_name account); // @abi action void create(const account_name account, const string& username, uint32_t age, const string& bio); // @abi action void get(const account_name account); // @abi action void update(const account_name account, const string& username, uint32_t age, const string& bio); // @abi action void remove(const account_name account); // @abi action void byage(uint32_t age); // @abi action void agerange(uint32_t young, uint32_t old);
這里定義了源文件里的方法接口,接下來就到了最核心的multi_index的相關(guān)定義:
private: // @abi table profile i64 struct profile { account_name account; string username; uint32_t age; string bio; account_name primary_key() const { return account; } uint64_t by_age() const { return age; } EOSLIB_SERIALIZE(profile, (account)(username)(age)(bio)) }; typedef eosio::multi_index< N(profile), profile, // N(name of interface) indexed_by< N(age), const_mem_fun> > profile_table; };
這里定義了multi_index表的結(jié)構(gòu) (struct profile),主鍵以及按年齡的索引定義。(上一章詳細講過)
最后再加上EOSIO_ABI的聲明:
EOSIO_ABI(app, (hello)(create)(get)(update)(remove)(byage)(agerange))
這里只需要簡單地把所有方法串聯(lián)在一起就可以了。
上述可以看到hpp頭文件里的內(nèi)容很簡單,只包含了最簡單的變量和接口的聲明。而與之配套的*.cpp文件就要復雜一些,里面對這些接口都做了具體的實現(xiàn)。
源文件首先肯定是引用頭文件:
#include1. 添加數(shù)據(jù)void app::hello(account_name account) { print("Hello ", name{account}); }
void app::create(const account_name account, const string& username, uint32_t age, const string& bio) { require_auth(account); profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr == profiles.end(), "Account already exists"); profiles.emplace(account, [&](auto& p) { p.account = account; p.username = username; p.age = age; p.bio = bio; }); }
require_auth語句和以太坊中的require(msg.sender == xxx)類似,都對調(diào)用者的身份做了限制。
profile_table是一種類型,可以理解成表示multi_index表,后面的profiles(_self, _self)才是真正構(gòu)建一個multi_index表的實例。profiles里的兩個參數(shù)依次就是我們前面提到過的code和scope,分別表示表的擁有賬戶以及代碼層次結(jié)構(gòu)的范圍標識符(已經(jīng)忘記的小伙伴可以翻看上一章內(nèi)容)。
當profiles表實例化完成之后,緊接著就是插入數(shù)據(jù)。關(guān)于插入數(shù)據(jù)的操作上一章我們有過詳細的介紹,這里就不再贅述了。主要注意防止主鍵重復的操作。
2. 根據(jù)主鍵獲取相關(guān)信息void app::get(const account_name account) { profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr != profiles.end(), "Account does not exist"); print("Account: ", name{itr->account}, " , "); print("Username: ", itr->username.c_str(), " , "); print("Age: ", itr->age , " , "); print("Bio: ", itr->bio.c_str()); }
這里也很簡單,先把multi_index表實例化,之后要求查詢的結(jié)果不能為空 (即itr != profiles.end()),如果不為空的話,就返回主鍵對應(yīng)的其他字段的信息。
這些操作都是通過我們上一章介紹過的迭代器來完成。
3. 根據(jù)主鍵更新信息void app::update(const account_name account, const string& username, uint32_t age, const string& bio) { require_auth(account); profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr != profiles.end(), "Account does not exist"); profiles.modify(itr, account, [&](auto& p) { p.username = username; p.age = age; p.bio = bio; }); }
和之前的操作類似,確保主鍵不為空的情況下,更新該主鍵對應(yīng)的其他字段的信息。
4. 根據(jù)主鍵刪除數(shù)據(jù)void app::remove(const account_name account) { require_auth(account); profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr != profiles.end(), "Account does not exist"); profiles.erase(itr); print(name{account} , " deleted!"); }5. 通過自定義的自定義索引實現(xiàn)查詢
前面四個介紹的都是主鍵相關(guān)的增刪改查的操作,別忘了我們在上一章中還曾經(jīng)定義過自定義索引by_age(),即以年齡為條件進行篩選。具體實現(xiàn)如下:
void app::byage(uint32_t age) { print("Checking age: ", age, " "); profile_table profiles(_self, _self); // get an interface to the "profiles" containter // that looks up a profile by its age auto age_index = profiles.get_index(); auto itr = age_index.lower_bound(age); for(; itr != age_index.end() && itr->age == age; ++itr) { print(itr->username.c_str(), " is ", itr->age, " years old "); } }
這里我們使用了在頭文件里定義過的名為age的index,重新得到了一張以age排序的multi_index。
這里的lower_bound是EOS封裝的API,返回age_index中,當前索引≥age的迭代器;之后遍歷該迭代器,就可以獲得所有age≥某個特定值的所有數(shù)據(jù)。
和lower_bound相對應(yīng)的,就是upper_bound方法,用法和lower_bound類似。如下就實現(xiàn)了同時指定age上下限的查詢:
void app::agerange(uint32_t young, uint32_t old) { profile_table profiles(_self, _self); auto age_index = profiles.get_index合約部署(); auto begin = age_index.lower_bound(young); auto end = age_index.upper_bound(old); for_each(begin, end, [&](auto& p) { print(p.username.c_str(), " is ", p.age, " years old "); }); }
把前文中所有的hpp和cpp的代碼片段拼接成完整的hpp和cpp文件進行編譯:
#使用 -o 生成wast文件和wasm文件 eosiocpp -o ./app.wast ./app.cpp #使用 -g 生成abi文件 eosiocpp -g ./app.abi ./app.cpp
生成wast和abi文件的詳細內(nèi)容我們之前章節(jié)介紹過了,這里也不贅述了。這時我們的當前文件夾下會出現(xiàn)app.wast和app.abi文件。
部署合約:
cleos set contract eosio ./ ./app.wast app.abi -p eosio@active
(該命令前文也詳細介紹過每個參數(shù)的含義,詳情參考第五篇)
下圖為成功部署合約的畫面:
合約調(diào)用 1. 查看表內(nèi)容cleos get table eosio eosio profile
通過上述指令查看表中的內(nèi)容,參數(shù)eosio eosio profile分別表示前文提到過的code、scope和表名。
結(jié)果如下圖:
因為在頭文件里聲明過,可以看到該表已存在,但是內(nèi)容為空。
2. 插入數(shù)據(jù)執(zhí)行如下命令往表中插入數(shù)據(jù),然后再次查詢:
// 插入 cleos push action eosio create "["eosio","hammer","25","programmer"]" -p eosio@active // 再次查詢 cleos get table eosio eosio profile
這時就可以看到表中保存了我們剛插入的一條數(shù)據(jù)。
還記得我們曾經(jīng)創(chuàng)建過一個叫做testeosio的賬戶么?我們再使用那個賬戶往表中插入一條數(shù)據(jù)(記得先unlock錢包哦):
// 切換賬號插入數(shù)據(jù) cleos push action eosio create "["testeosio","maggie","23","waitress"]" -p testeosio@active // 查詢 cleos get table eosio eosio profile
這時我們可以看到:
數(shù)據(jù)確實添加進入表中了。
傳入數(shù)據(jù)的第一個參數(shù)必須是調(diào)用該方法的賬戶名,還記得代碼中的require_auth么?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/24295.html
摘要:是企業(yè)與區(qū)塊鏈相遇的地方。的框架旨在成為開發(fā)區(qū)塊鏈解決方案的支柱。以太坊,主要是針對工程師使用進行區(qū)塊鏈以太坊開發(fā)的詳解。 如果你想將區(qū)塊鏈合并到一個Java項目中,現(xiàn)在我們來看看就是這個細分領(lǐng)域中三個最大的OSS玩家。 好的伙計們,我們都聽說過比特幣,以太坊或其他加密貨幣,其中有一些時髦的名字圍繞著我們常見的新聞,但我們作為Java開發(fā)人員知道如何輕松地與這些區(qū)塊鏈技術(shù)進行交互嗎?以...
摘要:我們目前正處于一個新興的區(qū)塊鏈開發(fā)行業(yè)中。,一種在以太坊開發(fā)人員中流行的新的簡單編程語言,因為它是用于開發(fā)以太坊智能合約的語言。它是全球至少萬開發(fā)人員使用的世界上最流行的編程語言之一。以太坊,主要是針對工程師使用進行區(qū)塊鏈以太坊開發(fā)的詳解。 我們目前正處于一個新興的區(qū)塊鏈開發(fā)行業(yè)中。區(qū)塊鏈技術(shù)處于初期階段,然而這種顛覆性技術(shù)已經(jīng)成功地風靡全球,并且最近經(jīng)歷了一場與眾不同的繁榮。由于許多...
摘要:在新智能合約的構(gòu)造函數(shù)中,將引用我們的合約工廠的地址。以太坊,主要是針對工程師使用進行區(qū)塊鏈以太坊開發(fā)的詳解。以太坊入門教程,主要介紹智能合約與應(yīng)用開發(fā),適合入門。這里是原文用工廠模式管理多個智能合約 我們寫了一份小的計算合約作為Hello World。如果我們可以創(chuàng)建一個允許用戶創(chuàng)建自己的計數(shù)器的合約怎么辦? showImg(https://segmentfault.com/img/...
摘要:許多人正試圖學習如何在上開發(fā)智能合約。但是,這些智能合約是由編寫的,并編譯成,這對大多數(shù)非程序員來說似乎很奇怪。在這里,你可以將其視為可以在瀏覽器中加載和運行的文件。將代碼編譯成的格式編譯代碼有很多種方法。 許多人正試圖學習如何在EOS上開發(fā)智能合約。但是,這些智能合約是由C++編寫的,并編譯成WebAssembly,這對大多數(shù)非c++程序員來說似乎很奇怪。因此,在深入了解EOS之前,...
摘要:本文簡單的介紹一下如何安裝智能合約開發(fā)工具包,簡稱,是與智能合約編制相關(guān)的工具集合。對于初學者來說,可以通過使用來編譯智能合約和生成。 本文簡單的介紹一下如何安裝EOS智能合約開發(fā)工具包(Contract Development Toolkit),簡稱CDT,是與智能合約編制相關(guān)的工具集合。對于EOSIO初學者來說,可以通過使用CDT來編譯智能合約和生成ABI。 從1.3.x開始,CD...
閱讀 1686·2021-09-22 10:02
閱讀 1931·2021-09-02 15:40
閱讀 2835·2019-08-30 15:55
閱讀 2243·2019-08-30 15:44
閱讀 3593·2019-08-30 13:18
閱讀 3224·2019-08-30 11:00
閱讀 1945·2019-08-29 16:57
閱讀 564·2019-08-29 16:41