2.1 區塊鏈1.0——數字加密貨幣
以前我們常說的web1.0、web2.0、移動互聯網等概念,那么區塊鏈1.0,區塊鏈2.0乃至區塊鏈3.0又是什么呢?區塊鏈1.0是數字加密貨幣。

上圖是數字加密貨幣的結構,從整體來看,一個區塊鏈系統分為節點后臺和前端兩大部分,前端包含多種表現形式,比如錢包、命令行接口、區塊鏈瀏覽器、圖形化界面開發工具等。
我們接觸得比較多的就是各種各樣的錢包,錢包的主要作用是保管賬戶或者說保管私鑰,在交易的時候進行簽名,發送交易驗證等。
節點后臺包含著系統最核心的功能,包括共識機制、鄰節點的管理、區塊鏈管理、交易驗證、內存管理、腳本引擎等。節點可以安裝在各式各樣的計算機或設備中,專門用來挖礦的設備叫礦機。
2.2 區塊鏈2.0 可編程區塊鏈
接下來一起看看區塊鏈2.0。區塊鏈2.0是創建去中心化的程序、自治組織和智能合約的一個系統。
和1.0不同的是2.0提供了一個平臺,可以在平臺上搭建應用。最大的代表是以太坊,提供了各種模塊,讓用戶可以在其基礎上搭建應用,這個應用本質上就是智能合約。
除了構建貨幣體系之外,智能合約可以用來做股票債券期貨貸款產權智能財產等功能。智能合約的核心是利用程序算法替代人去執行合同,這些合同需要自動化的資產過程。合約包含三個基本要素:要約、承諾和價值交換。智能合約有效定義了新的應用形式,使得區塊鏈從最初的貨幣體系拓展到金融以及其他行業的應用。

如圖,我們來看看2.0的內部結構,和1.0相比,2.0也是分為前端應用和后臺節點兩大部分。前端應用大同小異,不同的是,在區塊鏈2.0中有一個智能合約開發工具,這個開發工具是一個基于web的應用,它在智能合約的開發中被廣泛使用。
節點后臺最大的變化也是加入了智能合約這一模塊以及EVM虛擬機。EVM是用來執行智能合約的虛擬機,它類似于Java的虛擬機,可以執行智能合約編譯后的字節碼。
以太坊目前支持三種編程語言:solidity、serpent、LLL。Solidity比較主流,除了金融類的應用,solidity還被廣泛應用在游戲的表現上,比如去年流行的加密貓就是用solidity開發的。
除此以外,以太坊還加入了數據庫模塊,數據庫模塊是存儲以太坊的事件狀態的,以太坊的區塊并不存儲所有的交易信息,而只存交易的哈希值。關于以太坊的存儲結構,我們會在后面的章節中詳細介紹。
2.3 區塊鏈3.0 區塊鏈在金融行業之外的各行業的應用場景
上面介紹了區塊鏈1.0和區塊鏈2.0的特征,那么區塊鏈3.0是什么呢?
區塊鏈3.0:區塊鏈3.0是指區塊鏈在金融行業之外的各行業的應用場景。能夠滿足更加復雜的商業邏輯。區塊鏈3.0被稱為互聯網技術之后的新一代技術創新,足以推動更大的產業改革。
2.4 什么是以太坊
以太坊的概念首次在2013至2014年間由程序員Vitalik Buterin,受比特幣啟發后提出,大意為“下一代加密貨幣與去中心化應用平臺”,在2014年通過ICO眾籌開始得以發展。
與其它區塊鏈一樣,以太坊需要幾千人在自己的計算機上運行一個軟件,為該網絡提供動力。網絡中的每個節點(計算機)運行一個叫做以太坊虛擬機(EVM)的軟件。將以太坊虛擬機想象成一個操作系統,它能理解并執行通過以太坊特定編程語言編寫的軟件。由以太坊虛擬機執行的軟件/應用程序被稱為“智能合約”。
要在這一世界計算機上做任何事都需付費。不過,付的不是美元或英鎊等普通貨幣,而是該網絡自帶的加密貨幣,叫做以太幣。以太幣與比特幣大致相同,除了一點,即以太幣可以為在以太坊上執行智能合約而付費。
可以換個方式來理解,就像現在的云計算一樣,比如我們要做虛擬機需要付費,以太坊可以理解成另外一種形式的云,我們在它上面跑自己的應用或服務業需要用它自己的貨幣來支付費用。

