【劉文彬】區塊鏈3.0:擁抱EOS

圓方圓區塊鏈發表於2018-12-11

原文連結:醒者呆的部落格園,www.cnblogs.com/Evsward/p/e…

EOS是當下最火的區塊鏈技術,被社會廣泛看好為下一代區塊鏈3.0。不同於以太坊的學習,EOS的主語言是C++,本文作為EOS研究的首篇文章,重點介紹EOS的創新點,它的周邊生態,各種概念原理的解釋,以及它被看好的原因。而針對EOS的原始碼學習,原理實現以及並行的C++語言的快速學習與掌握,我會在接下來制定一系列學習計劃一一付諸實現。

關鍵字:EOS,DAPP,石墨烯技術,構建本地節點,公鏈對映,選舉,EOS鏈配置,術語解釋

EOS.IO

EOS.IO 是由block.one開發的一個基於區塊鏈結構設計的能夠支援水平和垂直擴充套件的去中心化應用的平臺。它就像是一個完整的作業系統,可以在上面構建各種應用。EOS.IO提供了賬戶、認證、資料庫,非同步通訊以及跨平臺跨叢集的定時應用。它有望支援每秒百萬級交易,完全零費率,並可以快速且容易地部署去中心化應用。
複製程式碼

以上是我對官方定義的理解,通過這個定義,我們可以抽離出最主要內容,就是EOS的核心競爭力是:

  • tps:百萬級
  • gas = 0
  • Dapp更加容易高效地被部署

正如在之前的文章中的分析,下一代區塊鏈不是ico,肯定是大規模的各行各業的Dapp的雄起,就像當年網際網路革了傳統行業的命一樣,所以,能夠做好大型商業應用的基建工作的公鏈就是未來區塊鏈的寵兒。目前,呼喊著百萬級tps,手續費為0,快速部署Dapp的EOS無疑切中了所有的要點。

下面針對一些名詞進行一個解釋,以防止混淆:

  • EOS,目前指的是基於ERC20在以太坊上發行的代幣,用於block.one公司開發軟體與社群運營。
  • EOS.IO,是由block.one開發的可構建公鏈的軟體原始碼。
  • EOS platform,採用了EOS.IO軟體構建的公鏈平臺。
  • Dapp,這裡指的是未來在EOS公鏈平臺上基於EOS.IO軟體開發部署的去中心化應用。

EOS

EOS目前是以太坊ERC20的一個Token,很多看好EOS未來的朋友已經大量買入了此Token(包括我身邊很多同事),已成為以太坊Token體系中最強勢的一支。在即將到來的5月底,不出意外地話,EOS.IO公鏈將如期上線,屆時,EOS持有者將會通過某種對映方式將資產轉移到該公鏈上。

EOS私募分配機制

例如,一個週期我計劃發放20枚EOS。在這期間,Bob貢獻了4個ETH,而Alice貢獻了1個ETH,此週期結束。那麼總ETH募集量為5ETH,對應發放一個EOS的等價價值為0.25ETH,因此,Bob會得到16枚EOS,而Alice會獲得4枚EOS。

所以,當你花費ETH或者BTC參與了EOS私募,一定是等到它一個週期結束才會進行錨定核算,你才會收到EOS token。

有個有意思的是,在EOS官方問答上,它不允許美國公民、實體將EOS當做一種投機性產品購買,當然了,因為區塊鏈的匿名性,EOS這麼說並沒有什麼意義,估計只是做個態度,對了官方也不建議EOS買賣,但你也控制不了OTC和交易所(總之,EOS是戲精)。
複製程式碼

另外,block.one為了保證它們不會購買EOS,不會為投資人支付股息,也不會發起任何形式的回購來操縱幣盤,它們打算進行一個獨立的第三方審計,將會釋出一個獨立審計報告提供進一步的保證。

EOS上EOS platform的對映機制

上面講到了,EOS是存在於以太坊的代幣,那麼當EOS公鏈平臺推出以後,如何轉移這些代幣到EOS公幣呢?上面我也提到過是通過某種對映方法。那麼下面就來具體說說是如何對映的。

2018年6月1日,22:59:59,也就是EOS代幣最終的發放週期結束前的23小時倒數計時,EOS將被鎖定交易,不可被交易。

思考,通過上面的總結作為未來研究EOS的經驗,官方講的內容有多少是做戲,有多少隻是提議,畢竟我們是在區塊鏈行業,它無法做到對個人節點行為的控制。所以就以上這句話來講,它如何控制以太坊EOS代幣的交易鎖定?我想它是控制不了的,因為交易所和OTC都不會聽它的,它最多隻是能通過智慧合約控制代幣發放週期而已。因此,要時刻保持獨立思考能力,不要人云亦云,被人洗腦。
複製程式碼

