【跟着源碼學】EOS智能合約之eosio.system - part1

本系列還是着眼於瞭解EOS的設計理念,力求在繁雜的版本變更,以及各種區塊鏈技術文章當中,根據源碼整理出一個清晰簡明的eos實現,而暫時不着眼研究C++工程開發的奇淫巧技,主要是因爲還需要時(目)間(前)繼(領)續(悟)修(不)煉(到)。

正文

clipboard.png

代碼鏈接

這個multi_index是什麼呢?

在eoslib目錄下有multi_index.hpp,自然而然的來看看這裏面有什麼線索。

這裏,找到了如下解釋:

  • EOSIO Multi-Index API provides a C++ interface to the EOSIO database. It is patterned after Boost Multi Index Container.
  • EOSIO Multi-Index table requires exactly a uint64_t primary key. For the table to be able to retrieve the primary key,
  • the object stored inside the table is required to have a const member function called primary_key() that returns uint64_t.
  • EOSIO Multi-Index table also supports up to 16 secondary indices. The type of the secondary indices could be any of:
    • uint64_t
    • uint128_t
    • uint256_t
    • double
    • long double

原來multi_index是跟EOSIO數據庫相關的API。相對應的,官方開發者文檔有DB API的描述,簡要解釋一下使用場景:

比如開發一個遊戲DApp,用戶有自己的Action(很難翻譯,可以理解爲執行一個函數,比如randint(6),模擬了一次擲骰子,返回結果從1至6)操作, 該遊戲智能合約要記錄每位用戶遊戲Actions,本次合約執行完畢後數據不能丟失,就需要將數據存儲到 EOS 數據庫中。

Action在被稱爲Action執行上下文的環境中運作。如下圖所示,

clipboard.png

Action上下文提供執行Action所需的幾件事情。
其中一件事是Action的工作內存。這是Action執行的地方。在處理一個Action之前,EOSIO爲該Action進行一次內存清理工作。在新Action的上下文中當另一個Action執行時可能已經被設置的變量不可用。在Action中傳遞狀態的唯一方法是將其持久存儲並從EOSIO數據庫中檢索。

看到這裏,感覺引入概念越來越多,暫時先搬運了一些現成資料(見參考),再後續學習中慢慢消化。

這裏提到了eosio::multi_index table借鑑了Boost庫中的multi_index容器(Boost庫中的mult_index)。可以在概念上看作傳統數據庫中的表格,其中行是容器中的單個對象,列是容器中對象的成員屬性,並且索引通過與一個鍵兼容的鍵提供對對象的快速查找 對象成員屬性。

傳統的數據庫表允許索引成爲表中某些列數的用戶定義函數。eosio::multi_index同樣允許索引是任何用戶定義的函數。但其返回值僅限於受支持的一組受限密鑰類型之一。

傳統數據庫表通常有一個唯一的主鍵,它允許明確標識表中的特定行,併爲表中的行提供標準排序順序。eosio::multi_index支持類似的語義,但是該對象的主鍵在eosio::multi_index容器必須是唯一的無符號64位整數。eosio::multi_index中的對象容器按主鍵索引按無符號64位整數主鍵的升序排序。

智能合約無法直接操作存儲在硬盤中的數據表,而是需要使用multi_index作爲中間工具(或者叫容器),每個multi_index實例都與一個特定賬戶的特定數據表進行交互(取決於實例化時的參數)。EOS智能合約與EOS數據庫的數據交互如下圖所示。

clipboard.png

每一個multi_index都相當於傳統數據庫的一個數據表(table),但將傳統數據庫的行與列的形式改爲了單純的列。也就是說multi_index是一個線性排列的表,只有一列,每一行都只存儲一個對象。但是一般來說multi_index存儲的對象都是結構體或者類,裏面含有多個成員變量,所以multi_index存儲數據的靈活性也是不亞於傳統數據庫的。

我們使用官方的“汽車維修店”示例,我們建立一個數據表,儲存每個汽車維修店客戶的賬戶名、保養時間、車輛里程。那麼multi_index數據表儲存的項目中,每個都是如下的結構體:

struct service_rec {
    uint64_t        pkey;           // 主鍵
    account_name    customer;       // 車主用戶名
    uint32_t        service_date;   // 維修保養時間
    uint32_t        odometer;       // 車輛里程
}

在傳統數據庫中,需要建立一個 4 列的數據表,用來儲存每個用戶的這個 4 個數據,而multi_index的每個數據表只有一列,只存儲每個用戶的 service_rec 整個結構體即可。下圖爲multi_index數據結構。

clipboard.png

多索引迭代器(multi_index iterator),與僅提供鍵值(key-value)存儲的其他區塊鏈不同,EOSIO Multi-Index表允許合約開發人員保存按照各種不同鍵類型排序的對象集合,這些鍵類型可以從對象內的數據派生。這使得豐富的檢索功能。最多可以定義16個二級索引,每個索引都有自己的排序和檢索表格內容的方式。

EOSIO多索引迭代器遵循C++迭代器通用的模式。所有迭代器都是雙向常量,可以是const_iterator或const_reverse_iterator。迭代器可以取消引用以提供對多索引表中的對象的訪問。

在 EOS 數據庫中,可以將迭代器比喻爲一個“電梯”,在整個數據表中上下穿梭。所有對數據的操作必須通過迭代器完成。典型的數據修改過程是這樣的:首先使用迭代器的find()方法,在特定的索引中尋找需要的數據,比如在車主用戶名索引中尋找某個用戶。迭代器會移動到需要的數據對象上。然後就可以使用迭代器的modify()方法修改當前迭代器對應的數據。下圖爲迭代器指向用戶 Sue 的情況。

clipboard.png

參考

EOS多索引表
EOS 數據庫與持久化 API —— 架構

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章