Qtum區塊鏈,又稱爲量子鏈,是一個基於未花費交易輸出(Unspent Transaction Output,UTXO)和權益證實(Proof of Stake,PoS)的智能合約平臺,融合了比特幣和以太坊生態系統各自的優勢 。智能合約能夠應用在諸多行業,如金融科技,物聯網和身份認證等。智能合約的核心技術是分佈式帳本,也就是咱們經常提到的區塊鏈。Qtum區塊鏈實現了完整的智能合約功能,經過帳戶抽象層(Account Abstraction Layer,AAL)技術把UTXO模型轉換成可供以太坊虛擬機(Ethereum Virtual Machine,EVM)執行智能合約的帳戶模型,合約開發者不需關心對合約操做相關的UTXO轉換細節,便可使用EVM的特性進行開發並且兼容現有以太坊的智能合約。c++
Qtum量子鏈採用了互惠權益證實(Mutualized Proof Of Stake, MPoS)共識機制,使得在智能合約下實現更安全的PoS共識。另外,首創性的提出和實現了分佈式自治協議(Decentralized Governance Protocol, DGP),DGP是經過內嵌到創世區塊的智能合約來治理區塊鏈網絡的參數,去中心化的網絡自治機制使得區塊鏈網絡在必定程度上實現自動升級和快速迭代而無需進行軟件升級。git
本指南介紹Qtum區塊鏈基本概念和使用的技術,介紹了Qtum的交易類型和智能合約的使用,對Qtum區塊鏈的使用能夠有一個基本的瞭解。github
首先介紹一下區塊鏈相關的概念。算法
區塊鏈是一種去中心化、分佈式的帳本,帳本以冗餘的方式存儲在全部參與節點。區塊鏈主要由如下底層技術組成:密碼學、共識算法、點對點網絡。就數據組織方式來看區塊鏈是由一系列的區塊連接造成的一種數據結構。最底層的第一個區塊是創世區塊,隨後每一個新區塊都被放置在前一個區塊之上,這些區塊有序地連接在一塊兒造成鏈。區塊之間是經過哈希指針進行鏈接的,哈希指針表示從原區塊指向目標區塊而且在目標區塊存儲有原區塊的哈希值。區塊由區塊頭和區塊記錄組成,區塊頭用於描述本區塊的組成信息,區塊頭最重要的用途是用做記錄前一區塊頭哈希值和區塊記錄的根哈希值。數據庫
簡化版區塊鏈示意圖編程
一個或多個新的交易收集到一塊兒成爲了一個區塊的交易數據,這些數據做爲區塊記錄。爲了對數據完整性進行保護,每一個交易的副本都會進行SHA256哈希,而後這些哈希做爲Merkle 樹的節點,對Merkle樹節點進行從下到上的哈希運算,最終在 Merkle根節點獲得一個根哈希值。該哈希寫入到區塊頭,而區塊頭也進行哈希運算獲得一個哈希值,該哈希值寫入下一個區塊頭部,所以經過寫入區塊頭的根哈希值就能夠驗證區塊記錄。json
因爲區塊頭裏的哈希值與前一個區塊相關,若是前一個區塊內容發生變化,其哈希值也會發生變化,所以會改變當前區塊的哈希值,這個改變會傳導到下一個區塊,並再傳導到下下一個區塊,以此類推,直到最後一個區塊。所以當改變某個區塊記錄時,會破壞該區塊以後的連接關係,除非對該區塊以後全部區塊進行相應的更改,即從新計算符合共識的哈希值。共識算法是用來確保從新計算哈希值在一個合適的難度,這樣若是想改變區塊內容,必須在計算能力或權益大小上超過共識難度,多個區塊共識難度的不斷積累,使得在機率上保證了最長鏈的安全性,這是就是工做量證實(Proof of Work,PoW)和權益證實(PoS)共識算法的做用原理。比特幣區塊鏈經過工做量證實,而Qtum區塊鏈採用的是權益證實機制改進算法:互惠權益證實(MPoS)。xcode
點對點網絡是實現Qtum節點之間進行通訊的方法,交易廣播、區塊同步與廣播等都經過點對點網絡來實現。經過點對點網絡,每一個節點共享同一份的帳本,並對帳本進行驗證,共識算法和共識規則是進行驗證的標準,因爲共識的一致,和密碼學結合確保了做惡節點沒法篡改和做假帳本上的數據。能夠看到,密碼學、共識算法和點對點網絡的結合確保了區塊鏈在去中心化的條件下能實現可信的帳本。Qtum在此基礎上增長了能夠運行智能合約虛擬機,從而實現了一個高度智能化的價值傳輸網絡。promise
Qtum量子鏈的區塊頭描述了區塊的狀態記錄,用於管理記錄區塊交易結果相關的信息和共識算法所需的數據。如下是Qtum區塊頭數據結構的定義:瀏覽器
Qtum區塊頭
其中nVersion版本信息描述了當前Qtum區塊鏈軟件的版本,hashPrevBlock記錄前一區塊頭哈希值,hashMerkleRoot記錄本區塊交易ID生成的Merkle樹根節點哈希值,nTime記錄區塊產生的時間,nBit記錄當前計算區塊頭哈希值的難度,nNonce與比特幣兼容,但PoS階段未使用,hashStateRoot記錄本區塊EVM執行完成後的根狀態哈希值,hashUTXORoot記錄本區塊EVM執行完後產生的UTXO根狀態哈希值,prevoutStake爲前一區塊用於PoS過程的交易輸出點,vchBlockSig是PoS時使用的區塊簽名。
Qtum交易的基本單位是未花費的一個交易輸出,簡稱UTXO。UTXO是不能再分割,並記錄在區塊鏈中。一個交易的輸入是一個或多個UTXO,生成交易時對這些UTXO進行簽名用於解鎖輸入,簽名標誌着對某個地址上Qtum的使用許可。這些簽名後的交易廣播到Qtum網絡中。網絡的每個全節點均可以接收、驗證、和在網絡中轉發這些交易。Qtum區塊鏈每隔一段時間就有挖礦節點產生新的區塊,把驗證經過的交易記錄到區塊。
Merkle樹是一種哈希二叉樹,用於快速概括和校驗大規模數據完整性。這種二叉樹的節點包含哈希值。在Qtum區塊鏈中,Merkle樹用來組織每一個區塊中的交易標識(txid)。txid是對交易進行兩次哈希算法生成。Merkle樹是自底向上構建的,經過對相鄰葉子節點的 txid 配對而後作哈希運算,生成爲父節點,對全部葉子節點重複這個過程,並對生成的父節點進行相似的操做,只到剩下頂部的一個節點,最終構建了 merkle 樹。以下圖所示:
Merkle樹
在簡化支付驗證(SPV)提案中指出,Merkle 樹容許客戶端經過一個完整節點從一個區塊頭中獲取其 Merkle 根節點和中間哈希值列表來驗證一個交易被包含在這個區塊中。這個完整節點並不須要是可信的,由於僞造區塊頭十分困難而中間哈希值是不可能被僞造的,不然驗證就會失敗。
Qtum的PoS區塊至少包含2筆交易。這些交易的第一筆是一個特殊的 coinbase 交易,該交易沒有Qtum輸出。第二筆交易是coin stake交易,它包含了這個區塊全部交易費和區塊獎勵。coin stake交易在以後的 500 個區塊內以後才能花費,在Qt錢包上顯示staking的Qtum就是參stake以後不夠500 個區塊鎖定的。
Qtum基本的共識算法基於PoSv3共識機制。關於共識機制孰優孰劣的討論一直在進行中,最常被討論的共識機制有:工做量證實機制PoW 、權益共識機制PoS 、動態權益共識機制和HyperLedger的拜占庭容錯機制 。共識機制的目的是利用分佈式算法達成數據的一致性。正如Fischer Lynch & Paterson定理指出,除非全部節點達成100%一致,不然沒法達成共識。 在比特幣網絡中,礦工經過工做量證實機制哈希碰撞參與交易驗證。當礦工計算出知足必定條件的哈希值時,礦工能夠向全網宣佈新區塊的誕生:
Hash(BlockHeader) ≤ M/D
M是礦工數量,D是挖礦難度,Hash()表明SHA256哈希運算,輸出值範圍爲[0,M]。比特幣的SHA-256哈希運算知足快速驗證(方便網絡中每一個節點對運算結果進行驗證)、可調整的難度值(能夠根據全網算力進行調整)和相對公平性(也就是說,每一個礦工解決哈希計算的機率與其算力成正比)。 在PoSv3交易中,新區塊的產生必須知足下列條件:
ProofHash < coins × target
在ProofHash中,StakeModifier 利用未花費輸出和當前時間進行運算。因爲Qtum實現了智能合約,交易處理須要花更多的時間去和智能合約交互和執行,所以須要更動態的費用機制。這其中有影響Qtum的幾個安全隱患。一個比較大的隱患是,攻擊者能夠經過支付昂貴費用執行惡意程序,但因爲這些費用會歸於區塊生產者,最終攻擊者付出的費用會變得很小。基於現有PoS系統的加密貨幣因爲不支持圖靈完備的智能合約VM,不會受到這類攻擊的影響。Qtum是第一個基於PoS和以太坊智合約的區塊鏈,實現了規範在區塊鏈上容許的計算用途和能力的gas機制。
Qtum進一步對PoSv3作了一個修改,用於部分解決經過垃圾交易攻擊而產生的無用satke問題。採用PoSv3一致的共識機制,但改變了區塊獎勵和交易費用的支付體系。與區塊生產者會當即收到區塊獎勵和交易費用相比,新的方法是獎勵和交易費用在網絡中多個挖礦者之間互相共享。具體說來,區塊生產者在生成區塊的時候會收到總費用的1/10,而通過預約的區塊確認時間以後,能夠接收到另外9個塊的費用的1/10。
這個新的方法看起來改動很微小,但它解決了影響Qtum的幾個安全隱患。一個比較大的隱患是,攻擊者能夠經過買入足夠的幣從而成爲有可能的區塊生產者,經過某些EVM操做碼使網絡變得容易遭受DoS攻擊。這隻須要很小的代價,甚至惡意交易須要消耗交易費用和gas,攻擊者能夠經過支付昂貴費用執行惡意程序,但因爲這些費用會歸於區塊生產者,最終攻擊者付出的費用會變得很小。使用MPoS,就不會出現這種狀況,產生區塊是隻能收到1/10的gas費用,除非他能再挖出連續的9個區塊,不然其他9/10的gas費用會因分給網絡上其餘的挖礦者而丟失。所以會致使這種類型的垃圾交易攻擊會變得很昂貴。
當一個區塊產生時,區塊生產者的獎勵交易必須包含至少10個輸出。第一個輸出屬於本區塊生產者,能夠接收本身用於stake的幣和1/10的交易費用,其餘九個輸出屬於500個區塊以前的區塊生產者。當一個區塊產生時,增長一個獎勵費用的接收者,同時減去另一個接收者,所以總接收者數量一直有10個。區塊生產者另外9/10的獎勵將在500個區塊以後,即(+501,+502,...,+509)每一個區塊獎勵的1/10。
智能合約(Smart Contract),以編程方式定義的一系列承諾,包括合約參與方能夠在上面執行這些承諾的協議。經過區塊鏈能夠實現這種智能合約的編程,並在區塊鏈上執行,所以一旦設立指定後,可以無需中介的參與自動執行。
Qtum實現了知足以太坊虛擬機(EVM)規範的智能合約功能,在Qtum上能夠部署和調用智能合約。以太坊虛擬機使用了256比特長度的機器碼,是一種基於堆棧的虛擬機,用於執行以太坊智能合約。因爲EVM是針對以太坊體系設計的,所以使用了以太坊帳戶模型(Account Model)進行價值傳輸。而Qtum量子鏈的設計是基於比特幣UTXO模型,因此在量子鏈模型設計中加入了帳戶抽象層(Account Abstraction Layer),用於將UTXO模型轉換成可供EVM執行的帳戶模型。帳戶抽象層能夠隱藏某些特定功能部署細節,併爲加強互操做性和平臺獨立性創建關注劃分。
Qtum量子鏈中的全部交易使用比特幣腳本語言,並在其基礎上進行了拓展,加入了三個全新的操做符。
在比特幣系統中,只有當解鎖腳本(ScriptSig)與鎖定腳本(ScriptPubKey)驗證經過後才能花費相對應的交易輸出。舉例來講,鎖定腳本一般會把一個交易輸出鎖定到一個比特幣地址上(公鑰的哈希值),只有當解鎖腳本和鎖定腳本的設定條件相符時,執行組合腳本纔會顯示結果爲真(系統返回值爲1),這樣相對應的交易輸出纔會被花費。
而在Qtum系統中,咱們更強調智能合約執行的及時性。所以咱們在鎖定腳本中加入了OP_CREATE和OP_CALL操做符。當Qtum系統檢測到該操做符時,全網節點就會執行該交易。這樣一來,比特幣腳本扮演的角色,更多的是將相關數據傳送至EVM,而不只僅做爲一種編碼語言。與以太坊執行智能合約同樣,由OP_CREATE和OP_CALL操做符觸發的合約,EVM會在各自的狀態數據庫中更改其狀態。
考慮到量子鏈智能合約的易用性,須要對觸發智能合約的數據以及數據來源的公鑰哈希值進行驗證。爲了防止量子鏈上UTXO所佔比例過大,將OP_CREATE和OP_CALL的交易輸出也設計成可花費的,OP_CALL的輸出能夠爲其餘合約或公鑰哈希地址發送資金。
對於智能合約的開發者來講,EVM的帳戶模型相對簡單。它支持合約餘額的查詢,還可爲其餘合約發送資金等操做。對於在Qtum上建立的智能合約,系統會生成一個交易哈希值用於合約的調用。新合約的初始餘額爲0(目前不支持非0初始餘額的合約)。爲了知足合約發送資金的需求,Qtum使用OP_CALL操做符來建立交易輸出。
目前Qtum支持使用Solidity語言進行編寫的智能合約,而且使用好比Remix Solidity IDE進行開發和編譯智能合約。部署智能合約或和合約進行交互能夠經過Qtum提供的RPC調用或PC錢包進行。
Qtum區塊鏈的分佈式自治協議(Decentralized Governance Protocol,DGP)是經過智能合約實現的,可管理的每一個區塊鏈網絡功能都由獨立的DGP智能合約(採用DGP-template描述)控制,這意味着每一個功能有獨立的治理、受權機制以及內置限制條件。每一個DGP都有一個很是簡單的核心治理模式:即經過具備管理或治理席位的地址來對提案進行管理,包括對投票席位自己和普通提案的管理。如今支持0,1,2三種類型的提案,分別對應:管理或治理席位增長、管理或治理席位刪除、普通參數提修改。全部提案的設置只有具有管理席位的發送地址纔有權限設置,具備管理或投票席位的發送地址才能進行投票。
對2類型提案,即普通類型提案的投票,至少支持如下項目:
具體的網絡參數更改流程爲:
提案投票成功後會更新到相應的變量保存,新參數會在500個塊以後生效,以免出現沒必要要的孤兒塊或分叉,錢包和區塊鏈上的全部節點能夠定時檢查RLP儲存從而判斷是否有新的更改發生。對於0,1類型的提案,即管理或治理席位增長和刪除,其投票流程和普通提案相似,也是經過具備管理或治理席位的發送者投票來決定,不過當投票經過後席位的變化能夠當即生效。
Qtum區塊鏈支持比特幣類型交易,即UTXO類型的交易,目前支持比特幣定義的五種UTXO類型的交易。UTXO交易的基本單位是未經使用的一個交易輸出,當接收比特幣時,金額是在輸出的UTXO裏的,而且經過腳原本鎖定,要花費這個UTXO須要提供解鎖腳本。對於智能合約功能,當須要進行部署合約或調用合約相關功能時,是經過合約交易來觸發的,合約交易的形式很像UTXO,是經過增長了操做碼進行擴展的。
在未花費交易輸出(UTXO)模型中,交易使用未花費的比特幣做爲輸入,此時輸入的UTXO就會做廢,而輸出是另外一個UTXO, Qtum數量上變化的結果會在新的UTXO記錄。必定數量的Qtum在不一樣私鑰持有人之間進行轉移,新的未花費交易輸出在交易中花費,並記錄在區塊上。在交易中,UTXO可用交易接收方公鑰地址生成的祕鑰進行解鎖。Qtum處理交易時利用腳本語言只能進行有限的操做,並以堆棧的形式進行數據處理 ,並遵循「後進先出」(FIFO)原則。
基於UTXO模型的交易
UTXO模型有諸多優點: 任何人能夠經過比特幣公共帳本對每一筆交易歷史進行查詢,UTXO有良好的可拓展性,可以同時處理多個地址發起的交易請求。此外,UTXO模型也提供了隱私保護,用戶可使用變動地址做爲UTXO輸出。
每一筆UTXO交易都會記錄在區塊帳本上,只要知道了私鑰就能夠掃描帳本得到全部屬於該私鑰用戶的UTXO。用戶的全部餘額,是全部屬於用戶私鑰的UTXO金額的總和,錢包經過掃描整個區塊鏈收集到用戶全部的UTXO來計算該用戶的餘額。
比特幣腳本語言並非圖靈完備的,沒法實現循環功能。這極大地制約了交易執行量和交易複雜度。所以Qtum量子鏈在UTXO模型的基礎上加入抽象帳戶層設計,在基於UTXO模型的交易上實現智能合約平臺。
Qtum合約帳戶
Qtum量子鏈智能合約功能使用了以太坊虛擬機(EVM),EVM使用了與UTXO不一樣的帳戶模型,EVM使用基於帳戶(Account)的模型。 具體來講,以太坊經過帳戶狀態的改變進行價值和信息的交換與傳輸,並經過長度爲20字節的隨機數做爲指針以確保交易處理的惟一性。用於供內部使用的費用是以Qtum計價,經過合約交易中的參數GasPrice和GasLimit來指定。對於以太坊EVM合約代碼是可選的,但對Qtum的合約帳號來講是強制的,即帳號的生成一定伴隨有合約代碼,生成帳號時存儲默認爲空。
以太坊帳戶有兩種類型,一種由外部私鑰控制的外部帳戶,另外一種由合約代碼控制的合約帳戶。外部帳戶用於信息傳輸的建立、交易簽名。合約帳戶用於收到內部存儲讀寫操做信息後建立合約或發送其餘信息。以太坊中的帳戶餘額管理與平常生活中的銀行帳戶管理相相似。每個新產生的區塊都有可能影響其餘帳戶的全局狀態。每一個帳戶都有各自的餘額、存儲和代碼空間用於調用其餘帳戶或地址。Qtum智能合約帳戶和以太坊一致,經過長度爲20字節的隨機數做爲地址,但沒有外部私鑰控制的外部帳戶,UTXO帳戶和以太坊的外部帳戶相似,但經過腳本語言,其功能比以太坊強大。
分爲普通交易和合約交易兩種交易類型。
Qtum區塊鏈的普通交易和比特幣的交易是兼容的,目前支持比特幣定義的五種UTXO類型的交易,分別爲:P2PKH(Pay to Public Key Hash)、P2PK (Pay to Public Key)、多重簽名(少於15個私鑰簽名)、P2SH (Pay to Script Hash)和OP_RETURN。利用這五種交易標準,客戶端能夠知足複雜的支付邏輯。如下舉例簡單說明各類交易類型的用法:
P2PKH交易
使用P2PKH交易方式,咱們假設用戶向虛擬Qtum地址Bread Address
支付了0.01 QTUM購買麪包。該交易的輸出爲:
OP_DUP OP_HASH160 <Bread Public Key Hash> OP_EQUAL OP_CHECKSIG
OP_DUP複製堆棧頂層數據;OP_HASH160返回公鑰哈希值並存入棧頂。除了公鑰哈希值,還須要數字簽名和數字祕鑰才能擁有QTUM全部權。若棧頂數據一致,則OP_EQUAL返回真值(1),不然返回非真值(0)。OP_CHECKSIG生成公鑰和簽名,並校驗交易哈希值。若一致,則返回真值。
鎖定腳本相對應的解鎖腳本爲:
<Bread Signature> <Bread Public Key>
將上述兩個腳本相結合:
<Bread Signature> <Bread Public Key> OP_DUP OP_HASH160 <Bread Public Key Hash> OP_EQUAL OP_CHECKSIG
只有當解鎖腳本和鎖定腳本知足預先設定的條件時,執行結合腳本的輸出爲真。上述例子中,當Bread Signature簽名與Bread Address私鑰相匹配,則返回真值。
P2PK交易
P2PK交易的鎖定腳本爲:
<Bread Public Key> OP_CHECKSIG
對應的解鎖腳本爲:
<Bread Signature>
將上述兩個腳本相結合:
<Bread Signature> <Bread Public Key> OP_CHECKSIG
這樣只要Bread Signature使用Bread Public Key對應的私鑰簽名,執行結合腳本的輸出爲真。
多重簽名交易
一個M-N類型的多重簽名交易的鎖定腳本爲:
M <Public Key 1> <Public Key 2> ... <Public Key N> N OP_CHECKMULTISIG
鎖定腳本須要至少M個簽名才能解鎖。
一個設置了K(K>=M)個簽名的解鎖基本爲:
OP_0 <Signature 1> <Signature 2>…<Signature K>
將上述兩個腳本相結合:
OP_0 <Signature 1> <Signature 2>…<Signature K> M <Public Key 1> <Public Key 2> ... <Public Key N> N OP_CHECKMULTISIG
經過執行這個組合腳本,只要簽名成功的個數達到M就會輸出真。
P2SH交易
P2SH交易的鎖定腳本爲:
OP_HASH160 <redeem scriptHash> OP_EQUAL
其中redeem scriptHash是解鎖腳本的哈希值。
解鎖腳本的形式爲: <Signature> {redeem script}
P2SH執行等效於如下的兩個驗證:
1) {redeem script} OP_HASH160 <redeem scriptHash> OP_EQUAL
2)<Signature> {redeem script}
首先1)用於驗證{ redeem script }爲是否真,2)再驗證redeem script的執行結果爲真,只有兩個驗證都爲真時,整個贖回腳本才輸出真。
OP_RETURN
OP_RETURN容許在交易輸出上增長40字節的非交易數據,通常這個數據是一個哈希值,用於記錄證實。OP_RETURN 輸出的資金不能被使用,因此設置爲一個金額爲0的輸出,任何輸出不爲0的QTUM都會消失而不可用。OP_RETURN交易格式很簡單,以下所示:
OP_RETURN <data>
一個P2PKH交易例子
下面使用P2PKH交易方式,使用sendtoaddress發送一筆交易到一個公鑰哈希地址,詳細的交易信息以下:
{
"txid": "41af815df6af399bec82b4e7b25587463aec6c2c6a11815ddd62aaa314b9aa0c",
"hash": "41af815df6af399bec82b4e7b25587463aec6c2c6a11815ddd62aaa314b9aa0c",
"size": 225,
"vsize": 225,
"version": 2,
"locktime": 720,
"vin": [
{
"txid": "2dac9840b183661e5aed458133daa466765131bed7b2cd4e625ef9d477c81b71",
"vout": 0,
"scriptSig": {
"asm": "3044022073caa7d8fe0ba4a7561a6165369c32d6de48d594f0eab169aee82c915205ecc6022050c9ee0dcc7e8a967ea64e8c40df271c479d8bed446e10d0b4da9e05352248bc[ALL] 02646b87a66a70311619fe6e1cc0300a6940fd5bc191c16f1d6d4d1cea9fbe8e74",
"hex": "473044022073caa7d8fe0ba4a7561a6165369c32d6de48d594f0eab169aee82c915205ecc6022050c9ee0dcc7e8a967ea64e8c40df271c479d8bed446e10d0b4da9e05352248bc012102646b87a66a70311619fe6e1cc0300a6940fd5bc191c16f1d6d4d1cea9fbe8e74"
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 12.50000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 52f60b28f652ff43e07ddae02e6bb037f6937ef8 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a91452f60b28f652ff43e07ddae02e6bb037f6937ef888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"qR83KAp8u2nCxSpwTx39MSTrFedMerJydA"
]
}
},
{
"value": 1987.49909600,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 0bb60c781c8f31be21e3901b63cb7f25dd3aeeb0 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9140bb60c781c8f31be21e3901b63cb7f25dd3aeeb088ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"qJdJg7BaPV89Em8xQZyMdHni4Ss3VG5fTo"
]
}
}
]
}
複製代碼
其中輸入UTXO的hex格式的解鎖腳本由如下組成:
使用私鑰進行簽名的結果:473044022073caa7d8fe0ba4a7561a6165369c32d6de48d594f0eab169aee82c915205ecc6022050c9ee0dcc7e8a967ea64e8c40df271c479d8bed446e10d0b4da9e05352248bc0121
複製代碼
對應的公鑰:
02646b87a66a70311619fe6e1cc0300a6940fd5bc191c16f1d6d4d1cea9fbe8e74
複製代碼
組合在一塊兒就是"scriptSig"裏面的內容了。輸出的UTXO 0鎖定腳本爲:
OP_DUP OP_HASH160 52f60b28f652ff43e07ddae02e6bb037f6937ef8 OP_EQUALVERIFY OP_CHECKSIG
複製代碼
Qtum在設計上以比特幣UTXO爲基礎帳戶模型實現了支持EVM規範的智能合約,這是經過新增UTXO操做碼和帳戶抽象層(AAL)來完成的。AAL對UTXO帳戶和EVM合約帳戶之間進行了適配,這樣經過AAL可使用UTXO交易輸出實如今鏈上建立智能合約,發送交易到合約帳戶用於觸發合約的執行,完成執行後AAL最終對執行結果進行處理並適配至UTXO。因爲採用了AAL,合約開發者不需關心對合約操做相關的UTXO轉換細節,便可使用EVM的特性進行開發並且兼容現有以太坊的智能合約。
Qtum合約交易處理
Qtum 針對UTXO交易腳本新增了三個操做碼OP_CREATE,OP_CALL和OP_SPEND,目的是用於爲UTXO和EVM帳戶模型之間的轉換提供操做支持。這個三個操做碼分別有如下做用:OP_CREATE用於智能合約的建立;OP_CALL用於合約的執行;OP_SPEND用於合約餘額的花費。
產生或驗證新的區塊時,除了對UTXO交易進行常規的參數合法性、共識規則、DDOS攻擊檢查等以外,還須要使用操做碼檢查函數判斷交易輸出是否包含OP_CREATE或OP_CALL,分別對應着EVM須要執行合約建立或合約調用。在合約建立和執行前,須要進行UTXO交易到EVM模型交易的轉換,以後使用構建的EVM執行環境和引擎,完成合約的執行。
目前合約交易相關的qtum-cli命令或RPC有:
createcontract "bytecode" (gaslimit gasprice "senderaddress" broadcast)
複製代碼
其中: bytecode(必選): 智能合約編譯生成的字節碼 gaslimit(可選): 最大gas數量,默認是2500000 gasprice(可選):gas價格,以QTUM爲單位,默認爲0.0000004 senderaddress(可選):指定發送者的地址,默認爲當前帳號地址 broadcast(可選):是否廣播,默認爲true
好比,
qtum-cli createcontract "60606040525b33600060006101000a81548173fffffffffffffffffffffffffffff fffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256"
複製代碼
或
qtum-cli createcontract "60606040525b33600060006101000a81548173ffffffffffffffffffffffffffff ffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256" 3000000 0.0000005
複製代碼
均可以完成部署同一個智能合約。
sendtocontract "contractaddress" "data" (amount gaslimit gasprice senderaddress)
複製代碼
contractaddress (必選): 智能合約地址,大小20字節 data(必選): 智能合約調用函數及參數 amount:發送到智能合約的QTUM數量,可選擇爲0 gaslimit(可選): 最大gas數量,默認是2500000 gasprice(可選):gas價格,以QTUM爲單位,默認爲0.0000004 senderaddress(可選):指定發送者的地址,默認爲當前帳號地址 broadcast(可選):是否廣播,默認爲true
好比,
qtum-cli sendtocontract "c6ca2697719d00446d4ea51f6fac8fd1e9310214" "54f6127f"
複製代碼
或
qtum-cli sendtocontract "c6ca2697719d00446d4ea51f6fac8fd1e9310214" "54f6127f" 12.0015 6000000 0.0000005
複製代碼
或
qtum-cli sendtocontract "c6ca2697719d00446d4ea51f6fac8fd1e9310214" "54f6127f" 12.0015 6000000 0.0000005 qYcH9wHcd86LaDAAxquKPyfpmSraxAbBop
複製代碼
均可以完成發送交易到智能合約,調用智能合約提供的功能。當須要配置某個參數時,該參數前面的參數也要配置,好比須要配置senderaddress時,gaslimit和gasprice也要相應的配置。
Qtum主網發佈後在連接 github.com/qtumproject…上提供已經編譯好的軟件下載,支持Windows 、Linux和OSX平臺,支持X86和ARM架構。也能夠本身 下載源代碼進行編譯生成。Qtum core可執行軟件qtumd和qtum-qt都具備全節點功能,同時也具備錢包功能。 節點數據和錢包文件wallet.dat默認保存在電腦的特定目錄下,不一樣操做系統對應的目錄以下:
下面介紹在Linux上和Mac OS上從源代碼編譯Qtum Core的方法。
sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils git cmake libboost-all-dev
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:bitcoin/bitcoin
sudo apt-get update
sudo apt-get install libdb4.8-dev libdb4.8++-dev
sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
複製代碼
git clone --recursive https://github.com/qtumproject/qtum.git
cd qtum
git submodule update --init --recursive
複製代碼
cd 到qtum目錄下,執行
./autogen.sh
./configure
make install
複製代碼
此時src文件夾會生成qtumd、qtum-cli、qtum-tx,和src/qt文件夾下的qtum-qt
如下須要安裝的工具或者庫,若是已經安裝過,能夠忽略對應步驟,直接進入下一步。
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
複製代碼
xcode-select --install
複製代碼
brew install cmake automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf qt libevent
複製代碼
這一步安裝的包比較多,若是電腦裏從未安裝過以上的包的話,須要耐心的等待一段時間。
首先找個路徑來存放qtum的代碼,沒有的話新建個路徑,好比代碼放在路徑~/workspace/qtum
cd ~/workspace/ qtum
git clone --recursive https://github.com/qtumproject/qtum.git
cd qtum
git submodule update --init –recursive
複製代碼
./autogen.sh
./configure
make install
複製代碼
此時src文件夾會生成qtumd、qtum-cli、qtum-tx,和src/qt文件夾下的qtum-qt
QTUM的全部權是私鑰、地址和簽名來確立的。私鑰是QTUM的全部權的證實,全部權認證基於密碼學證實的安全模型。私鑰的泄漏也就會致使獲得私鑰的人能夠轉移掉私鑰控制的QTUM,所以要保護好本身的QTUM私鑰。地址是由私鑰導出公鑰,並對公鑰進行哈希和編碼後獲得的,用於接收QTUM。簽名用私鑰對交易進行簽名並造成解鎖腳本,從而證實某個UTXO的全部權。錢包,是管理生成、存儲私鑰,並實現接收和發送QTUM功能的工具,錢包通常把私鑰保存在一個文件或簡單的數據庫中,所以錢包文件的保存很重要,在沒備份私鑰的狀況下丟失錢包文件也就丟失了該私鑰擁有的QTUM。下面介紹兩種QTUM錢包的使用。
Qtumd自帶錢包數據保存在.qtum目錄下的wallet.dat文件,因此要妥善保管wallect.dat文件,須要常常進行備份不然一旦丟失或損壞裏面的QTUM將永久丟失。qtum-cli是和qtumd交互的命令行工具,經過qtum-cli + 命令 + 參數方式使用。
錢包相關的經常使用命令有:
getaccount "address" // 獲取地址對應的帳戶名
getaccountaddress "account" // 獲取某個帳戶名下關聯的一個地址
getaddressesbyaccount "account" // 獲取某個帳戶名下關聯的全部地址
getbalance ( "account") // 獲取帳戶可花費的QTUM數量
getnewaddress ( "account" ) //生成指定帳戶名的一個新地址
dumpprivkey "address" //導出私鑰
importprivkey "mykey" // 導入私鑰
listaccounts //列出全部在用帳戶名
sendtoaddress "address" amount //往某個地址發送必定數量的QTUM
複製代碼
qtum-qt錢包支持完整功能的全節點,支持錢包應用。PC錢包數據保存在.qtum目錄下的wallet.dat文件,和qtumd共享這個文件,要妥善保管wallect.dat文件,常常進行備份。運行qtum-qt便可以打開軟件。打開錢包時進入到Overview界面,以下所示:
點擊錢包左邊的Send按鈕,進入發送Qtum的操做界面,能夠往特定的地址發送Qtum。使用流程以下:
發送QTUM
選擇手續費
點擊錢包左邊的Receive按鈕,進入接收Qtum的操做界面,能夠管理用於接收Qtum地址。使用流程以下:
管理接收地址
智能合約(Smart Contract),是密碼學家Nick Szabo在1994年首次提出以數字形式定義的一系列承諾(promises),包括合約參與方能夠在上面執行這些承諾的協議。智能合約經過區塊鏈來執行,所以一旦設立指定後,可以無需中介的參與自動執行。
Qtum支持使用Solidity語言進行智能合約的編寫。Solidity寫好智能合約的智能合約,可使用solc來編譯,也能夠直接使用基於瀏覽器的編譯器,好比Remix Solidity IDE。下面經過一個簡單的例子來講明開發、部署智能合約的過程。
Qtum支持與EVM兼容的智能合約,編寫智能合約最經常使用的語言是Solidity。編寫完智能合約以後能夠採用Remix Solidity IDE進行編譯,該工具一個基於瀏覽器的編譯器,其連接以下:ethereum.github.io/browser-sol…
這裏經過一個簡單的智能合約實例,說明合約怎樣完成編譯,部署以及和合約交互。測試的智能合約代碼以下:
pragma solidity ^0.4.11;
contract Test {
uint256 public totalSupply = 0;
mapping (address => uint256) public balanceOf;
function Test() { }
modifier validAmount(uint256 _amount) {
require(_amount > 0);
_;
}
function contribute() public payable validAmount(msg.value)
returns (uint256 amount) {
uint256 tokenAmount = msg.value/100000000;
totalSupply += tokenAmount;
balanceOf[msg.sender] += tokenAmount;
return tokenAmount;
}
}
複製代碼
把以上代碼拷貝到Remix Solidity IDE左邊的空白處,點擊右邊Contract details就能夠看到編譯生成的字節碼(bytecode)。這是智能合約編譯後的可執行二進制代碼,下面的部署就是用這個生成的字節碼。部署智能合約至關因而安裝一個軟件到操做系統,所以須要把智能合約部署到量子鏈後,才能使用該智能合約的服務。
使用Remix Solidity IDE編譯智能合約
部署智能合約須要訪問Qtum區塊鏈的節點,經過Qtum節點提供的cli命令行或RPC調用能夠進行智能合約相關的操做。
首先要運行Qtum全節點軟件qtumd,把編譯生成的字節碼(bytecode)copy一份,而後使用qtum-cli調用createcontract能夠把智能合約部署到Qtum量子鏈上。
qtum-cli createcontract 60606040526000600055341561001157fe5b5b5b5b6101b7806100236000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005157806370a0823114610077578063d7bb99ba146100c1575bfe5b341561005957fe5b6100616100df565b6040518082815260200191505060405180910390f35b341561007f57fe5b6100ab600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506100e5565b6040518082815260200191505060405180910390f35b6100c96100fd565b6040518082815260200191505060405180910390f35b60005481565b60016020528060005260406000206000915090505481565b60006000346000811115156101125760006000fd5b6305f5e1003481151561012157fe5b0491508160006000828254019250508190555081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508192505b5b5050905600a165627a7a723058203e478f327587dc2eb6995d102ce549279f911bc27074dc932ef8b81bad7bb0ba0029 3000000 0.0000005
複製代碼
3000000 0.0000005是 gaslimit和gasprice參數,參考第2.3.1節知道者兩個參數能夠不設置或能夠改成其餘的值。命令執行後或產生以下輸出:
{
"txid": "52b3eef0fe0032f685974256972b340655501fc87adec4cffe2b96cc46446001",
"sender": "qYcH9wHcd86LaDAAxquKPyfpmSraxAbBop",
"hash160": "a5161fee8ff92457c0829889854888b45255f961",
"address": "2d4b6564a012ae1383854ac48574c2248660d897"
}
複製代碼
這個輸出是一個交易,全部合約相關的功能都是經過發送交易觸發的,該交易在Qtum量子鏈上部署了地址爲2d4b6564a012ae1383854ac48574c2248660d897的智能合約。智能合約的須要等待區塊對交易確認後,纔在Qtum鏈上部署完成。
和智能合約的交互也須要訪問Qtum區塊鏈的節點,經過Qtum節點提供的cli命令行或RPC調用能夠和智能合約進行交互,使用智能合約提供的服務。使用智能合約比較簡單,首先是生成須要交互的函數或公共變量的ABI(Application Binary Interface)數據,以後使用sendtocontract發送合約交易,完成和Qtum鏈上智能合約交互。使用callcontract能夠在本地調用智能合約相關函數或公共變量,但其執行只在本地執行,不會影響到鏈上的智能合約狀態。
ABI是和智能合約交互的接口,爲了使用上一節部署的合約,須要智能合約相關函數和參數生成的數據(ABI數據),可使用ethabi工具把函數和參數轉換成以上的」data」數據。
首先建立一個空文件test.json,把Remix Solidity IDE右邊的Interface的內容放到文件test.json上。好比上面的合約ABI以下:
[{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"contribute","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]
複製代碼
ethabi encode function ~/test.json contribute
複製代碼
獲得輸出數據:
d7bb99ba
複製代碼
balanceOf(Address)須要傳遞Address參數,使用選項-p指定,Address是一個20字節的16進制參數,使用ethabi運行:
ethabi encode function ./test.json balanceOf -p a5161fee8ff92457c0829889854888b45255f961
複製代碼
獲得輸出:
70a08231000000000000000000000000a5161fee8ff92457c0829889854888b45255f961
複製代碼
totalSupply是一個帶有public屬性的變量,所以雖然totalSupply不是一個函數,但也能夠和它進行交互,一樣使用ethabi生成交互所需的數據:
ethabi encode function ./test.json totalSupply
複製代碼
獲得輸出:
18160ddd
複製代碼
若是要調用鏈上的智能合約,把執行結果保存在鏈上,須要發起一個合約交易,這是經過sendtocontract來完成的。使用sendtocontract發起一個合約交易的格式以下:
sendtocontract "contractaddress" "data" (amount gaslimit gasprice senderaddress)
複製代碼
其中「data」爲上一節產生的ABI數據,所以要調用合約的contribute函數,採用以下的命令:
sendtocontract 2d4b6564a012ae1383854ac48574c2248660d897 d7bb99ba 2 1000000 0.0000004 qYcH9wHcd86LaDAAxquKPyfpmSraxAbBop
複製代碼
d7bb99ba即爲數據,2是這筆交易發生到智能合約的QTUM數量,1000000是gaslimit,0.0000004是gasprice, qYcH9wHcd86LaDAAxquKPyfpmSraxAbBop是senderaddress。此處爲了指定senderaddress,須要把前面的amount、gaslimit 、gasprice參數也指定,執行後命令會返回:
{
"txid": "1e9742000cc5d261f18b3ecc41ffd44b37f965567127b1779fb7d48b12bdfcda",
"sender": "qYcH9wHcd86LaDAAxquKPyfpmSraxAbBop",
"hash160": "a5161fee8ff92457c0829889854888b45255f961"
}
複製代碼
合約交易的執行須要新區塊打包和執行,所以查看智能合約的結果須要等待至少1個區塊的確認。
雖然使用callcontract能夠在本地調用智能合約相關函數或公共變量,但其執行只在本地執行,不會保存結果和影響到鏈上的智能合約狀態。所以該功能通常用於查看由sendtocontract發起的合約交易引發的智能合約狀態改變結果。其格式以下: callcontract "address" "data" ( senderaddress )
好比要查看a5161fee8ff92457c0829889854888b45255f961的balance使用:
callcontract 2d4b6564a012ae1383854ac48574c2248660d897 70a08231000000000000000000000000a5161fee8ff92457c0829889854888b45255f961
複製代碼
命令返回:
{
"address": "2d4b6564a012ae1383854ac48574c2248660d897",
"executionResult": {
"gasUsed": 23183,
"excepted": "None",
"newAddress": "2d4b6564a012ae1383854ac48574c2248660d897",
"output": "0000000000000000000000000000000000000000000000000000000000000002",
"codeDeposit": 0,
"gasRefunded": 0,
"depositSize": 0,
"gasForDeposit": 0
},
"transactionReceipt": {
"stateRoot": "cb3e98d8bfcde37e37df441915a3d6f50712a7e368f6e798cc804aa574fd6c27",
"gasUsed": 23183,
"bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"log": [
]
}
}
複製代碼
在PC錢包(qtum-qt軟件)上能夠經過GUI實現和qtum-cli一樣的智能合約的部署、交互等功能。
部署合約都是要和Qtum鏈上進行交互的,所以鏈接到一個全節點,因爲PC錢包自己是一個全節點,所以不須要另外運行qtumd之類的節點。在PC錢包左邊點擊Smart Contract按鈕出現智能合約功能界面,點擊Create後,把4.1節編譯的字節碼拷貝在Bytecode輸入框,同時把ABI也放入對應的輸入框。對應qtum-cli createcontract命令參數,界面下面的GasLimit、GasPrice、和Sender Address能夠設置。最後點擊Create Contract按鈕,就會生成一個合約交易,把合約部署到Qtum鏈上,彈出的對話框顯示了發送者、合約地址等相關信息。
PC錢包部署智能合約
和智能合約的交互,一樣要鏈接Qtum節點,經過PC錢包就能夠了。生成須要交互的函數或公共變量的ABI數據能夠參考4.3.1節。點擊Sendto切換到合約交易生成界面,把Contract Address、ABI填好,從Functtion選擇要調用的函數,有函數參數的話,在address dest面填寫參數,GasLimit、GasPrice、和Sender Address能夠根據須要設置。點擊Send To Contract按鈕即生成了合約交易, 完成和Qtum鏈上智能合約交互。
和智能合約交互
和callcontract同樣能夠經過qt錢包在本地調用智能合約相關函數或公共變量,其執行不會影響到鏈上的智能合約狀態,通常用來查看智能合約在Qtum鏈上執行某個函數以後的結果。點擊Call按鈕切換到本地執行合約界面,把Contract Address、、ABI填好,有函數參數的話,在address dest面填寫參數,從Functtion選擇要調用的函數,Sender Address可選設置,最後點擊Call Contract完成智能合約相關功能調用,合約執行的結果會在彈出的對話框中顯示出來。
本地調用智能合約
在 qtum 智能合約中,msg.value 使用的單位是 Satoshi, 即聰, 1 qtum = 10^8 聰; 而在以太坊中,msg.value 使用的單位是 wei, 1 ether = 10^18 wei 。
若是你在 Qtum 智能合約中使用了 ether 關鍵字,那麼它實際至關於10^10 qtum。
爲了不沒必要要的麻煩,請不要使用 wei、ether 等單位,而是直接使用數字。
在 Qtum 上發行合約代幣時, 推薦將 decimals 設置爲 8 。
調用智能合約,傳遞address類型參數的時候,須要使用hash160地址,而不是Q開頭的qtum地址。可使用qtum-cli gethexaddress命令將qtum地址轉換爲hash160地址。
啓動 qtumd 或者 qtum-qt 的時候使用 -logevents 參數,而後使用 qtum-cli searchlogs 或者 qtum-cli gettransactionreceipt 獲取 event log 。