본문 바로가기
솔리디티

솔리디티 이해하기 기초-2

by gun_poo 2022. 2. 4.

컨트랙트의 소유권

pragma solidity ^0.8.10;

contract myContract {
  function sendEther(address _address, uint _amount) external {
    send(_address, _amount);
  }
}

sendEther는 external 로 선언되어 누구나 호출할 수 있는 상태, 컨트랙트의 소유자만 특정 함수에 접근할 수 있도록 하기 위해 Ownable 이라는 라이브러리를 활용한다.

[Ownable.sol 라이브러리 코드 전문]
코드 안에 주석으로 해석 처리한다.

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
 
 
contract Ownable {
  address public owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
   ///////////////////////////////////////////////////////////////////////////////
   
  function Ownable() public {
    owner = msg.sender;
  }
Ownable 함수는 생성자로써 컨트랙트가 생성될 때 owner 변수를 현재 호출자의 주소로 초기화한다

  /**
   * @dev Throws if called by any account other than the owner.
   */
   
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

onlyOwner 함수는 함수 제어자로써, 제어자가 작용된 함수가 실행되기 전에 제어자를 호출한다.

//////////////////////////////////////////////////////////////////////////////////
  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
   
   
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }

}

먼저 Ownable.sol을 불러온 뒤, 컨트랙트가 Ownable을 상속받게 하자
이제 onlyOwner 라는 함수 제어자를 활용하면

pragma solidity ^0.8.10;
import "./ownable.sol"

contract myContract is Ownable {
  function sendEther(address _address, uint _amount) external onlyOwner{
    send(_address, _amount);
  }
}

이더를 전송하는 sendEther 함수는 호출자가 소유권자와 동일한지 매번 자동으로 검사하게 되어, 컨트랙트의 소유권자만이 안전하게 이더를 전송할 수 있게 된다.

가스 최적화

가스 - 이더리움 DApp이 사용하는 연료

솔리디티에서는 DApp의 함수를 실행할 때마다 가스라고 불리는 화폐를 지불한다.
사용자는 이더를 이용해서 가스를 사기 때문에 결국 이더를 소모한다.

함수를 실행하는 데에 얼마나 많은 가스가 필요한지는 함수가 얼마나 복잡한지에 따라 다르다.

각각의 연산은 소모되는 가스 비용(gas cost)이 있고 그 연산을 수행하는 데에 소모되는 컴퓨팅 자원의 양이 비용을 결정한다.

storage에 값을 쓰는 것은 두 개의 정수를 더하는 것보다 비용이 높으며 함수의 전체 가스 비용은 함수를 구성하는 개별 연산들의 가스 비용을 모두 합친 것과 같다

이더리움에서 함수를 실행하는 것은 사용자들에게 실제 돈을 쓰게 하기 때문에 다른 프로그래밍 언어들에 비해 최적화가 더 중요하다.

가스는 왜 필요하나

어떤 함수를 실행하면 네트워크 상의 모든 노드가 함수의 출력값을 검증하기 위해 그 함수를 실행한다.

이더 개발자들은 공개 네트워크인 이더리움 사용자인 누군가가 자원 소모값이 큰 연산을 통해 네트워크 자원을 모두 사용하지 못하게 하기 위해 연산 처리에 비용이 필요하게 만들었다. 사용자들이 저장 공간 뿐만 아니라 연산 사용 시간에 따라서도 비용을 지불하도록 설계되었다.

가스 소모 최적화 - 구조체 최적화

최적화를 적용할 수 있는 요소중 하나가 바로 자료형이다
일반적인 변수를 사용할 때는 작은 자료형으로 선언하는 것이 최적화에 영향을 미치지 않는다
대신, 구조체를 사용할 때는 작은 자료형으로 선언하는 것이 최적화에 도움을 준다

storage 활용 최소화하기

storage와 memory를 다루는 파트에서 storage는 블록체인에 영원히 기록되는 정보임을 알게되었다.
배열을 함수 내부에서만 사용할 예정이라면 다음과 같이 memory를 활용해 배열을 선언하는 것이 보다 효율적이다.

function getArray() external view returns(uint[]) {
    // new 키워드를 활용해 배열을 생성할 때는 반드시 길이 인자를 뒤에 붙여 생성해야 한다.
    uint[] memory result = new uint[](100);
    return result;
}

external view(pure) 함수 활용

외부에서 호출되는 view와 pure 함수만큼은 무료로 실행 가능하다.
단순히 외부로부터 컨트랙트의 데이터를 읽기만 하는 함수가 있다면 반드시 external view 선언을 통해 수수료를 절감해야 한다

출처, 참조
charming2

 

댓글