一文看懂(dǒng)怎樣用(yòng) Python 創建比特币交易

2018-04-04 15:20

 

比特币價格的(de)上上下(xià)下(xià),始終撩動著(zhe)每一個(gè)人(rén)無比關切的(de)小心髒。從去年初的(de) 800 美(měi)元左右,飛(fēi)漲到去年底到 19783.21 美(měi)元最高(gāo)點,不到1年,便有将近 25 倍的(de)升值速度。盡管眼下(xià)又掉回 8000 多(duō)美(měi)元的(de)價格,但價格差不多(duō)能搞出去年同期一個(gè)數量級,币圈人(rén)士“過去一年比以往 10 年掙的(de)都多(duō)”,已經是不争的(de)事實。

而對(duì)區(qū)塊鏈開發者來(lái)說,據說也(yě)已經有拿到年新 500 萬的(de)天價。所以“跑步進入區(qū)塊鏈”,已經成爲不少程序員(yuán)的(de)共識。但是看過很多(duō)遠(yuǎn)離,我們如何才能迅速上手呢(ne)?國外網友 Ken Shirriff 在博客中分(fēn)享了(le)他(tā)在手動茶古劍比特币交易時(shí)的(de)代碼與對(duì)比特币協議(yì)的(de)心得(de),區(qū)塊鏈大(dà)本營編譯如下(xià)。

 

近期,媒體行業對(duì)比特币表現出極大(dà)的(de)熱(rè)情,這(zhè)鼓舞著(zhe)我從網絡底層的(de)數據流開始,認真學習(xí)比特币的(de)工作原理(lǐ)。通(tōng)常人(rén)們會使用(yòng)錢包軟件來(lái)進行比特币交易,錢包軟件在方便用(yòng)戶的(de)同時(shí),向用(yòng)戶隐藏了(le)比特币的(de)交易流程,而我想親自動手來(lái)體驗比特币交易,我的(de)目标是用(yòng)Python手動創建一筆比特币交易,以十六進制數據的(de)形式将交易廣播到比特币網絡中,然後觀察這(zhè)筆交易是怎麽被加入到區(qū)塊鏈中的(de)。事實證明(míng),這(zhè)個(gè)過程很有趣,希望你也(yě)對(duì)它感興趣。

 

在本篇文章(zhāng)中,首先我會對(duì)比特币進行一個(gè)簡單的(de)概述,之後,我會從以下(xià)幾個(gè)方面帶領你們學習(xí)比特币:創建一個(gè)比特币地址(比特币中的(de)賬戶),進行一筆比特币交易,簽署交易,将交易廣播到比特币網絡中,最後等待交易的(de)确認。

 

比特币簡述:

 

首先,我會介紹一下(xià)比特币系統是怎麽運轉的(de),然後再深入探討(tǎo)整個(gè)細節。比特币是一個(gè)基于點對(duì)點網絡的(de)電子貨币,你可(kě)以用(yòng)現金在網上購(gòu)買比特币,用(yòng)比特币向他(tā)人(rén)轉賬,在有些商家,你可(kě)以像使用(yòng)支付寶一樣使用(yòng)比特币付款,當然,你也(yě)可(kě)以賣出所持有的(de)比特币換回現金。

 

簡而言之,在比特币網絡中,分(fēn)布式賬本(區(qū)塊鏈)記錄并随時(shí)更新著(zhe)每個(gè)比特币的(de)所有權。與銀行不同的(de)是,比特币并沒有與個(gè)人(rén)或個(gè)人(rén)的(de)賬戶綁定,相反的(de),比特币隻屬于一個(gè)個(gè)比特币地址,比如:1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa。這(zhè)裏你可(kě)能已經繞暈了(le),難道這(zhè)段字符中藏著(zhe)比特币?當然不是,比特币地址是比特币網絡中的(de)一個(gè)身份,也(yě)可(kě)以通(tōng)俗地說是你在比特币中開的(de)一個(gè)“銀行賬戶”,我們用(yòng)這(zhè)個(gè)“賬戶”來(lái)進行交易。在網站:blockchain.info中,你可(kě)以查到所有的(de)交易信息:

 

比特币賬戶信息

 

但是怎麽證明(míng)這(zhè)個(gè)賬戶是我的(de)呢(ne),不急,先往下(xià)看,你的(de)疑問我會爲你一一解答(dá)。

 

比特币交易

 

如何像使用(yòng)現金一樣使用(yòng)比特币呢(ne)?答(dá)案是創建一筆交易。在一筆交易中,比特币的(de)所有者(上文提到過比特币的(de)所有者是比特币地址)将所有權轉移到一個(gè)新的(de)比特币地址。比特币的(de)一個(gè)颠覆性創新就是通(tōng)過鼓勵節點記賬(也(yě)叫礦工挖礦),将交易記錄放在一個(gè)分(fēn)布式的(de)數據庫中。交易被集合在區(qū)塊中,大(dà)概每十分(fēn)鐘(zhōng)比特币網絡中産生一個(gè)新的(de)區(qū)塊,成爲交易記錄的(de)一部分(fēn),稱爲區(qū)塊鏈。加入到區(qū)塊鏈中的(de)交易可(kě)以被認爲是一筆成功的(de)交易。現在問題來(lái)了(le),誰來(lái)給你記賬呢(ne)?是礦工,礦工的(de)挖礦過程就是在往區(qū)塊鏈中記賬,礦工要核實每筆交易是否正确,核實完後,礦工們就開始算(suàn)一道很難的(de)數學題(密碼學中的(de)哈希函數),最早算(suàn)出答(dá)案的(de)人(rén)就能生成一個(gè)區(qū)塊,也(yě)叫挖出了(le)一個(gè)新的(de)區(qū)塊,這(zhè)個(gè)區(qū)塊将成爲區(qū)塊鏈的(de)新一部分(fēn)。

 

也(yě)許你會問了(le),明(míng)明(míng)是記賬,幹著(zhe)會計的(de)活,爲什(shén)麽要叫挖礦呢(ne)?和(hé)傳統的(de)在地下(xià)挖礦石一樣,比特币挖礦也(yě)是會有收獲的(de)。挖礦是一種新發行比特币的(de)過程,當前,每挖到一個(gè)礦,礦工會得(de)到系統獎勵的(de)12.5個(gè)比特币,按目前一個(gè)比特币接近一萬美(měi)元的(de)市價,這(zhè)就是一筆12.5萬美(měi)元的(de)巨款。此外,礦工還(hái)可(kě)以獲得(de)本區(qū)塊中所有的(de)交易費,舉例來(lái)說,在高(gāo)度爲512587的(de)區(qū)塊中,幸運的(de)礦工總共收獲了(le)12.829個(gè)比特币。正因如此,礦工之間的(de)競争十分(fēn)激烈,采礦的(de)難度與礦工間激烈的(de)競争是比特币安全的(de)重要保證,因爲這(zhè)樣可(kě)以保證沒有壞人(rén)能操縱系統。

 

