Solidity / Function visibility

Function visibility

Visibility буюу "харагдах байдал" нь function эсвэл state variable-г хэн дуудаж болох-ыг тодорхойлно. Буруу visibility сонгосноор хэн ч contract-ийн нууц логикийг дуудаж, мөнгийг хулгайлах боломж үүснэ — тиймээс аюулгүй байдлын хамгийн чухал тохируулгуудын нэг.

Дөрвөн visibility

| Visibility | Гадны дуудалт | Удамшсан contract | Өөрийн contract | |---|---|---|---| | public | ✅ | ✅ | ✅ | | external | ✅ | ❌ | ❌ (зөвхөн this.func()) | | internal | ❌ | ✅ | ✅ | | private | ❌ | ❌ | ✅ |

public

public function-г хэн ч дуудаж болно — гадны данс, өөр contract, удамшсан contract.

solidity
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 функц үүсгэдэг:

solidity
uint256 public totalSupply = 1_000_000;
// дээрх нь доорхтой адилхан:
// function totalSupply() public view returns (uint256) { return totalSupply; }

external

external function-г зөвхөн гаднаас дуудаж болно — гадны данс эсвэл өөр contract. Өөрийн contract-аас шууд дуудах боломжгүй.

solidity
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 дуудаж болно. Гаднаас дуудах боломжгүй.

solidity
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 хүртэл дуудаж болохгүй.

solidity
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 хамгаалалт болохгүй.

solidity
// ❌ БУРУУ ойлголт — нууц хадгалахад ашиглаж болохгүй
uint256 private password = 999999;
// Ethereum node-ийн storage slot 0-г унших замаар хэн ч харж болно!

State variable-ийн visibility

State variable-д public, internal, private тавьж болно (external тавьж болохгүй).

solidity
contract Example {
    uint256 public   openData   = 1;   // getter автоматаар үүснэ
    uint256 internal sharedData = 2;   // удамшсан contract уншиж болно
    uint256 private  hiddenData = 3;   // зөвхөн энэ contract
}

Default visibility нь internal — тайлбаргүй бол internal гэж үзнэ. Гэхдээ үргэлж тодорхой бич — тайлбаргүй орхих нь алдаа гаргахад хүргэнэ.

Аюулгүй байдлын үүднээс

Хамгийн хязгаарлагдмал visibility-ийг сонго — шаардлагатай болсон үед л өргөсгө.

solidity
// ❌ БУРУУ — бүгдийг 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 бүрийг харуулсан

solidity
// 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 онцлогийг судална.