챕터7:스마트 컨트랙트와 솔리디티
컨트랙트 계정은 개인키를 갖지 않으므로 스마트 컨트랙트에 규정된 미리 결정된 방식으로 '스스로 제어'하는 반면, EOA는 프로토콜의 외부에 있어서 프로토콜에 독립적인 '실제 세계'의 개인키로 생성되고 암호로 서명된 거래에 의해 제어된다.
여러번 나오는 얘기이지만 이더리움에는 EOA와 컨트랙트 계정 이렇게 두가지 유형의 계정이 있다.
이번장에서는 컨트랙트 계정과 이를 제어하는 코드에 대해서 설명한다.
스마트 컨트랙트란 무엇인가
이 책에서는 '스마트 컨트랙트'라는 용어를 불변적인(immutable) 컴퓨터 프로그램을 지칭하는데, 이 프로그램은 이더리움 네트워크 프로토콜(즉, 탈중앙화된 이더리움 월드 컴퓨터)의 일부인 이더리움 가상 머신의 컨텍스트 상에서 결정론적으로(deterministically) 작동한다.
컨트랙트는 단순히 컴퓨터 프로그램이고, '컨트랙트'라는 단어에 법적인 의미는 없다.
스마트 컨트랙트 코드는 배포 후 변경이 불가능하기에 불변적이고, 인풋에 따른 아웃풋이 정해져 있어 결정론적으로 작동한다.(실행을 시작한 트랜잭션의 컨텍스트와 실행 시점에 이더리움 블록체인의 상태가 동일하다는 전제가 있기 때문이다.)
스마트 컨트랙트는 매우 제한된 실행 컨텍스트(EVM컨텍스트)에서 작동된다.
EVM은 모든 이더리움 노드에서 로컬 인스턴스로 실행되지만, EVM의 모든 인스턴스는 동일한 초기 상태에서 작동하고 동일한 최종 상태를 생성하기 때문에 시스템 전체가 단일 '월드 컴퓨터'로 작동한다.
스마트 컨트랙트의 생명주기
스마트 컨트랙트는 일반적으로 솔리디티와 같은 고급 언어로 작성된다. 그러나 컨트랙트를 실행하려면 EVM에서 실행되는 저수준의 바이트 코드로 컴파일되어야 한다. 일단 컴파일되면 고유한 컨트랙트 생성(contract creation) 트랜잭션을 사용하여 이더리움 플랫폼에 배포되며, 이 트랜잭션은 고유한 컨트랙트 생성 주소, 즉 0x0으로 전송된다.
컨트랙트가 전송되면 각 컨트랙트는 이더리움 주소로 식별이 된다.
이 주소에는 트랜잭션을 전송하거나 자금을 보내거나 함수를 호출하는데 사용 할 수 있지만, EOA와 달리 관련된 키가 없다.
키가 없다는 말은 이미 생성된 컨트랙트에 대해서 특별한 권한을 얻지 못한다는 의미이다.
이 책에서는 이런 부분을 '컨트랙트 계정은 그들 자체를 소유하고 있다'고 표현한다.
중요한 것은 컨트랙트가 트랜잭션에 의해 호출된 경우에만 실행된다는 것이다.
이더움의 모든 스마트 컨트랙트는 인풋을 기다리는 함수라고 보면 된다.
EOA에서 트랜잭션을 통해 인풋값을 보내주어야, 해당하는 아웃풋값을 받을 수 있다.
컨트랙트가 컨트랙트를 호출하는 경우가 있지만, 어쨋든 맨 처음엔 EOA에서 컨트랙트가 시작된다.
컨트랙트는 자체적으로 혹은 백그라운드에서 자동적으로 실행되지 않는다.
불러주기 전까진 그냥 코드 자체로써 존재한다.(김춘수 시인의 꽃이라는 시가 생각난다...)
또한 컨트랙트는 '병렬적'으로 실행되지 않는다.
이 말은 이더리움 월드 컴퓨터가 단일 스레드 컴퓨터같이 동작한다는 의미이다.
트랜잭션은 호출하는 컨트랙트 수 또는 호출 시 해당 컨트랙트가 수행하는 작업과 상관없이 원자성(atomic)의 특징을 지닌다.
트랜잭션은 모든 실행이 성공적으로 종료된 경우에만 글로벌 상태(컨트랙트, 계정 등)의 모든 변경사항이 기록되고 전체가 실행된다.
실행에 성공했을 경우에는 정상적으로 기록되지만, 실패했을 경우 트랜잭션은 '롤백'된다.
아무일도 일어나지 않은 것처럼... 다만 컨트랙트를 호출하는 시도 자체는 기록에 남고 그에 해당하는 만큼의 가스는 차감된다.
컨트랙트 내용 변경은 안되지만, 삭제는 가능하다.
컨트랙트를 삭제해서 코드와 내부 스토리지를 제거하고 빈 계정으로 남겨 자원을 반환하는 효과를 낼 수 있다.
물론 컨트랙트가 지워져도 블록을 수정할 수는 없기 때문에 관련 트랜잭션들이 지워지지는 않는다. 이 과정에서 가스 환불이 일어난다.
또한 당연한 얘기이지만, 미리 코드상으로 구현해놓은 삭제만이 가능하다.
이더리움 고급 언어의 소개
EVM은 x86_64 같은 머신 코드를 실행하는 컴퓨터의 CPU와 유사한 EVM 바이트코드라는 특수한 형태의 코드를 실행하는 가상 머신이다. 13장에서 EVM의 작동 및 언어를 자세히 살펴 볼 것이다. 이 장에서는 EVM에서 스마트 컨트랙트가 실행되는 방법을 살펴보겠다.
스마트 컨트랙트를 바이트코드로 직접 프로그래밍할 수 있다. 하지만 바이트코드 이름만 들어도 난이도가 체감이 간다.
특히 EVM은 다루기 까다롭다고 한다. 따라서 보통 고급언어를 사용하고 컴파일러를 사용해 바이트코드로 변환하는 식으로 사용한다.
이 고급 언어의 종류는 다음과 같다.
LLL(Low-level Lisp-like Lannguage), 서펀트(Serpent), 솔리디티(Solidity), 바이퍼(Vyper), 밤부(Bamboo)
스마트 컨트랙트에는 선언형 언어가 더 적당하나, 일반적으로 프로그래머들은 명령형 언어에 더 익숙하기 때문에
가장 많이 쓰이는 언어는 명령형 언어인 솔리디티이다.
솔리디티로 스마트 컨트랙트 생성
솔리디티는 개빈 우드(이 책의 공동 저자)에 의해 창안되었으며, 명시적으로 스마트 컨트랙트 작성을 위해 만들어진 언어인데, 이더리움 월드 컴퓨터의 탈중앙화된 환경에서의 실행을 직접적으로 지원한다. 그 결과, 언어의 속성이 매우 일반적이어서 다른 여러 블록체인 플랫폼에서 스마트 컨트랙트를 코딩하는 데 사용된다.
...
솔리디티는 이제 깃허브(//github.com/ethereum/solidity
솔리디티의 버전 선택
솔리디티는 시맨틱 버저닝(semantic versioning)이라고 하는 버전 관리 모델을 따르며, 버전 번호는 점으로 구분된 3개의 숫자로 구성된다(MAJOR.MINOR.PATCH). '메이저(major)' 번호는 주요 기능 변경 및 이전 버전과의 호환이 변경될 때마다 증가하며, 주요 버전 간에 하위 호환 기능이 추가될 때 '마이너(minor)'가 증가하고, 이전 버전과 호환되는 버그 수정을 위해 '패치(patch)' 번호가 증가한다.책을 쓰는 당시 솔리디티 버전은 0.4.24이다. 프로젝트 초기 개발을 위한 메이저 버전 0에 대한 규칙은 다르다. 즉, 언제든지 변경될 수 있다. 실제로 솔리디티는 '마이너'를 메이저 버전인 것처럼 처리하고 '패치' 번호를 마이너 버전인 것처럼 처리한다. 따라서 0.4.24에서는 4를 메이저 버전으로, 24를 마이너 버전으로 간주한다.
책을 쓰는 당시 솔리디티 버전은 0.4.24였다고 한다. 지금은 21.8.11에 배포된 0.8.7이 최신인 듯 하다
다운로드 및 설치
이 부분은 패스...
개발환경
책에서는 개발환경을 자유롭게 선택하라고 말하고 있다.
결국 텍스트 파일이고, 확장자만 .sol이면 컴파일러가 인식하기 때문인데
다양한 환경에서 개발 할 수 있다는 것과,
리믹스 IDE(remix.ethereum.org), EthFiddle(ethfiddle.com) 같은 웹 기반 개발환경도 있다는 것만 알아두면 될 것 같다.
단순한 솔리디티 프로그램 작성
패스...
솔리디티 컴파일러(solc)로 컴파일
패스...
이더리움 컨트랙트 ABI
컴퓨터 소프트웨어에서 어플리케이션 바이너리 인터페이스(Application Binary Interface, ABI)는 두 프로그램 모듈 간 또는 때때로 운영체제와 사용자 프로그램 간의 인터페이스다. ABI는 데이터 구조와 함수가 어떻게 기계 코드(machine code)에서 사용되지는 그 방법을 정의한다. 이것은 API와 혼동되어서는 안 되며, API는 사람이 읽을 수 있는 형식인 고수준의 소스 코드(source code)로 정의한다. 따라서 ABI는 기계 코드와 데이터를 교환하기 위해 인코딩 및 디코딩하는 기본 방법이다.
ABI는 json 형태로 지정된다. 이 json 파일을 EVM에서 컨트랙트 호출을 인코딩하고 트랜잭션에서 데이터를 읽는 데 사용한다.
EVM한테 어떤 함수가 어떤 인자를 받고 어떤 결과를 내는지 전달해주는 역할이라고 보면 된다.
ABI를 사용하면 어떤 인수를 어떤 함수에 넣어야하는 지 미리 알기 때문에, 해당 컨트랙트에 필요한 올바른 인자들을 사용자들에게 미리 요구할 수 있다.
따라서 어플리케이션이 컨트랙트와 상호작용하는 데 필요한 것은 ABI와 컨트랙트가 배포된 주소이다.
솔리디티 컴파일러 및 언어 버전 선택
어쨋든 바이트 코드는 동일한 것이고 솔리디티 언어와 컴파일러가 변하는 것이기 때문에,
솔리디티 단에서 해당 버전을 잘못 입력하게 되면, 잘못된 바이트 코드로 번역되어 전달될 수 있다.
따라서 버전을 명시하는 것이 중요하고, 이를 솔리디티에서는 pragma라고 하는 컴파일러 지시문(compiler directive)를 통해 나타낸다.
^0.4.19 기호는 같은 마이너 버전내의 0.4.19 이상의 버전에서 호환 가능하다는 의미이다.(0.4.20 --> o, 0.5.0 --> x)
당연한 얘기이지만 이 지시문은 컴파일러에서만 사용되고 바이트코드로 번역되지 않는다.
솔리디티로 프로그래밍하기
데이터 타입
패스...
사전 정의된 글로벌 변수 및 함수
패스
컨트랙트 정의
솔리디티의 주요 데이터 타입은 contract이다. 우리의 Faucet 예제는 단순히 contract 객체를 정의한다. 객체 지향 언어의 객체와 마찬가지로, 컨트랙트는 데이터와 메서드가 포함된 컨테이너다. 솔리디티는 컨트랙트와 유사한 두 가지 객체 유형을 제공한다.
interface
이런 유형은 흔히 stub이라고 불린다. 함수가 정의되어 있지 않고 선언만 되어있어서 어떤 구현도 없이 함수의 인자와 반환 유형을 알려준다. 컨트랙트의 형태(shape)을 지정한다. 상속될 때 인터페이스에 의해 선언된 각 함수는 자식에 의해 정의되어야 한다.
library
delegatecall 메서드를 사용하여 한 번만 배포되고 다른 컨트랙트에서 사용되기 위한 컨트랙트이다.
함수
패스
컨트랙트 생성자 및 selfdestruct
생성자 함수는 컨트랙트 생성 시에만 한 번 실행되어, 컨트랙트의 상태를 초기화 하는 함수이다.
v0.4.21까지의 버전에서는 컨트랙트의 이름과 동일한 이름의 함수로 생성자를 지정했지만,
이가 실수 하기 쉬운 부분이고, 배포후에는 실수를 바로 잡을 수 없기 때문에
v0.4.22버전 부터는 constructor 키워드를 도입했다.
<컨트랙트의 생명주기>
EOA 또는 컨트랙트 계정으로부터의 트랜잭션 생성 -> 생성자가 있다면 컨트랙트 상태 초기화 후 소멸
<또 다른 컨트랙트 생명주기의 끝>
컨트랙트 소멸(contract destruction)
컨트랙트는 SELFDESTRUCT(자기파괴)라는 특수한 EVM 연산코드에 의해 소멸된다.
이 함수는 하나의 인수, 즉 컨트랙트 계정에 남아 있는 이더 잔액을 받기 위한 주소를 받는다.
slefdestruct(address recipient);컨트랙트의 삭제를 원할 때에는 이 코드를 컨트랙트에 명시적으로 추가해야한다.
Faucet에 생성자와 selfdestruct를 추가하는 예제
패스...
함수 변경자
함수 변경자는 컨트랙트 내에서 함수에 적용되어야 할 여러 조건을 생성하기 위해 가장 자주 사용된다.
아래의 코드는 변경자를 사용하여 selfdestruct에 조건을 주는 예시이다.
modifier onlyOwner { require(msg.sender == owner); _; } function destroy() public onlyOwner { selfdestruct(owner); }변경자 안의 언더바(_)는 이 변경자를 사용하는 함수의 내용으로 대체된다.
변경자를 적용하려면 함수 선언에 변경자 이름을 추가해야하면 된다.
한 함수에 둘 이상의 변경자를 적용할 수 있고, 쉼표로 구분된 리스트로 선언된 순서대로 적용된다.
변경자는 함수의 전제 조건을 일관되게 적용하여 코드를 쉽게 만들기 때문에 유용한 도구이다.
보통은 접근 제어에 자주 사용되지만, 다양한 목적으로 사용할 수 있다.
컨트랙트 상속
솔리디티의 contract 객체는 바탕이 되는 컨트랙트에 기능들을 추가해서 확장하기 위한 메커니즘인 상속(inheritance)을 지원한다.
상속을 사용하려면 부모 컨트랙트에 is 키워드를 지정하면 된다.
contract Child is Parent1, Parent2 { ... }콤바를 구분해서 다중 상속도 가능하며, 상속 시 Child 컨트랙트가 Parent의 모든 메서드, 기능 및 변수를 상속한다.
에러처리
이벤트
다른 컨트랙트 호출(send, call, callcode, delegatecall)
//solidity-kr.readthedocs.io/ko/latest/index.html
Solidity — Solidity 0.5.10 documentation
Solidity는 스마트 컨트랙트를 구현하기 위한 컨트랙트 기반의 고급 프로그래밍 언어입니다. Solidity는 C++, Python, 그리고 JavaScript의 영향을 받아 만들어졌습니다. 그리고 Ethereum Virtual Machine(EVM)에서
solidity-kr.readthedocs.io
가스 고려사항
동적 크기 배열 피하기
다른 컨트랙트 호출 피하기
가스 비용의 추정
결론
이번 장에서는 스마트 컨트랙트를 사용하는 방법을 자세하게 알아봤고, 솔리디티 컨트랙트 프로그래밍 언어를 살펴봤다.
...
8장에서는 또 다른 컨트랙트용 프로그래밍 언어인 바이퍼(Vyper)에 대해 알아본다.
바이퍼와 솔리디티를 비교하여 설계상의 차이점을 보여주며 스마트 컨트랙트 프로그래밍에 대한 이해를 높여줄 것이다.
해당 내용 세미나
//www.umlcert.com/mastering_ethereum-5-1/
‘마스터링 이더리움' 세미나 5-1 – 7장. 스마트 컨트랙트와 솔리디티 | 뉴테크프라임
이번 세미나에서는 ‘7장. 스마트 컨트랙트와 솔리디티’를 다룹니다. 솔리디티를 전반적으로 다루기 때문에 분량이 꽤 많이 됩니다. 한 번에 다 읽어 내려고 하면 지칠 수 있고, 실습을 제대로
www.umlcert.com
EVM에 대한 내용
//steemkr.com/kr/@tenihil/introducing-ethereum-and-solidity-3
[모두의 연구소] Introducing Ethereum and Solidity 3장 요약본 — Steemkr
안녕하세요, 모두의 연구소 블록체인 연구실입니다. 10월 12일 3회차 스터디에서 진행한 Introducing Ethereum and Solidity의 3장 요약본입니다. 3장 EVM(이더리움 가상… by tenihil
steemkr.com
인터페이스와 라이브러리 관련 내용들
//merrily-code.tistory.com/103
솔리디티 - 06. 상속과 인터페이스
솔리디티는 "계약 지향 프로그래밍 언어" 인데요, 사실 배우다 보면 객체지향 프로그래밍과도 유사한 점이 많습니다. 상속을 통해 "고양이는 동물이다" 처럼 부분집합 관계에 있는 컨트랙트의
merrily-code.tistory.com
//medium.com/returnvalues/%EC%86%94%EB%A6%AC%EB%94%94%ED%8B%B0-v-0-5-2-%EC%8A%A4%ED%83%80%EC%9D%BC-%EA%B0%80%EC%9D%B4%EB%93%9C-19e2686201f6
솔리디티 v.0.5.2 스타일 가이드
By Yeonju Kang, Developer at ReturnValues ()
medium.com
//blog.naver.com/suresofttech/221204092938
스텁(stub)은 언제 어떻게 사용할까?
이번 포스팅에서는 스텁을 사용한 테스트 기법과 CodeScroll Controller Tester에서 제공하는 스텁 기...
blog.naver.com