תארו לעצמכם שהפרוטוקול שלכם יוצר מאות חוזי פרוקסי באמצעות מפעל (factory)—עמדות הלוואה, כספות לכל משתמש, סשנים של משחקים. UUPS סטנדרטי או פרוקסי שקוף (Transparent Proxy) דורשים עדכון של כל פרוקסי בנפרד. עם 500 חוזים, זה 500 עסקאות ועשרות ETH רק על גז. אנו משתמשים ב-Beacon Proxy כדי לעדכן את כל הפרוקסים בעסקה אחת. במשך 5 שנים של עבודה עם פרויקטי בלוקצ'יין, גילינו שזו הגישה הסבירה היחידה לארכיטקטורות מפעל עם מופעים רבים. כפי שOpenZeppelin BeaconProxy מציין, התבנית אידיאלית לעדכונים המוניים, ומפחיתה עלויות גז בעד 99% כאשר מתקפלים למאות חוזים.
Beacon Proxy פותר את הבעיה הבסיסית של עדכונים המוניים: במקום N עסקאות—אחת, במקום שבועות של עדכונים—דקות. התבנית רלוונטית במיוחד לפרוטוקולי DeFi, פלטפורמות משחקים ושווקי NFT שבהם מספר חוזי המשתמש גדל באופן אקספוננציאלי.
איך Beacon Proxy עובד
הארכיטקטורה מורכבת משלושה רכיבים:
-
חוזה Beacon — מאחסן את כתובת היישום ופונקציית
upgradeTo(address)עם בקרת גישה. - חוזי פרוקסי — בכל קריאה, קוראים את הכתובת מה-beacon ומבצעים delegatecall.
- חוזה יישום — לוגיקה עסקית, משותפת לכל הפרוקסים.
// BeaconProxy.sol (упрощённо)
fallback() external payable {
address impl = IBeacon(beacon).implementation();
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}קריאה אחת // BeaconProxy.sol (упрощённо) fallback() external payable { address impl = IBeacon(beacon).implementation(); assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } מעדכנת מאות פרוקסים. בלעדיה—500+ עסקאות. בגישה קרה (קריאה ראשונה לאחר פריסה), Beacon Proxy צורך ~4200 גז; חם—~400 גז. זה רק מעט יותר יקר מ-UUPS, אבל לעדכונים המוניים, החיסכון מגיע ל-99.8%.
למה Beacon Proxy משתלם יותר מתבניות סטנדרטיות
השוואה: פרוקסי שקוף מוציא ~2100 גז על שכבת הפרוקסי, UUPS ~400, אבל כל עדכון הוא עסקה נפרדת. ב-N=100, חיסכון בגז העדכון הוא 99% בהשוואה ל-UUPS. Beacon Proxy יקר יותר לכל קריאה רגילה (~4200 גז קר), אבל עדכון המוני—עסקה אחת—נותן הפחתת עלות של פי 100.
| תבנית | תוספת גז | עדכון N פרוקסים | הכי מתאים ל |
|---|---|---|---|
| פרוקסי שקוף | ~2100 גז | N עסקאות | חוזים בודדים |
| UUPS | ~400 גז | N עסקאות | חוזים בודדים, רגישים לגז |
| Beacon Proxy | ~4200 גז (קר) | עסקה אחת | מפעל, מופעים מרובים |
| Diamond | תלוי ב-facets | N עסקאות | חוזים גדולים (>24KB) |
מתי לבחור ב-Beacon Proxy
Beacon Proxy הוא אופטימלי כאשר:
- יש לכם מפעל שיוצר 5+ מופעים (למשל, עמדות, כספות, סצנות משחק).
- נדרש עדכון סינכרוני של כל הפרוקסים.
- אתם מקבלים תוספת גז קטנה לכל קריאה (SLOAD קר) תמורת חיסכון עצום בעדכונים.
- אם יש פחות מ-5 מופעים או עדכונים נדירים—UUPS יעיל יותר.
טעויות נפוצות עם Beacon Proxy
| טעות | השלכה | פתרון |
|---|---|---|
| חוסר בדיקת יישום ב-beacon | ניתן להגדיר כתובת אפס, מה שמקפיא פרוקסים | הוסיפו beacon.upgradeTo(newImplementation) ב-require(_implementation != address(0)) |
| פריסת אחסון שגויה בעדכון | שחיתות מצב פרוקסי | השתמשו בOpenZeppelin Upgrades Plugins לבדיקת תאימות |
גישה לא מוגבלת ל-upgradeTo |
תוקף יכול להשתלט על כל הפרוקסים | השתמשו ב-Ownable או AccessControl |
| חוסר fallback לשגיאות אתחול | הפרוקסי עלול להישאר לא מאותחל | יישמו fallback שבודק אתחול |
איך לפרוס Beacon Proxy נכון
הפריסה כוללת שלושה שלבים:
- פרסו את היישום ובדקו את פריסת האחסון באמצעות OpenZeppelin Upgrades Plugins.
- פרסו UpgradeableBeacon עם כתובת היישום.
- פרסו מפעל שיוצר BeaconProxy באמצעות
upgradeTo.
דרישות טכניות ליישום
- חוזה היישום לא יכול לכלול constructor—רק initializer עם ה-modifier
new BeaconProxy(address(beacon), data). - פריסת האחסון חייבת להיות תואמת שדרוג: לא ניתן לשנות סדר משתנים, למחוק משבצות בשימוש, או להוסיף משתנים לפני קיימים.
- השתמשו בEIP-1967 לאחסון כתובת ה-beacon (משבצת
initializer).
יישום עם OpenZeppelin
OpenZeppelin מספקת חוזים מוכנים 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50 ו-BeaconProxy. בשילוב עם מפעל:
contract VaultFactory {
UpgradeableBeacon public immutable beacon;
constructor(address initialImplementation) {
beacon = new UpgradeableBeacon(initialImplementation);
beacon.transferOwnership(msg.sender);
}
function createVault(address owner) external returns (address) {
BeaconProxy proxy = new BeaconProxy(
address(beacon),
abi.encodeWithSignature("initialize(address)", owner)
);
return address(proxy);
}
function upgradeImplementation(address newImpl) external onlyOwner {
beacon.upgradeTo(newImpl);
}
}חוזה היישום חייב לעמוד בכללי תאימות פריסת אחסון—כמו UUPS. UpgradeableBeacon בודק זאת אוטומטית במהלך הפריסה.
מקרה בוחן: פרוטוקול DeFi עם 500 עמדות הלוואה
לאחרונה עבדנו על פרוטוקול DeFi שבו עמדת ההלוואה של כל משתמש הייתה חוזה פרוקסי נפרד. בתחילה, הם השתמשו ב-UUPS, מה שחייב 500 עסקאות עדכון לכל שינוי לוגיקה—בעלות של מעל 10 ETH בגז לכל עדכון. עברנו ל-Beacon Proxy, פרסנו beacon יחיד ועדכנו את כל הפרוקסים בעסקה אחת. עלות גז העדכון ירדה ל~0.02 ETH (לקריאת ה-beacon), חיסכון של מעל 99% בגז. כעת, כל עדכון עתידי הוא עסקה אחת, ללא קשר למספר העמדות.
מה כוללת העבודה שלנו
- עיצוב ארכיטקטוני של beacon + מפעל תוך התחשבות בשדרוגים עתידיים
- פיתוח חוזים חכמים עם בדיקות (Foundry/Hardhat) המכסות 100% מתרחישי השדרוג
- אימות פורמלי של פריסת אחסון באמצעות Slither
- פריסה ל-testnet/mainnet עם אימות ב-Etherscan
- תיעוד API ומדריך הפעלה
- חודש תמיכה חינם לאחר הפריסה
לוחות זמנים ואחריות
לצוות שלנו יש מעל 5 שנות ניסיון ב-Solidity ועשרות פרויקטים המשתמשים ב-Beacon Proxy. זמן סיום לפיתוח מלא: 3 עד 7 ימי עסקים בהתאם למורכבות הלוגיקה. אנו מבטיחים מנגנוני שדרוג ללא שגיאות—בדיקות מכסות 100% מתרחישי השדרוג. בשלוש השנים האחרונות, השלמנו מעל 20 פרויקטים עם עדכונים המוניים—אפס תקלות.
אם כבר יש לכם חוזי מפעל, נוכל להעריך את הפרויקט שלכם ביום אחד. קבלו ייעוץ לפרויקט שלכם—נעזור לבחור את התבנית האופטימלית. צרו קשר להערכה. הזמינו פיתוח וקבלו פתרון מוכח עם תיעוד מפורט.







