欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

一文看懂怎樣用 Python 創建比特幣交易

系統 1608 0

鏈客,專為開發者而生,有問必答!

此文章來自區塊鏈技術社區,未經允許拒絕轉載。
一文看懂怎樣用 Python 創建比特幣交易_第1張圖片

比特幣價格的上上下下,始終撩動著每一個人無比關切的小心臟。從去年初的 800 美元左右,飛漲到去年底到 19783.21 美元最高點,不到1年,便有將近 25 倍的升值速度。盡管眼下又掉回 8000 多美元的價格,但價格差不多能搞出去年同期一個數量級,幣圈人士“過去一年比以往 10 年掙的都多”,已經是不爭的事實。

而對區塊鏈開發者來說,據說也已經有拿到年新 500 萬的天價。所以“跑步進入區塊鏈”,已經成為不少程序員的共識。但是看過很多遠離,我們如何才能迅速上手呢?國外網友 Ken Shirriff 在博客中分享了他在手動茶古劍比特幣交易時的代碼與對比特幣協議的心得,區塊鏈大本營編譯如下。

近期,媒體行業對比特幣表現出極大的熱情,這鼓舞著我從網絡底層的數據流開始,認真學習比特幣的工作原理。通常人們會使用錢包軟件來進行比特幣交易,錢包軟件在方便用戶的同時,向用戶隱藏了比特幣的交易流程,而我想親自動手來體驗比特幣交易,我的目標是用Python手動創建一筆比特幣交易,以十六進制數據的形式將交易廣播到比特幣網絡中,然后觀察這筆交易是怎么被加入到區塊鏈中的。事實證明,這個過程很有趣,希望你也對它感興趣。

在本篇文章中,首先我會對比特幣進行一個簡單的概述,之后,我會從以下幾個方面帶領你們學習比特幣:創建一個比特幣地址(比特幣中的賬戶),進行一筆比特幣交易,簽署交易,將交易廣播到比特幣網絡中,最后等待交易的確認。

比特幣簡述:

首先,我會介紹一下比特幣系統是怎么運轉的,然后再深入探討整個細節。比特幣是一個基于點對點網絡的電子貨幣,你可以用現金在網上購買比特幣,用比特幣向他人轉賬,在有些商家,你可以像使用支付寶一樣使用比特幣付款,當然,你也可以賣出所持有的比特幣換回現金。

簡而言之,在比特幣網絡中,分布式賬本(區塊鏈)記錄并隨時更新著每個比特幣的所有權。與銀行不同的是,比特幣并沒有與個人或個人的賬戶綁定,相反的,比特幣只屬于一個個比特幣地址,比如:1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa。這里你可能已經繞暈了,難道這段字符中藏著比特幣?當然不是,比特幣地址是比特幣網絡中的一個身份,也可以通俗地說是你在比特幣中開的一個“銀行賬戶”,我們用這個“賬戶”來進行交易。在網站:blockchain.info中,你可以查到所有的交易信息:

比特幣賬戶信息

但是怎么證明這個賬戶是我的呢,不急,先往下看,你的疑問我會為你一一解答。

比特幣交易

如何像使用現金一樣使用比特幣呢?答案是創建一筆交易。在一筆交易中,比特幣的所有者(上文提到過比特幣的所有者是比特幣地址)將所有權轉移到一個新的比特幣地址。比特幣的一個顛覆性創新就是通過鼓勵節點記賬(也叫礦工挖礦),將交易記錄放在一個分布式的數據庫中。交易被集合在區塊中,大概每十分鐘比特幣網絡中產生一個新的區塊,成為交易記錄的一部分,稱為區塊鏈。加入到區塊鏈中的交易可以被認為是一筆成功的交易。現在問題來了,誰來給你記賬呢?是礦工,礦工的挖礦過程就是在往區塊鏈中記賬,礦工要核實每筆交易是否正確,核實完后,礦工們就開始算一道很難的數學題(密碼學中的哈希函數),最早算出答案的人就能生成一個區塊,也叫挖出了一個新的區塊,這個區塊將成為區塊鏈的新一部分。

