以太坊基礎概念詳解

本文不講區塊鏈,也就意味着你有一些區塊鏈的基本認知。
主要講解以太坊中的一些基本元素,如:區塊、帳戶、狀態、交易、費用等。因這些概念之間相互緊密聯繫,雖描述的時候儘可能分出層級,但提醒看官看得時候能夠先後翻閱。算法

對以太坊的解剖按從總體到局部的思路進行:數據庫

一、以太坊

以太坊能夠用幾句話道出其本質:小程序

以太坊是一個基於交易的狀態機。安全

全球就這一臺單機(但分佈存在),【系統狀態】不停的改變。系統狀態是一個術語,即後面講到的world state。網絡

這臺單機主要由區塊鏈組成,區塊鏈上保存着狀態和交易。數據結構

當咱們與以太坊交互時,其實就是在執行交易、改變系統狀態。函數

用一個簡潔優美的公式表示就是:區塊鏈

σ′ =Υ(σ,T)

Υ是狀態轉換函數,T是交易,σ是狀態,σ′轉換後的狀態。ui

借用一張圖吧編碼

圖片描述

從創世區塊開始,無盡的交易不斷的刷新着系統當前狀態,每產生一個區塊就對當前狀態作一次快照(patricia trie根)存入區塊頭中。

patricia trie是merkle tree的變體,請自行了解merkle tree。

二、區塊結構

再看一個公式

B≡ (B H,B T,B U)

意思是區塊恆等於(區塊頭,交易列表,叔塊)

因此,區塊是由三大部分組成:
區塊頭,叔塊,交易列表。請看圖:
圖片描述

1)區塊頭由15個字段組成。
2)叔塊其實就是孤塊,因以太坊出塊速度很快平均十幾秒就會打包生成一個塊,因此礦工挖礦的競爭性很高,可能同時產出幾個都合法的區塊,以太坊爲了一些安全性起見,容許競爭塊也掛在到主鏈上,同時給與挖出這些孤塊的礦工們少量獎勵增長工做的公平性。這些孤塊最多容許6個高度,這也是6個區塊確認主鏈說法的來源。
3)交易列表,存儲的是本區塊中全部的交易內容。

圖中的公式後面說。

看一下一個實際的區塊信息:

"blocks" : [
            {
                "blockHeader" : {
                    "bloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
                    "coinbase" : "0x3535353535353535353535353535353535353535",
                    "difficulty" : "0x020000",
                    "extraData" : "",
                    "gasLimit" : "0x05f5e100",
                    "gasUsed" : "0x014fa1",
                    "hash" : "0x39f4659b079e257df8fd7e699528531e97a6b8a442ca0d11200c4a2f7433c483",
                    "mixHash" : "0x7379f33af4ae2db7e293f808a165135d0b1a99572cc96fb9f7d17ef64a751969",
                    "nonce" : "0x8e08d7aabeee8773",
                    "number" : "0x01",
                    "parentHash" : "0xadbef3bf0b3b7b14f6e7b1a45d240ecc863543a279a86c23f60170e8e7a6bcc3",
                    "receiptTrie" : "0xb21660268480338c0cd0613358315359b619bd527d5850949c4863cddaec316b",
                    "stateRoot" : "0xde4ce9b5b2f88ab1680962c64281224b1743bdf94bd6a9e390ea779ff616c1f7",
                    "timestamp" : "0x03e8",
                    "transactionsTrie" : "0x56445ba866f3e41851154fb8700dcec8556a178f1833021e030b8a47b494769d",
                    "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
                },
                "rlp" : "0xf90308f901f9a0adbef3bf0b3b7b14f6e7b1a45d240ecc863543a279a86c23f60170e8e7a6bcc3a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347943535353535353535353535353535353535353535a0de4ce9b5b2f88ab1680962c64281224b1743bdf94bd6a9e390ea779ff616c1f7a056445ba866f3e41851154fb8700dcec8556a178f1833021e030b8a47b494769da0b21660268480338c0cd0613358315359b619bd527d5850949c4863cddaec316bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018405f5e10083014fa18203e880a07379f33af4ae2db7e293f808a165135d0b1a99572cc96fb9f7d17ef64a751969888e08d7aabeee8773f90108f90105460183030d4094c305c901078781c232a2a521c2af7980f8385ee980b8a430c8d1da000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000001ba021a28cc82b40931239f8653ffa5300e1a506c0ef7fb79a663772cafe6558ab44a075af23441f7f176a2770af41142c77b671391209b15d59144e7a1332179b5e14c0",
                "transactions" : [
                    {
                        "data" : "0x30c8d1da000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
                        "gasLimit" : "0x030d40",
                        "gasPrice" : "0x01",
                        "nonce" : "0x46",
                        "r" : "0x21a28cc82b40931239f8653ffa5300e1a506c0ef7fb79a663772cafe6558ab44",
                        "s" : "0x75af23441f7f176a2770af41142c77b671391209b15d59144e7a1332179b5e14",
                        "to" : "0xc305c901078781c232a2a521c2af7980f8385ee9",
                        "v" : "0x1b",
                        "value" : "0x00"
                    }
                ],
                "uncleHeaders" : [
                ]
            }
        ]

