鏈客,專爲開發者而生,有問必答!python
此文章來自區塊鏈技術社區,未經容許拒絕轉載。git
bitcoin項目地址位於github倉庫,當前各類「幣」,基本都是從抄寫bitcoin代碼開始起步的。想要深度研究,從看源碼開始不可避免。github
P2P:電騾、迅雷、BT,在中國網絡影視的發展讓你們對P2P很熟悉,可能已經沒有人記得比特幣其實是第一批P2P的實踐者。全部交易記錄在全網經過P2P的方式廣播,每一個人都保存一份完整的交易記錄。因此也叫去中心化。算法
去中心化:bitcoin的去中心化是指的帳本去中心化,每一個人都擁有完整的交易記錄。所以不會出現人爲修改某一個帳本就致使財產丟失的狀況。
在這種模式下,想有效的修改之前的交易記錄,就須要有工做量證實(POW)。理論上修改以前的區塊必須作到51%的聯網機器都承認纔可能成功,而這確定是作不到的。
實際在整個比特幣系統的運行中,P2P的特色實際上仍是要有服務器系統負責支持維護,這是顯然的。
在比特幣軟件中,這個支持系統採用的是DNS Seed來獲取一部分對等節點列表,使用戶快速發現對等節點,這部分DNS地址被硬編碼在源碼中的,每一個新安裝的客戶端須要使用這些地址來工做:
vSeeds.emplace_back("seed.bitcoin.sipa.be", true); // Pieter Wuille, only supports x1, x5, x9, and xd vSeeds.emplace_back("dnsseed.bluematt.me", true); // Matt Corallo, only supports x9 vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org", false); // Luke Dashjr vSeeds.emplace_back("seed.bitcoinstats.com", true); // Christian Decker, supports x1 - xf vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch", true); // Jonas Schnelli, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.btc.petertodd.org", true); // Peter Todd, only supports x1, x5, x9, and xd
當客戶端已經工做過,而且緩存了對等的網絡節點地址以後,下次再次啓動,就不須要訪問這個地址了。每一個客戶端等於自帶了路由,這個時候就是真正的去中心化了。
DNS系統採用UDP方式工做,速度更快,也不容易受到DDOS攻擊。
去中心化的商業理念曾經很是火爆,也被認爲是比特幣的重點創新之處,不過最近業界基本已經認爲「去中心化」是個僞命題。由於全部提出去中心化的公司,實際都是爲了以此爲武器,打破大公司或者行業壟斷企業的獨佔優點。且不說是否可以成功,即使成功的話,新公司仍然是但願本身能夠獨佔和壟斷。因此你們實際想要的不是去中心化,而是本身能夠控制、別人不能控制的優點。數據庫
工做量證實:工做量證實(Proof Of Work,簡稱POW)。由於記帳的過程是分佈式的,每一個人均可能發生,這個過程的監督很是困難。工做量證實等因而只監督結果,你必須付出足夠的工做量(有效挖礦),才能證實你的記帳工做是有效的。這個工做量的定義是由挖礦的難度決定的,參見後面挖礦。緩存
共識機制:區塊鏈系統使用上面所述的工做量證實來解決節點可信的問題(共識問題在計算機算法中有一個典型的模型叫拜占庭將軍問題,一般分佈式數據庫中都會存在這種問題)。安全
區塊鏈:區塊鏈是老概念,軟件專業的算法課程,基本上頭幾節課就會涉及到鏈表的概念。區塊鏈就是鏈表,除了第一個「創世紀」節點,每個節點都有一個指針指向前一個節點。單向鏈表的特徵使得確定會出現多個節點指向同一個節點的狀況,這通常是因爲同時出現兩個挖礦成功,這種狀況就是分叉,無限制的發展就成爲了樹。比特幣系統的設計是不容許這種狀況的,每次都會在鏈表中選擇最長的一條鏈表進行下一個節點的連接,而最終短的分支會被拋棄。比特幣的設計中,一個區塊以後又連接了5個另外的區塊(共6個區塊),就能夠確認本區塊的交易是安全的了。一個示意性的區塊鏈節點結構圖示以下:服務器
區塊鏈是把一個基本數據結構模型應用於去中心化記帳算法的成功範例。優勢是這種創新必將對從此的金融系統設計形成深入影響,缺點則是至今彷佛還沒有發現這種區塊鏈結構在其它領域的優點應用或者優選方案。網絡
挖礦:區塊鏈中每個節點都是用來記帳的。爲了防止節點被僞造,節點的生成有嚴格、耗時的要求,只有找到一個新的節點符合這些要求,這個節點才能把最近發生的交易記錄進去並連接到區塊鏈主鏈之上。尋找一個新的記帳節點的過程就是挖礦。數據結構
挖礦算法:若是用python來表述一下挖礦算法,源碼大體是這樣的:
import hashlib, struct ver = 1 prev_block = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" mrkl_root = "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" time = 1231469665 bits = 486604799 nonce = 2573394689 hex_str = struct.pack("<L", ver) + prev_block.decode('hex')[::-1] + mrkl_root.decode('hex')[::-1] + struct.pack("<LLL", time, bits, nonce) hash_str = hashlib.sha256(hashlib.sha256(hex_str).digest()).digest() # bitcoin礦機就是使用顯卡或者FPGA實現sha256算法,經過暴力循環找到一個合適的nonce ... block_hash = hash_str[::-1].encode('hex_codec') #如下是僞代碼 if meetReqirements(block_hash): newBlock=bookkeeping(block_hash) block_hash(newBlock)
挖礦的核心是進行兩次的sha256運算,而且要求結果符合當前比特幣要求的難度值,難度值表示兩次sha256計算的結果,前面有符合難度值的0。意思是,假設計算結果是"000000xx...xxxxxx",前面0的個數,必須符合難度的要求,並且這個難度值在比特幣系統中是不斷增長的,也就是說挖礦難度愈來愈大。
參考上面的鏈表圖,開頭定義的幾個常量都是節點的基本資料,不可改變,可變的只有nonce。而sha256 hash算法的特色,使得最終結果只能暴力循環全部的nonce可能值,纔可能獲得最終結果,至今尚無投機取巧的辦法。
這個設計是爲了區塊鏈的生成沒有那麼容易,從而僞造區塊鏈就成了拼計算能力的行爲,而挖礦如此流行,計算能力想超過全球挖礦計算能力的半數已是一件不可能的事情。從而在技術上杜絕了「帳本僞造」這種可能性。這也成爲「工做量證實(Proof-of-Work)」的共識達成機制的核心。
礦池:由於挖礦的難度愈來愈高,今天一我的使用本身的電腦挖礦成功的事情已經極難成功,所以出現了在輔助網站及輔助程序的幫助下,把你們零散的計算能力匯聚起來,一塊兒進行挖礦,收益你們分享的方式,這就是礦池。礦池的主要算法是把上述的一個nonce值分段,每人窮舉其中一小段,從而並行起來提升找到正確nonce值的機率。實際上今天礦池這種概念已經很成功的應用在了很多領域,諸如分佈式計算、衆籌等。
UTXO:一種記帳方法,每一個交易的記錄,僅記錄最終最近的交易及「UTXO」也就是未花費輸出(Unspent Transaction Output),最重點,每個交易中都包含這筆錢是誰轉給你的。而鏈表中上一個交易也是,所以實際上每一筆錢都是能夠完整追溯的。這種方式的特色是:1.獲得餘額須要去遍歷區塊鏈,而不是某一個節點。2.顯然能大大縮小節點的數據尺寸。這對分佈式每一個人都保存一份帳本的狀況下,能夠大大的下降空間需求。
礦機:上面的挖礦源碼能夠看出,主要的計算就是兩次的sha256,想提升速度,除了用CPU,GPU更適合用做這種單純的數學運算。所以出現了專門爲挖礦設計的計算機,好比同時支持多塊顯卡,從而大大加快速度。這種電腦除了挖礦,在其它應用中意義並不大,因此叫「礦機」。GPU計算以後,又出現過FPGA礦機及ASIC礦機,不過看起來產量並非很大。也多是由於一旦挖礦失敗,普通設備還能夠拆開賣顯卡,而這種純粹的專業機就很差辦了。
創世塊:也就是創世紀區塊,鏈表中第一個區塊,至關於鏈表的頭。這個也是硬編碼在源代碼中的,這個區塊及其挖礦收入屬於做者中本聰。來看看本尊:
curl https://blockchain.info/rawbl... { "hash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "ver":1, "prev_block":"0000000000000000000000000000000000000000000000000000000000000000", "mrkl_root":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", "time":1231006505, "bits":486604799, "fee":0, "nonce":2083236893, "n_tx":1, "size":285, "block_index":14849, "main_chain":true, "height":0, "tx":[ { "lock_time":0, "ver":1, "size":204, "inputs":[ { "sequence":4294967295, "witness":"", "script":"04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" } ], "weight":816, "time":1231006505, "tx_index":14849, "vin_sz":1, "hash":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", "vout_sz":1, "relayed_by":"0.0.0.0", "out":[ { "addr_tag_link":"https://en.bitcoin.it/wiki/Genesis_block", "addr_tag":"Genesis of Bitcoin", "spent":false, "tx_index":14849, "type":0, "addr":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", "value":5000000000, "n":0, "script":"4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" } ] }] }
請注意prev_block之中的一串「0」和height中的「0」,這證實這是鏈表的root。
創世塊有個有趣的「反作用」,由於比特幣「帳本」的不可篡改性,其內容的惟一肯定性是無可質疑的,並且人人能夠驗證。
所以只要有人用創世塊地址的私鑰簽名一份聲明,那就能夠確定是中本聰本人的聲明,或者本人泄露了私鑰。
若是說祕鑰是比特幣世界的印章的話,創世塊地址對應的祕鑰就是傳國玉璽。中本聰的比特幣地址就是addr中的:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa。
創世紀區塊能夠看源碼文件:src/chainparams.cpp,其中的:
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
Merkle Tree:默克爾樹,一般也被稱做Hash Tree,顧名思義,就是存儲hash值的一棵樹。Merkle樹的葉子是數據塊(例如,文件或者文件的集合)的hash值,在區塊鏈中表明用於記帳的帳本內容。非葉節點是其對應子節點串聯字符串的hash。hash算法也就是摘要算法,用於保證主體內容的一點點改變都致使hash內容的改變,逐級的樹狀結構,保證下一級的數據不被篡改。這裏使用默克爾樹而不是整個數據塊作一個hash值,起源實際上是p2p軟件,用於在整個帳本下載的時候,若是發生錯誤,不須要所有下載,而是逐級回溯hash值,下載出錯的一小塊數據就能夠。
電子簽名:比特幣也是最先實踐電子簽名的應用之一。
電子簽名分紅私鑰、公鑰兩部分,有私鑰的話,能夠通過計算獲得公鑰,反之則不可。工做時,私鑰本身持有,本身負責保密,公鑰發佈在網絡,全部人均可以看到。
全部的交易數據,都由交易者的私鑰簽名,其它人則可使用公佈的公鑰對簽名進行驗證。對交易數據的修改會致使簽名失效,這個纔是比特幣系統對資產最大的保證。
比特幣電子簽名使用ecdsa算法,這個算法有一個小缺陷,就是若是交易記錄中僅僅修改了一個字節,仍然會驗證經過。
固然這個修改沒法作到修改交易金額,但可能形成後續的哈希計算獲得徹底不一樣的ID值。在攻擊方網絡足夠快、廣播能力足夠強的話,可能在小範圍內形成的僞造出現。
歷史上曾經發生過利用這個方式僞造交易失敗並向交易商索賠成功的事情,可是究其緣由不算比特幣系統設計問題,若是交易商嚴格遵循交易原則,只接受程序結果,不人爲干預,是能夠避免損失的。
比特幣源碼:src/secp256k1/src/secp256k1.c這裏主要處理簽名相關的東西。
電子簽名機制今天已經無孔不入的遍及互聯網各個環節,包括https網站、email、電子交易、網絡銀行,如今的問題已經不是要不要用電子簽名,而是努力把每一個由公網通過的環節都儘量的簽名化纔是如今的趨勢。
智能合約:比特幣系統中的整個過程的商業邏輯就算作智能合約,與他人完成交易就至關於雙方共同簽定一份合約,隨後利用區塊鏈記帳、交易廣播、工做量證實等手段保障合約正確執行並不被篡改、攻擊。這個描述比較抽象化,可能涉及了多個方面。以我我的認爲,「智能合約」的理念纔是比特幣系統中最難得的概念。
交易確認:交易確認分紅兩個部分,一個是區塊生成後的確認,一個是一筆比特幣交易完成後的確認,二者都設定了交易確認時間(當前是10分鐘)。主要緣由都是P2P的廣播是須要時間的,在這個廣播被儘量多的人收到以前就確認交易,前者會形成區塊鏈的衝突而出現分支,未能及時矯正的分支甚至會成爲樹從而形成區塊鏈崩潰。後者未能廣播以前就確認會出現僞造的可能,而廣播被更多人收到以後,僞造就須要工做量證實,也就不可能達到了。但一般認爲,達到不可逆轉的6個區塊鏈的標準,6*10實際是1小時的時間,才能真正肯定一筆交易安全。