也許你會問了,明明是記賬,干著會計的活,為什么要叫挖礦呢?和傳統的在地下挖礦石一樣,比特幣挖礦也是會有收獲的。挖礦是一種新發行比特幣的過程,當前,每挖到一個礦,礦工會得到系統獎勵的12.5個比特幣,按目前一個比特幣接近一萬美元的市價,這就是一筆12.5萬美元的巨款。此外,礦工還可以獲得本區塊中所有的交易費,舉例來說,在高度為512587的區塊中,幸運的礦工總共收獲了12.829個比特幣。正因如此,礦工之間的競爭十分激烈,采礦的難度與礦工間激烈的競爭是比特幣安全的重要保證,因為這樣可以保證沒有壞人能操縱系統。

點對點網絡

比特幣并沒有一個中央服務器,相反,比特幣在一個點對點網絡中運行。如果你運行一個比特幣節點,那你就成了網絡的一部分。比特幣網絡中的節點彼此交換自己存儲的交易,區塊,以及IP地址信息(用于節點間建立連接互相通信)。當你第一次連接到比特幣網絡,你的節點會從隨機挑選的節點中下載區塊鏈的信息。反過來,你的節點也會向后加入者提供信息。當你要創建一筆比特幣交易時,你要把這筆交易發送給一些節點,這些節點會在比特幣網絡中廣播這筆交易,直到全網都收到這筆交易。礦工們會收集你的交易信息,生成一個含有你這筆交易的區塊,向全網廣播,這時,你的節點也會收到這個區塊信息,通過驗證,這筆交易被加入到了區塊鏈中,你就交易成功了。

加密技術

現在回到證明比特幣賬戶是誰的這個問題。比特幣使用數字簽名技術以確保只有比特幣賬戶的所有者才能使用賬戶中的比特幣。比特幣地址的所有者擁有與該地址相匹配的私鑰,當花費比特幣時,你用要這個私鑰在交易上簽名,證明自己是這個賬戶的所有者。這有點像現實生活中的蓋章,蓋章就意味著授權。怎么驗證呢,公鑰與比特幣賬戶相關聯,用公鑰就可以驗證簽名是否正確。這樣就解決了比特幣賬戶是誰的這個問題。

怎么來區分不同的交易呢?交易和區塊都使用密碼學上的哈希值進行索引,是不是有點耳熟,對,在比特幣協議中,多處使用到了哈希函數,礦工們剛才算的數學題就是在算哈希函數。

其實比特幣并不長這個樣

比特幣協議探究

在接下來的文章里,我將逐步介紹我是怎樣手動進行一次比特幣交易的。首先,我生成了一個比特幣賬戶以及對應的公鑰,私鑰。接下來我發起了一筆比特幣交易,我向這個新生成的賬戶轉了一小筆比特幣。期間手動簽署這筆交易很困難,它花費了我很多的時間。最后,我將這筆交易發送到比特幣網絡,等待它被加入區塊鏈。本文的其余部分會詳細地介紹這些步驟。

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

我遇到的第二個難題就是加密,嘗試一下手動加密,你就會發現密碼學對人們多不友好,甚至可以說是無情。即使你只輸錯了一個字節,交易就會因出錯被拒絕,而且它不會告訴你哪里出錯了,你只能重來。

最后,手動簽署交易的過程也比想象中難得多,簽署交易時每個環節都必須零失誤,要么又要退回重來。

比特幣地址和密鑰

第一步,我創建了一個比特幣地址。通常情況下,人們都是使用比特幣客戶端軟件來創建比特幣地址和與之相關的密鑰。本著學習的態度,我寫了一些Python代碼來生成比特幣地址,從而揭示地址創建的機理。

比特幣使用了一系列的密鑰和地址,下圖解釋了它們的關系。首先你要創建一個隨機的256位的私鑰,這個私鑰用于在花費比特幣時簽署交易。因此,私鑰必須保密,否則你的比特幣可能會被盜用。

