본문으로 건너뛰기
Change page

스마트 컨트랙트의 구조

스마트 컨트랙트는 이더리움의 특정 주소에서 실행되는 프로그램입니다. 스마트 컨트랙트는 트랜잭션을 수신할 때 실행할 수 있는 데이터와 함수로 구성됩니다. 다음은 스마트 컨트랙트를 구성하는 요소에 대한 개요입니다.

전제 조건

먼저 스마트 컨트랙트에 대해 읽어보시기 바랍니다. 이 문서는 JavaScript나 Python 같은 프로그래밍 언어에 이미 익숙하다고 가정합니다.

데이터

모든 컨트랙트 데이터는 storage 또는 memory 중 하나의 위치에 할당되어야 합니다. 스마트 컨트랙트에서 스토리지를 수정하는 것은 비용이 많이 들기 때문에 데이터가 어디에 저장되어야 할지 신중하게 고려해야 합니다.

스토리지 (Storage)

영구적인 데이터는 스토리지라고 부르며 상태 변수로 표현됩니다. 이 값들은 블록체인에 영구적으로 저장됩니다. 컴파일 시 컨트랙트가 블록체인에서 얼마나 많은 스토리지를 필요로 하는지 추적할 수 있도록 타입을 선언해야 합니다.

// Solidity 예제
contract SimpleStorage {
    uint storedData; // 상태 변수
    // ...
}
# Vyper 예제
storedData: int128

객체 지향 언어로 프로그래밍해 본 적이 있다면 대부분의 타입에 익숙할 것입니다. 하지만 이더리움 개발이 처음이라면 address 타입은 생소할 것입니다.

address 타입은 20바이트 또는 160비트에 해당하는 이더리움 주소를 담을 수 있습니다. 이 값은 앞에 0x가 붙은 16진수 표기법으로 반환됩니다.

다른 타입들은 다음과 같습니다:

  • 불리언 (boolean)
  • 정수 (integer)
  • 고정 소수점 숫자 (fixed point numbers)
  • 고정 크기 바이트 배열 (fixed-size byte arrays)
  • 동적 크기 바이트 배열 (dynamically sized byte arrays)
  • 유리수 및 정수 리터럴 (rational and integer literals)
  • 문자열 리터럴 (string literals)
  • 16진수 리터럴 (hexadecimal literals)
  • 열거형 (enums)

더 자세한 설명은 문서를 참조하세요:

메모리 (Memory)

컨트랙트 함수가 실행되는 동안에만 저장되는 값을 메모리 변수라고 합니다. 이 변수들은 블록체인에 영구적으로 저장되지 않기 때문에 사용하는 데 훨씬 저렴합니다.

EVM이 데이터를 저장하는 방법(스토리지, 메모리, 스택)에 대해 더 알아보려면 Solidity 문서 (새 탭에서 열림)를 참조하세요.

환경 변수

컨트랙트에 정의하는 변수 외에도 몇 가지 특별한 전역 변수가 있습니다. 이 변수들은 주로 블록체인이나 현재 트랜잭션에 대한 정보를 제공하는 데 사용됩니다.

예시:

속성상태 변수설명
block.timestampuint256현재 블록의 에포크 타임스탬프
msg.senderaddress메시지 발신자 (현재 호출)

함수

가장 단순하게 말하자면, 함수는 들어오는 트랜잭션에 대한 응답으로 정보를 가져오거나 설정할 수 있습니다.

함수 호출에는 두 가지 유형이 있습니다:

  • internal – EVM 호출을 생성하지 않습니다.
    • 내부 함수와 상태 변수는 내부적으로만 접근할 수 있습니다(즉, 현재 컨트랙트 내부 또는 이를 상속받은 컨트랙트에서만).
  • external – EVM 호출을 생성합니다.
    • 외부 함수는 컨트랙트 인터페이스의 일부이므로 다른 컨트랙트나 트랜잭션을 통해 호출될 수 있습니다. 외부 함수 f는 내부적으로 호출할 수 없습니다(즉, f()는 작동하지 않지만 this.f()는 작동합니다).

