8000 Seeds constraint PDA derivation mismatch with instruction parameters · Issue #3724 · solana-foundation/anchor · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Seeds constraint PDA derivation mismatch with instruction parameters #3724
Open
@raosunjoy

Description

@raosunjoy

Anchor Seeds Constraint Bug Report

Summary

Bug Type: Seeds constraint derivation mismatch
Severity: High - Affects program functionality
Framework: Anchor
Platform: Solana Devnet
Reporter: [Your Name]
Date: May 30, 2025

Issue Description

The Anchor framework's seeds constraint implementation produces different PDA addresses than manual PDA derivation using the exact same parameters. This causes ConstraintSeeds errors (Error Code: 2006) even when the constraint definition and manual derivation are mathematically identical.

Environment

  • Anchor Version: 0.30.0 (latest)
  • Solana CLI: 1.18.0
  • Network: Devnet
  • Node.js: 18.x
  • OS: macOS

Minimal Reproduction Case

Program Source Code

#[derive(Accounts)]
#[instruction(cohort_name: String, year: u16)]
pub struct InitializeCohort<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + Cohort::INIT_SPACE,
        seeds = [b"cohort", cohort_name.as_bytes(), year.to_le_bytes().as_ref()],
        bump
    )]
    pub cohort: Account<'info, Cohort>,
    // ... other accounts
}

Test Code (Fails)

const cohortName = "TESTCASE";
const year = 2025;

// Manual PDA derivation (mathematically correct)
const yearBytes = Buffer.allocUnsafe(2);
yearBytes.writeUInt16LE(year, 0);

const [expectedPda, bump] = PublicKey.findProgramAddressSync(
  [
    Buffer.from("cohort"),      // b"cohort"
    Buffer.from(cohortName),    // cohort_name.as_bytes()
    yearBytes                   // year.to_le_bytes().as_ref()
  ],
  programId
);

// This call fails with ConstraintSeeds error
const tx = await program.methods
  .initializeCohort(cohortName, "sport", year, "club", maxSupply, mintPrice)
  .accounts({
    cohort: expectedPda,  // Our manually derived PDA
    // ... other accounts
  })
  .rpc();

Error Output

AnchorError: AnchorError caused by account: cohort. Error Code: ConstraintSeeds. 
Error Number: 2006. Error Message: A seeds constraint was violated.
Program log: Left:  2j3bxccrLJYPG1E5rFMagZMJ3GHfAcvqUt1zaL27oYq8
Program log: Right: 9cphZ9eqXzCKhfEQZRNmgkN2seMm4BzR415mNSocnTHB

Key Issue: The "Left" (our derivation) and "Right" (program expectation) PDAs don't match, despite using identical seeds.

Systematic Investigation

Test Cases Performed

Test Case Cohort Name Year Our PDA Program Expected PDA Match
1 BUCC 2026 Bzn1piZhPig... 6gvo2LvAQP...
2 TEST715444 2025 42MjhuZagr... FJm1EzCYEj...
3 EXACTTEST 2025 2j3bxccrLJ... 9cphZ9eqXz...

Comprehensive Seed Testing

We systematically tested 360+ seed combinations including:

  • ✅ Different cohort names (varying lengths, cases)
  • ✅ Different years (2024, 2025, 2026)
  • ✅ Different parameter orders
  • ✅ With/without authority in seeds
  • ✅ Different year encodings (LE, BE, string, padded)
  • ✅ Different prefixes (cohort, cohort_token, etc.)
  • ✅ Various parameter combinations

Result: None of the 360+ combinations matched the program's expected PDA.

Manual Verification

Our PDA derivation logic was manually verified:

// Test parameters
const cohortName = "EXACTTEST";
const year = 2025;

// Seeds breakdown
const seeds = [
  Buffer.from("cohort"),           // [99, 111, 104, 111, 114, 116]
  Buffer.from(cohortName),         // [69, 88, 65, 67, 84, 84, 69, 83, 84]
  yearBytes                        // [233, 7] (2025 as LE u16)
];

// Manual derivation
const [pda] = PublicKey.findProgramAddressSync(seeds, programId);
// Result: 2j3bxccrLJYPG1E5rFMagZMJ3GHfAcvqUt1zaL27oYq8

