當前位置:
首頁 > 最新 > 使用Group操作碼實現代幣化

使用Group操作碼實現代幣化

綜述

本文對GROUP屬性進行了定義,它包含一個最小32位元組的組標識符(group identifier)和一個整數「數量」。這個屬性可以定義為一種新交易格式版本里的一個屬性,或是通過新操作碼(OP_GROUP)執行的部分輸出腳本。

Group本質上是建立可互換性壁壘,由共識規則執行:在一筆交易里,不同Group標記的金額不能混合,grouped input的數量必須等於output數量(Group交易餘額),除非這筆交易鑄幣和銷毀許可權被激活。因此,Group最基本的用途是創建代幣。

Group有普通交易和管理操作兩種。Group的管理操作是指為Group創建者預留(或指定)的功能,例如,鑄幣和銷毀代幣。Group的管理通過交易實現,這些交易實際上「打破」了通常由礦工執行的規則,例如交易Group餘額。為了獲取這種能力,Group的管理員必須包含一種特殊的UTXO作為交易輸入。這些UTXO叫做group authority UTXO。

創建一個Group需要構建一筆交易創建一個group authority UTXO,由此獲得所有的管理許可權。隨後的交易可以花費這個UTXO,再創建其他的group authority UTXO,來執行某些group操作(比如說鑄幣)。這些group authority UTXO有特殊標註,但在編寫腳本/花費時,它們與普通的UTXO是一樣的,所以Group的創建者可以將這些UTXO發送到新地址,實現密鑰輪換(key rotation),或者將其發送給其他人或多重簽名地址進行授權。由於可以創建新的groupauthority UTXO,這些許可權可以永久性保留,或者管理員可以通過不再創建新的groupauthority UTXO放棄某一個許可權。

本方案引入了腳本模板。腳本模板把兌換腳本里的常量部分和可變部分分離。Group可以執行一項規則,某個grouped output的兌換腳本必須與第一個grouped input的兌換腳本模板相匹配,這是可選的。通過這種方式,只要智能合約的是用比特幣腳本語言編寫的,代幣發行方就可以創建一個由鏈上「智能合約」管理的代幣。

要求

問題陳述

支持SPV錢包

簡化的支付確認(簡稱SPV)技術是使用輕錢包的基礎,很多終端用戶在手機上使用的就是輕錢包。因為比特現金將來可能會發展到使用非常大的區塊,所以個人用戶可能無法運行全節點。SPV錢包對於確保人人都可以無需信任、無需許可、免受審查地使用BCH網路來說非常重要。比特現金的目標是成為人人都可以使用的世界貨幣。而代幣非常重要的一個用途是,通過讓所有人都可以使用BCH購買代幣,推動比特現金的應用和普及。因為SPV錢包是且將會是人們使用BCH網路最常見的方式,我們需要這些錢包支持代幣。

類似於比特幣的貨幣屬性:無需許可、無法阻擋、匿名、點對點、不可逆、無需信任

比特現金因其獨特的屬性在世界貨幣里佔據一席之地。基於比特現金的代幣也會憑藉相同的屬性在代幣市場里佔據一席之地。根據應用不同(股票市場、土地登記等等),通常情況下其他解決方案更為完善和高效。但是類似比特幣的獨特屬性使代幣可以為很多使用場景提供解決方案。

限制發行方的權力,保護所有權

發行方不能因為現有的代幣而破壞似比特幣的貨幣屬性,除非發行方可以花掉代幣。換句話說,區塊鏈必須防止發行方干涉代幣轉移或持有代幣的權利,除非這種特例已編入代幣合約。至於其他權力,例如「鑄幣」(增發),必須可證明(發行方)已放棄這項權利。放棄鑄幣權才能保證代幣限量發行。

區塊鏈必須記錄個人持有的代幣數量,而不是信任發行方做這件事。這就好比區塊鏈記錄BCH的數量。代幣的價格可能會因外部因素出現波動(例如,安全性、公眾對發行方支持或公司表現的信任度都有可能會影響到價格),但這與外部因素會引起BCH價格波動是一樣的。

通用的腳本語言

代幣和BCH必須使用相同的腳本語言限制output。這樣隨著腳本語言的發展,代幣和BCH都可以得到加強。

功能描述

創建Group

任何人都可以通過發起交易創建一個特殊輸出group authority UTXO,以此創建Group。除了正常的交易手續費外,建Group不需要任何成本。該輸出會用32位元組的組標識符進行標記,組標識符通過該筆交易的第一個輸出(熵源)與任意選擇的隨機數進行SHA256得到。Group id的最後一個位元組是標記位元組,用於描述該Group的一些功能。像比特幣地址一樣,Group的創建者不能選定組標識符,這樣不會與現有Group產生衝突,但是創建者可以通過增加隨機數(類似於vanity addresses)快速計算多種可能性,來確定一些bits。這樣創建者可以找到一個擁有理想標識位元組的Group id。

Input:

第32位元組的組標識符是標記位元組,定義如下:

最多 22 列

附加數據可以放到建Group那筆交易的output OP_RETURN欄位。這些信息可以用於為錢包提供更友好的用戶界面,用於為用戶提供額外信息,例如法律文件。此信息的標準請參見附錄C。

Group Authority UTXO

Group Authority UTXO允許交易執行操作,稱為許可權(capability),共識規則通常是不允許這樣操作的。Group Authority UTXO可以用於創建更多的Group AuthorityUTXO。所以,實體有權發送Group Authority UTXO,就有權創建其他的Group Authority UTXO,可以保留自己的許可權,或者花掉所有的UTXO,移除自己的許可權。

Group authority UTXO可以包含任意的比特幣兌換腳本,permission-to-use可以像比特幣的permission-to-spend一樣變化和有趣。例如,只需要把groupauthority UTXO發送到新地址就可以實現「私鑰輪流」(更換Group的管理員),很簡單。

管理權分為不同的許可權。從企業的角度來看,比特幣錢包要在訪問和安全之間權衡。代幣發行方的私鑰也存在這樣的權衡,因為發幣和rescripting是最重要的權力。把權力分散,Group許可權系統將提供極大的安全性。

目前的許可權有:

普通的Group output有一個專門指定代幣數量的欄位。在authority output里,數量欄位不是必要的,沒有必要再包含上述標記。但是,為便於清楚說明,本文大多數表格/例子的數量和許可權/隨機數欄位都是分開顯示。

讓我們看一些示例場景(重點在鑄幣操作):

移除鑄幣許可權

最安全的方案是限制代幣的發行量。代幣發行方可以花掉所有擁有MINT bit set的group authority UTXO,證明代幣的發行量是有限的。假設我們有一個地址bitcoincash:qpae0tg5k4mh5uhhcnwkx2rytj3800j8nunzm8rmed,我們想要創建一個Group限量發行1,000,000個代幣。通過兩次發幣操作,發送100,000個代幣到地址1,發送900,000個代幣到地址2。

創建Group的初始交易(TX0)

Input: 9944d3a522d70d3b0ec4bd395591bd19c5430e6c29e2373a50348f77c9b5b86e,0 (任意UTXO)

Output:

創建Group的初始交易會生成一個mint authority UTXO,我們會在下一筆交易中用到這個UTXO。

第一筆鑄幣交易(TX1):

Input: TX0,0 (上述創建的mintauthority UTXO)

我們通過這筆交易鑄了100,000個代幣,並又創建了一個mint authority UTXO。

第二筆鑄幣交易(TX1)

Input: TX1, 1 (第一筆鑄幣交易創建的mintauthority UTXO)

Output:

我們通過這筆交易鑄了900,000個代幣。注意,這筆交易不會再構造mint authority UTXO。mint authority UTXO已用完,無法再創建新的。這證明這個Group實際只有1,000,000個代幣。當然,更簡單的做法是,用一筆交易兩個output創建1,000,000個代幣。我們在這裡分兩筆交易完成是為了演示。

根據不同應用,限制數量的Group可能需要或想要銷毀代幣或是rescript。通過分權,代幣發行方可以在放棄某些許可權的同時保留另外一些許可權。

保護鑄幣權UTXO(Securing Mint Authority UTXO)