또한 public 또는 private일 수 있습니다.

  • public 함수는 컨트랙트 내부에서 내부적으로 호출되거나 메시지를 통해 외부에서 호출될 수 있습니다.
  • private 함수는 해당 함수가 정의된 컨트랙트에서만 볼 수 있으며 파생된 컨트랙트에서는 볼 수 없습니다.

함수와 상태 변수 모두 public 또는 private으로 설정할 수 있습니다.

다음은 컨트랙트의 상태 변수를 업데이트하는 함수입니다:

// Solidity 예제
function update_name(string value) public {
    dapp_name = value;
}
  • string 타입의 매개변수 value가 함수에 전달됩니다: update_name
  • public으로 선언되어 누구나 접근할 수 있습니다.
  • view로 선언되지 않았으므로 컨트랙트 상태를 수정할 수 있습니다.

View 함수

이 함수들은 컨트랙트 데이터의 상태를 수정하지 않을 것을 보장합니다. 일반적인 예로는 "getter" 함수가 있으며, 예를 들어 사용자의 잔액을 가져올 때 사용할 수 있습니다.

// Solidity 예제
function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerPizzaCount[_owner];
}
dappName: public(string)

@view
@public
def readName() -> string:
  return dappName

상태를 수정하는 것으로 간주되는 작업:

  1. 상태 변수에 쓰기.
  2. 이벤트 발생시키기 (새 탭에서 열림).
  3. 다른 컨트랙트 생성하기 (새 탭에서 열림).
  4. selfdestruct 사용하기.
  5. 호출을 통해 이더 전송하기.
  6. view 또는 pure로 표시되지 않은 함수 호출하기.
  7. 저수준(low-level) 호출 사용하기.
  8. 특정 연산 코드(opcode)가 포함된 인라인 어셈블리 사용하기.

생성자 함수

constructor 함수는 컨트랙트가 처음 배포될 때 단 한 번만 실행됩니다. 많은 클래스 기반 프로그래밍 언어의 constructor와 마찬가지로, 이 함수들은 종종 상태 변수를 지정된 값으로 초기화합니다.

# Vyper 예제

@external
def __init__(_beneficiary: address, _bidding_time: uint256):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

내장 함수

컨트랙트에 정의하는 변수와 함수 외에도 몇 가지 특별한 내장 함수가 있습니다. 가장 대표적인 예는 다음과 같습니다:

  • address.send() – Solidity
  • send(address) – Vyper

이를 통해 컨트랙트가 다른 계정으로 ETH를 전송할 수 있습니다.

함수 작성하기

함수에는 다음이 필요합니다:

  • 매개변수 변수 및 타입 (매개변수를 허용하는 경우)
  • internal/external 선언
  • pure/view/payable 선언
  • 반환 타입 (값을 반환하는 경우)

완전한 컨트랙트는 다음과 같은 모습일 수 있습니다. 여기서 constructor 함수는 dapp_name 변수에 초기값을 제공합니다.

이벤트 및 로그

이벤트를 통해 스마트 컨트랙트는 프론트엔드나 다른 구독 애플리케이션과 통신할 수 있습니다. 트랜잭션이 검증되어 블록에 추가되면, 스마트 컨트랙트는 이벤트를 발생시키고 정보를 로그로 남길 수 있으며, 프론트엔드는 이를 처리하고 활용할 수 있습니다.

주석이 달린 예제

다음은 Solidity로 작성된 몇 가지 예제입니다. 코드를 직접 다뤄보고 싶다면 Remix (새 탭에서 열림)에서 상호작용해 볼 수 있습니다.

Hello world

토큰

고유한 디지털 자산

더 읽어보기

스마트 컨트랙트에 대한 더 완전한 개요를 보려면 Solidity와 Vyper의 문서를 확인하세요: