šŸ¶
Solidity

Solidity Internal vs Private: What's the Difference?

By Ondřej DolanskĆ½ on 12/02/2024

This article explains the key differences between the `internal` and `private` visibility modifiers in Solidity and when to use each one.

Solidity Internal vs Private: What's the Difference?

Table of Contents

Introduction

In Solidity, managing access to your contract's functions and variables is essential for security and structure. You achieve this control using visibility specifiers: public, internal, external, and private. Each specifier dictates how and where a function or variable can be accessed, shaping the interaction points of your smart contract.

Step-by-Step Guide

In Solidity, controlling access to your contract's functions and variables is key. You do this with these visibility specifiers: public, internal, external, and private.

Think of public like an open door. Anyone, inside or outside the contract, can interact with it.

public uint256 myNumber; 

external is similar to public, but it can only be called from outside the contract.

external function doSomething() {} 

internal is like a family secret. Only the contract itself and its children (contracts that inherit from it) can access it.

internal string secretMessage;

private is the most restrictive. Only the contract itself can access it, not even its children.

private uint256 mySecretNumber;

If you don't specify visibility for a function, it defaults to internal.

Understanding these visibility specifiers is crucial for writing secure and well-structured smart contracts.

Code Example

This Solidity code demonstrates the different visibility levels for variables and functions within Solidity smart contracts. It showcases public, external, internal, and private visibility using a contract named VisibilityExample. The example includes a derived contract to illustrate how visibility affects inheritance and a separate contract to demonstrate calling external functions. The code provides clear examples of how each visibility level controls access to members from within and outside the contract and its derived contracts.

pragma solidity ^0.8.0;

contract VisibilityExample {

    // Public: Accessible from everywhere
    uint256 public myNumber = 10; 

    // External: Only callable from outside the contract
    external function changeNumberExternally(uint256 _newNumber) public {
        myNumber = _newNumber;
    }

    // Internal: Accessible within this contract and derived contracts
    internal string internalMessage = "This is a secret message!";

    function getInternalMessage() public view returns (string memory) {
        return internalMessage;
    }

    // Private: Only accessible within this contract
    private uint256 privateNumber = 5;

    function getPrivateNumberInternal() internal view returns (uint256) {
        return privateNumber;
    }
}

// Example of a derived contract
contract DerivedContract is VisibilityExample {

    function getInternalMessageFromDerived() public view returns (string memory) {
        // Can access internal members of the parent contract
        return internalMessage; 
    }

    // This would result in an error, as private members are not accessible
    // function getPrivateNumberFromDerived() public view returns (uint256) {
    //     return privateNumber; 
    // }
}

contract CallerContract {
    VisibilityExample visibilityExample = new VisibilityExample();

    function callExternalFunction(uint256 _newNumber) public {
        visibilityExample.changeNumberExternally(_newNumber);
    }
}

Explanation:

  • VisibilityExample contract:

    • myNumber: A public variable, accessible from anywhere.
    • changeNumberExternally: An external function, callable only from other contracts.
    • internalMessage: An internal variable, accessible within VisibilityExample and DerivedContract.
    • getInternalMessage: A public function, allowing external access to the internal internalMessage.
    • privateNumber: A private variable, accessible only within VisibilityExample.
    • getPrivateNumberInternal: An internal function, demonstrating access to the private variable within the contract.
  • DerivedContract:

    • Inherits from VisibilityExample.
    • getInternalMessageFromDerived: Demonstrates access to the internal internalMessage from the parent contract.
    • The commented-out function getPrivateNumberFromDerived shows that private members are inaccessible to derived contracts.
  • CallerContract:

    • Creates an instance of VisibilityExample.
    • callExternalFunction: Demonstrates calling the external function changeNumberExternally of VisibilityExample.

This example illustrates how visibility specifiers control access to contract members, ensuring data protection and proper contract interaction.

Additional Notes

General:

  • Security: Visibility plays a crucial role in Solidity security. Exposing functions or variables unnecessarily can lead to vulnerabilities. Always use the most restrictive visibility level possible.
  • Gas Optimization: external functions are slightly cheaper (gas-wise) than public functions when interacting with them externally. This is because external functions don't need to copy data to memory.
  • Default Visibility: While functions default to internal, it's good practice to explicitly declare the visibility for all functions and variables for better code readability and to avoid unintended consequences.

Specifics:

  • public:
    • Use for functions and variables that need to be accessed both internally and externally.
    • Be cautious when making variables public, as any changes can have implications for external contracts relying on them.
  • external:
    • Ideal for functions that will only ever be called from other contracts.
    • Slightly more gas-efficient than public for external calls.
  • internal:
    • Useful for functions and variables that are only needed within the contract and its derived contracts.
    • Promotes modularity and code organization.
  • private:
    • The most secure option for data that should never be accessible outside the contract, even by derived contracts.
    • Use for sensitive information or internal calculations that don't need to be exposed.

Inheritance:

  • Derived contracts inherit all functions and variables from their parent contracts, except for private members.
  • Even though a derived contract cannot directly access a private member of its parent, it can still indirectly interact with it through internal or public functions provided by the parent contract.

Best Practices:

  • Start Restrictive: Begin with the most restrictive visibility (private) and only loosen it (internal, external, public) if absolutely necessary.
  • Explicit Declarations: Always explicitly declare the visibility of functions and state variables, even if it's the default.
  • Documentation: Clearly document the visibility and intended usage of functions and variables in your contract's comments.

Summary

Specifier Access Level Description Example
public Everyone Accessible from inside and outside the contract. public uint256 myNumber;
external External only Accessible only from outside the contract. external function doSomething() {}
internal Contract & Children Accessible within the contract and its inheriting contracts. internal string secretMessage;
private Contract only Accessible only within the contract itself. private uint256 mySecretNumber;
(none) internal Default visibility if none is specified.

Key Takeaway: Choosing the right visibility specifier is crucial for controlling access to your contract's data and functions, ultimately impacting its security and structure.

Conclusion

Mastering visibility specifiers is fundamental for Solidity developers. By strategically using public, external, internal, and private, you control the access points to your contract's functions and variables. This control is essential for building secure, well-structured, and gas-efficient smart contracts. Remember to follow best practices like starting with the most restrictive visibility and explicitly declaring it for all functions and variables. Clear documentation further enhances code readability and understanding, contributing to a robust and secure smart contract ecosystem.

References

Were You Able to Follow the Instructions?

šŸ˜Love it!
šŸ˜ŠYes
šŸ˜Meh-gical
šŸ˜žNo
šŸ¤®Clickbait