但是,保留髮幣權力是一個常見要求。設想一下,一個代幣由某種貨幣作為擔保,需要定期發幣/銷毀代幣,以保證與儲備金等值,但這需要極大的安全性。

首先,在公司高層之間創建一個多重簽名地址(masterAddr),作為最後的訴求手段。因為這個地址很少會用到,所以可以離線存儲和離線簽名,非常安全。

創建下一個Group「G」,生成一個具備所有許可權的authority UTXO。我們將其稱之為master group authority UTXO。在這個場景下,無論我們什麼時候花掉這個UTXO,我們都可以創建出另一個擁有相同許可權的output,一個未花費一次可以創建出一系列master group authority UTXO。但為了簡化概念,我們不會一直對這點進行說明,而是用master group authority UTXO這個術語指代現在的UTXO,即使這個UTXO會多次被花費和重建。

無需信任發幣

代幣公開發行之前(代幣獲得任意貨幣支持之前),創建代幣可能會是在不安全的環境中完成的。我們假設發行方聯繫了一個不可信的代理,讓其用某些初始配置創建Group。在創建代幣期間,這個代理可以執行多次交易,發行方不需要了解或檢查這些交易。當創建代幣完成,區塊鏈的UTXO集合將會包含所有可用的許可權。因此,發行方只需要檢查最終的UTXO集合,保證沒有不知道的授權即可。發布者是無法隱藏未轉播和未確認的授權交易的,因為之前所有的authority UTXO都已經被花出去。因此,他隱藏的交易將一筆毫無價值的雙花交易。所以,創建代幣無需信任。

密鑰輪換(Key Rotation )

一旦創建完成,master group authority UTXO就可以發送到在企業高層之間創建的安全性更高的地址(記為已知地址)。

如有高層出現變動,這個UTXO可以發送到新的多重簽名地址,實現「密鑰輪換」。

密鑰輪換也可以用於其他 authority UTXO。

定期發幣

發幣時,Group可以設置為定期創建一定數量的代幣。要實現這個功能,我們要用mastergroup authority創建一筆交易,生成多個mint authority UTXO。這些authority UTXO無需許可再創建出更多的authority UTXO(CCHILD bit),這樣實現一次性授權。數量欄位可以進行設置,限制這項一次性授權只能用於創建一定數量的代幣。

首先,我們在負責發幣的人之間創建一個多重簽名地址(mintPubKeys)。接著定義輸出腳本。我們會使用用於鎖定比特幣一段時間的哈希時間鎖合約(HTLC)腳本。

def futureSpend(date, minKeys, mintPubKeys...)

{

date

OP_CHECKLOCKTIMEVERIFY

OP_DROP

minKeys

mintPubKeys

number of mintPubKeys

OP_CHECKMULTISIG

}

上述用到的比特現金腳本語言簡介可參見附錄A。

現在讓我們來創建這筆交易。

授權定期鑄幣交易的創建:

Input: 上述創建的master group authority UTXO

例如,提前創建一年份的UTXO,mintPubKeys所有者就可以去處理日常的經營活動。如果出現異常,mintPubKeys所有者仍可以隨時再創建新的mint authority UTXO。

如果mintPubKeys被破解,定期發幣的特性也可以拖延偷盜者發幣的速度,因為特定時間內只能花費一筆UTXO,每筆發幣交易創建的時候都限定了發幣數量。如果這個代幣足夠有價值,有必要進行人為干預,一旦UTXO到期(可以花費),公司就可以與盜賊競爭花費這個UTXO,還有可能會獲得礦工的支持。

即使認為私鑰沒有被破解,公司也最好迅速執行發幣交易,以使合法交易的速度快於潛在私鑰破解者的交易速度。如果公司跑贏私鑰破解者,就會發現破解者在網路上雙花,同時公司不會有任何資金損失。

可撤銷的定期發幣

但這些選擇並不合適; 我們真的想要一種方法來廢除已經被破壞的mint authority UTXO。有兩種可能性。

通過未確認交易來撤銷鑄幣許可權

第一種方法是使用未確認交易。 創建一個哈希時間鎖合約(HTLC)和另一個花費少量比特幣的UTXO。 使用這些UTXO作為創建鑄幣許可權交易的input。 在這個HTLC可用之前,這個不可轉發的交易將會被網路拒絕。 通過這種設置,無效化mintauthority UTXO只需要將input UTXO加倍。 由於這個鑄幣許可權的交易在到期之前是不可轉發的,因此網路不會將此視為雙重支出。

如果小偷在不被發現的情況下破壞了鑄幣許可權密鑰,並且有mint authority creation transaction,則當第一HTLC到期時,通過轉發mint authority creation transaction然後用它來鑄幣,他可以發起一個鑄幣交易。 一旦在網路上看到該交易,該公司就可以重複花費所有其他mint UTXOs。

請注意,為了清楚起見,此描述使用3個input(每個input具有獨立功能),但應該可以組合這些功能中的任意兩個來實現更簡單、更有效的應用。

通過未確認交易來撤銷鑄幣許可權

第二種方法是在mint group authority UTXO中使用「緊急支出」條款。 首先創建一個緊急支出多重簽名地址,並將其存儲為「masterAddress」。接下來使用以下兌換腳本創建mint group authority UTXO:

現在,如果出現問題,可以在使用mintSig之前,使用緊急pubkeys來花掉UTXO。 由於在正常操作期間不使用緊急pubkeys,因此可以非常安全地存儲它們。並且它們必須安全存儲,因為如果被盜的話,小偷就可以花掉所有mint UTXO。 因此,此選項不如第一個選項安全,但可能更容易實現。

OP_IF

OP_CHECKLOCKTIMEVERIFY

OP_DROP

OP_CHECKMULTISIG

OP_ELSE

OP_CHECKMULTISIG

OP_ENDIF

受合約限制的Group(契約)

論文《比特幣契約》首次提出一個很強大的概念:限制output腳本為某個特定模板。雖然這項普通功能可以實現各種不同特性不屬於本文討論的內容,但是,契約存在一些關於把input covenant和數量應用到output的實際問題。

如果group擁有這樣一種特性:所有的Grouped output都必須匹配一個腳本模板,我們將解決契約的問題,真正在比特現金上實現智能合約。我們的方法是,使用group id里的bit定義受合約限制的group和不受合約限制的Group,以創建一個無需新操作碼的腳本模板公式,然後作為一條共識規則,強制Grouped output腳本匹配第一個Grouped input腳本的模板。

創建腳本模板A

雖然《比特幣契約》提出了一個新的模板對比操作碼(template comparison opcode),但是我們可以在不改變比特幣腳本的情況下實現契約。首先從審查封裝P2PKH(pay to public key hash) 贖回腳本的P2SH(payto script hash)ouput花費開始。我們將其發送至一個由pubkey和addr標記的地址(addr = hash160(pubkey)),sig即簽名,像p2pkh(pubkeyhash)和p2sh(scripthash)這樣的函數定義大家所熟知的P2PKH和P2SH腳本程序(這些會在下面演示)。我們遵循的腳本規範:將單行數據推送至堆棧,操作碼是OP_XXXXX。通過引入宏定義,我們對此進行了擴展,這將會通過替換進行「編譯」,類似於C宏。

讓我們從輸入腳本開始,因為這首先執行:

sig

pubkey

Binary serialization of: p2pkh(addr)

因為無論最後壓入什麼,都是壓入堆棧頂部,所以在看下一步執行輸出腳本時別忘了把上面的內容倒過來。

def p2sh(scriptHash)

{

OP_HASH160

scriptHash

OP_EQUAL

}

執行這條指令後,我們已經移去棧頂的項目:Binary serialization of: p2pkh(addr),因此這個堆棧(這裡的頂部是真的頂部)看起來會是這樣:

Pubkey

Sig

接下來有點尷尬,因為系統「神奇地」知道它應該執行棧頂項目:Binaryserialization of: p2pkh(addr)。P2PKH腳本如下:

def p2pkh(pubkeyhash)

{

OP_DUP

OP_HASH160

pubkeyhash

OP_EQUALVERIFY

OP_CHECKSIG

}