我們繼續來分析,在上面這個時間點,EOS token的發放將會完成,任何人通過EOS.IO原始碼啟動一個EOS platform的,將能夠生成一個JSON檔案會對映EOS的公鑰為以太坊的EOS token賬戶的餘額。

block.one是EOS.IO公鏈原始碼的開發者,它不會配置或啟動任何EOS平臺,block.one將不會控制何時,如何或者EOS.IO軟體是否被使用或實現,或者如何,何時以及是否啟動一個EOS platform。因此,您不應該期望,也不能保證您現在或將來會收到任何其他加密token或數字資產(不想對EOS代幣負責)。

WebAssembly

WebAssembly(縮寫Wasm)是一種基於堆疊的虛擬機器的二進位制指令格式。Wasm設計作為一個行動式的針對高階語言的編譯器,例如C/C++/Rust,使各種客戶端或服務端應用程式都能夠在web中部署。
複製程式碼

目前Wasm支援Firefox,chrome,IE以及Safari瀏覽器。WebAssembly技術是在瀏覽器中不同於JS的另一種存在,但由於C++的高效,Wasm的效率可能會比JS更高,它就是在瀏覽器中執行C++程式的意思,目前WebAssembly比較好的編譯器是LLVM。

石墨烯技術

石墨烯技術是新一代的區塊鏈技術,基於DPOS共識演算法。目前市場上流行的區塊鏈陣營有三種,一種是第一代以比特幣為主的生態體系,他們是基於POW共識,純粹的去中心化,基於p2p的加密數字貨幣技術;第二種就是以以太坊構成的生態體系,主要以基於智慧合約的ERC20的代幣體系,他們是基於POW共識,目前以太坊正準備切換到POW+POS的多共識體系;第三種就是進化到目前最強勁的石墨烯技術生態體系,它是基於DPOS(股份授權證明共識),支援高併發,高效能等大規模工業級商業場景的基礎設施,誕生了BTS(BitShare)開源商業系統,Steem去中心化社交網路平臺以及EOS。未來會針對石墨烯技術以及DPOS共識做一個專門的博文調查。,目前我們看到的石墨烯技術的幾個顯著特點是:

  • 轉賬速度特別快
  • 吞吐量tps極高
  • 安全性很高,沒有原生bug出現
  • 功能強大,應用性極高

防禦機制

第一代比特幣體系是非常安全的,但瓶頸很多。相比之下,第二代的以太坊有很多獨特的創新點,例如智慧合約,然而它歷史遭受攻擊的次數和影響範圍都非常嚴重。最後說基於石墨烯技術的EOS,它是通過個人持有幣的數量進行資源分配(包括儲存空間、網路頻寬以及算力),沒有足夠幣是無法發起攻擊的,而如果大量購幣攻擊,則相當於已經成為房東卻要砸自家房子,是得不償失的行為。所以EOS在防禦攻擊方面是具備天然免疫力的。

分叉的處理

由於出塊權被牢牢掌握在21個超級節點的手裡,如果其中某個節點作惡的話是很容易被追蹤到的,這個節點作惡的表現可能是在它出塊的輪次人為造成了一個分叉,此時,需要21個節點中的15個節點進行確認,通過確認的這一區塊被認為是主鏈上不可逆的一個塊,任何不存在該塊的都會被看做無效。這樣就避免了分叉的可能。

DApp

EOS通過石墨烯基礎技術,再加上自身的優化,可以達到百萬級tps,同時不同於以太坊停留在Paas(平臺即服務)的屬性,EOS開拓思路增加了SaaS(軟體即服務)的能力,加入了Dapp通用的賬號體系、許可權身份認證、非同步通訊、自描述資料庫、自描述介面以及上面提到的WebAssembly瀏覽器客戶端部署工具包,總之,擁有這一切優勢的EOS將真正成為了未來工業級應用的平臺。

不過我們也要感謝以太坊提供的智慧合約和Dapp的思想,在EOS得到了廣泛而有效地發揚,我們可以開發自己的Dapp部署在EOS上,通過持幣數量來獲得對應比例的資源(包括儲存空間,網路頻寬以及算力),這是革了AWS SAAS和PaaS的命(恐怕未來AWS只有提供雲端計算基礎設施的市場了)。

超級節點的選舉機制

不同於以太坊POA,因為以太坊的POA是基於非常小場景的私鏈或者聯盟鏈的,這與大規模對外公開的公鏈EOS的場景是不同的。不過在我還未研究過EOS原始碼的當下來看,DPOS的超級節點的選舉以及出塊的機制與POA如出一轍。

  • 使用者節點通過rpc介面進行投票,這裡面不同的地方是:EOS是通過持幣數量來決定手裡有幾票(這也是權益證明的精髓所在),而以太坊POA只是一個節點一票的形式。
  • 節點被選舉成功,以太坊POA是沒有確定數量限制的,隨時按照全網投票與票數清零以後的每一輪投票結果去增刪超級節點。而EOS則不同,超級節點目前只有21個,在整個投票週期結束以後,排名前21位即勝任。
  • 超級節點的要求不同,以太坊POA的認證節點與普通節點並非有任何差別。而EOS的超級節點則不同,這21個超級節點必須符合非常高的效能要求以及運維能力,社群規模等。
  • 機會均等概念在EOS超級節點中仍然是存在的,不過當一個超級節點出塊方面出現問題,在一定規則下會被丟棄,然後重新選出新的節點替代它作為超級節點的身份。

