[寫給程序員的]比特幣科普文

區塊鏈是目前技術熱點之一,有人將它與互聯網媲美,也有人聲稱區塊鏈沒有將來。肯定的是在大多數人對區塊鏈的理解仍停留在比特幣等加密數字貨幣概念的時候,已經有公司和我的嘗試將其應用於其它領域。若要對一個事物做出合理評價,較深刻的瞭解必不可少,而瞭解的較快方式是從某個具體應用入手。如今最知名和「成功」的區塊鏈應用仍然是與它一同誕生的比特幣,網上不乏有比特幣的科普文,可是本人看來,這些文章要麼寫得太抽象,要麼寫得太通俗,看完以後能獲得幾個概念,但若要深想下去仍是一頭霧水。本篇是以前爲公司培訓作的ppt整理而來,主要闡述了比特幣的核心概念,ppt面向公司全員,刪除程序員必備知識後整理成該博文。html

注:本文旨在幫助你們理解比特幣[&區塊鏈],因此會有意簡化一些概念,即不保證描述和實際場景徹底一致。關鍵點粗體顯示。程序員

區塊鏈 = 鏈成一串的區塊集合算法

這確定沒有異議吧,那麼區塊裏面包含什麼呢?暫時能夠認爲包含以下東東:api

重點關注散列值,它的身影貫穿區塊鏈始終。目前散列函數有不少種,以SHA256爲例,輸出有2256種可能(培訓時費了老大勁讓你們對這個數的大小有個感性的認識)。散列函數的特色是不可逆,即給定一個散列值,推算出對應的輸入基本上是不可能的。這種特性讓它有了防篡改的功能,好比區塊被廣播並被其它節點肯定後,若再去更改區塊裏的其它字段(好比交易的比特幣金額,存於數據字段中),會形成新數據計算獲得的散列值≠原散列值,那這個區塊必定是有問題的。咱們用這種方式保障了區塊的安全/合法性。安全

目前區塊鏈典型應用之一知識產權保護的關鍵就是防篡改和相關度計算。網絡

那麼數據自己的安全呢?衆所周知,[公共]區塊鏈是匿名的,那麼如何知道數據屬於誰,誰能存取該數據,這裏就引出了密鑰的概念。數據結構

密鑰:用於加密和解密的一種規則函數

根據加密密鑰和解密密鑰是否相同,又可分爲對稱加密和非對稱加密。各位對它們必定很是熟悉,它們在純粹加解密上的優缺點這裏就不細說了,在效率上,前者通常都要高於後者。所以咱們使用非對稱加密並不是衝它的加密效果去,而是爲了使用它「非對稱」這個特性帶來的好處,現實中有不少場景用到,好比調用第三方openapi,或者更復雜的oauth認證過程,調用方都會以私鑰簽名調用信息,服務方使用調用方的公鑰校驗調用者的合法性。這個特性使得匿名和去中心化成爲可能,一次比特幣的交易可以下圖所示:區塊鏈

XX將1000B打入Bob的帳戶(即用Bob公鑰加密),Bob私鑰解密後取出加密

公鑰不須要含有任何Bob的我的信息,因此雖然其餘人可使用公鑰將數據綁定到這個「帳戶」,但也僅此而已,他們沒法也無需知道這個公鑰究竟是屬於誰的(除非公鑰全部人本身公開我的信息);只要有人能將之解出,那就表示那人有對應的私鑰,亦即他的身份是合法的(若是他將私鑰給了別人,那也無話可說)。因而,一個匿名的交易就完成了。

固然,上述圖示是很是不嚴謹的。首先,比特幣網絡是個閉環,Bob沒法將比特幣取出(你見過比特幣長啥樣?),固然也沒法主動存入,這相似於咱們只能在ATM機上進行帳號間的轉帳操做,而不能取現;那Bob私鑰解密後的比特幣去哪了呢,或者說,原本這筆錢在「公鑰裏」呆的好好的,取又取不出,你把它解出來幹啥?答案是當Bob要將錢打入其餘人的公鑰的時候,他就要用私鑰轉帳了;而以前XX轉給Bob亦是如此。因此更準確的圖示以下:

