在比特幣網絡中,一筆交易是如何進行的?本文是筆者的理解,若有錯誤,歡迎批評指出 QQ:921658495
A要轉給B十個ETH,首先A需要有10ETH,其次A需要有B的公鑰HASH
為什么A需要B的公鑰hash?這個問題我們待會再回答,我們先看一下轉賬是怎么回事.
在比特幣系統中,是沒有賬戶的概念的,余額沒有存在賬戶中,而是一個叫UTXO的數據結構,
UTXO的結構
一個地址可以有多個UTXO,每個UTXO上有字段value,可以理解為每個UTXO上都有一個余額,而這個余額就是這個UTXO里有多少錢。
轉帳前,我要先驗證A確實有10ETH(礦工來驗證),如何驗證呢?
UTXO集合中是所有未花費輸出,找到集合中addr為A的地址的UTXO,然后將所有value加起來,就是A的總錢數。
轉賬時UTXO的變化?
比如說A有3張銀行卡(3個UTXO),每張卡里有50ETH(每個UTXO中的value為50)。而A轉給B時,並不是將一張銀行卡中錢轉出到B的銀行卡,而是將A的這張卡銷毀(UTXO中spent字段設為TRUE,表示已花),然后再生成2個銀行卡(一個是B的UTXO,接受A轉給他的10ETH;一個是A的UTXO,接受找零的40ETH)。
為什么還需要生成一個A的UTXO,直接將A之前的UTXO中減去10不行嗎?
比特幣系統中花費UTXO時,必須一次性花完,花不完需要有一個找零地址,如果沒有找零地址,找零的這部分錢就會作為交易費支付該礦工。下面第二個A就是一個找零地址
回到之前的問題,為什么A給B轉賬需要B的公鑰hash呢?
剛才說了,轉賬時,生成目標地址的UTXO,花費轉賬方的UTXO。那么A如何花費它的UTXO時,是不是需要一些驗證呢,如果沒有驗證,任何人都跑來花費A的UTXO。
那么,如何驗證A花費的是屬於它的UTXO呢?(涉及到P2PKH)
這里涉及到鎖定腳本和解鎖腳本,每個UTXO在生成時,都會用這個UTXO的擁有者A的公鑰(實際是公鑰HASH)進行鎖定,比如說A在花費它的UTXO時,A需要用自己的公鑰明文和簽名進行解鎖。解鎖過程分兩步:1、解鎖腳本中A的公鑰明文經過HASH160加密后,是否與鎖定腳本中A的公鑰HASH相等 2、公鑰驗證通過后,公鑰驗證解鎖腳本中A的簽名。如果能解鎖成功,說明這個UTXO確實是A的,那么A就可以花這個UTXO了。
到這里A轉賬給B時為什么需要B的公鑰HASH,已經解決,那么問題又來了:A如何獲取B的公鑰HASH?
我們都知道每筆交易打包時都需要在鏈上廣播,而廣播時不就知道B的公鑰明文或者hash了嗎,確實!但是如果B是新生成的地址,從未進行過任何交易,也從未進行過任何廣播,那么A怎樣才能知道B的公鑰HASH呢?B的地址就是B的公鑰HASH的編碼,地址和公鑰hash是可以相互轉換。我們可以看一下地址是如何生成的:
1、隨機生成私鑰
2、進行SHA256和RIPEMD160兩次加密(不可逆)
3、截取前20BYTES得到公鑰HASH
4、公鑰經過BASE58編碼得到地址(類似BASE64,可逆的)
我們看一下一筆交易中的代碼體現:
這里的兩個輸出:實際上是生成了兩個UTXO,上面體現的好像不是很明顯,下圖是在比特幣瀏覽器上截的圖
不知道大家有沒有注意到,上面驗證A是否可以花費這個UTXO時,驗證了解鎖腳本中的簽名,問簽名的內容是什么?
簽名的內容是這筆交易的內容,ScriptSig是解鎖腳本,簽名+公鑰+指令應該放到這個ScriptSig里面,但是這個鍵本身就屬於交易的一部分,那么豈不是矛盾了嗎?看到一個大佬的博客后恍然大悟,簽名的內容確實是這筆交易,但簽名時把ScriptSig替換成B(接收方)的鎖定腳本的內容,然后再對整個交易進行簽名,最后再把簽名+公鑰+指令編碼后放在ScriptSig中
簽名前的交易
Scriptsig進行填充,對填充后的交易簽名
簽名后,替換到ScriptSig
交易部分基本結束,現在我們知道一筆交易是如何讓驗證,如何簽名,UTXO是如何變化的了。
上面篇幅已經講了交易生成,接下來將交易打包到區塊。
注意,這里不是兩個獨立的概念,下圖中粗略展示了交易和區塊的關系
注意:區塊鏈的是不可篡改的分布式賬本,他的目的是為了記賬,也就是把交易打包到區塊鏈中。
打包過程:
A要轉給B十個ETH,這筆交易被廣播到比特幣網絡上,所有礦工節點接收到后,先對這筆交易進行合法性驗證,也就是上文中的簽名,腳本等。
驗證通過的話,將這筆交易放在礦工本地的chainstate中(可以理解為臨時存放區),然后礦工從chainstate中挑選出一些交易,優先挑選交易費高的,但不能太多,區塊容量不能超出1M。
然后將這些交易構造成merkel tree,計算出這顆tree的root hash,再加上version、previous_hash(前一個區塊頭Hash)、target(目標閾值)、timestamp(時間戳)還有nonce(隨機數),上面這6個值一起進行HASH運算,要求得到的運算出的HASH<=target,如果不滿足,變換nonce,繼續進行HASH運算,這個過程就成為挖礦。
直到滿足HASH<=target,說明找到了滿足要求的nonce,也就是挖到礦了。
然后礦工節點將上面這些數據按照區塊的數據結構打包成一個區塊,廣播至其他節點進行驗證,其他節點驗證時主要驗證塊結構、是否滿足挖礦難度、時間戳、merkel tree root hash、塊大小、coinbase(一個區塊只能有一個)。
如果驗證通過,則可以發布到區塊鏈上。