3個Aleo 開發者必知的核心概念

Engilsh

作為主網上線前的最後一次測試網,Aleo Testnet 3已經吸引了全球一眾開發者的目光。隨著三階段Phase 1的進行,開發者可以進行程序部署和轉賬,離網絡的完善又更近了一步。站在開發者的角度,本文會為大家簡單介紹關於 Aleo 程序開發的三大核心概念,來幫助開發者社區對Aleo有更進一步的了解。

基於零知識證明的編程語言

不管是Leo還是其編譯後的Aleo instructions都是Aleo公鏈的智能合約的一部分。就像其他公鏈的智能合約編程語言一樣like solidity,都是為鏈上交易以及鏈上應用開發提供便利性的工具。而Aleo公鏈不同的是在於,Aleo公鏈的智能合約編程語言是基於零知識證明技術zksnark實現的。通過將“智能合約的執行”打包成一個同態加密的多項式,通過驗證這個多項式的結果,來確定交易是否可信是否上鍊,這樣就可以做到真正的隱私計算、隱私交易。具體的操作過程如下圖所示。

這樣的好處不僅僅是提高了隱私性,這種鏈下執行加鏈下驗證的模式,給程序提供了無上限的運行時,同時鏈上節點只需要驗證Proof是否正確,驗證時間遠比執行時間短,所以可以大幅提高鏈的tps。同時因為不存在鏈上運行時的概念,所以也不需要考慮程序gas費過高的問題。

那麼對於我們開發者來說,知道這些有什麼用呢?這就要說它的缺點了,我們知道通過zksnark生成的多項式本質是程序約束的一種形式。所以我們的程序必須是確定性的,這樣程序的約束才能是確定性的,才能生成對應的多項式。所以很多傳統編程語言的功能很難實現,這也就是為什麼Aleo團隊不選擇實現圖靈完備的原因。所以作為開發者,我們需要了解這部分知識,對其有一個正確的期待。

還有一個缺點就是鏈下生成proof需要設備的性能比較強,所以低性能設備例如手機生成proof可能會非常慢。當然Aleo也有解決方案,那就是低性能設備可以通過委託Prover幫你生成證明,當然這樣就有一定的tradeoff,因為你的部分隱私會被用來換取便利性。在Aleo instructions中,可以通過finalize關鍵字實現部分程序鏈上執行的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// The function `mint_public` issues the specified token amount
// for the token receiver publicly on the network.
function mint_public:
// Input the token receiver.
input r0 as address.public;
// Input the token amount.
input r1 as u64.public;
// Mint the tokens publicly.
finalize r0 r1;

// The finalize scope of `mint_public` increments the
// `account` of the token receiver by the specified amount.
finalize mint_public:
// Input the token receiver.
input r0 as address.public;
// Input the token amount.
input r1 as u64.public;

// Increments `account[r0]` by `r1`.
// If `account[r0]` does not exist, it will be created.
// If `account[r0] + r1` overflows, `mint_public` is reverted.
increment account[r0] by r1;

這裡默認你已經看了avm的doc。可以看到這裡主要實現了min_public函數,並且用finalize關鍵字重寫了mint_public。簡單來說用finalize關鍵字重寫的函數是鏈上執行的,而原函數則是鏈下執行的。原函數通過將輸入寄存在finalize類型的寄存器裡,之後在鏈上執行的時候會取出finalize寄存器的值進行對應finalize function的操作。這裡要注意finalize寄存器只能接受public的數據,所以意味著你的input是可能有隱私問題的,就像上面說的,這是一個tradeoff。

ZEXE模型

aleo的模型和以太坊以及比特幣不同,比特幣使用的是UTXO(Unspent Transaction Output)模型,而以太坊使用的是基於賬戶的模型。 aleo的zexe交易模型更像是比特幣。

zexe模型中有一個重要的概念就是record,record承載著智能合約的數據。在zexe模型中每個transaction至少對應一個record。

這裡的record就像UTXO模型一樣,每次交易消耗掉舊的records,生成新的records,而所有該用戶現存的records總和,即為該用戶所有資產的總餘額。就像現實中的紙幣一樣,不同的是record能夠承載別的數據。

每個record會包含4個parameter

  • owner是該record所有者,也就是user的公鑰地址。
  • gates是該record持有的aleo幣的數量
  • data是存在該record的數據,屬於程序可自定義的map存儲區。開發者可以在這個值裡存儲自己定義的數據類型。
  • nonce是隨機值,也就是防止雙花record的標識。

下面的代碼是Aleo instructions定義record的方式

1
2
3
4
5
//aleo instruction define record
record credits:
owner as address.private;
gates as u64.private;
{ident} as {type}.{pub|priv}

這樣任何輸入輸出的records,都會在對應的data map區域新增對應的鍵值對map<ident,type>(如果已經存在則不新增)。利用這個功能我們能自己定義屬於自己的assets,去支持各種金融應用。

最近Aleo instructions還引入的新的關鍵字mapping。這個關鍵字是目前專門用於鏈上執行的,也就是只能用於前面所說的finalize關鍵字聲明的function裡面。

1
2
3
4
5
mapping account:
// The token owner.
key owner as address.public;
// The token amount.
value amount as u64.public;

通過聲明mapping<key,value>,會在全節點的內存中開闢一個新的**公開的(public)全局的(global)**的data storage。開發者可以在鏈上存儲自己定義的鍵值對,這裡鍵值對必須是public的,並且對應的increment decrement的操作也只能是finalize類型的寄存器。目前對於mapping的使用場景還不清楚,還需要看後續的開發情況。

棧式虛擬機(Stack-based virtual machine)

眾所周知,虛擬機分為棧式虛擬機和寄存器虛擬機(register-based virtual machine)。知名的JVM和以太坊EVM都是棧式虛擬機,lua是寄存器虛擬機。目前Aleo的snarkvm實現的也是棧式虛擬機。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pub struct Stack<N: Network> {
/// The program (record types, interfaces, functions).
program: Program<N>,
/// The mapping of external stacks as `(program ID, stack)`.
external_stacks: IndexMap<ProgramID<N>, Stack<N>>,
/// The mapping of closure and function names to their register types.
register_types: IndexMap<Identifier<N>, RegisterTypes<N>>,
/// The mapping of finalize names to their register types.
finalize_types: IndexMap<Identifier<N>, FinalizeTypes<N>>,
/// The universal SRS.
universal_srs: Arc<UniversalSRS<N>>,
/// The mapping of function name to proving key.
proving_keys: Arc<RwLock<IndexMap<Identifier<N>, ProvingKey<N>>>>,
/// The mapping of function name to verifying key.
verifying_keys: Arc<RwLock<IndexMap<Identifier<N>, VerifyingKey<N>>>>,
}

上面的代碼就是snarkvm的棧幀數據結構。當snarkvm執行一段程序的對應function的時候,會先將該program初始化到新的棧幀裡,包括外部函數的使用(external_stack),所有function所需的registers(register_types,finalize_types),以及對應的pk,vk。每個棧幀都會有對應的寄存器數量,這個跟你寫完的program相關。加載完畢後,就按照棧的先進先出(first in first out)的原則,依次執行對應代碼和對應的外部函數引用。

就像是深度優先遍歷樹結構一樣,root節點的棧是我們初始程序,向下擴展的樹枝都是外部引用的程序棧。

以上就是關於 Aleo 開發階段的三個比較重要的核心概念,對於想要基於 Aleo開發隱私應用的開發者而言,這也是入門的基礎,希望本文可以給開發者社區帶來一些參考和啟發。

鏈接已復制!