상세 컨텐츠

본문 제목

스마트 컨트랙트 구조와 Solidity 변수

Programming Language/Solidity

by Yongari 2023. 2. 7. 21:38

본문

 

 

컨트랙트의 구조

 

  • 상태변수(State Variables)
  • 구조체(Struct Types)
  • 열거형(Enum Types)
  • 함수(Functions)
  • 함수 제어자(Function Modifiers)
  • 이벤트(Events)
  • 에러(Errors)
  • 상속(inheritance)

 

솔리디티의 정의

 

솔리디티는 객체지향 프로그래밍 언어입니다.

솔리디티는 이더리움 플랫폼 위에서 스마트 컨트랙트를 작성할 때 사용합니다.

 

솔리디티의 특징

 

1. 정적 타입(static-typed)의 중괄호(curly-braces) 언어 : 자바스크립트와 달리 컴파일시에 변수 타입이 결정되는 언어다. 소스코드에 타입을 명확히해야한다.
2. 튜링완전언어 : 이더리움은 Gas를 통한 과금 메커니즘을 도입해서 블록체인에서 튜링완전언어를 가능하게 했고 반복문등의 작업이 가능하다.
3. 컴파일 언어 : 솔리디티로 작성한 스마트 컨트랙트는 EVM에서 동작하기 위해 바이트코드(Bytecode)로 컴파일된다. 

 

 

 

솔리디티 파일을 구성하는 문법들

 

SPDX License Identifier

저작권 문제를 해소하기 위해 SPDX 라이센스를 명시 -> 링크 

 

SPDX License List | Software Package Data Exchange (SPDX)

SPDX License List The SPDX License List is an integral part of the SPDX Specification. The SPDX License List itself is a list of commonly found licenses and exceptions used in free and open or collaborative software, data, hardware, or documentation. The S

spdx.org

// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: GPL-3.0

 

 

Pragma

pragma 키워드는 특정 컴파일러의 버전을 표기할 때 사용한다.

다음과 같이 코드 최상단에 작성한다.

 

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.14;  // 0.8.14 버전을 사용합니다

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.14;  // 0.8.14 이상의 버전을 사용합니다

//다음과 같은 방법으로 많이 사용하는 것 같다.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0; // 0.4.0 이상 0.9.0 미만의 버전을 사용합니다

 

 

Contract

솔리디티에서 Contract는 데이터와 코드의 모음이다 

 contract CallerContract is Ownable {
      // 1. Declare ethPrice
      // 변수 선언
      EthPriceOracleInterface private oracleInstance;
      address private oracleAddress;
      mapping(uint256=>bool) myRequests;
      event newOracleAddressEvent(address oracleAddress);
      event ReceivedNewRequestIdEvent(uint256 id);
      // 2. Declare PriceUpdatedEvent
      //함수 선언
      function setOracleInstanceAddress (address _oracleInstanceAddress) public onlyOwner {
        oracleAddress = _oracleInstanceAddress;
        oracleInstance = EthPriceOracleInterface(oracleAddress);
        emit newOracleAddressEvent(oracleAddress);
      }
      function updateEthPrice() public {
        uint256 id = oracleInstance.getLatestEthPrice();
        myRequests[id] = true;
        emit ReceivedNewRequestIdEvent(id);
      }
      function callback(uint256 _ethPrice, uint256 _id) public {
        // 3. Continue here
      }
  }

 

Import

javascript와 import 하는 방식은 비슷하며 다음과 같이 파일 경로를 코드 최상단에 보여주면서 import 하면된다.

  import "./EthPriceOracleInterface.sol";
  import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

 

주석

 

단일라인은 // 

여러 주석처리는 /* */

 

      // 단일 주석 처리
      
      
      /*
      여러 줄 주석 처리
      function updateEthPrice() public {
        uint256 id = oracleInstance.getLatestEthPrice();
        myRequests[id] = true;
        emit ReceivedNewRequestIdEvent(id);
      }
      
      */

 

 

