以太坊基礎原理學習

一個朋友說,沒有研究過代碼,你怎麼能算了解區塊鏈?

我當時的心情是這樣的:F***,轉產品後,代碼數年沒碰過了。

轉念一想,如果沒有去看代碼,去看本質,如何能夠提出自己的需求?如何去思考更深入的應用?如何去提自己的需求做一條符合自己要求的鏈?

我打算花一周的時間,基於以太坊仔細研究下。以太坊,確實是目前看來比較好的一個平台了,雖然也有很多問題,但是確實比較興奮。重新看代碼肯定不可能了,只能站在巨人的肩膀上,希望能夠窺視到一些東西!


1.區塊瀏覽器

目前整體情況如下:

瀏覽器上面查看產線上最新的一筆交易:

Height:t< Prev 4896777 Next >n TimeStamp:t1 min ago (Jan-12-2018 03:43:47 PM +UTC)n Transactions:t246 transactions and 14 contract internal transactions in this blockn Hash:t0x43e69979a11aec5bdcdec5e8021b7b8d73f4d6c5ed40a36ab59e760f01670a5dn Parent Hash:t0xe9d552d54266947fdb5312eea9dcd824143cb10b57d2c45f96e35b4e2fcb28d3n Sha3Uncles:t0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347n Mined By:t0xea674fdde714fd979de3edf0f56aa9716b898ec8 (Ethermine) in 25 secsn Difficulty:t2,079,662,402,903,195n Total Difficulty:t2,040,977,597,418,315,199,265n Size:t33907 bytesn Gas Used:t7,999,312 (99.99%)n Gas Limit:t8,000,029n Nonce:t0x88e1f88e08244ea0bdn Block Reward:t3.224291759561512113 Ether (3 + 0.224291759561512113)n Uncles Reward:t0n Extra Data:tethermine-asia4 (Hex:0x65746865726d696e652d6173696134)n

後一個區塊:

Height:t< Prev 4896778 Next >n TimeStamp:t22 hrs 16 mins ago (Jan-12-2018 03:44:09 PM +UTC)n Transactions:t232 transactions and 10 contract internal transactions in this blockn Hash:t0x58733dcef5a28f2f8de2b40bd3bfd5e4e5894a18aff20f50023eefc2b02cd32bn Parent Hash:t0x43e69979a11aec5bdcdec5e8021b7b8d73f4d6c5ed40a36ab59e760f01670a5dn Sha3Uncles:t0x8d0cb901e561c36a7773047c465215f8e8f85bb66a90a34059a059e66285d3d3n Mined By:t0xea674fdde714fd979de3edf0f56aa9716b898ec8 (Ethermine) in 22 secsn Difficulty:t2,078,646,942,811,064n Total Difficulty:t2,040,979,676,065,258,010,329n Size:t34783 bytesn Gas Used:t7,985,961 (99.82%)n Gas Limit:t8,000,029n Nonce:t0x8815fe70a808f6df92n Block Reward:t3.62598404525173896 Ether (3 + 0.43848404525173896 + 0.1875)n Uncles Reward:t4.875 Ether (2 Uncles at Position 0, Position 1)n Extra Data:tethermine-eu10 (Hex:0x65746865726d696e652d65753130)n

Block Reward:t

3.62598404525173896 = 3(固定獎勵) + 0.43848404525173896(GAS開銷) + 0.1875(包含叔塊獎勵)

以太坊的具體獎勵,查看:以太坊(Ethereum ETH)的獎勵機制

我們看某一筆交易的:

TxHash:0x200c793d4cdba862d09ce1af1a869349e6a8f1ee7c2cd4f1fd64d9f238bbbf3a nTxReceipt Status:SuccessnBlock Height:4902096 (2 block confirmations)nTimeStamp:1 min ago (Jan-13-2018 02:58:20 PM +UTC)nFrom:0x8403105fd5c8ae3a57130b8c0e7e05740706474fnTo:0xde98e1af057dc8e973b09b63fe5055ca2b6f9380 nValue: 1.4612 Ether ($1,975.45) nGas Limit: 21000 nGas Used By Txn: 21000 nGas Price: 0.00000002 Ether (20 Gwei) nActual Tx Cost/Fee: 0.00042 Ether ($0.57) nCumulative Gas Used: 7871616 nNonce: 80n

當前GAS的價格是0.00000002 Ether.


2.原理摘錄

在Ethereum 代碼里,所有用到的哈希值,都使用該Hash類型,長度為32bytes,即256 bits;Ethereum 中所有跟帳號(Account)相關的信息,比如交易轉帳的轉出帳號(地址)和轉入帳號(地址),都會用該Address類型表示,長度20bytes。

