天天躁日日躁狠狠很躁,色又黄又爽18禁免费网站,与丰满少妇做爽视频,国内精品一线二线三线黄

一文看懂怎樣用 Python 創(chuàng)建比特幣交易

2018-04-04 15:20

 

比特幣價(jià)格的上上下下,始終撩動(dòng)著每一個(gè)人無(wú)比關(guān)切的小心臟。從去年初的 800 美元左右,飛漲到去年底到 19783.21 美元最高點(diǎn),不到1年,便有將近 25 倍的升值速度。盡管眼下又掉回 8000 多美元的價(jià)格,但價(jià)格差不多能搞出去年同期一個(gè)數(shù)量級(jí),幣圈人士“過(guò)去一年比以往 10 年掙的都多”,已經(jīng)是不爭(zhēng)的事實(shí)。

而對(duì)區(qū)塊鏈開(kāi)發(fā)者來(lái)說(shuō),據(jù)說(shuō)也已經(jīng)有拿到年新 500 萬(wàn)的天價(jià)。所以“跑步進(jìn)入?yún)^(qū)塊鏈”,已經(jīng)成為不少程序員的共識(shí)。但是看過(guò)很多遠(yuǎn)離,我們?nèi)绾尾拍苎杆偕鲜帜兀繃?guó)外網(wǎng)友 Ken Shirriff 在博客中分享了他在手動(dòng)茶古劍比特幣交易時(shí)的代碼與對(duì)比特幣協(xié)議的心得,區(qū)塊鏈大本營(yíng)編譯如下。

 

近期,媒體行業(yè)對(duì)比特幣表現(xiàn)出極大的熱情,這鼓舞著我從網(wǎng)絡(luò)底層的數(shù)據(jù)流開(kāi)始,認(rèn)真學(xué)習(xí)比特幣的工作原理。通常人們會(huì)使用錢(qián)包軟件來(lái)進(jìn)行比特幣交易,錢(qián)包軟件在方便用戶的同時(shí),向用戶隱藏了比特幣的交易流程,而我想親自動(dòng)手來(lái)體驗(yàn)比特幣交易,我的目標(biāo)是用Python手動(dòng)創(chuàng)建一筆比特幣交易,以十六進(jìn)制數(shù)據(jù)的形式將交易廣播到比特幣網(wǎng)絡(luò)中,然后觀察這筆交易是怎么被加入到區(qū)塊鏈中的。事實(shí)證明,這個(gè)過(guò)程很有趣,希望你也對(duì)它感興趣。

 

在本篇文章中,首先我會(huì)對(duì)比特幣進(jìn)行一個(gè)簡(jiǎn)單的概述,之后,我會(huì)從以下幾個(gè)方面帶領(lǐng)你們學(xué)習(xí)比特幣:創(chuàng)建一個(gè)比特幣地址(比特幣中的賬戶),進(jìn)行一筆比特幣交易,簽署交易,將交易廣播到比特幣網(wǎng)絡(luò)中,最后等待交易的確認(rèn)。

 

比特幣簡(jiǎn)述:

 

首先,我會(huì)介紹一下比特幣系統(tǒng)是怎么運(yùn)轉(zhuǎn)的,然后再深入探討整個(gè)細(xì)節(jié)。比特幣是一個(gè)基于點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)的電子貨幣,你可以用現(xiàn)金在網(wǎng)上購(gòu)買(mǎi)比特幣,用比特幣向他人轉(zhuǎn)賬,在有些商家,你可以像使用支付寶一樣使用比特幣付款,當(dāng)然,你也可以賣(mài)出所持有的比特幣換回現(xiàn)金。

 

簡(jiǎn)而言之,在比特幣網(wǎng)絡(luò)中,分布式賬本(區(qū)塊鏈)記錄并隨時(shí)更新著每個(gè)比特幣的所有權(quán)。與銀行不同的是,比特幣并沒(méi)有與個(gè)人或個(gè)人的賬戶綁定,相反的,比特幣只屬于一個(gè)個(gè)比特幣地址,比如:1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa。這里你可能已經(jīng)繞暈了,難道這段字符中藏著比特幣?當(dāng)然不是,比特幣地址是比特幣網(wǎng)絡(luò)中的一個(gè)身份,也可以通俗地說(shuō)是你在比特幣中開(kāi)的一個(gè)“銀行賬戶”,我們用這個(gè)“賬戶”來(lái)進(jìn)行交易。在網(wǎng)站:blockchain.info中,你可以查到所有的交易信息:

 

?比特幣賬戶信息

 

但是怎么證明這個(gè)賬戶是我的呢,不急,先往下看,你的疑問(wèn)我會(huì)為你一一解答。

 

比特幣交易

 

