當(dāng)前位置:首頁(yè) > 物聯(lián)網(wǎng) > 區(qū)塊鏈
[導(dǎo)讀] 前段時(shí)間,Gavin Wood要求我研究基于Substrate實(shí)施UTXO鏈的可能性,Substrate是目前最有前景的區(qū)塊鏈技術(shù)底層架構(gòu),而且目前Polkadot是基于substrate進(jìn)行開(kāi)

前段時(shí)間,Gavin Wood要求我研究基于Substrate實(shí)施UTXO鏈的可能性,Substrate是目前最有前景的區(qū)塊鏈技術(shù)底層架構(gòu),而且目前Polkadot是基于substrate進(jìn)行開(kāi)發(fā)的。

我們想知道Substrate的靈活性,而UTXO鏈似乎是進(jìn)行測(cè)試的一個(gè)不錯(cuò)的選擇,因?yàn)樗c我們過(guò)去在實(shí)施Substrate時(shí)所考慮的完全不同。如果可行,則表明Substrate確實(shí)非常靈活且通用。我們可以更有信心,把Substrate應(yīng)該到不同領(lǐng)域的區(qū)塊鏈項(xiàng)目中。

與以太坊類似,Substrate保留一定數(shù)量的可用資金。從某種意義上講,它類似于普通的銀行系統(tǒng),其中帳戶余額用數(shù)字表示,并存儲(chǔ)數(shù)據(jù)庫(kù)計(jì)算機(jī)內(nèi)存中的某個(gè)位置。

從歷史上看,第一個(gè)成功的加密貨幣是比特幣,它使用完全不同的方法。在比特幣中,本身沒(méi)有賬戶,余額也不是作為一個(gè)數(shù)字存儲(chǔ)的。取而代之的是,可用資金是根據(jù)一組所謂的未用交易輸出來(lái)定義的,簡(jiǎn)稱為UTXO,這是一個(gè)非常簡(jiǎn)單的主意。

簡(jiǎn)而言之是UTXO

簡(jiǎn)而言之,UTXO非常類似于現(xiàn)金,或者更確切地說(shuō),是旅行支票。

當(dāng)你用現(xiàn)金支付某人時(shí),你通常會(huì)想到要支付的總價(jià)值,但是你用一組獨(dú)特的、不可分割的單位(代幣或鈔票)來(lái)表示這個(gè)價(jià)值。例如如果Alice希望付給Bob$250美元,她可以給Bob2張價(jià)值$100美元的鈔票和1張價(jià)值50美元的鈔票,或五張面值$50的鈔票,或總計(jì)為所需值的任何其他組合。

每一張鈔票都是獨(dú)一無(wú)二的。盡管有數(shù)百萬(wàn)張鈔票具有相同的價(jià)值,但是每張鈔票在物理上都是唯一的,并在其表面印有序列號(hào)。通常情況下,我們不太注意它,只是在支付東西的時(shí)候,把兩張100美元的鈔票視為相等,但這個(gè)數(shù)字對(duì)于銀行控制資金流動(dòng)和真?zhèn)螜z查是必不可少的。

因此每張鈔票代表著具有預(yù)定和固定價(jià)值的獨(dú)特且不可分割的資產(chǎn),這些資產(chǎn)只能整體使用,即您不能將100美元的鈔票撕成兩張50美元的鈔票。當(dāng)然你可以要求某人找零,將價(jià)值分成較小的單位,但是您仍然需要花100美元的原始鈔票。同樣,購(gòu)買咖啡時(shí),您會(huì)花掉10美元的鈔票,作為回報(bào),您會(huì)得到咖啡和一些零錢。

UTXO的工作方式與此類似。要使用比特幣付款,您的錢包中應(yīng)該已經(jīng)有一些未使用的資產(chǎn)。與法定貨幣一樣,您可以結(jié)合使用多個(gè)UTXO以獲得更大的價(jià)值。

與現(xiàn)金不同,每個(gè)UTXO都有自己的所有者。從這個(gè)意義上說(shuō),它類似于旅行支票,因?yàn)橹挥兄彼腥瞬趴梢允褂盟_@是通過(guò)所有者簽名增加單位來(lái)完成的。不同之處在于,旅行支票由所有者的手簽名,而UTXO使用非對(duì)稱加密,并且包含收件人而非發(fā)件人的公鑰。而是鈔票由政府印刷,UTXO由發(fā)起人創(chuàng)建。

目標(biāo)

在我們的研究中,我們將嘗試建立一個(gè)區(qū)塊鏈模型,使用與比特幣相同的原理將資金從一個(gè)所有者轉(zhuǎn)移到另一個(gè)所有者。