這需要公鑰和簽名,根據OP_CHECKSIG的結果真或假在堆棧上完成腳本的執行。

接下來,我們會用一種類似p2sh的技術創建一個pay-to-template-script-hash(p2tsh) output。我們的方法是把模板「變數」從兌換腳本 (這裡我指的是 p2pkh) 里分離出來,將其壓入輸出腳本的堆棧里。我們就得到了一個腳本哈希值沒有變數的p2sh變體。然後我們可以要求交易里的所有grouped inputs 和 outputs,這個腳本哈希值都必須匹配。

除了一個不同的腳本(p2tpkh,描述如下)是序列化的,其他和p2sh是一樣的。我們先從input腳本開始,因為它首先執行:

sig

pubkey

Redeem script, binary serialization of:p2tpkh(addr)

接下來,輸出腳本:

def p2tsh(scriptHash)

{

// first the standard P2SH, except let』s fix the birthdayattack issue by using 256 bit hashes rather than 160.

OP_HASH256 scriptHash

OP_EQUAL

// next, something new: supply needed parameters to thescript

pubkeyhash

}

像p2sh一樣,到這裡我們已經移除該腳本並驗證其哈希匹配(hash match)。另外,我們已經壓入我們的模板參數(公鑰哈希值),所以堆棧看起來與p2sh的有所不同:

Pubkeyhash

pubkey

Sig

接下來執行p2pkh變數的腳本:

def p2tpkh()

{

OP_SWAP

OP_DUP OP_HASH160

OP_EQUALVERIFY

OP_CHECKSIG

}

注意,這個贖回腳本會拿走其在堆棧上的所有數據。這裡沒有「寫死」的數據值,正如p2pkh腳本里所發現的pubkeyhash。有些堆棧數據是由input腳本提供的,像p2sh一樣,有些是由output腳本提供的。因此這個兌換腳本將會作為一個模板。

實現這個「腳本模板」唯一需要改變的是,把這個腳本類型添加到isStandard,對它就像P2SH一樣,也就是說需要知道去執行redeem腳本模板。這不是更改共識規則,只是執行兌換腳本的P2SH「魔術」。

不合作實體注意事項(Caveats For UncooperativeEntities )

讓我們暫時假設Group管理員可以對所有Grouped output執行腳本模板。他可以通過執行一個腳本制定一項政策,部分代幣持有者可能不喜歡這項政策並試圖推翻它。讓我們來看一下,當腳本模板創建者和當前所有者發生分歧時,這個系統會如何運作。以下是一個示例腳本,Group管理員擁有「claw back」的能力:

OP_SWAP

OP_IF

p2tpkh()

OP_ELSE

OP_DROP

p2pkh(ClawBackPubKeyHash)

OP_ENDIF

這個模板參數是所有者的pubkeyhash。所有者用「ownerPubkey ownerSig 1」進行花費。「管理員的claw back」可以用「clawbackPubkeyclawbackSig 0」花費。但是,新的所有者可以通過把「1pubkeyhash」壓入堆棧否決管理員的條款。接著,所有者用「ownerPubkey ownerSig」花費,Group管理員因為「1」 causes the OP_IF to be always taken無法花費。本質上,所有者使用的模板參數已經超出「預期」數量,並欺騙腳本用它提供的參數,而不是用來自於花費腳本的參數。

這需要更複雜的腳本,總從堆棧的底部抓取第三個項目。

OP_DEPTH

OP_3

OP_SUB

OP_PICK

OP_IF

OP_DROP

p2tpkh()

OP_ELSE

OP_DROP

p2pkh(ClawBackPubKeyHash)

OP_ENDIF

但是有一個更簡單、更好的解決方案,將在為Group引入新交易版本的章節里討論到。

其他的可能性:固定P2SH

上文提到在P2SH腳本里執行數據的魔術可以清除,這麼做可以實現強大的腳本功能。為了實現這點,我們提議執行一個新的操作碼OP_EXEC,執行已壓入堆棧底部的數據。這樣可以解決p2sh問題,P2SH變成:

OP_DUP

OP_HASH160

scriptHash

OP_EQUAL

OP_EXEC

這將激活MAST(使用簽名由代碼代替的樹簽名計劃),這方面的內容不在本文的討論範圍內。

最終它將會啟用腳本模板,使數據和代碼都可以模板化。可以使用非常通用的模板。例如,讓我們再看看支持之前定義的允許「claw back」的模板:

OP_SWAP

OP_IF

p2tpkh()

OP_ELSE

OP_DROP

p2pkh(ClawBackPubKeyHash)

OP_ENDIF

審查時,模板參數是所有者的pubkeyhash。所有者用「ownerPubkey ownerSig 1」花費,「claw back」可以用「clawbackPubkey clawbackSig 0」花費。但是這個模板有個問題,每一個所有者都必須使用公鑰散列機制( public key hash mechanism)限制output。所有者的腳本「部分」被定義為「pay-to-template-public-key-hash」腳本。如果她想要使用多重簽名、HTLC或者一些新合約,怎麼辦?

我們可以使用OP_EXEC實現:

OP_SWAP

OP_IF

OP_EXEC

OP_ELSE

p2pkh(ClawBackPubKeyHash)

OP_ENDIF

現在模板參數是任意腳本。所有者用"ownerScript 1"花費,「claw back」用相同的「clawbackPubkey clawbackSig 0」花費。