如何像使用現(xiàn)金一樣使用比特幣呢?答案是創(chuàng)建一筆交易。在一筆交易中,比特幣的所有者(上文提到過(guò)比特幣的所有者是比特幣地址)將所有權(quán)轉(zhuǎn)移到一個(gè)新的比特幣地址。比特幣的一個(gè)顛覆性創(chuàng)新就是通過(guò)鼓勵(lì)節(jié)點(diǎn)記賬(也叫礦工挖礦),將交易記錄放在一個(gè)分布式的數(shù)據(jù)庫(kù)中。交易被集合在區(qū)塊中,大概每十分鐘比特幣網(wǎng)絡(luò)中產(chǎn)生一個(gè)新的區(qū)塊,成為交易記錄的一部分,稱(chēng)為區(qū)塊鏈。加入到區(qū)塊鏈中的交易可以被認(rèn)為是一筆成功的交易?,F(xiàn)在問(wèn)題來(lái)了,誰(shuí)來(lái)給你記賬呢?是礦工,礦工的挖礦過(guò)程就是在往區(qū)塊鏈中記賬,礦工要核實(shí)每筆交易是否正確,核實(shí)完后,礦工們就開(kāi)始算一道很難的數(shù)學(xué)題(密碼學(xué)中的哈希函數(shù)),最早算出答案的人就能生成一個(gè)區(qū)塊,也叫挖出了一個(gè)新的區(qū)塊,這個(gè)區(qū)塊將成為區(qū)塊鏈的新一部分。

 

也許你會(huì)問(wèn)了,明明是記賬,干著會(huì)計(jì)的活,為什么要叫挖礦呢?和傳統(tǒng)的在地下挖礦石一樣,比特幣挖礦也是會(huì)有收獲的。挖礦是一種新發(fā)行比特幣的過(guò)程,當(dāng)前,每挖到一個(gè)礦,礦工會(huì)得到系統(tǒng)獎(jiǎng)勵(lì)的12.5個(gè)比特幣,按目前一個(gè)比特幣接近一萬(wàn)美元的市價(jià),這就是一筆12.5萬(wàn)美元的巨款。此外,礦工還可以獲得本區(qū)塊中所有的交易費(fèi),舉例來(lái)說(shuō),在高度為512587的區(qū)塊中,幸運(yùn)的礦工總共收獲了12.829個(gè)比特幣。正因如此,礦工之間的競(jìng)爭(zhēng)十分激烈,采礦的難度與礦工間激烈的競(jìng)爭(zhēng)是比特幣安全的重要保證,因?yàn)檫@樣可以保證沒(méi)有壞人能操縱系統(tǒng)。

 

點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)

 

比特幣并沒(méi)有一個(gè)中央服務(wù)器,相反,比特幣在一個(gè)點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)中運(yùn)行。如果你運(yùn)行一個(gè)比特幣節(jié)點(diǎn),那你就成了網(wǎng)絡(luò)的一部分。比特幣網(wǎng)絡(luò)中的節(jié)點(diǎn)彼此交換自己存儲(chǔ)的交易,區(qū)塊,以及IP地址信息(用于節(jié)點(diǎn)間建立連接互相通信)。當(dāng)你第一次連接到比特幣網(wǎng)絡(luò),你的節(jié)點(diǎn)會(huì)從隨機(jī)挑選的節(jié)點(diǎn)中下載區(qū)塊鏈的信息。反過(guò)來(lái),你的節(jié)點(diǎn)也會(huì)向后加入者提供信息。當(dāng)你要?jiǎng)?chuàng)建一筆比特幣交易時(shí),你要把這筆交易發(fā)送給一些節(jié)點(diǎn),這些節(jié)點(diǎn)會(huì)在比特幣網(wǎng)絡(luò)中廣播這筆交易,直到全網(wǎng)都收到這筆交易。礦工們會(huì)收集你的交易信息,生成一個(gè)含有你這筆交易的區(qū)塊,向全網(wǎng)廣播,這時(shí),你的節(jié)點(diǎn)也會(huì)收到這個(gè)區(qū)塊信息,通過(guò)驗(yàn)證,這筆交易被加入到了區(qū)塊鏈中,你就交易成功了。 

 

加密技術(shù)

 

現(xiàn)在回到證明比特幣賬戶是誰(shuí)的這個(gè)問(wèn)題。比特幣使用數(shù)字簽名技術(shù)以確保只有比特幣賬戶的所有者才能使用賬戶中的比特幣。比特幣地址的所有者擁有與該地址相匹配的私鑰,當(dāng)花費(fèi)比特幣時(shí),你用要這個(gè)私鑰在交易上簽名,證明自己是這個(gè)賬戶的所有者。這有點(diǎn)像現(xiàn)實(shí)生活中的蓋章,蓋章就意味著授權(quán)。怎么驗(yàn)證呢,公鑰與比特幣賬戶相關(guān)聯(lián),用公鑰就可以驗(yàn)證簽名是否正確。這樣就解決了比特幣賬戶是誰(shuí)的這個(gè)問(wèn)題。

 

怎么來(lái)區(qū)分不同的交易呢?交易和區(qū)塊都使用密碼學(xué)上的哈希值進(jìn)行索引,是不是有點(diǎn)耳熟,對(duì),在比特幣協(xié)議中,多處使用到了哈希函數(shù),礦工們剛才算的數(shù)學(xué)題就是在算哈希函數(shù)。

 

比特幣協(xié)議探究

 