三、區塊頭

區塊頭包含15個字段,介紹以下:

type Header struct {
        ParentHash  common.Hash    //Hp,上一區塊所有內容的hash,區塊因它而成鏈!
        UncleHash   common.Hash    //Ho,本區塊的ommers(全部叔塊)列表的hash
        Coinbase    common.Address //Hc,成功挖出本區塊的礦工地址,用於接收礦工費
        Root        common.Hash    //Hr,本區塊全部交易的狀態tree的根hash
        TxHash      common.Hash    //Ht,本區塊全部交易tree的根hash
        ReceiptHash common.Hash    //He,本區塊全部交易的收據的tree的根hash
        Bloom       Bloom          //Hb,交易收據日誌組成的Bloom過濾器 
        Difficulty  *big.Int       //Hd,本區塊難度級別
        Number      *big.Int       //Hi,區塊序號,從創世塊0遞增
        GasLimit    uint64         //Hl,每一個區塊當前的gas limit
        GasUsed     uint64         //Hg,本區塊交易消耗的總gas
        Time        *big.Int       //Hs,本區塊建立時的Unix時間戳
        Extra       []byte         //Hx,區塊附加數據,<=32字節
        MixDigest   common.Hash    //Hm,256位的hash,與nonce組合證實出塊執行了足夠的計算
        Nonce       BlockNonce     //Hn,64位的hash,與MixDigest組合證實出塊執行了足夠的計算
}

首先,ParentHash是上一個區塊所有內容的hash值,下一個區塊老是包含上一個區塊所有內容的hash值,這就使得區塊成鏈。

再次,有三個特別的字段保存的是patricia trie的根,Root(狀態hash)、TxHash(交易列表hash)、ReceiptHash(收據列表hash)。這個Root就是系統狀態hash。系統狀態就是以太坊整個網絡中全部帳戶的狀態,就是world state,它是一個merkle patricia trie結構。這個樹(包括全部patricia trie)並不存在於區塊,而存在於節點的levelDB中。只有它的根hash存在於區塊頭Root中,每個區塊頭裏的Root都是區塊被挖出確認時的快照,而world state指如今全部帳戶的狀態。

圖片描述

world state是跨塊存在的,另外兩棵樹只存儲本區塊的交易和收據。

四、world state

再說一下world state:
world state是一顆全局狀態樹,在以太坊裏只有一個,它被持續地更新。
這棵樹包含了以太坊網絡裏每個帳戶的key/value映射。
因此它表示的是整個以太坊系統全部帳戶當前的狀態。

其摺疊函數是:

L S(σ) ≡ {p(a) : σ[a]≠ ∅}

意味着非空p(a)的集合,p(a)就是patrcia 葉子節點的內容:

p(a) ≡ (KEC(a), RLP((σ[a]n, σ[a]b, σ[a]s, σ[a]c)))

這表示一個葉子節點是一個key/value映射,key是KEC(a)即160位的帳戶地址的哈希(Keccak-256算法),value是帳戶(nonce、balance、storageRoot、codeHash)的RLP格式序列化字節。

五、帳戶

以太坊中有兩種帳戶
一、外部擁有帳戶(EOA),通常指天然人擁有的帳戶。
二、合約帳戶(CA),爲智能合約分配的帳戶。

看一下帳戶的源碼定義:

type Account struct {
    Nonce    uint64      // σ[a]n ,若爲EOA是發送的交易序號,如爲CA是合約建立的序號。
    Balance  *big.Int    // σ[a]b ,這個地址的餘額。
     //merkle root of the storage trie
    Root     common.Hash // σ[a]s ,帳戶自身內容RPL編碼組成的Merkle Trie的根哈希
    CodeHash []byte      // σ[a]c ,帳戶綁定的EVM Code,帳戶一經建立不可修改。
}
  • EOA特徵
    codeHash爲空
    storageRoot爲空
    經過私鑰控制
    發起交易(轉移以太幣或觸發合約代碼)
  • CA特徵
    不能發起交易,能夠被觸發執行合約代碼(經過EOA發起的交易或者從其餘CA接收的消息調用激活)