Gas, 是Ethereum里對所有活動進行消耗資源計量的單位。這裡的活動是泛化的概念,包括但不限於:轉帳,合約的創建,合約指令的執行,執行中內存的擴展等等。

Ether, 是Ethereum世界中使用的數字貨幣,也就是常說的以太幣。如果某個帳號,Address A想要發起一個交易,比如一次簡單的轉帳,即向 Address B 發送一筆金額H,那麼Address A 本身擁有的Ether,除了轉帳的數額H之外,還要有額外一筆金額用以支付交易所耗費的Gas。

如果可以實現Gas和Ether之間的換算,那麼Ethereum系統里所有的活動,都可以用Ether來計量。

上面說明了GAS/Ether的關係。

區塊(Block)是Ethereum的核心結構體之一,是交易的集合!

包括以下:

AccountNonce :發送者的發起的交易總數量

price:單位Gas消耗所折抵的Ether多少

GasLimit:該tx執行過程中所允許消耗資源的總上限,解決惡意佔據資源的問題

Recipient:轉賬轉入方地址

Amount:此次交易轉移的以太幣數量

Payload:數據成員,用於合約的數據

轉出方地址是加密保護的,沒有直接顯示。

交易的執行

Block 類型的基本目的之一,就是為了執行交易。狹義的交易可能僅僅是一筆轉帳,而廣義的交易同時還會支持許多其他的意圖。Ethereum 中採用的是廣義交易概念。按照其架構設計,交易的執行可大致分為內外兩層結構第一層是虛擬機外,包括執行前將Transaction類型轉化成Message,創建虛擬機(EVM)對象,計算一些Gas消耗,以及執行交易完畢後創建收據(Receipt)對象並返回等;第二層是虛擬機內,包括執行轉帳,和創建合約並執行合約的指令數組。

在一個Block的處理過程(即其所有tx的執行過程)中,GasPool 的值能夠告訴你,剩下還有多少Gas可以使用。在每一個tx執行過程中,Ethereum 還設計了償退(refund)環節,所償退的Gas數量也會加到這個GasPool里。

對一個Block的處理如下:

1.購買Gas。首先從交易的(轉帳)轉出方賬戶扣除一筆Ether,費用等於tx.data.GasLimit * tx.data.Price;同時 st.initialGas = st.gas = tx.data.GasLimit;然後(GasPool) gp -= st.gas。

2.計算tx的固有Gas消耗 - intrinsicGas。它分為兩個部分,每一個tx預設的消耗量,這個消耗量還因tx是否含有(轉帳)轉入方地址而略有不同;以及針對tx.data.Payload的Gas消耗,Payload類型是[]byte,關於它的固有消耗依賴於[]byte中非0位元組和0位元組的長度。最終,st.gas -= intrinsicGas

3.EVM執行。如果交易的(轉帳)轉入方地址(tx.data.Recipient)為空,調用EVM的Create()函數;否則,調用Call()函數。無論哪個函數返回後,更新st.gas。

計算本次執行交易的實際Gas消耗: requiredGas = st.initialGas - st.gas

4.償退Gas。它包括兩個部分:首先將剩餘st.gas 折算成Ether,歸還給交易的(轉帳)轉出方賬戶;然後,基於實際消耗量requiredGas,系統提供一定的補償,數量為refundGas。refundGas 所折算的Ether會被立即加在(轉帳)轉出方賬戶上,同時st.gas += refundGas,gp += st.gas,即剩餘的Gas加上系統補償的Gas,被一起歸併進GasPool,供之後的交易執行使用。

5.獎勵所屬區塊的挖掘者:系統給所屬區塊的作者,亦即挖掘者賬戶,增加一筆金額,數額等於 st.data,Price * (st.initialGas - st.gas)。注意,這裡的st.gas在步驟5中被加上了refundGas, 所以這筆獎勵金所對應的Gas,其數量小於該交易實際消耗量requiredGas。

關於簽名

Ethereum 中每個交易(transaction,tx)對象在被放進block時,都是經過數字簽名的,這樣可以在後續傳輸和處理中隨時驗證tx是否經過篡改。Ethereum 採用的數字簽名是橢圓曲線數字簽名演算法(Elliptic Cure Digital Signature Algorithm,ECDSA)。

關於EMV

每個交易(Transaction)帶有兩部分內容需要執行:1. 轉帳,由轉出方地址向轉入方地址轉帳一筆以太幣Ether; 2. 攜帶的[]byte類型成員變數Payload,其每一個byte都對應了一個單獨虛擬機指令。這些內容都是由EVM(Ethereum Virtual Machine)對象來完成的。EVM 結構體是Ethereum虛擬機機制的核心。

關於合約

合約(Contract)是EVM用來執行(虛擬機)指令的結構體。

合約包含的參數:

CallerAddress :調用地址

caller :轉出方地址