在接下來(lái)的文章里,我將逐步介紹我是怎樣手動(dòng)進(jìn)行一次比特幣交易的。首先,我生成了一個(gè)比特幣賬戶以及對(duì)應(yīng)的公鑰,私鑰。接下來(lái)我發(fā)起了一筆比特幣交易,我向這個(gè)新生成的賬戶轉(zhuǎn)了一小筆比特幣。期間手動(dòng)簽署這筆交易很困難,它花費(fèi)了我很多的時(shí)間。最后,我將這筆交易發(fā)送到比特幣網(wǎng)絡(luò),等待它被加入?yún)^(qū)塊鏈。本文的其余部分會(huì)詳細(xì)地介紹這些步驟。

 

事實(shí)證明,手動(dòng)進(jìn)行比特幣交易比我想象中的更加困難。正如你所看到的,比特幣的協(xié)議有些許混亂:它使用了大端格式數(shù)字(高位編址,將高序字節(jié)存儲(chǔ)在起始地址),小端格式數(shù)字(低位編址,將低序字節(jié)存儲(chǔ)在起始位置),固定長(zhǎng)度數(shù)字,可變長(zhǎng)度數(shù)字,自定義編碼格式,DER編碼格式以及各種加密算法。因此,僅僅是將數(shù)據(jù)轉(zhuǎn)換為正確的格式就浪費(fèi)了很多時(shí)間。

 

我遇到的第二個(gè)難題就是加密,嘗試一下手動(dòng)加密,你就會(huì)發(fā)現(xiàn)密碼學(xué)對(duì)人們多不友好,甚至可以說(shuō)是無(wú)情。即使你只輸錯(cuò)了一個(gè)字節(jié),交易就會(huì)因出錯(cuò)被拒絕,而且它不會(huì)告訴你哪里出錯(cuò)了,你只能重來(lái)。

 

最后,手動(dòng)簽署交易的過(guò)程也比想象中難得多,簽署交易時(shí)每個(gè)環(huán)節(jié)都必須零失誤,要么又要退回重來(lái)。

 

比特幣地址和密鑰

 

第一步,我創(chuàng)建了一個(gè)比特幣地址。通常情況下,人們都是使用比特幣客戶端軟件來(lái)創(chuàng)建比特幣地址和與之相關(guān)的密鑰。本著學(xué)習(xí)的態(tài)度,我寫(xiě)了一些Python代碼來(lái)生成比特幣地址,從而揭示地址創(chuàng)建的機(jī)理。

 

比特幣使用了一系列的密鑰和地址,下圖解釋了它們的關(guān)系。首先你要?jiǎng)?chuàng)建一個(gè)隨機(jī)的256位的私鑰,這個(gè)私鑰用于在花費(fèi)比特幣時(shí)簽署交易。因此,私鑰必須保密,否則你的比特幣可能會(huì)被盜用。

 

橢圓曲線數(shù)字簽名算法(Elliptic Curve Digital Signature Algorithm,ECDSA,美國(guó)政府的標(biāo)準(zhǔn),接下來(lái)我們會(huì)討論它)會(huì)從私鑰中生成一個(gè)512位的公鑰,這個(gè)公鑰用于驗(yàn)證交易的簽名。但不方便的是,比特幣協(xié)議中需要在這個(gè)公鑰上添加了前綴04,這個(gè)公鑰在交易簽署之前不會(huì)被泄露,不像其它系統(tǒng)中公鑰就是為了公之于眾的。

 

比特幣地址與公鑰的關(guān)系

 

下一步就是生成與他人交易時(shí)使用的比特幣地址了。512位的公鑰太長(zhǎng)不方便使用,因此使用SHA-256和RIPEMD哈希算法將其縮小為160位。然后使用比特幣定義的Base58Check 編碼將密鑰編碼為ASCII(American Standard Code for Information Interchange,美國(guó)信息交換標(biāo)準(zhǔn)代碼)格式。得到的地址(例如上文中的:1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa)就是你接收別人比特幣時(shí)要發(fā)布的地址。需要注意的是,你無(wú)法從比特幣地址中復(fù)原出公鑰或私鑰。如果你丟失了你的私鑰(比如說(shuō)你把私鑰存在你的硬盤(pán)上,但硬盤(pán)丟失),你的比特幣將永遠(yuǎn)丟失。

 

最后,錢(qián)包交換格式密鑰(WIF)用于將私鑰添加到你的錢(qián)包軟件中,這只是將私鑰進(jìn)行Base58Check編碼轉(zhuǎn)換為ASCII格式,這一步是可逆的,而且很容易經(jīng)過(guò)逆變換恢復(fù)出256位的私鑰。(圖中有我的私鑰,我很好奇是否有人會(huì)用我的私鑰去偷(通過(guò)私鑰簽署交易,從而轉(zhuǎn)走)我那價(jià)值80美分的比特幣,然而真有人那么做了,可以在

https://blockchain.info/address/1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa 看到,也算是為教學(xué)做貢獻(xiàn)了。)

 

總之,共有三種密鑰:私鑰,公鑰,公鑰的哈希值,經(jīng)過(guò)使用Base58Check編碼,它們對(duì)外都是以ASCII格式表示。私鑰是其中最重要的密鑰,因?yàn)榛ㄙM(fèi)比特幣時(shí)需要私鑰簽署交易,而且其他的密鑰都可以從私鑰中產(chǎn)生。公鑰的哈希值就是你們剛看的的比特幣地址。

 

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

 

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

 

從內(nèi)部分析一筆交易

 

