如果你想学习如何开发Solana智能合约和项目,那么你来对地方了。
Solana是一个新兴的、高性能的且无许可的公链,它提供了快速、经济且可扩展的交易体验,并且它还支持使用Rust,C++和C语言来编写智能合约。
在本技术教程中,我们将一起看一看如何在Solana Devnet(测试网)编写、部署合约并与之进行交互,以及如何在Solana智能合约中使用Chainlink Price Feeds。
如何开发并部署Solana智能合约,完整视频:https://v.qq.com/x/page/k3303htl9gc.html
Solana的架构和编程模型
Solana是一个高性能的区块链,每秒能够处理数千笔交易,并且出块时间达到了亚秒级。它通过拜占庭容错(BFT)共识机制实现了这一点,该机制利用了一种称之为历史证明(PoH)的创新密码学函数。
历史证明
历史证明 (PoH) 通过使用高频可验证延迟函数(VDF),随着时间的推移建立可通过密码验证的事件顺序(在本例中为交易)。 从本质上讲,这意味着 PoH 就像一个加密时钟,可以帮助网络就时间和事件顺序达成一致,而无需等待其他节点的消息。这就像古老的水钟可以通过观察水位上升来记录时间的流逝一样,历史证明的区块链状态哈希的连续输出能够给出可验证的事件顺序。
这允许并行处理有序事件来帮助提升网络的性能,而在传统的区块链场景中,单个进程验证并打包要包含在下一个块中的所有交易。
一个简单的类比是想象一个100块的大型拼图。在正常情况下,完成拼图需要一个或多个人一定的时间。但是想象一下,如果事先所有拼图块都印有与其位置相对应的数字,从拼图的左上角到右下角,并按顺序排列成一行。 因为拼图的确切顺序和它们在拼图中的位置是事先知道的,所以可以让多人专注于每个部分,可以更快地解决拼图。 这是相对时间而言具有可验证的事件序列对共识机制的影响;它使得将事务分解为多个并行进程成为可能。
智能合约架构
Solana提供了一种不同于传统的基于EVM的区块链的智能合约模型。在传统的基于EVM的链中,合约代码/逻辑和状态被组合成一个部署在链上的合约。Solana中智能合约(或程序)是只读或无状态的,并且只包含程序逻辑。一旦部署后,智能合约就可以通过外部账户进行交互。Solana中与程序交互的账户会存储与程序交互相关的数据。这创建了状态(帐户)和合约逻辑(程序)的逻辑分离。这是Solana和基于EVM的智能合约之间的关键区别。以太坊上的账户与Solana上的账户不同,Solana账户可以存储数据(包括钱包信息),而以太坊账户并不存储数据。
除此之外,Solana还提供了CLI(命令行) 和JSON RPC API,这些可以用于去中心化应用程序与Solana区块链进行交互。还可以使用现有的SDK,用于客户端与区块链和Solana程序对话。
Solana开发工作流的抽象表述。 来源:Solana 文档
部署第一个Solana智能合约
在本节,你将会创建并部署一个“hello world”的Solana程序,使用Rust进行编写。
要求
在继续之前,应安装以下工具:
• NodeJS v14或更高版本 & NPM
• 最新的稳定版本的Rust
• Solana CLI v1.7.11或者更高版本
• Git
HelloWorld程序
该HelloWorld程序是一个智能合约,它可将输出打印到控制台,并统计给定的帐户调用该程序的次数,并将该数字存储在链上。我们将代码分解成不同的部分来讲解。
第一部分定义了一些标准的Solana程序参数并定义了程序的入口(“process_instruction”函数)。 此外,它还使用borsh对传入和传出部署程序的参数进行序列化和反序列化。
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint,
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};
/// Define the type of state stored in accounts
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
/// number of greetings
pub counter: u32,
}
// Declare and export the program's entrypoint
entrypoint!(process_instruction);
process_instruction函数接受program_id,这是一个公钥,也即程序部署后的地址;以及accountInfo,这是用于和合约交互的账户。
pub fn process_instruction(
program_id: &Pubkey, // Public key of the account the hello world program was loaded into
accounts: &[AccountInfo], // The account to say hello to
_instruction_data: &[u8], // Ignored, all helloworld instructions are hellos
ProgramResult是写程序的主要逻辑的地方。在本教程中,它只是打印一条消息,然后遍历“accounts”来选择帐户。 但是,在我们的示例中,将只有一个帐户。
) -> ProgramResult {
msg!("Hello World Rust program entrypoint");
// Iterating accounts is safer then indexing
let accounts_iter = &mut accounts.iter();
// Get the account to say hello to
let account = next_account_info(accounts_iter)?;
接下来,程序会检查该帐户是否有权修改指定帐户的数据。
// The account must be owned by the program in order to modify its data
if account.owner != program_id {
msg!("Greeted account does not have the correct program id");
return Err(ProgramError::IncorrectProgramId);
}
最后,该函数会将现有帐户存储的数字加一并将结果写回,然后显示一条消息。