-
1 # frank60
-
2 # 曉智誠
讓我們先一起看一下比特幣的交易,比特幣交易的過程其實就是不停地創造區塊的過程,為了理解上的方便,我們先看一個簡單模式的賬簿,在這個賬簿裡,每一筆交易依次被新增到賬簿裡。那我們如何使用這個賬簿來創造一種貨幣呢?首先你可能想到(也是許多人誤認作比特幣使用的方式):建立一個以賬戶為核心的系統,可以創造新的幣並且放入某人的賬號,然後就可以轉給其他人了。一筆交易的資訊就像這樣:“把愛麗絲賬戶裡17個幣轉給鮑勃”,然後由愛麗絲簽名。我們從圖3.1可以看到,愛麗絲在第一筆交易裡收到
25個幣,然後轉了17個幣給鮑勃,她的賬戶裡應該還有8個幣。
圖3.1 基於賬戶的賬簿這麼做的不便之處在於,任何人如果想要確認一筆交易是否真實,就必須跟蹤每一個賬戶的餘額。讓我們再看一下圖3.1,當愛麗絲想要轉給戴維15個幣的時候她是否真的有15個幣呢?為了搞清楚這個問題,我們必須回過頭去看和愛麗絲有關的所有交易,並加總來確認當時的餘額。當然,我們可以有一些更有效的辦法,比如另外增加一個數據段,用來更新每次交易後的賬戶餘額,但這也增加了記賬的工作量。
所以,比特幣並沒有用這種記賬方式,而是用了我們在第1章1.5節裡提到的“財奴幣”相類似的方法來記錄交易。
這種方式就像財奴幣裡的付幣,每個交易中都有一個輸入值和輸出值。輸入值可以看成是將被消費掉的幣(這些幣是前一個交易創造出來的),把輸出看成是在本次交易中創造出來的幣。鑄造新幣時,只會創造新幣,而不會消費舊幣(就像財奴幣裡的造幣,只有輸出,沒有輸入)。每筆交易都有一個獨一無二的ID。每筆交易中可能有多個輸出,輸出的索引從0開始,所以我們稱第一個輸出為“輸出0”。
我們現在來看圖3.2。交易1是鑄造新幣的交易,因此沒有輸入,也沒有簽名;交易1的輸出是向愛麗絲轉移25個幣。現在,愛麗絲想把一些幣轉給鮑勃,她就創造了一條新的交易,這就是圖3.2中的交易2。在交易裡,她必須明確指出要轉出的幣的來源(引用之前的某筆交易)。愛麗絲指出本次交易的幣來自交易1中的輸出0(也是交易1中的唯一輸出),即向愛麗絲轉移25個幣。交易中,愛麗絲還要明確收款人——也就是輸出的地址,在這個例子裡,有兩個輸出,一個是轉17個幣給鮑勃,另一個是轉8個幣給愛麗絲自己。當然,整個交易由愛麗絲簽名,這樣,大家就知道這筆交易愛麗絲是確實授權了的。
圖3.2 與比特幣類似的基於交易的賬本地址轉換。在這個例子裡,為什麼愛麗絲要把幣轉給自己呢?事實上比特幣就像財奴幣中描述的幣一樣,一個交易中輸出的幣,要麼在另一個交易中被完全消費掉,要麼就一個都不被消費,不存在只消費部分的情況。愛麗絲只需付給鮑勃17個幣,但愛麗絲在上一交易中實際獲得了25個幣,為了把這些幣全部消費掉,她必須再轉給自己8個幣。這8個幣可以轉到另外一個地址(不同於交易1中獲得25個幣的地址),但前提是該地址為愛麗絲所有,這就叫地址轉換。
有效驗證。當一個新的交易被加入總賬,它的有效性是否容易被驗證?在這個例子裡,我們要核查一下愛麗絲引用的交易輸出,確認她確實有25個幣沒有被花費掉。因為我們使用了雜湊指標,所以核查很快。為了確認這25個幣沒有被花掉,我們只需從愛麗絲所引用的交易開始,一直核查到賬本上最新記錄的交易為止即可——而不需要從賬本建立之初的交易開始核查。而且,這種方法也不需要增加額外的資料結構(當然,我們將會看到,加入新的資料結構將進一步提高速度)。
資金合併。和財奴幣一樣,比特幣交易可能有許多輸入與輸出,資金分隔與合併也很容易。假如鮑勃在兩筆不同的交易中分別收到17個幣和2個幣,現在他想把這兩筆錢合併起來花掉,這很容易,他只需發起一個交易,交易裡有兩個輸入和一個輸出,輸出的地址是他自己的地址,這樣,鮑勃就把兩個交易合二為一了。共同支付。同樣地,共同支付也很容易做到。如果卡羅爾和鮑勃想要共同支付給戴維,他們可以發起一個交易,交易裡也有兩個輸入和一個輸出,唯一不同在於,兩個輸入所引用的“上一筆交易”的輸出地址不同,因此,這筆交易需要兩個簽名:卡羅爾的和鮑勃的。交易語法。比特幣交易涉及的概念就是上面這些。我們再來看看比特幣交易在底層是如何實現的。實際上,比特幣在網路上傳輸的資料結構都是一串字元,圖3.3顯示了一個真實的程式,經過編譯就會變成供機器執行的二進位制程式碼了。圖3.3 一個真實的比特幣交易程式段從圖3.3可以看到,一個比特幣交易就是上面這些。我們再來看看比特幣交易在底層是如何實現的。實際上,比特幣在網路上傳輸的資料結構都是一串字元,圖3.3顯示了一個真實的程式,經過編譯就會變成供機器執行的二進位制程式碼了。分成三部分:元資料、一系列的輸入和一系列的輸出。● 元資料。這裡存放一些內部處理的資訊:包含這筆交易的規模、輸入的數量、輸出的數量,還有此筆交易的雜湊值,也就是這個交易獨一無二的ID。我們可以用雜湊指標指向這個ID。最後還有一個“鎖定時間”(lock_time),我們後面會談到。● 輸入。所有輸入排成一個序列,每個輸入的格式都是一樣的。輸入需要明確說明之前一筆交易的某個輸出,因此它包括之前那筆交易的雜湊值,使其成為指向那個特定交易的雜湊指標。這個輸入部分同時包括之前交易輸出的索引和一個簽名:我們必須有簽名來證明我們有資格去支配這筆比特幣。● 輸出。所有輸出也排成一個序列。每個輸出的內容分成兩部分。所有輸出的金額之和必須小於或等於輸入的金額之和。當輸出的總金額小於輸入總金額時,輸出的總金額與輸入的總金額的差額部分,就作為交易費支付給為這筆交易記賬的礦工。一長串怪怪的(funny)字元看上去像是接收地址。實際上,每個輸出都要和一個特定的公鑰(地址)對應,所以這一長串字元裡面確實有一部分看上去是公鑰的雜湊值,但裡面還有一部分看上去像指令集合的東西,它其實是一個比特幣的指令碼
回覆列表
比特幣沒有所謂的“投票”環節,每個礦工都在其本地最長鏈上進行工作(礦池也是基於此原則,但是還需要協調所有礦工的協作),當一個新塊產生後,也會像交易一樣進行全網廣播,每個接收到新塊的全節點都會驗證區塊的合法性:
主要包括區塊的prehash是否為其本地的tip塊hash,難度是否符合預期,時間簽名是否正常範圍,梅克爾根是否正確,區塊中每筆交易是否合法,區塊獎勵(包括交易小費)是否正確等。
交易的合法性主要包括:
交易輸入輸出是否平賬,交易來源output是否合法,交易傳送者簽名是否合法。每個接收到區塊的節點執行相同的規則檢查,所有檢查透過則加入本地最長鏈,當然如果後面有更長符合規則的鏈,程式會自動切換到最長鏈,理論上當一個塊被確認六次基本不會在被丟棄。比特幣賬本就是所有節點維護一致的一條最長鏈。當交易被打包的進的區塊加入到這條鏈中,交易也即被全網確認了。