交易是比特幣系統(tǒng)的基本操作,也許你會(huì)認(rèn)為交易就是簡(jiǎn)單地把比特幣從一個(gè)地址轉(zhuǎn)移到另一個(gè)地址,但交易其實(shí)并不簡(jiǎn)單。一筆交易包含一個(gè)或多個(gè)輸入和輸出,交易中的每個(gè)輸入的地址都提供比特幣,每個(gè)輸出的地址都接受比特幣。

 

一筆簡(jiǎn)單的比特幣交易,交易C花費(fèi)了從交易A和交易B獲得的0.008個(gè)比特幣,其中0.001個(gè)比特幣被當(dāng)作交易費(fèi)付給礦工

 

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

 

在一筆交易中,輸入的比特幣地址必須花出所有的比特幣,假如你在之前的交易收到了100個(gè)比特幣,但你只想花1個(gè)比特幣,創(chuàng)建這筆交易你必須花完所有的100個(gè)比特幣,那剩下的99個(gè)比特幣怎么辦呢?解決方案就是在交易中再增加一個(gè)輸出,將剩余的99個(gè)比特幣轉(zhuǎn)給自己。這樣你就可以花費(fèi)任意數(shù)額的比特幣。 

 

通常交易要支付交易費(fèi),如果一筆交易中輸入的比特幣總和大于輸出的比特幣的總和,剩余的費(fèi)用就是給礦工的交易費(fèi)。這筆費(fèi)用并沒(méi)有明確要求,但是對(duì)于礦工而言,沒(méi)有交易費(fèi)的交易就會(huì)被列為低優(yōu)先級(jí)交易,可能要等上幾天才會(huì)被處理甚至被礦工直接丟棄。交易費(fèi)通常并不高,但它可能影響著你的交易。

 

手動(dòng)創(chuàng)建一筆交易

 

如下圖所示,在我的實(shí)驗(yàn)中我發(fā)起了一筆只有一個(gè)輸入一個(gè)輸出的交易。我在Coinbase上買(mǎi)了一些比特幣,并將0.00101234個(gè)比特幣放入地址:

1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5中,這筆交易哈希為:

81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48,我的目標(biāo)是創(chuàng)建一筆交易,將這些比特幣轉(zhuǎn)入我的另一個(gè)地址:

1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa,扣除0.0001個(gè)比特幣的交易費(fèi)后,目標(biāo)地址將獲得0.00091234個(gè)比特幣。

比特幣交易結(jié)構(gòu)實(shí)例

 

? Blockchain.info上的交易記錄

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

 

按照協(xié)議標(biāo)準(zhǔn),創(chuàng)建這筆交易很簡(jiǎn)單。如下表所示,這筆交易只有一個(gè)輸入,源自于81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48中的輸出0(第一個(gè)輸出)。輸出為0.00091234個(gè)比特幣(91234在十六進(jìn)制中用0x016462表示),它以小端格式存儲(chǔ)在值區(qū)域中。加密過(guò)程中的scriptSig和scriptPubKey較為復(fù)雜,我們稍后再做討論。

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

這是我生成交易使用的代碼,這段代碼只是把數(shù)據(jù)打包成二進(jìn)制文件。簽署交易較為困難,我們等一會(huì)兒再說(shuō)。

 


 

# 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

 

比特幣交易怎樣簽署

 

下圖為我們簡(jiǎn)單描述了交易是如何簽署并相互連接的。針對(duì)中間這筆從比特幣地址B轉(zhuǎn)賬到比特幣地址C的交易。交易的內(nèi)容(包括前一個(gè)交易的哈希值(索引))被進(jìn)行哈希計(jì)算并用B的私鑰簽名。另外,B的公鑰也被包含在了交易中。 

 

通過(guò)執(zhí)行幾個(gè)簡(jiǎn)單運(yùn)算,任何人都能驗(yàn)證B是否簽署了這筆交易。首先,B的公鑰與之前收到這筆比特幣交易的地址做驗(yàn)證,證明B的公鑰有效。(正如前面所說(shuō)的,地址很容易從公鑰中計(jì)算獲得)。接下來(lái),可以通過(guò)B的公鑰驗(yàn)證B交易簽名的真?zhèn)?。這些步驟能確保交易的有效性和交易得到B的授權(quán)。比特幣于眾不同的一點(diǎn)是,B的公鑰在B發(fā)起交易之前是不公開(kāi)的。 

 

在比特幣系統(tǒng)中,比特幣通過(guò)區(qū)塊鏈上的一筆筆交易在不同的地址間傳遞。區(qū)塊鏈上的每一筆交易都能被驗(yàn)證以確保比特幣交易的有效性。

 

比特幣腳本語(yǔ)言

 

你可能會(huì)以為僅僅通過(guò)在交易內(nèi)容中附上簽名就可以簽署比特幣交易,其實(shí)不然,這個(gè)過(guò)程十分復(fù)雜。實(shí)際上,每一筆交易中都包含一個(gè)“小程序”,用于確認(rèn)交易是否有效。這個(gè)“小程序”用腳本語(yǔ)言寫(xiě)成,通過(guò)這種基于堆棧的比特幣腳本語(yǔ)言,我們可以應(yīng)對(duì)許多復(fù)雜的比特幣支付場(chǎng)景。例如,托管系統(tǒng)可以設(shè)定只要經(jīng)過(guò)三分之二的用戶授權(quán),就可執(zhí)行交易的規(guī)則,也可以設(shè)置其他的合約。 

 

