AElf共識合約標準(ACS4)--aelf開發者社區

ACS:AElf Contract Standard,AElf合約標準,顧名思義,就是開發AElf智能合約時須要繼承和實現的一些接口。
全部的ACS都經過protobuf的service定義。 ACS4做爲ACS之一,是實現任意一種共識合約時,須要實現的一些接口。
本文主要討論共識標準接口的可行性和AElf中爲共識合約的實現所提供的接口及其餘支持。

抽象共識的思路

站在實現區塊鏈共識的角度,咱們主要關心三件事:git

誰能夠產生區塊,如PoW共識容許每個人參與算力競爭,PoS和DPoS共識則要對此作出必定限制;
若是能夠產生區塊,那麼應該在何時產生,或者說當前的時間能不能開始嘗試廣播區塊;
做爲一個區塊鏈全節點,應該怎麼驗證這個區塊的合法性。github

針對這三點,咱們很容易想到三類接口:數據庫

輸入公鑰,判斷這個公鑰有沒有資格產生區塊,PoW共識直接返回true就能夠了,DPoS可能會對大部分人返回false。
輸入公鑰,返回這個公鑰下一次可以產生區塊的時間戳,或者返回這個公鑰當前能不能產生區塊。
全節點獲得區塊頭(block header)以後,輸入從中提取到的共識數據,驗證這個區塊的1和2相關信息,即,PoW共識須要驗證nonce的合法性,DPoS共識須要驗證新區塊的生產者身份合法性、生產者是否尊重本身的時間槽,獲得驗證結果。
除此之外,爲了獲得接口3中的輸入,即區塊頭中的共識數據,至少還須要爲區塊生產者提供一個生成區塊頭共識數據的方法。區塊鏈

AElf中的實踐
首先,AElf的主鏈選擇的共識屬於DPoS,本文雖然說討論的是通用共識接口,也免不了傾向於多討論(AE)DPoS。google

其次,全部的共識合約標準上的接口,都是隻讀的,由於單純獲取這些數據無需改動WorldState。(WorldState是以太坊中的概念,AElf在開發中稱用於存儲合約的狀態的數據庫爲State DB;除此以外還有Chain DB,用於存儲區塊自己,包括區塊中的交易。)code

ACS4中合併了接口1和接口2,獲得一個接口:orm

rpc GetConsensusCommand (google.protobuf.BytesValue) returns (ConsensusCommand) {繼承

option (aelf.is_view) = true;

}接口

message ConsensusCommand {開發

int32 NextBlockMiningLeftMilliseconds = 1;// How many milliseconds left to trigger the mining of next block.
int32 LimitMillisecondsOfMiningBlock = 2;// Time limit of mining next block.
bytes Hint = 3;// Context of Hint is diverse according to the consensus protocol we choose, so we use bytes.
google.protobuf.Timestamp ExpectedMiningTime = 4;

}
很顯然,NextBlockMiningLeftMilliseconds的值取決於ExpectedMiningTime(預期出塊時間)與當前時間(調用這個接口的時間)的差值。

LimitMillisecondsOfMiningBlock是系統分配給這個塊用於打包的時間,決定了這個區塊可以打包多少用戶發送的交易(給打包用戶發送的交易留了多長時間)。

Hint字段用來傳遞一些單獨的狀態,取決於選用的共識協議,在PoW中這個字段可能顯得沒必要要,而AEDPoS定義了一些區塊類型,如Normal Block,Extra Block,只更新少許共識信息的Tiny Block。這些,都須要反應在Hint中——共識合約不只須要告知區塊生產者多久之後能夠着手產生區塊,也須要告知他應該產生什麼類型的區塊,而不一樣區塊會更新不一樣的共識信息。除此以外,引入Hint字段也能爲實現其餘共識協議提供了更多的可能。

這個接口分別會在鏈剛剛啓動時、在本地Best分支上同步完一個新的區塊(不管這個區塊是否是本身產生的)時、區塊生產者在執行本身的區塊前的驗證中突然發現當前時間已經超出了本身的時間槽(即調用下文的ValidateConsensusBeforeExecution接口)後被調用。

調用以後,Consensus Service會將NextBlockMiningLeftMilliseconds傳入共識的調度器中,時間一到,就會去觸發生產區塊的邏輯。

注意,調度器中的時間是能夠隨時被覆蓋的。事實上,每一次同步一個新的區塊,調度器都會被從新初始化。

事關接口3,ACS4拆分出兩個接口:

rpc ValidateConsensusBeforeExecution (google.protobuf.BytesValue) returns (ValidationResult) {

option (aelf.is_view) = true;

}
rpc ValidateConsensusAfterExecution (google.protobuf.BytesValue) returns (ValidationResult) {

option (aelf.is_view) = true;

}
message ValidationResult {

bool Success = 1;
string Message = 2;

}
也就是說,AElf中,每個區塊執行先後,會分別調用以上兩個接口的實現對區塊頭進行驗證。驗證的邏輯位於實現ACS4的合約中,驗證的數據就不得不基於State DB。由於你不能憑空去驗證區塊頭裏的共識信息對不對,共識合約裏須要存儲最近的共識信息,才能給最近的共識信息提供驗證的支撐。

既然驗證的數據基於State DB,而ACS4的接口都是隻讀的方法,那就須要單獨生成一筆交易去更新State DB(區塊鏈的特性,更新WorldState或者State DB必須經過執行交易來完成)。

這樣,ACS4除了要提供生成區塊頭信息的方法以外,還須要可以返回一個(或者一組)可以更新State DB中的共識信息的交易。這個交易會做爲系統交易被生成,而後在打包過程當中,最早添加進區塊中。系統交易的執行會先於普通交易,這樣普通交易在執行時會獲取到最近更新的系統提供的信息,如hash-commit-reveal策略下的隨機數。在AElf中,每一個區塊會至少包含一個共識系統交易。

ACS4的最後兩個與更新共識信息相關的接口以下:

rpc GetInformationToUpdateConsensus (google.protobuf.BytesValue) returns (google.protobuf.BytesValue) {

option (aelf.is_view) = true;

}
rpc GenerateConsensusTransactions (google.protobuf.BytesValue) returns (TransactionList) {

option (aelf.is_view) = true;

}
message TransactionList {

repeated aelf.Transaction Transactions = 1;

}
在AElf的kernel模塊代碼中,GetInformationToUpdateConsensus會在生成區塊頭的過程當中被調用,該接口返回的數據會做爲區塊頭的Extra Data之一,用於收到區塊的人驗證共識信息。GenerateConsensusTransactions接口會在生成區塊頭以後,進一步生成系統交易的過程當中被調用。補充一句,ValidateConsensusAfterExecution接口本質上只是爲了驗證區塊頭中的共識信息和執行完共識系統交易後State DB中的共識信息的一致性,防止區塊生產者「出爾反爾」。

ACS4的完整代碼在這裏。關於對本文或者ACS4或者其餘AElf共識組件的建議都會被認真對待,歡迎留言、私信甚至直接去github開issue。

以上是AElf區塊鏈共識合約標準ACS4的大體介紹,下一篇文章會介紹其中最爲複雜的GetConsensusCommand接口在AEDPoS共識下的具體實現。

相關文章
相關標籤/搜索