點對(duì)點網絡

 

比特币并沒有一個(gè)中央服務器,相反,比特币在一個(gè)點對(duì)點網絡中運行。如果你運行一個(gè)比特币節點,那你就成了(le)網絡的(de)一部分(fēn)。比特币網絡中的(de)節點彼此交換自己存儲的(de)交易,區(qū)塊,以及IP地址信息(用(yòng)于節點間建立連接互相通(tōng)信)。當你第一次連接到比特币網絡,你的(de)節點會從随機挑選的(de)節點中下(xià)載區(qū)塊鏈的(de)信息。反過來(lái),你的(de)節點也(yě)會向後加入者提供信息。當你要創建一筆比特币交易時(shí),你要把這(zhè)筆交易發送給一些節點,這(zhè)些節點會在比特币網絡中廣播這(zhè)筆交易,直到全網都收到這(zhè)筆交易。礦工們會收集你的(de)交易信息,生成一個(gè)含有你這(zhè)筆交易的(de)區(qū)塊,向全網廣播,這(zhè)時(shí),你的(de)節點也(yě)會收到這(zhè)個(gè)區(qū)塊信息,通(tōng)過驗證,這(zhè)筆交易被加入到了(le)區(qū)塊鏈中,你就交易成功了(le)。 

 

加密技術

 

現在回到證明(míng)比特币賬戶是誰的(de)這(zhè)個(gè)問題。比特币使用(yòng)數字簽名技術以确保隻有比特币賬戶的(de)所有者才能使用(yòng)賬戶中的(de)比特币。比特币地址的(de)所有者擁有與該地址相匹配的(de)私鑰,當花費比特币時(shí),你用(yòng)要這(zhè)個(gè)私鑰在交易上簽名,證明(míng)自己是這(zhè)個(gè)賬戶的(de)所有者。這(zhè)有點像現實生活中的(de)蓋章(zhāng),蓋章(zhāng)就意味著(zhe)授權。怎麽驗證呢(ne),公鑰與比特币賬戶相關聯,用(yòng)公鑰就可(kě)以驗證簽名是否正确。這(zhè)樣就解決了(le)比特币賬戶是誰的(de)這(zhè)個(gè)問題。

 

怎麽來(lái)區(qū)分(fēn)不同的(de)交易呢(ne)?交易和(hé)區(qū)塊都使用(yòng)密碼學上的(de)哈希值進行索引,是不是有點耳熟,對(duì),在比特币協議(yì)中,多(duō)處使用(yòng)到了(le)哈希函數,礦工們剛才算(suàn)的(de)數學題就是在算(suàn)哈希函數。

 

比特币協議(yì)探究

 

在接下(xià)來(lái)的(de)文章(zhāng)裏,我将逐步介紹我是怎樣手動進行一次比特币交易的(de)。首先,我生成了(le)一個(gè)比特币賬戶以及對(duì)應的(de)公鑰,私鑰。接下(xià)來(lái)我發起了(le)一筆比特币交易,我向這(zhè)個(gè)新生成的(de)賬戶轉了(le)一小筆比特币。期間手動簽署這(zhè)筆交易很困難,它花費了(le)我很多(duō)的(de)時(shí)間。最後,我将這(zhè)筆交易發送到比特币網絡,等待它被加入區(qū)塊鏈。本文的(de)其餘部分(fēn)會詳細地介紹這(zhè)些步驟。

 

事實證明(míng),手動進行比特币交易比我想象中的(de)更加困難。正如你所看到的(de),比特币的(de)協議(yì)有些許混亂:它使用(yòng)了(le)大(dà)端格式數字(高(gāo)位編址,将高(gāo)序字節存儲在起始地址),小端格式數字(低位編址,将低序字節存儲在起始位置),固定長(cháng)度數字,可(kě)變長(cháng)度數字,自定義編碼格式,DER編碼格式以及各種加密算(suàn)法。因此,僅僅是将數據轉換爲正确的(de)格式就浪費了(le)很多(duō)時(shí)間。

 

我遇到的(de)第二個(gè)難題就是加密,嘗試一下(xià)手動加密,你就會發現密碼學對(duì)人(rén)們多(duō)不友好,甚至可(kě)以說是無情。即使你隻輸錯了(le)一個(gè)字節,交易就會因出錯被拒絕,而且它不會告訴你哪裏出錯了(le),你隻能重來(lái)。

 

最後,手動簽署交易的(de)過程也(yě)比想象中難得(de)多(duō),簽署交易時(shí)每個(gè)環節都必須零失誤,要麽又要退回重來(lái)。

 

比特币地址和(hé)密鑰

 

第一步,我創建了(le)一個(gè)比特币地址。通(tōng)常情況下(xià),人(rén)們都是使用(yòng)比特币客戶端軟件來(lái)創建比特币地址和(hé)與之相關的(de)密鑰。本著(zhe)學習(xí)的(de)态度,我寫了(le)一些Python代碼來(lái)生成比特币地址,從而揭示地址創建的(de)機理(lǐ)。

 

比特币使用(yòng)了(le)一系列的(de)密鑰和(hé)地址,下(xià)圖解釋了(le)它們的(de)關系。首先你要創建一個(gè)随機的(de)256位的(de)私鑰,這(zhè)個(gè)私鑰用(yòng)于在花費比特币時(shí)簽署交易。因此,私鑰必須保密,否則你的(de)比特币可(kě)能會被盜用(yòng)。

 

橢圓曲線數字簽名算(suàn)法(Elliptic Curve Digital Signature Algorithm,ECDSA,美(měi)國政府的(de)标準,接下(xià)來(lái)我們會討(tǎo)論它)會從私鑰中生成一個(gè)512位的(de)公鑰,這(zhè)個(gè)公鑰用(yòng)于驗證交易的(de)簽名。但不方便的(de)是,比特币協議(yì)中需要在這(zhè)個(gè)公鑰上添加了(le)前綴04,這(zhè)個(gè)公鑰在交易簽署之前不會被洩露,不像其它系統中公鑰就是爲了(le)公之于衆的(de)。

 

比特币地址與公鑰的(de)關系

 