腳本語(yǔ)言十分復(fù)雜,大約有80種操作碼,包括算數(shù)計(jì)算,按位操作,字符串處理,條件語(yǔ)句和堆棧操作。腳本語(yǔ)言也包含一些必要的密碼學(xué)操作(SHA-256,RIPEMD等等)作為原語(yǔ)(原語(yǔ)是執(zhí)行過(guò)程中不可被打斷的基本操作,你可以理解為一段代碼)。為了確保腳本語(yǔ)言可以運(yùn)行完畢自動(dòng)退出,該語(yǔ)言不支持任何循環(huán)操作,因此它不是圖靈完備的。然而,實(shí)際上,它只支持少數(shù)類(lèi)型的交易。 

 

前一個(gè)交易中的腳本稱(chēng)為scriptPubKey,當(dāng)前交易中的腳本稱(chēng)為scriptSig。要驗(yàn)證交易時(shí),先執(zhí)行scriptSig,然后再執(zhí)行scriptPubKey。如果兩個(gè)腳本都成功執(zhí)行,交易就被認(rèn)定為有效,交易中的比特幣就可以成功花出。否則,交易無(wú)效。要注意的是前一個(gè)交易中的scriptPubKey規(guī)定了花費(fèi)比特幣的條件,當(dāng)前交易的scriptSig必須滿足這個(gè)條件。 

 

在一個(gè)標(biāo)準(zhǔn)的交易中,scriptSig腳本將從私鑰中生成的簽名并壓入堆棧中,再壓入公鑰。接下來(lái)scriptPubKey腳本會(huì)執(zhí)行運(yùn)算先驗(yàn)證公鑰的有效性,再驗(yàn)證簽名的有效性。

 

正如腳本中所表示,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

 

當(dāng)這段代碼執(zhí)行時(shí),PUSHDATA操作首先會(huì)把簽名壓入堆棧,接著把公鑰壓入堆棧。OPHASH-160操作計(jì)算公鑰的160位哈希值,PUSHDATA操作再把交易中的輸入地址(輸入賬號(hào))壓入堆棧,然后,OP-EQUALVERIFY操作驗(yàn)證驗(yàn)證前兩個(gè)堆棧中的值是否相等(驗(yàn)證這筆交易中你使用的比特幣是否屬于你自己)-如果公鑰的哈希等于之前交易中的輸出地址,這就證明公鑰是有效的(證明這個(gè)比特幣是你的)。最后,OP_CHECKSIG操作將檢查交易的簽名是否與堆棧里的公鑰和簽名匹配,匹配就證明簽名是有效的(證明交易的到了你的授權(quán))

 

簽署交易

 

我發(fā)現(xiàn)簽署這筆交易是手動(dòng)使用比特幣時(shí)最難的地方,這一過(guò)程出奇地困難且容易出錯(cuò)。簽名的基本思想很簡(jiǎn)單,使用橢圓曲線簽名算法和私鑰來(lái)生成交易的數(shù)字簽名,但細(xì)節(jié)非常棘手。簽署交易的過(guò)程可以通過(guò)這19個(gè)步驟描述。

 

 

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

 

對(duì)交易的簽名讓我面臨巨大的挑戰(zhàn),這涉及到一個(gè)如何在交易內(nèi)容中還沒(méi)有加入簽名時(shí)簽署這筆交易的問(wèn)題。為了避免這個(gè)問(wèn)題,在計(jì)算生成簽名之前,我把scriptPubKey這個(gè)腳本從上一筆交易復(fù)制到當(dāng)前交易中(當(dāng)前這筆交易正在被簽署),然后將簽名轉(zhuǎn)換為腳本語(yǔ)言的代碼,創(chuàng)建嵌入在當(dāng)前交易中的scriptSig腳本。對(duì)于具有多個(gè)輸入的交易,簽署交易環(huán)節(jié)更加復(fù)雜,因?yàn)槊總€(gè)輸入都需要單獨(dú)的簽名,這里我就不做詳細(xì)討論了。

 

哈希值這一步驟難倒了我。在簽名之前,交易中有一個(gè)臨時(shí)附加的哈希值常量。對(duì)于常規(guī)的交易,這個(gè)值是SIGHASH_ALL(0x00000001)。簽名后,這個(gè)哈希值將從交易內(nèi)容的最后刪除,附加到scriptSig腳本中。

 

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

 

由于ECDSA算法需要使用隨機(jī)數(shù),所以調(diào)試簽名十分困難。每次計(jì)算出的簽名都會(huì)有所不同,因此無(wú)法與已知正確的簽名進(jìn)行比較。

 

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

 

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

 

最終的scriptSig腳本中包含簽名以及比特幣源地址的公鑰(1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5)。 這證明這筆交易有效,我可以花費(fèi)這些比特幣。

 

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

   
   

 

