스마트 컨트랙트

Aiden
14 min readFeb 23, 2022

--

이 포스팅은 ‘블록체인 인 액션’ (비나 라마머시 저, 정우현 옮김)의 내용을 다루고 있다.

필자는 블록체인을 완전 처음부터 공부하는 것이라, 필자의 블록체인 시리즈 포스팅은 블록체인에 관심이 있는 개발자라면 모두 이해할 수 있을 것이라 생각한다.

이번 포스팅은 2장 ‘스마트 컨트랙트’를 다룰 것이다. 주요 내용은 아래와 같다.

  1. 스마트 컨트랙트 이해하기
  2. 스마트 컨트랙트 개발을 위한 설계 원칙 적용하기
  3. 솔리디티 언어를 사용해 컨트랙트 코딩하기

스마트 컨트랙트는 암호 화폐 프레임워크를 신뢰 프레임워크로 전환시켜, 보다 폭 넓은 영역에서 탈중앙화 애플리케이션을 활용할 수 있게 해주는 블록체인의 핵심적인 컴포넌트다.

구조적으로 스마트 컨트랙트(smart contract)는 객체지향 프로그램에서 클래스와 유사한 독립적인 코드다. 또한, 데이터와 함수를 가진 배포 가능한 코드 모듈이다. 함수는 확인, 검증, 그리고 전송된 메시지를 저장하는 등의 특정한 목적을 수행한다. 현실 세계에서 컨트랙트는 규칙, 조건, 법, 강제해야 하는 규정, 기준, 상황, 날짜 등 서명 같은 증명을 위한 항목 등을 다룬다.

스마트 컨트랙트는 애플리케이션의 규칙과 규정들을 디지털로 정의하고, 검증하고, 검사하며, 강제하기 위한 블록체인에서 작동시킬 수 있는 실행 가능한 코드다. 스마트 컨트랙트는 제삼자 없이도 신뢰할 수 있는 트랜잭션의 수행을 지원한다. 이런 트랜잭션은 추적 가능하고 되돌릴 수 없다.

이 장에서는 스마트 컨트랙트와 블록체인 프로그래밍의 설계와 개발을 가이드해 줄 개발 원칙을 설명한다. 코드의 형식으로 설계를 구현하기 위해서는 다음과 같은 것이 필요하다.

  • 블록체인 플랫폼
  • 스마트 컨트랙트를 코딩하기 위한 언어
  • 개발, 컴파일, 배포, 테스트하기에 적합한 환경

우리는 이더리움을 플랫폼으로 사용할 것이고, 솔리디티라는 특수한 언어를 사용할 것이다. 그런 후에 리믹스라는 IDE를 통해 코드를 배포하고 작동 테스트를 진행할 것이다.

스마트 컨트랙트 개념

스마트 컨트랙트는 비트코인 블록체인 프로토콜이 제공했던 기본적인 신뢰를 확장시키는 코드다. 스마트 컨트랙트는 암호 화폐 이외의 디지털 자산을 위한 트랜잭션을 지원할 수 있는 프로그래밍을 가능하게 해준다. 스마트 컨트랙트는 각 블록체인 애플리케이션이 필요로 하는 특정한 확인과 검증을 가능하게 한다. 범용적인 애플리케이션을 위한 블록체인의 신뢰 레이어를 열어 주는 것이다.

여기서는 이더리움의 스마트 컨트랙트 정의를 사용하는데, ㅣ더리움은 가장 많이 사용하는 범용적인 퍼블릭 블록체인이기 때문이다.

비트코인 트랜잭션 vs. 스마트 컨트랙트 트랜잭션

비트코인의 경우, 모든 트랜잭션은 가치를 전송하기 위한 것이다. 스마트 컨트랙트를 지원하는 컨트랙트의 경우, 트랜잭션은 스마트 컨트랙트가 구현한 기능을 임베드한다. 블록체인에 이러한 임의적인 코드를 올리고 실행할 수 있는 기능은 단순한 암호 화폐 전송을 넘어서서 블록체인의 활용도를 크게 향상 시킨다.

스마트 컨트랙트는 무엇을 하나