當(dāng)閱讀文章時(shí),請(qǐng)記住我們的主要目標(biāo)是評(píng)估Substrate的靈活性,而不是比特幣移植時(shí)使用端口的詳細(xì)解釋。在某些情況下,其實(shí)現(xiàn)幾乎與Parity比特幣的實(shí)現(xiàn)相同,而在其他情況下則不是。例如當(dāng)前的實(shí)現(xiàn)不支持挖掘和coinbase事務(wù);它只是重新分配在genesis塊中初始化的“預(yù)先定義”UTXO集的值。

另外,請(qǐng)注意,所提供的實(shí)現(xiàn)還不能完全投入生產(chǎn)。它尚未經(jīng)過(guò)正式驗(yàn)證,并且可能存在一些安全性或穩(wěn)定性問(wèn)題,因此,我不建議您在沒(méi)有適當(dāng)研究的情況下,將其用于任何關(guān)鍵基礎(chǔ)架構(gòu)。但是如果有人將這個(gè)原型制作成可行的解決方案,我會(huì)非常高興。

話雖如此,讓我們繼續(xù)進(jìn)行代碼。

首先讓我們談?wù)凷ubstrate如何允許您對(duì)其進(jìn)行自定義。作為應(yīng)用程序員,您應(yīng)該提供一個(gè)runtime的運(yùn)行邏輯,這些邏輯告訴Substrate如何處理鏈以及應(yīng)采用的業(yè)務(wù)邏輯。所有這些都圍繞著狀態(tài)轉(zhuǎn)換函數(shù)(簡(jiǎn)稱STF)的概念。但現(xiàn)在我們只需說(shuō),每個(gè)區(qū)塊鏈都可以表示為一個(gè)函數(shù),接受當(dāng)前狀態(tài)和一個(gè)掛起的事務(wù),然后生成另一個(gè)狀態(tài),反映在應(yīng)用事務(wù)后所做的更改。

假設(shè)Alice和Bob都有10個(gè)代幣,然后Alice向Bob發(fā)送了5個(gè)代幣。應(yīng)用此交易后,我們預(yù)計(jì)Alice現(xiàn)在將有5個(gè)代幣,而B(niǎo)ob將有15個(gè)代幣。如果Bob隨后嘗試向Claire支付20個(gè)代幣,則該交易必須視為無(wú)效,因?yàn)楦鶕?jù)最新的鏈條狀態(tài),Bob只有15個(gè)代幣。

這正是runTIme的意圖-它定義了所有實(shí)體及其關(guān)系,驗(yàn)證了傳入的事務(wù)并相應(yīng)地更改了狀態(tài)。

讓我們從指定將用于定義UTXO鏈的業(yè)務(wù)邏輯的數(shù)據(jù)類型開(kāi)始。首先是TransacTIon 類型。它表示要調(diào)度的單個(gè)UTXO事務(wù):

/// Single transacTIon to be dispatched

#[cfg_attr(feature = “std”, derive(Serialize, Deserialize, Debug))]

#[derive(ParTIalEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash)]

pub struct Transaction {

/// UTXOs to be used as inputs for current transaction

pub inputs: Vec《TransactionInput》,

/// UTXOs to be created as a result of current transaction dispatch

pub outputs: Vec《TransactionOutput》,

}

這里沒(méi)有什么特別的,只是一個(gè)簡(jiǎn)單的定義,即Transaction只是一堆輸入和輸出。如果您好奇,可以將其與Parity Bitcoin的版本進(jìn)行比較,以了解相似之處。上面所有#[。..]怪異都稱為屬性,它告訴Rust編譯器為我們實(shí)現(xiàn)各種操作,例如比較運(yùn)算符,哈希函數(shù)和序列化例程。您現(xiàn)在可以放心地忽略它們。

我留下了所有注釋和屬性,以表明即使將它們包括在內(nèi),代碼仍會(huì)保持緊湊。我認(rèn)為,即使與在成千上萬(wàn)行中做“同一件事”的Parity Bitcoin相比,這也是Substrate的可觀成就。就像在用JavaScript為網(wǎng)絡(luò)編寫代碼時(shí)一樣,您并沒(méi)有考慮過(guò)瀏覽器引擎或任何底層操作系統(tǒng)(包括操作系統(tǒng))的復(fù)雜性。相反,您只是以高級(jí)形式制定業(yè)務(wù)邏輯,然后讓系統(tǒng)完成其余工作。

好的,但是TransactionInput呢?

/// Single transaction input that refers to one UTXO

#[cfg_attr(feature = “std”, derive(Serialize, Deserialize, Debug))]

#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash)]

pub struct TransactionInput {

/// Reference to an UTXO to be spent

pub parent_output: H256,

/// Proof that transaction owner is authorized to spend referred UTXO

pub signature: Signature,

}

TransactionInput匯總花費(fèi)一個(gè)UTXO所需的所有數(shù)據(jù)。首先我們需要一種方法來(lái)引用一些現(xiàn)有的UTXO。最簡(jiǎn)單的方法是使用其哈希作為標(biāo)識(shí)符。這是分布式系統(tǒng)世界中的一種普遍做法,并且只要哈希沖突的可能性可以忽略不計(jì),它就可以很好地工作。為此我們使用256位Blake2。parent_output字段包含此類哈希。

如前所述,要使用UTXO,所有者必須使用與存儲(chǔ)在該特定UTXO中的公鑰匹配的秘密密鑰對(duì)其進(jìn)行簽名。只要知道密鑰的唯一人是所有者,這就是安全的。這種證明存儲(chǔ)在簽名字段中。

我們的實(shí)現(xiàn)與比特幣之間的區(qū)別在于,我們直接通過(guò)其哈希值引用parent_output,而比特幣則使用產(chǎn)生了UTXO的交易的哈希值以及一個(gè)索引來(lái)從交易輸出列表中選擇特定條目。原因是比特幣是根據(jù)交易和區(qū)塊定義的,而我們是根據(jù)業(yè)務(wù)邏輯和狀態(tài)轉(zhuǎn)換來(lái)定義的。在我們的例子中,Substrate事務(wù)只是輔助實(shí)體,它們促進(jìn)了流程,并且大部分都超出了業(yè)務(wù)邏輯的范圍。稍后再談。

接下來(lái)是定義UTXO的TransactionOutput結(jié)構(gòu):

/// Single transaction output to create upon transaction dispatch

#[cfg_attr(feature = “std”, derive(Serialize, Deserialize, Debug))]

#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Hash)]

pub struct TransactionOutput {

/// Value associated with this output

pub value: Value,

/// Public key associated with this output. In order to spend this output

/// owner must provide a proof by hashing whole `TransactionOutput` and

/// signing it with a corresponding private key.

pub pubkey: H256,

/// Unique (potentially random) value used to distinguish this

/// particular output from others addressed to the same public

/// key with the same value. Prevents potential replay attacks.

pub salt: u32,

}

value和pubkey字段的用途應(yīng)該已經(jīng)清楚。唯一值得解釋的是salt。此字段提供了額外的熵,以使每個(gè)UTXO及其哈希真正唯一。想象一下這樣的情況,我們有一個(gè)機(jī)器人每天向同一個(gè)收件人發(fā)送10個(gè)代幣。為了簡(jiǎn)單起見(jiàn),它可以使用相同的目的地地址,即接收者的公鑰。因?yàn)関alue和pubkey字段都包含相同的數(shù)據(jù),所以bot創(chuàng)建的所有UTXO看起來(lái)都完全相同,因此具有相同的散列。

沒(méi)有salt,攻擊者將能夠記住所有者所用的第一個(gè)UTXO的簽名,然后在所有者甚至沒(méi)有注意到之前就花費(fèi)所有后續(xù)的UTXO來(lái)竊取金錢,這稱為重放攻擊。同樣還有另一種在源代碼中尚未解決的重放攻擊的可能性。

請(qǐng)注意,由于比特幣實(shí)現(xiàn)依賴于交易哈希來(lái)精確定位UTXO,因此它不會(huì)遭受此問(wèn)題的困擾,因此不需要salt。然而,這并不意味著比特幣不可能進(jìn)行重放攻擊。這就是為什么為每一筆交易生成一個(gè)新的比特幣地址是至關(guān)重要的。

狀態(tài)

到目前為止,我們已經(jīng)定義了表示內(nèi)存中單個(gè)事務(wù)所需的所有數(shù)據(jù)結(jié)構(gòu)。但是我們還需要告訴Substrate通過(guò)在一段時(shí)間內(nèi)保留此信息,在狀態(tài)數(shù)據(jù)庫(kù)中存儲(chǔ)什么以支持鏈的業(yè)務(wù)邏輯。

這是通過(guò)使用decl_storage定義模塊存儲(chǔ)來(lái)完成的!marco:

decl_storage! {

trait Store for Module《T: Trait》 as Utxo {

/// All valid unspent transaction outputs are stored in this map.

/// Initial set of UTXO is populated from the list stored in genesis.

UnspentOutputs build(|config: &GenesisConfig《T》| {

config.initial_utxo

.iter()

.cloned()

.map(|u| (BlakeTwo256::hash_of(&u), u))

.collect::《Vec《_》》()

}): map H256 =》 Option《TransactionOutput》;

/// Total leftover value to be redistributed among authorities.

/// It is accumulated during block execution and then drained

/// on block finalization.

LeftoverTotal: Value;

/// Outputs that are locked

LockedOutputs: map H256 =》 Option《LockStatus《T》》;

}

add_extra_genesis {

config(initial_utxo): Vec《TransactionOutput》;

}

}

上面的代碼實(shí)際上它僅定義了三件事:未使用的輸出列表,當(dāng)前剩余值量以及已定且除非解鎖就無(wú)法使用的輸出列表。除此之外,它還定義了在引導(dǎo)過(guò)程中如何使用一組初始的UTXO填充鏈。

需要要注意的是,狀態(tài)存儲(chǔ)與區(qū)塊存儲(chǔ)有很大不同。

區(qū)塊存儲(chǔ)是每個(gè)區(qū)塊鏈節(jié)點(diǎn)的重要組成部分,用于存儲(chǔ)該鏈中的區(qū)塊。如今只有專用的存檔節(jié)點(diǎn)將整個(gè)鏈存儲(chǔ)在本地,而普通節(jié)點(diǎn)僅管理最近區(qū)塊的臨時(shí)子集。

另一方面,狀態(tài)存儲(chǔ)與業(yè)務(wù)邏輯有關(guān)。它包含反映業(yè)務(wù)實(shí)體及其關(guān)系的當(dāng)前狀態(tài)所需的所有數(shù)據(jù)。為了驗(yàn)證傳入交易,您唯一需要知道的是所有受影響方的狀態(tài)及其資金額。這就是為什么即使是輕度客戶也能夠驗(yàn)證交易的原因。

設(shè)計(jì)邏輯

當(dāng)我們說(shuō)Alice從Bob那里得到一些資金時(shí),我們的意思是根據(jù)規(guī)則,Bob用來(lái)支付Alice的一組UTXO必須標(biāo)記為已用(以防止Bob以后重復(fù)使用)。然后Bob為Alice創(chuàng)建的一組新UTXO現(xiàn)在必須被記住是有效的,這樣Alice就可以在之后使用它們了。

這些規(guī)則是業(yè)務(wù)邏輯的本質(zhì),在驗(yàn)證和調(diào)度傳入事務(wù)時(shí)需要考慮這些規(guī)則。

讓我們看一下整個(gè)UTXO模塊的入口點(diǎn):

decl_module! {

pub struct Module《T: Trait》 for enum Call where origin: T::Origin {

/// Dispatch a single transaction and update UTXO set accordingly

pub fn execute(origin, transaction: Transaction) -》 Result {

ensure_inherent(origin)?;

let leftover = match Self::check_transaction(&transaction)? {

CheckInfo::MissingInputs(_) =》 return Err(“all parent outputs must exist and be unspent”),

CheckInfo::Totals { input, output } =》 input - output

};

Self::update_storage(&transaction, leftover)?;

Self::deposit_event(Event::TransactionExecuted(transaction));

Ok(())

}

/// Handler called by the system on block finalization

fn on_finalise() {

let authorities: Vec《_》 = Consensus::authorities().iter().map(|&a| a.into()).collect();

Self::spend_leftover(&authorities);

}

}

}

我們定義了兩個(gè)函數(shù):execute和on_finalize

execute函數(shù)是整個(gè)UTXO邏輯的關(guān)鍵。它接受單個(gè)事務(wù),對(duì)其進(jìn)行檢查,如果有效,則通過(guò)更新存儲(chǔ)應(yīng)用該事務(wù)。最后它存儲(chǔ)一個(gè)事件,表示一個(gè)事務(wù)剛剛被處理。

當(dāng)剛剛形成一個(gè)充滿交易的單個(gè)塊時(shí),將調(diào)用on_finalize事件處理程序。通過(guò)觸發(fā)該事件處理程序,Substrate允許運(yùn)行時(shí)根據(jù)需要采取一些措施。我們使用此處理程序從參與創(chuàng)建此塊的驗(yàn)證程序之間的所有事務(wù)中重新分配合并的剩余價(jià)值,作為對(duì)其工作的獎(jiǎng)勵(lì)。

交易檢查

為了驗(yàn)證傳入事務(wù),我們需要確保以下內(nèi)容:

1. 輸入和輸出不為空。

2. 所有輸入與現(xiàn)有的、未使用的和未鎖定的輸出匹配。

3. 每個(gè)輸入只使用一次。

4. 每個(gè)輸出只定義一次,并且有一個(gè)非零值。

5. 總產(chǎn)值不得超過(guò)總產(chǎn)值。

6. 新的輸出不能與現(xiàn)有的沖突。

7. 輸入和輸出值之和不能溢出。

8. 提供的簽名有效。

違反任何一項(xiàng)檢查都可能導(dǎo)致連鎖安全性問(wèn)題,因此正確實(shí)施它們至關(guān)重要。幸運(yùn)的是,邏輯非常簡(jiǎn)單明了:

pub fn check_transaction(transaction: &Transaction) -》 CheckResult《‘_》 {

ensure?。?!transaction.inputs.is_empty(), “no inputs”);

ensure!(!transaction.outputs.is_empty(), “no outputs”);

{

// Collecting inputs into a set where every element is unique.

// If two equal elements are inserted, only one will remain.

let input_set: BTreeMap《_, ()》 = transaction

.inputs

.iter()

.map(|input| (input, ()))

.collect();

// Ensuring that the size of original collection and the set are equal.

// If they are not, then due to pigeonhole principle, some entries must

// have been maliciously mentioned several times.

ensure?。?/p>

input_set.len() == transaction.inputs.len(),

“each input must be used only once”

);

}

{

let output_set: BTreeMap《_, ()》 = transaction

.outputs

.iter()

.map(|output| (output, ()))

.collect();

ensure!(

output_set.len() == transaction.outputs.len(),

“each output must be defined only once”

);

}

let mut total_input: Value = 0;

let mut missing_utxo = Vec::new();

for input in transaction.inputs.iter() {

// Fetch UTXO from the storage

if let Some(output) = 《UnspentOutputs《T》》::get(&input.parent_output) {

ensure?。?!《LockedOutputs《T》》::exists(&input.parent_output), “utxo is locked”);

// Check that we’re authorized to spend this UTXO

ensure?。?/p>

ed25519_verify(

input.signature.as_fixed_bytes(),

input.parent_output.as_fixed_bytes(),

&output.pubkey

),

“signature must be valid”

);

// Add the value to the input total

total_input = total_input.checked_add(output.value).ok_or(“input value overflow”)?;

} else {

missing_utxo.push(&input.parent_output);

}

}

let mut total_output: Value = 0;

for output in transaction.outputs.iter() {

ensure!(output.value != 0, “output value must be nonzero”);

let hash = BlakeTwo256::hash_of(output);

ensure?。?!《UnspentOutputs《T》》::exists(hash), “output already exists”);

total_output = total_output.checked_add(output.value).ok_or(“output value overflow”)?;

}

if missing_utxo.is_empty() {

ensure?。╰otal_input 》= total_output, “output value must not exceed input value”);

Ok(CheckInfo::Totals { input: total_input, output: total_output })

} else {

Ok(CheckInfo::MissingInputs(missing_utxo))

}

}

您可能注意到,除了事務(wù)檢查之外,此函數(shù)還收集一些信息。讓我們看看它的定義:

/// Result of transaction verification

pub type CheckResult《‘a(chǎn)》 = rstd::result::Result《CheckInfo《’a》, &‘static str》;

/// Information collected during transaction verification

pub enum CheckInfo《’a》 {

/// Combined value of all inputs and outputs

Totals { input: Value, output: Value },

/// Some referred UTXOs were missing

MissingInputs(Vec《&‘a(chǎn) H256》),

}

/// Representation of UTXO value

pub type Value = u128;

稍后將顯示,我們使用總的 inputs和outputs來(lái)計(jì)算交易的優(yōu)先級(jí),并將剩余價(jià)值的一部分作為塊式獎(jiǎng)勵(lì)在驗(yàn)證者之間重新分配。

但是如果交易未通過(guò)驗(yàn)證,談?wù)撨@些價(jià)值絕對(duì)沒(méi)有任何意義。否則攻擊者將能夠通過(guò)淹沒(méi)交易池并阻止正常交易被派發(fā),從而故意制作具有最高優(yōu)先級(jí)的交易并對(duì)鏈進(jìn)行DoS。或者,它可能會(huì)“憑空產(chǎn)生”大量剩余價(jià)值以利用獎(jiǎng)勵(lì)系統(tǒng)。

通過(guò)將數(shù)據(jù)組織為Rust枚舉,可以防止意外誤用,因?yàn)橹挥性诮灰子行r(shí)值才可用。反之亦然,只有在發(fā)現(xiàn)事務(wù)引用狀態(tài)數(shù)據(jù)庫(kù)中不存在的某個(gè)UTXO時(shí),才可以使用缺少輸入的列表。這樣一來(lái),就不會(huì)濫用API,這有利于提高可讀性和鏈安全性。

狀態(tài)更新

如果交易經(jīng)過(guò)驗(yàn)證并證明是正確的,那么我們要做的就是更改鏈狀態(tài)以反映該交易所做的更改:

/// Update storage to reflect changes made by transaction

fn update_storage(transaction: &Transaction, leftover: Value) -》 Result {

// Calculate new leftover total

let new_total = 《LeftoverTotal《T》》::get()

.checked_add(leftover)

.ok_or(“l(fā)eftover overflow”)?;

// Storing updated leftover value

《LeftoverTotal《T》》::put(new_total);

// Remove all used UTXO since they are now spent

for input in &transaction.inputs {

《UnspentOutputs《T》》::remove(input.parent_output);

}

// Add new UTXO to be used by future transactions

for output in &transaction.outputs {

let hash = BlakeTwo256::hash_of(output);

《UnspentOutputs《T》》::insert(hash, output);

}

Ok(())

}

基本上,我們刪除所有現(xiàn)在認(rèn)為已用完的輸入,并添加所有新輸出以將其標(biāo)記為可用。我們還將剩余的值累積在臨時(shí)存儲(chǔ)變量LeftoverTotal中,該變量將在區(qū)塊確定期間使用。

阻止獎(jiǎng)勵(lì)

區(qū)塊完成后,就該獎(jiǎng)勵(lì)創(chuàng)作該區(qū)塊的節(jié)點(diǎn)了。這是通過(guò)重新分配從此區(qū)塊中包括的所有事務(wù)中收集的剩余價(jià)值來(lái)完成的:

/// Redistribute combined leftover value evenly among authorities

fn spend_leftover(authorities: &[H256]) {

let leftover = 《LeftoverTotal《T》》::take();

let share_value = leftover / authorities.len() as Value;

if share_value == 0 { return }

for authority in authorities {

let utxo = TransactionOutput {

pubkey: *authority,

value: share_value,

salt: System::block_number() as u32,

};

let hash = BlakeTwo256::hash_of(&utxo);

if !《UnspentOutputs《T》》::exists(hash) {

《UnspentOutputs《T》》::insert(hash, utxo);

runtime_io::print(“l(fā)eftover share sent to”);

runtime_io::print(hash.as_fixed_bytes() as &[u8]);

} else {

runtime_io::print(“l(fā)eftover share wasted due to hash collision”);

}

}

}

邏輯非常簡(jiǎn)單:我們接受一個(gè)權(quán)限列表,然后將剩余的總值除以權(quán)限數(shù)平均得出一個(gè)share_value。然后,我們?yōu)槊總€(gè)作者創(chuàng)建一個(gè)UTXO,并將其插入U(xiǎn)nspentOutputs中。我們將當(dāng)前區(qū)塊號(hào)用作salt值,以防止上述潛在的重放攻擊。

我們還通過(guò)將獎(jiǎng)勵(lì)UTXO插入U(xiǎn)nspentOutputs來(lái)進(jìn)行檢查,以確保我們不會(huì)意外覆蓋一些恰好具有相同哈希值的現(xiàn)有UTXO。這種情況在實(shí)踐中極為罕見(jiàn),但是不幸的是,如果有人因?yàn)槌R?guī)獎(jiǎng)勵(lì)UTXO覆蓋了他或她的UTXO而損失了數(shù)百萬(wàn)美元的UTXO,那將是不幸的。

乍一看,我們似乎是憑空創(chuàng)造價(jià)值,但仔細(xì)想想,人們可能會(huì)意識(shí)到,全局價(jià)值不會(huì)增加,因?yàn)榻灰姿姓呙鞔_放棄了部分資金,以換取優(yōu)先權(quán)。

最后,由于每個(gè)區(qū)塊發(fā)起人都知道所有詳細(xì)信息,例如區(qū)塊編號(hào),該特定時(shí)代使用的會(huì)話密鑰,當(dāng)然還有與該會(huì)話密鑰匹配的秘密密鑰,因此區(qū)塊發(fā)起人將始終能夠重構(gòu)UTXO,計(jì)算其哈希值,即使沒(méi)有將UTXO存儲(chǔ)在任何地方也可以要求其獎(jiǎng)勵(lì)。

UTXO鎖定

這就是與比特幣不同的地方。

據(jù)我所知,比特幣規(guī)范并沒(méi)有規(guī)定哪些信息需要存儲(chǔ)在磁盤上以及如何存儲(chǔ)。唯一重要的是比特幣協(xié)議本身,它是根據(jù)交易和區(qū)塊來(lái)制定的。因此,每個(gè)節(jié)點(diǎn)必須建立自己的理解,在區(qū)塊鏈歷史的任何給定點(diǎn)上,哪些UTXO是有效的。

相反,根據(jù)定義,我們的UTXO實(shí)現(xiàn)具有所有參與節(jié)點(diǎn)都同意的全局狀態(tài)數(shù)據(jù)庫(kù)。眾所周知,它用于存儲(chǔ)UTXO狀態(tài)和剩余的臨時(shí)值。由于狀態(tài)數(shù)據(jù)庫(kù)是共識(shí)的一部分,因此我們可以在業(yè)務(wù)邏輯中依賴狀態(tài)數(shù)據(jù)庫(kù)的內(nèi)容,并確保所有其他節(jié)點(diǎn)都將這樣做。

但沒(méi)有什么能阻止我們儲(chǔ)存額外的東西。例如我們可以將現(xiàn)有UTXO的哈希映射映射到定義該UTXO的鎖定狀態(tài)的結(jié)構(gòu)。如果UTXO被鎖定,則不允許以通常的方式使用它:

#[cfg_attr(feature = “std”, derive(Serialize, Deserialize, Debug))]

#[derive(Clone, Encode, Decode, Hash)]

pub enum LockStatus《T: Trait》 {

// Referred UTXO is locked

Locked,

// Referred UTXO is locked until specified block

LockedUntil(T::BlockNumber),

}

decl_storage! {

trait Store for Module《T: Trait》 as Utxo {

。..

/// Outputs that are locked

LockedOutputs: map H256 =》 Option《LockStatus《T》》;

}

}

很像鎖在保險(xiǎn)箱里的現(xiàn)金:你可以最終使用它,但不早于你打開(kāi)保險(xiǎn)箱的時(shí)候。它是可用的,只是鎖上了。

你可能在想,為什么一個(gè)人會(huì)需要這個(gè)?您會(huì)發(fā)現(xiàn),在加密貨幣的世界中,有一種趨勢(shì)是用貪婪程度更低,更有效的方法來(lái)代替舊的廢物證明算法(proof-of-waste)。一種可能是將資金本身用作保證同peer行為正常的保證。

基本上,有人會(huì)說(shuō):“我發(fā)誓要遵守規(guī)則。這是我的錢。請(qǐng)把它鎖在安全的地方。如果有人證明我的行為不當(dāng),那么我的錢就必須削減或在誠(chéng)實(shí)的參與者之間分配?!碑?dāng)然,如果這樣的人隨后希望取回他或她的資金,則網(wǎng)絡(luò)將檢查是否沒(méi)有惡意行為。在最后期限內(nèi)提取,然后解鎖資金。通常,鎖定的資金越多,您獲得的能力,投票權(quán)重或收入就越多。此類系統(tǒng)通常簡(jiǎn)稱為權(quán)益證明或PoS。

只要網(wǎng)絡(luò)中三分之二以上的節(jié)點(diǎn)沒(méi)有惡意,并且按照協(xié)議操作,這就可以正常工作。除了執(zhí)行常規(guī)任務(wù)外,這些節(jié)點(diǎn)還將支持PoS。

在類似以太坊的區(qū)塊鏈中,在調(diào)度交易時(shí),對(duì)可用資金的推論可能非常復(fù)雜:每個(gè)節(jié)點(diǎn)必須確保有足夠的可用資金,尤其是因?yàn)榭赡艽嬖谂c時(shí)間相關(guān)的復(fù)雜合約。

有趣的是,我們的UTXO實(shí)現(xiàn)以幾行代碼來(lái)完成。與以太坊式的鏈相反,類比特幣的鏈的資金已經(jīng)以自然的方式分配。我們可以輕松地鎖定單個(gè)UTXO,并在滿足某些解鎖條件之前防止其被花費(fèi)。

由于狀態(tài)數(shù)據(jù)庫(kù)不是其原始規(guī)范的一部分,因此在比特幣中很難做到這一點(diǎn)。因此,很難在任何給定的時(shí)間點(diǎn)推斷哪個(gè)UTXO被鎖定,更不用說(shuō)客戶端兼容性問(wèn)題了。

交易排序

