336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이더리움 스마트 프로그래밍 언어인 Solidity 언어 예제를 기반으로 이더리움 스마트 컨트랙트의 생성과 함수 호출에 대해 설명하는 글입니다.


Solidity 프로그래밍에 앞서 Solidity의 런타임 환경인 이더리움이 추상적으로 무엇을 하고, 어떻게 프로그램이 동작하는지 이해할 필요가 있습니다. 우선 블록체인 기술을 P2P 분산 스토리지로 생각할 수 있습니다. 블록체인 자체에 대한 내용은 다른 포스팅으로 소개하겠습니다. 이더리움은 비트코인과 마찬가지로 어떤 주소로 이더(Ether, ETH)를 주고 받을 수 있고, 주고 받은 내역이 스토리지에 됩니다. 이더리움의 차별점은 거래내역만 저장할 뿐 아니라 이더를 입출금할 수 있는 코드와 그 실행 결과를 저장합니다. 즉, 이더리움 네트워크에서 이더를 주고 받을 수 있는 주소는 2가지 종류가 있습니다. 이더리움에서는 주소라는 말 대신 어카운트(Account)라는 말을 사용하기에 아래부턴 어카운트라고 지칭하겠습니다.


- 이더리움의 어카운트 종류


이더리움에는 두 가지 종류의 어카운트가 있습니다. 하나는 Externally Owned Account, 줄여서 EOA라고도 부르며, 공개키/비밀키 쌍을 만들고 공개키를 공개하는 원리를 생각하면 되며 만들기 쉽습니다. 이 공개키로 만든 주소를 이더를 보내줄 사람에게 알려주면 이더를 받을 수 있고, 받은 이더를 다른 사람에게 보내려면 비밀키로 서명하여 네트워크에 전파하면 됩니다. 서명된 거래내역(트랜잭션)이 어떻게 다른 노드들에 의해 받아들여지고 위변조가 불가능해지는지는 비트코인 화이트페이퍼(https://bitcoin.org/bitcoin.pdf)를 참고하는 것을 추천합니다. 디테일로 들어가면 이더리움과 비트코인은 다르지만 키 아이디어를 이해하는데에는 효과적입니다. 다른 어카운트 종류 하나는 Contract 입니다. 저번 포스트에 이어 코드를 우선 보겠습니다.


위의 Contract는 bet()을 호출할 때 받은 돈을 prize_money로 누적시켜 기억해뒀다가 10번째 호출하는 사람에게 몰아주는 복권입니다. 실질적으로는 누구나 count 값을 알 수 있기 때문에 실제로 쓰이긴 어려운 예제입니다. 저번 예제과 다르게 payable이나 msg.value, msg.sender.transfer 등이 나타나면서 설명이 필요할 것 같습니다. payable은 이 함수를 호출할 때 이더를 보낼 수 있다는 것을 의미합니다. payable이 아닌 경우 이 함수를 호출할 때 이더를 보낼 수 없습니다. msg는 특수한 객체인데, 이 함수가 호출된 컨텍스트 정보를 얻어올 수 있습니다. msg.value는 전달된 이더 값이고, msg.sender는 이더를 보낸 어카운트의 주소입니다. Solidity에서는 주소 타입이 있어 balance()나 transfer() 등을 통해 해당 어카운트의 잔고를 확인하거나 이더를 보내는 함수를 호출할 수 있습니다.


사실, 위의 예제를 더 정확히 이해하기 위해서는 실행 환경에 대해 더 이해할 필요가 있어 그 얘기를 하려 합니다.


- Contract 인스턴스의 특정 함수를 실행시키는 방법

- Contract 인스턴스를 생성하는 방법


이더리움의 Contract 객체 생성이나 함수 호출은 트랜잭션에 의해 이루어집니다. 트랜잭션은 아래와 같은 정보를 포함합니다.


- 보내는 사람의 주소

- 받는 사람의 주소

- 이더

- 입력 데이터

- 가스 제한

- 가스 가격


가스에 관련된 내용은 이어질 포스팅에서 다루도록 하겠습니다. 보내는 주소/받는 주소/이더 외에 데이터 항목이 있다는 것에 주목하시면 됩니다. 함수를 호출하기 위해선 함수를 지정하는 Function Selector와 함수에 넘길 인자를 인코딩하여 전달해야 합니다. 기술적인 상세한 내용은 ABI 스펙 문서(https://solidity.readthedocs.io/en/develop/abi-spec.html)를 보면 됩니다. 만약 유효한 Function Selector가 아닌 경우 Contract에 정의되어 있는 Fallback 함수가 호출됩니다. Fallback 함수가 없으면 트랜잭션은 실패합니다. 아래는 위의 예제를 bet() 함수 대신 Fallback 함수로 바꾼 것입니다. Fallback 함수는 해당 Contract 내의 이름이 없는 유일한 함수이며 함수 인자를 받거나 값을 리턴하지 않습니다. Fallback 함수로 바꾸면 이 Contract에 그냥 이더를 보내는 트랜잭션으로 함수를 호출한 것과 같은 효과를 낼 수 있습니다.

스마트 컨트랙트의 보안에서 신경써야 할 점 중 하나는 msg.sender를 포함해서 어떤 address가 Contract 일 수 있다는 점입니다. msg.sender.transfer()를 호출하는 순간 단순히 내가 이더를 보내는 것이 아닌 다른 사람이 작성한 Fallback 함수가 실행될 수 있다는 점입니다.


다음은 Contract의 생성(혹은 deploy)인데, 이더리움은 Contract의 생성을 위한 프로토콜을 가지고 있습니다. 받는 사람의 주소를 0x0으로 주고 입력 데이터에 Solidity 코드를 컴파일한 EVM Bytecode를 넘겨주는 것입니다. Constructor에 전달해줘야 하는 인자가 있다면 역시 ABI 인코딩하여 넘겨줘야 합니다. 인스턴스의 파괴는 해당 인스턴스 내에서 selfdestruct 함수를 호출해야 합니다. 인스턴스의 주의해야 할 특징으로는 한 번 deploy 된 코드는 바꿀 수 없다는 점입니다. 코드를 업데이트 해야 하는 요구사항이 있을 경우 업데이트된 Contract의 인스턴스를 deploy 한 뒤 기존 인스턴스의 변수를 새 인스턴스로 이전하거나 Proxy 역할을 하는 Contract를 써야 하는 등의 문제가 있습니다. 만약 selfdestruct를 호출할 수 없는 Contract는 이더리움 프로토콜이 바뀌지 않는 한 영원히 파괴되지 않습니다. 


여기까지 이더를 주고 받을 수 있는 스마트 컨트랙트 예제와 컨트랙트의 생성과 함수 호출에 대해 살펴봤습니다. 설명을 위해 간단한 예제만 보여드렸지만 응용은 다양하게 있을 수 있습니다. 대표적인 예제로는 투표 시스템, 크라우드 펀딩, 경매 시스템 등이 있습니다. 이런 응용들을 블록체인으로 하면서 얻게 되는 장점으로는 암호학적으로 증명되는 투명성과 거래의 보장입니다. 크라우드 펀딩을 예로 설명하면 환불과 관련된 규정을 적고 고객을 설득 할 필요없이 코드로 작성하여 공개하면 됩니다. 단점으로는 한번 배포된 계약은 사업 주체의 통제에서 벗어나 해커의 공격 대상이 될 수 있다는 점입니다.

+ Recent posts