
가빈의 Web3 이상국: 폴카닷 스마트 계약 및 가상 머신 진화사
저자: 구오즈
폴카닷은 오래된 블록체인 프로젝트로, Web3 산업에 종사하는 사람들이라면 그들의 제품을 사용하지 않았더라도 적어도 이 프로젝트는 알고 있을 것이다.

최근 폴카닷은 새로운 JAM 아키텍처를 발표하며 눈길을 끌었고, 창립자가 DOOM 게임을 시연하면서 폴카닷의 새로운 가능성을 보여주었다. 이로 인해 나는 큰 연구 관심을 갖게 되었으며, 폴카닷 프로젝트는 규모가 크기 때문에 폴카닷 체인, 서브스트레이트 개발 프레임워크, 리레이어/패러렐 체인 등 다양한 요소들이 있지만, 분량과 집중력을 고려하여 이번에는 내가 가장 관심 있는 실행 계층 즉 가상 머신(Virtual Machine) 라인을 중심으로 발전 역사와 현재 상황, 관련 정보를 정리해보려 한다.
서막
예전에 이더리움이 설립될 무렵, Gavin Wood는 이더리움에 대한 관심으로 이더리움 프로젝트 개발에 합류했다. 당시 이더리움은 아직 초기 프레임워크 수준이었으나, Gavin이 합류한 후 기술적으로 실현 가능하게 되었다. 그가 이더리움에 기여한 내용은 다음과 같다:
(1) 이더리움 PoC-1(Proof of Concept-1) 완성; (2) 거의 혼자서 이더리움 최초의 C++ 클라이언트 버전을 완성; (3) 이더리움 기술 명세서인 옐로우북(Yellow Book) 작성; (4) 스마트 컨트랙트 개발용 고급 언어인 Solidity 발명.
이러한 역사에 대해 관심이 있다면 『만물에 대한 연결점: 이더리움과 미래 디지털 금융』을 참고할 수 있고, Gavin Wood의 전설적인 이야기는 인터넷에서 쉽게 검색할 수 있으므로 여기서는 생략한다.
Solidity와 EVM에 주목해보자. 먼저 간단한 Solidity 카운터 예제 코드를 살펴보자:
pragma solidity ^0.8.3; contract Counter { uint public count; function get() public view returns (uint) { return count; } function inc() public { count += 1; } function dec() public { count -= 1; } }
이 예제는 데이터베이스의 단일 슬롯으로 볼 수 있는 상태 변수 count를 선언하며, 이를 관리하는 코드를 통해 조회 및 수정이 가능하다. 본 예제에서는 컨트랙트가 변수 값을 수정하거나 조회할 수 있는 함수 inc, dec, get을 정의하고 있다.
Solidity 컴파일러 solc로 컴파일하면 아래와 같은 바이트코드를 얻을 수 있으며, JSON-RPC를 통해 노드에 배포되면 실행 계층에서 먼저 합의를 거친 후 EVM에서 실행된다.
6080604052348015600e575f80fd5b506101d98061001c5f395ff3fe608060405234801561000f575f80fd5 b506004361061004a575f3560e01c806306661abd1461004e578063371303c01461006c5780636d4ce63c14 610076578063b3bcfa8214610094575b5f80fd5b61005661009e565b60405161006391906100f7565b60405 180910390f35b6100746100a3565b005b61007e6100bd565b60405161008b91906100f7565b604051809103 90f35b61009c6100c5565b005b5f5481565b60015f808282546100b4919061013d565b92505081905550565 b5f8054905090565b60015f808282546100d69190610170565b92505081905550565b5f819050919050565b 6100f1816100df565b82525050565b5f60208201905061010a5f8301846100e8565b92915050565b7f4e487 b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61 0147826100df565b9150610152836100df565b925082820190508082111561016a57610169610110565b5b9 2915050565b5f61017a826100df565b9150610185836100df565b925082820390508181111561019d576101 9c610110565b5b9291505056fea26469706673582212207b7edaa91dc37b9d0c1ea9627c0d65eb34996a5e3 791fb8c6a42ddf0571ca98164736f6c634300081a0033
이것을 어셈블리 명령어 형식으로 보면 다음과 같다:
PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xE JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH2 0x1D9 DUP1 PUSH2 0x1C PUSH0 CODECOPY PUSH0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0xF JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x4A JUMPI PUSH0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x6661ABD EQ PUSH2 0x4E JUMPI DUP1 PUSH4 0x371303C0 EQ PUSH2 0x6C JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH2 0x76 JUMPI DUP1 PUSH4 0xB3BCFA82 EQ PUSH2 0x94 JUMPI JUMPDEST PUSH0 DUP1 REVERT JUMPDEST PUSH2 0x56 PUSH2 0x9E JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x63 SWAP2 SWAP1 PUSH2 0xF7 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x74 PUSH2 0xA3 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x7E PUSH2 0xBD JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x8B SWAP2 SWAP1 PUSH2 0xF7 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x9C PUSH2 0xC5 JUMP JUMPDEST STOP JUMPDEST PUSH0 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x1 PUSH0 DUP1 DUP3 DUP3 SLOAD PUSH2 0xB4 SWAP2 SWAP1 PUSH2 0x13D JUMP JUMPDEST SWAP3 POP POP DUP2 SWAP1 SSTORE POP JUMP JUMPDEST PUSH0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x1 PUSH0 DUP1 DUP3 DUP3 SLOAD PUSH2 0xD6 SWAP2 SWAP1 PUSH2 0x170 JUMP JUMPDEST SWAP3 POP POP DUP2 SWAP1 SSTORE POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xF1 DUP2 PUSH2 0xDF JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0x10A PUSH0 DUP4 ADD DUP5 PUSH2 0xE8 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x11 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH2 0x147 DUP3 PUSH2 0xDF JUMP JUMPDEST SWAP2 POP PUSH2 0x152 DUP4 PUSH2 0xDF JUMP JUMPDEST SWAP3 POP DUP3 DUP3 ADD SWAP1 POP DUP1 DUP3 GT ISZERO PUSH2 0x16A JUMPI PUSH2 0x169 PUSH2 0x110 JUMP JUMPDEST JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH2 0x17A DUP3 PUSH2 0xDF JUMP JUMPDEST SWAP2 POP PUSH2 0x185 DUP4 PUSH2 0xDF JUMP JUMPDEST SWAP3 POP DUP3 DUP3 SUB SWAP1 POP DUP2 DUP2 GT ISZERO PUSH2 0x19D JUMPI PUSH2 0x19C PUSH2 0x110 JUMP JUMPDEST JUMPDEST SWAP3 SWAP2 POP POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH28 0x7EDAA91DC37B9D0C1EA9627C0D65EB34996A5E3791FB8C6A42DDF057 SHR 0xA9 DUP2 PUSH5 0x736F6C6343 STOP ADDMOD BYTE STOP CALLER
컴파일 원리 측면에서 실행 흐름을 보면 다음과 같다: Solidity 소스 코드 → 어휘 분석기 → 구문 분석기 → 컴파일 → 바이트코드 → 가상 머신 → 해석 실행
맞다. 컴퓨터 업계에서는 단지 새로운 프로그래밍 언어일 뿐이지만, 당시로서는 매우 대단한 일이었다. 이더리움 개발 프로젝트에 참여한 지 2년 만에 이더리움은 예정대로 출시되었다. 만약 V 신이 이더리움의 형태를 만들었다면, Gavin은 이더리움에게 영혼을 부여했다. 비트코인은 전자 결제 시스템이지만, 이더리움은 블록체인을 프로그래머블하게 만들었고, "월드 컴퓨터(World Computer)"라는 슬로건을 내걸며 모든 것이 달라졌다.
Web 3.0
Gavin은 여전히 이더리움 공동 창립자이자 CTO였던 2014년 4월 17일, 「Insights into a Modern World」 블로그에 글 한 편을 게시했다: DApps: What Web 3.0 Looks Like[1]. 이 글에서 그는 자신이 생각하는 Web3.0 시대의 모습과 구성 요소 네 가지를 포괄적으로 설명했다. Web3.0이라는 개념이 얼마나 유명하고 영향력이 큰지는 모두가 잘 알고 있으며, Gavin은 기술뿐 아니라 앞선 안목도 가지고 있었다. Web 3.0의 역사와 논쟁에 대해서는 위키백과 Web3 항목[2]을 참고할 수 있고, 미국의 기업가이자 벤처 캐피탈리스트인 노바·스피박[3]은 Web3.0의 정의를 현재 각 기술 트렌드가 새로운 성숙 단계로 나아가는 구체적 표현까지 확장할 것을 제안했다. 다음은 발췌한 내용이다:
• 인터넷 어디서나 접속 가능: 광대역 네트워크의 보급과 발전, 모바일 통신 장치의 인터넷 접속 (예: 태블릿 PC)
• 네트워크 컴퓨팅: "SaaS 서비스"의 비즈니스 모델, 웹 서비스 상호 운용성, 분산 컴퓨팅, 그리드 컴퓨팅 및 유틸리티 컴퓨팅("클라우드 컴퓨팅"이라고도 함).
• 오픈 기술: 오픈 API 및 프로토콜, 오픈 데이터 형식, 오픈소스 소프트웨어 플랫폼 및 오픈 데이터(크리에이티브 커먼즈, 오픈 데이터 라이선스 등 포함).
• 오픈 아이덴티티: OpenID, 오픈 평판, 도메인 간 아이덴티티 및 프로필.
• 스마트 네트워크: 자원 기술 설명 프레임워크(RDF), 웹 온톨로지 언어(OWL), SWRL, SPARQL 등의 의미 웹 기술 및 선언형 데이터 저장 기반의 의미 응용 프로그램 플랫폼.
• 분산 데이터베이스: 의미 웹 기술로 구현되는 세계 데이터베이스("World Wide Database").
• 스마트 애플리케이션: 일반 언어 처리, 머신 러닝, 머신 추론, 자율 에이전트.

