본문으로 건너뛰기
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 문서 (opens in a new tab)를 참조하세요.

환경 변수

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

예시:

속성상태 변수설명
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. 이벤트 발생시키기 (opens in a new tab).
  3. 다른 컨트랙트 생성하기 (opens in a new tab).
  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 (opens in a new tab)에서 상호작용해 볼 수 있습니다.

Hello world

토큰

고유한 디지털 자산

더 읽어보기

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