EOS術語解釋

  • Account,賬戶
  • Authority,權力
  • Block,縮寫Blk,每個區塊可包含0個或多個交易,以及一個對前置區塊的加密連線。不可逆。
  • DAC,分權自治集體,或者是分權自治公司。
  • DAO,分權自治組織
  • Deferred Transaction,縮寫defTx,延期交易。該交易是有智慧合約所建立,會在未來的某個時間被執行。這個交易也能夠建立另一個在其之後的交易。因此,延期交易可以建立無限迴圈的順序交易。使用者授權一個延期交易必須指定到執行的時刻擁有足夠的頻寬,儲存來執行預期交易。
  • DLTs,分散式賬本技術。一種分散式賬本(也被稱作共享式賬本),它是一個基於複製、共享以及同步數字化資產的跨站點、跨國家、跨機構的共識。
  • DPoS,授權權益證明。此外,也可以代表民主即權益證明。DPoS是共識演算法的一種,即區塊生產者能夠針對交易或區塊的真實性,可驗證,不可逆等特性達成共識的一種方法。
  • Key pair,縮寫keys,一個金鑰對,包括公鑰和其對應的私鑰。
  • larimer,一種EOS的計量單位,等於0.0001 EOS。(性質如同以太坊中的Wei)
  • Master Password,用於解鎖,或解密一個錢包檔案的密碼。
  • Action,一個對區塊鏈的改變動作。可以是一個或這多個動作組成一個交易。
  • Non-Producing Node,非生產節點,也可以被理解為普通節點。這是一個完整的區塊鏈節點,但它智慧觀察和驗證區塊,以及只能維護自己本地區塊鏈的拷貝。一個普通節點可以在一個“備用池”中,通過投票流程稱為生產節點(具備出塊權的超級節點)一個超級節點,也會被投票出局,成為一個普通節點。但是值得注意的是,大多數普通節點並不在“備用池”中。
  • Oracle,在區塊鏈和智慧合約的上下文中,它是一個代理,被智慧合約使用用來找到和驗證實際發生的並提交這個資訊到區塊鏈上。
  • peer-to-peer,p2p,對等計算或網路是一個分散式應用程式架構,在對等環境下,它被分去為任務或者是工作量。對等節點是擁有等價許可權,在應用程式中的參與機會均等。他們組成了點對點的網路節點。
  • Permission,加權的,安全機制,通過評估它的簽名權力來確定一個資訊是否被正確授權。
  • Private Key,用來簽名交易的私鑰。
  • Public Key,縮寫pub key,公鑰,會在交易間被傳輸。
  • Scope,作用域,智慧合約的作用域,智慧合約智慧寫入他們同一個作用域的自己的其他合約,而只能夠讀取其他作用域的合約。
  • Smart Contract, 智慧合約,一個計算機協議,旨在促進、驗證或執行談判。
  • Standby Pool,100個全節點的集合,渴望被選中為21個超級節點之一,他們實際上已經擁有了超級節點的能力,無論何時鏈需要替換一個超級節點時,就會從備用池中選擇。
  • Transaction,縮寫Tx,Txn。它有事務的含義,一般我們稱作交易。它是一個完整的原子的區塊鏈的變化,一個或多個訊息的組合,在EOS中通常是由一個智慧合約來執行。
  • Wallet,錢包,會生成一個加密錢包檔案或是通過客戶端來管理,例如cleos。它管理了私鑰以及用一個安全的方式去促進交易的簽名。錢包可以被鎖定或解鎖。
  • Block Producer, 縮寫bp。21個超級節點之一,是目前正在出塊輪次的那個超級節點。

構建本地環境

EOS三個元件:

  • nodeos:服務端區塊鏈節點元件
  • cleos:命令列介面,與區塊鏈互動,管理錢包,管理賬戶,在區塊鏈上呼叫方法。(很重要,相當於以太坊web3)
  • keosd:管理EOSIO錢包的元件。

接下來,我們將構建這些EOSIO元件,並將它們部署在一個主機,通過單個節點對網路(testnet)進行測試與配置。

構建原始碼

獲取原始碼

recursive引數會將所有子元件自動克隆下來,最終我們會在本地得到全部完整的原始碼。

git clone https://github.com/EOSIO/eos --recursive

自動構建原始碼。

cd eos && ./eosio_build.sh

構建時間較長,最終構建成功的頁面如下:

[100%] Built target cleos
Scanning dependencies of target nodeos
[100%] Building CXX object programs/nodeos/CMakeFiles/nodeos.dir/main.cpp.o
[100%] Linking CXX executable chain_test
[100%] Linking CXX executable nodeos
[100%] Built target chain_test
[100%] Built target nodeos


     _______  _______  _______ _________ _______
    (  ____ \(  ___  )(  ____ \\__   __/(  ___  )
    | (    \/| (   ) || (    \/   ) (   | (   ) |
    | (__    | |   | || (_____    | |   | |   | |
    |  __)   | |   | |(_____  )   | |   | |   | |
    | (      | |   | |      ) |   | |   | |   | |
    | (____/\| (___) |/\____) |___) (___| (___) |
    (_______/(_______)\_______)\_______/(_______)

    EOS.IO has been successfully built. 0:32:57

    To verify your installation run the following commands:

    /home/liuwenbin/opt/mongodb/bin/mongod -f /home/liuwenbin/opt/mongodb/mongod.conf &
    cd /home/liuwenbin/eos/build; make test

    For more information:
    EOS.IO website: https://eos.io
    EOS.IO Telegram channel @ ***EOSProject
    EOS.IO resources: https://eos.io/resources/
    EOS.IO wiki: https://github.com/EOSIO/eos/wiki
複製程式碼

手動構建原始碼

安裝開發工具包

sudo apt-get update
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo apt-get install clang-4.0 lldb-4.0 libclang-4.0-dev cmake make \
                     libbz2-dev libssl-dev libgmp3-dev \
                     autotools-dev build-essential \
                     libbz2-dev libicu-dev python-dev \
                     autoconf libtool git mongodb
複製程式碼
wget 下載llvm-key出錯,可以按照提示加入引數--no-check-certificate搞定。
複製程式碼

依賴

基於我本機是Ubuntu16.04,除了使用上面的自動編譯以外,也可以手動安裝,不怕折磨的話。

目前EOS當前版本的依賴包括:

  • Clang 4.0.0
  • CMake 3.5.1
  • Boost 1.66
  • OpenSSL
  • LLVM 4.0
  • secp256k1-zkp (Cryptonomex branch)

依賴安裝請參照官方文件

跑單元測試

cd build && make test

這一步是為了驗證原始碼功能完整度,耗時也較久。

安裝命令

sudo make install

命令會被安裝在/usr/local。執行完這個命令以後,我們可以在系統任何位置進行命令啟用。

啟動一個單獨節點

構建完成後,會在build/programs/目錄中出現nodeos資料夾,這是我們要啟動節點的工具。通過以下命令啟動你自己的獨立節點區塊鏈

cd programs/nodeos && ./nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::account_history_api_plugin 
複製程式碼

這條命令中,可執行檔案./nodeos後面有很多引數,好看的是後面的plugin是啟動時對外掛的配置,剩下的引數配置我們會在接下來介紹到。啟動以後,日誌列印出來相關資訊:

liuwenbin@liuwenbin-H81M-DS2:~/work/CLionProjects/github.com/eos/build/programs/nodeos$ ./nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::c
hain_api_plugin --plugin eosio::account_history_api_plugin 
3054170ms thread-0   wallet_plugin.cpp:41          plugin_initialize    ] initializing wallet plugin
3054170ms thread-0   http_plugin.cpp:141           plugin_initialize    ] host: 127.0.0.1 port: 8888 
3054170ms thread-0   http_plugin.cpp:144           plugin_initialize    ] configured http to listen on 127.0.0.1:8888
3054170ms thread-0   chain_plugin.cpp:99           plugin_initialize    ] initializing chain plugin
3054170ms thread-0   net_plugin.cpp:2628           plugin_initialize    ] Initialize net plugin
3054170ms thread-0   net_plugin.cpp:2644           plugin_initialize    ] Setting net_plugin logging level to info
3054170ms thread-0   net_plugin.cpp:2669           plugin_initialize    ] host: 0.0.0.0 port: 9876 
3054170ms thread-0   net_plugin.cpp:2745           plugin_initialize    ] my node_id is 86aa711400110362b7a94d9468fc45bdbfa8887a3bdaf9502dbea59694179b09
3054170ms thread-0   main.cpp:90                   main                 ] nodeos version 96ee0325
3054170ms thread-0   main.cpp:91                   main                 ] eosio root is /home/liuwenbin/.local/share
3054170ms thread-0   http_plugin.cpp:213           plugin_startup       ] start listening for http requests
3054170ms thread-0   wallet_api_plugin.cpp:70      plugin_startup       ] starting wallet_api_plugin
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/create
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/get_public_keys
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/import_key
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/list_keys
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/list_wallets
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/lock
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/lock_all
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/open
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/set_timeout
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/sign_transaction
3054170ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/wallet/unlock
3054170ms thread-0   chain_plugin.cpp:178          plugin_startup       ] 
 generating default genesis file /home/liuwenbin/.local/share/eosio/nodeos/config/genesis.json