2015년 말, Gavin은 이더리움을 떠났다.
이후 그는 Parity Technologies를 설립하고 Rust 언어로 작성된 이더리움 클라이언트를 개발하여 일시적으로 이더리움 생태 지갑 시장을 독점하기도 했다. Gavin이 이더리움을 떠난 이유는 알 수 없지만, 우리가 아는 것은 Gavin의 비전은 완전히 새로운 탈중앙화 인터넷 세상을 구축하는 것이라는 점이다.
"이더리움은 나에게 기술의 실현 가능성을 실험하는 프로토타입이었다. 이더리움은 내 학교였고, 나는 그 학교를 졸업했으며, 더 많은 일을 해보고 싶다."
"사실 이더리움에서 제가 가장 많이 배운 것은 기술이 아니라 사회적 경험입니다. 거버넌스가 바로 그 중 하나죠. 블록체인 시스템에서 거버넌스를 통해 시스템 능력을 향상시키는 것이 중요하다고 생각합니다. 이것은 혁명적인 새로운 특성이 될 것이며, 이것이 바로 이더리움이 하지 못한 부분입니다."
이더리움 재직 기간 동안 Gavin은 항상 실천자였지만, 설계자는 아니었으며, 계속해서 새로운 혁신을 준비하고 있었다.
폴카닷의 탄생
일 년 후, Gavin은 오랫동안 마음속에 맴돌던 문제를 해결하고 2016년 폴카닷 백서를 발표했다. 많은 사람들이 알고 있듯이, 폴카닷은 확장성 문제를 해결할 뿐만 아니라 서로 독립된 블록체인이 통신할 수 있도록 하는, 즉 크로스체인 문제를 해결하려 한다. 하지만 폴카닷에 대해 가장 먼저 알아야 할 것은 바로 샤딩(sharding)이며, 극한까지 샤딩을 적용하면 그것이 바로 폴카닷이기 때문이다.
폴카닷 창립자 Gavin의 말이 이를 더욱 잘 설명해 준다:
"폴카닷(폴카닷)의 설계 논리는 직접적으로 상호 운용성과 연결되지 않는다. 우리는 이더리움의 샤딩 기술이 나오기를 기다렸다. 하지만 샤딩은 계속 나오지 않았고, 지금도 나오지 않았다. 그래서 나는 더 확장 가능한 '이더리움'을 스스로 만들어 보기로 했고, 설계 과정에서 샤딩 개념을 극한까지 밀어붙였다. 결국 샤딩을 아예 없애고 독립된 체인을 설계하기로 했다. 이렇게 설계하면 서로 다른 체인들 사이에서 정보를 교환할 수 있으며, 최종 결과는 공유된 컨센서스 계층을 통해 통신하는 것이다."
그렇다면 우리는 어떻게 샤딩을 이해해야 할까? 우선 이더리움의 난관부터 살펴보자. 이더리움의 성능 문제는 오랫동안 고질적인 문제였다. 2018년 인기 있었던 크립토키티(CryptoKitties)로 인해 심각한 정체 현상이 발생했으며, 이는 트랜잭션 시간을 증가시키고 수수료를 높이는 결과를 초래했다. 마치 은행에서 업무를 볼 때 은행에 창구가 하나뿐이고 처리 속도가 느릴 경우 고객이 많아지면 줄을 서서 기다려야 하는 것과 같다.
하지만 은행에 여러 개의 창구가 있어 동시에 업무를 처리한다면 줄을 설 필요가 없을 수도 있다. 이것이 바로 샤딩의 기본 논리로, 전체 네트워크의 노드들을 샤드(shard)라고 불리는 여러 구역으로 나누고, 다수의 트랜잭션을 각기 다른 샤드들이 처리하게 함으로써 효율을 극대화하는 것이다.
따라서 폴카닷에서는 각 샤드가 핵심 로직을 담당하며, 병렬 트랜잭션 처리와 데이터 교환이 가능하고, 궁극적으로 여러 블록체인을 하나의 네트워크에 연결한다.
폴카닷의 등장은 단순히 이더리움 2.0의 개념을 따라잡거나 넘어서는 것을 넘어, 폴카닷 안에는 수많은 이더리움이 존재할 수 있다는 창의적인 점이 있다. 이제 그것은 단순한 블록체인이 아니라, "폴카닷은 다양한 사회적 혁신을 위한 진정으로 개방되고 자유로운 플랫폼을 제공하고자 한다."
이것이 바로 Web3의 이상이며, 폴카닷의 이상이며, Gavin의 이상이다.
폴카닷 1.0
폴카닷의 리레이어 체인 자체는 스마트 컨트랙트를 지원하지 않지만, 연결된 패러렐 체인[4]은 상태 전이 규칙을 자유롭게 정의할 수 있으므로 스마트 컨트랙트 기능을 제공할 수 있다. 다른 생태계와의 차이점은 폴카닷 맥락에서 패러렐 체인과 스마트 컨트랙트가 스택의 다른 계층에 있다는 점이다. 스마트 컨트랙트는 패러렐 체인 위에 위치한다. 패러렐 체인은 일반적으로 1층 블록체인으로 묘사되며, 차이점은 자체 보안을 구축할 필요가 없고 업그레이드 및 상호 운용이 가능하다는 점이다.
폴카닷은 개발자들이 스마트 컨트랙트를 구축할 수 있도록 유연성을 제공하며, EVM(이더리움 가상 머신)에서 실행되는 Solidity 컨트랙트뿐만 아니라 ink!를 사용하는 Wasm 기반의 컨트랙트도 지원한다:
EVM과 호환되는 컨트랙트
폴카닷 생태계는 Frontier[5]라는 도구 세트 덕분에 이더리움 가상 머신(EVM)을 지원한다. Frontier는 서브스트레이트 기반 블록체인이 네이티브로 이더리움 스마트 컨트랙트를 실행하고 이더리움과 호환되는 API/RPC 인터페이스를 통해 이더리움 생태계와 원활하게 상호 작용할 수 있게 해준다. 컨트랙트는 Solidity 또는 Vyper 등의 언어로 작성되며, Astar, Moonbeam, Acala 등의 폴카닷 패러렐 체인을 포함하여 EVM은 블록체인에서 널리 표준화되어 있다. 이러한 호환성은 컨트랙트가 최소한의 수정만으로 여러 네트워크에 배포될 수 있도록 하여 잘 정비되고 광범위한 개발 생태계의 혜택을 누릴 수 있게 한다.
예를 들어, Astar[6]는 폴카닷의 핵심 스마트 컨트랙트 플랫폼으로, 독특한 멀티 가상 머신 방식을 통해 EVM과 WebAssembly(Wasm) 스마트 컨트랙트를 동시에 지원한다. 이 이중 VM 지원은 개발자가 선호하는 프로그래밍 환경을 선택할 수 있도록 하면서도 이더리움과의 완전한 호환성을 유지한다. 이 플랫폼의 런타임[7]은 서브스트레이트 상에서 FRAME으로 구축되었으며, 폴카닷 SDK의 핵심 구성 요소들과 독특한 기능을 처리하기 위한 맞춤형 모듈이 결합되어 있다.

