Solidity 기본 문법

매정·2022년 5월 27일
3
post-thumbnail

😀 솔리디티 기본 문법 정리
KMOOC 내의 포항공대 '스마트 계약 및 응용' 강의 중 솔리디티 기본 문법 내용을 정리해보았다.
일부 내용은 urclass에서 참조했다.

솔리디티 언어

  • 절차적 프로그래밍 언어 (함수형 언어와 대비됨), (C++, 자바스크립트, 자바)
  • 정적 타입 언어 (like JAVA) : 컴파일 시에 타입이 결정, 오류가 있다면 컴파일 에러가 발생함.
  • 객체 지향 언어
  • 확장자로 sol을 사용.

SPDX License Identifier

스마트 컨트랙트에 대한 신뢰를 높이고, 저작권 문제를 해소하기 위해 코드 최상단에 SPDX 라이센스를 주석으로 명시. SPDX 라이센스 리스트
// SPDX-License-Identifier: MIT


Pragma

컴파일러의 특정 기능을 활성화 하는 데 사용됨.

  1. Version Pragma: 컴파일러 버전 설정 시 사용
    caret(^): 해당 메이저 버전의 최신 버전까지 지원한다.

    2. Experimental Pragma: 컴파일러나 프로그래밍 언어의 특정 기능 사용 시

import

다른 솔리디티 파일에 있는 코드를 사용할 수 있게 해줌 → 코드의 모듈화가 가능해짐


Contract

  • 객체 지향 언어에서의 class와 유사
  • Contract 내부 variable에 데이터를 보관하며 이를 제어하기 위한 function들을 가짐.
  • 하나의 솔리디티 파일에 여러 contract가 선언될 수 있음.
  • Contract 구성: 상태 변수(state variable), 함수(function), 이벤트(event), 함수 제어자(function modifier) 등

상태 변수(State Variables)

Contract 내부에서 선언된 변수 중 function 외부에서 선언된 변수

contract storage에 저장됨. → 모든 function이 접근 가능, function이 변경한 값은 계속해서 저장됨.

Storage: 블록체인에 기록되어 영구적으로 값이 유지되는 데이터 영역
Memory: 프로그램이 동작되는 동안에만 값을 기억하고, 종료되면 값을 잃는 데이터 영역. 대체로 임시값들이 저장됨. (예: function 내에서만 쓰는 파라미터 등)


값형 데이터 타입 (Value types)

  • Boolean
    true(default)/false

  • 정수(int, uint)
    signed integers: 부호 있음
    unsigned integer: 부호 없음
    8bit ~ 256bit까지 지원 (예: int8: -128 ~ 127, uint16: ~65,535)

  • Byte
    데이터를 바이너리 형태로 저장하기 위해 byte타입을 지원함.
    bytes1 ~ bytes32까지 정해져 있음.
    크기가 정해져 있기 때문에 fixed-sized byte array라고도 불림.
    정해진 바이트 크기와 다르면 에러가 남.

    cf.) bytes 타입: dynamically sized byte array - 참조형(reference) 타입임

  • 주소(Address)
    20byte 크기의 이더리움 어드레스
    balance property를 갖고 있어 이더 잔액을 확인할 수 있음.
    이더를 옮기는 transfer, send 메소드 지원(address.transfer(amount), address.send(amount))

  • 열거형 (Enumerations)
    내부적으로는 정수 값으로 구현됨.


참조형 데이터 타입 (Reference types)