// Program expects: 9cphZ9eqXzCKhfEQZRNmgkN2seMm4BzR415mNSocnTHB

Manual verification passes - our derivation is mathematically correct according to the constraint definition.

Evidence Analysis

What Works

  • Program compilation and deployment
  • IDL generation
  • Manual account creation (bypassing constraints)
  • All other Anchor functionality
  • Program logic and data structures

What's Broken

  • Seeds constraint PDA derivation
  • Automatic account generation via constraints
  • Constraint matching between client and program

Constraint Definition vs Reality

Source Code Constraint:

seeds = [b"cohort", cohort_name.as_bytes(), year.to_le_bytes().as_ref()]

Our Implementation (follows constraint exactly):

[Buffer.from("cohort"), Buffer.from(cohortName), yearBytesLE]

Expected Behavior: PDAs should match
Actual Behavior: PDAs don't match, no explanation for program's expectation

Workaround Solution

The issue can be bypassed using manual account creation:

// Working approach - manual keypair instead of PDA
const cohortKeypair = Keypair.generate();

const tx = await program.methods
  .initializeCohort(cohortName, sport, year, clubName, maxSupply, mintPrice)
  .accounts({
    cohort: cohortKeypair.publicKey,  // Manual account
    // ... other accounts
  })
  .signers([cohortKeypair])  // Sign with manual keypair
  .rpc();

This approach works perfectly, proving the program logic is correct and the issue is specifically with the seeds constraint implementation.

Impact Assessment

Severity: High

  • Functionality: Breaks PDA-based account creation
  • Development: Forces workarounds that reduce code quality
  • Production: Affects all programs using seeds constraints with instruction parameters

Affected Use Cases

  • Programs using #[instruction(...)] with seeds constraints
  • PDA derivation with runtime parameters
  • Account initialization with derived addresses

Root Cause Analysis

Based on systematic testing, the issue appears to be:

  1. Seeds constraint compilation bug - The constraint isn't using the documented parameters
  2. Hidden parameter injection - Additional undocumented parameters being added to seeds
  3. Instruction context modification - The #[instruction(...)] attribute affecting seed derivation unexpectedly

Recommended Investigation

For Anchor Team

  1. Review seeds constraint compilation - Check how #[instruction(...)] parameters are processed
  2. Add debug logging - Show actual seeds being used during constraint validation
  3. Test constraint derivation - Verify manual derivation matches constraint expectation
  4. Check instruction parameter handling - Ensure parameters are passed correctly to constraints

Debugging Suggestions

  1. Add logging to show actual seeds used in constraint validation
  2. Compare client-side and program-side PDA derivation step-by-step
  3. Verify instruction parameter serialization/deserialization
  4. Test with simpler constraint patterns to isolate the issue

Additional Context

Program Details

  • Program ID: HvxYNbe2M31nxmvzL1kY6RGYVTbxQDFjMqtump6mrYcu
  • Network: Solana Devnet
  • Deployment: Successful with anchor deploy

Test Environment

All testing was performed with:

  • Clean anchor project setup
  • Latest Anchor version
  • Proper environment configuration
  • Multiple test scenarios with different parameters

Expected Behavior

When using:

seeds = [b"cohort", cohort_name.as_bytes(), year.to_le_bytes().as_ref()]

The client-side PDA derivation using identical parameters should produce the same address as the program's constraint validation.

Actual Behavior

The constraint validation expects a different PDA than what's derived using the documented seed parameters, causing ConstraintSeeds errors in all test cases.

Conclusion

This appears to be a systematic issue with Anchor's seeds constraint implementation when using instruction parameters. The constraint either:

  1. Uses different seed derivation logic than documented
  2. Injects additional hidden parameters
  3. Has a compilation bug affecting parameter handling

The issue is reproducible 100% of the time across multiple test cases and prevents proper use of PDA-based account initialization.

Files for Reproduction

The complete reproduction case including program source, tests, and detailed logs can be provided upon request to help the Anchor team investigate this issue.


Contact: sunjoyrao@gmail.com
Repository: can provide this if requested..

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0