פיתוח מערכת RNG On-Chain לבלוקצ'יין
שימוש ב-block.timestamp, block.prevrandao, או ה-hash של הבלוק הקודם ליצירת מספרים אקראיים הוא מסוכן: כורים או מאמתים יכולים להשפיע על ערכים אלה. לפני כמה שנים, לוטו ידוע הפסיד 4 מיליון דולר עקב מניפולציה על hash של בלוק. מספרים אקראיים על בלוקצ'יין הם בעיה לא טריוויאלית הדורשת גישה מותאמת. אנו מפתחים מערכות RNG turnkey, מעריכים איומים, ומציעים פתרונות אופטימליים. הניסיון שלנו כולל יותר מ-50 פרויקטים מוצלחים בתחום זה.
למה אקראיות On-Chain היא קשה?
בלוקצ'יין הוא דטרמיניסטי. כל צומת חייב להגיע לאותה תוצאה על ידי ביצוע אותן פעולות. זה סותר מהותית את האקראיות: אם התוצאה צפויה, היא לא אקראית. כל מקור גלוי על הרשת לפני שהתוצאה מתחייבת יכול להיות מנוצל על ידי תוקף.
הטיה של מאמתים — מאמת Ethereum רואה את block.prevrandao (RANDAO reveal) לפני פרסום הבלוק. אם התוצאה לא חיובית, הם יכולים לדלג על ה-slot שלהם (ה-slot מדולג, התוצאה משתנה). עלות ההתקפה = אובדן תגמול slot (~0.01 ETH). אם ההימור בלוטו גדול מ-0.01 ETH, ההתקפה היא רציונלית.
Chainlink VRF: הסטנדרט לרוב המקרים
Chainlink VRF (פונקציה אקראית ניתנת לאימות) הוא הפתרון המנוסה ביותר עבור NFT mints, לוטו, ומכניקת משחקים. הוא עובד דרך רשת האורקל:
- החוזה מבקש מספר אקראי על ידי שליחת LINK.
- צומת Chainlink מייצר את המספר האקראי והוכחה קריפטוגרפית.
- ההוכחה מאומתת על הרשת לפני שהמספר בשימוש.
// VRF V2.5 (актуальная версия)
import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
contract Lottery is VRFConsumerBaseV2Plus {
uint256 public s_subscriptionId;
bytes32 public keyHash; // gas lane
uint32 public callbackGasLimit = 200_000;
uint16 public requestConfirmations = 3;
mapping(uint256 => address) public requestToPlayer;
function requestRandomWinner() external returns (uint256 requestId) {
requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: keyHash,
subId: s_subscriptionId,
requestConfirmations: requestConfirmations,
callbackGasLimit: callbackGasLimit,
numWords: 1,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
)
})
);
requestToPlayer[requestId] = msg.sender;
}
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
address player = requestToPlayer[requestId];
uint256 result = randomWords[0] % totalTickets;
_declareWinner(player, result);
}
}// VRF V2.5 (актуальная версия) import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; contract Lottery is VRFConsumerBaseV2Plus { uint256 public s_subscriptionId; bytes32 public keyHash; // gas lane uint32 public callbackGasLimit = 200_000; uint16 public requestConfirmations = 3; mapping(uint256 => address) public requestToPlayer; function requestRandomWinner() external returns (uint256 requestId) { requestId = s_vrfCoordinator.requestRandomWords( VRFV2PlusClient.RandomWordsRequest({ keyHash: keyHash, subId: s_subscriptionId, requestConfirmations: requestConfirmations, callbackGasLimit: callbackGasLimit, numWords: 1, extraArgs: VRFV2PlusClient._argsToBytes( VRFV2PlusClient.ExtraArgsV1({nativePayment: false}) ) }) ); requestToPlayer[requestId] = msg.sender; } function fulfillRandomWords( uint256 requestId, uint256[] calldata randomWords ) internal override { address player = requestToPlayer[requestId]; uint256 result = randomWords[0] % totalTickets; _declareWinner(player, result); } } — המתן ל-3 אישורי בלוק לפני יצירת המספר. זה מסבך התקפות reorg על הבקשה.
מגבלות VRF: זמן השהיה של 1-3 בלוקים (15-45 שניות ברשת הראשית), עלות LINK לכל בקשה (0.25-2 LINK תלוי ברשת), וניהול מנוי. עבור משחקים בתדירות גבוהה (כל מהלך במשחק דורש אקראיות), זה יקר מדי ואיטי.
Commit-Reveal: אקראיות ללא אורקל
למקרים ללא גישה ל-Chainlink או כדי למזער עלויות, השתמשו בסכמת commit-reveal:
חולשת commit-reveal: האדם האחרון שחושף רואה את התוצאה הסופית לפני הפרסום. הם עשויים לבחור לא לחשוף (griefing) או לחשוף רק אם התוצאה חיובית. הפחתה: קנס על אי-חשיפה (ערבות שהופקדה ב-commit שנשרפת אם ה-reveal מתפספס).
דוגמת יישום עם ערבויות
mapping(address => bytes32) public commits;
mapping(address => uint256) public bonds;
uint256 public bondAmount = 0.1 ether;
function commit(bytes32 commitment) external payable {
require(msg.value == bondAmount);
commits[msg.sender] = commitment;
bonds[msg.sender] = msg.value;
}
function reveal(uint256 secret) external {
require(keccak256(abi.encode(secret, msg.sender)) == commits[msg.sender]);
// process secret
payable(msg.sender).transfer(bonds[msg.sender]); // возврат залога
delete bonds[msg.sender];
}
function claimBond(address participant) external {
require(bonds[participant] > 0);
// проверка, что участник не раскрыл в срок
// перевести залог штрафующему
} RANDAO: אקראיות טבעית של Ethereum אחרי מעבר ל-PoS
אחרי ש-Ethereum עבר ל-Proof of Stake, requestConfirmations: 3 מספק את ה-RANDAO המאוגד מהמאמתים. זה טוב יותר מה-mapping(address => bytes32) public commits; mapping(address => uint256) public bonds; uint256 public bondAmount = 0.1 ether; function commit(bytes32 commitment) external payable { require(msg.value == bondAmount); commits[msg.sender] = commitment; bonds[msg.sender] = msg.value; } function reveal(uint256 secret) external { require(keccak256(abi.encode(secret, msg.sender)) == commits[msg.sender]); // process secret payable(msg.sender).transfer(bonds[msg.sender]); // возврат залога delete bonds[msg.sender]; } function claimBond(address participant) external { require(bonds[participant] > 0); // проверка, что участник не раскрыл в срок // перевести залог штрафующему } הישן, אבל יש לו את בעיית ההטיה של מאמתים שתוארה לעיל.
לשימושים לא קריטיים (קוסמטיים במשחקים, סדר תורים, לוטו קטן), block.prevrandao מספיק וחינמי:
uint256 random = uint256(keccak256(abi.encode( block.prevrandao, block.timestamp, msg.sender, nonce++ ))); הוספת block.difficulty ו-block.prevrandao מגדילה את האנטרופיה ומקשה על חיזוי למשתמש ספציפי, אם כי היא לא מבטלת את ההטיה של מאמתים.
איך לבחור את שיטת ה-RNG הנכונה?
| מקרה שימוש | הימור / ערך | המלצה |
|---|---|---|
| NFT mint (אקראיות ברשימת לבנים) | גבוה | Chainlink VRF |
| לוטו עם פרס גדול | גבוה | Chainlink VRF + requestConfirmations: 5+ |
| אקראיות במשחק (פריטים) | בינוני | Commit-reveal או Chainlink VRF |
| סדר תורים | נמוך | block.prevrandao |
| שיבוץ PvP | נמוך | block.prevrandao + nonce |
השוואת שיטות
| שיטה | אבטחה | מהירות | עלות | מורכבות |
|---|---|---|---|---|
| Chainlink VRF | גבוהה | 1-3 בלוקים | 0.25-2 LINK לכל בקשה | בינונית |
| Commit-reveal | בינונית (תלוי במכניקה) | 2+ סבבים | רק גז | גבוהה |
| RANDAO | נמוכה (הטיית מאמתים) | 0 בלוקים | חינם | נמוכה |
| היברידי (off-chain + on-chain) | גבוהה | 0 בלוקים | שילוב | גבוהה |
פתרונות היברידיים
לפרויקטים של GameFi הדורשים אקראיות מהירה עם תפוקה גבוהה, אנו משתמשים ב-VRF off-chain עם התחייבות on-chain:
- השרת מייצר seed דרך Chainlink VRF מראש.
- ה-hash של ה-seed מתפרסם על הרשת (התחייבות).
- לכל אירוע משחק, השתמשו ב-HMAC(seed, event_id) כאקראיות.
- אחרי הסשן, חשפו את ה-seed; משתמשים יכולים לאמת את כל התוצאות.
זה מספק תגובה מיידית לכל פעולה ואימות מלא לאחר מעשה. פתרון היברידי חוסך עד 90% בעלויות גז בהשוואה לבקשות VRF ישירות, ובשימוש בתדירות גבוהה, הוא זול פי 5-10.
מה אתם מקבלים
- ניתוח איומים ובחירת הסכמה האופטימלית.
- חוזה חכם משולב עם כיסוי בדיקות יחידה (200+ בדיקות).
- תיעוד פריסה ושימוש.
- תמיכה במהלך הפריסה והניטור.
- הדרכה לצוות (אופציונלי).
אנו מבטיחים שקיפות — כל הפתרונות ניתנים לאימות על הרשת. צרו קשר כדי להעריך את הפרויקט שלכם.
תהליך העבודה
ניתוח. קבעו את מודל האיומים: מי יכול לתקוף? מה הרווח המקסימלי ממניפולציה? איזה זמן השהיה מקובל? האם Chainlink זמין ברשת היעד?
פיתוח ובדיקות. VRFConsumer נבדק באמצעות uint256 random = uint256(keccak256(abi.encode( block.prevrandao, block.timestamp, msg.sender, nonce++ ))); מחבילת Chainlink, המאפשר סימולציית fulfillment בבדיקות יחידה ללא רשת האורקל האמיתית. Commit-reveal נבדק נגד התקפות griefing והתקפות של החושף האחרון.
פריסה. עבור Chainlink VRF, צרו מנוי, ממנו LINK, והוסיפו את הצרכן. הגדירו ניטור של יתרת המנוי.
הערכות זמן
שילוב Chainlink VRF בחוזה קיים: 1-2 ימים. מערכת RNG עם commit-reveal ואנטי-griefing: 1-2 ימים. VRF היברידי off-chain עם התחייבות ואימות on-chain: 3-5 ימים.
קבלו ייעוץ — אנו נעריך את הפרויקט שלכם ונציע פתרון turnkey אופטימלי.