最終的scriptPubKey腳本包含成功花費(fèi)比特幣時(shí)必須執(zhí)行的腳本。需要注意的是,這個(gè)腳本將在未來(lái)花費(fèi)這些比特幣的時(shí)候執(zhí)行。它包含以十六進(jìn)制表示而不是以Base58Check表示的目標(biāo)地址1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa,腳本的效果是只有這個(gè)目標(biāo)地址的私鑰所有者才能使用比特幣,因此目標(biāo)地址實(shí)際上是這些比特幣的所有者

 

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

 

最終的交易

 

經(jīng)過(guò)上述的一系列操作,我們完成了最終的交易。但是,別忘了,此時(shí)的交易還沒(méi)加入?yún)^(qū)塊鏈中,接收方還沒(méi)有收到你的比特幣。

 

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

 

最終的交易信息如下所示:

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

 

小插曲:橢圓曲線簽名

 

比特幣的簽名算法使用到了橢圓曲線簽名算法,這么實(shí)用的功能,你可能會(huì)好奇它是怎么做到的?在當(dāng)年英國(guó)數(shù)學(xué)家安德魯·懷爾斯攻克費(fèi)馬大定理時(shí),我第一次接觸到了橢圓曲線的算法。橢圓曲線的數(shù)學(xué)思想很有意思,所以在這里我給大家做一個(gè)快速的概述。

 

橢圓曲線這個(gè)叫法令人迷惑,因?yàn)闄E圓曲線并不是橢圓,而且看起來(lái)也不像橢圓,甚至橢圓曲線與橢圓相關(guān)性都很少。通俗地講,橢圓曲線就是滿足一個(gè)簡(jiǎn)單方程y ^ 2 = x ^ 3 + ax + b的曲線。比特幣中使用的稱(chēng)為secp256k1的橢圓曲線,它滿足的方程為y ^ 2 = x ^ 3 + 7。

 

 

secp256k1橢圓曲線

 

橢圓曲線的一個(gè)重要特性就是你可以用一個(gè)簡(jiǎn)單的規(guī)則來(lái)定義橢圓曲線上點(diǎn)的相加:如果在曲線上繪制一條直線,這條直線與曲線交與A,B,C三個(gè)點(diǎn),那么這個(gè)加法定義為A+B+C=0。由這個(gè)加法的定義,我們可以定義整數(shù)乘法:例如4A = A + A + A + A。

 

為什么橢圓曲線在密碼學(xué)上很有用?因?yàn)闄E圓曲線做整數(shù)乘法運(yùn)算速度很快,但做除法時(shí)需要蠻力。例如,你可以快速地計(jì)算一個(gè)乘法12345678*A = Q,但是如果你只知道A和Q,求解n*A=Q中的n十分困難。因此在橢圓曲線算法中,這里的12345678將是私鑰,曲線上的點(diǎn)Q將是公鑰。

 

在密碼學(xué)中,點(diǎn)的坐標(biāo)并不是它在曲線上的實(shí)值點(diǎn),而是對(duì)整數(shù)的模數(shù)。橢圓曲線的一個(gè)好用的特性就是對(duì)實(shí)數(shù)或模數(shù)進(jìn)行運(yùn)算的數(shù)學(xué)運(yùn)算幾乎相同。正因?yàn)槿绱?,比特幣的橢圓曲線并不像上面的圖片,而是一團(tuán)雜亂無(wú)章的256位點(diǎn)集(想想在一個(gè)空間中充滿了大量雜亂無(wú)章的點(diǎn))。

 

橢圓曲線數(shù)字簽名算法(ECDSA)接收交易的哈希值,使用該交易數(shù)據(jù),私鑰,以及一個(gè)隨機(jī)數(shù)從橢圓曲線上生成一個(gè)新的點(diǎn),從而實(shí)現(xiàn)對(duì)交易的簽名。任何擁有公鑰,交易數(shù)據(jù),和簽名的人都可以通過(guò)做一個(gè)簡(jiǎn)單的橢圓曲線運(yùn)算來(lái)驗(yàn)證簽名的有效性。讀到這里,你應(yīng)該明白了為什么只有擁有私鑰的人才能簽署消息,但擁有公鑰的任何人都可以驗(yàn)證該消息。

 

把交易發(fā)送到比特幣網(wǎng)絡(luò)

 

回到交易中來(lái),別忘了此時(shí)我們的交易還沒(méi)有被加入到區(qū)塊鏈中,還不是一筆有效交易。剛剛我創(chuàng)建并簽署了一筆交易。下一步就是將這筆交易發(fā)送到比特幣網(wǎng)絡(luò)中,網(wǎng)絡(luò)中的礦工會(huì)收集交易并把它打包進(jìn)區(qū)塊中。

 

如何找到比特幣網(wǎng)絡(luò)的節(jié)點(diǎn)

 

首先我要在比特幣的點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)中找到一個(gè)節(jié)點(diǎn)。節(jié)點(diǎn)的列表會(huì)隨節(jié)點(diǎn)的進(jìn)出動(dòng)態(tài)更新,當(dāng)一個(gè)比特幣節(jié)點(diǎn)連接到另一個(gè)節(jié)點(diǎn)時(shí),它們就會(huì)不斷交換彼此新發(fā)現(xiàn)的比特幣節(jié)點(diǎn)信息,因此,新節(jié)點(diǎn)加入的消息會(huì)快速地傳遍整個(gè)網(wǎng)絡(luò)。

 

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

 

 

