Function visibility
Visibility буюу "харагдах байдал" нь function эсвэл state variable-г хэн дуудаж болох-ыг тодорхойлно. Буруу visibility сонгосноор хэн ч contract-ийн нууц логикийг дуудаж, мөнгийг хулгайлах боломж үүснэ — тиймээс аюулгүй байдлын хамгийн чухал тохируулгуудын нэг.
Дөрвөн visibility
| Visibility | Гадны дуудалт | Удамшсан contract | Өөрийн contract |
|---|---|---|---|
| public | ✅ | ✅ | ✅ |
| external | ✅ | ❌ | ❌ (зөвхөн this.func()) |
| internal | ❌ | ✅ | ✅ |
| private | ❌ | ❌ | ✅ |
public
public function-г хэн ч дуудаж болно — гадны данс, өөр contract, удамшсан contract.
contract Token {
uint256 public totalSupply = 1_000_000;
// хэн ч дуудаж болно
function getTotalSupply() public view returns (uint256) {
return totalSupply;
}
function transfer(address to, uint256 amount) public {
// шилжүүлгийн логик
}
}
public state variable-д Solidity автоматаар getter функц үүсгэдэг:
uint256 public totalSupply = 1_000_000;
// дээрх нь доорхтой адилхан:
// function totalSupply() public view returns (uint256) { return totalSupply; }
external
external function-г зөвхөн гаднаас дуудаж болно — гадны данс эсвэл өөр contract. Өөрийн contract-аас шууд дуудах боломжгүй.
contract Oracle {
// зөвхөн гадны contract дуудна гэж хүлээгдэж байна
function getPrice(string calldata symbol) external view returns (uint256) {
// үнийн мэдээлэл буцаана
return 0;
}
}
contract Consumer {
Oracle oracle;
function fetchPrice() public view returns (uint256) {
return oracle.getPrice("ETH"); // ✅ гаднаас дуудаж байна
}
}
external нь public-тай харьцуулахад gas хямд — параметрийг memory-д хуулахгүй, calldata-г шууд ашигладаг. Зөвхөн гаднаас дуудагдах функцэд external ашиглах нь gas хэмнэлтийн сайн дадал.
internal
internal function-г зөвхөн өөрийн contract ба удамшсан (child) contract дуудаж болно. Гаднаас дуудах боломжгүй.
contract MathBase {
// гаднаас дуудаж болохгүй, гэхдээ удамшсан contract дуудаж болно
function _multiply(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
}
contract AdvancedMath is MathBase {
function square(uint256 n) public pure returns (uint256) {
return _multiply(n, n); // ✅ internal функц дуудаж байна
}
}
Заншил: internal функцийн нэрийг _ угтвартай бичдэг — _transfer, _mint, _validateInput. Энэ нь дотоод функц гэдгийг харуулах кодын соёл.
private
private function-г зөвхөн тэр contract өөрөө л дуудаж болно. Удамшсан contract хүртэл дуудаж болохгүй.
contract Vault {
uint256 private secretKey = 12345;
address private owner;
// зөвхөн энэ contract дотроос дуудна
function _isOwner(address caller) private view returns (bool) {
return caller == owner;
}
function withdraw() public {
require(_isOwner(msg.sender), "Зөвхөн эзэмшигч");
// ...
}
}
contract EvilVault is Vault {
function steal() public {
// _isOwner(msg.sender); ← ❌ compile error — private функц хүрэхгүй
}
}
⚠️ Чухал анхааруулга: private storage-д хадгалагдсан утга нь блокчейнд ил харагдана — зөвхөн Solidity-ийн гаднаас дуудахыг хязгаарлана. Нууц дата хадгалахад private хамгаалалт болохгүй.
// ❌ БУРУУ ойлголт — нууц хадгалахад ашиглаж болохгүй
uint256 private password = 999999;
// Ethereum node-ийн storage slot 0-г унших замаар хэн ч харж болно!
State variable-ийн visibility
State variable-д public, internal, private тавьж болно (external тавьж болохгүй).
contract Example {
uint256 public openData = 1; // getter автоматаар үүснэ
uint256 internal sharedData = 2; // удамшсан contract уншиж болно
uint256 private hiddenData = 3; // зөвхөн энэ contract
}
Default visibility нь internal — тайлбаргүй бол internal гэж үзнэ. Гэхдээ үргэлж тодорхой бич — тайлбаргүй орхих нь алдаа гаргахад хүргэнэ.
Аюулгүй байдлын үүднээс
Хамгийн хязгаарлагдмал visibility-ийг сонго — шаардлагатай болсон үед л өргөсгө.
// ❌ БУРУУ — бүгдийг public болгох
contract Unsafe {
uint256 public adminPassword;
function _internalTransfer(address to, uint256 amount) public { // аюултай!
// хэн ч дуудаж болно
}
}
// ✅ ЗӨВ — хамгийн бага visibility
contract Safe {
uint256 private adminPassword;
function _internalTransfer(address to, uint256 amount) internal {
// зөвхөн contract дотроос дуудна
}
function transfer(address to, uint256 amount) external {
_internalTransfer(to, amount);
}
}
Бүтэн жишээ: visibility бүрийг харуулсан
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract AccessExample {
address public owner; // гаднаас уншиж болно
uint256 private _fee = 100; // зөвхөн энэ contract
uint256 internal _balance; // удамшсан contract ч уншиж болно
constructor() {
owner = msg.sender;
}
// гаднаас дуудна, gas хямд
function deposit(uint256 amount) external {
_validateAmount(amount);
_balance += amount;
}
// хэн ч дуудаж болно
function getBalance() public view returns (uint256) {
return _balance;
}
// зөвхөн дотооддоо ашиглана
function _validateAmount(uint256 amount) private pure {
require(amount > 0, "Дүн тэгээс их байх ёстой");
require(amount <= 1_000_000, "Дүн хэт их байна");
}
}
Дараагийн хичээлд:
view ба pure — state-г уншдаг ч үгүй, өөрчилдөг ч үгүй функцүүд, тэдгээрийн gas онцлогийг судална.