פיתוח חוזים חכמים של Solana מקצה לקצה ב-Rust
אנו מפתחים חוזים חכמים של Solana ב-Rust במפתח מלא — החל מעיצוב מודל החשבונות ועד לפריסה עם multisig. Solana מושכת מפתחים עם סופיות תת-שנייה ועלות עסקה של $0.00025. אך מאחורי המהירות הזו עומד מודל ביצוע שונה מהותית: מודל חשבונות במקום אחסון חוזה, תוכניות חסרות מצב, גזירת PDA במקום מיפויים. מפתח שמגיע מ-EVM מבלה את השבועיים הראשונים במחשבה ש-Solana שבורה — כי הדפוסים המוכרים של Solidity או לא עובדים כאן או מובילים לסוג אחר של פרצות. למדנו לעקוף את המלכודות הללו במשך 5 שנות ניסיון.
למה תוכניות Solana שוברות מפתחי EVM
לפי התיעוד של Solana, תוכניות אינן הבעלים של נתונים — הן רק מאשרות פעולות על חשבונות שהועברו אליהן. ב-EVM, החוזה מאחסן את המצב שלו פנימי. ב-Solana, התוכנית היא קובץ הפעלה חסר מצב, והנתונים חיים בחשבונות נפרדים שהתוכנית אינה הבעלים שלהם — היא רק מאשרת פעולות עליהם.这意味着 כל קריאת הוראה דורשת העברת כל החשבונות המעורבים במפורש.
בדיקת חותם חסרה
מלכודת ראשונה: בדיקת חותם חסרה. התוכנית מקבלת חשבון דרך AccountInfo אך אינה בודקת שה-authority שהועבר אכן חתם על העסקה. ב-Anchor, זה נתפס עם התכונה #[account(signer)] או סוג Signer<'info>. ב-Rust טבעי, זה נעשה באמצעות בדיקה מפורשת if !authority.is_signer { return Err(...) }. קל לפספס את זה כשכותבים תוכניות ראשונות.
החלפת חשבון
הפרצה הקלאסית השנייה היא החלפת חשבון. התוכנית מקבלת token_account ו-authority אך אינה בודקת ש-token_account.owner תואם ל-authority שהועבר. תוקף מעביר token_account משלו ו-authority של מישהו אחר — התוכנית מתבצעת ללא שגיאה ומרוקנת אסימונים זרים.
אי-התאמה בגזירת PDA
הכאב הגדול השלישי הוא אי-התאמה בגזירת PDA. כתובת נגזרת מתוכנית (PDA) נגזרת מ-seeds + program_id. אם ה-seeds לא מאומתים במפורש דרך find_program_address עם אילוץ ב-Anchor (seeds = [b"vault", user.key().as_ref()]), תוקף יכול להעביר חשבון שרירותי שתואם לכתובת ה-PDA אך אינו לגיטימי.
| פרצה | סיבה | מניעה |
|---|---|---|
| חותם חסר | החתימה לא נבדקה | Signer<'info> או #[account(signer)] |
| החלפת חשבון | הבעלות לא נבדקה | אימות token_account.owner == authority |
| אי-התאמת PDA | ה-seeds לא אומתו | אילוץ seeds = [...] ב-Anchor |
איך Anchor משנה את משוואת האבטחה?
אנו משתמשים בעיקר במסגרת Anchor (גרסה נוכחית 0.30.x). Anchor מייצר מבדל (discriminator) לכל סוג חשבון ובודק אותו במהלך דה-סריאליזציה — זה סוגר אוטומטית מחלקה שלמה של התקפות בלבול סוגים שבהן תוקף מעביר חשבון מסוג שגוי.
מבנה הוראה טיפוסי בקוד שלנו:
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(
mut,
seeds = [b"vault", user.key().as_ref()],
bump,
constraint = vault.authority == user.key() @ ErrorCode::Unauthorized
)]
pub vault: Account<'info, VaultState>,
#[account(
mut,
associated_token::mint = mint,
associated_token::authority = user
)]
pub user_token_account: Account<'info, TokenAccount>,
pub user: Signer<'info>,
pub mint: Account<'info, Mint>,
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,
}אילוצים ב-#[derive(Accounts)] pub struct Deposit<'info> { #[account( mut, seeds = [b"vault", user.key().as_ref()], bump, constraint = vault.authority == user.key() @ ErrorCode::Unauthorized )] pub vault: Account<'info, VaultState>, #[account( mut, associated_token::mint = mint, associated_token::authority = user )] pub user_token_account: Account<'info, TokenAccount>, pub user: Signer<'info>, pub mint: Account<'info, Mint>, pub token_program: Program<'info, Token>, pub system_program: Program<'info, System>, } אינם רק סוכר תחבירי. הם מתקמפלים לבדיקות מפורשות שמתבצעות לפני לוגיקת ההוראה. אם אילוץ מופר — העסקה מתבטלת לפני שהלוגיקה רצה.
איך לבדוק תוכניות Solana בלי להפעיל Validator?
לרוב בדיקות היחידה, אנו משתמשים ב-solana-bankrun — זה מריץ runtime סינתטי בזיכרון בלי להפעיל validator. בדיקה שלוקחת 3 שניות על localnet (slot כל 400 אלפיות השנייה) מתבצעת ב-50 אלפיות השנייה — פי 60 מהר יותר. זה קריטי ל-fuzzing.
בדיקות אינטגרציה רצות על localnet דרך #[account(...)]. אנו מוסיפים anchor test כאשר תרחיש הבדיקה דורש תוכניות אמיתיות (Associated Token Program, Metaplex) — אנו משכפלים את המצב שלהן מ-mainnet באמצעות --skip-local-validator.
ל-fuzzing של תוכניות SPL, אנו משתמשים ב-Trident (ה-fuzzer של Ackee Blockchain). הוא מייצר רצפים אקראיים של הוראות ומחפש panics, מצב חשבון לא צפוי, גלישת מספרים שלמים. בפרויקט אחד, Trident מצא ב-4 שעות תרחיש שבו הרצף init → close → reinit הוביל לאתחול מחדש של חשבון עם נתונים זרים — המבדל של Anchor עבר כי ה-reinit השתמש באותו סוג.
אופטימיזציה של Compute Units
Solana מגביל כל עסקה ל-1.4M compute units כברירת מחדל (אפשר לבקש עד 1.4M דרך --clone). סריאליזציה/דה-סריאליזציה דרך Borsh יקרה למבנים גדולים.
פרקטיקה: לפצל מבני מצב גדולים למספר חשבונות. במקום SetComputeUnitLimit אחד עם 50 שדות — כמה חשבונות ייעודיים. פחות נתונים שעוברים דה-סריאליזציה לכל קריאה — פחות CU שנצרך.
טכניקה שנייה: חשבונות zero_copy דרך ProgramState ב-Anchor. הנתונים נקראים ישירות מהזיכרון בלי דה-סריאליזציה של Borsh. על מבנים >1KB, אנו חוסכים 30-50% CU.
| גישה | CU לדה-סריאליזציה של 1KB | יכולת שינוי |
|---|---|---|
| Borsh סטנדרטי | ~8000 CU | מלאה |
| zero_copy (bytemuck) | ~500 CU | מוגבלת (repr(C)) |
תהליך הפיתוח
אנליטיקה ועיצוב (2-5 ימים). אנו מפרקים את מודל החשבונות למשימה: אילו PDAs נדרשים, אילו seeds, איפה נדרש CPI ל-Token Program או Associated Token Program. אנו מתכננים את המצב לפני כתיבת קוד — שינוי מבנה החשבונות במהלך בדיקות הוא יקר.
פיתוח (3-10 ימים תלוי במורכבות). Anchor + Rust stable. אנו מכסים כל הוראה בבדיקות דרך Bankrun. תרחישים מורכבים (מחזור חיים של PDA, שרשראות CPI) רצים על localnet.
סקירת אבטחה. אנו מריצים את זה דרך Soteria (ניתוח סטטי לתוכניות Solana) וסקירה ידנית לפי רשימת בדיקה: חותם חסר, בדיקות בעלות, אימות PDA, חשבון מספרים שלמים (אנו משתמשים ב-#[account(zero_copy)], checked_add בכל מקום).
רשימת בדיקות אבטחה לתוכניות Solana
- [ ] כל החותמים אומתו
- [ ] בדיקות בעלות על כל חשבון
- [ ] גזירת PDA עם אילוץ seeds
- [ ] חשבון עם checked_ops
- [ ] אין פרצות reinit
- [ ] הרשאת שדרוג מוגדרת ל-multisig
פריסה. checked_mul עם הרשאת שדרוג multisig (Squads Protocol). הרשאת השדרוג לא צריכה להיות EOA — אם המפתח הפרטי דולף, ניתן לשכתב את התוכנית.
מה כלול
- עיצוב מודל חשבונות ומבנה PDA
- כתיבת תוכנית ב-Rust עם Anchor
- בדיקות יחידה (Bankrun) ובדיקות אינטגרציה (localnet)
- סקירת אבטחה (ניתוח סטטי + ביקורת ידנית)
- פריסה עם הרשאת שדרוג multisig
- תיעוד של הוראות וחשבונות
לצוות שלנו יש 5+ שנות ניסיון בפיתוח בלוקצ'יין ומעל 10 פרויקטים שהושלמו על Solana. אם אתה מפתח פרוטוקול DeFi או שוק NFT על Solana — פנה אלינו, נעזור להימנע מטעויות נפוצות. צור קשר כדי להעריך את הפרויקט שלך ולקבל תוכנית פיתוח.