橢圓曲線數字簽名算法(Elliptic Curve Digital Signature Algorithm,ECDSA,美國政府的標準,接下來我們會討論它)會從私鑰中生成一個512位的公鑰,這個公鑰用于驗證交易的簽名。但不方便的是,比特幣協議中需要在這個公鑰上添加了前綴04,這個公鑰在交易簽署之前不會被泄露,不像其它系統中公鑰就是為了公之于眾的。

比特幣地址與公鑰的關系

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

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

https://blockchain.info/addre... 看到,也算是為教學做貢獻了。)

總之,共有三種密鑰:私鑰,公鑰,公鑰的哈希值,經過使用Base58Check編碼,它們對外都是以ASCII格式表示。私鑰是其中最重要的密鑰,因為花費比特幣時需要私鑰簽署交易,而且其他的密鑰都可以從私鑰中產生。公鑰的哈希值就是你們剛看的的比特幣地址。

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

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

從內部分析一筆交易

交易是比特幣系統的基本操作,也許你會認為交易就是簡單地把比特幣從一個地址轉移到另一個地址,但交易其實并不簡單。一筆交易包含一個或多個輸入和輸出,交易中的每個輸入的地址都提供比特幣,每個輸出的地址都接受比特幣。

一筆簡單的比特幣交易,交易C花費了從交易A和交易B獲得的0.008個比特幣,其中0.001個比特幣被當作交易費付給礦工

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

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

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

手動創建一筆交易

如下圖所示,在我的實驗中我發起了一筆只有一個輸入一個輸出的交易。我在Coinbase上買了一些比特幣,并將0.00101234個比特幣放入地址:

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

81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48,我的目標是創建一筆交易,將這些比特幣轉入我的另一個地址:

1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa,扣除0.0001個比特幣的交易費后,目標地址將獲得0.00091234個比特幣。

比特幣交易結構實例

Blockchain.info上的交易記錄

https://blockchain.info/addre...

按照協議標準,創建這筆交易很簡單。如下表所示,這筆交易只有一個輸入,源自于81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48中的輸出0(第一個輸出)。輸出為0.00091234個比特幣(91234在十六進制中用0x016462表示),它以小端格式存儲在值區域中。加密過程中的scriptSig和scriptPubKey較為復雜,我們稍后再做討論。

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

