以前的章節已經比較粗略的解釋了在Transaction體系當中的總體運做原理。接下來的章節會對這個體系進行分解,比較詳細描述細節的構成。編程
本章將要詳細分析bitcoin交易中的交易腳本-script究竟是什麼東西。安全
在前面的文章中提到,在bitcoin的體系中,一個交易是被髮布到比特幣的總體系統中的,而可以操控以前交易的的TxOut(被鎖住的coin),是須要可以操控這個TxOut的人提供"鑰匙"來控制。就像前文描述的,coin在整個系統中是像流水同樣的在體系中進行流通,而coin在其中在分叉點的時候會有一個像 「鎖」 的東西把coin鎖在這個節點上。而根據這個鎖產生了一個新的交易,繼續流通被這個鎖所鎖住的coin,是須要提供一個"鑰匙"的。數據結構
因此這裏的比喻:「鎖」和「鑰匙」就是比特幣交易中的交易腳本Scriptide
其中函數
「鎖」 對應着 scriptPubKey區塊鏈
「鑰匙」對應着 scriptSigui
可是單純的把Script理解爲「鎖」和「鑰匙」實在是太淺薄了。只能完成這點事情的並不能體現Script 的強大,也沒法對後人創立「智能合約」有所啓發。this
因此在我看來,比特幣的Script其實是:加密
scriptPubKey 是上一個交易(out)提出的一個 「問題」spa
而
scriptSig 是我想使用上一個交易中錢,那麼我就對你提出的這個問題提供個人「答案」
由於公私鑰的關係,因此若是scriptPubKey 提出的問題是公鑰相關的問題,那麼很明顯,只有持有私鑰的人才能回答這個問題,因此就簡化爲剛纔的所說的「鎖」和「鑰匙」的關係。
而另外一方面,如何確認提供的「答案」就是能回答「問題」的呢?這就說明Script是須要被執行驗證的,並且這個驗證的過程只須要txin提供的scriptSig 和驗證者本身從本身的記錄中找到的txout的scriptPubKey ,而這個驗證者就是廣大的礦工們。
整個系統精妙的地方就在於,scriptPubKey是驗證者(礦工)各自獨立持有的東西,其安全性由本身所保證的,而想要完成交易的人只須要提供scriptSig給廣大驗證者就行,不須要一些多餘的上下文(能夠理解爲上下文由驗證者本身持有,雖然你們都互不信任,可是對於最廣大的人來講,這個上下文都是相同的)。
另外一個方面不太被大多數人所注意到的是:
實際上剛纔的模型簡化爲了「問題」和「答案」,可是這個「問題」可不是很容易提供的。
這個「問題」應該知足2個方面的要求:
而公私密鑰的模式實際上是完美的符合了這2方面的要求的。
那麼有沒有其餘的問題呢?那是固然有的,好比我提出了一個數學問題,這個問題的解是惟一的而且能夠很容易的驗證個人回答對不對
那麼我就能夠建立一筆交易,而這筆交易的txin就提供這個問題的答案,只要個人這個tx優先被礦工打包進入區塊中,併成爲最長鏈,那麼這個問題下的錢就歸我了。
這個場景就是符合正向很難,逆向容易的場景。
接下來就解釋 比特幣系統中的 CScript 究竟是怎麼運做的。
在比特幣源碼當中,對於CScript 單獨列出了 script.c/script.h 來實現這塊體系(對比把tx,block等全部實現所有放在main.c/.h來講),可見得中本聰在一開始設計這套體系的時候就把這塊的內容看的至關的重要。事實上這套體系也確實很複雜,可是也是得益於這套體系,才能取得如今的地位,若是沒有這個設計,比特幣的實用性會被大幅度減弱。
class CScript : public vector<unsigned char> { // 把各類類型的數據序列化到 vector 中 CScript& operator<<(char b) { return (push_int64(b)); } CScript& operator<<(short b) { return (push_int64(b)); } CScript& operator<<(int b) { return (push_int64(b)); } CScript& operator<<(long b) { return (push_int64(b)); } CScript& operator<<(int64 b) { return (push_int64(b)); } CScript& operator<<(unsigned char b) { return (push_uint64(b)); } CScript& operator<<(unsigned int b) { return (push_uint64(b)); } CScript& operator<<(unsigned short b) { return (push_uint64(b)); } CScript& operator<<(unsigned long b) { return (push_uint64(b)); } CScript& operator<<(uint64 b) { return (push_uint64(b)); } CScript& operator<<(opcodetype opcode) CScript& operator<<(const uint160& b) CScript& operator<<(const uint256& b) CScript& operator<<(const CBigNum& b) CScript& operator<<(const vector<unsigned char>& b) { // } bool GetOp(const_iterator& pc, opcodetype& opcodeRet, vector<unsigned char>& vchRet) const