이러한 체인들은 일반적으로 기존의 컨트랙트 모듈을 사용하면서 추가적인 혁신을 수행한다. 예를 들어: Phala[8]: 신뢰 실행 환경(TEE)에서 컨트랙트 모듈을 사용하여 기밀 스마트 컨트랙트 실행 및 상호 운용성 구현. Aleph Zero[9]: 제로 지식 환경에서 컨트랙트 팔레트 사용. t3rn[10]: 컨트랙트 모듈을 빌딩 블록으로 사용하여 스마트 컨트랙트의 멀티체인 실행 구현. EVM과 호환되는 패러렐 체인(Aster, Moonbeam, Acala 등)에 대한 더 많은 기술 정보는 공식 문서 참조: 패러렐 체인 컨트랙트[11]
Wasm (ink!) 컨트랙트:
폴카닷은 FRAME 프레임워크를 통해 Contracts 모듈[12]을 제공하며, 이 모듈은 WebAssembly를 컨트랙트의 실행 환경으로 사용한다. 이론적으로 Wasm으로 컴파일할 수 있는 모든 언어를 스마트 컨트랙트 개발에 사용할 수 있지만, 최적화와 편의성을 고려하여 Parity는 특별히 ink![13]를 출시했다.
ink!를 논의하기 전에 먼저 Substrate[14]란 무엇인지와 그 컨트랙트 모듈(pallet-contracts)을 명확히 해야 한다. Substrate는 독립된 블록체인이나 Kusama[15] 또는 폴카닷[16]에 연결되는所谓 패러렐 체인을 구축하기 위한 프레임워크이다.
Substrate는 많은 모듈을 포함하고 있으며, Substrate 용어에서는 팔레트(pallet)라고 부른다. Substrate는 현대적인 블록체인에 일반적으로 필요한 요구 사항—스테이킹, 토큰화폐, NFT, 거버넌스 등을 충족시키는 일련의 모듈을 함께 제공한다.
또한 Substrate는 스마트 컨트랙트를 위한 모듈도 제공하는데, 이것을 Contracts 팔레트라고 한다. 만약 Substrate에서 패러렐 체인을 개발했다면, 이 팔레트를 포함함으로써 쉽게 스마트 컨트랙트 기능을 추가할 수 있다. 이 모듈은 단지 실행 환경일 뿐이며, WebAssembly 파일을 입력으로 받는다. 이 모듈의 스마트 컨트랙트는 WebAssembly(Wasm) 타겟 아키텍처로 컴파일되어야 한다.
ink!는 여기서 어떻게 작용하는가? ink!는 프로그래밍 언어이며, 구체적으로는 인기 있는 Rust 프로그래밍 언어의 임베디드 도메인 특화 언어(eDSL)이다. 즉, 기존의 모든 Rust 문법과 새로 추가된 일부 세부사항을 사용하여 이 언어를 스마트 컨트랙트 세계에 적합하게 만들 수 있다는 의미이다. 컨트랙트 모듈은 이러한 ink! 컨트랙트를 받아 안전하게 실행한다. 간단히 말해:
ink!를 사용하면 Contracts 팔레트가 포함된 Substrate 기반 블록체인에 Rust로 스마트 컨트랙트를 작성할 수 있다.
ink!는 새로운 언어를 만들지 않고, 명확한 "컨트랙트 형식"을 갖춘 표준 Rust이며, 전용 #[ink(...)] 속성 매크로를 포함한다. 이러한 속성 매크로는 ink! Rust 스마트 컨트랙트의 각 부분이 무엇을 의미하는지를 알려주며, 궁극적으로 ink!가 폴카닷 SDK와 호환되는 Wasm 바이트코드 생성에 필요한 모든 작업을 수행할 수 있게 해준다. ink! 스마트 컨트랙트는 Wasm으로 컴파일되기 때문에 샌드박스 실행을 통해 높은 실행 속도, 플랫폼 독립성 및 강화된 보안성을 제공한다.
간단한 ink! 컨트랙트를 살펴보자. 이 컨트랙트는 저장소에 불리언 값을 저장한다. 컨트랙트 생성 후 불리언 값을 true로 설정한다. 컨트랙트는 두 가지 함수를 공개한다: 하나는 불리언 값의 현재 값을 읽는 함수(fn get()), 다른 하나는 값을 반대 불리언 값으로 전환하는 함수(fn flip()).
#[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn new(init_value: bool) -> Self { Self { value: init_value } } #[ink(message)] pub fn flip(&mut self) { self.value = !self.value; } #[ink(message)] pub fn get(&self) -> bool { self.value } }}
Solidity가 제공하는 기능과 거의 비슷해 보이며, Storage 저장소, Message 메시지, Errors 오류, Event 이벤트 등이 있다. 컨트랙트 개발자들에게는 ink!로 스마트 컨트랙트를 작성할 수 있을 뿐만 아니라 다른 언어를 사용할 수도 있다는 의미가 된다: Solidity의 Solang 컴파일러[17], AssemblyScript의 ask![18] (아래 참조)
import { env, Pack } from "ask-lang";import { FlipEvent, Flipper } from "./storage";@contractexport class Contract { _data: Pack<Flipper>; constructor() { this._data = instantiate<Pack<Flipper>>(new Flipper(false)); } get data(): Flipper { return this._data.unwrap(); } set data(data: Flipper) { this._data = new Pack(data); } @constructor() default(flag: bool): void { this.data.flag = flag; } @message({ mutates: true }) flip(): void { this.data.flag = !this.data.flag; let event = new FlipEvent(this.data.flag); // @ts-ignore env().emitEvent(event); } @message() get(): bool { return this.data.flag; }}
새로운 언어를 추가하는 것은 어렵지 않다. WebAssembly용 언어 컴파일러만 있으면 Contracts pallet API를 구현할 수 있다.
현재 이 API는 저장소 접근, 암호화 기능, 환경 정보(예: 블록 번호), 난수 생성 또는 컨트랙트 자기 종료 함수 접근 등 스마트 컨트랙트가 필요로 할 수 있는 모든 기능에 사용할 수 있는 약 15~20개의 함수를 포함하고 있다. 모든 기능을 해당 언어로 구현할 필요는 없다—ink!의 "Hello, World!"는 단지 여섯 개의 API 함수만 필요로 한다. 다음 패턴은 이러한 관계를 설명한다:

EVM과 비교할 때, ink!와 Contracts pallet을 선택하는 데는 많은 장점이 있다. 본문에서 자세히 설명된 몇 가지 장점을 요약하자면:
• ink!는 그냥 Rust다—clippy, crates.io[19], IDE 등 모든 일반적인 Rust 도구를 사용할 수 있다.
• Rust는 수년간의 언어 연구가 융합된 언어로, 안전하고 빠르다. 또한 Solidity와 같은 오래된 스마트 컨트랙트 언어로부터 주요 교훈을 얻어 ink! 언어 설계에 반영했다. 예를 들어, 기본적으로 오버플로우를 비활성화하거나 함수를 기본적으로 비공개로 설정하는 등 더 합리적인 기본 동작을 선택했다.
• Rust는 StackOverflow에서 7년 연속 가장 사랑받는 프로그래밍 언어로 선정된 놀라운 언어다(출처[20]).
• 회사라면 스마트 컨트랙트 개발자를 고용할 때 Solidity 개발자보다 훨씬 더 큰 Rust 생태계에서 인재를 영입할 수 있다.
• ink!는 서브스트레이트에 원생(native)이며, 동일한 타입 시스템처럼 유사한 원시(primitive)를 사용한다.
• 컨트랙트에서 패러렐 체인으로의 이주 경로가 매우 명확하다. ink!와 서브스트레이트 모두 Rust이기 때문에 개발자는 대부분의 코드, 테스트, 프론트엔드 및 클라이언트 코드를 재사용할 수 있다.
• WebAssembly는 블록체인 세계를 넘어 산업 표준이다. Google, Apple, Microsoft, Mozilla, Facebook 등의 대기업들이 지속적으로 개선하고 있다.
• WebAssembly는 Rust, C/C++, C#, Typescript, Haxe, Kotlin 등을 포함하여 스마트 컨트랙트 개발자가 사용할 수 있는 언어군을 확장한다. 즉, 익숙한 어떤 언어로든 스마트 컨트랙트를 작성할 수 있다. 이 설계는 언어와 실행 아키텍처의 긴밀한 결합보다 더 앞선 전망을 갖추고 있다.
본 섹션에 대한 자세한 내용은 What is Parity's ink!?[21]를 참고하라.
폴카닷 2.0 / JAM
2월 28일 Gavin Wood는 JAM Tour 상하이 행사에서 JAM에서 DOOM 게임을 실행하는 것을 처음으로 공개 시연했다! 이것은 블록체인 업계의 역사적인 순간으로, JAM는 블록체인을 단순한 네트워크가 아닌, DOOM과 같은 일반 소프트웨어를 실행할 수 있는 강력한 슈퍼컴퓨터 플랫폼으로 만들며, 강력한 컴퓨팅 능력과 낮은 지연을 제공한다.

다른 것은 잠시 접어두고, PolkaVM 관련 소스코드를 며칠간 읽은 내 판단으로는 실제로 발생한 일이다. 핵심은 PolkaVM이 Host에서 VM을 실행하고 내보내기 인터페이스를 제공한 후, VM 위에서 RISC-V 버전의 Doom 게스트 버전 코드를 실행했다는 점이다.
소스코드는 여기에 있다:
https://github.com/paritytech/polkavm/tree/master/examples/doom
이번에 가장 중요한 새로운 스마트 컨트랙트 솔루션의 구성 요소를 살펴보자:
Revive Pallet
Revive Pallet[22]은 런타임에 PolkaVM 스마트 컨트랙트 배포 및 실행 기능을 제공한다. 이것은 pallet_contracts를 대폭 수정한 분기이다. 이러한 컨트랙트는 RISC-V로 컴파일할 수 있는 모든 언어로 작성할 수 있다. 현재 공식적으로 지원되는 언어는 Solidity(Revive[23]를 통해)와 Rust(Rust 예제는 fixtures 디렉터리 참조)뿐이다.
컨트랙트 언어 수준에서 이더리움과 호환: Solidity로 컨트랙트를 작성하고, 이더리움 JSON RPC 및 MetaMask 등의 이더리움 지갑을 통해 노드와 상호 작용할 수 있다. 백엔드에서는 YUL에서 다시 컴파일하여 RISC-V로 변환함으로써 EVM이 아닌 PolkaVM에서 실행한다. 간편한 조작을 위해 Westend Asset Hub Parachain[25]에 컨트랙트를 RISC-V로 컴파일하고 배포할 수 있는 맞춤형 REMIX[24] 웹 프론트엔드를 사용할 수 있다.
Revive
Revive[26]는 "Solidity to PolkaVM" 컴파일러 프로젝트의 총칭으로, 여러 구성 요소(YUL 프론트엔드 및 resolc 실행 파일 자체 포함)를 포함한다. resolc는 revive 구성 요소를 투명하게 사용하여 컴파일된 컨트랙트 아티팩트를 생성하는 단일 진입점 프론트엔드 바이너리 실행 파일의 이름이다. Solidity 컨트랙트를 PolkaVM에서 실행 가능한 RISC-V 코드로 컴파일함으로써 폴카닷에서 Solidity 컨트랙트를 실행할 수 있게 한다.
이를 위해 컴파일러가 필요하다. 그 작동 원리는 원래의 solc 컴파일러를 사용한 후 중간 표현(YUL) 출력을 RISC-V로 다시 컴파일하는 것이다. LLVM[27]은 인기 있고 강력한 컴파일러 프레임워크로 백엔드로 사용되며, 최적화 및 RISC-V 코드 생성에서 중요한 역할을 한다. revive는 주로 생성된 YUL 중간 표현(IR)을 solc에서 LLVM IR로 낮추는 일을 담당한다.

이 방법은 높은 수준의 이더리움 호환성, 우수한 컨트랙트 성능 및 실현 가능한 공학적 노력 사이에서 좋은 균형을 제공한다. 완전한 Solidity 컴파일러를 구현하는 것과 비교하면 작업량이 훨씬 적다는 장점이 있다. 이러한 방법을 선택함으로써 Solidity 및 그 모든 다양한 버전의 특이한 점과 특이함을 모두 지원할 수 있다.
PolkaVM
PolkaVM[28]은 RISC-V 기반의 범용 사용자 수준 가상 머신이다. 이것은 경쟁 기술과 비교했을 때 가장 명백한 변화다. EVM 대신 새로운 맞춤형 가상 머신을 사용하여 컨트랙트를 실행한다. 현재 런타임 자체에 PolkaVM 인터프리터가 포함되어 있다. 이후 업데이트에서는 클라이언트 내에서 실행되는 완전한 PolkaVM JIT를 제공할 예정이다.

• 기본적으로 안전하며 샌드박스 환경이다. 가상 머신에서 실행되는 코드는 별도의 프로세스에서 실행되어야 하며, 가상 머신 내부에 원격 코드 실행 권한을 가진 공격자가 있더라도 호스트 시스템에 접근할 수 없어야 한다.
• 실행 속도가 빠르다. VM에서 실행되는 코드의 런타임 성능은 최첨단 WebAssembly VM과 견줄 수 있어야 하며, 적어도 동일한 수준이어야 한다.
• 컴파일 속도가 빠르며, 단일 컴파일 O(n)을 보장한다. 새 코드를 가상 머신에 로드하는 것은 거의 즉시 이루어져야 한다.
• 메모리 사용량이 낮다. 가상 머신의 동시 인스턴스 당 기준 메모리 오버헤드는 128KB를 초과하지 않아야 한다.
• 작은 바이너리 파일. 이 VM용으로 컴파일된 프로그램은 가능한 한 적은 공간을 차지해야 한다.
• 가상 주소 공간을 낭비하지 않는다. VM은 샌드박스 목적을 위해 GB 단위의 가상 주소 공간을 미리 할당하지 않아야 한다.
• 완전한 결정성. 동일한 입력과 동일한 코드가 주어졌을 때 실행은 항상 완전히 동일한 출력을 반환해야 한다.
• 고성능 비동기 가스 측정 지원. 가스 측정은 저렴하고 결정적이며 합리적으로 정확해야 한다.
• 간단함. 프로그래머가 일주일 이내에 이 가상 머신과 완전히 호환되는 인터프리터를 작성할 수 있어야 한다.
• 버전화된 운영 의미론. 고객 프로그램이 관찰할 수 있는 의미에 대한 향후 변경 사항은 버전화되어 명시적으로 선택 가입해야 한다.
• 표준화. 이 가상 머신의 고객이 관찰 가능한 운영 의미론을 완전히 설명하는 사양이 있어야 한다.
• 크로스 플랫폼. 지원되지 않는 운영 체제 및 플랫폼에서는 VM이 인터프리터 모드로 실행된다.
• 최소 외부 의존성. 가상 머신은 기본적으로 독립적이어야 하며, 컴파일 속도가 빠르고 공급망 공격에 저항할 수 있어야 한다.
• 디버깅 및 성능 분석을 위한 내장 도구.
EVM과의 두 가지 근본적인 차이점은:
• 레지스터 머신—EVM은 스택 머신이다. 즉, 함수의 매개변수는 무한한 스택을 통해 전달된다. PolkaVM은 RISC-V 기반이며, 이는 레지스터 머신이라는 의미다. 즉, 매개변수는 제한된 레지스터 집합을 통해 전달된다. 이로 인해 하드웨어와의 변환 단계가 더욱 효율적이며, 유명한 레지스터 부족 x86-64 명령어 세트보다 적은 수의 레지스터를 선택함으로써 NP-hard 레지스터 할당 문제를 간단한 1대1 매핑으로 단순화하여 PolkaVM의 빠른 컴파일 시간을 실현한다.
• 워드 길이 감소—EVM은 256비트의 워드 길이를 사용한다. 즉, 모든 산술 연산이 이러한 큰 숫자를 처리해야 한다는 뜻이다. 이는 본질적인 명령어로 변환해야 하기 때문에 의미 있는 숫자 연산이 매우 느려진다. PolkaVM은 하드웨어가 네이티브로 지원하는 64비트 워드 길이를 사용한다. 즉, YUL(#Revive)를 통해 Solidity 컨트랙트를 변환할 때 여전히 256비트 산술을 사용하지만, YUL이 너무 낮은 수준이라 정수 유형을 자동으로 변환할 수 없다. 그러나 다른 언어로 컨트랙트를 작성하고 Solidity에서 원활하게 호출하는 것은 완전히 가능하다. 비즈니스 로직은 Solidity로 작성하고, 하위 구조는 더 빠른 언어로 작성하는 시스템을 상상해 보라. 파이썬에서 대부분의 무거운 작업이 C 모듈에 의해 수행되는 것과 유사하다.
요약
스마트 컨트랙트 프로그래밍 언어
스마트 컨트랙트 언어의 수는 해마다 증가하고 있다. 특히 초보자에게는 첫 번째 언어를 선택하는 것이 도전적일 수 있다. 선택은 주로 관심 있는 생태계에 달려 있지만, 일부 언어는 여러 플랫폼에 적합하다. 각 언어는 장단점이 있으며, 본문에서는 일일이 소개하지 않을 것이다.
왜 이렇게 많은 컨트랙트 언어가 있을까? 나는 다음과 같은 가능성들을 정리했다: 1) 기존 언어가 체인의 고유한 특성을 충족하지 못함; 2) 더 나은 성능, 보안, 비용; 3) 취향 :)
나는 컨트랙트 언어에 편견이 없으며, 다음은 다양한 목소리를 발췌한 것으로, 사용자 입장이나 언어 또는 VM 설계 관점에서 모두 다른 통찰을 얻을 수 있다.
• 왜 Solidity를 사용하지 않는가? Solidity는 존경받는 선구자지만, EVM의 많은 역사적 특이점에 얽매여 있다. 프로그래머가 기대하는 일반적인 기능이 부족하고, 타입 시스템은 상대적으로 표현력이 부족하며, 통합된 도구 생태계도 부족하다. Sway에서는 현대적인 도구 세트를 사용하여 스마트 컨트랙트를 설계할 수 있다. 제네릭, 대수적 타입, 특성 기반 다형성 등 기능이 풍부한 언어를 제공한다. 또한 코드 완성 LSP 서버, 포맷터, 문서 생성, 그리고 컨트랙트 실행 및 배포에 필요한 모든 것을 포함하는 통합되고 사용하기 쉬운 도구 체인을 제공하여 쉽게 원하는 기능을 구현할 수 있다. 우리의 표현적인 타입 시스템은 의미 오류를 잡아낼 수 있으며, 좋은 기본값을 제공하고 광범위한 정적 분석 검사를 수행하여(java.lang.Integer.pattern 사용 등) 컴파일 시간에 안전하고 올바른 코드를 작성할 수 있도록 한다.
via https://docs.fuel.network/docs/sway/
• 왜 Rust를 사용하지 않는가? Rust는 훌륭한 시스템 프로그래밍 언어이지만(Sway 자체도 Rust로 작성됨), 스마트 컨트랙트 개발에는 적합하지 않다. Rust가 훌륭한 이유는 제로 비용 추상화와 복잡한 빌림 검사기 메모리 모델을 통해 가비지 컬렉터 없이도 복잡한 프로그램에 인상적인 런타임 성능을 제공하기 때문이다. 블록체인에서는 실행과 배포 비용이 희소 자원이다. 메모리 사용률이 낮고 실행 시간이 짧아야 한다. 따라서 복잡한 메모리 관리는 일반적으로 비용이 너무 많이 들며 가치가 없고, Rust의 빌림 검사기는 아무런 이점 없이 부담이 된다. 일반적인 프로그래밍 언어는 일반 컴퓨팅 환경에서 실행된다고 가정하는 설계를 해야 하기 때문에 이러한 환경에 적합하지 않다. Sway는 친숙한 구문과 블록체인 환경의 특정 요구에 적합한 기능을 제공함으로써 Rust의 다른 모든 장점—현대적인 타입 시스템, 안전한 방법, 좋은 기본값—을 스마트 컨트랙트 개발자에게 가져오려고 한다.
via https://docs.fuel.network/docs/sway/
• Clarity 코드는 작성된 그대로 해석되고 제출된다. Solidity 및 기타 언어는 체인에 제출되기 전에 바이트코드로 컴파일된다. 스마트 컨트랙트 언어를 컴파일하는 위험은 두 가지 측면에서 발생한다. 첫째, 컴파일러는 복잡성의 한 층을 추가한다. 컴파일러의 오류로 인해 바이트코드가 예상과 다르게 되어 취약점을 유발할 수 있다. 둘째, 바이트코드는 인간이 읽을 수 없기 때문에 스마트 컨트랙트가 실제로 무엇을 하는지 검증하기 어렵다. 스스로에게 물어보라. 읽을 수 없는 계약서에 서명할 것인가? 당신의 대답이 '아니오'라면, 스마트 컨트랙트는 무엇이 다른가? Clarity에서는 당신이 보는 것이 바로 당신이 얻는 것이다.
via https://docs.stacks.co/concepts/clarity#clarity-is-interpreted-not-compiled
가상 머신 및 명령어 세트
우리가 잘 아는 JVM부터 블록체인 분야에서 획기적인 등장한 EVM까지, 내가 아는 가상 머신만 수십 개이며, 각기 다른 가상 머신 구현 방식이 다르다. 그 중 핵심인 인터프리터(Interpreter)는 일반적으로 가장 기본적인 실행 방식 중 하나이며, 특히 Just-In-Time(JIT) 컴파일 또는 Ahead-Of-Time(AOT) 컴파일 외에도 인터프리터는 여전히 코드 실행에 널리 사용되며, 바이트코드를 파싱하고 실행하는 역할을 한다.
인터프리터 예제
다음은 최소한의 본질적인 인터프리터를 보여주는 작은 예제이며, 다양한 최적화 메커니즘은 고려하지 않는다.
use std::collections::VecDeque; #[derive(Debug, Clone, Copy)] enum OpCode {Push(i32), Add, Sub, Mul, Div, Print} struct Interpreter { stack: Vec<i32>, } impl Interpreter { fn new() -> Self { Interpreter { stack: Vec::new() } } fn run(&mut self, bytecode: VecDeque<OpCode>) { for op in bytecode { match op { OpCode::Push(value) => self.stack.push(value), OpCode::Add => self.binary_op(|a, b| a + b), OpCode::Sub => self.binary_op(|a, b| a - b), OpCode::Mul => self.binary\_op(|a, b| a * b), OpCode::Div => self.binary\_op(|a, b| a / b), OpCode::Print => { if let Some(value) = self.stack.last() { println!("{}", value); } } } } }fn binary_op(&mut self, op: fn(i32, i32) -> i32) { if self.stack.len() < 2 { panic!("Stack underflow!"); } let b = self.stack.pop().unwrap(); let a = self.stack.pop().unwrap(); self.stack.push(op(a, b)); }} fn main() { let bytecode = VecDeque::from(vec!\[ OpCode::Push(10), OpCode::Push(20), OpCode::Add, OpCode::Push(5), OpCode::Mul, OpCode::Print, ]); let mut interpreter = Interpreter::new(); interpreter.run(bytecode); }
각 명령어는 하나의 opcode(작업 코드)로 구성되며, 매개변수가 있을 수 있고, 인터프리터는 스택(stack)을 사용하여 계산 데이터를 저장하며, 총 6개의 명령어만 있다.
명령어 세트 분류
위 인터프리터 예제에서 명령어의 수와 확장성은 가상 머신의 큰 방향을 결정한다. 내 분석에 따르면 가상 머신은 명령어 세트에 따라 다음과 같이 대략 4가지로 분류할 수 있다:
1. EVM이 대표하는 자체 제작 명령어 세트. 컴파일러, 명령어 설계 등 반복 작업이 많다. EIP-3855[29] 이전에 이미 141개의 명령어가 있었고, 계속해서 새로운 명령어가 추가되고 있다.
2. WASM은 즉시 사용 가능하며, 다수의 언어를 지원하지만 상대적으로 무겁다. 폴카닷 문서에서도 WASM의 이 점을 언급하고 있다. 나는 WASM의 장점이 자연스러운 다국어 지원에 있다고 생각한다. 어떤 체인이 단지 논리를 실행하고 상태를 account storage slot에 다소 무차별적으로 기록하고자 한다면, 이는 적합하다. 빠른 개발과 빠른 통합이 가능하지만, 단점은 명령어가 블록체인을 위해 특별히 설계되지 않았으며, 특수 기능을 지원하거나 축소하기 어렵다는 점이다(150개 이상의 명령어[30]).
여기서 또 언급할 것은 솔라나의 SVM으로, BPF 명령어를 실행한다. 임의의 프로그래밍 언어를 BPF 명령어의 동적 라이브러리로 컴파일할 수 있는데, WASM에 비해 다소 소수의 언어를 지원한다.
3. RISC-V 명령어 세트 기반. 예: PolkaVM과 현재 많은 zkVM 계열: ceno, eigen zkvm, jolt, mozak vm, nexus, o1vm, openvm, powdrVM, risc0, sp1, sphinx 등. 다른 것은 아직 연구하지 못했고, 내가 아는 PolkaVM과 Nexus zkVM만 언급하자면, 일반적인 RISC-V 명령어 해석을 구현했다. 현재 대부분의 언어는 GCC 또는 LLVM 컴파일 후 RISC-V 명령어로 출력할 수 있으므로, 언어 수준에서 시야를 열어 향후 다국어 지원의 기반을 마련했다. 기본 RV32I 명령어는 47개이며, 선택 확장 가능. x86의 3000개 이상 명령어와 비교하면 정말 간결하다.
4. 인터프리터형. 예: Stacks의 Clarity(Lisp), AO의 Lua, Mina의 Typescript 등. 요약하면, 왼쪽이 EVM이 대표하는 사설 명령어이고, 오른쪽이 개방적인 WASM이라면, RISC-V는 비교적 균형 잡힌 2차 개발의 좋은 선택이다. 먼저, 각 컴파일러가 이미 이 명령어 세트를 지원하며, 참조 구현이 많다. 또한 이를 기반으로 맞춤형 명령어 설계를 쉽게 할 수 있다.
추가: 멀티체인 스마트 컨트랙트의 미래 탐색
블록체인 생태계의 다양화 발전에 따라 독특한 기능을 지원하기 위해 자체 스마트 컨트랙트 언어를 출시하는 프로젝트가 점점 더 많아지고 있다(Solidity, Move, Cairo, Sway 등). 이러한 혁신은 기술 스택을 풍부하게 하지만, 새로운 학습 비용과 호환성 문제도 가져온다. 핵심적인 질문이 점차 드러난다: 성숙한 Solidity 컨트랙트를 신생 블록체인에 원활하게 배포할 수 있을까?
이를 위해 우리는 컴파일러 기술에 열정을 가진 몇몇 연구자들과 함께 Hummanta 컴파일러 프로젝트를 공동 발족했다. 이 프로젝트는 체인 간 장벽을 깨뜨려 스마트 컨트랙트 언어의 크로스체인 컴파일을 실현하며, Solidity, Move, Cairo, Sway 등의 언어를 EVM 및 PolkaVM, SolanaVM, MoveVM, FuelVM 등의 신생 VM으로 컴파일할 수 있도록 지원하는 것을 목표로 한다.

프로젝트 현재 진행 상황
우리는 세 가지 방향에서 이 비전을 추진하고 있다:
1. 구문 및 명령어 세트 표준화: 각 언어의 구문 정의와 가상 머신 명령어 세트를 체계적으로 정리하여 크로스체인 컴파일의 기반을 마련한다.
2. 컴파일러 도구 체인 개발: LALRPOP[31]을 기반으로 파서를 구축하고, Cranelift[32]/LLVM을 활용하여 코드 생성을 구현하며, 다국어에서 다중 대상 바이트코드로의 변환을 지원한다.
3. 통합 개발 경험: Cargo와 유사한 Hummanta CLI 도구[33]를 개발하여 컴파일에서 배포까지 전 과정을 지원한다.
TechFlow 공식 커뮤니티에 오신 것을 환영합니다
Telegram 구독 그룹:https://t.me/TechFlowDaily
트위터 공식 계정:https://x.com/TechFlowPost
트위터 영어 계정:https://x.com/BlockFlow_News