這是我生成交易使用的代碼,這段代碼只是把數據打包成二進制文件。簽署交易較為困難,我們等一會兒再說。

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("
            
          
        

txnUtils.py

比特幣交易怎樣簽署

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

通過執行幾個簡單運算,任何人都能驗證B是否簽署了這筆交易。首先,B的公鑰與之前收到這筆比特幣交易的地址做驗證,證明B的公鑰有效。(正如前面所說的,地址很容易從公鑰中計算獲得)。接下來,可以通過B的公鑰驗證B交易簽名的真偽。這些步驟能確保交易的有效性和交易得到B的授權。比特幣于眾不同的一點是,B的公鑰在B發起交易之前是不公開的。

在比特幣系統中,比特幣通過區塊鏈上的一筆筆交易在不同的地址間傳遞。區塊鏈上的每一筆交易都能被驗證以確保比特幣交易的有效性。

比特幣交易的相互連接

比特幣腳本語言

你可能會以為僅僅通過在交易內容中附上簽名就可以簽署比特幣交易,其實不然,這個過程十分復雜。實際上,每一筆交易中都包含一個“小程序”,用于確認交易是否有效。這個“小程序”用腳本語言寫成,通過這種基于堆棧的比特幣腳本語言,我們可以應對許多復雜的比特幣支付場景。例如,托管系統可以設定只要經過三分之二的用戶授權,就可執行交易的規則,也可以設置其他的合約。

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

前一個交易中的腳本稱為scriptPubKey,當前交易中的腳本稱為scriptSig。要驗證交易時,先執行scriptSig,然后再執行scriptPubKey。如果兩個腳本都成功執行,交易就被認定為有效,交易中的比特幣就可以成功花出。否則,交易無效。要注意的是前一個交易中的scriptPubKey規定了花費比特幣的條件,當前交易的scriptSig必須滿足這個條件。

在一個標準的交易中,scriptSig腳本將從私鑰中生成的簽名并壓入堆棧中,再壓入公鑰。接下來scriptPubKey腳本會執行運算先驗證公鑰的有效性,再驗證簽名的有效性。

正如腳本中所表示,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
當這段代碼執行時,PUSHDATA操作首先會把簽名壓入堆棧,接著把公鑰壓入堆棧。OPHASH-160操作計算公鑰的160位哈希值,PUSHDATA操作再把交易中的輸入地址(輸入賬號)壓入堆棧,然后,OP-EQUALVERIFY操作驗證驗證前兩個堆棧中的值是否相等(驗證這筆交易中你使用的比特幣是否屬于你自己)-如果公鑰的哈希等于之前交易中的輸出地址,這就證明公鑰是有效的(證明這個比特幣是你的)。最后,OP_CHECKSIG操作將檢查交易的簽名是否與堆棧里的公鑰和簽名匹配,匹配就證明簽名是有效的(證明交易的到了你的授權)

簽署交易

我發現簽署這筆交易是手動使用比特幣時最難的地方,這一過程出奇地困難且容易出錯。簽名的基本思想很簡單,使用橢圓曲線簽名算法和私鑰來生成交易的數字簽名,但細節非常棘手。簽署交易的過程可以通過這19個步驟描述。

簽署交易的19個步驟

對交易的簽名讓我面臨巨大的挑戰,這涉及到一個如何在交易內容中還沒有加入簽名時簽署這筆交易的問題。為了避免這個問題,在計算生成簽名之前,我把scriptPubKey這個腳本從上一筆交易復制到當前交易中(當前這筆交易正在被簽署),然后將簽名轉換為腳本語言的代碼,創建嵌入在當前交易中的scriptSig腳本。對于具有多個輸入的交易,簽署交易環節更加復雜,因為每個輸入都需要單獨的簽名,這里我就不做詳細討論了。

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

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

由于ECDSA算法需要使用隨機數,所以調試簽名十分困難。每次計算出的簽名都會有所不同,因此無法與已知正確的簽名進行比較。

正是由于上述的復雜性,我花了很長時間才得到了一個簽名。不過,最終我找出了簽名代碼中所有的錯誤,并成功用它簽署了一筆交易。這是我使用的簽名代碼:

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)。 這證明這筆交易有效,我可以花費這些比特幣。

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腳本包含成功花費比特幣時必須執行的腳本。需要注意的是,這個腳本將在未來花費這些比特幣的時候執行。它包含以十六進制表示而不是以Base58Check表示的目標地址1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa,腳本的效果是只有這個目標地址的私鑰所有者才能使用比特幣,因此目標地址實際上是這些比特幣的所有者

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

最終的交易

經過上述的一系列操作,我們完成了最終的交易。但是,別忘了,此時的交易還沒加入區塊鏈中,接收方還沒有收到你的比特幣。

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

小插曲:橢圓曲線簽名

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

橢圓曲線這個叫法令人迷惑,因為橢圓曲線并不是橢圓,而且看起來也不像橢圓,甚至橢圓曲線與橢圓相關性都很少。通俗地講,橢圓曲線就是滿足一個簡單方程y ^ 2 = x ^ 3 + ax + b的曲線。比特幣中使用的稱為secp256k1的橢圓曲線,它滿足的方程為y ^ 2 = x ^ 3 + 7。

secp256k1橢圓曲線

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

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

在密碼學中,點的坐標并不是它在曲線上的實值點,而是對整數的模數。橢圓曲線的一個好用的特性就是對實數或模數進行運算的數學運算幾乎相同。正因為如此,比特幣的橢圓曲線并不像上面的圖片,而是一團雜亂無章的256位點集(想想在一個空間中充滿了大量雜亂無章的點)。

橢圓曲線數字簽名算法(ECDSA)接收交易的哈希值,使用該交易數據,私鑰,以及一個隨機數從橢圓曲線上生成一個新的點,從而實現對交易的簽名。任何擁有公鑰,交易數據,和簽名的人都可以通過做一個簡單的橢圓曲線運算來驗證簽名的有效性。讀到這里,你應該明白了為什么只有擁有私鑰的人才能簽署消息,但擁有公鑰的任何人都可以驗證該消息。