3054209ms thread-0   chain_plugin.cpp:208          plugin_startup       ] starting chain in read/write mode
3054209ms thread-0   chain_plugin.cpp:213          plugin_startup       ] Blockchain started; head block is #0, genesis timestamp is 2018-03-01T12:00:00.000
3054209ms thread-0   chain_api_plugin.cpp:62       plugin_startup       ] starting chain_api_plugin
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/abi_bin_to_json
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/abi_json_to_bin
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_account
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_block
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_code
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_currency_balance
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_currency_stats
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_info
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_required_keys
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/get_table_rows
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/push_block
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/push_transaction
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/chain/push_transactions
3054209ms thread-0   account_history_api_plugin.cpp:45 plugin_startup       ] starting account_history_api_plugin
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/account_history/get_controlled_accounts
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/account_history/get_key_accounts
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/account_history/get_transaction
3054209ms thread-0   http_plugin.cpp:242           add_handler          ] add api url: /v1/account_history/get_transactions
3054209ms thread-0   net_plugin.cpp:2757           plugin_startup       ] starting listener, max clients is 25
3054209ms thread-0   producer_plugin.cpp:161       plugin_startup       ] producer plugin:  plugin_startup() begin
3054209ms thread-0   producer_plugin.cpp:166       plugin_startup       ] Launching block production for 1 producers.

*******************************
*                             *
*   ------ NEW CHAIN ------   *
*   -  Welcome to EOSIO!  -   *
*   -----------------------   *
*                             *
*******************************

Your genesis seems to have an old timestamp
Please consider using the --genesis-timestamp option to give your genesis a recent timestamp

3054209ms thread-0   producer_plugin.cpp:176       plugin_startup       ] producer plugin:  plugin_startup() end
eosio generated block bd1a5181... #1 @ 2018-04-13T02:50:54.500 with 0 trxs, lib: 0
eosio generated block a8c18ba3... #2 @ 2018-04-13T02:50:55.000 with 0 trxs, lib: 1
eosio generated block 1e4c703f... #3 @ 2018-04-13T02:50:55.500 with 0 trxs, lib: 2
eosio generated block d4c29cd4... #4 @ 2018-04-13T02:50:56.000 with 0 trxs, lib: 3
複製程式碼

下面來逐一分析一下這個日誌內容,可以看出EOS啟動私鏈節點是通過外掛實現的,在啟動私鏈前,要對外掛進行初始化配置,啟動各依賴元件處理器。下面來列舉一下主要外掛內容:

  • wallet_plugin,錢包管理相關,啟動階段只出現過一次,說明它的功能主要依賴啟動後的操作,而在啟動期間需要做的配置很少。
  • wallet_api_plugin,依賴於wallet_plugin,出現一次,應該是提供外部呼叫與錢包互動的介面服務。
  • http_plugin,啟動階段大量出現的外掛,說明在準備期,針對HTTP的配置和新增介面服務非常多。配置包括url,埠,監聽。介面服務包括錢包相關,鏈相關,賬戶相關的一系列api地址。
  • chain_plugin,鏈外掛配置,出現了幾次,除了初始化啟動以外,還有針對鏈資料讀取模式的配置為read/write模式,生成創世塊配置檔案genesis.json,以及展示了創世區塊的各種屬性資訊。
  • chain_api_plugin,同樣的,依賴於chain_plugin,提供外部呼叫鏈相關操作的介面服務。
  • net_plugin,網路外掛,出現了幾次,是對網路節點的基本配置,包括網路日誌的級別為info,本地網路監聽埠,生成節點id。最後啟動監聽器,並設定了以該網路節點為伺服器的客戶端最多能夠連入25個。
  • main,主外掛,對eosio這整個軟體的一個主要外掛,配置了eosio的版本以及展示了eosio工作的本地root地址。
  • account_history_api_plugin,顧名思義,賬戶歷史介面外掛,估計是與賬戶歷史相關的供外部呼叫的介面服務。
  • producer_plugin,區塊生產者外掛,外掛啟動。

以上出現的所有外掛亦可理解為元件。

接著看日誌,提示我創世塊時間戳過時,可以通過一個引數來修改,下面我嘗試修改一下,在以上啟動命令加入了引數,重新啟動:

--genesis-timestamp 2018-04-13T12:00:00.000

重新啟動以後,列印出來的日誌中,前面的都是相同的,我們從producer_plugin貼出來是:

862009ms thread-0   producer_plugin.cpp:161       plugin_startup       ] producer plugin:  plugin_startup() begin
862009ms thread-0   producer_plugin.cpp:166       plugin_startup       ] Launching block production for 1 producers.
862009ms thread-0   producer_plugin.cpp:176       plugin_startup       ] producer plugin:  plugin_startup() end
862501ms thread-0   fork_database.cpp:77          _push_block          ] Number of missed blocks: 2783
eosio generated block 8e2a6ce1... #34 @ 2018-04-13T03:14:22.500 with 0 trxs, lib: 33
eosio generated block eb5e67b9... #35 @ 2018-04-13T03:14:23.000 with 0 trxs, lib: 34
eosio generated block 5aa06ff6... #36 @ 2018-04-13T03:14:23.500 with 0 trxs, lib: 35
複製程式碼

可以看到,那個關於創世塊時間戳的提示已經消失,producer_plugin外掛啟動開始與完畢。接下來就是

fork_database程式,推送區塊,報出了消失區塊好2783。TODO:這一行還待未來分析解決。
複製程式碼

接下來就是正常出塊了,由於我們本地啟動的節點一定是具備出塊權的(目前只有一個節點未涉及共識),這些塊是不包含任何交易資訊的,出塊速度很快。

停止

斷開私鏈直接按下複製鍵(Ctrl+C)即可,日誌中也有體現:

eosio generated block de403b91... #37 @ 2018-04-13T03:14:24.000 with 0 trxs, lib: 36
eosio generated block f40f0e68... #38 @ 2018-04-13T03:14:24.500 with 0 trxs, lib: 37
eosio generated block c1b717d0... #39 @ 2018-04-13T03:14:25.000 with 0 trxs, lib: 38
865075ms thread-0   net_plugin.cpp:2771           plugin_shutdown      ] shutdown..
865075ms thread-0   net_plugin.cpp:2774           plugin_shutdown      ] close acceptor
865075ms thread-0   net_plugin.cpp:2777           plugin_shutdown      ] close 0 connections
865075ms thread-0   net_plugin.cpp:2785           plugin_shutdown      ] exit shutdown
複製程式碼

可以看到私鏈停止時,都是通過net_plugin外掛來操作,操作的方法是與plugin_startup對應的plugin_shutdown,步驟為:

  • 開始關閉的標識
  • 關閉接收器acceptor
  • 關閉連線
  • 完成私鏈停止工作,退出shutdown程式

以上內容在未來的原始碼分析中均會涉及。

配置

EOS環境啟動以後,可以在本地目錄:~/.local/share/eosio/nodeos/ 找到鏈相關檔案:

liuwenbin@liuwenbin-H81M-DS2:~/.local/share/eosio/nodeos$ tree
.
├── config
│   ├── config.ini
│   └── genesis.json
└── data
    ├── blocks
    │   ├── blocks.index
    │   └── blocks.log
    └── shared_mem
        ├── shared_memory.bin
        └── shared_memory.meta

4 directories, 6 files
複製程式碼

根目錄下包含config和data兩個目錄,data目錄中儲存了區塊執行時資料,日誌以及共享記憶體相關資料,我們重點來看config資料夾中的內容:

genesis.json

{
  "initial_timestamp": "2018-03-01T12:00:00.000",
  "initial_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
  "initial_configuration": {
    "base_per_transaction_net_usage": 100,
    "base_per_transaction_cpu_usage": 500,
    "base_per_action_cpu_usage": 1000,
    "base_setcode_cpu_usage": 2097152,
    "per_signature_cpu_usage": 100000,
    "per_lock_net_usage": 32,
    "context_free_discount_cpu_usage_num": 20,
    "context_free_discount_cpu_usage_den": 100,
    "max_transaction_cpu_usage": 10485760,
    "max_transaction_net_usage": 104857,
    "max_block_cpu_usage": 104857600,
    "target_block_cpu_usage_pct": 1000,
    "max_block_net_usage": 1048576,
    "target_block_net_usage_pct": 1000,
    "max_transaction_lifetime": 3600,
    "max_transaction_exec_time": 0,
    "max_authority_depth": 6,
    "max_inline_depth": 4,
    "max_inline_action_size": 4096,
    "max_generated_transaction_count": 16
  },
  "initial_chain_id": "0000000000000000000000000000000000000000000000000000000000000000"
}
複製程式碼

可以看到初始化時間戳,初始化key,以及初始鏈id,鏈配置。其中鏈配置又包含了基礎每筆交易的網路使用size、cpu使用size,每個方法、每個setcode、每個簽名的cpu使用size,每個鎖的網路使用size,空閒期間的cpu使用度折扣上下文,交易的cpu、網路使用度的最大值,區塊的最大網路使用size,目標區塊的網路使用size,交易最大存活生命週期長度、執行時間,許可權深度的最大值,最大內聯深度,最大內聯操作size,交易的最大生成數量。