self :轉入方地址

Code:指令數組,其中每一個byte都對應於一個預定義的虛擬機指令

Input:數據數組,是指令所操作的數據集合

create()和call()用於創建合約並完成轉賬,call針對處理(轉帳)轉入方地址不為空的情況,create用於處理(轉帳)轉入方地址為空的情況,會創建一個。

已定義的operation,種類很豐富,包括:

算術運算:ADD,MUL,SUB,DIV,SDIV,MOD,SMOD,EXP...;

邏輯運算:LT,GT,EQ,ISZERO,AND,XOR,OR,NOT...;

業務功能:SHA3,ADDRESS,BALANCE,ORIGIN,CALLER,GASPRICE,LOG1,LOG2...等等

Ethereum的數據結構:

StateDB---交易和操作的結果

Block(head,body)

BlockChain

LevelDB

Merkle-PatriciaTrie(MPT)數據結構

Block

Block(區塊)是Ethereum的核心數據結構之一。所有賬戶的相關活動,以交易(Transaction)的格式存儲,每個Block有一個交易對象的列表;每個交易的執行結果,由一個Receipt對象與其包含的一組Log對象記錄;所有交易執行完後生成的Receipt列表,存儲在Block中(經過壓縮加密)。不同Block之間,通過前向指針ParentHash一個一個串聯起來成為一個單向鏈表,BlockChain 結構體管理著這個鏈表。

Block結構體基本可分為Header和Body兩個部分

Header是Block的核心,包含以下參數:

ParentHash:指向父區塊(parentBlock)的指針。除了創世塊(Genesis Block)外,每個區塊有且只有一個父區塊。

Coinbase:挖掘出這個區塊的作者地址。在每次執行交易時系統會給與一定補償的Ether,這筆金額就是發給這個地址的。

UncleHash:Block結構體的成員uncles的RLP哈希值。uncles是一個Header數組,它的存在,頗具匠心。

Root:StateDB中的「state Trie」的根節點的RLP哈希值。Block中,每個賬戶以stateObject對象表示,賬戶以Address為唯一標示,其信息在相關交易(Transaction)的執行中被修改。所有賬戶對象可以逐個插入一個Merkle-PatricaTrie(MPT)結構里,形成「state Trie」。

TxHash: Block中 「tx Trie」的根節點的RLP哈希值。Block的成員變數transactions中所有的tx對象,被逐個插入一個MPT結構,形成「tx Trie」。

ReceiptHash:Block中的 "Receipt Trie」的根節點的RLP哈希值。Block的所有Transaction執行完後會生成一個Receipt數組,這個數組中的所有Receipt被逐個插入一個MPT結構中,形成"Receipt Trie"。

Bloom:Bloom過濾器(Filter),用來快速判斷一個參數Log對象是否存在於一組已知的Log集合中。

Difficulty:區塊的難度。Block的Difficulty由共識演算法基於parentBlock的Time和Difficulty計算得出,它會應用在區塊的『挖掘』階段。

Number:區塊的序號。Block的Number等於其父區塊Number +1。

Time:區塊「應該」被創建的時間。由共識演算法確定,一般來說,要麼等於parentBlock.Time + 10s,要麼等於當前系統時間。

GasLimit:區塊內所有Gas消耗的理論上限。該數值在區塊創建時設置,與父區塊有關。具體來說,根據父區塊的GasUsed同GasLimit * 2/3的大小關係來計算得出。

GasUsed:區塊內所有Transaction執行時所實際消耗的Gas總和。

Nonce:一個64bit的哈希數,它被應用在區塊的"挖掘"階段,並且在使用中會被修改

StateDB作為本地存儲模塊,它面向業務模型,又連接底層資料庫,內部利用兩極緩存機制來存儲和更新所有代表「賬戶」的stateObject對象。

stateObject除了管理著賬戶餘額等信息之外,也用了類似的兩級緩存機制來存儲和更新所有的State數據。

關於Uncle Block

Uncle區塊

以太坊為什麼要這麼設計呢?因為以太坊的區塊時間是20秒左右,相對於比特幣,更容易出現臨時分叉和孤兒區塊。而且較短的區塊時間,也使得區塊在整個網路中更難以充分傳播,尤其是對那些網速慢的礦工,這是一種極大的不公平。為了平衡各方利益,才設計了這樣一個叔塊機制。叔塊在全部挖掘出來的區塊中占的比例叫叔塊率,目前叔塊率在9.7%左右。

生產一個區塊

對於一個新區塊被挖掘出的過程,代碼實現上基本分為兩個環節:一是組裝出一個新區塊,這個區塊的數據基本完整,包括成員Header的部分屬性,以及交易列表txs,和叔區塊組uncles[],並且所有交易已經執行完畢,所有收據(Receipt)也已收集完畢,這部分主要由worker完成;二是填補該區塊剩餘的成員屬性,比如Header.Difficulty等,並完成授權,這些工作是由Agent調用<Engine>介面實現體,利用共識演算法來完成的。