把交易發送到比特幣網絡

回到交易中來,別忘了此時我們的交易還沒有被加入到區塊鏈中,還不是一筆有效交易。剛剛我創建并簽署了一筆交易。下一步就是將這筆交易發送到比特幣網絡中,網絡中的礦工會收集交易并把它打包進區塊中。

如何找到比特幣網絡的節點

首先我要在比特幣的點對點網絡中找到一個節點。節點的列表會隨節點的進出動態更新,當一個比特幣節點連接到另一個節點時,它們就會不斷交換彼此新發現的比特幣節點信息,因此,新節點加入的消息會快速地傳遍整個網絡。

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

Nslookup命令可以用來尋找比特幣節點

當用戶啟動或停止比特幣客戶端時,節點就會加入或離開比特幣網絡。所以連接節點有很大的不確定性,在我實驗時,就遇到了連接的節點已經離開比特幣網絡的情況,如果你想重復我的實驗,最好多找幾個節點,可能需要多次嘗試才能找到一個運行著的節點。

與比特幣節點通信

一旦獲得了一個正在工作的比特幣節點的IP地址,當務之急就通過這個節點是把我的交易發送到比特幣的點對點網絡中。使用點對點的網絡協議十分簡單,我在端口8333上打開了一個到任意對等端的TCP連接,發送消息,然后接受反饋消息。比特幣的點對點協議對用戶很友好,即使我的請求數據出錯時,還是繼續與我保持通信。

重要提示:正如一些人指出的那樣,如果你想重復我的實驗,切記要使用比特幣的測試網絡,在測試網絡上,你可以使用“虛擬”的比特幣來進行交易。因為在真實網絡上,萬一你不小心,有可能會失去所有的比特幣。還記得上面提到的那個100個比特幣轉賬1個的交易么,如果你忘了將剩余的比特幣轉給自己,那么剩余的99個比特幣就會作為交易費支付給礦工。但是本著科學的態度,我并不在意在真實的比特幣網絡中損失我這些價值1美元的比特幣。

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

連接到比特幣網絡的第一步就是通過交換客戶端版本信息來建立連接。首先,我發送了一條客戶端版本信息,其中包含我的協議版本號,IP地址和其他內容。比特幣節點也向我回復了它的版本信息。在此之后,我應該回復一個verack信息(version acknowledgement,版本確認)來確認它的版本信息。正如我所說,比特幣點對點網絡協議對用戶十分友好,即使我跳過了verack信息,之后的操作也是一切正常。

