最近一直在研究區塊鏈,算是從之前據說過,到如今大概瞭解一些。先說下本身學習過程當中的感覺,那就是「幹!能不能把話說明白些。」大部分學習材料都存在結構混亂,或者對一個點單薄,沒法深刻淺出。至於那些還在拿着露天麥喊什麼是區塊鏈,錯事後悔一生的,都是騙子。html
我相信如今不少投資機構都在瞄區塊鏈,今年,即便AI也沒有區塊鏈這麼火爆。那麼對於一個區塊鏈項目,到底靠不靠譜,是在畫餅,仍是真的可能搞成,全部人都應該擦亮眼睛。算法
談區塊鏈最好先拋開各類幣的價格,價格這種事你懂的,貴和便宜根本不是人能控制的。可是基於區塊鏈技術去作項目,倒是實實在在能夠可持續發展。因此,瞭解區塊鏈技術比炒幣來的實在。數據庫
「區塊鏈」三個字並不能闡明這項技術的所有,若是要非要用能夠完整表達的命名,我以爲應該叫「Peer-to-Peer Encrypted Non-Tampered Database」,即「點對點的加密化不可篡改數據庫」。編程
它不一個數據庫(好比MySQL,MongoDB),也不是一類數據庫(好比SQL,NoSQL),它是一種數據庫架構,它在數據庫自己的技術上還上升了一層,考慮到數據的可靠性如何保證,以及數據庫服務如何不下線。所以,你不能把它跟普通的某個有名字數據庫拿來類比,甚至,你能夠在某一個具體的區塊鏈實現時,使用其餘的數據庫來幫助存儲和檢索數據。服務器
在咱們普通的數據庫中,不管是關係型仍是非關係型,咱們的不一樣記錄之間可能存在關係,也可能不存在關係,但在區塊鏈中,一條數據必定和另一條數據存在聯繫,即便在現實的業務邏輯上沒有聯繫,可是它老是存在於鏈上,沒法脫離鏈而存在,總有一條路徑從一個數據出發到達另一個數據,不信往下讀。網絡
「區塊」表達了區塊鏈裏面數據關係的最終呈現形式,一條記錄,不管它是什麼信息,最終它(或它的檢索信息)都要被放置在一個區塊中。而區塊與區塊之間,是一個「鏈表」的數據關係,會編程的人都知道什麼是鏈表,就是後一個數據中存在指向前一個數據的索引鍵。所以,區塊鏈上的任何兩個數據永遠能夠經過這些索引鍵最終連在一塊兒,數據沒法逃離這個邏輯。數據結構
可是「區塊鏈」這三個字沒法闡述這樣的數據結構和普通數據庫結構之間的不一樣,由於上面描述的的這種鏈表數據結構,用普通的數據庫也能夠構建出來,只要你想要的話。架構
真正的價值在於,區塊鏈用密碼學的原理,現有的加密技術,把這些索引關係進行了層層加密,以致於在保存的數據中,這些索引鍵並無那麼明顯,而是須要經過各類計算才能獲得。好比區塊在保存一堆交易信息時,採用了merkle樹的方式進行保存,父節點是兩個子節點的double hash獲得的結果,而merkle算法確保了交易信息不能被篡改。編程語言
咱們這裏還不須要知道具體的加密都有什麼用,咱們須要瞭解的是,區塊鏈裏面處處是加密,這是一個顯著的特色。學習
區塊鏈上的數據是不可篡改的,你們都這樣說。但其實,數據是能夠改的,只是說改了之後就你本身認,並且被修改數據所在區塊以後的全部區塊都會失效。區塊鏈網絡有一個同步邏輯,整個區塊鏈網絡老是保持全部節點使用最長的鏈,那麼你修改完以後,一聯網同步,修改的東西又會被覆蓋。這是不可篡改的一個方面。
更有意思的是,區塊鏈經過加密校驗,保證了數據存取須要通過嚴格的驗證,而這些驗證幾乎又是不可僞造的,因此也很難篡改。加密並不表明不可篡改,但不可篡改是經過加密以及經濟學原理搭配實現的。這還有點玄學的味道,一個純技術實現的東西,還要靠理論來維持。但事實就是這樣。這就是傳說中的挖礦。
挖礦過程實際上是礦工爭取建立一個區塊的過程,一旦挖到礦,也就表明這個礦工有資格建立新區塊。怎麼算挖到礦呢?經過一系列複雜的加密算法,從0開始到∞,找到一個知足難度的hash值,獲得這個值,就是挖到礦。這個算法過程被稱爲「共識機制」,也就是經過什麼形式來決定誰擁有記帳權,共識機制有不少種,區塊鏈採用哪一種共識機制最佳,徹底是由區塊鏈的實際目的結合經濟學道理來選擇。
挖完礦沒完,拿比特幣來講,接下來礦工要把被廣播到網絡中的交易打包到這個區塊裏,一筆交易是否是合法的呢?發起這筆交易的人是否是僞造了一筆交易?要確保一筆交易的合法性,必須從已經存在的前面的區塊裏面去找到這筆交易的來源的真實性,而如何驗證交易真實性呢?在前面的區塊裏,保存着交易來源的merkle root hash,只要找出這個交易所在的區塊,再作一次merkle校驗,就能夠斷定交易是不是合法的。獲得merkle root hash是經過區塊內的全部交易不斷加密獲得的,所以,只要交易是假的,就得不到這個merkle root hash。加密在這裏又幫助實現了數據的可靠性。
除了這些,區塊鏈裏面的加密比比皆是,這些加密規則和算法,使得整個區塊鏈遵循一種規律,讓篡改數據的成本特別高,以致於參與的人對篡改數據都沒有興趣,甚至忌憚。這又是玄學的地方。
若是區塊鏈沒有p2p網絡,僅僅是按照前面的描述,有加密體系,有鏈式特徵,而後運行在某一臺(組)服務器上,按照咱們如今中心化的模式運行,看上去也挺好玩的。可是發明者想玩的更大些,加密體系讓數據不可篡改,可是我直接拋顆原子彈把你機房炸掉,不是不可篡改,是直接玩兒完了。
爲了防止被原子彈炸掉機房,發明者設計了點對點的網絡(客戶端和客戶端直接通訊,不通過某一臺特定的服務器)到區塊鏈裏面。簡單說就是在這個點對點網絡裏面,全部人的電腦裏保管着如出一轍的一個數據結構(其實就是一個完整的「區塊」「鏈」),他們相互經過網絡鏈接,進行同步,當礦工建立了新的區塊,其餘人就會把這個區塊同步到本身保管的數據結構中。所以,不管這個網絡上哪個節點被炸,其餘節點都還活着,新加入的小夥伴就能夠從這些節點裏同步數據到本身的電腦。想要讓區塊鏈數據消失,那把地球炸了吧。
而這種加入點對點網絡的設計,就叫「去中心化」,只要網絡上還有一個節點活着,區塊鏈的數據就不會消失。
更讓政客們懼怕的是,這些保存的數據,節點上的用戶能夠隨便看,無所謂,徹底公開。節點用戶既然把數據同步過來了,你就能夠隨便用,就是你的數據了,想怎麼用就怎麼用。試想一下,哪天淘寶說我要把本身的數據區塊鏈化……目不忍視……
前面僅僅闡述的是區塊鏈之因此是區塊鏈的基礎。本節要講的是,如今已經有區塊鏈在你面前了,咱們須要去剖析區塊鏈裏面所使用的具體技術點或架構。
前面已經提到區塊了。那麼到底什麼是區塊呢?區塊是區塊鏈的主要數據存儲結構,一個區塊包含區塊頭和區塊體兩個部分。而區塊頭則是區塊的重頭戲。
區塊鏈中的一個區塊結構示意圖(注:漏掉了version信息)
對於一個區塊而言,它就是一個特殊的數據結構。它的區塊頭包含了一些固定信息:版本(客戶端版本,每次升級客戶端軟件,這個信息就會不同),塊高度(其實就是表示這是鏈中的第幾個區塊),塊哈希(這個區塊的hash值,是挖礦獲得的),上一個塊的塊哈希(這個字段是重點中的重點,是造成鏈表結構的關鍵),時間戳(區塊建立時間),難度和Nonce(這兩個字段和挖礦有關,後文講挖礦的時候詳細講),merkle root(區塊體的merkle根hash值,後文會簡單介紹merkle樹,詳細會在其餘文章講)。除了這些字段,若是作一個本身的區塊鏈,還能夠添加一些其餘信息到區塊頭中。
區塊體是保存具體內容的位置,在比特幣的區塊鏈中,區塊體保存的是一段時間的交易信息。在其餘區塊鏈中,這裏可不必定保存的是交易信息,多是其餘信息,總之區塊體是保存該區塊鏈用來作什麼業務的具體業務信息。
在部分區塊鏈實現中,一個區塊還能夠有區塊尾,用來保存一些區塊建立結束以後的信息,這些信息多是區塊頭和區塊體已經建立完之後,附加上去的,好比區塊的長度、容量等信息。
這就是一個區塊。而一個區塊頭中的previousHash字段,保存的是上一個區塊的hash值,所以,經過這個區塊就知道了上一個區塊是哪一個,上一個區塊又能知道上上個區塊,直到能夠追溯回整個鏈條的第一個區塊。這就是區塊鏈。
區塊是如何構成鏈的的示意圖
就像上圖同樣,後面一個區塊老是指向前一個區塊。一旦一個區塊生成,而且後面有區塊指向它,那它就不能被修改,由於一旦修改,全部的hash都須要從新計算。可是咱們知道,hash算法的特色是,想要獲得這個hash必須用原始內容進行一遍hash算法,因此,若是給的內容和原始內容不一樣,是得不到這個hash的,因此,中間某個區塊鏈被修改而獲得的hash,不可能被後面的區塊指向,區塊鏈就會斷掉。斷掉的區塊鏈加入到網絡中,要麼不被承認,別的節點不會把你看成合法節點,要麼你要再同步一遍,從網絡中從新複製最長的鏈到你的本機覆蓋原來的鏈。
可是你可能會有兩個疑問:1.這個blockHash又不是內容的hash,怎麼確保區塊體內的信息不被修改呢?要是我不改blockHash,只改內容,那不是能夠瞞天過海?2.若是有兩個區塊同時指向了一個區塊,而這兩個區塊的區塊體不同,這該怎麼辦?
第一個問題,咱們須要經過後面的挖礦和merkle tree兩部分結合,知道這個原理。第二個問題,實際上,這種狀況很是常見,挖礦成功的機率實際上是100%,關鍵在於哪一位礦工先挖到礦,通常當礦工挖到礦以後,會向全網廣播,其餘沒有挖到礦的礦工就會中止。可是因爲網絡延時等狀況,可能在短期內多個礦工一塊兒挖到礦,他們都建立了新的區塊,而且廣播到了網絡中。這種狀況叫「分叉」。
當分叉發生的時候,有兩種辦法。但都是順其天然,不人工干預。後面挖新塊的礦工,會本身決定把哪個分支最後的塊做爲本身的前一個塊。若是在比較短的塊數內,一條鏈明顯長於另一條鏈,那麼長的鏈會被保留,短的會被拋棄,挖短鏈的礦工算是白乾了一場。全部的網絡節點在同步的時候,都會選擇當前最長的鏈進行同步,後面挖礦的礦工建立新塊的時候也是選擇最長的鏈。
可是還有一種狀況,就是短鏈的礦工不依不饒,或者短期內兩條鏈沒法分出勝負,甚至最後每條鏈都有了不少塊跟在後面。一幫人的轉帳總不能有兩個帳單吧,若是兩個帳單最後發現還不同就麻煩了。因此遇到這種狀況,礦工們會決定分家。也就是一個區塊鏈變成了兩個鏈,其中一條鏈把前面的全部鏈複製出來,成爲獨立的鏈,今後這兩條鏈再無瓜葛,雖然前面的區塊都是一摸同樣的,可是後面井水不犯河水。這種狀況叫「硬分叉」,BitCoin Cash就是這樣誕生的。新產生的鏈繼承了前面的區塊,可是後面的區塊徹底是挖這條鏈的礦工決定的。硬分叉的好處是,對於原來的用戶而言,忽然之間,本身的一份資產變成了兩份😂
至於區塊體,真的是根據區塊鏈應用的業務需求來設計。好比比特幣,就被設計爲交易模型,全部區塊體裏面的交易記錄放在一塊兒,就是一個長長的帳單,每一分錢的前因後果寫的一清二楚,若是當初紅十字會用區塊鏈來捐款,那就不會有那麼大的風波。可是其餘區塊鏈應用不必定是交易模型,好比用於記錄醫療信息的區塊鏈,用於記錄用戶位置的區塊鏈……因此,對於區塊鏈技術自己而言,點到這裏即止,再往下說就是比特幣特有的技術了。
前面已經屢次說了挖礦。簡單說挖礦過程就是一堆礦工在搶建立一個新區塊的權利的過程。在加密貨幣的世界裏,搶到這個權利,就會在這個區塊的最前面加上一筆轉帳給本身的交易,而這個交易的錢是憑空而來的,因此又叫「挖礦獎勵」,並且數額還很多,因此礦工才擠破腦殼搶這一個記帳權。可是在其餘非幣區塊鏈應用裏,假如沒有這個獎勵,怎麼激勵礦工挖礦呢?這也是區塊鏈領域裏一個玄而又玄的話題,至今沒有答案。
那麼挖礦挖礦,究竟是怎麼一個技術上的算法過程呢?
在礦機程序裏,規定了如何獲得一個hash,而這個規定,就被稱爲共識機制,全部礦工按照這個共識機制去進行某個算法,看誰先獲得一個符合條件的結果,而這個結果又能夠被垂手可得的驗證是符合條件的(驗證是否符合共識機制)。不一樣的區塊鏈,共識機制不一樣,目前比較知名的是PoW和PoS,以及在這二者基礎上衍生出來的其餘共識機制。
爲了可以把挖礦過程講清楚,咱們只拿比特幣遵循的PoW來進行演示。
SHA256(SHA256(version + prevHash + merkleRoot + time + currentDifficulty + nonce )) < TARGET
礦機執行上面公式,只要知足上面這個公式(執行結果爲真),就算挖到礦。如今對這個公式進行解釋。
currentDifficulty = diff_1_target/TARGET
這個公式裏面的diff_1_target能夠認爲是一個常量,在比特幣客戶端裏面是不變的,值爲0x1d00ffff。固然,其實它也有可能變,但怎麼變都差很少這個值,咱們仍是把它看成常量。而TARGET咱們在下面會講到。這就算比特幣的挖礦,礦工們天天看着本身的機器,反覆不斷的執行這個公式,尋找那個nonce,日復一日,年復一年。
當礦機找到nonce以後,就奪得了記帳權,就能夠把內存中的交易信息調出來,打包到區塊體中。而merkle root是經過交易記錄計算獲得的,因此不可能礦工在打包時又去作手腳,一旦他僞造了某一條交易,打包進區塊體的交易就不能獲得他挖礦時使用的那個merkle root,也就沒法獲得挖礦時找到的那個hash。
固然了,實際上比特幣挖礦可能還要麻煩一些,好比說還有nonce溢出、礦池……
前面說了好屢次Merkle,它究竟是什麼?Merkle Tree是一種數據結構,比特幣裏面就是一棵二叉樹,也就是每一個父節點有兩個子節點那種。我以前寫過一篇文章《區塊鏈如何運用merkle tree驗證交易真實性》裏面詳細講了一些Merkle Tree的原理以及問題。這裏主要仍是作一個科普,不深刻講。
區塊頭裏面的Merkle Root是怎麼來的呢?它是經過對區塊體內的記錄作Merkle算法獲得的。以比特幣爲例,一個區塊裏面包含n個交易,咱們把這些交易兩兩分組,每兩個一組,獲得n/2組,若是有單數,那麼最後一個交易複製一份湊數。先對每一個交易作hash提取,這樣就獲得來n個hash,而後對每組的hash作double hash運算:
parentHash = sha256(sha256( hash1 + hash2 ))
也就是把這個組裏的兩個hash連起來,再計算獲得一個新hash,這個新hash就算這兩個hash的父節點。獲得全部組的父節點以後,按照一樣的邏輯,獲得父父節點,如此一直下去,最後獲得一個根節點,這個根節點就是merkle root。
merkle算法大體是這樣,但它不只限於區塊鏈領域,在其餘任何驗證領域均可能用到,並且也不必定是這裏講的必須兩個獲得一個的算法,也能夠是任意個獲得一個的算法,總之merkle是一種對多個記錄進行運算獲得一個根hash的算法。
而能夠想象,對參與算法的任何一個交易作小小的改動,都會致使獲得的merkle root不同,因此區塊裏面只須要保存merkle root就能夠了。這就算密碼學的力量。
區塊鏈數據的特徵主要有兩點:1.公開透明,任何節點對數據有徹底的權利去查看;2.難以僞造或篡改。所以,區塊鏈很是適合兩類場景:1.證據;2.監督。若是區塊鏈上的信息獲得法律承認,那麼但凡拿出區塊鏈上的證據,侵權方將百口莫辯。而試想,若是將稅收徹底遷移到區塊鏈,每一個公民的每一筆稅收,最後都用到哪裏,一清二楚,這多是令某些人懼怕的點。
但區塊鏈有兩大缺點:1.要挖礦,還有分叉風險,也就是說一個數據放到區塊鏈上,要等好久才能成爲不可篡改的可信數據。2.分區塊,數據被割裂存放,這給查詢帶來巨大的麻煩,很是影響效率。因此,區塊鏈不適合那種即時性要求高的場景,不管是信息交換的即時性(例如聊天)仍是查詢的即時性(如搜索引擎)。
區塊鏈不是萬能的,某些服務明明中心化模式效率更高,成本更低,卻偏要爲了風口搞區塊鏈化,那隻能看韭菜長沒長齊。還有一點使人擔憂的是,因爲區塊鏈上信息的公開透明,並且不可刪除,是否會對我的隱私形成極大的損害,試想一下,當年給冠希哥修電腦的小哥經過區塊鏈網絡炫耀本身發現的照片……那對當事人的傷害……連人死了都不會消散……
隨着風口的來臨,區塊鏈應用此起彼伏。但目前比較成熟的,無非三種模式:1.比特幣;2.以太坊智能合約;3.比特股。其餘的,很少說,讀者本身看着辦。
一個區塊鏈應用,它的架構是怎樣的呢?在區塊鏈自己之上,還須要有哪些其餘的技術來支撐呢?
區塊鏈應用體系架構圖(邵奇峯等《區塊鏈技術:架構及進展》)
區塊鏈應用,如比特幣、以太坊,與區塊鏈自己有比較大的耦合度,也就是說區塊鏈做爲數據庫沒法較爲獨立的成爲應用中的一個模塊,和咱們如今流行的B/S架構稍有不一樣,區塊鏈應用中會把區塊鏈拆解以後,於應用其餘層進行融合,最終實現應用的總體功能。
咱們以比特幣爲例來說一個區塊鏈應用,比單純一個區塊鏈自己多了哪些部分。比特幣是一個基於區塊鏈的帳單系統,它除了區塊鏈,還要包含:1.交易模型;2.身份認證體系(相似PKI);3.智能合約。
交易模型就是區塊體內保存的交易記錄。之因此比特幣裏面的每一筆錢的前因後果都一清二楚,就是依賴於交易模型。咱們現實中銀行裏面的一個帳號,只會告訴你一個帳號如今有多少錢,曾經花了多少錢,收入多少錢,還欠多少錢。可是不會告訴你「某一筆你花掉的錢,來自你某一筆收入」。但比特幣裏面必須告訴你這樣的邏輯,一條交易包含「輸入」和「輸出」兩個部分,好比你要轉10BTC,那麼你的帳號必須有一個或多個「輸入」加起來總和等於或超過10BTC,而輸出就是指你要把這10BTC轉給誰。可是有一種狀況,當全部「輸入」加起來爲10.5BTC時怎麼辦,就像你有100塊毛爺爺,去買70塊的東西同樣,須要「找零」。因此「輸出」有的時候會有一個是轉給本身的,就是「找零」。
比特幣交易輸入與輸出示意圖
而實際上,輸出在另一個交易中,又是這個新交易的輸入。
在區塊體裏面,這些交易記錄,以及它們的輸入輸出都被如實記錄。除此以外,還要進行merkle計算,將merkle root存到區塊頭中。
既然是交易,那麼必然涉及到交易雙方的身份。比特幣交易的兩端是兩個帳號,至於究竟是誰它無論,但它經過加密算法,保證這一筆交易是哪個帳號發起的,發起交易的人要對交易信息進行簽名。
你可能聽過非對稱加密、公鑰和私鑰。比特幣帳號最關鍵的就是這個私鑰,一旦私鑰丟失,你就沒法證實本身是這個帳號的主人,也就沒法從帳號中進行轉帳要作的簽名動做,你就不能再花這個帳號裏面的幣,也就丟失了幣。
那麼簽名是怎樣的一個過程?怎麼證實這個交易是我發出的?怎麼證實這錢是轉給個人?
密鑰、地址與錢包
密鑰 一般指的是保護比特幣資產的對應於全部權用戶的私鑰,個別時候也會模糊的統稱私鑰和公鑰爲密鑰,這裏咱們以狹義的私鑰解釋爲準。
地址 比特幣的收款地址,大部分狀況下是指對公鑰的封裝(個別時候除了公鑰還有腳本)。
錢包 一種比特幣客戶端軟件,是私鑰的容器,一般經過有序文件或者簡單的數據庫實現。比特幣錢包包含私鑰和公鑰數據,儘管公鑰數據理論是是不須要存儲的。
通常來講,用戶的公鑰和比特幣地址能夠劃等號,但實際上不是。比特幣地址是一串比公鑰短不少的字符串,主要是爲了方便輸入。而公鑰則用於各類非對稱加密。
比特幣公鑰到比特幣地址
公鑰和地址都是公開在比特幣網絡中的,只有私鑰是用戶本身保存,不能給任何人。當一個交易發起時,交易發起方用「本身的私鑰」和「接收方公鑰」對交易進行簽名,那麼網絡中的其餘人就能夠用發起人的公鑰去驗證這個交易是否是他發起的,對於接收方而言,要提供本身的私鑰進行解密運算,來證實這個交易確實是發送給本身的。而比特幣客戶端(錢包)就是幹這個加密解密和簽名的事。
比特幣自己已經有智能合約的雛形,只是它所採用的編程語言腳本能力比較弱,能實現的合約邏輯不復雜。以太坊則是在這個基礎上擴展鏈智能合約部分,使智能合約的編程能力大大加強。
在上文提到的輸入和輸出,輸出其實就被做爲另一個新交易的輸入。比特幣的輸出不僅僅是告訴系統要轉給哪一個地址多少錢,輸出其實是一段比特幣腳本。這段腳本也通過複雜的非對稱加密,要運行這段,想要獲得一個輸出裏面的錢,把這筆錢做爲本身交易的輸入,必須用本身的私鑰先解密腳本,而後運行腳本,腳本運行完,這筆錢就能夠做爲本身交易的輸入了。結合前面的知識,只有擁有對應的私鑰才能解密,因此,只有輸出記錄對應的比特幣地址對應的那個用戶才能解密腳本,獲得這些錢。
在這個過程裏面,「腳本」是一個關鍵,除了上面這種最簡單的轉帳邏輯,還能夠經過一些條件判斷來實現稍微複雜一些的編程,好比只有當知足某些條件的時候,解密後的腳本才能運行。因而,基於這種設計,比特幣的腳本系統能夠用來實現多重簽名、保證合同等功能,也就是智能合約的雛形。
對於區塊鏈的研究,我也是剛剛開始,一定有很多地方沒有理解透,有些地方也有誤解。但對於想要了解這個領域的朋友,但願大家先了解區塊鏈背後的技術原理(沒必要對技術細節掌握透徹),讀一些比較成熟的可信的材料(我一不當心發現前人已經在《計算機學報》上發表相似綜述的文章了,讀者能夠閱讀《區塊鏈技術:架構及進展》),而不是道聽途說就信覺得真。一旦你掌握了這些技術原理,就會發現,其實它的限制挺多,有美好的地方,也有不必的地方,那些莫名奇妙的項目就坑不到你了。
原文載於個人博客:http://www.tangshuang.net/4133.html 若是後期又發現一些錯誤,會在個人博客去更新,因此請關注個人博客。