스마트 컨트랙트는 블록체인 애플리케이션의 두뇌와 같은 역할을 한다.

  • 각 애플리케이션의 특수한 조건에 맞는 확인과 검증을 할 수 있는 비즈니스 로직 레이어를 표현한다.
  • 블록체인에서 작동하기 위한 규칙의 명세(specification of rules)를 설정할 수 있게 한다.
  • 탈중앙화 네트워크에서 자산의 전송을 위한 정책을 구현하기 쉽도록 한다.
  • 메시지나 다른 함수의 호출에 의해 실행되는 함수를 내장하는데, 개인 어카운트나 다른 스마트 컨트랙트 어카운트가 이런 호출을 하게 된다. 이 메시지는 블록체인으 분산 장부에 트랜잭션 일부로 기록되는데, 여기에는 입력 파라미터, 송신자의 주소, 타임스탬프 등과 같은 추가적인 메타 데이터를 포함한다.
  • 탈중앙화 블록체인 기반 애플리케이션을 위한 소프트웨어 기반 중개자로서 기능한다.
  • 스마트 컨트랙트 기능의 구체적인 설정을 통해 블록체인에게 프로그래밍 가능성(programmablity)와 지능성을 제공해 준다.

이런 핵심적인 기능성을 가지고 있는 스마트 컨트랙트는 의심할 여지 없이 탈중앙화 블록체인 애플리케이션의 중심 컴포넌트라 할 수 있다.

스마트 컨트랙트의 설계

스마트 컨트랙트로 해결해야 할 문제 설정에서부터 코드의 배포에 이르기까지 전 과정을 살펴볼 수 있는 간단한 예제를 통해 스마트 컨트랙트 설계를 탐구하자. 첫 번째 예제는 탈중앙화 카운터다.

카운터는 단순하지만, 스마트 컨트랙트 개발의 다양한 유스 케이스를 보여줄 수 있는 좋은 예다. 코드를 개발하기 앞서 올바른 설계를 하는 것이 중요하다. 더욱이 설계 자체는 스마트 컨트랙트 언어와는 독립적인 것이므로 다른 언어로도 구현할 수 있는 설계도와 같은 것이다.

트랜잭션을 통해 스마트 컨트랙트를 블록체인에 배포하는데, 블록의 일부분에 포함됨으로써 블록체인에 영구히 기록되고, 되돌릴 수 없으며, 수정할 수 없다. 이를 설계 원칙 1로 요약할 수 있다.

설계원칙 1 — 테스트 체인에서 스마트 컨트랙트를 코딩, 개발, 배포하기 전에 우선 설계부터 한다. 또한 프로덕션 블록체인에 배포하기 전에 철저한 테스트를 거쳐야 한다. 왜냐하면 스마트 컨트랙트는 변조 불가능하기 때문이다.

설계 과정의 목표는 스마트 컨트랙트의 내용을 정의하는 것인데, 구체적으로는 다음과같은 점을 설정하는 것이다.

  • 데이터
  • 데이터를 처리할 함수
  • 처리를 위한 규칙

설계원칙 2 — 시스템 사용자와 유스케이스를 정의한다. 사용자란 행위와 입력값을 발생시키고, 설계하고 있는 해당 시스템으로부터 그 출력값을 받는 주체다.

카운터를 위한 유스 케이스 다이어그램

유스 케이스와 클래스 다이어그램을 보여주기 위해 표준적입 통합 모델 언어(UML)를 사용할 것이다.(책에서는 그림으로 나타내지만, 포스팅할 때는 그림을 사용하기가 어려워 그림 없이 진행되니 양해바란다)

UML 유스 케이스 다이어그램은 해결해야 할 문제와 스마트 컨트랙트를, 정확히는 그것의 함수들을 어떻게 사용해야 할지에 대해 숙고할 수 있도록 해준다.

우선, 카운터의 함수들을 생각해보자.

  • initialize() — 값에대한 초기화
  • increment() — 주어진 값만큼 증가
  • decrement() — 주어진 값만큼 감소
  • get() — 카운터값을 가져오기

해당 스마트 컨트랙트가 의도하는 바를 명확히 표현해 주는 이 다이어그램은 설계 과정의 출발점이자 개발팀원들과 이 문제 해결에 관심 있는 관계자들이 같이 논의해 볼 수 있는 자료가 된다. 또한 다음 설계 단계로 이끄는 도입부다. 여기서 한 가지 주목할 점은 이 단계에서 만든 설계 내용이 해결해야 하는 문제에는 종속적이지만, 특정한 코딩 또는 시스템에는 종속적이지 않다는 점이다.