Nslookup命令可以用來(lái)尋找比特幣節(jié)點(diǎn)

 

當(dāng)用戶啟動(dòng)或停止比特幣客戶端時(shí),節(jié)點(diǎn)就會(huì)加入或離開(kāi)比特幣網(wǎng)絡(luò)。所以連接節(jié)點(diǎn)有很大的不確定性,在我實(shí)驗(yàn)時(shí),就遇到了連接的節(jié)點(diǎn)已經(jīng)離開(kāi)比特幣網(wǎng)絡(luò)的情況,如果你想重復(fù)我的實(shí)驗(yàn),最好多找?guī)讉€(gè)節(jié)點(diǎn),可能需要多次嘗試才能找到一個(gè)運(yùn)行著的節(jié)點(diǎn)。

 

與比特幣節(jié)點(diǎn)通信

 

一旦獲得了一個(gè)正在工作的比特幣節(jié)點(diǎn)的IP地址,當(dāng)務(wù)之急就通過(guò)這個(gè)節(jié)點(diǎn)是把我的交易發(fā)送到比特幣的點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)中。使用點(diǎn)對(duì)點(diǎn)的網(wǎng)絡(luò)協(xié)議十分簡(jiǎn)單,我在端口8333上打開(kāi)了一個(gè)到任意對(duì)等端的TCP連接,發(fā)送消息,然后接受反饋消息。比特幣的點(diǎn)對(duì)點(diǎn)協(xié)議對(duì)用戶很友好,即使我的請(qǐng)求數(shù)據(jù)出錯(cuò)時(shí),還是繼續(xù)與我保持通信。 

 

重要提示:正如一些人指出的那樣,如果你想重復(fù)我的實(shí)驗(yàn),切記要使用比特幣的測(cè)試網(wǎng)絡(luò),在測(cè)試網(wǎng)絡(luò)上,你可以使用“虛擬”的比特幣來(lái)進(jìn)行交易。因?yàn)樵谡鎸?shí)網(wǎng)絡(luò)上,萬(wàn)一你不小心,有可能會(huì)失去所有的比特幣。還記得上面提到的那個(gè)100個(gè)比特幣轉(zhuǎn)賬1個(gè)的交易么,如果你忘了將剩余的比特幣轉(zhuǎn)給自己,那么剩余的99個(gè)比特幣就會(huì)作為交易費(fèi)支付給礦工。但是本著科學(xué)的態(tài)度,我并不在意在真實(shí)的比特幣網(wǎng)絡(luò)中損失我這些價(jià)值1美元的比特幣。

 

協(xié)議中包含24種不同的信息種類(lèi)。每一條信息都是一個(gè)簡(jiǎn)單的二進(jìn)制大對(duì)象(binary large object ,BLOB,是一個(gè)可以存儲(chǔ)二進(jìn)制文件的容器),其中包含一個(gè)ASCII命令和一個(gè)適用該命令的二進(jìn)制有效參數(shù)。該協(xié)議可以在比特幣的維基上查詢。 

 

連接到比特幣網(wǎng)絡(luò)的第一步就是通過(guò)交換客戶端版本信息來(lái)建立連接。首先,我發(fā)送了一條客戶端版本信息,其中包含我的協(xié)議版本號(hào),IP地址和其他內(nèi)容。比特幣節(jié)點(diǎn)也向我回復(fù)了它的版本信息。在此之后,我應(yīng)該回復(fù)一個(gè)verack信息(version acknowledgement,版本確認(rèn))來(lái)確認(rèn)它的版本信息。正如我所說(shuō),比特幣點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)協(xié)議對(duì)用戶十分友好,即使我跳過(guò)了verack信息,之后的操作也是一切正常。 

 

交換版本信息這一步并不簡(jiǎn)單,因?yàn)樾畔⒕哂袠?biāo)準(zhǔn)的格式,不過(guò)不用害怕,可以用幾行代碼來(lái)創(chuàng)建這些信息。下面代碼段中的makeMessage函數(shù)可以由隨機(jī)數(shù),命令名以及命令的參數(shù)來(lái)生成一條消息。getVersionMessage函數(shù)通過(guò)將各個(gè)字段打包在一起來(lái)為版本消息創(chuàng)建參數(shù)。

 

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

 

發(fā)送交易tx

 

我使用下面精簡(jiǎn)的Python代碼把我的交易發(fā)送到比特幣網(wǎng)絡(luò)中,這個(gè)代碼發(fā)送一條客戶端版本信息,接受(也可以忽略)比特幣節(jié)點(diǎn)的版本信息和verack信息。最后將我的交易以tx信息發(fā)送。代碼中這個(gè)16進(jìn)制的字符串是我之前創(chuàng)建的交易。

 

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

 

以下Wireshark(一個(gè)抓取,分析網(wǎng)絡(luò)封包的軟件)軟件的截圖顯示出我是如何將交易發(fā)送到比特幣網(wǎng)絡(luò)中的。我用Python編寫(xiě)了腳本來(lái)分析網(wǎng)絡(luò)數(shù)據(jù),為了簡(jiǎn)單起見(jiàn),在這里我使用Wireshark。從圖中可以看到我的這筆tx交易。

 

 

 