下(xià)一步就是生成與他(tā)人(rén)交易時(shí)使用(yòng)的(de)比特币地址了(le)。512位的(de)公鑰太長(cháng)不方便使用(yòng),因此使用(yòng)SHA-256和(hé)RIPEMD哈希算(suàn)法将其縮小爲160位。然後使用(yòng)比特币定義的(de)Base58Check 編碼将密鑰編碼爲ASCII(American Standard Code for Information Interchange,美(měi)國信息交換标準代碼)格式。得(de)到的(de)地址(例如上文中的(de):1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa)就是你接收别人(rén)比特币時(shí)要發布的(de)地址。需要注意的(de)是,你無法從比特币地址中複原出公鑰或私鑰。如果你丢失了(le)你的(de)私鑰(比如說你把私鑰存在你的(de)硬盤上,但硬盤丢失),你的(de)比特币将永遠(yuǎn)丢失。

 

最後,錢包交換格式密鑰(WIF)用(yòng)于将私鑰添加到你的(de)錢包軟件中,這(zhè)隻是将私鑰進行Base58Check編碼轉換爲ASCII格式,這(zhè)一步是可(kě)逆的(de),而且很容易經過逆變換恢複出256位的(de)私鑰。(圖中有我的(de)私鑰,我很好奇是否有人(rén)會用(yòng)我的(de)私鑰去偷(通(tōng)過私鑰簽署交易,從而轉走)我那價值80美(měi)分(fēn)的(de)比特币,然而真有人(rén)那麽做(zuò)了(le),可(kě)以在

https://blockchain.info/address/1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa 看到,也(yě)算(suàn)是爲教學做(zuò)貢獻了(le)。)

 

總之,共有三種密鑰:私鑰,公鑰,公鑰的(de)哈希值,經過使用(yòng)Base58Check編碼,它們對(duì)外都是以ASCII格式表示。私鑰是其中最重要的(de)密鑰,因爲花費比特币時(shí)需要私鑰簽署交易,而且其他(tā)的(de)密鑰都可(kě)以從私鑰中産生。公鑰的(de)哈希值就是你們剛看的(de)的(de)比特币地址。

 

我使用(yòng)下(xià)面的(de)代碼片段來(lái)生成WIF格式的(de)私鑰和(hé)地址。私鑰隻是一個(gè)随機的(de)256位的(de)數字,使用(yòng)橢圓曲線數字簽名算(suàn)法從私鑰中生成公鑰,公鑰使用(yòng)SHA-256算(suàn)法,RIPEMD-160算(suàn)法進行哈希計算(suàn),再經Base58編碼并進行校驗後得(de)到比特币地址。最後,私鑰用(yòng)Base58Check編碼以生成用(yòng)于将私鑰輸入錢包軟件的(de)WIF編碼。注意,這(zhè)段Python随機函數代碼在密碼學上安全性并不高(gāo),如果你想要嘗試這(zhè)一步驟,建議(yì)使用(yòng)更安全的(de)錢包軟件來(lái)生成比特币地址和(hé)密鑰。

 

def privateKeyToWif(key_hex):        return utils.base58CheckEncode(0x80, key_hex.decode('hex'))    def privateKeyToPublicKey(s):    sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1)    vk = sk.verifying_key    
   return ('\04' + sk.verifying_key.to_string()).encode('hex')  
 def pubKeyToAddr(s):    ripemd160 = hashlib.new('ripemd160')    ripemd160.update(hashlib.sha256(s.decode('hex')).digest())    
   return utils.base58CheckEncode(0, ripemd160.digest())

def keyToAddr(s):    
   return pubKeyToAddr(privateKeyToPublicKey(s))

# Warning: this random function is not cryptographically strong and is just for example
private_key = ''.join(['%x' % random.randrange(16) for x in range(0, 64)]) print keyUtils.privateKeyToWif(private_key) print keyUtils.keyToAddr(private_key)

keyUtils.py

 

從内部分(fēn)析一筆交易

 

交易是比特币系統的(de)基本操作,也(yě)許你會認爲交易就是簡單地把比特币從一個(gè)地址轉移到另一個(gè)地址,但交易其實并不簡單。一筆交易包含一個(gè)或多(duō)個(gè)輸入和(hé)輸出,交易中的(de)每個(gè)輸入的(de)地址都提供比特币,每個(gè)輸出的(de)地址都接受比特币。

 

一筆簡單的(de)比特币交易,交易C花費了(le)從交易A和(hé)交易B獲得(de)的(de)0.008個(gè)比特币,其中0.001個(gè)比特币被當作交易費付給礦工

 

上圖顯示了(le)一筆簡單的(de)比特币交易“C”,在這(zhè)筆交易中,有0.005個(gè)比特币是在交易A中獲得(de)的(de),0.003個(gè)比特币是在交易B中獲得(de)的(de)。(圖中箭頭是由新交易的(de)輸入指向得(de)到這(zhè)些比特币的(de)交易的(de)輸出,所以比特币的(de)流向是逆著(zhe)箭頭方向的(de)。)對(duì)于輸出,有0.003個(gè)比特币給了(le)第一個(gè)比特币地址,有0.004個(gè)比特币給了(le)第二個(gè)比特币地址,剩餘的(de)0.001個(gè)比特币作爲交易費付給礦工。請注意,本次交易并沒有影(yǐng)響到在交易A中另一個(gè)輸出爲0.015的(de)比特币。 

 

在一筆交易中,輸入的(de)比特币地址必須花出所有的(de)比特币,假如你在之前的(de)交易收到了(le)100個(gè)比特币,但你隻想花1個(gè)比特币,創建這(zhè)筆交易你必須花完所有的(de)100個(gè)比特币,那剩下(xià)的(de)99個(gè)比特币怎麽辦呢(ne)?解決方案就是在交易中再增加一個(gè)輸出,将剩餘的(de)99個(gè)比特币轉給自己。這(zhè)樣你就可(kě)以花費任意數額的(de)比特币。 

 

通(tōng)常交易要支付交易費,如果一筆交易中輸入的(de)比特币總和(hé)大(dà)于輸出的(de)比特币的(de)總和(hé),剩餘的(de)費用(yòng)就是給礦工的(de)交易費。這(zhè)筆費用(yòng)并沒有明(míng)确要求,但是對(duì)于礦工而言,沒有交易費的(de)交易就會被列爲低優先級交易,可(kě)能要等上幾天才會被處理(lǐ)甚至被礦工直接丢棄。交易費通(tōng)常并不高(gāo),但它可(kě)能影(yǐng)響著(zhe)你的(de)交易。

 

手動創建一筆交易

 

如下(xià)圖所示,在我的(de)實驗中我發起了(le)一筆隻有一個(gè)輸入一個(gè)輸出的(de)交易。我在Coinbase上買了(le)一些比特币,并将0.00101234個(gè)比特币放入地址:

1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5中,這(zhè)筆交易哈希爲:

81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48,我的(de)目标是創建一筆交易,将這(zhè)些比特币轉入我的(de)另一個(gè)地址:

1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa,扣除0.0001個(gè)比特币的(de)交易費後,目标地址将獲得(de)0.00091234個(gè)比特币。

比特币交易結構實例

 

 Blockchain.info上的(de)交易記錄

https://blockchain.info/address/1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5?filter=4

 

按照(zhào)協議(yì)标準,創建這(zhè)筆交易很簡單。如下(xià)表所示,這(zhè)筆交易隻有一個(gè)輸入,源自于81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48中的(de)輸出0(第一個(gè)輸出)。輸出爲0.00091234個(gè)比特币(91234在十六進制中用(yòng)0x016462表示),它以小端格式存儲在值區(qū)域中。加密過程中的(de)scriptSig和(hé)scriptPubKey較爲複雜(zá),我們稍後再做(zuò)討(tǎo)論。

version

01 00 00 00

input count

01

input

previous output hash(reversed)

48 4d 40 d4 5b 9e a0 d6 52 fc a8 25 8a b7 ca a4 25 41 eb 52 97 58 57 f9 6f b5 0c d7 32 c8 b4 81

previous output index

00 00 00 00

script length

 

scriptSig

script containing signature

sequence

ff ff ff ff

output count

01

output

value

62 64 01 00 00 00 00 00

script length

 

scriptPubKey

script containing destination address

block lock time

00 00 00 00

這(zhè)是我生成交易使用(yòng)的(de)代碼,這(zhè)段代碼隻是把數據打包成二進制文件。簽署交易較爲困難,我們等一會兒(ér)再說。

 


 

# Makes a transaction from the inputs# outputs is a list of [redemptionSatoshis, outputScript]
def makeRawTransaction(outputTransactionHash, sourceIndex, scriptSig, outputs):    
          def makeOutput(data):               redemptionSatoshis, outputScript = data
              return (struct.pack("<Q", redemptionSatoshis).encode('hex') +
              '%02x' % len(outputScript.decode('hex')) + outputScript)           formattedOutputs = ''.join(map(makeOutput, outputs))
          return (        
              "01000000" + # 4 bytes version               "01" + # varint for number of inputs               outputTransactionHash.decode('hex')[::-1].encode('hex') + # reverse outputTransactionHash               struct.pack('<L', sourceIndex).encode('hex') +        
              '%02x' % len(scriptSig.decode('hex')) + scriptSig +        
              "ffffffff" + # sequence               "%02x" % len(outputs) + # number of outputs               formattedOutputs +        
              "00000000" # lockTime
              )

txnUtils.py

 

比特币交易怎樣簽署

 

下(xià)圖爲我們簡單描述了(le)交易是如何簽署并相互連接的(de)。針對(duì)中間這(zhè)筆從比特币地址B轉賬到比特币地址C的(de)交易。交易的(de)内容(包括前一個(gè)交易的(de)哈希值(索引))被進行哈希計算(suàn)并用(yòng)B的(de)私鑰簽名。另外,B的(de)公鑰也(yě)被包含在了(le)交易中。 

 

通(tōng)過執行幾個(gè)簡單運算(suàn),任何人(rén)都能驗證B是否簽署了(le)這(zhè)筆交易。首先,B的(de)公鑰與之前收到這(zhè)筆比特币交易的(de)地址做(zuò)驗證,證明(míng)B的(de)公鑰有效。(正如前面所說的(de),地址很容易從公鑰中計算(suàn)獲得(de))。接下(xià)來(lái),可(kě)以通(tōng)過B的(de)公鑰驗證B交易簽名的(de)真僞。這(zhè)些步驟能确保交易的(de)有效性和(hé)交易得(de)到B的(de)授權。比特币于衆不同的(de)一點是,B的(de)公鑰在B發起交易之前是不公開的(de)。 

 

在比特币系統中,比特币通(tōng)過區(qū)塊鏈上的(de)一筆筆交易在不同的(de)地址間傳遞。區(qū)塊鏈上的(de)每一筆交易都能被驗證以确保比特币交易的(de)有效性。

 

比特币腳本語言

 

你可(kě)能會以爲僅僅通(tōng)過在交易内容中附上簽名就可(kě)以簽署比特币交易,其實不然,這(zhè)個(gè)過程十分(fēn)複雜(zá)。實際上,每一筆交易中都包含一個(gè)“小程序”,用(yòng)于确認交易是否有效。這(zhè)個(gè)“小程序”用(yòng)腳本語言寫成,通(tōng)過這(zhè)種基于堆棧的(de)比特币腳本語言,我們可(kě)以應對(duì)許多(duō)複雜(zá)的(de)比特币支付場(chǎng)景。例如,托管系統可(kě)以設定隻要經過三分(fēn)之二的(de)用(yòng)戶授權,就可(kě)執行交易的(de)規則,也(yě)可(kě)以設置其他(tā)的(de)合約。 

 

腳本語言十分(fēn)複雜(zá),大(dà)約有80種操作碼,包括算(suàn)數計算(suàn),按位操作,字符串處理(lǐ),條件語句和(hé)堆棧操作。腳本語言也(yě)包含一些必要的(de)密碼學操作(SHA-256,RIPEMD等等)作爲原語(原語是執行過程中不可(kě)被打斷的(de)基本操作,你可(kě)以理(lǐ)解爲一段代碼)。爲了(le)确保腳本語言可(kě)以運行完畢自動退出,該語言不支持任何循環操作,因此它不是圖靈完備的(de)。然而,實際上,它隻支持少數類型的(de)交易。 

 

前一個(gè)交易中的(de)腳本稱爲scriptPubKey,當前交易中的(de)腳本稱爲scriptSig。要驗證交易時(shí),先執行scriptSig,然後再執行scriptPubKey。如果兩個(gè)腳本都成功執行,交易就被認定爲有效,交易中的(de)比特币就可(kě)以成功花出。否則,交易無效。要注意的(de)是前一個(gè)交易中的(de)scriptPubKey規定了(le)花費比特币的(de)條件,當前交易的(de)scriptSig必須滿足這(zhè)個(gè)條件。 

 

在一個(gè)标準的(de)交易中,scriptSig腳本将從私鑰中生成的(de)簽名并壓入堆棧中,再壓入公鑰。接下(xià)來(lái)scriptPubKey腳本會執行運算(suàn)先驗證公鑰的(de)有效性,再驗證簽名的(de)有效性。

 

正如腳本中所表示,scriptSig:

 


 