以太坊不像比特幣那樣只是一種加密貨幣,它還存在其它特征,使其成為了一個巨大的分布式計算機。但是,它運行起來極其緩慢——比如今的普通計算機的運行速度緩慢約5至100倍——而且成本很高。那么為什么這個看起來不怎么樣的計算機系統能火遍全球呢?
在以太坊上,無論是人還是智能合約都可作為用戶。人類用戶能做的事,智能合約也能做,而且還遠不止如此。以太坊提供了一個內部的圖靈完備的腳本語言以供用戶來構建任何可以精確定義的智能合約或交易類型。想建立一個全規模的守護程序(Daemon)或天網(Skynet),你可能需要幾千個聯鎖合約并且確定慷慨地喂養它們,一切皆有可能。
2.5智能合約
那什么是智能合約呢?
想象一下,我們倆關于明天的天氣打個賭。我賭明天天晴,你賭明天下雨。我們約定輸家必須給贏家100美元。我們如何打這個賭,還要確保輸家會履行諾言呢?我能想出以下三種不同方法:
最簡單的方法是互相信任。如果我們已經是老朋友了,很容易信任對方。我知道你的家庭住址而你知道我的黑歷史。然而,如果我們是陌生人的話,那就難辦多了。你沒理由信任我,我也沒理由信任你。
另一個可行的方法是根據我們之間的賭約制定一份法定合同。我們雙方會簽署一份詳細規定了賭約條款的合同——包括關于輸家違約的規定。該合同會讓我們有向贏家支付賭金的法律義務,卻不具實用性。因為如果通過法律途徑強迫對方履行合同,其代價高出賭金本身。
我們可以找一個雙方都信任的共同朋友,各交100美元在他/她那里保管。第二天,他/她會查看天氣情況,將這200美元都交給贏家。這種方式簡單明了,除非出現一種情況:要是這位朋友卷款而逃該怎么辦呢?

以太坊的智能合約在這種情況下就可以派上用場了。智能合約就像是尋求共同朋友的幫助,不過是被編寫成了代碼。通過以太坊,我們可以編寫一款軟件,向兩方各收取價值100美元的以太幣。第二天打開接入天氣應用的API查看天氣情況,并將總價值為200美元的以太幣轉給贏家。因為區塊鏈的特性,智能合約一旦完成,無論如何都無法被編輯或修改。因此,可以肯定的是不管合約中有何規定,無論如何都會被執行。
2.6 智能合約的原理

本質上來說,智能合約也是一條以太坊交易。不管智能合約于何時執行,它都記錄了在區塊上執行的交易的信息。上圖描述了以太坊的交易,它分為幾個字段:時間戳、發送方、接收方、賬戶發送的金額、data。在這里發送方就是調用者,接收方是智能合約的地址,data就是智能合約要調用的內容,也就是俗稱的API,DATA字段,賦予了以太坊獨特的能力,用于創建記錄和執行智能合約。
通常來說以太坊的交易分為三種:
第一種是人類用戶之間的互相轉賬,如下圖所示,這個時候 Data字段是沒有內容的,發送者和接收者都是人類。

第二種是無接收方的以太幣轉賬。在進行沒有接收方的交易時,這就意味著該交易的目的是在網絡中利用“數據”項的內容創建一個智能合約。“數據”項中包含軟件代碼,該代碼會像網絡中的其它用戶一樣進行操作。

第三種是用戶和智能合約之間的以太幣轉賬。無論用戶(或智能合約)何時想要執行智能合約,他/她/它需要與智能合約進行一次交易,將執行指令置于“數據”項中。

2.6.1 以太坊的賬戶
在以太坊中有兩種賬號共享地址空間:外部賬號和合約賬號。外部賬號是由公鑰和私鑰控制的(如人),合約賬號是由賬號存儲的代碼所控制。
無論賬戶類型是什么都存在這四個組成部分:Nonce、Balance、StorageRoot、CodeHash。
外部賬號的地址是由公鑰決定的,而合約地址是在智能合約被創建的時候決定的(這個地址由創建者的地址和發送方發送過來的交易數字衍生而來,這個數字通常被叫做“nonce”)不管是否賬號存有代碼(合約賬號存儲了代碼,而外部賬號沒有),對于EVM來說這兩種賬號是相等的。每一個賬號都有持久化存儲一個key和value長度都為256位字的鍵值對,被稱為“storage”。而且,在以太坊中,每個賬號都有一個余額(確切的是用“Wei”來作為基本單位),該余額可以被發送方發送過來帶有以太幣的交易所更改。
2.6.2 交易
交易的本質是一個賬戶和另一個賬戶之間的信息交換,它包含了二進制數據(也就是消費數據)和以太數據。如果目標賬號包含了代碼,這個代碼一旦被執行,那么它的消費數據就會作為一個輸入數據。如果目標賬號是一個0賬號(地址為0的賬號),交易會生成一個新的合約。


