EOS入門指南PART6——別忙着開發,先來看看智能合約數據是怎麼存的

上一章咱們學習了開發智能合約以前須要知道的必要概念:c++

  • 什麼是webAssembly以及它在智能合約上下游中的位置;
  • 什麼是ABI以及怎樣使用eosiocpp工具產生ABI和wasm、wast
  • hello智能合約的簡單入門:部署和調用

若是說智能合約開發是一個鎖着門的圖書館,那麼以前的學習就是鑰匙。如今咱們終於能夠拿着鑰匙打開大門,走進去一探究竟。web

摘要

說到智能合約開發,你們首先想到的確定是寫代碼、像solidity開發同樣教語法。EOS的智能合約是用C++寫的,基本語法你們能夠去買本C++的書;這一篇主要介紹EOS智能合約的數據存儲,爲你們掃清智能合約開發道路上的最後一道障礙。數據庫

什麼是RAM

以前咱們在學習如何在主網建立帳戶時,曾經接觸到RAM的概念。咱們不能像操做以太坊那樣,憑空生成一個地址做爲本身的帳戶,而是要先有一個帳戶,再去建立另外一個帳戶。其中就涉及到一個關於RAM很關鍵的知識點:建立帳戶須要消耗RAM。bash

當時咱們只是很模糊地知道,RAM大概是內存的意思。app

RAM is used to store data in an in-memory database. DApps will use this to store state information so it is quickly available to their app.

RAM是EOS主網中的內存,用於存儲用戶在EOS中使用頻率高的數據(帳戶餘額、合約狀態等)。工具

BM對EOS的指望是成爲區塊鏈世界中的【操做系統】,所以能夠把計算機的一些概念對標到EOS中,其中計算機中的運行內存,在EOS中就能夠看作是RAM;而硬盤就能夠對標EOS區塊鏈數據庫。學習

因此高訪問量的決策類數據,例如帳戶餘額、智能合約的當前狀態等就會被存儲在RAM中,而且這部分數據將長期佔用RAM;而低訪問的費決策性存證數據,例如交易數據,就會存儲在EOS系統的硬盤中,也就是區塊鏈中。當存儲帳號狀態的空間不足,即RAM不足時,轉帳或部署合約等相關操做就沒法執行。區塊鏈

什麼是EOS數據庫

以前咱們曾經介紹過transaction和action,action是智能合約執行的基本單元,transaction能夠認爲是一個或幾個action組成的原子性操做。action在被稱爲action上下文的環境中執行,action上下文提供了執行action所需的一些條件,其中一個就是action的工做內存,這是action保存工做狀態的地方。在處理一個action以前,eosio會先爲它清理一次內存,所以當變量在一個action中被賦值後,另外一個action的上下文是拿不到這個值的。那麼在action之間傳遞狀態的惟一方法就是把它持久存儲到EOS數據庫中,以下圖:ui

action_and_database

這個持久化存儲就是數據庫存儲數據。EOS容許智能合約定義本身的私有數據庫表。好比上圖,Apply Context的內容都是一次性的,一次action執行完成,對象就釋放了,只有存儲到EOSIO database的才被保存。this

什麼是multi_index

接着上面介紹的數據庫往下說, 這個私有數據表是經過multi_index來訪問和交互的。EOS的multi_index相似boost的multi_index,即多索引容器。有了多級索引,智能合約就具有了操做相似數據庫模塊的功能。

multi_index是一個很是方便的、能夠和數據庫交互的容器。

從字面意思來看,multi_index就是一個可使用多索引的數據表。

以下圖:

multi_index

每個multi_index容器均可以理解成傳統數據庫中的一張表,可是行和列稍有不一樣。和傳統的多列的表不一樣的是,multi_index只有一列。這一列中的每一行都表示一個對象,一般這個對象是struct或者是class類型的,有多個成員變量。所以雖然只有一列,可是multi_index的靈活性絲絕不亞於傳統的數據表。

舉個例子,好比下面的這個struct

// @abi table proposal i64
struct Proposal {
  uint64_t id;
  account_name owner = 0;
  string description;
  std::vector<account_name, uint32_t> votes;

  uint64_t primary_key() const { return id; }

  EOSLIB_SERIALIZE( Proposal, (id)(owner)(description)(votes))
};


typedef eosio::multi_index<N(Proposal), Proposal> proposals;

首先看第一行:

// @abi table proposal i64

在部署合約以前,咱們都會用eosiocpp來生成ABI,EOS智能合約編譯器能夠讀取struct結構體和public方法以前的注。在註釋中咱們能夠傳入兩種類型:actiontable,ABI就會根據咱們的聲明,自動在生成的ABI中添加相應的方法或者表定義。

第二個proposal就是表名,而第三個i64就是表的主鍵的類型。在這裏主鍵就是id

account_name

注意到第二個成員變量owner:

account_name owner = 0;

這裏的account_name是EOS本身定義的類型,也就是以前咱們曾經建立過的帳戶名。能夠理解成以太坊中的address類型。

vector

std::vector<account_name, uint32_t> votes;

vector這裏能夠理解成以太坊中的mapping - 自定義的一個映射集合。

Primary Keys

uint64_t primary_key() const { return id; }

eosio::multi_index規定,每行必須有一個主鍵,類型爲64位的無符號整型。表中的對象都會根據主鍵,升序或者降序排列。經過在struct中定義primary_key()方法來獲取。在這個例子中,Proposal的主鍵就是id,類型爲uint64_t。固然主鍵的類型也能夠是account_name等。(account_name在eos中被存儲爲uint64_int類型)。

數據序列化

EOSLIB_SERIALIZE( Proposal, (id)(owner)(description)(votes))

經過閱讀contracts/eosiolib/serialize.hpp文件能夠知道,它實際上是使用了BOOST_PP_SEQ_FOR_EACH宏。它的做用基本上就是賦予了struct額外的操做,能夠把數據序列化到multi_index,或者從multi_index中反序列化出來。

multi_index相關操做

雖然不想SQL語句那樣豐富,可是multi_index依然提供了一些基礎的操做:

  • 建立:使用.emplace
  • 查詢:使用.find
  • 修改已存在的入口:使用.modify

舉個查詢的例子:

auto itr = proposals.find(proposal_id)

以上語句查詢了特定id的proposal,它返回的是一個迭代器iterator。這就涉及到咱們如何使用表中的數據,答案就是迭代器。

eos_iterator

能夠把迭代器想象成一個電梯,在整個數據表中上下滑動(來定位數據),任何對數據的操做都必須經過迭代器。

結束語

這一章概念雖然有些多,可是值得你們仔細研究。這一章咱們學習了:

  • RAM的概念:存儲用戶高頻使用的數據的地方,好比當前狀態;
  • EOS數據庫的概念以及如何存儲;
  • multi_index是什麼 - 和數據庫交互的容器

這一章理論性的內容偏多,理解上可能不如以前的幾篇直觀。下一篇咱們將學習如何操做multi_index,以此帶你們更加深刻地理解multi_index,同時正式開啓咱們的智能合約開發之旅。

相關文章
相關標籤/搜索