什么是 PDA?
PDA 在 Solana 中代表“程序派生地址”。它是由 Solana 程序生成的一种特殊类型的地址,并非直接来自用户的私钥。PDA的主要目的是允许程序拥有和控制某些数据或资产,而无需传统的私钥签名。
如果您觉得这个概念令人困惑,让我们分解一下以获得更详细的解释。
私钥、公钥和助记词
与以太坊类似,Solana 有三个主要组成部分:私钥、公钥和助记词。私钥是保密的,不应泄露。在授权交易时,我们使用私钥对其进行签名以授予授权。私钥是一串随机字符,对应于助记词。助记词可用于通过算法派生私钥。因此,在使用钱包时,只需记住助记词就足够了。可以使用加密算法从私钥派生出公钥。公钥是可共享的,其他人可以使用它来向您转移资金。此外,公钥还用作程序的地址,称为program_id 。
需要注意的是,我们可以从助记词推导出私钥,从私钥推导出公钥,但不能从公钥逆向推导出私钥或助记词。这确保了加密地址的安全性。这个过程涉及到 ECDSA 算法,为了更深入地了解,你可以探索ECDSA算法的原理。
如上图简化所示,曲线上每个 X 轴上的私钥都对应着 Y 轴上的公钥。然而,Q 点的公钥在任何 X 轴上都没有对应的私钥。这意味着这个公钥没有对应的私钥!这意味着这个公钥不是从任何私钥派生出来的。
这就是 PDA 的原理。“程序派生地址”(PDA)没有对应的私钥。它来自程序的program_id和seed ,这就是为什么它被称为“程序派生地址”。有时,通过 program_id和seed 获得的公钥有对应的私钥。在这种情况下,我们需要重新生成公钥,通常是在我们的program_id和 seed 之外添加一个数字(这个数字有一个特殊的术语叫做bump )。这个数字从 255 开始递减,直到我们生成一个没有对应私钥的公钥。
我们为什么需要PDA?
在区块链中,你需要一个私钥来证明公钥的所有权。你可以用这个私钥签署并授权账户的转账请求。但是,如果账户属于一个去中心化的程序,而不是个人,那么将私钥放在链上并不是一个好主意。由于所有程序代码在链上都是公开的,如果每个人都能看到你的私钥,那么就会发生恶意操作,比如窃取你的代币。这时,没有私钥的 PDA 就派上用场了。这样,程序就可以在不需要私钥的情况下签署地址。
如何生成 PDA 地址
在这里,我们使用 Solana Anchor开发框架来初始化一个 PDA 账户(我们将在后面的部分中专门介绍 Anchor 框架;这里,我们旨在让您对 PDA 账户生成过程有一个基本的了解)。
// Data stored in the PDA account2pub struct Counter { count: u64
该PDA账户存储了Counter结构的数据,其中包含一个u64类型的值count 。
pub struct InitializeAccounts<'info> { #[account( init, seeds = [b"my_seed", user.key.to_bytes().as_ref() ] bump, payer = user, space = 8 + 8 )] pub pda_counter: Account<'info, Counter>, }
pda_counter字段表示要生成的 PDA 账户。我们标记了初始化时使用的种子值和bump 。种子可以是任何根据业务场景设置的字节数组。Anchor 会自动使用第一个符合条件的 bump 值,因此无需手动指定。在内部,Anchor 还会自动检索 program_id ,因此这里也不需要手动指定。
但是我们需要指定账户所占用的空间,以及用于支付初始化交易费用的账户(payer )。这里指定账户的空间大小为16个字节。前8个字节存储了Anchor自动添加的鉴别符,用于标识账户类型。后8个字节为Counter账户类型存储的数据分配空间(count为u64类型,占用8个字节)。该空间主要用于计算账户在网络中的租金。
虽然这段代码并不完整,但它演示了PDA账户的相关内容:program_id、程序ID、种子、bump值和空间。详细的解释将在后面的部分中讲解。