Yhteenveto
PDA:t johdetaan hajautusarvolla seedit + ohjelmatunniste + bump SHA-256:n kautta, kunnes tulos on Ed25519-käyrän ulkopuolella. Kanoninen bump on ensimmäinen arvo, joka tuottaa käyrän ulkopuolisen osoitteen. Maksimi 16 seediä, maksimi 32 tavua per seedi.
Tausta
Solanan
Keypair
-arvot ovat pisteitä Ed25519-käyrällä. Avainpari
koostuu julkisesta avaimesta (käytetään tilin osoitteena) ja salaisesta
avaimesta (käytetään allekirjoitusten tuottamiseen). Kuka tahansa, jolla on
salainen avain, voi allekirjoittaa transaktioita kyseiselle osoitteelle.
Kaksi tiliä käyrällä olevilla osoitteilla
PDA johdetaan tarkoituksella putoamaan Ed25519-käyrän ulkopuolelle. Koska se
ei ole kelvollinen käyräpiste, salaista avainta ei ole olemassa, eikä mikään
ulkopuolinen taho voi tuottaa allekirjoitusta. Vain johdattava ohjelma voi
valtuuttaa operaatioita PDA:lla invoke_signed:n kautta.
Käyrän ulkopuolinen osoite
PDA vs avainparitilit
| Ominaisuus | Avainparitili | PDA-tili |
|---|---|---|
| Osoitetyyppi | Ed25519-käyrällä | Ed25519-käyrän ulkopuolella |
| On yksityinen avain | Kyllä | Ei |
| Voi allekirjoittaa transaktioita | Kyllä (yksityisellä avaimella) | Ei |
| Voi allekirjoittaa CPI:n aikana | Ei (ellei allekirjoitusta sisällytetä transaktioon) | Kyllä (invoke_signed:n kautta) |
| Johdannainen | Generoi Ed25519-avainpari | Deterministinen seediistä + ohjelmatunnisteesta |
| Tyypillinen käyttö | Käyttäjälompakot, ohjelmatunniste | Ohjelman omistamat datatilit |
Valinnaiset siemenet
Valinnaiset siemenet ovat käyttäjän määrittämiä tavujonoja, jotka toimivat
syötteinä PDA-johdannaiselle. Ne luovat ainutlaatuisia, deterministisiä
osoitteita, jotka on rajattu ohjelmaan. Esimerkiksi ["user", user_pubkey]:n
käyttäminen siemeninä johtaa eri PDA:han jokaiselle käyttäjälle.
Siementen on noudatettava seuraavia rajoituksia:
- Enintään 16 siementä johdannaista kohti (
MAX_SEEDS) - Enintään 32 tavua siementä kohti (
MAX_SEED_LEN)
Bump seed
Bump seed on yksittäinen tavu (0-255), joka liitetään valinnaisten siementen
perään johdannaisen aikana.
find_program_address
etsii arvosta 255 alaspäin arvoon 0, kutsuen create_program_address:a
jokaisella arvolla, kunnes tulos putoaa Ed25519-käyrän ulkopuolelle. Ensimmäinen
onnistunut arvo on kanoninen bump.
Ohjelmien tulisi aina käyttää kanonista bumpia varmistaakseen ainutlaatuisen, deterministisen yhdistämisen siemenistä osoitteeseen.
Käytä aina kanonista bumpia johdettaessa PDA:ita. Ei-kanonisen bumpin käyttäminen luo toisen kelvollisen osoitteen samoille siemenille, mikä voi johtaa haavoittuvuuksiin, joissa hyökkääjä korvaa odotetun tilin toisella.
PDA-johdannainen
Johdannaisalgoritmi
PDA-johdannainen on toteutettu SDK:n
create_program_address-funktiossa.
Algoritmi toimii seuraavasti:
- Validoi, että siementen määrä ei ylitä
MAX_SEEDS:a (16) eikä yksittäinen siemen ylitäMAX_SEED_LEN:a (32 tavua). Jos jompikumpi tarkistus epäonnistuu, palautaPubkeyError::MaxSeedLengthExceeded. - SHA-256-hajautusarvo kaikista siemenistä, ohjelmatunnuksesta ja merkkijonosta
"ProgramDerivedAddress"yhdessä tuottaaksesi 32-tavuisen tuloksen. - Tarkista, onko tulos kelvollinen piste Ed25519-käyrällä.
- Jos tulos ON käyrällä, palauta
PubkeyError::InvalidSeeds(osoitteella olisi vastaava yksityinen avain, mikä rikkoo PDA:n turvallisuusominaisuutta). - Jos tulos EI ole käyrällä, palauta se PDA:na.
Laskentayksikkökustannukset
Ketjussa oleva syscall
create_program_address-toiminnolle veloittaa
1 500 CU:ta
per kutsu.
try_find_program_address syscall
veloittaa 1 500 CU:ta alussa (ennen silmukkaa), ja sen jälkeen ylimääräiset 1
500 CU:ta jokaisesta epäonnistuneesta bump-yrityksestä silmukan sisällä.
Yleiset seed-mallit
Seedit ovat sovelluskohtaisia. Yleisiä malleja ovat:
| Malli | Seedit | Käyttötapaus |
|---|---|---|
| Globaali singleton | ["global"] | Yksittäinen ohjelman laajuinen konfiguraatiotili |
| Käyttäjäkohtainen tili | ["user", user_pubkey] | Yksi tili per käyttäjä per ohjelma |
| Käyttäjä-entiteetti-kohtainen | ["vault", user_pubkey, mint_pubkey] | Token-holvit, per käyttäjä per token |
| Laskuri / peräkkäinen | ["order", user_pubkey, &order_id.to_le_bytes()] | Peräkkäiset tietueet per käyttäjä |
Seedit yhdistetään ennen hajautusta, joten ["ab", "cd"] ja ["abcd"]
tuottavat saman PDA:n. Käytä kiinteän pituisia seedejä tai erotinta
välttääksesi törmäykset. Esimerkiksi ["ab", "-", "cd"] on yksiselitteinen.
Esimerkit: PDA:n johdattaminen
PDA:n johdattaminen laskee vain osoitteen. Se ei luo ketjussa olevaa tiliä
kyseiseen osoitteeseen. Tili on luotava erikseen erillisellä instruktiolla
(tyypillisesti create_account CPI:n kautta).
Solana SDK:t tarjoavat funktioita PDA:n johdattamiseen. Jokainen funktio ottaa:
- Program ID: Ohjelman osoite, jota käytetään PDA:n johdattamiseen. Tämä ohjelma voi allekirjoittaa PDA:n puolesta.
- Valinnaiset seedit: Ennalta määritellyt syötteet, kuten merkkijonot, numerot tai muut tilien osoitteet.
| SDK | Funktio |
|---|---|
@solana/kit (TypeScript) | getProgramDerivedAddress |
@solana/web3.js (TypeScript) | findProgramAddressSync |
solana_sdk (Rust) | find_program_address |
Alla olevat esimerkit johdattavat PDA:n käyttäen Solana SDK:ita. Napsauta ▷ Suorita suorittaaksesi koodin.
Johda PDA merkkijonoseedillä
Alla oleva esimerkki johtaa PDA:n käyttäen ohjelma-ID:tä ja valinnaista merkkijonoseedä.
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}`);
Johda PDA osoiteseedillä
Alla oleva esimerkki johtaa PDA:n käyttäen ohjelma-ID:tä ja valinnaista osoiteseedä.
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}`);
Johda PDA useilla seedeillä
Alla oleva esimerkki johtaa PDA:n käyttäen ohjelma-ID:tä ja useita valinnaisia seedejä.
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}`);
Kaikkien bumpien iterointi
Seuraavat esimerkit näyttävät PDA:n johtamisen käyttäen kaikkia mahdollisia
bump-seedejä (255:stä 0:aan), havainnollistaen kuinka find_program_address
palauttaa kanonisen bumpin:
Kit-esimerkkiä ei ole mukana, koska
createProgramDerivedAddress-funktiota
ei ole viety.
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);}}
bump 255: Error: Invalid seeds, address must fall off the curvebump 254: 46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6Xbump 253: GBNWBGxKmdcd7JrMnBdZke9Fumj9sir4rpbruwEGmR4ybump 252: THfBMgduMonjaNsCisKa7Qz2cBoG1VCUYHyso7UXYHHbump 251: EuRrNqJAofo7y3Jy6MGvF7eZAYegqYTwH2dnLCwDDGdPbump 250: Error: Invalid seeds, address must fall off the curve...// remaining bump outputs
Tässä esimerkissä bump 255 tuottaa käyrällä olevan osoitteen ja epäonnistuu. Ensimmäinen kelvollinen bump on 254, mikä tekee siitä kanonisen bumpin.
Is this page helpful?