데이터 애셋, 피어 참여자, 역할, 규칙, 그리고 트랜잭션

유스 케이스 다이어그램이 나왔고, 이제 문제 해결을 위한 블록체인 기반 컴포넌트들의 여러 속성(attributes)에 대해 설명할 차례다.

설계원칙 3 — 데이터 애셋, 피어 참여자, 그들의 역할, 강제할 규칙, 설계하고 있는 시스템에 기록해야 할 트랜잭션을 정의한다.

탈 중앙화 카운터 문제에서 설계 원칙 3을 적용하면 다음과 같은 아이템을 설정할 수 있다.

  • 추적해야 할 데이터 애셋 — 카운터값
  • 피어 참여자 — 카운터값을 업데이트할 애플리케이션
  • 참여자의 역할 — 카운값을 업데이트하고 그 값에 액세스 하는 것
  • 데이터와 함수에 검증, 검사해야 할 규칙 — 이 유스케이스에는 없음
  • 디지털 장부에 기록해야 하는 트랜잭션 — initialize(), increment(), decrement()

카운터값을 바꾸는 함수나 트랜잭션만을 기록하면 된다는 점에 주목하자. 스마트 컨트랙트에 정의된 모든 함수가 블록체인의 분산 장부에 기록을 남기는 트랜잭션을 생성하는 것은 아니다. get()함수는 카운터의 내용을 보기만 할 뿐이므로 이 함수의 호출을 블록체인에 기록할 필요는 없다. 이런 특성을 읽기 전용(view-only) 함수로 정의할 수 있다. 읽기 전용 함수의 실행은 블록체인에 기록하지 않는다.

클래스 다이어그램에서 컨트랙트 다이어그램으로

이 단계에서는 카운터 문제 해결 설계를 위해 UML 클래스 다이어 그램을 설정한다. 클래스 다이어 그램은 솔루션의 여러가지 구조적 요소들을 정의한다. 이전의 두 단계(유스 케이스와 디지털 애셋 분석)에서 나온 아이템들을 바탕으로 클래스 다이어 그램을 그린다. 전통적인 객체 지향 프로그래밍의 전형적인 UML 클래스 다이어 그램은 다음의 세 가지 요소를 포함한다.

  • 클래스의 이름
  • 데이터 정의
  • 함수 정의

아래 내용은 기존 클래스 다이어그램과 컨트랙트 다이어 그램의 차이를 나타낸다.

----------------------
클래스 이름
----------------------
데이터 정의 또는 디지털 애셋
----------------------
함수를 구동시키기 위한 수정자
(modifier) 또는 규칙들
* 이부분이 기존 클래스 다이어그램과 다른 부분이다.
----------------------
상태 변환을 초래할 수 있는
함수들과 분산 장부에 기록할
트랜잭션들
----------------------

수정자는 데이터와 함수에 대한 접근을 통제하는 규칙을 규정한다. 규칙은 함수의 파라미터를 검사하고 함수 실행을 제어한다.

설계원칙 4 — 컨트랙트 이름, 데이터 애셋, 함수, 함수의 실행과 데이터 접근을 위한 규칙을 정의하는 컨트랙트 다이어 그램을 작성한다.

최종적인 카운터 컨트랙트 다이어 그램은 하단과 같다.

----------------------
Counter
----------------------
uint value
----------------------
규칙이나 조건은 없음.
누구나 카운터 작동을 위한
함수를 호출할 수 있다.
----------------------
constructor()
initialize(uint)
increment(uint)
decrement(uint)
get()
----------------------

스마트 컨트랙트 코드 작성

스마트 컨트랙트 개발을 위해서는 블록체인 오퍼레이션에 특화된 전용 언어가 필요하다. 솔리디티는 그러한 언어 중 하나다. 이더리움 재단이 이 언어를 처음 도입했는데, 하이퍼레저와 같은 다른 블록체인 플랫폼도 이를 사용한다. 우리도 스마트 컨트랙트 코딩을 하기 위해서 이 솔리디티를 사용할 것이다.