比特幣的交易鏈

如今讓咱們看下比特幣中的加解密過程具體是怎樣的。

首先咱們把交易給它結構化,能夠簡單理解爲:交易 = 個人錢轉給你 = 個人錢 + 轉給你。

由上圖可知:個人錢 = 我用私鑰解出的別人轉到我公鑰的錢 = 別人轉給公鑰的錢 + 我用私鑰解出;轉給你 = 轉多少到你的公鑰。

翻譯成數據結構,示例以下:

    {
        from: {
            上一筆交易to數據的ID: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            key: 私鑰解密(用於證實我擁有上一筆交易轉出的錢)
        },
        to: {
            本筆輸出的ID: "8ae4538afc617cd284d36d135fe09f1a0d2f42a22d890d548f6f65cda45e6f1d2",
            轉出多少錢: 0.01500000,
            lock: 公鑰加密(只有正確解密才能得到轉出的錢)
        }
    }

咱們將上述代碼的key和lock稱爲腳本。lock和key可看做問題與答案,注意from中的key解密的是上一筆轉給個人交易的lock。好比XX轉了一筆錢給Bob,同時設置了lock:1+1=?——?是佔位符,以後用key代替——等到Bob要花這筆錢時,他必定要提供正確的key值(此處是2),不然沒法經過節點的交易校驗,同時Bob也要設置本筆交易的lock,以此類推。key與lock能夠互換,只要合在一塊兒等式成當即可。

將公私鑰代入腳本,可構建以下交易:

XX轉給Bob——

    {
        from: ……,
        to: {
            本筆輸出的ID: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            轉出多少錢: 10,
            lock: 轉入方的公鑰
        }
    }

Bob轉給Alice——

    {
        from: {
            上一筆交易to數據的ID: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            key: ? 解密 (私鑰加密(本次交易的散列值)後的密文)=本次交易的散列值
        },
        to: ……   
 }

節點校驗Bob轉給Alice這筆交易,會將上一筆交易lock與當前交易key合併,此處即爲:轉入方的公鑰解密 (私鑰加密(本次交易的散列值)後的密文)=本次交易的散列值。易得,若公私鑰是一對,那等式成立。

所謂節點,咱們能夠理解爲平常據說的比特幣礦工。他們無時無刻不在蒐集交易,並將它們打包進區塊,這個過程就是「挖礦」。挖礦 = 新建有效區塊,具體過程以下:

  1. 交易校驗無誤後,節點將其放入本地的「未確認交易池」;
  2. 節點選取部分或所有未確認交易(通常選取佣金相對高的交易,佣金=from的金額-to的金額,能夠本身找零調節,好比XX轉Bob10塊,Bob以此轉Alice8塊,轉本身即找零1.5塊,那麼佣金爲0.5塊),放入本地臨時區塊中;
  3. 計算該臨時區塊散列值。

如圖:

圖中上一個區塊的ID取的是區塊鏈中當前最末的有效區塊的ID。而計算獲得散列值是剎那間的事,若是交易數據足夠多,那每秒都能產生萬億個區塊,如此,則吞吐量槓槓的。可是億萬個區塊承載的數據未必相同(根據節點本身的選擇而來),更不用說有同筆交易被多個節點打包的狀況,爲了帳本的一致性,咱們須要避免鏈分支(分叉)的出現,能添加到鏈末尾的只能是其中一個區塊,即只能認可其中一個區塊是有效的。那麼如何選出這個區塊,並讓其餘節點心服口服呢,這就是共識算法須要解決的問題。

比特幣使用的共識算法是POW,proof of work,工做量證實。具體到實現,就是提升計算散列值這個環節的難度。怎麼提升呢?

中本聰說,你算出的散列值必定要符合某種的規則,好比必定要是「9ce4538afc617cd284d361d53fe09f1a0d2f42a26d890d548f6f65cda45e6f1d2」這個數,如此,你的區塊就是能夠被認可的。

此言一出,衆礦工紛紛吐槽:哇,中大神你懂不懂的,數據(交易)我都打包好了,出來的散列值還能變嗎?你說從新打包?選佣金低的試?求求你不要秀了。

中本聰說,行吧,給大家加個字段,該字段可隨意取數,汝等將其一併歸入散列值計算中,該字段的值的改變勢必會影響到散列結果,如此,只要找到正確的隨機數,那麼就能獲得規定的結果,那麼,區塊就能夠被認可。

now,挖礦變成了:新建有效區塊 = 計算出符合規則的散列值 = 得到一個使計算出的散列值符合規則的隨機數

規則爲:

咱們知道,2256是很大的一個數字, 要找到一個隨機數(爲了覆蓋整個輸出值域,該隨機數也得是同量級位數),使得結果剛好等於其中之一,以目前計算機能力,到時光盡頭也未必能找到。因此說,這個規則定義的難度太大。

那麼,咱們制定一個難度不大的規則,以下:

只要散列結果落入特定區間便可,這個難度的量化不言自明:若紅色區間佔滿整個橫條,那麼難度是最低的,即獲得的任意散列值都知足條件,也就是剛開始沒有規則的狀態;如若佔到一半,那麼機率上講每兩次都有一次會成功,難度也不大;若調節到億分之一,那麼機率上須要試錯一億次。也就是說,咱們能夠經過調節區間大小調節計算難度。比特幣目前是保持平均10分鐘出塊的速度,且會根據前幾回的出塊時間自動調節計算難度,而不至於因爲硬件發展等因素致使速度的變化。另外,隨機數字節數也不用很大,比特幣中是4個字節。

在挖礦時,nonce隨機數是未知的,要從0試到232,可是這個數字其實不大,只有4294967296,以如今的礦機動輒14T每秒的算力,所有算完到上限也不須要一秒,確定沒法覆蓋難度對應的散列值域。因此咱們須要使用創幣交易中的附帶信息,額外的字符串成爲extra nonce,參看 比特幣挖礦究竟在計算一個什麼問題?手動驗證區塊鏈給出答案。至於爲何是10分鐘,這個就見仁見智了,有人說考慮到網絡延時、帶寬,10分鐘是一個相對合適的時間,也有人以爲太長,好比LTC就是2.5分鐘。其實,這只是當初中本聰的一個設定,總要設置個時間嘛,只要不過短就行你說是不。

挖到礦後,節點須要將區塊入鏈。節點經過p2p向外廣播,其它節點收到後校驗區塊合法性,無誤後將該區塊存入本身的本地鏈,同時繼續向外廣播,並開啓下一輪挖礦競賽。經過p2p,全部節點的本地鏈均可以保持一致,這樣,去中心化就實現了。

值得討論的是,在新區塊發現到被網絡確認的時間段內,若是有多個節點同時找到有效的隨機數,或者節點收到其餘多個節點的挖礦成功的消息,以哪一個爲準呢?答案是隨意,由於通常來講這種臨時分叉的狀況會隨着後續區塊的挖掘自動消失,由於比特幣優先選擇鏈最長的那條分支,除非能保證各分支出塊的速率徹底同樣,不然總會出現必定的時間差,從而致使其中一條分支變得更長成爲主鏈,其他分支被網絡拋棄(也可能有惡意節點維持短分支,加大算力以圖在未來超過主鏈,這就涉及到51%攻擊了)。

康奈爾大學的研究人員Ittay Eyal和 Emin Gun Sirer發表的一篇論文裏,描述了只要掌握25%算力便可成功攻擊比特幣網絡的場景,可參看 Selfish Mining: A 25% Attack Against the Bitcoin Network

 

轉載請註明本文出處:http://www.javashuo.com/article/p-tgakxvwj-kw.html

相關文章
相關標籤/搜索