環節一:

worker.update()分別監聽ChainHeadEvent,ChainSideEvent,TxPreEvent幾個事件

ChainHeadEvent:新的區塊已經挖好。準備下一個

ChainSideEvent:有Uncle塊產生,加入Uncle隊列

TxPreEvent:指的是一個新的交易tx被加入,沒有挖掘,則執行該tx

對於任何一個Ethereum網路中的節點來說,挖掘一個新區塊和從其他節點下載、同步一個新區塊,根本是相互衝突的。

環節二:

Ethash共識演算法-正式環境

Ethash演算法又被稱為Proof-of-Work(PoW),是基於運算能力的授權/封印過程。Ethash實現的Seal()函數,其基本原理可簡單表示成以下公式:

RAND(h, n) <= M / d

這裡M表示一個極大的數,比如2^256-1;d表示Header成員Difficulty。RAND()是一個概念函數,它代表了一系列複雜的運算,並最終產生一個類似隨機的數。這個函數包括兩個基本入參:h是Header的哈希值(Header.HashNoNonce()),n表示Header成員Nonce。整個關係式可以大致理解為,在最大不超過M的範圍內,以某個方式試圖找到一個數,如果這個數符合條件(<=M/d),那麼就認為Seal()成功。

我們可以先定性的驗證一個推論:d的大小對整個關係式的影響。假設h,n均不變,如果d變大,則M/d變小,那麼對於RAND()生成一個滿足該條件的數值,顯然其概率是下降的,即意味著難度將加大。考慮到以上變數的含義,當Header.Difficulty逐漸變大時,這個對應區塊被挖掘出的難度(恰為Difficulty本義)也在緩慢增大,挖掘所需時間也在增長,所以上述推論是合理的。

Clique共識演算法-測試環境

Clique演算法又稱Proof-of-Authortiy(PoA),它實現的Seal()其實是一個標準的數字簽名加密過程,可由下列公式表示:

n = F(pr, h)

其中F()是數字簽名函數,n是生成的數字簽名,pr是公鑰,h是被加密的內容。具體到Clique應用中,n是一個65 bytes長的字元串,pr是一個common.Address類型的(長度20 bytes)地址,h是一個common.Hash類型(32 bytes)的哈希值,而簽名演算法F(),目前採用的正是橢圓曲線數字簽名演算法(ECDSA)。

關於以太錢包

以太坊中代碼中,accounts.Manager是管理賬戶信息的模塊。Manager可以管理多個<Wallet>的實現,每個<Wallet>實現擁有多個Account賬戶,每個Account對應一個Address地址,而以太幣Ether存放於每個Address上。以太坊同時提供軟體版和硬體版的<Wallet>實現。

以太坊中,每個Address類型變數均來自於橢圓曲線數字簽名演算法(ECDSA)所用的公鑰,因此錢包程序還必須提供管理數字簽名公鑰密鑰的功能。軟體版accounts.<Wallet>實現叫keystore,通過在本地文件系統中分別顯式存儲賬戶信息和加密存儲公鑰密鑰的方式,提供以上功能。

以太坊客戶端程序之間,會通過accounts.Manager模塊相互訂閱Wallet更新事件,以保證每個客戶端個體(peer),都能及時更新全網路中的完整Wallet列表。

客戶端程序的核心是eth.Ethereum,它以RPC service的形式,向外提供內部各模塊的功能,諸如挖掘區塊, 資料庫讀寫,p2p下載等。

Key{}通過ecdsa.PrivateKey對象從而同時攜帶ECDSA所用的公鑰密鑰,所以這裡涉及到公鑰密鑰部分,都是針對Key對象做的操作。keystore機制中,在本地存儲的是經過加密的Key對象的JSON格式,所用的加密方法被稱為Web3 Secret Storage.

關於錢包

下載一個錢包,我選擇了本地網路,因為測試網路很難拿到測試Eth,所以只能本地挖礦了。

以太錢包的頁面

列舉下常用的功能:

  1. 創建賬戶,需要輸入密碼,產生一個賬戶地址
  2. 備份KeyStore文件
  3. 查詢賬戶餘額
  4. 發送交易
  5. 部署合約
  6. 發送數據,執行合約

參考資料:

1.teaspring的技術專欄 - CSDN博客 【侵刪】

2.Ethereum BlockChain Explorer and Search

3.The Ethereum Blockchain Explorer


推薦閱讀:

To Be A Product Manager | Day 64
1.6 產品經理的常用軟體

TAG:产品经理 | 区块链Blockchain |