What are PDAs?
Program Derived Addresses are special Solana addresses that:- Are derived deterministically from seeds and a program ID
- Have no corresponding private key (cannot sign transactions)
- Can only be controlled by the program that derived them
- Allow programs to “sign” for these addresses using
invoke_signed
All SolBid game state accounts (GameState, PlayerState, Bid) use PDAs to ensure secure, deterministic addressing.
PDA derivation utilities
The program provides three utility functions for PDA derivation, located inutils.rs:
game_pda_seeds
Derives the PDA for a GameState account.["game", game_id.to_le_bytes()]
Returns: (Pubkey, u8) - The derived address and bump seed
See utils.rs:13-15 for implementation.
Unique game identifier. Each game_id produces a unique PDA.
The SolBid program’s public key. Used by
find_program_address to derive the PDA.player_pda_seeds
Derives the PDA for a PlayerState account.["player", game_id.to_le_bytes(), player_pubkey.as_ref(), bid_count.to_le_bytes()]
Returns: (Pubkey, u8) - The derived address and bump seed
See utils.rs:24-34 for implementation.
The game identifier this player state belongs to.
The public key of the player who placed the bid.
The bid sequence number when this player state was created. This allows the same player to have multiple PlayerState accounts (one per bid).
The SolBid program’s public key.
The same player bidding multiple times will have different PlayerState PDAs because bid_count changes.
bid_pda_seeds
Derives the PDA for a Bid account.["bid", game_id.to_le_bytes(), bid_number.to_le_bytes()]
Returns: (Pubkey, u8) - The derived address and bump seed
See utils.rs:17-22 for implementation.
The game identifier this bid belongs to.
Sequential bid number (1, 2, 3, …). Matches the game’s total_bids count when this bid was placed.
The SolBid program’s public key.
PDA usage in instructions
CreateGame instruction
The CreateGame instruction creates three PDAs:instructions/create_game.rs:38-61 for full implementation.
PlaceBid instruction
The PlaceBid instruction creates two new PDAs:instructions/place_bid.rs:56-75 for full implementation.
Creating accounts with PDAs
The program usesinvoke_signed to create PDA accounts:
- For GameState:
["game", game_id, bump] - For PlayerState:
["player", game_id, player_pubkey, bid_count, bump] - For Bid:
["bid", game_id, bid_number, bump]
instructions/create_game.rs:68-102 for examples.
PDA verification
Every instruction verifies that provided accounts match expected PDAs:PDA examples by account type
Game PDA
Seeds:["game", game_id]
| game_id | Derived Address (example) |
|---|---|
| 1 | Game11...xyz1 |
| 2 | Game22...abc2 |
| 100 | Game33...def3 |
Player PDA
Seeds:["player", game_id, player_pubkey, bid_count]
| game_id | player_pubkey | bid_count | Derived Address (example) |
|---|---|---|---|
| 1 | Alice… | 1 | Play11...aaa1 |
| 1 | Alice… | 5 | Play22...aaa5 (same player, different bid) |
| 1 | Bob… | 2 | Play33...bbb2 |
Bid PDA
Seeds:["bid", game_id, bid_number]
| game_id | bid_number | Derived Address (example) |
|---|---|---|
| 1 | 1 | Bid111...xyz1 |
| 1 | 2 | Bid222...xyz2 |
| 2 | 1 | Bid333...abc1 (different game) |
Client-side PDA derivation
Clients must derive PDAs before calling instructions:U64 values must be converted to little-endian byte arrays to match the Rust implementation’s
to_le_bytes() format.Benefits of PDA-based architecture
- Deterministic addressing - Anyone can derive account addresses without on-chain queries
- No keypair management - Users don’t need to generate or store keypairs for game accounts
- Security - Only the program can sign for PDAs, preventing unauthorized modifications
- Collision resistance - Unique seeds ensure different games/players/bids never collide
- Simplified client code - Clients just need game_id and other parameters to find accounts
Common PDA errors
When working with PDAs, watch for these errors:- InvalidGameAccount - Provided game account doesn’t match expected PDA
- InvalidPlayerAccount - Provided player account doesn’t match expected PDA
- InvalidBidAccount - Provided bid account doesn’t match expected PDA
- InvalidNewPlayerAccount - New player PDA mismatch in PlaceBid
- InvalidNewBidAccount - New bid PDA mismatch in PlaceBid
error.rs:8-21 for error definitions.