2021-06-16 18:09

解析 | Solana中的关键数据结构

Solana中的关键数据结构 

为了方便合约的书写,Solana官方提供了C和Rust的SDK,对于Rust来说,只要在工程中添加

solana-program = "1.6.7"

即可以添加SDK的依赖,这里的版本号可以自行选择。而SDK的相关代码可以查阅相关Crate solana_sdk这里介绍一些SDK中提供的主要数据结构。 

Pubkey

#[repr(transparent)]
#[derive(
    Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash, AbiExample,
)]
pub struct Pubkey([u8; 32]);]

Pubkey实际上就是32个字符表示的base58的Account地址,在Instruction中,我们看到的ProgramId 就是这样的类型,因为Program本身其实是一个文件,也就是Account,只是是可执行的文件。

AccountInfo

/// Account information
#[derive(Clone)]
pub struct AccountInfo<'a> {
    /// Public key of the account
    pub key: &'a Pubkey,
    /// Was the transaction signed by this account's public key?
    pub is_signer: bool,
    /// Is the account writable?
    pub is_writable: bool,
    /// The lamports in the account.  Modifiable by programs.
    pub lamports: Rc'a mut u64>>,
    /// The data held in this account.  Modifiable by programs.
    pub data: Rc'a mut [u8]>>,
    /// Program that owns this account
    pub owner: &'a Pubkey,
    /// This account's data contains a loaded program (and is now read-only)
    pub executable: bool,
    /// The epoch at which this account will next owe rent
    pub rent_epoch: Epoch,
}

AccountInfo就是一个Account在链上的表达形式,可以认为是一个文件的属性,想象一下state函数列出的文件属性。

其中,key表示文件名,也就是base58的地址。而文件大小可以认为是lamports,这里区别于我们操作系统里面的文件,操作系统里面的文件的大小是可以为0的,且文件存在,而Solana链上的Account如果其大小也就是lamports为0的话,就认为这个文件被删除了。

这里的“executable”表示文件是否可执行,如果是可执行的,那么就是一个智能合约账号。而data里面则是文件的内容,类似电脑上的ls列出的文件属性,和cat列出来的文件内容。

每个文件都要由一个程序来创建,这个程序称之为这个文件的拥有者,也就是这里的owner。 

ProgramResult

/// Reasons the program may fail
#[derive(Clone, Debug, Deserialize, Eq, Error, PartialEq, Serialize)]
pub enum ProgramError {
    /// Allows on-chain programs to implement program-specific error types and see them returned
    /// by the Solana runtime. A program-specific error may be any type that is represented as
    /// or serialized to a u32 integer.
    #[error("Custom program error: {0:#x}")]
    Custom(u32)
    ...
}
use std::{
    result::Result as ResultGeneric,
};
pub type ProgramResult = ResultGeneric<(), ProgramError>;

ProgramResult实际上类型为ProgramError的Result对象,而ProgramError是Solana自定义的一个Error的枚举,也就是Solana抛出来的错误枚举。

在合约中,当正常逻辑执行结束后,我们通过Ok()来返回这里Reuslt正确的结果,如果出错了,则通过这里的Result中的ProgramError错误返回。

AccountMeta

/// Account metadata used to define Instructions
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct AccountMeta {
    /// An account's public key
    pub pubkey: Pubkey,
    /// True if an Instruction requires a Transaction signature matching `pubkey`.
    pub is_signer: bool,
    /// True if the `pubkey` can be loaded as a read-write account.
    pub is_writable: bool,
}

AccountMeta主要用于Instruction结构的定义,用于协助传递这个指令需要的其他账号信息,其中包括了账号的地址,这个账号是否为签名账号,以及这个账号对应的内容(AccountInfo)是否可以修改。 

Instruction

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Instruction {
    /// Pubkey of the instruction processor that executes this instruction
    pub program_id: Pubkey,
    /// Metadata for what accounts should be passed to the instruction processor
    pub accounts: Vec,
    /// Opaque data passed to the instruction processor
    pub data: Vec<u8>,
}

Instruction在上面已经有介绍了,代表一个处理指令,包含了要处理他的程序的地址program_id,以及这个程序处理时需要用到的AccountMeta表示的账号信息,还有这个指令对应的具体数据payload部分的data。

这里真实的用户协议数据是序列化后,存放在data里面的,所以整体流程是DApp客户端将自定义的指令数据序列化到data里面,然后将账号信息和data发到链上,Solana节点为其找到要执行的程序,并将账号信息和数据data传递给合约程序,合约程序里面将这个data数据反序列化,得到客户端传过来的具体参数。 

总结 

Solana的合约编程,其实主要就是对Account的增删改查,或者说就是我们普通程序中的对文件的增删改查。这其中需要使用Solana提供的SDK,按照其框架进行编程,主要数据结构在SDK中都有提供,在编写逻辑的时候,可以直接使用。

本文链接:https://www.8btc.com/media/6649536
转载请注明文章出处

评论
登录 账号发表你的看法,还没有账号?立即免费 注册
下载
阅读
分享
评论
点赞
上一篇
下一篇