PUSHDATA
signature data and SIGHASH_ALL
PUSHDATA
public key data

 

scriptPubKey:

 


 

OP_DUP OP_HASH160 PUSHDATA Bitcoin address (public key hash) OP_EQUALVERIFY OP_CHECKSIG

 

當這(zhè)段代碼執行時(shí),PUSHDATA操作首先會把簽名壓入堆棧,接著(zhe)把公鑰壓入堆棧。OPHASH-160操作計算(suàn)公鑰的(de)160位哈希值,PUSHDATA操作再把交易中的(de)輸入地址(輸入賬号)壓入堆棧,然後,OP-EQUALVERIFY操作驗證驗證前兩個(gè)堆棧中的(de)值是否相等(驗證這(zhè)筆交易中你使用(yòng)的(de)比特币是否屬于你自己)-如果公鑰的(de)哈希等于之前交易中的(de)輸出地址,這(zhè)就證明(míng)公鑰是有效的(de)(證明(míng)這(zhè)個(gè)比特币是你的(de))。最後,OP_CHECKSIG操作将檢查交易的(de)簽名是否與堆棧裏的(de)公鑰和(hé)簽名匹配,匹配就證明(míng)簽名是有效的(de)(證明(míng)交易的(de)到了(le)你的(de)授權)

 

簽署交易

 

我發現簽署這(zhè)筆交易是手動使用(yòng)比特币時(shí)最難的(de)地方,這(zhè)一過程出奇地困難且容易出錯。簽名的(de)基本思想很簡單,使用(yòng)橢圓曲線簽名算(suàn)法和(hé)私鑰來(lái)生成交易的(de)數字簽名,但細節非常棘手。簽署交易的(de)過程可(kě)以通(tōng)過這(zhè)19個(gè)步驟描述。

 

 

簽署交易的(de)19個(gè)步驟

 

對(duì)交易的(de)簽名讓我面臨巨大(dà)的(de)挑戰,這(zhè)涉及到一個(gè)如何在交易内容中還(hái)沒有加入簽名時(shí)簽署這(zhè)筆交易的(de)問題。爲了(le)避免這(zhè)個(gè)問題,在計算(suàn)生成簽名之前,我把scriptPubKey這(zhè)個(gè)腳本從上一筆交易複制到當前交易中(當前這(zhè)筆交易正在被簽署),然後将簽名轉換爲腳本語言的(de)代碼,創建嵌入在當前交易中的(de)scriptSig腳本。對(duì)于具有多(duō)個(gè)輸入的(de)交易,簽署交易環節更加複雜(zá),因爲每個(gè)輸入都需要單獨的(de)簽名,這(zhè)裏我就不做(zuò)詳細討(tǎo)論了(le)。

 

哈希值這(zhè)一步驟難倒了(le)我。在簽名之前,交易中有一個(gè)臨時(shí)附加的(de)哈希值常量。對(duì)于常規的(de)交易,這(zhè)個(gè)值是SIGHASH_ALL(0x00000001)。簽名後,這(zhè)個(gè)哈希值将從交易内容的(de)最後删除,附加到scriptSig腳本中。

 

在比特币中另一件令人(rén)討(tǎo)厭的(de)事情是雖然簽名和(hé)公鑰都是512位的(de)橢圓曲線值,但它們的(de)表示方式完全不同:簽名用(yòng)DER編碼方式編碼,而公鑰用(yòng)純字節表示。另外,兩個(gè)值都有一個(gè)額外的(de)字節,但位置并不一緻:SIGHASH_ALL這(zhè)個(gè)附加的(de)哈希值常量放在簽名後面,而04這(zhè)個(gè)值放在公鑰前面。

 

由于ECDSA算(suàn)法需要使用(yòng)随機數,所以調試簽名十分(fēn)困難。每次計算(suàn)出的(de)簽名都會有所不同,因此無法與已知正确的(de)簽名進行比較。

 

正是由于上述的(de)複雜(zá)性,我花了(le)很長(cháng)時(shí)間才得(de)到了(le)一個(gè)簽名。不過,最終我找出了(le)簽名代碼中所有的(de)錯誤,并成功用(yòng)它簽署了(le)一筆交易。這(zhè)是我使用(yòng)的(de)簽名代碼:

 

def makeSignedTransaction(privateKey, outputTransactionHash, sourceIndex, scriptPubKey, outputs):    myTxn_forSig = (makeRawTransaction(outputTransactionHash, sourceIndex, scriptPubKey, outputs)         + "01000000") # hash code    s256 = hashlib.sha256(hashlib.sha256(myTxn_forSig.decode('hex')).digest()).digest()    sk = ecdsa.SigningKey.from_string(privateKey.decode('hex'), curve=ecdsa.SECP256k1)    sig = sk.sign_digest(s256, sigencode=ecdsa.util.sigencode_der) + '\01' # 01 is hashtype    pubKey = keyUtils.privateKeyToPublicKey(privateKey)    scriptSig = utils.varstr(sig).encode('hex') + utils.varstr(pubKey.decode('hex')).encode('hex')    signed_txn = makeRawTransaction(outputTransactionHash, sourceIndex, scriptSig, outputs)    verifyTxnSignature(signed_txn)    
   return signed2_txn

txnUtils.py

 

最終的(de)scriptSig腳本中包含簽名以及比特币源地址的(de)公鑰(1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5)。 這(zhè)證明(míng)這(zhè)筆交易有效,我可(kě)以花費這(zhè)些比特币。

 

PUSHDATA 47

47

signature(DER)

sequence

30

length

44

integer

02

length

20

X

2c b2 65 bf 10 70 7b f4 93 46 c3 51 5d d3 d1 6f c4 54 61 8c 58 ec 0a 0f f4 48 a6 76 c5 4f f7 13

integer

02

length

20

Y

6c 66 24 d7 62 a1 fc ef 46 18 28 4e ad 8f 08 67 8a c0 5b 13 c8 42 35 f1 65 4e 6a d1 68 23 3e 82

SIGHASH_ALL

01

PUSHDATA 41

41

public key

type

04

X

14 e3 01 b2 32 8f 17 44 2c 0b 83 10 d7 87 bf 3d 8a 40 4c fb d0 70 4f 13 5b 6a d4 b2 d3 ee 75 13

Y

10 f9 81 92 6e 53 a6 e8 c3 9b d7 d3 fe fd 57 6c 54 3c ce 49 3c ba c0 63 88 f2 65 1d 1a ac bf cd

   
   

 