변수

 

데이터 저장 위치

 

일반 프로그래밍 언어 : 스택, 힙, 메모리에 저장됨

솔리디티 언어 : 메모리, 스토리지, 콜데이터에 저장됨 

 

데이터 저장위치 각각의 특징

 

스토리지 (Storage) : 영속적으로 읽기/쓰기 가능, 키(key)-값(value) 쌍으로 이루어진 매핑 구조, 각 키와 값은 32바이트 크기를 가짐, 함수 외부에 정의된 변수(상태변수), 함수와 같은 스마트 컨트랙트의 주요정보가 영속히 저장되서 가스비용이 비쌈

 

메모리(Memory) : 휘발적으로 읽기/쓰기 가능, 메모리에는 함수나 반복이 실행될 때 매개변수나 반환값, 함수 내부변수 같은 데이터가 잠시 저장되었다가 실행이 완료되면 삭제

콜데이터(Calldata) : 휘발적이지만 읽기만 가능한 공간 / 메모리와 달리 데이터 저장은 불가능함 / 주로 external이 적용된 함수의 매개변수에 콜데이터 공간을 사용함

 

 

기본 데이터 위치 

함수, 반복문 매개변수(반환 값 포함) : 메모리 

모든 지역 변수 : 스토리지

 

강제 데이터 위치

외부(external)함수의 매개 변수 (반환 값 미포함) : calldata

상태 변수 : 스토리지 

 

다음 코드를 예시로 보면 된다.

 

pragma solidity ^0.8.7;

contract Example {


    //storage에 변수를 저장하는 예시
    //함수 외부에 선언된 상태변수라 storage에 저장됨
    //public을 사용해서 외부에 선언된 것으로  봐야함
    uint public a = 3; 

    struct Item{
        uint price;
        uint units;
    }

    Item[] public items;
    function myFunc1() external view returns(uint, uint){
        uint b = 4; 
        return (a,b);
    }

    function myFunc2(uint _itemIdx) public returns (uint){
        Item storage item = items[_itemIdx];
        return item.units; 
    }

    //memory에 변수를 저장하는 예시
    //함수 등 매개변수가 있기 때문에 메모리에 저장 
    function myFunc3(string memory str) public pure returns(uint, string memory, bytes memory){
        uint num = 99;
        bytes memory byt = hex"01";
        return (num, str, byt);

    }

    // calldata에 변수를 저장하는 예시
    // external을 사용하기 때문에 calldata에 저장됨
    function myFunc4(string calldata str) external pure returns(string memory){
        return str; 
    }
}

 

 

변수의 종류 

 

 

상태 변수(state variable) :


함수 외부에 선언되는 변수

스토리지에 저장되서 영속적인 속성을 가짐

 

상태변수 접근 수준

1. internal (default) : 

  • 외부 접근 불가
  • 해당 변수가 선언된 컨트랙트를 상속받거나 선언된 컨트랙트 내부에서 엑세스 가능 
    따로 접근수준을 명시하지 않으면 default로 설정됨

 

2. public

  • 직접 스토리지에서 변수값을 가져옴(internal과 공통점)
  • 컴파일러가 읽기위해 getter 함수를 생성하고 외부컨트랙트나 클라이언트에서 getter함수를 통해 모든 사람들이 해당 변수를 읽을 수 있음 (internal과 차이점)
  • getter 함수는 view 함수라서 가스비용을 지불 하지 않음 

 

3. private :

  • 해당 변수가 선언된 컨트랙트 내에서만 엑세스 가능

 

참고링크 :

https://programtheblockchain.com/posts/2018/01/02/making-smart-contracts-with-public-variables/ 

 

Making Smart Contracts with Public Variables

State variables in Solidity, like functions, have a notion of visibility. By default, they are not marked as “public,” but this is a somewhat confusing concept in the context of a public blockchain, where all data can be read by anyone. In this post, I