上圖中紅框的內容就是一個新的合約所編譯出來的字符串。
這個合約的地址不為0,但是是來源于發送方,之后這個賬號的交易數據會被發送。這個合約消費會被編譯為EVM的二進制代碼,并執行。這次的執行會被作為這個合約的代碼持久化。這就是說:為了創建一個合約,你不需要發送真正的代碼到這個合約上,事實上是代碼的返回作為合約代碼。
2.6.3 Gas
以太坊上的每筆進行一筆交易都會被收取一定數量的Gas.這是為了限制交易的數量,同時對每一筆交易的進行支付額外費用。當EVM執行一個交易,交易發起方就會根據定義的規則消耗對應的Gas。交易的創造者定義了的Gas 價格。所以交易發起方每次需要支付 gas_price * gas 。如果有gas在執行后有剩余,會以同樣的方法返回給交易發起方。如果gas在任何時候消耗完,out-of-gas 異常會被拋出,那當前的這邊交易所執行的后的狀態全部會被回滾到初始狀態。
這是一個保護機制,用來保護以太坊不會受到惡意攻擊,讓整個網絡中一些惡意的程序無法進行。這里又可以看出區塊鏈是用經濟模型的方式,或者說用經濟的方式來限制黑客攻擊的。黑客并不是不能用技術手段來進行惡意攻擊,但是他要付出的代價成本遠大于獲得的價值。
2.6.4 以太坊虛擬機的內存結構
以太坊每個賬號都有持久化的內存空間叫做存儲. 存儲是一個key和value長度都為256位的key-value鍵值對。從一個合約里列舉存儲是不大可能的。讀取存儲里的內容是需要一定的代價的,修改storage里的內容代價則會更大。一個合約只能讀取或是修改自己的存儲內容。
以太坊的第二內存區域叫做主存。系統會為每個消息的調用分配一個新的,被清空的主存空間。主存是線性并且以字節粒度尋址。讀的粒度為32字節(256位),寫可以是1個字節(8位)或是32個字節(256字節)。當訪問一個字(256位)內存時,主存會按照字的大小來擴展。主存擴展時候,消耗Gas也必須要支付,主存的開銷會隨著其增長而增大(指數增長)。
EVM不是一個基于寄存器,而是基于棧的。所以所有的計算都是在棧中執行。最大的size為1024個元素,每個元素為256位的字。棧的訪問限于頂端,按照如下方式:允許拷貝最上面的16個元素中的一個到棧頂或是棧頂和它下面的16個元素中的一個進行交換。所有其他操作會從棧中取出兩個(有可能是1個,多個,取決于操作)元素,把操作結果在放回棧中。當然也有可能把棧中元素放入到存儲或是主存中,但是不可能在沒有移除上層元素的時候,隨意訪問下層元素。
2.6.5 指令集
為了避免錯誤的實現而導致的一致性問題,EVM的指令集保留最小集合。所有的指令操作都是基于256位的字。包含有常用的算術,位操作,邏輯操作和比較操作。條件跳轉或是非條件跳轉都是允許的。而且合約可以訪問當前區塊的相關屬性比如編號和時間戳。
2.6.6 消息調用
合約可以通過消息調用來實現調用其他合約或是發送以太幣到非合約賬號。消息調用和交易類似,他們都有一個源,一個目標,數據負載,以太幣,gas和返回的數據。事實上,每個交易都包含有一個頂層消息調用,這個頂層消息可以依次創建更多的消息調用。
一個合約可以定義內部消息調用需要消耗多少gas,多少gas需要被保留。如果在內部消息調用中出現out-of-gas異常,合約會被通知,會在棧里用一個錯誤值來標記。這種情況只是這次調用的gas被消耗完。在Solidity,這種情況下調用合約會引起一個人為異常,這種異常會拋出棧的信息。
上面提到,調用合約會被分配到一個新的,并且是清空的主存,并能訪問調用的負載。調用負載時被稱為calldata的一個獨立區域。調用結束后,返回一個存儲在調用主存空間里的數據。這個存儲空間是被調用者預先分配好的。調用限制的深度為1024.對于更加復雜的操作,我們更傾向于使用循環而不是遞歸。
2.6.7 代理調用/ 代碼調用和庫
存在一種特殊的消息調用,叫做代理調用。除了目標地址的代碼在調用方的上下文中被執行,而且msg.sender和msg.value不會改變他們的值,其他都和消息調用一樣。這就意味著合約可以在運行時動態的加載其他地址的代碼。存儲,當前地址,余額都和調用合約有關系。只有代碼是從被調用方中獲取。這就使得我們可以在Solidity中使用庫。比如為了實現復雜的數據結構,可重用的代碼可以應用于合約存儲中。
2.6.8日志
我們可以把數據存儲在一個特殊索引的數據結構中。這個結構映射到區塊層面的各個地方。為了實現這個事件,在Solidity把這個特性稱為日志。合約在被創建出來后是不可以訪問日志數據的。但是他們可以從區塊鏈外面有效的訪問這些數據。因為日志的部分數據是存儲在bloom filters上。我們可以用有效并且安全加密的方式來查詢這些數據。即使不用下載整個區塊鏈數據(輕客戶端)也能找到這些日志。
2.6.9創建
合約可以通過特殊的指令來創建其他合約。這些創建調用指令和普通的消息調用唯一區別是:負載數據被執行,結果作為代碼被存儲,調用者在棧里收到了新合約的地址。
2.6.10 自毀
從區塊鏈中移除代碼的唯一方法是合約在它的地址上執行了selfdestruct操作。這個賬號下剩余的以太幣會發送給指定的目標,存儲和代碼從棧中刪除。