PDA türetme

Özet

PDA'lar, seed'ler + program ID + bump değerlerinin SHA-256 ile hash'lenmesiyle, sonuç Ed25519 eğrisinin dışına çıkana kadar türetilir. Canonical bump, eğri dışı bir adres üreten ilk değerdir. Maksimum 16 seed, seed başına maksimum 32 bayt.

Arka plan

Solana Keypair değerleri Ed25519 eğrisi üzerindeki noktalardır. Bir keypair, bir public key (hesap adresi olarak kullanılır) ve bir secret key'den (imza üretmek için kullanılır) oluşur. Secret key'e sahip olan herkes o adres için işlem imzalayabilir.

Eğri üzerinde adreslere sahip iki hesapEğri üzerinde adreslere sahip iki hesap

Bir PDA, kasıtlı olarak Ed25519 eğrisinin dışına düşecek şekilde türetilir. Geçerli bir eğri noktası olmadığı için secret key mevcut değildir ve harici bir taraf imza üretemez. Yalnızca türeten program, invoke_signed aracılığıyla PDA üzerindeki işlemleri yetkilendirebilir.

Eğri dışı adresEğri dışı adres

PDA ve keypair hesapları

ÖzellikKeypair hesabıPDA hesabı
Adres türüEd25519 eğrisi üzerindeEd25519 eğrisi dışında
Private key var mıEvetHayır
İşlem imzalayabilir miEvet (private key ile)Hayır
CPI sırasında imzalayabilir miHayır (imza işleme dahil edilmedikçe)Evet (invoke_signed ile)
TüretmeEd25519 keypair oluşturSeed'ler + program ID'den deterministik
Tipik kullanımKullanıcı cüzdanları, program IDPrograma ait veri hesapları

İsteğe bağlı seed'ler

İsteğe bağlı seed'ler, PDA türetme işlemi için girdi olarak kullanılan kullanıcı tanımlı bayt dizileridir. Bunlar bir programa özgü benzersiz, deterministik adresler oluştururlar. Örneğin, ["user", user_pubkey] seed olarak kullanıldığında her kullanıcı için farklı bir PDA türetilir.

Seed'ler şu kısıtlamalara uymalıdır:

  • Türetme başına maksimum 16 seed (MAX_SEEDS)
  • Seed başına maksimum 32 bayt (MAX_SEED_LEN)

Bump seed

Bump seed, türetme sırasında isteğe bağlı seed'lere eklenen tek bir bayttır (0-255). find_program_address 255'ten 0'a doğru arama yapar ve her değerle create_program_address çağrısı yaparak sonucun Ed25519 eğrisinin dışına çıkmasını sağlar. Başarılı olan ilk değer kanonik bump'tır.

Programlar, seed'lerden adrese benzersiz ve deterministik bir eşleme sağlamak için her zaman kanonik bump kullanmalıdır.

PDA'ları türetirken her zaman kanonik bump kullanın. Kanonik olmayan bir bump kullanmak aynı seed'ler için ikinci bir geçerli adres oluşturur ve bu durum bir saldırganın beklenenden farklı bir hesabı yerine koyabileceği güvenlik açıklarına yol açabilir.

PDA türetmePDA türetme

Türetme algoritması

PDA türetme işlemi SDK'nın create_program_address fonksiyonunda uygulanmıştır. Algoritma şu şekilde çalışır:

  1. Seed sayısının MAX_SEEDS (16) değerini aşmadığını ve hiçbir seed'in MAX_SEED_LEN (32 bayt) değerini aşmadığını doğrulayın. Her iki kontrolden biri başarısız olursa PubkeyError::MaxSeedLengthExceeded döndürün.
  2. Tüm seed'leri, program ID'sini ve "ProgramDerivedAddress" dizesini birlikte SHA-256 ile hash'leyerek 32 baytlık bir sonuç üretin.
  3. Sonucun Ed25519 eğrisi üzerinde geçerli bir nokta olup olmadığını kontrol edin.
  4. Sonuç eğri ÜZERİNDE ise PubkeyError::InvalidSeeds döndürün (adresin karşılık gelen bir özel anahtarı olur ki bu PDA güvenlik özelliğini ihlal eder).
  5. Sonuç eğri üzerinde DEĞİLSE, onu PDA olarak döndürün.

Hesaplama birimi maliyetleri

create_program_address için on-chain syscall çağrı başına 1.500 CU ücretlendirir.

try_find_program_address syscall girişte 1.500 CU (döngüden önce), ardından döngü içindeki her başarısız bump denemesi için ek 1.500 CU ücretlendirir.

Yaygın seed kalıpları

Seed'ler uygulamaya özgüdür. Yaygın kalıplar şunlardır:

KalıpSeed'lerKullanım durumu
Global singleton["global"]Program genelinde tek config hesabı
Kullanıcı başına hesap["user", user_pubkey]Program başına kullanıcı başına bir hesap
Kullanıcı başına varlık başına["vault", user_pubkey, mint_pubkey]Token vault'ları, kullanıcı başına token başına
Sayaç / sıralı["order", user_pubkey, &order_id.to_le_bytes()]Kullanıcı başına sıralı kayıtlar