沒有限制的OP_EXEC是很危險的。可能會創建消耗大量CPU時間的腳本,導致「拒絕服務攻擊」(OP_DUPOP_EXEC,甚至是 recursive trick)。不過我們已經用OP_CAT解決及其他操作碼,通過指定限制解決了類似的問題。我認為,即使是嚴格限制OP_EXEC可以被調用的次數(比如說4次——注意# 指令可以執行的最大次數和堆棧項目數量是有限的),比特幣腳本編寫者仍然將得到很大好處。

其他的可能性:P2CH

P2SH最初設計的一個目的是將自定義腳本從輸出腳本移出,移到花費者(spender)。畢竟,當你發送資金時,你應該不關心接收者接下來會如何花費它。p2tsh的方式則破壞了這個目的,因為這種方式又將腳本移回到了輸出腳本。我們可以增加這一功能,使用允許腳本在堆棧中執行兩次,和將p2tsh封裝進一個p2sh里,來實現這一功能。

但是這個規範使用group提出了一種新的交易版本和格式。在這種情況下,我們可以很好的實現設計——我們將腳本完全移出輸出,僅僅包含腳本模板和參數的哈希(詳見「交易格式」的章節)。這意味著只有1個地址類型——一個32byte的數字——所以從用戶角度來看,最終結果是一個更簡潔的系統,但包含了更強大的特性。

創建受限制Group

創建受限制的Group的第一步是把它定義成受限制的Group。每一筆交易都必須可以識別這樣的Group,而不需要追溯以前的交易。

我們之前定義了組識別符,並展示了如何用一個隨機數找出一個最後8bit可以選且可以作為標記位元組的Group。我們把標記bit 0定義為Encumbered Group標記。如果這是一個1,那麼必須執行下面的共識規則:

受限制Group共識規則

1.必須使用p2tsh outputs ( 新交易格式這條永遠為真)。

2.如果交易包含附帶RESCRIPT field set的group authority input ,則

返回真(不再執行受限規則)

3.對於每一個「真實的」(不是group authority)grouped input:

a. 驗證scriptTemplate的hash256是否匹配已花費UTXO相關的

scriptTemplate hash。這個相關scriptTemplate哈希值是包含

UTXO交易的第一個「真正」groupedinput的腳本模板哈希值。更多

細節請參見本文的交易格式部分。

注意,group 里的腳本模板並不一定都是相同的。發行方可以發起一筆鑄幣交易,模板A在某一個output里,模板B在另外一個output里,或者發行方可以分開發起鑄幣交易。這樣的話,如果代幣所有者可以用包含所需模板的UTXO混幣,那麼他就可以將其所有的代幣轉換成 encumbrance A或者B。這是可行的,因為encumbrance 實際上是發行方和代幣所有者之間的一個合約,發行方可以提供一份新的合約,但持幣者有權接受或者拒絕。

子group(Subgroup)

也許有望在一個Group里設置獨立的可互換壁壘(fungibility barrier)。我們常見的使用場景是同一類別里不可互換的單品。例如,某一場音樂會的門票,每張票必須指定某個具體的座位。儘管可以創建不同的Group表示每一個座位,但是subgroup可以更好的解決這個問題。

Subgroup具有group的所有屬性,但是它是通過32位元組group id和附加任意位元組形成的(最大是堆棧的上限520位元組)。具有subgroup capability set 的group authority可以創建新的subgroup。要創建一個sub-group GrpId.1,就要鑄一個代幣或者創建一個指定33位元組group id的group authority。

普通的subgroup前綴意義不大。換句話說,沒有 sub-sub-group。

交易格式

目前的交易格式對於非Group交易來說仍有效。但是,如果Group的交易使用一種新的交易格式,組識別符屬性可以從交易output里的腳本中分離出來。雖然犧牲掉了更多變化,但是代碼會更簡潔。我們在下面提出了一種Group交易必須使用的交易格式:

交易格式

Output格式或CTxOut2

注意,ouput里不允許有腳本。對於發送者來說,決定什麼spending encumbrances增加到subsequent花費是沒有意義的。有些情況下,發送者可能會需要一些限制,接受者可以發送兌換腳本和參數連同兌換腳本哈希值,供發送者驗證。因此,我們只需要模板化的比特現金pay-to-script-hash(P2SH)功能模型(一個贖回腳本模板和哈希值和參數)。

redeemScriptHash用於創建地址(例如今天,增加一個typebyte和checksum,通過bech32編碼),為了接受付款,用戶會互相發送地址。

Input格式或CTxIn2

沒有參數的scriptTemplate是一個正常的腳本。因此如果output沒有使用腳本模板,就使用空的「templateParams」和「scriptTemplate」里的正常兌換腳本。

要計算先前輸出中指定的「redeemScriptHash」,對連起來的templateParams和scriptTemplate進行hash256(兩次sha256)。

如果使用受限制的Group, scriptTemplate hash256必須與COutPoint里指定交易的第一個同組非許可權input里的scriptTemplate hash256相匹配。這個句子聽起來可能有點讓人困惑,初期腳本模板公式使用舊的交易格式,我們在每個output里納入scriptTemplate哈希值。但是,如上所述,這個公式有一個問題,發送者指那些只對未來花費感興趣的encumbrance。

scriptTemplate

新的交易格式可以解決這個問題,代價是一個很容易就能獲得scriptTemplate哈希值。但是,實現這項檢查最簡單的方法是,把這個哈希值放回全節點的UTXO集合里。每當創建UTXO時,節點通過驗證交易input知道scriptTemplateHash,因此,這個數據可以作為欄位添加到每個UTXO里。

另外一個選項是增加兩個欄位到output格式里:scriptTemplateHash 和parameterHash。但是,這個選擇的空間利用率不高,並且還會增加地址的長度。

注意,在新的交易版本里,執行templateParams 腳本的結果變成altstack。這是與我們最初的模板公式有點不同。在我們最初的模板公式里,我們展示了一個不合作用戶如何通過推出比預期更多的模板參數打敗一個寫得很爛的腳本。我們通過使用堆棧操作我們通過使用棧處理指令解決這個問題。但是,還有一個解決方案是,把templateParams放至altstack(執行這個模板時altstack是空的)。templateParams 腳本無法獲取花費腳本參數,因為這受限於堆棧壓入的數據。當模板腳本運行的時候,它可以輕易通過OP_FROMALTSTACK指令獲得模板參數。但是,通過把模板參數從花費參數里分離出來,模板作者的工作將變得容易很多。

基本操作

原子交換

我們可以構建一筆交易,將代幣轉給Alice的同時把BCH轉給Bob,這樣Alice就可以以一種無須信任、偽匿名和免審查的方式從Bob手中購買代幣。如果Alice想要購買1000個T,Bob和Alice必須通過一些可以找到彼此的機制進行溝通,並構建如下交易:

inputs

半交易

通信協議有可能會使用「半交易(half transaction)」。「半交易」是指一筆因input和output不相抵而無效的簽名交易。讓我們假設Bob想要以1BCH的價格出售10000個代幣T。他構造了下面這筆半交易,發起競拍:

接著Bob公開發布這筆交易——把十六進位轉儲的半交易發布到留言板上或是通過郵件發送出去等等。Alice看到Bob發布的信息,根據他的半交易構造如下完整交易:

這筆交易完成就可以發布到BCH網路上。

注意,Bob可以根據他構造的半交易選擇發起購買代幣或者出售代幣的「競拍」。

這個機制並不是用於取代交易所提供的服務,功能全面的交易所可以快速在鏈下發起和取消競拍,還有深度圖和諸如止損的功能,等等。但是這個機制的確具備有中心化服務所不具備的特性:交易是偽匿名的,無法停止,點對點,並且無需信任。大部分代幣交易可能都不會選擇這種方式交易,但是可以以這種方式交易能增強代幣持有者對流動性的信心——以「半交易」為基礎的代幣市場可以並且將會存活下來,無需許可,即使代幣沒有在交易所上線,或者被下架,也能存活。

與 OP_GROUP之間的關係

原OP_GROUP提案受到了若干批評,這項修改後的提案加入了針對這幾項批評的解決方案。這部分將探討這些批評及其解決方案。

更簡單的共識實現

原OP_GROUP提案里,鑄幣/銷毀的許可權由「私鑰持有者或者能夠滿足特定P2SH地址者」授予。採用這種方法的好處在於,概念簡單,鑄幣/銷毀的操作效率更高。但是,存在以下幾個缺點:1. 授權鑄幣/銷毀代幣時,共識代碼需要檢查之前腳本的內容,以確保這是P2SH或者P2PKH格式,並提取支配地址(controlling address)。腳本模板代碼要編入共識。2. 不能更改支配地址(密鑰輪換)。3. 不能證明代幣的供應量是有限的(註:修改後的OP_GROUP版本已經以一種類似於當前規範的方式解決了這個問題)。

通過分化許可權,發行方可以在證明自己已放棄鑄幣許可權的同時保留其他許可權。通過授權UTXO而不是私鑰,我們密鑰輪換,不需要檢查腳本的內容,提取共識代碼里的支配地址。而只需要做一個小小的檢查:mint authorityUTXO是否為擁有CTRL 和MINT bit set的Grouped input。由於大多數權威權力實際上涉及刪除約束,因此能力的實施是非常簡單的。例如,以下是除了鑄幣和銷毀幣功能例外的,強制實施代幣平衡的共識代碼。 在此代碼中,「bal」是通過迭代輸入和輸出以及代幣數量總和而形成的每組數據結構:

if ((bal.input > bal.output) && !hasCapability(bal.ctrlPerms,GroupControllerFlags::MELT))

{

return state.Invalid(false,REJECT_GROUP_IMBALANCE, "grp-invalid-melt", "Group input exceedsoutput, but no melt permission");

}

if ((bal.input

{

return state.Invalid(false,REJECT_GROUP_IMBALANCE, "grp-invalid-mint", "Group outputexceeds input, but no mint permission");

}

儘管共識簡化了,但是authority wallet implementation變得更複雜(權力更大),因為代幣發行方每次執行管理操作都要消耗authority UTXO,所以錢包必須創建新的authority UTXO。

合約Group

原OP_GROUP提案「只能發代幣」,不能創建智能合約。這些代幣的使用要由鏈下項目或合約(受信任的實體)管理,在違約的情況下代幣持有者只能採取法律行動。

分散式的、無需信任的合約應用(智能合約)使用編程語言定義代幣參與者(發行方、代幣持有者及其他持有者)之間達成的協議。比特幣的腳本語言不能實現這個功能,因為UTXO的發送者可以在每一筆交易里都指定一個新的output腳本。也就是說,持有者只要用不同的腳本給自己發送一筆交易就可以重新定義合約。

我們準備添加 contract encumbered group,以便未來在BCH上實現「智能合約」。現在因腳本無法訪問數據而嚴重受限。幾十年來人們都一直認為,數據和代碼是開發項目的基本因素,因此,要使用比特現金腳本,獲取額外數據是不可避免的。

外部數據可以由oracle簽名以及通過OP_DATASIGVERIFY提供。提供交易數據本身很高效,因為每個錢包都肯定保留全部的交易記錄用於驗證。交易數據實際上已經作為一個固定的OP_CHECKSIG input 提供給腳本,不過因為它沒有被壓入堆棧,並且已經進行哈希,所以通常是不可用的。

使用外部數據源的例子請參見本文Using Contract Encumbered Groups這一章的內容。為了避免出現先有雞還是先有蛋的問題,鑒於這些數據訪問指令,實現智能合約 contract encumbered group似乎是合理的。

Group應用

以下部分給出了一些Groups的用例示例。其實還有更多。但在閱讀以下章節之前,您可能需要閱讀附錄A,其中簡要介紹了示例中使用的BchScript語言。另外,如果您正在閱讀並問自己「這是否被我的金融監管機構認可?」,請閱讀附錄B:合法性說明。

證券

證券有兩種可能的實施方案。首先,證券經紀人持有實際證券的所有權,並在個人投資者交易的區塊鏈上放置一個承諾(代理)代幣。這與今天使用的系統非常類似(你實際上並不擁有Schwab,E-trade,Fidelity等代理商的「你的」股票,你擁有期票),並且因為證券代理商在法律上是所有者,它遵守證券法規。

在該實施例中,經紀人有效地將區塊鏈外包給每個人的股票投資組合(如今的內部分類賬)的維護,並且外包代表交易所的個人進行交易的需要。當個人想要從該分類帳和代幣中插入或提取值時(這與與代幣與代幣間或代幣與BCH間的交易非常不同),會完成KYC / AML。這種KYC / AML-at-the-border戰略是當前加密貨幣交換的工作方式。

第二種實施方案是,公司直接在區塊鏈上發布其自己的證券作為代幣。如果這些是註冊證券,則區塊鏈分類賬是公司的分類賬,並且證券的典型要求可以在法律管轄範圍內解決,如上文「合法性說明」部分所述。這將公司的股票分類賬,官方公告和投票流程放在公共區塊鏈上,這些區塊鏈強制執行某些限制和持有人/所有權,並允許公開驗證其餘部分。Group管理系統可以用來仔細控制新股票的發行,例如,在董事會成員或公司官員持有的非常安全的多地址中放置無限制的授權,並且只在額外股份獲得授權時發行一次性有限數量的授權。

債務證券(債券)可以在到期時使用半交易或通過直接服務進行兌換,該服務可以實現為網站和錢包,其相互作用以創建將代幣發送給公司的交易以及自動地向個人發送所需的BCH。

如果您需要出售證券的個人或機構的真實身份,可以索要他們的身份證明。如果向公司註冊時使用真實的身份證明才能合法轉讓,那麼當收到證券時,錢包可以自動將此信息直接發送給公司。公共區塊鏈不需要包含或強制執行此信息。

抵押貸款或貸款

無論是在個人還是在機構層面,Groups都能實現貸款的簡單標記化。在這兩種情況下,都會創建一個有限的供應Group來代表貸款。任何所需的額外區塊鏈信息(例如法律合同,擔保人,土地等)都放在Group創建事務中的OP_RETURN數據中。如果此貸款不可分割,則使用單個代幣創建Group,否則可能會創建許多代幣。然後,這些代幣可以通過半交易提供給BCH或其他代幣,並通過atomic transfer出售。抵押貸款可以通過在單筆交易中包含多個抵押貸款代幣來「捆綁」,或者機構可以將一組抵押貸款捆綁在一起並發行另一個代表它們的代幣。在第二種情況下,你信任該機構來管理捆綁,但如果捆綁包含鏈上抵押貸款,你可以驗證對這些抵押貸款的利息支付會導致隨後向捆綁代幣持有人支付正確的價值。與單一抵押貸款一樣,OP_RETURN中可以包含指定所涉及的確切抵押以及代幣持有人如何獲得付款的法律合同(或包括合同的哈希)。

如果你需要抵押貸款人或機構的身份信息,你要向他們詢問。而公鏈不需要包含或者執行該信息。

供應鏈

供應鏈查詢是指創建一個不可更改的商品生產記錄。它實際上是一個有向無環圖,因為input產品是通過人、工具和加工成附加產品的過程(這些附加品隨後又以類似的方式組合成產品)相結合。因為區塊鏈也是一個有向無環圖,UTXO組合形成新的UTXO,所以供應鏈在區塊鏈上建模很簡單。我們還缺失的一環是可互換壁壘,以便把產品區分開來。Group正好可以補上這缺失的一環。

讓我們模擬一下這樣的映射:

從原材料到成品的過程中需要使用到各種不同的「原料」:

1.製成最終產品所需的材料/產品

2.消耗掉的材料/產品

3.「催化」材料/產品、工具、人力

4.加工流程

5.測試

從第1、2、3步就可以看出,這是循環的——某一個流程里的output產品,也許是另一個流程里的input。

原材料和產品展示是通過建group來創建的。對於不可互換的產品例如鑽石,可以是一個單獨的代幣group(比如說,我們切割一個鑽石,就創建GroupD來追蹤它)。可互換的或者「大部分」可互換的(可互換但你需要追蹤個體)產品/材料可以每個類型用一個Group來建模,把一些代幣發送到一個UTXO用來代表一個實例。例如,Acme 挖出來的1克金彈頭可以是GroupG, 每次製造出一個彈頭,就往新的UTXO(1)發送1000個代幣,然後在OP_RETURN來填寫製造信息。為了標記化,我們用dotted convention來指代Group和initial UTXO instance,括弧里是數量(如果相關的話)。所以,這個金彈頭是G.1(1000)。為了補充完整這個例子,我們用M.1(10) 指代一個可以使用10次的模具,Rings公司的一個員工定義為E.1。當Rings公司購買這些原材料產品,代表這些原材料的代幣將會轉至購買者。

衍生的產品可以建模為交易。為了製造出500毫克的金戒指,我們構造一筆交易把G.1(1000)分成兩個G.1(500)output。接著,我們再創建一筆交易,把所有的input放到一起造成一枚特殊戒指:D、G.1(500)、M.1(1)、E.1並支付,把它們發送到R的地址R 。實際上打造一枚特殊戒指的成分由R可花費的UTXO表示。R實際上成了這枚戒指的識別符。

注意,如果黃金貶值或者重量少於500毫克,該公司可以用多出來的黃金製造出更多產品,因為公司將會用完G代幣。個別的黃金貶值需要黃金製造公司協助,將被盜黃金引入供應鏈。同樣的。公司不能引入不一致的鑽石到供應鏈上,因為該公司已經創建鑽石代幣,但是這會被注意到的,因為該公司沒有鑽石礦。戒指打得不好?模具只能用10次,有10個代幣可以保證Rings公司使用這個模具不超過10次,或者已經生產出來的戒指不會有模具代幣作為input。因為M.1與這枚鍛造得不好的戒指有關,我們可以把這個數據與其他鍛造得不好的數據相結合,從統計數據上看,這枚戒指質量不好是不是因為某個模具或是模具製造商造成。最後,僱員E.1被定義為生產者,所以人為失誤或者偷盜行為也可以追蹤到個人。

所以,在區塊鏈上,產品就是關聯到一個特定地址,理想狀態下包含一筆「初始」交易的完整UTXO集合。但是如果一個產品有成千上萬配件的產品,其本身也是另外一個產品的配件,這會變得很龐大複雜。為了解決這個問題,我們創建一個與這個中間產品相關的Group P。發行代幣P.1並將其發送到與其他所有配件相同的地址,最好是這個產品創始交易的一部分。當產品賣出,代幣P.1就會發送給購買者,而不是其所有配件部分的UTXO。這部分UTXO現在可以銷毀,以減少UTXO的消耗。這樣執行可以很高效,因為melt authority可以提供給這家公司,因為它與鑄幣許可權是獨立的。但是,因為鑽石一般被用來打造新的戒指,當戒指被拆解時,鑽石UTXO可以選擇不銷毀。

即使我們已經將大量成員打包進一個代幣P.1。全節點仍然可以完整的供應鏈。如果產品是通過一筆交易創建的,SPV客戶端可以請求查看P1代幣input交易和SPVproof迅速查看P.1的組成部分。如果產品是通過多筆交易產生,SPV錢包首先必須找到P.1代幣之前的地址,然後請求所有這筆地址相關的UTXO。這並不繁瑣;因為用備份種子恢復的時候需要恢復所有的交易記錄,所以這項功能在作為區塊瀏覽器和輕錢包的全節點中已經很常見了。

這個系統的第一步,創建原材料代幣,需要信任。我們要把現有這種材料的數據輸入區塊鏈,這也一直需要信任。但之後,這個系統就無需信任了。

票證

通票,即不需要指定座位的票,可以用代幣來表示,為該活動創建Group,一個代幣就是一張票。售票相當於一筆BCH原子交易,錢包可以用手機的NFC功能證明所有權,或者列印二維碼。

很多場館都不鼓勵轉售,而這可以通過encumbered group實現。但是可能會難以區分這是個人之間的換票,還是轉售。

指定座位的票可以通過subgroup編碼座位信息來實現。每個座位都是其自己的Group,因而是不可互換的。

總的來說,對於大型、不支持預售的活動來說,使用區塊存儲票據並不是最好的選擇,中心化的伺服器和手機APP支持BCH購票,不過執行的售票政策是與區塊鏈的理念是相反的。但是,基於區塊鏈的售票方式對於當地每年數百萬場的活動來說是一個簡單有效的方案。沒有預算或者制定售票方案的專業知識,這些票的功能:發行、銷售、預售、防偽,還有入場全部都可以通過一個手機錢包完成。

使用合約受限制的Group

比特幣的腳本語言嚴格限制對數據的訪問。輸出腳本只能在通過花費(簽名)腳本提供給它的數據上運行。但花費腳本的創建者會被激勵,提供任意滿足輸出腳本的數據(真或假)。

多年來,代碼和數據都被認為是程序的基本組成部分(https://en.wikipedia.org/wiki/Algorithms_%2B_Data_Structures_%3D_Programs) 。沒有數據,現在能用的腳本一隻手就能數得過來。

如果我們想要把比特幣腳本變成一個實用的合約語言,讓輸出腳本可以訪問更多的數據源是很有必要的。有些額外的數據源是可以以一種無須信任的方式提供的,例如關於交易本身的信息,或者以一種部分可信的方式提供,例如OP_DATASIGVERIFY操作碼的output, 該操作碼暫定於11月激活。

比特現金網路通過一次分叉就部署大量更改是不現實的,但是考慮到比特現金腳本語言將會繼續發展,部署一個像group這樣的功能是可以的。因此,在這部分內容里,我有時會使用當前不存在的數據源,以及使用尚不存在的操作碼opcode PUSH_TX_DATA來定義它們。執行這個操作碼可以訪問當前的交易數據,並將其壓入堆棧。

有期限的票證或優惠券

一個Group里的所有代幣都是同一優惠券的實例。10%折扣的優惠券是與20%的是不同的group。購買者發起支付的時候,代幣作為支付的一部分,用於激活優惠券。理想狀態下,用代幣構造交易,支付者可以先給商家提供tx, 這樣商家可以驗證優惠券是否正確。這個協議是對現有支付協議作出的一個很簡單的擴展,但這不在本文討論範圍內。

優惠券一旦過期就毫無價值。優惠券應該在過期時,「某人可以花掉」,以便清零。優惠券的發出者可以掃描他的Group,一旦發現過期的優惠券,便將其全部清除,可以讓所有者的錢包自己完成,或是讓礦工利用未填滿的區塊空間做這件事情。

def couponExpiryTemplate(userAddress)

{

OP_IF

p2pkh(userAddress)

OP_ELSE

couponExpiryTime

OP_CHECKLOCKTIMEVERIFY

OP_TRUE // Anyone can spend if coupon is expired

OP_ENDIF

}

注意,上述代碼只允許優惠券所有者使用p2pkh腳本轉賬。但是如果我們有OP_EXEC,我們可以移除這條要求,讓所有者提供任意腳本:

def couponExpiryTemplate(userScript)

{

OP_IF

userScript

OP_EXEC

OP_ELSE

couponExpiryTime

OP_CHECKLOCKTIMEVERIFY

OP_TRUE// Anyone can spend if coupon is expired

OP_ENDIF

}

備兌認購期權

備兌認購期權是一種以出售持有股票背書的期權。例如Alice一共有100股XYZ的股票,價格是10mBCH, 她覺得股票很穩定,於是把100股XYZ股票下個月到期的期權以15mBCH的價格出售。Bob認為XYZ的股票下個月會漲到30mBCH,於是他買入了Alice的call, 價格是每股1mBCH。如果Alice是正確的,Bob無法行權,Alice將保留100股XYZ股票和100mBCH。如果Bob是正確的,他行使權力購買Alice的股票,那麼Alice將獲得1500mBCH,Bob獲得100股XYZ股票,現價是每股30mBCH,並扣除1500mBCH。

基本的方法是,首先鎖定在腳本里鎖定代幣,只能在期貨到期,買方行權的時候可以花費。創建一下個group,代表這個期權。它可以正常轉賬,但是也可以結合鎖定期權的代幣和支付交易來執行。

我們先創建GroupT,發行代幣N。接著創建一個供應量有限的受限制Group,代表期權(OptT)。

接著,代幣(期權可以用於交易)被發送至一個holding腳本,這個腳本可以使當前所有者在期權到期前都不能動用代幣,但是允許執行Call。

def coveredCallLock(ownerAddress)

{

OP_IF // stop current owner from spending until releasedate

callExpiryTime

OP_CHECKLOCKTIMEVERIFY

p2pkh(ownerAddress)

OP_ELSE // allow spend ifexercised

PUSH_TX_DATA(quantity of OptT ininputs)

P_DUP // We』ll use the abovetwice.

PUSH_TX_DATA(quantity of T in inputs)

OP_EQUALVERIFY // don』t allow T to bespent unless an equal number of options exist

PUSH_TX_DATA(quantity of OptT melted)

OP_EQUAL // make sure all options areconsumed.

OP_ENDIF

}

接著,發行期權代幣N,並將它們發送至如下腳本。注意,在這個例子中,我使用的是更為普遍的userscriptOP_EXEC構想,接受者通過任意腳本都可以進行基本的轉賬。但是,如果不能使用OP_EXEC,該系統可能會限制轉賬,只能轉到某一類型的地址上(例如P2PKH)。如果是這種情況,在代碼里用「p2pkh(userPubKeyHash)」替換「userscript OP_EXEC」腳本有3字句,這三個字句由花費腳本通過把1s或者0s壓入堆棧的標準方法選出。第一個子句只允許代幣轉賬。第二個子句允許Bob行權,使用現在不存在的交易訪問操作碼,以確保交易包含支付給Alice的適當金額。第三個子句,Alice可以在到期的時候拿回期權。這個子句不需要很嚴格,因為基於當前的腳本,期權到期後Alice也可以將她的代幣T轉至新地址。

def coveredCallForToken(tokenHolderAddress,exercisePrice,

@userScript)

{

OF_IF

OP_IF // Option is transferred

@userScript

OP_EXEC

OP_ELSE // Bob exercises theoption

PUSH_TX_DATA(quantity of this output)

exercise price

OP_MUL // figure out the total exercisecost

PUSH_TX_DATA(quantity of BCH sent totokenHolderAddress)

OP_EQUALVERIFY // Make sure exercise price of BCHhas been sent to alice

@userScript // Make sure Bob (current owner) is theone exercising

OP_EXEC

OP_ENDIF

OP_ELSE // After some time, Alice can take theoption away

callExpiryTime

OP_CHECKLOCKTIMEVERIFY

p2pkh(tokenHolderAddress)

OP_ENDIF

這實現了一個在到期前任意時間執行的期權。應該明確的是,在運行子句里的OP_CHECKLOCKTIMEVERIFY限制可以防止期權在特定時間之前執行。這與逾期日相結合,期權需要在這段特定的時間內執行。例如,30天後,Bob有1天的時間行權。

通過花費期權Group的mint authority,Alice可以證明她不會發行超過當前covering代幣數量的期權,因為Group的鑄幣許可權已經不存在。Alice不能使用相同的covering代幣創建多個Group,因為期權Group識別符被編入coveredCallLock腳本。

這些腳本是為了說明一個概念,而不是明天就去部署。例如,它們的一個問題是,執行代碼需要期權input的數量完全與代幣input數量相匹配。但是,UTXO可能沒法實現。例如,只有1個代幣UTXO,代表100股,但是你只有50股的期權。鑒於這個問題是已知的,這是不可避免的;Alice創建了一定量的多個UTXO,Bob知道他必須購買多個UTXO。但是,要擴展腳本驗證適量的「更改」output是否存在於給定的PUSH_TX_DATA當中也不會太難,指令類似於之前已經使用過的那些。

預測市場(投注代幣化)

目前正在研究當中的OP_DATASIGVERIFY操作碼可以構建一個賭注,投注的結果取決於受信任的oracles所做的陳述。但是,投注是單個時間點可能事件的快照。它無法捕捉到對於不同結果可能性的觀點變化。預測市場允許人們購買和出售某個賭局結果的份額。不同結果的份額價格改變實際上反映的是對某一特定事件發生可能性的預測,這就是一個「預測市場」。

要創建一個預測市場,我們將採取以下步驟:首先,創建代表賭注結果份額的Group。接著,發送BCH到一個腳本里,如果相同數量的贏的份額被注入交易(這稱之為儲備資金BCH),這個腳本只能被花費。接著,如果結果是有利的,結果Group的mint token可以無限制轉賬,或是1:1兌換BCH儲備金。最終,放棄結果Group的鑄幣許可權,以證明將會有1:1的儲備金做擔保。

為了讓事情簡單化,我們將研究只有兩種結果A和B的投注。使用OP_DATASIGVERIFY不在本文的討論範圍之內,但是它所支持的功能子集可以用以下的宏表示:

makeBet(outcomePredicate, AWinsScript, BWinsScript, @data, @dataSignature)

MakeBet首先檢查oracle是否已經對所提供的數據進行適當的簽名。接著使用這個數據決定output A或者B。如果是A, 執行AWinsScript,如果是B,則執行BWinsScript。

我們將會創建2個代幣Group A和B,這代表這個預測市場可交易的份額。AWinsScript和BWinsScript代碼如下:

def WinsScript(tokGrp)

{

// You can』t spend this unlessyou are spending the same quantity of tokGrp (A or B)

PUSH_TX_DATA(quantity of BCHinputs)

PUSH_TX_DATA(quantity of tokGrpinputs)

OP_EQUALVERIFY // verify BCHinput quantity == tokGrp quantity

// Verify that the spender ismelting the tokGrp units not transferring them

PUSH_TX_DATA(quantity of tokGrpoutputs)

OP_0 OP_EQUAL

// Optionally, you could add aOP_CHECKLOCKTIMEVERIFY clause that spends the coins back to yourself aftergiving people sufficient time to redeem their A and B tokens. This would clean up after forgetful people, andgive you an exit without loss if for some reason the bet is undecidable or theoracle disappears.

}

BCH需要打包入一個「賭注」group,以區別於代幣轉賬時發送的BCH。

makeBet(predicate, WinsScript(A), WinsScript(B))

示例使用的是BchScript macro語言,這個語言可以用關鍵字「def」對子程序進行定義。當子程序隨後在代碼里相遇,它將由定義內容替代(類似於C』s #的定義)。注意,因為編譯程序只簡單使用macro replacement,參數可能是數據或代碼。這個語言還定義了一個特殊的語法,這是由於比特幣腳本執行的獨特方式:如果一個變數開始以@符號開頭,那麼它是由支出(簽名)腳本提供的一個預先存在於堆棧上的參數。這二者都有助於提高可讀性,

還要注意,我們確保這筆交易里的獎勵代幣已消耗(銷毀)。(Melt Authority input通常都可以用作為input)這保證代幣不會被多次兌現。

我們現在按照如下encumbrance腳本模板創建Group A 和B:

Def winsToken(grpId, @userScript)

{

OP_IF // case where the token is transferred

// New output script

@userScript

OP_EXEC

OP_ELSE // case where the bet isresolved, redeeming

// Make sure spender is claimingthe right number of 「Bet」 tokens

PUSH_TX_DATA(quantity of BCH inputs)

PUSH_TX_DATA(quantity of grpIdinputs)

OP_EQUALVERIFY

// make sure spender is meltinghis claims

PUSH_TX_DATA(quantity of outputgrpId)

OP_0

OP_EQUALVERIFY

// Enforce ownership of thisclaim

@userScript

OP_EXEC

OP_ENDIF

}

再次說明,如果用戶提供自己的BCHinput,那麼他可以成功兌現(OP_ELSE子句)。在這種情況下,這個腳本允許他「兌現」他已擁有的BCH,銷毀程序里的資金。但理性的用戶只會納入受限於「makeBet」腳本里的BCH output,因為持有他認領的代幣,他可以花費這筆output,從而獲取這筆BCH。

這個例子說明,在比特幣腳本和共識里增加基本操作——通過oracles、代幣(可互換性界限),以及讓腳本訪問數據——可以組合實現很複雜的操作。

附錄

附錄A:示例代碼說明

示例使用BchScript macro語言,子程序可以用關鍵字「def」定義。當子程序隨後在代碼里相遇的時候,它將由定義內容替代(類似於C』s #的定義)。注意,因為編譯程序只簡單使用macro replacement,參數可能是數據或代碼。這個語言還定義了一個特殊的語法,這是由於比特幣腳本執行的獨特方式:如果一個變數開始以@符號開頭,那麼它是由支出(簽名)腳本提供的一個預先存在於堆棧上的參數。這二者都有助於提高可讀性,並實現在編譯時從代碼中生成所有可能的spend腳本。例如,這個代碼定義普通的P2PKH腳本如下:

def p2pkh(pubkeyhash, @sig, @pubkey)

{

@sig

@pubkey

OP_DUP

OP_HASH160

pubkeyhash

OP_EQUALVERIFY

OP_CHECKSIG

}

一個標準的P2PKH output將會包含對這個宏的單獨調用:

p2pkh(bitcoincash:qpae0tg5k4mh5uhhcnwkx2rytj3800j8nunzm8rmed)

這是一個非常簡短的說明,但應該足以讀懂示例的偽代碼。

附錄B:合法性說明

當你讀到後面的Group使用場景時,你可能會想,「這不符合法律,所以我們不應該這麼做」。但是這個推理是有問題的。對於這個論斷最有力的證明是:這個世界有比特幣、比特現金、Airbnb、優步、Lyft、Kickstarter,以及很多成功的社會變革技術和企業,他們都處於法律的灰色地帶或完全被禁止(並且通常都會解禁)。讓我們共同探究裡面的原因,但要知道,我不是一名律師。

法律具有複雜性、矛盾性和地域性

人們,尤其是軟體開發者對於法律的認識都過於簡單粗暴。新興技術和新立法的實際情況要遠遠複雜得多。新興技術和新立法要複雜太多,要做出決定必須有真實的法庭審理案件作為參考,即要考慮雙方的意見,又要查詢是否有先例和考慮訴訟程序。

美國的一個經典案例是焚燒國旗案。該案件始末https://en.wikipedia.org/wiki/Texas_v._Johnson在最高法院作出最終判決之前,案情一直在反轉。隨後國會通過了1989年《國旗保護法》,但不久被取消。這還沒結束,國會隨後又多次試圖採取這項法案,但到現在都沒能成功。

焚燒國旗事件也展示了法律體系的另外一面。1989年《國旗保護法》生效沒多久,就有人在聯邦大樓面前蓄意破壞這項法律。儘管有很多先例和道德判斷供你預測你某種行為的後果,但遺憾的是,如果存在模稜兩可,要確定法律的有效性,以及是否適用於你身上的唯一方法就是行動,然後看看會發生什麼。這就是為什麼有人會在這項法律剛生效的時候焚燒國旗。結果是在美國訴艾奇曼一案中https://en.wikipedia.org/wiki/United_States_v._Eichman,再次取消該法。這暫時「解決」了一個國家的這一個問題,全球還有195個國家。

在美國,很多金融問題都是由州政府監管。這意味著,對於比特現金和代幣化的問題,僅在美國就有50個不同的司法轄區。

紐約的數字貨幣許可證(BitLicense )就是這種情況的一個好例子。確定BitLicense 合法性的唯一途徑就是挑戰它,Theo Chino就是這麼乾的(https://cryptoinsider.com/content/ny-oct-10-court-challenge-may-worldwide-bitcoin-implications/index.html)。

Creative Legal Interpretation Can Make It Possible

非常成功並且具有社會價值的初創企業例如優步、Lyft、Kickstarter 和Indegogo都是遊走在法律的灰色地帶。以前使用Lyft叫車是免費的,乘客可以選擇性捐款。因此,這不是合法的計程車(交通運輸)服務。但是如果你不「捐贈」,就別指望還會有Lyft司機願意載你。

在眾籌方面,SEC制定了一條法規將最高100萬美元的捐款合法化(https://www.sec.gov/news/pressrelease/2015-249.html),但這樣的限制立刻被無視((https://www.kickstarter.com/projects/poots/kingdom-death-monster-15/description)。然而,這說明了法律另外一個很重要的現實點:作出判決或是改變需要非常充分的理由(例如$$$)。監管一切可能會發生的事情,將會耗掉有關部門太多時間,但是如果事情已經發生,想像後果要容易得多。

搬到加密貨幣上來,很多ICO謹慎發行代幣,以避開豪威測試和證券法。(https://consumer.findlaw.com/securities-law/what-is-the-howey-test.html)避開豪威測試一個常見的方法是避開第三點。「普通企業」指的是你的公司。但是如果代幣被用於一個開源且無需許可的網路(這個網路剛好目前由你的公司維護)和兩個團體之間的中介服務(你的公司剛好是最大的服務供應商),那麼從法律上來說,購買該代幣有可能不是對某個公司進行投資。

讓我們發散思維,看一下註冊證券。註冊證券要求公司在賬簿中記錄證券持有人的信息,以便派發股息、記錄選票和交流。要轉讓股份,持股人有義務告知公司(否則這是不合法的)。從表面面來看,只使用區塊鏈代幣,公司是不可能做到這點的,因為代幣可以點對點轉移。我們需要額外增加一個步驟,把轉移信息發送給公司。

但是,區塊鏈的交易記錄可以作為發給公司的通知?實際上,區塊鏈是否可以作為公司的賬本?你可以用BCH向持有代幣的相同output腳本(或地址)支付股息。你可以同樣通過構建交易在OP_RETURN欄位附上文件(或鏈接)與持有人溝通。你可以讓持有人用代幣output地址對應的私鑰對聲明進行簽名,以此進行投票。與傳統的方式相比,這些技術里每一項都有優勢,其中包括「三式記賬法」、可證實的溝通、可證實的股息支付,以及可證實的投票。

技術不會執行法律

汽車會拒絕超速嗎?他們應該執行公路法嗎?如果有高速路規定最低行駛速度,那自動駕駛如何處理那些低於下限速度的汽車呢?顯然這個問題很愚蠢,但法律如何加強對新技術(自動駕駛)的執法,但對其他(非新技術)的執法呢?誰來決定執法?

我們根本不能預先確定一些普通概念,例如「鏈上證券」的各種具體表現形式在全球數百個司法管轄區都是非法的。作為工程師,我們必須用技術創造出我們想要生活的世界,並相信法律會被明確或修訂,但在該技術受到監管的管轄區,最終依賴於個人的知情選擇。

附錄C:OP_RETURN里的Group信息

OP_RETURN output的內容如下:

` `

有可能會有空白的欄位,例如:

欄位定義:根據這裡提供指導,在OP_RETURN里定義這類數據的一個4位元組數字。

: 代幣簡稱,顯示在貨幣數量附近。最大8個字元。

: 代幣全稱

: 這個欄位支持http和https協議,請參考以下代幣說明文檔里的內容"application/json" type document in [I-JSON format]

(https://tools.ietf.org/html/rfc7493)

: 對代幣說明文檔里的字典做兩次SHA256。這個哈希值提交至文檔內容並證明它沒有被修改過。

代幣說明文檔

代幣說明文檔是一個使用I-JSON格式的「application/json」類型的文檔(https://tools.ietf.org/html/rfc7493)至少包含以下欄位。如有需要,作者可以納入其他欄位。

**signature**: 這個簽名欄位包含使用所有需要花費第一個group authority的簽名的前一個字典的簽名。驗證者必須檢查這個文件的確切位元組數,保證行距沒有變。簽名演算法與在Satoshi客戶端的signmessage RPC函數里使用的相同。以下信息僅供參考,不具有權威性:

*通過使用Bitcoin Signed Message:
字元串的double SHA-256計算信息哈希值+信息*創建一個緻密的ECDSA簽名*使用base 64編碼將下面的字符集轉換成文本:

"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

錢包和用戶使用這個簽名表明代幣的創建者正在確認這個json文檔里的信息。這個簽名也證明這個文檔和參考URL與這個Group是相關的。通過host他的文件,域名所有者與代幣關聯。這就是為什麼域名是XYZ.com的XYZ公司發行的代幣與假冒的XYZ代幣不同。

建議代幣發行方為統一資源識別符使用https協議,這樣就無法發動中間人攻擊,使其看起來像是你的域名正在host一份代幣描述文檔。

**ticker**: 代幣簡稱。最大8個字元。

**name**: 代幣全稱

**summary**: 段落描述

**description**: 完整描述

**legal**: 代幣用戶和代幣發行者之間完整的合法合約,如果有的話。

**creator**: 代幣創建者

**contact**: 任選的創建者聯繫信息,例如:

定義的方法是: "address", "email", "phone","twitter.com", "facebook.com"

作者可能會添加自己的方法。如果這是一個支持web的服務,請使用域名來標識該方法。如果這是一個URL協議,則使用包含以冒號結束的協議名稱(e.g. "http:": "//www.mywebsite.com/contactform")

作者可能會添加這個字典這個文件里沒有定義的欄位。

不合法的代號名稱

因為OP_RETURN沒有達成共識,代幣發行方可以任意命名。但是,為了避免用戶混淆,錢包可能會限制用戶使用與現有貨幣或證券有密切關聯的名字。因為這些名字可能會經常換,所以更好的方案是以協商一致的方式命名。錢包作者可以保存一張預留的名單,並定期更新該名單的副本。

錢包的作者可能會考慮要求在顯示代幣簡稱之前進行人工審批。例如,收到一個新型的代幣,錢包可以問: 「Display issued by as?」

但如果代幣聲稱要使用下面的代碼(不區分大小寫),我們強烈建議錢包拒絕顯示這些代碼,而是使用hex里組識別符的前幾個位元組:

BCH, mBCH, uBCH, cash

如果一個代幣表示要使用下面的代碼(不區分大小寫),我們將以錢包拒絕顯示該代碼(使用hex里組識別符的前幾個位元組),除非用戶明確指定:

Any ISO4217 currency code,

any NYSE ticker,

any NASDAQ ticker,

any symbol from your locale"s national securitiesexchange,

other popular crypto-currencies.

如果第三方公司或個人正在創建一個代表證券的代幣,他們的代碼應該反映出,這個代幣是「具有代表性的」。例如,如果公司ABC代表股東持有證券XYZ,代幣可以命名為ABC.XYZ。

在比特現金的區塊鏈上發行真正的貨幣和證券是有可能的。我們保留國家和國際知名的股票代碼,以備將來使用,但目前用戶可以忽略這點,因為錢包實現很有可能會落後於最早的一些部署。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 閃電HSL 的精彩文章:

比特幣和以太坊的記賬方式——UTXO和賬戶餘額

TAG:閃電HSL |