programtheblockchain.com

 

https://docs.soliditylang.org/en/develop/contracts.html#visibility-and-getters

 

Contracts — Solidity 0.8.19 documentation

Contracts Contracts in Solidity are similar to classes in object-oriented languages. They contain persistent data in state variables, and functions that can modify these variables. Calling a function on a different contract (instance) will perform an EVM f

docs.soliditylang.org

 

 

상수 사용

 

constant : 컴파일 시에 고정되야함

immutable: 선언한 뒤 생성자에서도 할당 할 수 있음

 

다음 예제코드를 통해 사용방법을 알 수 있습니다.

 

pragma solidity ^0.8.7; 

uint constant bigNum = 32**22 + 8;

contract Example {

    //constant는 선언 및 초기화를 해주어야 함 
    string constant str = "hello";
    bytes32 constant hash = keccak256("hello");

    //immutable은 선언해두었다. constructor에서 값을 할당할 수 있음
    address immutable owner = msg.sender ;
    uint immutable decimals;
    uint immutable maxBalance; 

    constructor(uint decimals_, address ref){
        decimals = decimals_;
        maxBalance = ref.balance; 

    }

    function isBalanceTooHigh(address other) public view returns (bool){
        return other.balance > maxBalance; 
    }
    
}

 

 

지역 변수(local variable):

 

지역변수는 함수가 실행될 때까지만 존재하는 변수

지역변수는 동적크기를 갖는 참조형 변수가 아니면 기본적으로 메모리에 저장

동적인 크기의 구조체나 배열 형식의 참조형 변수는 기본적으로 스토리지에 저장

 

다음 코드예제를 통해 사용방법을 참고하세요

 

pragma solidity ^0.8.14;

contract SimpleStorage{

    //동적 크기의 배열 상태변수 선언
    uint256[] stateArray;

    function doStuff() public {
        //솔리디티는 아래와 같은 지역변수는 자동으로 storage reference로 생성합니다.
        //이것은 다음과 같이 명시한 것과 같습니다. uint256[] storage localReference = stateArray
        uint256[] localReference = stateArray;

        uint256[] memory memArray = new uint256[](5);
    }
    function simpleFunction() public pure returns(uint){
        uint a; //지역변수 선언 
        uint b = 1; //지역변수 선언 및 초기화
        a = 1;
        uint result = a + b;
        return result ;
    }

    
}

 

 

전역변수(global variable):

 

블록체인의 여러 정보를 나타내는 변수로 전역 이름 공간(global name space)에 존재

글로벌한 블록체인에 있는 특수변수임 

 

 

전역변수데이터 형식설명

 

blockhash(uint blockNumber) bytes32 주어진 블록의 해시를 반한. bytes32 형식.
block.basefee uint 현재 블록의 기본 수수료. uint 형식.
block.chainid uint 현재 블록의 체인 ID. uint 형식.
block.coinbase address payable 현재 블록의 채굴자 주소. address 형식.
block.difficulty uint 현재 블록의 난이도. utint 형식.
block.gaslimit uint 현재 블록의 가스 한도. uint 형식.
block.number uint 현재 블록의 번호. uint 형식.
block.timestamp uint 현재 블록의 유닉스 타임스탬프. uint 형식.
gasleft() uint256 남아있는 가스의 양을 반환. uint256 형식.
msg.data bytes calldata 전체 콜데이터 본문. bytes 형식.
msg.sender address 현재 호출을 수행하고 있는 메시지 발신자. address 형식.
msg.sig bytes4 호출 데이터의 첫 4바이트(함수 식별자). bytes4 형식.
msg.value uint 메시지와 함께 보낸 이더(Wei) 금액. uint 형식.
tx.gasprice uint 트랜잭션 가스 비용. uint 형식.
tx.origin address 트랜잭션 발신자. address 형식.
 

관련글 더보기