Seed'ler hash'lenmeden önce birleştirilir, bu nedenle ["ab", "cd"] ve ["abcd"] aynı PDA'yı üretir. Çakışmaları önlemek için sabit uzunlukta seed'ler veya ayırıcı kullanın. Örneğin, ["ab", "-", "cd"] belirsizlik içermez.

Örnekler: Bir PDA türetme

Bir PDA türetmek yalnızca bir adres hesaplar. Bu adreste on-chain bir hesap oluşturmaz. Hesap, ayrı bir talimat aracılığıyla açıkça oluşturulmalıdır (genellikle CPI aracılığıyla create_account).

Solana SDK'ları PDA türetme için fonksiyonlar sağlar. Her fonksiyon şunları alır:

  • Program ID: PDA'yı türetmek için kullanılan programın adresi. Bu program, PDA adına imzalayabilir.
  • Opsiyonel seed'ler: String'ler, sayılar veya diğer hesap adresleri gibi önceden tanımlanmış girdiler.
SDKFonksiyon
@solana/kit (TypeScript)getProgramDerivedAddress
@solana/web3.js (TypeScript)findProgramAddressSync
solana_sdk (Rust)find_program_address

Aşağıdaki örnekler Solana SDK'larını kullanarak bir PDA türetir. Kodu çalıştırmak için ▷ Çalıştır'a tıklayın.

String seed ile PDA türetme

Aşağıdaki örnek, bir program ID'si ve isteğe bağlı bir string seed kullanarak PDA türetir.

import { Address, getProgramDerivedAddress } from "@solana/kit";
const programAddress = "11111111111111111111111111111111" as Address;
const seeds = ["helloWorld"];
const [pda, bump] = await getProgramDerivedAddress({
programAddress,
seeds
});
console.log(`PDA: ${pda}`);
console.log(`Bump: ${bump}`);
Console
Click to execute the code.

Adres seed'i ile PDA türetme

Aşağıdaki örnek, bir program ID'si ve isteğe bağlı bir adres seed'i kullanarak PDA türetir.

import {
Address,
getAddressEncoder,
getProgramDerivedAddress
} from "@solana/kit";
const programAddress = "11111111111111111111111111111111" as Address;
const addressEncoder = getAddressEncoder();
const optionalSeedAddress = addressEncoder.encode(
"B9Lf9z5BfNPT4d5KMeaBFx8x1G4CULZYR1jA2kmxRDka" as Address
);
const seeds = [optionalSeedAddress];
const [pda, bump] = await getProgramDerivedAddress({
programAddress,
seeds
});
console.log(`PDA: ${pda}`);
console.log(`Bump: ${bump}`);
Console
Click to execute the code.

Birden fazla seed ile PDA türetme

Aşağıdaki örnek, bir program ID'si ve birden fazla isteğe bağlı seed kullanarak PDA türetir.

import {
Address,
getAddressEncoder,
getProgramDerivedAddress
} from "@solana/kit";
const programAddress = "11111111111111111111111111111111" as Address;
const optionalSeedString = "helloWorld";
const addressEncoder = getAddressEncoder();
const optionalSeedAddress = addressEncoder.encode(
"B9Lf9z5BfNPT4d5KMeaBFx8x1G4CULZYR1jA2kmxRDka" as Address
);
const seeds = [optionalSeedString, optionalSeedAddress];
const [pda, bump] = await getProgramDerivedAddress({
programAddress,
seeds
});
console.log(`PDA: ${pda}`);
console.log(`Bump: ${bump}`);
Console
Click to execute the code.

Tüm bump'ları yineleme

Aşağıdaki örnekler, tüm olası bump seed'lerini (255'ten 0'a) kullanarak PDA türetmeyi gösterir ve find_program_address fonksiyonunun kanonik bump değerini nasıl döndürdüğünü gösterir:

Kit örneği dahil edilmemiştir çünkü createProgramDerivedAddress fonksiyonu dışa aktarılmamıştır.

import { PublicKey } from "@solana/web3.js";
const programId = new PublicKey("11111111111111111111111111111111");
const optionalSeed = "helloWorld";
// Loop through all bump seeds (255 down to 0)
for (let bump = 255; bump >= 0; bump--) {
try {
const PDA = PublicKey.createProgramAddressSync(
[Buffer.from(optionalSeed), Buffer.from([bump])],
programId
);
console.log("bump " + bump + ": " + PDA);
} catch (error) {
console.log("bump " + bump + ": " + error);
}
}
Console
Click to execute the code.
bump 255: Error: Invalid seeds, address must fall off the curve
bump 254: 46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6X
bump 253: GBNWBGxKmdcd7JrMnBdZke9Fumj9sir4rpbruwEGmR4y
bump 252: THfBMgduMonjaNsCisKa7Qz2cBoG1VCUYHyso7UXYHH
bump 251: EuRrNqJAofo7y3Jy6MGvF7eZAYegqYTwH2dnLCwDDGdP
bump 250: Error: Invalid seeds, address must fall off the curve
...
// remaining bump outputs

Bu örnekte, bump 255 eğri üzerinde bir adres üretir ve başarısız olur. İlk geçerli bump 254'tür ve bu onu kanonik bump yapar.

Is this page helpful?

Yönetici

© 2026 Solana Vakfı.
Tüm hakları saklıdır.
Bağlanın