上面對genesis.json創世塊描述檔案進行了平鋪直敘,我們可以看到,鏈時間,鏈key,鏈id都比較常見,而細緻入微到標識了每個方法、每個簽名等等的資源分配,這是很令人驚奇的。說明了

EOS對資源的控制是非常看中的。
複製程式碼

config.ini

這是一個全域性配置檔案,就像java的property檔案一樣。這裡面的配置會被細分到是由哪一個外掛來使用的,例如針對http_plugin配置的地址埠號等等,我們也可以通過手動修改這些配置來控制鏈的一些表現。config.ini這個全域性配置檔案就是開放給外部人員,作為各種功能的靜態變數配置,功能開關等工具使用。下面針對配置項逐一分析: 屬於account_history_plugin外掛的配置

  • filter_on_accounts:功能是實現僅追蹤配置值的賬戶產生的交易,預設註釋掉該配置項,意思是不設過濾器,追蹤所有交易。
  • get-transactions-time-limit:執行單個get_transactions呼叫的執行時間,單位是豪妙,預設值為3(意思是3毫秒讀不到就丟棄)

屬於chain_plugin外掛的配置

  • genesis-json,指定創世塊配置檔案位置,預設值是“genesis.json”
  • genesis-timestamp,複寫初始化創世塊時間戳,我們上面不是在啟動命令中通過加入--genesis-timestamp引數來配置該值了麼,在這裡配置以後重啟會是相同的效果。預設值是註釋掉,啟動時時間戳一般會過時。
  • block-log-dir:是區塊日誌的儲存位置,絕對路徑或者應用程式的相對路徑。
  • checkpoint:是一對區塊高度+區塊id,用來作為檢查點。預設註釋掉,不設定檢查點。(檢查點的使用會在之後介紹,TODO)
  • max-reversible-block-time:允許可逆區塊在被確認為無效之前存在的時間,預設為-1,不允許出現可逆區塊。
  • max-pending-transaction-time:允許pending交易在無效之前的執行時間,預設為-1,不允許出現pending的交易。
  • max-defered-transaction-time:允許延遲執行交易到區塊的推送時間,預設值20,
  • wasm-runtime:複寫預設的WebAssembly的runtime。預設是註釋掉(TODO:啥意思)

屬於faucet_testnet_plugin配置

  • faucet-create-interval-ms:建立賬戶的間隔,預設1秒鐘。
  • faucet-name:建立賬戶的建立器的名字。預設就是faucet。
  • faucet-private-key:公鑰,WIF(TODO:解釋WIF)私鑰,用於faucet建立賬戶簽名。預設值是在原始碼下載時指定的,我們可以通過工具自己更改。

屬於http_plugin配置

  • http-server-address:本地IP埠,用於監聽進入的http連線。預設值為127.0.0.1:8888
  • access-control-allow-origin:允許訪問控制,每個請求會返回一個確定的access-control-allow-origin。預設註釋掉,不設定特殊訪問限制。
  • access-control-allow-headers:同上,只是不是http請求的origin控制了,而是通過http頭來控制。預設也註釋掉,不設定特殊訪問限制。
  • access-control-allow-credentials:如果有特殊的訪問限制證照則返回true。預設值為flase,不設限。

屬於mongo_db_plugin配置

  • mongodb-queue-size:nodeos和mongodb元件執行緒之間的佇列大小。預設值為256。
  • mongodb-uri:MongoDB的uri連線字串,如果不配置則該mongodb元件是未被啟用的,而使用預設的‘EOS’資料庫。預設值不配置。

屬於net_plugin配置

  • p2p-listen-endpoint:實際的主機加埠,用來監聽進來的p2p連線。預設值為0.0.0.0:9876
  • p2p-server-address:一個外部訪問的主機加埠,用於標識當前節點。預設使用上面的p2p-listen-endpoint配置。
  • p2p-peer-address:公共的對等節點的端點位置,提供外部連線。使用多重p2p-peer-address選項作為構成網路的需要。預設值是註釋掉,不設定p2p相關配置。(TODO,p2p網路設定測試)
  • agent-name:在對等節點之間,用於標識一個節點而設定的名字。
  • allowed-connection:連線許可,可選值包括
    • any:允許所有連線,不設限制。
    • producers:僅允許區塊生產者連線,節點key是不需要的。
    • specified:配置節點key作為特殊連線,可以與producers節點key重複(要配置多個的時候可以不適用producers,而用這個,否則沒意義)
    • none:誰都不允許連入。
  • peer-key:可選項,允許連線的節點公鑰。可以被多次使用。預設值是註釋掉,不使用該配置項。
  • peer-private-key:公鑰,WIF私鑰元組,可被指定多次。預設註釋掉,不使用。
  • log-level-net-plugin:日誌級別包括all,debug,info,warn,error,off,這個不說了
  • max-clients:接收連線的客戶端的最大數量,設為0的話表示沒有限制。預設25個。
  • connection-cleanup-period:在清理死連線之前,等待的秒數。預設值是30s。
  • network-version-match:準確匹配對等網路版本。
  • sync-fetch-span:同步獲取量,同步時,從任何個人節點取回作為一個chunk(大塊)的區塊數量,預設是100個。