最終的(de)scriptPubKey腳本包含成功花費比特币時(shí)必須執行的(de)腳本。需要注意的(de)是,這(zhè)個(gè)腳本将在未來(lái)花費這(zhè)些比特币的(de)時(shí)候執行。它包含以十六進制表示而不是以Base58Check表示的(de)目标地址1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa,腳本的(de)效果是隻有這(zhè)個(gè)目标地址的(de)私鑰所有者才能使用(yòng)比特币,因此目标地址實際上是這(zhè)些比特币的(de)所有者

 

OP_DUP

76

OP_HASH160

a9

PUSHDATA 14

14

public key hash

c8 e9 09 96 c7 c6 08 0e e0 62 84 60 0c 68 4e d9 04 d1 4c 5c

OP_EQUALVERIFY

88

OP_CHECKSIG

ac

 

最終的(de)交易

 

經過上述的(de)一系列操作,我們完成了(le)最終的(de)交易。但是,别忘了(le),此時(shí)的(de)交易還(hái)沒加入區(qū)塊鏈中,接收方還(hái)沒有收到你的(de)比特币。

 

privateKey = keyUtils.wifToPrivateKey("5HusYj2b2x4nroApgfvaSfKYZhRbKFH41bVyPooymbC6KfgSXdD") #1MMMM

signed_txn = txnUtils.makeSignedTransaction(privateKey,        

"81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48", # output (prev) transaction hash        0, # sourceIndex        
keyUtils.addrHashToScriptPubKey("1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5"),        [[91234, #satoshis        
keyUtils.addrHashToScriptPubKey("1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa")]]        )     txnUtils.verifyTxnSignature(signed_txn)
print'SIGNED TXN', signed_txn

makeTransaction.py

 

最終的(de)交易信息如下(xià)所示:

version

01 00 00 00

input count

01

input

previous output hash(reversed)

48 4d 40 d4 5b 9e a0 d6 52 fc a8 25 8a b7 ca a4 25 41 eb 52 97 58 57 f9 6f b5 0c d7 32 c8 b4 81

previous output index

00 00 00 00

script length

8a

scriptSig

47 30 44 02 20 2c b2 65 bf 10 70 7b f4 93 46 c3 51 5d d3 d1 6f c4 54 61 8c 58 ec 0a 0f f4 48 a6 76 c5 4f f7 13 02 20 6c 66 24 d7 62 a1 fc ef 46 18 28 4e ad 8f 08 67 8a c0 5b 13 c8 42 35 f1 65 4e 6a d1 68 23 3e 82 01 41 04 14 e3 01 b2 32 8f 17 44 2c 0b 83 10 d7 87 bf 3d 8a 40 4c fb d0 70 4f 13 5b 6a d4 b2 d3 ee 75 13 10 f9 81 92 6e 53 a6 e8 c3 9b d7 d3 fe fd 57 6c 54 3c ce 49 3c ba c0 63 88 f2 65 1d 1a ac bf cd

sequence

ff ff ff ff

output count

01

output

value

62 64 01 00 00 00 00 00

script length

19

scriptPubKey

76 a9 14 c8 e9 09 96 c7 c6 08 0e e0 62 84 60 0c 68 4e d9 04 d1 4c 5c 88 ac

block lock time

00 00 00 00

 

小插曲:橢圓曲線簽名

 

比特币的(de)簽名算(suàn)法使用(yòng)到了(le)橢圓曲線簽名算(suàn)法,這(zhè)麽實用(yòng)的(de)功能,你可(kě)能會好奇它是怎麽做(zuò)到的(de)?在當年英國數學家安德魯·懷爾斯攻克費馬大(dà)定理(lǐ)時(shí),我第一次接觸到了(le)橢圓曲線的(de)算(suàn)法。橢圓曲線的(de)數學思想很有意思,所以在這(zhè)裏我給大(dà)家做(zuò)一個(gè)快(kuài)速的(de)概述。

 

橢圓曲線這(zhè)個(gè)叫法令人(rén)迷惑,因爲橢圓曲線并不是橢圓,而且看起來(lái)也(yě)不像橢圓,甚至橢圓曲線與橢圓相關性都很少。通(tōng)俗地講,橢圓曲線就是滿足一個(gè)簡單方程y ^ 2 = x ^ 3 + ax + b的(de)曲線。比特币中使用(yòng)的(de)稱爲secp256k1的(de)橢圓曲線,它滿足的(de)方程爲y ^ 2 = x ^ 3 + 7。

 

 

secp256k1橢圓曲線

 

橢圓曲線的(de)一個(gè)重要特性就是你可(kě)以用(yòng)一個(gè)簡單的(de)規則來(lái)定義橢圓曲線上點的(de)相加:如果在曲線上繪制一條直線,這(zhè)條直線與曲線交與A,B,C三個(gè)點,那麽這(zhè)個(gè)加法定義爲A+B+C=0。由這(zhè)個(gè)加法的(de)定義,我們可(kě)以定義整數乘法:例如4A = A + A + A + A。

 

爲什(shén)麽橢圓曲線在密碼學上很有用(yòng)?因爲橢圓曲線做(zuò)整數乘法運算(suàn)速度很快(kuài),但做(zuò)除法時(shí)需要蠻力。例如,你可(kě)以快(kuài)速地計算(suàn)一個(gè)乘法12345678*A = Q,但是如果你隻知道A和(hé)Q,求解n*A=Q中的(de)n十分(fēn)困難。因此在橢圓曲線算(suàn)法中,這(zhè)裏的(de)12345678将是私鑰,曲線上的(de)點Q将是公鑰。

 

在密碼學中,點的(de)坐(zuò)标并不是它在曲線上的(de)實值點,而是對(duì)整數的(de)模數。橢圓曲線的(de)一個(gè)好用(yòng)的(de)特性就是對(duì)實數或模數進行運算(suàn)的(de)數學運算(suàn)幾乎相同。正因爲如此,比特币的(de)橢圓曲線并不像上面的(de)圖片,而是一團雜(zá)亂無章(zhāng)的(de)256位點集(想想在一個(gè)空間中充滿了(le)大(dà)量雜(zá)亂無章(zhāng)的(de)點)。

 

橢圓曲線數字簽名算(suàn)法(ECDSA)接收交易的(de)哈希值,使用(yòng)該交易數據,私鑰,以及一個(gè)随機數從橢圓曲線上生成一個(gè)新的(de)點,從而實現對(duì)交易的(de)簽名。任何擁有公鑰,交易數據,和(hé)簽名的(de)人(rén)都可(kě)以通(tōng)過做(zuò)一個(gè)簡單的(de)橢圓曲線運算(suàn)來(lái)驗證簽名的(de)有效性。讀到這(zhè)裏,你應該明(míng)白了(le)爲什(shén)麽隻有擁有私鑰的(de)人(rén)才能簽署消息,但擁有公鑰的(de)任何人(rén)都可(kě)以驗證該消息。

 