Wireshark中抓取的這筆正在上傳至比特幣網(wǎng)絡(luò)的交易tx

 

為了實(shí)時(shí)監(jiān)控我這筆交易的進(jìn)度,我在比特幣網(wǎng)絡(luò)中新運(yùn)行了一個(gè)節(jié)點(diǎn),在把我交易發(fā)到比特幣網(wǎng)絡(luò)5秒鐘之后,另一個(gè)節(jié)點(diǎn)給我發(fā)送了這個(gè)tx消息,其中包含我剛剛發(fā)送的這筆交易的哈希,由此可見(jiàn),在僅僅這幾秒中,我的交易已經(jīng)傳遍了比特幣網(wǎng)絡(luò),至少也是比特幣網(wǎng)絡(luò)的一部分。

 

交易成功:我的交易被加入?yún)^(qū)塊鏈

 

在將我的交易發(fā)送比特幣網(wǎng)絡(luò)之后,我需要等待它被礦工開(kāi)采出來(lái)加入到區(qū)塊鏈中,然后才能宣稱(chēng)我的實(shí)驗(yàn)圓滿成功。10分鐘后,我的比特幣節(jié)點(diǎn)收到一條含有新區(qū)塊信息的inv消息(參見(jiàn)下圖Wireshark抓到的網(wǎng)絡(luò)封包),檢查這個(gè)區(qū)塊后發(fā)現(xiàn)我的交易被包含在了區(qū)塊中,證明我的交易是有效的,我的實(shí)驗(yàn)成功了。通過(guò)我的比特幣錢(qián)包軟件和在線查詢,再一次確認(rèn)了我已經(jīng)交易成功??梢哉f(shuō),經(jīng)過(guò)不斷的努力,我成功手動(dòng)創(chuàng)建了一筆交易,并讓比特幣系統(tǒng)接受了它。(當(dāng)然了,我也經(jīng)過(guò)了幾次失敗的嘗試,這些錯(cuò)誤的交易都消失在了網(wǎng)絡(luò)之中,永遠(yuǎn)都不會(huì)被檢索到。

 

Wireshark中抓取的新區(qū)塊產(chǎn)生的封包信息

 

我的交易是被當(dāng)時(shí)哈希算力(挖礦速度)最大的礦池(多個(gè)礦工一起挖礦)GHash.IO挖出,區(qū)塊高度為279068,區(qū)塊哈希為0000000000000001a27b1d6eb8c405410398ece796e742da3b3e35363c2219ee,在上圖Wireshark數(shù)據(jù)包中inv消息的哈希值是經(jīng)前后反轉(zhuǎn)得到的ee192……。你應(yīng)該會(huì)發(fā)現(xiàn)區(qū)塊的哈希值以大量的0開(kāi)頭,在一個(gè)16進(jìn)制的哈希值中發(fā)現(xiàn)一個(gè)以這么多0開(kāi)頭的數(shù),這就是為什么挖礦如此困難的原因。這個(gè)區(qū)塊中由462筆交易,我的交易是其中之一。

高度為279068的區(qū)塊以及我發(fā)起的這筆交易

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

 

挖到這個(gè)區(qū)塊的礦工們收到了25個(gè)比特幣的獎(jiǎng)勵(lì),交易費(fèi)總共是0.104個(gè)比特幣,按當(dāng)時(shí)的市價(jià)分別為19000美元和80美元。我支付了0.0001個(gè)比特幣的交易費(fèi),大約是我交易額的10%,按當(dāng)時(shí)的市價(jià)為8美分。

 

結(jié)論

 

手動(dòng)進(jìn)行比特幣交易比我想象中困難得多,但是在這個(gè)過(guò)程中我學(xué)到了很多,希望你也是。我的Python代碼僅僅是為了介紹,如果你想跟我一樣用Python手動(dòng)進(jìn)行比特幣交易,也可以試試這幾個(gè)項(xiàng)目。

 

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

https://github.com/richardkiss/pycoin

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

 

 

寫(xiě)在最后

2017年是區(qū)塊鏈的井噴之年,經(jīng)過(guò)一年的積攢,2018年將迎來(lái)區(qū)塊鏈的落地之年,區(qū)塊鏈會(huì)逐漸顛覆各行各業(yè)。對(duì)于個(gè)人,區(qū)塊鏈的機(jī)會(huì)會(huì)越來(lái)越多,也許你錯(cuò)過(guò)了比特幣的投資,不妨現(xiàn)在抓住區(qū)塊鏈這個(gè)風(fēng)口,投資自己,多學(xué)習(xí)相關(guān)知識(shí),區(qū)塊鏈大有可為,投身區(qū)塊鏈的你將大有作為!

*聲明:推送內(nèi)容及圖片來(lái)源于網(wǎng)絡(luò),部分內(nèi)容會(huì)有所改動(dòng),版權(quán)歸原作者所有,如來(lái)源信息有誤或侵犯權(quán)益,請(qǐng)聯(lián)系我們刪除或授權(quán)事宜。

 

 

衡水市| 苏尼特右旗| 荥经县| 荥阳市| 东阳市| 新巴尔虎左旗| 彝良县| 临沭县| 都昌县| 平顶山市| 云阳县| 阜城县| 安庆市| 佛坪县|