컨트랙트 코드를 작성하는 것은 블록체인 기반의 기록을 위해 정밀한 명령을 만드는 것이다. 어카운트 주소, 규칙 사양, 트랜잭션 되돌림(reversal)과 같은 블록체인에 특화된 특정 기능이 언어에 내장되어 있어야 한다. 또한, 스마트 컨트랙트 코드는 여러 블록체인 노드에서 실행될 때 일관성을 유지하기 위한 제한된(restricted) 샌드박스 환경에서 실행된다. 이러한 이유로 스마트 컨트랙트를 코딩하기 위해 특수한 언어를 사용한다.

솔리디티 언어

솔리디티 언어는 스마트 컨트랙트를 코딩하기 위한 객체지향 고수준 언어인데, C++, 파이썬 자바스크립트 등의 영향을 받았다. 솔리디티는 정적 타입(statically typed) 언어이고, 상속, 라이브러리, 사용자 정의 타입 등을 지원한다. 또한 블록체인 애플리케이션 개발을 위한 유용한 기능을 많이 제공한다. 시뮬레이트된 블록체인 위에 스마트 컨트랙트 코드를 작성, 수정, 컴파일하고, 이를 배포하고 테스트하기 위해 리믹스 통합 개발 환경을 사용할 것이다.

카운트를 위한 스마트 컨트랙트 코드

위의 컨트랙트 다이어 그램에서 설계한 내용을 코드롤 개발하면 아래와 같다.

첫 번째 라인은 오픈소스 라이센스를 지정해준다. 이 코드가 없으면 Remix IDE에서 Warning을 해준다. 두번째 라인은 이 코드를 작성하는 데 사용한 언어의 버전을 지칭한다. 코딩에 사용한 언어의 버전과 컴파일할 때 사용할 버전을 일치시키기 위해서 버전을 지정하는 이 구문이 필수 사항이다. 버전 번호를 지정할 때 pragma 지시문을 사용한다. 이 pragma 지시문 이후, contract 키워드와 컨트랙트의 이름(이 경우에는 Counter)으로 컨트랙트 코드 정의를 시작한다.

다음으로, 스마트 컨트랙트의 데이터 컴포넌트를 정의한다. 솔리디티의 데이터 타입은 다른 고수준 언어와 비슷하다. 이 예제에서는 uint(unsigned integer) 데이터 타입을 카운터값을 저장하는 식별자로 정의하기 위해 사용하였다. 블록체인 환경에서 uint 타입은 다른 주류 컴퓨팅에서 사용하는 정수 데이터 타입과 상당히 다른데, 범용 언어에서는 64비트인 데 반해 솔리디티에서는 256비트 값이다. uint, int, int 256, uint256는 모두 같은 값의 별칭이다.

모든 함수는 public으로 선언되어 있는데, 이것은 공개적 가시성을 가진다는, 즉 블록체인상에 있는 어떠한 외부의 참여자(또는 어카운트)도 이 함수를 호출할 수 있다는 것을 의미한다. initialize(), increment(), decrement() 함수는 파라미터 값을 받아서, 이 값을 가지고 함수 본문 안에서 변수 value를 갱신하는 역할을 한다. 이들 함수의 호출은 자동적으로 각각 분산 장부상의 트랜잭션으로 기록된다. 변수 value의 상태 변화(state change) 또한 모두 기록된다.

get() 함수는 ‘view’ 함수임에 주목하자. 이 함수를 호출하는 것은 블록체인상에 기록되지 않는데, 그 이유는 카운터값 상태를 변화시키지 않기 때문이다.

이 스마트 컨트랙트를 만들기 위해 하단과 같이 진행하자

  1. 브라우저에서 리믹스 IDE를 오픈한다 : https://remix.ethereum.org/
  2. 솔리디티 언어를 선택한다
  3. IDE에서 왼쪽 패널 맨 위에 있는 새파일 아이콘을 클릭해서 새파일을 만든다
  4. 열린 팝업 윈도우에서 Counter.sol이라고 이름을 설정한다(sol 확장자는 솔리디티 언어를 위한 파일 확장자이다)
  5. 필자가 상단에 정의해놓은 Counter 코드를 입력하거나 복사해서 에디터 창에 붙여 넣는다

