Skip to main content

2 posts tagged with "co-learn"

View All Tags

· 5 min read
v1xingyue

在solana的数据账号使用过程中,牵扯两种账号

  • PDA (Program Derived Account)

由 createProgramAddressSync 产生。 通常由特定程序(通常是一个智能合约)关联额外的账户。该账号没有私钥,故除程序本身外,无法完成数据签名,无法完成完整的数据交易。

  • ADA (Account Derived Account)

由 createWithSeed 方法产生。 有一个账号公钥派生出来的关联账户,数据签名权限属于主账号。也即,需要主账号的签名才能完成完整的数据交易。

solana中,根据数据签名,决定了数据的真实所有权。即 我的数据我做主

本文主要分析这两种账号的异同。

地址生成逻辑介绍如下

  • PDA 地址生成规则
  1. buffer = [seed,programId,"ProgramDerivedAddress"]
  2. 对buffer 取 sha256
  3. 如果在曲线上,那么抛出error, 如果不在,那么直接返回作为 使用地址

createProgramAddressSync

  • ADA 生成
  1. buffer=[fromPublicKey,seed,programId]
  2. buffer 取 sha256, 直接返回

createWithSeed

区别在于,数据的托管使用逻辑.

  • ADA 数据签名权限,在于账户本身。即 我的数据我做主,未经允许(我未签名)不能修改。
  • PDA 数据签名权限在于合约。经过程序签名,可以修改 account 的数据和提取其中的sol。

ADA 账号使用

数据操作,有配套的函数对应,内部包含 xxxxWithSeedParams 类型的参数,完成对应的操作。 操作数据,需要 主账户的签名,这一点决定了,账号的真实所有权。

  • SystemProgram.createAccountWithSeed 初始化账号
  • SystemProgram.assign 重新分配owner
  • SystemProgram.allocate 分配空间
  • SystemProgram.transfer 转移SOL

PDA 账号使用

  • 客户端只用于账户地址推导,不能初始化。初始化过程在合约内部完成。
  • 因其签名权限,必须在合约内部完成。他的操作权限完全属于智能合约。

ADA 账号使用 example

  const seed = "ada.creator";

// 初始化ada 账户
let ada_account = await web3.PublicKey.createWithSeed(
signer.publicKey,
seed,
program
);
console.log("ada_account address: ", ada_account.toBase58());

let ada_info = await connection.getAccountInfo(ada_account);

// 根据是否存在账号,决定是否初始化
if (ada_info) {
console.log(ada_info);
} else {
console.log("ada account not found");
const transaction = new web3.Transaction().add(
web3.SystemProgram.createAccountWithSeed({
newAccountPubkey: ada_account,
fromPubkey: signer.publicKey,
basePubkey: signer.publicKey,
programId: program,
seed,
lamports: web3.LAMPORTS_PER_SOL,
space: 20,
})
);

PDA 使用 example

客户端部分代码逻辑

const pda_seed = "pda.creator";

const obj = new Model();

const [pda, bump_seed] = web3.PublicKey.findProgramAddressSync(
[signer.publicKey.toBuffer(), new TextEncoder().encode(movie.title)],
program
);

console.log("pda address : ", pda.toBase58());

const instruction = new web3.TransactionInstruction({
keys: [
{
// 付钱的账户
pubkey: signer.publicKey,
isSigner: true,
isWritable: false,
},
{
// PDA将存储数据
pubkey: pda,
isSigner: false,
isWritable: true,
},
{
// 系统程序将用于创建PDA
pubkey: web3.SystemProgram.programId,
isSigner: false,
isWritable: false,
},
],
// 传输数据
data: obj.serialize(),
programId: program,
});

const transaction = new web3.Transaction().add(instruction);

const signature = await web3.sendAndConfirmTransaction(
connection,
transaction,
[signer]
);

console.log(signature);

合约部分代码逻辑

// 获取账户迭代器
let account_info_iter = &mut accounts.iter();

// 获取账户
let initializer = next_account_info(account_info_iter)?;
let pda_account = next_account_info(account_info_iter)?;
let system_program = next_account_info(account_info_iter)?;

// 构造PDA账户
let (pda, bump_seed) =
Pubkey::find_program_address(&[initializer.key.as_ref(), title.as_bytes()], program_id);

// 和客户端比对
if pda != *pda_account.key {
msg!("Invalid seeds for PDA");
return Err(ProgramError::InvalidArgument);
}

// 计算所需的租金
let rent = Rent::get()?;
let rent_lamports = rent.minimum_balance(total_len);

// 创建账户
invoke_signed(
&system_instruction::create_account(
initializer.key,
pda_account.key,
rent_lamports,
total_len
.try_into()
.map_err(|_| Error::ConvertUsizeToU64Failed)?,
program_id,
),
&[
initializer.clone(),
pda_account.clone(),
system_program.clone(),
],
&[&[initializer.key.as_ref(), title.as_bytes(), &[bump_seed]]],
)?;

// MovieAccountState 定义的state类型
let mut account_data =
try_from_slice_unchecked::<MovieAccountState>(&pda_account.data.borrow()).unwrap();

account_data.title = title;
account_data.rating = rating;
account_data.description = description;
account_data.is_initialized = true;

// 写入pda 数据本身
account_data.serialize(&mut &mut pda_account.data.borrow_mut()[..])?;

参考资料

· 3 min read
Davirain

欢迎来到Solana共学,这是一个精心设计的教程系列,供任何对Solana感兴趣的人深入学习。无论你是初学者还是有经验的开发者,这些模块都会引导你了解Solana区块链开发的基本内容。

模块1:Solana基础

  • 区块链基本概念介绍
  • 本地程序开发环境配置
    • 原始Solana合约实现《hello, World》
    • Anchor合约框架实现《hello, World》
    • 使用Solang编译器编译solidity合约实现《hello, World》
  • BackPack钱包使用
  • 客户端开发
  • 钱包和前端
  • 自定义指令
  • 开始你自己的定制项目

模块2:Solana高级主题

  • SPL token
  • NFTs + 使用Metaplex进行铸造
  • 在用户界面中展示NFTs
  • 创造神奇的网络货币并出售JPEG图片

更深入的模块:深入了解Solana

  • 模块3:Rust入门,原生Solana开发,安全性,NFT质押
  • 模块4:本地环境,跨程序调用,测试,质押应用开发
  • 模块5:Anchor入门,全栈Anchor应用开发
  • 模块6:发布周,随机性,完善

特别主题:超越基础

  • Solana程序中的环境变量
  • Solana支付,版本化事务,Rust宏
  • Solana程序安全:签名授权,所有者检查,重新初始化攻击,PDA共享等
  • 使用Solidity编写Solana合约
  • 发行Token2020,压缩NFT
  • 在Solana中使用The Graph,Oracles Pyth SDK
  • TipLink使用,如何在Quicknode和Helius申请RPC endpoint
  • 等等...

和我们一起,在这全面的指南中探索Solana的每一个方面。从最基本的内容到安全和合约开发的复杂方面,Solana共学为每一位Solana爱好者提供了内容。

敬请期待,如果有任何问题或需要进一步的协助,请随时与我们联系。欢迎来到Solana共学!