在談到鏈的業(yè)務(wù)邏輯時(shí),我們提到Substrate為我們完成了所有骯臟的工作,例如處理塊存儲(chǔ),執(zhí)行網(wǎng)絡(luò)交互和進(jìn)行共識(shí)投票。但這并非總是如此。我們已經(jīng)說(shuō)過(guò),我們的runtime原子性一次調(diào)度一個(gè)事務(wù)。因此如果該交易有效,則狀態(tài)將相應(yīng)更改。

但是如果兩個(gè)從屬事務(wù)在短時(shí)間內(nèi)到達(dá)同一節(jié)點(diǎn)會(huì)發(fā)生什么呢?真實(shí)的網(wǎng)絡(luò)是復(fù)雜且不可預(yù)測(cè)的。連接性問(wèn)題和突然的拓?fù)涓目赡軙?huì)對(duì)傳輸?shù)臄?shù)據(jù)造成各種影響。值得注意的是,消息可能會(huì)丟失,延遲或重新排序。后一個(gè)事實(shí)對(duì)我們尤為重要。

想象一個(gè)情況,我們有兩個(gè)事務(wù),A和B,B依賴于A。在UTXO的情況下,這意味著B(niǎo)消耗了A創(chuàng)建的UTXO。如果B在A之前到達(dá),我們可能會(huì)遇到這樣的情況節(jié)點(diǎn)運(yùn)行時(shí)將無(wú)法檢查事務(wù)的有效性,因?yàn)樗昧丝此撇淮嬖诘腢TXO。當(dāng)然,我們確實(shí)知道它存在,但尚未交付,但是節(jié)點(diǎn)不知道。本質(zhì)上,它有兩個(gè)選擇:

1. 只需將交易B視為無(wú)效即可。如果原始發(fā)送人重新廣播該交易,它仍將有機(jī)會(huì)被應(yīng)用,但不會(huì)早于A被調(diào)度。此解決方案可能有效,但它是骯臟且無(wú)效的。此外,一些嚴(yán)重的網(wǎng)絡(luò)問(wèn)題可能導(dǎo)致無(wú)法分配B的情況,從而使整個(gè)系統(tǒng)無(wú)用。我們可以做得更好。

2. 將事務(wù)B的分派推遲到有意義的時(shí)候。在我們的情況下,我們需要以某種方式等待A的發(fā)送。

第二種選擇似乎更有趣,但是在實(shí)踐中我們?cè)撊绾巫瞿??通過(guò)其本身的設(shè)計(jì),Substrate對(duì)運(yùn)行時(shí)內(nèi)部或鏈的業(yè)務(wù)邏輯一無(wú)所知。實(shí)際上,從其角度來(lái)看,Substrate就像不透明的字節(jié)數(shù)組一樣“看到”我們的交易。

這里的解決方案是“解釋” Substrate如何處理我們的交易以及如何正確排序它們。這是通過(guò)使用事務(wù)池向運(yùn)行時(shí)公開(kāi)的專用TaggedTransactionQueue API完成的。

在Substrate中,每個(gè)事務(wù)都與兩組標(biāo)簽相關(guān)聯(lián):require和Provides。標(biāo)簽只是代表某個(gè)唯一值的任意字節(jié)向量。第一組描述此事務(wù)需要哪些標(biāo)簽,而第二組定義此事務(wù)提供的標(biāo)簽。

在上述情況下,我們需要通過(guò)聲明A提供一些標(biāo)簽而B(niǎo)消耗與其要求相同的標(biāo)簽來(lái)將事務(wù)A和B鏈接在一起。為了簡(jiǎn)單起見(jiàn),我們可以使用UTXO哈希作為標(biāo)簽。

通過(guò)遍歷事務(wù)并查詢其標(biāo)記,事務(wù)池以一種順序組織它們,以使每個(gè)事務(wù)都可以滿足其要求。那些熟悉計(jì)算機(jī)科學(xué)的人可能會(huì)意識(shí)到這類似于拓?fù)漤樞颉?/p>

有時(shí)兩個(gè)事務(wù)不相互依賴,但又依賴于第三次事務(wù)。例如我們可能有交易A產(chǎn)生兩個(gè)輸出,交易B和C分別花費(fèi)這兩個(gè)輸出。這將導(dǎo)致B和C都依賴于A。拓?fù)渑判驙顟B(tài)規(guī)定必須在B和C之前調(diào)度A,但是未定義分發(fā)B和C的順序。在這種情況下,事務(wù)池使用其他條件來(lái)確定事務(wù)的優(yōu)先級(jí)。

經(jīng)典解決方案是將剩余值的數(shù)量用作優(yōu)先級(jí)。交易所有者有意留給當(dāng)局的資金越多,交易優(yōu)先級(jí)就越高,雙贏。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