把交易發送到比特币網絡

 

回到交易中來(lái),别忘了(le)此時(shí)我們的(de)交易還(hái)沒有被加入到區(qū)塊鏈中,還(hái)不是一筆有效交易。剛剛我創建并簽署了(le)一筆交易。下(xià)一步就是将這(zhè)筆交易發送到比特币網絡中,網絡中的(de)礦工會收集交易并把它打包進區(qū)塊中。

 

如何找到比特币網絡的(de)節點

 

首先我要在比特币的(de)點對(duì)點網絡中找到一個(gè)節點。節點的(de)列表會随節點的(de)進出動态更新,當一個(gè)比特币節點連接到另一個(gè)節點時(shí),它們就會不斷交換彼此新發現的(de)比特币節點信息,因此,新節點加入的(de)消息會快(kuài)速地傳遍整個(gè)網絡。

 

然而,新的(de)比特币節點如何第一次找到比特币節點?這(zhè)是一個(gè)先有雞還(hái)是先有蛋的(de)問題。比特币節點通(tōng)過以下(xià)幾種方法來(lái)解決這(zhè)個(gè)問題。有幾個(gè)可(kě)信的(de)比特币節點會以bitseed.xf2.org的(de)域名在DNS系統(Domain Name System,域名系統,萬維網上作爲域名和(hé)IP地址相互映射的(de)一個(gè)分(fēn)布式數據庫)上注冊,通(tōng)過執行nslookup命令,你就可(kě)以得(de)到這(zhè)些節點的(de)IP地址,隻要有一個(gè)在工作即可(kě)。如果很不幸它們都沒有工作的(de)話(huà),你可(kě)以試著(zhe)連接那幾個(gè)已經在你的(de)客戶端中硬編碼記錄下(xià)來(lái)的(de)地址。

 

 

Nslookup命令可(kě)以用(yòng)來(lái)尋找比特币節點

 

當用(yòng)戶啓動或停止比特币客戶端時(shí),節點就會加入或離開比特币網絡。所以連接節點有很大(dà)的(de)不确定性,在我實驗時(shí),就遇到了(le)連接的(de)節點已經離開比特币網絡的(de)情況,如果你想重複我的(de)實驗,最好多(duō)找幾個(gè)節點,可(kě)能需要多(duō)次嘗試才能找到一個(gè)運行著(zhe)的(de)節點。

 

與比特币節點通(tōng)信

 

一旦獲得(de)了(le)一個(gè)正在工作的(de)比特币節點的(de)IP地址,當務之急就通(tōng)過這(zhè)個(gè)節點是把我的(de)交易發送到比特币的(de)點對(duì)點網絡中。使用(yòng)點對(duì)點的(de)網絡協議(yì)十分(fēn)簡單,我在端口8333上打開了(le)一個(gè)到任意對(duì)等端的(de)TCP連接,發送消息,然後接受反饋消息。比特币的(de)點對(duì)點協議(yì)對(duì)用(yòng)戶很友好,即使我的(de)請求數據出錯時(shí),還(hái)是繼續與我保持通(tōng)信。 

 

重要提示:正如一些人(rén)指出的(de)那樣,如果你想重複我的(de)實驗,切記要使用(yòng)比特币的(de)測試網絡,在測試網絡上,你可(kě)以使用(yòng)“虛拟”的(de)比特币來(lái)進行交易。因爲在真實網絡上,萬一你不小心,有可(kě)能會失去所有的(de)比特币。還(hái)記得(de)上面提到的(de)那個(gè)100個(gè)比特币轉賬1個(gè)的(de)交易麽,如果你忘了(le)将剩餘的(de)比特币轉給自己,那麽剩餘的(de)99個(gè)比特币就會作爲交易費支付給礦工。但是本著(zhe)科學的(de)态度,我并不在意在真實的(de)比特币網絡中損失我這(zhè)些價值1美(měi)元的(de)比特币。

 

協議(yì)中包含24種不同的(de)信息種類。每一條信息都是一個(gè)簡單的(de)二進制大(dà)對(duì)象(binary large object ,BLOB,是一個(gè)可(kě)以存儲二進制文件的(de)容器),其中包含一個(gè)ASCII命令和(hé)一個(gè)适用(yòng)該命令的(de)二進制有效參數。該協議(yì)可(kě)以在比特币的(de)維基上查詢。 

 

連接到比特币網絡的(de)第一步就是通(tōng)過交換客戶端版本信息來(lái)建立連接。首先,我發送了(le)一條客戶端版本信息,其中包含我的(de)協議(yì)版本号,IP地址和(hé)其他(tā)内容。比特币節點也(yě)向我回複了(le)它的(de)版本信息。在此之後,我應該回複一個(gè)verack信息(version acknowledgement,版本确認)來(lái)确認它的(de)版本信息。正如我所說,比特币點對(duì)點網絡協議(yì)對(duì)用(yòng)戶十分(fēn)友好,即使我跳過了(le)verack信息,之後的(de)操作也(yě)是一切正常。 

 

交換版本信息這(zhè)一步并不簡單,因爲信息具有标準的(de)格式,不過不用(yòng)害怕,可(kě)以用(yòng)幾行代碼來(lái)創建這(zhè)些信息。下(xià)面代碼段中的(de)makeMessage函數可(kě)以由随機數,命令名以及命令的(de)參數來(lái)生成一條消息。getVersionMessage函數通(tōng)過将各個(gè)字段打包在一起來(lái)爲版本消息創建參數。

 

magic = 0xd9b4bef9

def makeMessage(magic, command, payload):    checksum =
hashlib.sha256(hashlib.sha256(payload).digest()).digest()[0:4]    
   return struct.pack('L12sL4s', magic, command, len(payload), checksum) + payload
   
def getVersionMsg():    
   version = 60002    services = 1    timestamp = int(time.time())    addr_me = utils.netaddr(socket.inet_aton("127.0.0.1"), 8333)    addr_you = utils.netaddr(socket.inet_aton("127.0.0.1"), 8333)    nonce = random.getrandbits(64)    sub_version_num = utils.varstr('')    start_height = 0    payload = struct.pack('<LQQ26s26sQsL', version, services, timestamp, addr_me,        addr_you, nonce, sub_version_num, start_height)    
   return makeMessage(magic, 'version', payload)

msgUtils.py

 

發送交易tx

 

我使用(yòng)下(xià)面精簡的(de)Python代碼把我的(de)交易發送到比特币網絡中,這(zhè)個(gè)代碼發送一條客戶端版本信息,接受(也(yě)可(kě)以忽略)比特币節點的(de)版本信息和(hé)verack信息。最後将我的(de)交易以tx信息發送。代碼中這(zhè)個(gè)16進制的(de)字符串是我之前創建的(de)交易。

 

def getTxMsg(payload):  return makeMessage(magic, 'tx', payload) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("97.88.151.164", 8333)) sock.send(msgUtils.getVersionMsg()) sock.recv(1000) # receive version sock.recv(1000) # receive verack sock.send(msgUtils.getTxMsg("0100000001484d40d45b9ea0d652fca8258ab7caa42541eb52975857f96fb50cd732c8b481000000008a47304402202cb265bf10707bf49346c3515dd3d16fc454618c58ec0a0ff448a676c54ff71302206c6624d762a1fcef4618284ead8f08678ac05b13c84235f1654e6ad168233e8201410414e301b2328f17442c0b8310d787bf3d8a404cfbd0704f135b6ad4b2d3ee751310f981926e53a6e8c39bd7d3fefd576c543cce493cbac06388f2651d1aacbfcdffffffff0162640100000000001976a914c8e90996c7c6080ee06284600c684ed904d14c5c88ac00000000".decode('hex')))

minimalSendTxn.py

 

以下(xià)Wireshark(一個(gè)抓取,分(fēn)析網絡封包的(de)軟件)軟件的(de)截圖顯示出我是如何将交易發送到比特币網絡中的(de)。我用(yòng)Python編寫了(le)腳本來(lái)分(fēn)析網絡數據,爲了(le)簡單起見,在這(zhè)裏我使用(yòng)Wireshark。從圖中可(kě)以看到我的(de)這(zhè)筆tx交易。

 

 

 

Wireshark中抓取的(de)這(zhè)筆正在上傳至比特币網絡的(de)交易tx

 

爲了(le)實時(shí)監控我這(zhè)筆交易的(de)進度,我在比特币網絡中新運行了(le)一個(gè)節點,在把我交易發到比特币網絡5秒鐘(zhōng)之後,另一個(gè)節點給我發送了(le)這(zhè)個(gè)tx消息,其中包含我剛剛發送的(de)這(zhè)筆交易的(de)哈希,由此可(kě)見,在僅僅這(zhè)幾秒中,我的(de)交易已經傳遍了(le)比特币網絡,至少也(yě)是比特币網絡的(de)一部分(fēn)。

 

交易成功:我的(de)交易被加入區(qū)塊鏈

 

在将我的(de)交易發送比特币網絡之後,我需要等待它被礦工開采出來(lái)加入到區(qū)塊鏈中,然後才能宣稱我的(de)實驗圓滿成功。10分(fēn)鐘(zhōng)後,我的(de)比特币節點收到一條含有新區(qū)塊信息的(de)inv消息(參見下(xià)圖Wireshark抓到的(de)網絡封包),檢查這(zhè)個(gè)區(qū)塊後發現我的(de)交易被包含在了(le)區(qū)塊中,證明(míng)我的(de)交易是有效的(de),我的(de)實驗成功了(le)。通(tōng)過我的(de)比特币錢包軟件和(hé)在線查詢,再一次确認了(le)我已經交易成功。可(kě)以說,經過不斷的(de)努力,我成功手動創建了(le)一筆交易,并讓比特币系統接受了(le)它。(當然了(le),我也(yě)經過了(le)幾次失敗的(de)嘗試,這(zhè)些錯誤的(de)交易都消失在了(le)網絡之中,永遠(yuǎn)都不會被檢索到。

 

Wireshark中抓取的(de)新區(qū)塊産生的(de)封包信息

 

我的(de)交易是被當時(shí)哈希算(suàn)力(挖礦速度)最大(dà)的(de)礦池(多(duō)個(gè)礦工一起挖礦)GHash.IO挖出,區(qū)塊高(gāo)度爲279068,區(qū)塊哈希爲0000000000000001a27b1d6eb8c405410398ece796e742da3b3e35363c2219ee,在上圖Wireshark數據包中inv消息的(de)哈希值是經前後反轉得(de)到的(de)ee192……。你應該會發現區(qū)塊的(de)哈希值以大(dà)量的(de)0開頭,在一個(gè)16進制的(de)哈希值中發現一個(gè)以這(zhè)麽多(duō)0開頭的(de)數,這(zhè)就是爲什(shén)麽挖礦如此困難的(de)原因。這(zhè)個(gè)區(qū)塊中由462筆交易,我的(de)交易是其中之一。

高(gāo)度爲279068的(de)區(qū)塊以及我發起的(de)這(zhè)筆交易

(https://blockchain.info/block-index/341440/0000000000000001a27b1d6eb8c405410398ece796e742da3b3e35363c2219ee)

 

挖到這(zhè)個(gè)區(qū)塊的(de)礦工們收到了(le)25個(gè)比特币的(de)獎勵,交易費總共是0.104個(gè)比特币,按當時(shí)的(de)市價分(fēn)别爲19000美(měi)元和(hé)80美(měi)元。我支付了(le)0.0001個(gè)比特币的(de)交易費,大(dà)約是我交易額的(de)10%,按當時(shí)的(de)市價爲8美(měi)分(fēn)。

 

結論

 

手動進行比特币交易比我想象中困難得(de)多(duō),但是在這(zhè)個(gè)過程中我學到了(le)很多(duō),希望你也(yě)是。我的(de)Python代碼僅僅是爲了(le)介紹,如果你想跟我一樣用(yòng)Python手動進行比特币交易,也(yě)可(kě)以試試這(zhè)幾個(gè)項目。

 

https://en.bitcoin.it/wiki/Bitcoin-python

https://github.com/richardkiss/pycoin

https://github.com/jgarzik/python-bitcoinlib

 

 

寫在最後

2017年是區(qū)塊鏈的(de)井噴之年,經過一年的(de)積攢,2018年将迎來(lái)區(qū)塊鏈的(de)落地之年,區(qū)塊鏈會逐漸颠覆各行各業。對(duì)于個(gè)人(rén),區(qū)塊鏈的(de)機會會越來(lái)越多(duō),也(yě)許你錯過了(le)比特币的(de)投資,不妨現在抓住區(qū)塊鏈這(zhè)個(gè)風口,投資自己,多(duō)學習(xí)相關知識,區(qū)塊鏈大(dà)有可(kě)爲,投身區(qū)塊鏈的(de)你将大(dà)有作爲!

*聲明(míng):推送内容及圖片來(lái)源于網絡,部分(fēn)内容會有所改動,版權歸原作者所有,如來(lái)源信息有誤或侵犯權益,請聯系我們删除或授權事宜。