리믹스

리믹스는 별도의 설치 과정 없이 웹/클라우드 기반으로 통합 개발 환경을 제공한다. 그뿐만 아니라 자바스크립트 기반의 테스트 체인 환경을 제공하고, 작성한 컨트랙트 코드를 이 체인 위에 바로 배포해서 실행할 수 있도록 지원해 준다. 이 일체형의 개발 환경에서 테스트한 스마트 컨트랙트 코드는 리믹스 테스트 체인뿐만 아니라 외부 블록체인 으로도 쉽게 배포할 수 있다.

https://remix-ide.readthedocs.io/en/latest/layout.html

리믹스 사용법은 위 문서에서 확인할 수 있다.

블록체인 컨트랙트는 왜 스마트한가

스마트 컨트랙트를 스마트하게 만드는 몇 가지 훌륭한 기능이 있다. 스마트 컨트랙트는 블록체인 네트워크의 다른 참여자와 동등한 지위를 갖는데, 스마트 컨트랙트가 다음과 같은 속성을 갖고 있기 때문이다.

  • 이름
  • 주소
  • 암호 회폐(여기서는 이더) 잔액
  • 암호 회폐(여기서는 이더)를 송금하고 수신할 수 있는 내장 기능
  • 데이터와 함수
  • 메시지를 수신하고 함수를 호출할 수 있는 내장 기능
  • 데이터와 함수
  • 메시지를 수신하고 함수를 호출할 수 있는 내장 기능
  • 함수 실행을 계산할 수 있는 능력

이러한 요소들이 스마트 컨트랙트가 일반적인 코드와 다른 점이다.

전통적인 컴퓨팅 시스템에서는 사용자 이름과 암호로 참여자를 식별한다. 하지만 이 조합은 탈중앙화 시스템에서는 작동하지 않는데, 그 이유는 피어(peer)가 통상적인 신뢰 범위 밖에 있기 때문이다. 해결책은 각 참여자에게 암호학적 알고리즘에 기반한 고유한 식별자를 제공하는 것이다. 블록체인과 상호작용을 하는 모든 참여자(스마트 컨트랙트 포함)는 고유하게 식별 가능한 어카운트 번호, 즉 주소를 가진다.

  • 이더리움은 두 가지 종류의 어카운트가 있는데, 하나는 외부 소유 어카운트(externally owned accounts, EOA)이고, 다른 하나는 스마트 컨트랙트 어카운트(smart contract accounts, SCA)다. 이 두 어카운트 모두 160비트 또는 20바이트 크기의 주소로 식별한다.
  • EOA와 스마트 컨트랙트 어카운트 모두 이더 밸런스를 가질 수 있다. 따라서 모든 어카운트는 address와 balance라는 묵시적(implicit) 속성을 가진다. 스마트 컨트랙트상에서 명시적으로 이 속성을 발견할 수 없음에도 address(this).balance와 같이 스마트 컨트랙트가 가진 밸런스를 조회해 볼 수 있다.
  • EOA와 스마트 컨트랙트는 스마트 컨트랙트에 메시지를 보냄으로써 함수를 호출할 수 있다. 이러한 메시지는 두 가지의 묵시적(implied) 속성을 가지고 있는데, msg.sender와 msg.value가 그것이다. 메시지는 가치를 전송할 수 있는데, 호출한 스마트 컨트랙트의 함수를 실행할 때 그 금액은 호출한 스마트 컨트랙트의 밸런스에 더해진다. 이렇게 금액을 전송받기 위해서는 해당 함수에 payable 수정자(modifier)를 포함해 선언해야 한다.

스마트 컨트랙트에 대한 개념적 설명은 이쯤으로 하고, 다음 포스팅에서는

  1. 카운터 기능을 가진 스마트 컨트랙트를 테스트 네트워크에 올리는 방법
  2. 모바일 환경의 프론트엔드(우리는 플러터를 사용할 것이다)에서 1의 네트워크에 올린 스마트 컨트랙트를 사용하는 방법

위 두가지 사항에 대해서 예제를 만들어서 보여줄 것이다.

--

--

Aiden

안드로이드 개발자(개인 공부용도의 블로그)