Solana(索拉納)公鏈
一、背景
隨着加密貨幣市場熱度不斷攀升,以太坊的用戶也不斷增加,隨之而來的就是高額的Gas費用以及擁堵的網絡,這迫使用戶不得不去尋找新的公鏈。
公鏈領域存在着“不可能三角”,即去中心化、安全性和可擴展性三者不可兼得。其中,各大公鏈都會首要保證去中心化和安全性,於是可擴展性便成為許多新興公鏈鑽研的目標。
Solana是在這個背景下產生的。它給自己的定位是世界上最快的高性能公鏈,它的可擴展性可以達到網絡級別,理論上標准千兆網絡下TPS 最高可達 71 萬。
公鏈領域的“不可能三角”問題,TPS對比圖如下:
TPS:Transactions Per Second(每秒傳輸的事物處理個數),即服務器每秒處理的事務數。TPS包括一條消息入和一條消息出,加上一次用戶數據庫訪問。(業務TPS = CAPS × 每個呼叫平均TPS)
TPS是軟件測試結果的測量單位。一個事務是指一個客戶機向服務器發送請求然后服務器做出反應的過程。客戶機在發送請求時開始計時,收到服務器響應后結束計時,以此來計算使用的時間和完成的事務個數。
一般的,評價系統性能均以每秒鍾完成的技術交易的數量來衡量。系統整體處理能力取決於處理能力最低模塊的TPS值。
二、基本概念
Solana 創立於2017年,總部位於瑞士日內瓦,三位主要創始人Anatoly Yakovenko、Greg Fitzgerald和Stephen Akridge,都曾就職於高通公司。這么一支技術團隊致力於將Solana打造為:一條根據摩爾定律(摩爾定律是由英特爾(Intel)創始人之一戈登·摩爾(Gordon Moore)提出來的。其內容為:當價格不變時,集成電路上可容納的元器件的數目,約每隔18-24個月便會增加一倍,性能也將提升一倍) 擴容、為大規模應用提供高性能和低費用的公鏈。
下面是Solana的大事件:
之前DeFi的盛行讓以太坊交易慢、gas貴。而Solana團隊在DeFi爆發的前夜,預見性地推出了以太坊橋——蟲洞(Wormhole)協議,實現了Solana和以太坊上資產的跨鏈轉移,這為以太坊上大量的DeFi項目提供了一個新的選項。在Layer 2擴容方案完善落地之前,Solana為各平台、項目提供了一條無需重寫合約即可低成本快速遷移的公鏈。
當以太坊的問題暴露在所有人面前的時候,Solana的提前布局為他們帶來了很多優質項目的遷移和大量活躍用戶。
(一)Solana的優勢
Solana利用工作歷史證明 PoH、基站拜占庭容錯(Tower BFT)、渦輪機(區塊傳播協議)、海灣流(無內存交易轉發協議)、海平面(並行智能合約)、管道(驗證交易)、雲散(水平擴展賬戶數據庫)以及檔案(分布式賬本存儲)八大突破性技術構建出了一個超高性能的區塊鏈。
現在相較與其他公鏈:費用低、可拓展性好、有自己的蟲洞協議來跨鏈互通。
(二)跟ETH公鏈的不同點
1.賬戶模型
作為一個開發者,最先要了解的就是賬戶模型
(1)以太坊賬戶模型
大家都知道以太坊賬戶模型是分兩種,一種是主網幣,一種是合約幣,主網幣里面的的account 就有一個balance字斷,用來記錄用戶的ETH 的數量,如果某個地址擁有其他的token ,是在合約里面給這個地址存了個mapping,用來記錄這個用戶token 的數量。因此用戶擁有的ERC20 token其實記賬是記錄在合約里面,以太坊合約具有存儲功能,是因為合約用一個世紀狀態永遠存儲在區塊里面。
(2)Solana賬戶模型
solana 的賬戶模型不一樣的地方在於,solana 賬戶除了可以存儲本幣sol以外,還增加了一個data字段。
這個data字段:具體可以參考https://github.com/jstarry/solana-wiki/blob/main/content/zh-cn/docs/Account%20Model/_index.md
先看一下賬戶的字段:
詳細描述一下
lamports :這個就是和以太坊的balance一樣,描述這個賬號有多少個SOL 可以使用
owner:owner這個字段保證了用戶對賬戶的決定擁有權利,如果某一個地址是某一個account的owner,那么那個地址就可以對這個account資產進行轉移。所以solana的合約token其實就是solana程序會幫忙生成一個account,然后把owner賦予給你。
Executable:這個表示用戶的狀態是不是可執行的狀態。在solana的賬戶體系里面的data字斷是表示存儲,或者可執行。可執行的data是帳戶數據專門用於不可變字節代碼該字節代碼用於處理交易。
data:這個和executable 描述相似
rent_epoch:這個比較有意思,就是solana的合約和solidity合約不一樣的地方,solana的合約部署是要按大小定期收費的,目前是費用是2天一收,應該是0.01SOL 1K的大小。如果沒有費用solana系統就會清除這些賬號。
2.solana 合約和solidity合約的區別
solana的合約其實就是一段程序,這個程序沒有存儲功能,程序編譯好以后,是一個BPF字節碼,這個和solidity 編譯后是一段二進制碼是一樣的。 solidity是通過合約地址找到合約存在得狀態數,然后再通過input參數,拿到需要執行得方法和參數,再執行對於得合約方法。solana 這個部分是一樣得,solana 發布到連上得合約有一個programID,這個programID也是一個Hash256,類似solidity合約地址一樣,solana 合約得方法通過一個枚舉來定義,也就是,方法分別是0-1-2-3-4,參數就是解析data,那么solana 合約最難得就是要解析這個data,因為這個data是用戶自己定義和排序的,solana不提供標准的map,struct,這些數據結構存儲, 都是以文本得形式存儲在各個account里面得data里面,所以solana合約最困難得就是要對data進行編碼,解析再解碼,你可以想象一下一個token合約,solidity 最多兩個map,一個是balance,一個是allowance,就夠了,但是solana不一樣,他沒有存儲,他需要為每一個人創建一個臨時得account,然后解析出來,給他們做tranfer或者approve操作。還要有一堆的安全性判斷。最重要得是你要得存儲進行排版,解析。
(三)Solana的合約
由於賬戶模型的不一樣,那么剛開始理解solana的合約就很困難,基於Solana開發需要知道的幾個問題:
1、solana 合約開發環境
2、solana 合約開發語言
3、solana 合約部署
4、solana 合約邏輯
5、solana 合約前端后端交互
1.solana 合約框架
先整理清楚solana 合約是怎么運行的。
2.合約具體分析
通過學習token 合約來整體理解Solana,這里不講helloworld,因為token 合約結構更完善。
token 合約路徑:[solana Token]
token 合約目錄結構
–cli
–js
---- cli
---- client
--------token.js
–program
----src
------entrypoint.rs // 這個整個程序的入口,也就是solana節點會把交易里面的參數都傳入到這個接口
------error.rs // 錯誤信息
------instruction.rs // 這個才是序列化/反序列化的/結構體的定義問題
------lib.rs //這個是rust 用來串聯本目錄或者其他目錄文件用的
------native_mint.rs // 這個是mint 方法
------processor.rs //這個是token 的所有方法調用的地方,所有方法實現的地方,進入到這些方法,需要傳入的參數包括(函數,參數 都要解析出來)
------state.rs // 這個是狀態
這里類比使用go 語言版本的solidity來理解Solana智能合約,首先要明白它是需要運行在主網代碼上,所以有幾個要點:
1、哪個程序
2、哪個函數
3、實現什么功能
4、結果在哪里
(1)用token 的tranfer 方法來對上面問題進行解答
1、哪個程序
前面介紹了solana 的智能合約的指向是一個programID,programID 就和solidity合約的合約地址是一個意思,所以發送交易的時候要指定programID。
2、哪個函數
我們的合約可能有很多方法,那么我一筆交易,指定了programID,我還需要指定是哪個函數,以及對應的參數,所以再processor方法里面,我們看到一個match 用來分發函數,里面的第一個就是獲取用戶輸入的調用的哪個方法。
代碼示例:pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {undefined
let instruction = TokenInstruction::unpack(input)?;
也可以通過看token.js方法里面的交易組裝函數(createTransferCheckedInstruction),就有一個instruction :12這樣一個賦值,所以這個12就是對應的函數,那么這個定義一般要怎么定義?
dataLayout.encode(
{
undefined
instruction: 12, // TransferChecked instruction
amount: new u64(amount).toBuffer(),
decimals,
},
data,
);
看instruction.rs文件,里面有定一個enum,里面定義了每個函數的instruction,也就是說,前端需要知道有哪些函數,這個就和ABI一樣,但是更簡單。復雜的事數據的處理,我們看看12是哪個函數:上面表示使用TransferChecked 這個函數。
TransferChecked {undefined
/// The amount of tokens to transfer.
amount: u64,
/// Expected number of base 10 digits to the right of the decimal place.
decimals: u8,
}
3、這個函數做什么事情
從 pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult 這個函數里面找到12 這個instruction對應的TransferChecked 然后去分發進入的是這個 【process_transfer】
TokenInstruction::TransferChecked {
amount, decimals } => {undefined
msg!(“Instruction: TransferChecked”);
Self::process_transfer(program_id, accounts, amount, Some(decimals))
}
通過學習可以知道process_transfer這個函數做了什么事情:
1、賬戶狀態的准備檢查
2、賬戶轉賬處理
3、賬戶信息打包(pack 函數)
4、怎么存儲
由於整個rust 都是用指針對內存文件進行讀寫操作,所有在pack 結束后就進行了存儲。
(2)solana 合約交易
對於前端而言,和solidity有什么區別?
solidity前端只需要使用ABI 對input data 進行bytecode 就可以了,然后進行組裝交易,發送簽名交易。就可以完成合約的調用,使用的是web3j的庫。
那么solana 的前端調用合約交易如何組裝呢?
統一交易的參數:
static createTransferInstruction(
programId: PublicKey,
source: PublicKey,
destination: PublicKey,
owner: PublicKey,
multiSigners: Array,
amount: number | u64,
輸出參數的定義
const dataLayout = BufferLayout.struct([
BufferLayout.u8(‘instruction’),
Layout.uint64(‘amount’),
]);
調用合約函數的綁定
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{undefined
instruction: 3, // Transfer instruction
amount: new u64(amount).toBuffer(),
},
data,
);
from /to 壓縮到keys 里面
let keys = [
{pubkey: source, isSigner: false, isWritable: true},
{pubkey: destination, isSigner: false, isWritable: true},
];
if (multiSigners.length === 0) {undefined
keys.push({undefined
pubkey: owner,
isSigner: true,
isWritable: false,
});
} else {undefined
keys.push({pubkey: owner, isSigner: false, isWritable: false});
multiSigners.forEach(signer =>
keys.push({undefined
pubkey: signer.publicKey,
isSigner: true,
isWritable: false,
}),
);
}
組裝好的交易返回出去
return new TransactionInstruction({undefined
keys,
programId: programId,
data,
});
總的來說 交易發送也是對交易的組裝,對input的組裝,和solidity 幾乎一樣。
3.solana 合約開發語言
solana 目前支持 rust、C++ 和C 對合約進行開發,官方建議跟網上建議都是推薦學習Rust,因為整個鏈都是rust的開發的。整個接口或者其他的框架也大部分是rust,這樣可利用的開發工具就會更多。
初步學習,在學習完helloworld以后看 token的代碼、合約,還有web3j調用。
示例學習鏈接如下:
helloworld 鏈接[solana Helloworld]
token 合約代碼鏈接[solana Token]
三、環境搭建
兩種環境搭建方式:有現有的docker鏡像,可以直接pull鏡像部署;或者通過拉源碼本地搭建節點。
(一)solana 的安裝
solana公鏈環境搭建可以參考的官方文檔如下:
1.環境安裝
[Install the Solana Tool Suite]
[Using Solana CLI]
2.anhore安裝
anhore 是一個開發工具,類似solidity 的 truffle 和 hardhat
3.本地節點搭建
依據該鏈接:https://solongwallet.medium.com/solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91-%E6%90%AD%E5%BB%BA%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83-9723b858937e
四、基於搭建環境的開發和部署
待完善
五、示例
時間問題,待本地完善后補充