Reference 타입은 EVM 내에서 Storage, Memory 중에서 어디에도 저장될 수 있기 때문에, 어디에 저장할 것인지 명시해야 한다. (data location)
데이터를 저장하는 영역에 연속되어 저장되어 있는 값의 첫 번째 메모리의 주소를 값으로 가지는 변수 타입.

  • 배열(Arrays)
    동일한 타입의 여러 항목을 저장할 때 사용
    Fixed Array: 배열 선언 시 크기가 결정됨
    Dynamic Array: 실행 중에 크기가 결정됨
    2차원 배열 시 다른 언어의 순서와 반대임 (예: array[1][2] → array[2][1])

  • 문자열(String)
    Array의 특별한 형태, bytes array에 기반한 string 타입
    Array와 달리 index, push, length, concat 등을 지원하지 않기 때문에 bytes array로 변환해야 함.

  • 구조체(Struct)
    서로 다른 타입을 하나로 묶어서 사용.

  • 매핑(Mappings)
    key-value pair를 저장할 때 사용되는 데이터 타입.

    대부분의 데이터 타입을 key 타입으로 쓸 수 있지만, contract, mapping, struct 타입처럼 복잡한 타입은 key 타입이 될 수 없음. (value로는 사용 가능)

    storage 영역에만 저장됨.
    함수의 parameter나 return type으로 사용될 수 없음.
    key 값 자체가 mapping에 저장되지 않기 때문에, key의 hash 값을 이용해 value에 접근함.


글로벌 변수

솔리디티에서 현재 이더리움 블록체인 정보(현재 블록정보, 트랜잭션 정보 등)를 제공하는 변수

block

블록 관련 정보를 제공함.

  • block.coinbase: 현재 블록을 채굴한 account의 주소를 알려줌
  • block.difficulty: 현재 블록 작업 증명의 어려운 정도
  • block.gaslimit: 현재 블록이 사용 가능한 최대 gas값
  • block.number: 블록 넘버
  • block.timestamp: 채굴 시 기록된 시간 정보

msg

컨트랙트는 외부 컨트랙트에서 호출하거나 다른 컨트랙트에서 message call을 하면 실행하는데, 이때 컨트랙트에게 전달된 메시지 정보를 msg object를 통해서 읽을 수 있음.

  • msg.sender: contract를 호출한 account의 주소가 들어있음.
  • msg.value: 메시지를 통해 전달된 이더가 wei unit으로 담겨있음.
  • msg.data: contract로 넘겨진 data가 담겨있음.
  • msg.sig: data의 첫 4바이트 → 어떤 메소드가 불리는지 알 수 있음.

tx

트랜잭션 관련 정보를 제공함

  • tx.price: 현재 트랜잭션의 gas 비용을 알려줌
  • tx.origin: 트랜잭션의 시작 외부소유 어카운트의 address를 알려줌

Address

address 관련 정보를 제공함

  • address.balance : 잔고를 보여줌
  • address.transfer(amount): 이더를 해당 어드레스로 보냄
  • address.send(amount): 이더를 해당 어드레스로 보냄
  • address.call(payload)
  • address.callcode(payload)
  • address.delegatecall()

상태 변수 접근 수준

  • internal(default): 선언된 contract와, 해당 contract 로 부터 상속받은 contract에서만 사용할 수 있음.
  • private: 선언된 contract에서만 사용 (그럼에도 이더리움 public 블록체인이기 때문에 데이터는 공개되어 있음.)
  • public: 외부에서도 접근할 수 있음. 특별히 solidity 컴파일러가 getter 메소드를 생성해 줌.
  • constant: 값에 변화가 없음. 처음에 값을 정하지 않거나, 변경을 하려고 하면 에러가 나게 됨.

함수

함수의 구조

  • 함수 이름 (Name)

이름으로 함수를 호출할 수 있음. 이름이 없는 함수는 fallback or default function이라고 함.

  • 매개변수 (Parameter)

함수에 넘겨질 argument들의 이름과 타입을 선언함.

  • 함수 접근 수준 (Visibility)

    • Public: 다른 contract나 외부 계정에서 불릴 수 있음
    • Private: 현재 contract에서만 불릴 수 있음
    • Internal: 자신 외에도 자신으로부터 상속받은 contract로 부터 불릴 수 있음.
    • External: public과 비슷, contract 내로부터 불릴 경우 ‘this’라는 키워드를 붙여야 함.
  • Qualifier ( view, pure, payable )

    함수가 contract의 내부 상태(state variable)을 변경할 수 있는 능력 선언, 다른 언어들에서 찾아보기 힘든 개념임.

    • view: storage 내의 variable 읽기O, 변경X
    • pure: storage 내의 variable 읽기X, 변경X
    • payable: 결제를 처리할 수 있다는 선언. 만약 선언되지 않은 함수에 이더를 보내면 거부됨.
  • returns