交換版本信息這一步并不簡單,因為信息具有標準的格式,不過不用害怕,可以用幾行代碼來創建這些信息。下面代碼段中的makeMessage函數可以由隨機數,命令名以及命令的參數來生成一條消息。getVersionMessage函數通過將各個字段打包在一起來為版本消息創建參數。

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('
            
          
        

msgUtils.py

發送交易tx

我使用下面精簡的Python代碼把我的交易發送到比特幣網絡中,這個代碼發送一條客戶端版本信息,接受(也可以忽略)比特幣節點的版本信息和verack信息。最后將我的交易以tx信息發送。代碼中這個16進制的字符串是我之前創建的交易。

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(一個抓取,分析網絡封包的軟件)軟件的截圖顯示出我是如何將交易發送到比特幣網絡中的。我用Python編寫了腳本來分析網絡數據,為了簡單起見,在這里我使用Wireshark。從圖中可以看到我的這筆tx交易。

Wireshark中抓取的這筆正在上傳至比特幣網絡的交易tx

為了實時監控我這筆交易的進度,我在比特幣網絡中新運行了一個節點,在把我交易發到比特幣網絡5秒鐘之后,另一個節點給我發送了這個tx消息,其中包含我剛剛發送的這筆交易的哈希,由此可見,在僅僅這幾秒中,我的交易已經傳遍了比特幣網絡,至少也是比特幣網絡的一部分。

交易成功:我的交易被加入區塊鏈

在將我的交易發送比特幣網絡之后,我需要等待它被礦工開采出來加入到區塊鏈中,然后才能宣稱我的實驗圓滿成功。10分鐘后,我的比特幣節點收到一條含有新區塊信息的inv消息(參見下圖Wireshark抓到的網絡封包),檢查這個區塊后發現我的交易被包含在了區塊中,證明我的交易是有效的,我的實驗成功了。通過我的比特幣錢包軟件和在線查詢,再一次確認了我已經交易成功。可以說,經過不斷的努力,我成功手動創建了一筆交易,并讓比特幣系統接受了它。(當然了,我也經過了幾次失敗的嘗試,這些錯誤的交易都消失在了網絡之中,永遠都不會被檢索到。

Wireshark中抓取的新區塊產生的封包信息

我的交易是被當時哈希算力(挖礦速度)最大的礦池(多個礦工一起挖礦)GHash.IO挖出,區塊高度為279068,區塊哈希為0000000000000001a27b1d6eb8c405410398ece796e742da3b3e35363c2219ee,在上圖Wireshark數據包中inv消息的哈希值是經前后反轉得到的ee192……。你應該會發現區塊的哈希值以大量的0開頭,在一個16進制的哈希值中發現一個以這么多0開頭的數,這就是為什么挖礦如此困難的原因。這個區塊中由462筆交易,我的交易是其中之一。

高度為279068的區塊以及我發起的這筆交易

(https://blockchain.info/block...)

挖到這個區塊的礦工們收到了25個比特幣的獎勵,交易費總共是0.104個比特幣,按當時的市價分別為19000美元和80美元。我支付了0.0001個比特幣的交易費,大約是我交易額的10%,按當時的市價為8美分。

結論

手動進行比特幣交易比我想象中困難得多,但是在這個過程中我學到了很多,希望你也是。我的Python代碼僅僅是為了介紹,如果你想跟我一樣用Python手動進行比特幣交易,也可以試試這幾個項目。

https://en.bitcoin.it/wiki/Bi...

https://github.com/richardkis...

https://github.com/jgarzik/py...

寫在最后
2017年是區塊鏈的井噴之年,經過一年的積攢,2018年將迎來區塊鏈的落地之年,區塊鏈會逐漸顛覆各行各業。對于個人,區塊鏈的機會會越來越多,也許你錯過了比特幣的投資,不妨現在抓住區塊鏈這個風口,投資自己,多學習相關知識,區塊鏈大有可為,投身區塊鏈的你將大有作為!

https://huiyi.csdn.net/activi...

大家可以比較市面上的不同類型區塊鏈課程,貨比三家,選適合自己的,趕緊上車是王道。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲偷图色综合色就色 | av影音资源| 91精品国产高清久久久久久91 | 狠狠综合久久av一区二区小说 | 国产欧美日韩一区二区三区四区 | 国产日韩精品久久 | 丝袜 亚洲 另类 欧美 变态 | 一区二区三区日韩在线观看 | 精品国产三级 | 天天操91| 超级碰碰碰视频在线观看 | 国产精品九九久久一区hh | 妞干网av| 国产91亚洲精品 | 一区二区精品在线 | 欧美伊人久久 | 一级毛片直接看 | 夜夜夜夜爽 | 亚洲一区二区三区四区 | 一区二区三区四区视频 | 成人免费看黄网站无遮挡 | 免费观看一级毛片 | 一级特黄特黄xxx视频 | 九九精品视频一区二区三区 | 日韩精品一区二区在线播放 | 中国黄色一级生活片 | 亚洲福利电影网 | 色婷婷精品国产一区二区三区 | 亚洲性人人天天夜夜摸 | 奇米第四色网站 | 天天看天天爽 | 亚洲无线一二三四手机 | 一区二区三区国产在线 | 高清国产激情视频在线观看 | 日本黄色大片免费看 | 国产精品一区二区三区免费 | 成人网在线播放 | 国产精品嫩草影视在线观看 | 欧美一区二区三区四区不卡 | 91热爆国产露脸 | 九九51精品国产免费看 |