怎麼判斷一個帳戶是空帳戶?

EMPTY(σ,a)≡ σ[a]c =KEC(()) ∧ σ[a]n =0 ∧ σ[a]b =0

從公式看,一個帳戶的Root爲空且nonce爲0且餘額爲0,則說明這是一個空帳戶。

六、交易

再回顧一個公式

σ′ =Υ(σ,T)

以太坊是一個基於交易的狀態機。
任意兩個帳戶之間的交易都會引發world state的改變。
兩個相鄰區塊之間的狀態差異很小,patricia trie這種數據結構能高效的處理整個系統帳戶變化的部分。

交易基本定義:【從外部擁有帳戶】發送的加密簽名序列化指令。換句話說交易必須是從EOA發起的才能叫交易,CA之間的通訊叫消息也有叫內部交易的,如今是有區別,之後這個區別會不會模糊化不知道。

交易類型有兩種:
一、消息調用(Td
二、合約建立(Ti

圖片描述

從EOA到EOA的交易僅是轉帳。
EOA到CA能夠激活各類操做。

看交易的源碼定義:

type txdata struct {
    AccountNonce uint64          //Tn
    Price        *big.Int        //Tp
    GasLimit     uint64          //Tg
    Recipient    *common.Address //Tt
    Amount       *big.Int        //Tv
    Payload      []byte          //Td || Ti 
    V *big.Int
    R *big.Int
    S *big.Int
    // This is only used when marshaling to JSON.
    Hash *common.Hash
}

Tn必須等於發起交易的帳戶的nonce(翻閱前面說法可知,帳戶nonce是該帳戶發起的第幾筆交易的序號,若是是建立合約則表明第幾回建立合約的序號)
Tp是這筆交易消耗的gas單價
Tg是你願意爲這筆交易最多能夠支付的上限
Tt是接收帳戶的地址,若是爲空說明接受帳戶是一個CA,不然是EOA
Tv是到接收者的額度
Td或Ti,若是交易類型是消息調用則Palload寫爲Td,表示輸入數據,例如消息的參數,假設有一個註冊域名的合約服務,則Td就是該服務須要的參數如IP等。若是交易類型是建立合約,則Payload寫爲Ti,表示一段代碼,這段代碼用於建立合約帳戶,這段初始化代碼只會被執行一次就丟棄掉,第二次執行的是建立完的合約代碼體。

交易的公式:
圖片描述

能夠看到當接收帳戶不一樣時,區別僅僅是Td和Ti的區別。

另外,一個區塊裏交易的順序由裝配這個區塊的礦工決定。

七、費用

以太坊網絡裏任何計算都要支付gas(燃料),
思考爲何不直接用eth作費用?
答案是用兩個概念gas和eth區別價值和價格,gas是一種固定衡量的價值,而eth是市場上快速變化的價格,不少EVM(以太坊虛擬機)的操做指令都須要消耗固定的費用就用gas來計價,gas的最小單位是wei,1eth = 1018wei = 109gwei。因此eth和gas之間是有匯率的。

GasPrice:燃料單價
GasLimit:願意支付的燃料上限

GasLimit × GasPrice = 願意支付的最大費用
10000 × 100gwei = 1015wei = 0.001eth

圖片描述

這圖要說明的是:
一筆交易中,你設置的最大費用若是沒有消耗完,多出的會返回給你。若是最大費用不夠計算的花費,那麼交易會終止、已改變的狀態會回滾、可是錢被消耗不會退回了。這些已消耗的費用都獎勵給礦工了。

計算都是有費用的,初次以外還有一些東西須要繳費:

費用的三種不一樣構成:
1)計算操做的固定費用
2)交易(合約建立或消息調用)費用
3)存儲(內存、存儲帳戶合約數據)費用

着重說一下存儲費用:
存儲收費是由於假如你的合約使得狀態數據庫存儲增大,全部節點都會增長存儲。
以太幣是鼓勵儘可能保持少許存儲的。
可是若是有操做是清除一個存儲條目,這個操做的費用不但會被免除,並且因爲釋放空間還會得到退款。

總結

以上就是以太坊裏的一些基礎元素,沒有講到複雜的交易執行、EVM等,後續再寫。

下面是一個區塊鏈小程序,供你們參考:
圖片描述

相關文章
相關標籤/搜索