賬本
1. 概述
賬本是hyperchain平台中的重要模塊,負責區塊鏈賬本數據的維護與組織。賬本數據可以分成兩部分:
- 區塊鏈數據
- 賬戶數據
其中,區塊鏈數據包括:區塊、交易、回執等數據。這部分也就是我們傳統意義上所說的區塊鏈。而后者指代的是區塊鏈上所有賬戶狀態的集合,該狀態集統稱為世界狀態。由於需要支持智能合約,因此hyperchain與以太坊一樣,摒棄了比特幣的UTXO模型而采用賬戶模型來組織數據,因而這部分數據稱為賬戶數據。
區塊鏈數據主要通過區塊的形式進行串聯。所有區塊被從后向前有序地鏈接在一個鏈條里,每一個區塊都指向其父區塊。區塊中包含了一批交易,由共識模塊負責統一打包並定序。區塊鏈節點在接收到一個區塊之后,在原有的賬戶狀態基礎上,依次執行交易,在此期間讀/寫相關賬戶的狀態數據。一筆交易執行結束,也就意味着區塊鏈狀態進行了一次變遷。
每一筆交易,在hyperchain中都會有一個對應的交易回執或者非法交易記錄來表示最終的執行結果。倘若這筆交易是一筆合法的交易,則執行結束后,會將該交易執行的結果記錄在交易回執中。反之,會將錯誤原因記錄在一條非法交易記錄中。
2. 區塊鏈數據
在本章中,將介紹以下幾種數據結構之間的關系:
- 區塊
- 交易
- 回執
- 區塊鏈
- 非法交易記錄
其中前兩類數據結構在區塊鏈網路中組成了“區塊鏈數據“,是區塊鏈網絡中進行流轉的“共識”數據;后三類數據結構由各節點維護在本地。以上五種數據結構組成了一個節點中所有的區塊鏈數據。
區塊
區塊結構可以分成兩部分:
- 區塊頭信息
- 區塊體信息
區塊頭中主要包含一些區塊鏈的元數據,包括:
- 區塊高度
- 區塊哈希
- 父區塊哈希
- 賬戶狀態哈希
- 交易集哈希
- 回執集哈希
- 時間戳
- 日志過濾數據
區塊體內包含所有的交易數據。
區塊的主要作用是封裝交易數據,記錄區塊鏈狀態數據。
交易
交易是由外部用戶發起的,在交易體中記錄了用戶指定的調用信息。
交易根據是否執行智能合約可以分為兩類:
- 普通交易:交易執行過程中不觸發智能合約的運行
- 合約交易:交易執行過程中會觸發智能合約的運行,又可以分為:合約部署交易和合約調用交易
交易體包含如下字段:
- 版本號:指明該交易數據結構定義的版本信息,便於向后兼容
- 交易發起者:長度為20字節的交易發起者的標識信息
- 交易接收者:長度為20字節的交易接收者的標識信息,若本交易是合約調用交易,該字段為被調合約的地址,若該字段為空,則表明本交易為部署合約交易
- 調用信息:若本交易為普通交易,在調用信息中指定需要轉賬的token數量;若本交易為合約調用交易,在調用信息中指定需要調用的函數以及調用參數;若本交易為合約部署交易,則需要在調用信息中指定合約的二進制代碼
- 隨機值:uint64的隨機值(避免產生哈希相同的交易,防止重放攻擊)
- 交易簽名:用戶利用自己的私鑰對交易發起者、交易接收者、調用信息、時間戳、隨機值五個字段的內容進行簽名,產生的簽名內容填在該字段,防止交易的內容被篡改
- 交易哈希:將上述五個字段加上交易簽名一起進行哈希計算,獲得一個哈希標識用於表示本交易
回執
每一筆合法的交易,其執行結果都會被封裝成一個交易回執存儲在區塊鏈上。交易回執包括:
- 版本號:指明該回執數據結構定義的版本信息,便於向后兼容
- 交易哈希:與該回執相關的交易哈希
- 合約地址:若該交易為部署合約交易,則新部署的合約地址被放置在該字段,否則該字段為空
- 執行結果:若該交易為調用合約交易,則執行結果被放置在該字段,否則該字段為空
- 虛擬機日志:智能合約運行過程中,可能會產生一系列日志,這些日志數據被放置在該字段中
- 智能合約類型:用於表示智能合約的類型,EVM,JVM或是其他類型
區塊鏈
一個本地的節點會維護一些區塊鏈元數據以便用戶進行查詢,因此在hyperchain中,有個名為chain的數據結構,記錄了這些數據,包括:
- 最新父區塊哈希
- 最新區塊哈希
- 最新區塊高度
- 創世區塊高度(默認為0,數據歸檔/數據恢復等操作會影響該高度的值)
- 交易總數
- 額外數據
非法交易記錄
每一筆非法的交易,其錯誤信息會被封裝成一個非法交易記錄,存儲在節點本地。
除了與之相關的交易數據,非法記錄中還會記載具體的錯誤原因,例如:
- 余額不足
- 合約調用參數錯誤
- 調用權限不夠等
共識比較
區塊鏈節點在執行完一個區塊中所有的交易后,需要將本次區塊處理得到的“結果”在節點間進行比較,只有大多數節點(超過quorum個)擁有與之相同的結果時,才會將本次執行結果提交到數據庫中。
而表示本區塊執行結果的標識是由以下幾個內容組成:
- 世界狀態哈希:交易執行過程中會更改賬戶狀態數據,當一個區塊中所有的交易執行結束后,會利用bucket tree對賬戶集合狀態進行哈希重計算,計算結果便是世界狀態哈希
- 交易集哈希:利用區塊中每一筆交易的*重要字段*作為sha256算法的輸入,計算得到一個用於表示整個交易集的哈希標識。重要字段為:交易發起者、交易接收者、調用信息、時間戳、隨機值
- 回執集哈希:利用區塊中每一個回執的*重要字段*作為sha256算法的輸入,計算得到一個用於表示整個回執集的哈希標識。重要字段為:虛擬機執行計數器、執行結果、虛擬機執行日志
3. 賬戶數據
之前提及的區塊鏈數據,其實可以總結為是合約調用信息的流水集合。而智能合約在運行過程中,需要讀/寫合約狀態數據。接下來就介紹這部分數據的組織結構。
由於hyperchain需要兼容EVM(Ethereum Virtual Machine),而EVM與以太坊的賬戶體系有着較強的耦合性,因此,hyperchain的state是在以太坊的基礎上,做了一系列的改造及優化得到。
賬戶類別
與以太坊一樣,hyperchain中的賬戶也可以分為兩類:
- 外部賬戶:外部賬戶的私鑰由用戶自己控制,可以主動發起交易,且這類賬戶不包含智能合約代碼
- 合約賬戶:合約賬戶包含一段可執行的智能合約代碼,且有自己的存儲空間用來存儲自身的狀態變量。該智能合約的運行可以由外部賬戶發起交易進行觸發,也可以由其他合約“主動調用”進行觸發
雖然兩類賬戶在邏輯上有所區別,但是共享一套定義:
一個賬戶的元數據包括以下字段:
- 賬戶地址(20字節,由哈希函數根據一定的輸入產生,不考慮哈希沖突的情況下,不會有兩個相同地址的賬戶)
- 余額:該余額表示該賬戶所擁有的hyperchain平台的token個數,這類token可以通過智能合約進行操控,也可以通過發起普通交易轉賬進行交易
- 狀態變量(存儲空間)哈希標識:一個合約賬戶,需要存儲其所有的狀態變量,一個用於表示這些狀態變量的哈希值被存儲在該字段
- 合約代碼哈希:智能合約代碼哈希標識
- 狀態:合約狀態,普通、凍結等
- 部署時間:若該賬戶為合約賬戶,則會記錄該賬戶第一次被部署的時間點
- 創建者地址:若該賬戶為合約賬戶,則會記錄該賬戶的創建者信息
- 已部署的合約地址列表:若該賬戶為外部賬戶,則會記錄該賬戶部署的所有合約賬戶的地址
除了以上這些”簡短”的數據被放置在賬戶元數據里,還有合約源碼、狀態變量這些需要大量存儲空間的數據被直接存儲,在元數據中只存儲這類數據的哈希值。
帳戶集
hyperchain將每一個賬戶的元數據進行序列化,將序列化得到的二進制作為一個賬戶的內容。
所有的賬戶數據,最終可以轉換成一系列的kv對,key為該賬戶的地址,value為元數據序列化的內容。
對於賬戶集,會有一棵全局級別的bucket tree進行賬戶數據的哈希計算。每個賬戶數據僅作為bucket tree中的一條數據項,不斷進行哈希計算,最終生成一個根節點,該節點的哈希值(merkle root)便是整個賬戶集的哈希標識。
該哈希值作為整個賬戶集的狀態表示,不僅是共識階段比較的依據之一,之后更是會被記錄在區塊頭中。