屬於producer_plugin配置

  • enable-stale-production:陳舊生產能力。即使鏈是陳舊的,也能夠出塊。預設值是false,不允許陳舊鏈(TODO:什麼是陳舊鏈)
  • required-participation:必須參與出塊。必須參與按序出塊的區塊生產者的百分比。預設值是33。至少33%的區塊生產者是要參與到按序出塊的。
  • producer-name:producer的ID,受節點控制。可能多次指定。預設值是註釋掉,不使用。
  • private-key:私鑰,公鑰,WIF私鑰元組,可以指定多次。預設值已有,可以修改。

屬於wallet_plugin配置

  • wallet-dir:錢包檔案的路徑,絕對路徑或者應用程式的相對路徑。預設值是當前路徑“.”

  • unlock-timeout:解鎖錢包的超時時間,單位是秒。錢包在沒有活動一段時間以後會自動上鎖,這些活動可來自於任何錢包命令,例如list-wallet等。預設是註釋掉,沒有超時時間,不自動上鎖。

  • eosio-key:在錢包建立時,eosio祕鑰將被自動匯入,預設是註釋掉,先不設定,因為我嗎是新建立錢包,未通過現有錢包匯入。

  • plugin:啟用外掛,可以被特殊指定多次。預設是註釋掉,沒有特例,是外掛都好使。

      配置中出現的所有time的單位一般都是毫秒。
    複製程式碼

啟動命令引數

配置檔案加啟動命令

上面我們通過命令

 ./nodeos -e -p eosio --genesis-timestamp 2018-04-13T12:00:00.000 --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::account_history_api_plugin 
複製程式碼

啟動了本地EOS環境。下面我們針對這個啟動指令碼的使用引數進行學習:

  • -e:enable-stale-production,參加上面config.ini的相關說明。設定以後相當於true。
  • -p:producer-name,給定了一個名字“eosio”用於出塊者名字。
  • --plugin:就是config.ini最後一個配置欄位。

所以我在config.ini針對以上命令進行靜態配置。

enable-stale-production = true
producer-name = eosio
複製程式碼

plugin的配置方式:

# Load the block producer plugin, so you can produce blocks
plugin = eosio::producer_plugin
# Wallet plugin
plugin = eosio::wallet_api_plugin
# As well as API and HTTP plugins
plugin = eosio::chain_api_plugin
plugin = eosio::http_plugin
# This will be used by the validation step below, to view account history
plugin = eosio::account_history_api_plugin
複製程式碼

配置結束以後,由於上面我們也執行了命令安裝(sudo make install),下面我們可以直接在任何位置使用命令

nodeos

即可啟動與之前命令相同的EOS本地環境。

指定配置檔案地址

我們可以在機器中維護多套config.ini 以及 genesis.json檔案,然後啟動EOS環境時通過引數

--config-dir:指定地址用來載入配置檔案,絕對路徑或應用程式相對路徑。

指定執行時資料地址

我們也可以通過啟動引數指定執行時資料的儲存位置。

--data-dir:指定地址用來存放執行時資料,日誌以及共享記憶體相關資料,絕對路徑或應用程式相對路徑。

其實config-dir和data-dir就是對映的上面的~/.local/share/eosio/nodeos/的內容,我在上面使用樹形結構列舉了出來,他們通過啟動引數均可指定新的位置。

總結

本文是EOS的入門手冊,介紹了EOS基本概念和術語解釋,包括髮展歷史,私募、代幣、公鏈對映方案,選舉機制、Dapp以及防禦機制,最後對本地環境進行了構建,包括自動和手動的,以及啟動引數,結合分析了鏈的各種外掛的配置引數,語義。接下來我分三個大步來加深自身的EOS的專業度:

  • 下一步我將通過兩篇文章重點快速學習C++語言基礎
  • 然後通過一到兩篇文章繼續EOS的分析研究,會根據官方文件從智慧合約、開發工具、互動工具、賬戶錢包許可權模組去進一步介紹EOS,同時會加入對RPC的使用研究
  • 再下一步我會根據EOS白皮書的結構,結合原始碼去具體分析EOS各個外掛的實現、區塊通訊、DPOS共識演算法,賬戶管理,併發,Token,治理,指令碼與虛擬機器

參考資料

EOS官方文件


相關文章和視訊推薦

圓方圓學院彙集大批區塊鏈名師,打造精品的區塊鏈技術課程。 在各大平臺都長期有優質免費公開課,歡迎報名收看。

公開課地址:ke.qq.com/course/3451…

相關文章