반환하는 타입 선언

  • 생성자 함수(constructor)

  • selfdestruct


함수 변경자(Modifier)

  • 비슷한 역할을 하는 코드를 모아서 만든 특별한 형태의 함수
  • 함수처럼 parameter를 받을 수 있고, 바디에 특정 조건을 만족하는지를 확인하는 코드가 들어감.
  • underscore(_;) 로 표현된 placeholder에 modifier가 적용된 함수의 코드가 위치함.
  • modifier 적용을 위해 적용을 원하는 function의 선언에 modifier의 이름을 추가하면 됨.


에러 핸들링

  • Require: 주어진 조건을 검사해서 이를 만족시키지 못하면 exception을 발생시켜 이전 상태로 되돌림. gas 반환 O
  • Revert: Require와 유사, control flow가 복잡할 때 (예: 중첩 if) 편리
  • Assert: 어떤 값을 변경하고 나서 그 값이 조건을 만족하는지, 절대로 발생하면 안되는 상황인지를 검사. gas 반환 X

주로 require, revert는 함수 앞쪽에서 pre-condition을 확인하는데 사용, assert는 뒷부분에서 post-conditon을 확인하는데 사용


상속

상속을 통해 두 컨트랙트 간에 parent-child relation을 만들어 줌. parent 컨트랙트에서 선언한 함수와 상태 변수들을 child 컨트랙트에서도 사용할 수 있게 해줌. “is” 키워드를 이용해 상속. 다중 상속(multiple inheritance)도 가능. 이때 parent contract 나열 순서가 중요. 가장 뒤에 명명된 컨트랙트가 더 가까운 parent임.


생성자 함수(constructor)

생성자 함수 선언 시, 컨트랙트가 생성될 때 생성자 함수가 실행되며 컨트랙트 상태를 초기화 함.

selfdestruct: 현재 컨트랙트를 소멸시킴. 남은 이더를 주어진 address로 보냄.

selfdestruct(컨트랙트 생성자의 주소);


이벤트

  • contract가 작업을 수행하는 동안 로그를 남길 수 있게 해주는 기능.
  • contract의 메소드가 불렸는지, contract의 내부의 값이 어떻게 변했는지 등을 알 수 있어 디버깅이 수월함.
  • 블록체인 밖의 시스템과의 연동을 가능하게 함.
  • 트랜잭션이 끝난 후 → 트랜잭션의 결과가 담긴 ‘Transaction Receipt’가 만들어짐
  • Transaction 이후의 상태
  • 사용된 총 gas
  • Transaction 동안 생성된 log → 블록체인에 기록됨. contract의 상태가 변경되었다는 것을 외부에 알려줄 수도 있음.
    바로 이 log를 생성하는데 event가 사용됨.
contract coinTransfer {

	// event 선언: 이벤트명(파라미터유형1 파라미터1, 파라미터유형2 파라미터2, ...);
	// variable의 이름을 명시할 필요는 없음. (타입만 나열해도 ok)
	// indexed라고 명시해서 선언 -> hash table에 저장되어 나중에 event를 쉽게 찾을 수 있음
	event Transfer(address from, address to, uint256 value);

	function transfer(address to, address amount) {

		// event가 'emit'을 통해 불려짐, 값들이 블록체인에 저장됨.
		// emit 이벤트명(인자1, 인자2 ...)
		emit Transfer(msg.sender, to, amount);
	}
}


Library

  • 대표적인 예: Openzeppelin
  • contract와 유사한 방식으로 선언됨. (contract 키워드 대신 library 키워드 사용)
  • contract와 다른점: state variable X, 상속 관계 X, fallback 함수 X, payable 함수 X
  • 파라미터를 받을 수 있음.
  • Library 호출 방법: 라이브러리 이름.메소드이름(), using 라이브러리 이름 for 데이터타입
profile
Prospective Entrepreneur

0개의 댓글