[Cosmos-SDK] CosmWasm 소개 - 1

20030 단어 Cosmos-SDKCosmos-SDK

Introduction

  • CosmWasm은 Cosmos 생태계에서의 스마트컨트랙트 플랫폼
  • Cosmos-SDK 내에 플러그인 할 수 있는 모듈로 작성되어 있음

Getting Started

Installation

  • Go 설치
cd /usr/local

GO_VERSION=1.17.6

sudo curl -LO https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz

cat ~/.profile | grep /usr/local/go/bin || echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
cat ~/.profile | grep GOPATH= || echo 'export GOPATH=$(go env GOPATH)' >> ~/.profile
cat ~/.profile | grep GOPATH/bin || echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.profile
source ~/.profile

echo $GOPATH
go version
  • Rust 설치
# install rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
sudo cp ~/.cargo/bin/rustup /usr/local/bin

rustup default stable
cargo version
# If this is lower than 1.55.0+, update
rustup update stable

rustup target list --installed
rustup target add wasm32-unknown-unknown
  • wasmd
    • wasmd는 CosmosWasm 플랫폼의 backbone임
    • wasm smart contract가 동작하는 Cosmos zone 구현임
    • cosmos/gaia 레포지토리에서 포크 가능
git clone https://github.com/CosmWasm/wasmd.git
cd wasmd
git checkout v0.23.0
make install

# verify the installation
wasmd version

Setting up Environment

  • Contract를 실행할 환경이 필요하며 local network나 testnet 사용 가능
  • ㅇㄹㅁ

Downloading and Compiling Contract

Uloading and Interacting

Architecture

Multi-chain Contracts

  • Different Chain, Same Contract
    • CosmWasm은 Multi-chain solution
    • host application에 제약을 거의 주지 않기 때문에 Cosmos SDK app은 wasm 모듈을 쉽게 embed 할 수 있고 커스터마이즈를 쉽게할 수 있음
    • 기반 Chain과는 무관하게 작성되기에 그저 CosmWasm Contract를 작성하는 것이 Cosmos 생태계에서는 다른 체인에서 동작하는 컨트랙트를 생성하는 것임
  • Inter Blockchain Contracts
    • Inter-Blockchain Communication과 유사함
    • 한 체인의 코드가 다른체인에서 트랜잭션을 생성하는 것을 가능하게 함
    • No middleman, no timing issue, full security한 상태에서 블록체인간 메세지를 보낼수가 있음
    • Actor Model을 가지며 IBC에 사용됨
    • Messages are fire-and-forget(보내고 나면 알아서 처리 됨), rather than awaiting a promise and worrying about race conditions and reentrancy attacks
  • Easy to Integrate
    • CosmWasm은 framework이기보다는 library길 지향 (대부분의 코드에 opt-in하는 것이 가능)
    • 이는 다양한 언어에서 CosmWasm을 사용하는 것이 가능하게 함
    • 또한 Cosmos SDK가 아닌 다른 프레임워크에도 임베드 될수 있게 함
    • core runtime logic인 cosmwasm-vm은 Rust로 작성되어 있고, wasmvm은 generic go를 제공함
    • 하지만 chain이 Tendermint consensus가 아닐 경우 IBC를 통한 interact는 불가능함

Actor Model

  • 신뢰할수 있고 분산된 시스템에서 사용하는 디자인 패턴
  • Actor가 자신의 내부 state에 대해 유일한 접근 권한을 가지고, Actor는 서로를 직접적으로 호출할 수 없음
  • 대신, 시스템의 state를 유지하고 code와 storage에 주소를 맵핑하는 Dispatcher를 통해 메세지를 가져옴
  • Actor는 다음과 같이 캡슐화 될 수 있음
pub trait Actor {
  fn handle(msgPayload: &[u8]) -> Vec<Msg>;
}

pub struct Msg {
  pub destination: Vec<u8>,
  pub payload: Vec<u8>,
}
  • 이는 CosmWasm에서 contract를 모델링하는데 사용되는 기본 형태로 아래와 동일한 기능을 함
    • Response : Vec<Msg>와 metadata를 포함
    • store : contract 내부 상태에 대한 access
    • parmas : global immutable context
pub fn handle<T: Storage>(store: &mut T, params: Params, msg: Vec<u8>) -> Result<Response>
  • 이와 같은 디자인을 통해 다음과 같은 효과를 얻음
    • Private internal state
      • Actor들 사이에 제한된 데이터 포맷을 이용하여 coupling을 줄일 수 있음
      • 복잡한 API나 함수 포인터를 전달하지 않음. 이는 REST or RPC 콜을 사용하는 것과 같음
      • 이 방식은 Cosmos SDK에서 StoreKey를 전달받은 trusted module이 다른 module의 스토리지에 full-access를 갖는 capabilities model과는 대조적임
      • Cosmos SDK에서는 compile time에서 module을 audit하는 것이 가능하지만, smart contract 시스템에서는 compile time check가 없어서 엄격한 boundary를 제공해야함
    • Efficiency
      • Actor는 각자의 큐를 통해 각자의 thread에서 실행 됨
      • 이는 concurrency를 가능하게 함(아직 CosmWasm에서 사용하진 않음)
      • Actor 내에서 serialized execution을 가능하게 함 (이전에 실행된 Handle 호출 도중에 다른 Handle 실행을 불가능하게한다는 뜻)
      • Handle은 동기 호출이고 Actor가 다음 메세지를 실행하기 전에 반환됨 (이를 통해 reentrancy attack을 방지함)
    • Locality
      • Actor는 이전에 받은 주소를 가진 다른 Actor들과만 통신함
      • Actor가 통신하기 위해서는 컨트랙트 생성자나 잠재적 사용자로 부터의 external message가 Actor에게 전달되어야함
      • 이와 같은 address를 전달하기 위해 데이터 포맷이 hard-coding 되어야함
      • Standard interface가 만들어지면, 여러 큰 규모의 컨트랙트들 사이의 composability를 지원할 수 있음
  • Atomic Execution
    • Message를 보내는 것은 두 컨트랙트 간에 state 변화를 atomic하게 커밋하는 문제가 존재
    • state를 커밋하기 전에 반환된 모든 메세지들이 정확하게 처리되었는지 확인해야할 경우가 많음
    • three-phase-commit과 같은 아이디어가 있지만, 일반적으로 모든 Actor는 동일한 바이너리에 존재하기에 Keeper를 이용하여 이를 핸들링할 수가 있음
    • external transaction으로 Msg가 실행되기 전에 global data store의 SavePoint를 생성하고 첫번째 컨트랙트에게 subset을 전달함. 그리고 동일한 sub-transaction 안에 있는 모든 반환된 메세지를 실행하고 만약 모두 성공할 경우 이를 sub-transaction에 커밋할 수 있음. 만약 실패할 경우 첫번째 컨트랙트가 실행되기 전에 실행을 취소하고 state를 rollback할 수 있음
    • 예를 들어, 두 ERC20 토큰 사이 거래가 있을 때 조건이 맞으면 A 토큰을 구매자에게, B 토큰을 판매자에게 전달하는 두 메세지가 생성됨. 반환된 메세지를 실행할 때, 구매자가 충분한 B 토큰을 갖고 있지 않는 것이 밝혀지면, 해당 메세지는 fail하고 전체 sequence가 취소됨. Transaction이 실패하고, 구매 조건이 만족했다는 것이 확인되지 않을 것이고, Token은 전달되지 않게 됨.
  • Dynamically Linking Host Modules
    • locality와 loose coupling의 뜻은 다른 CosmWasm 컨트랙트들과 연결될 필요가 없다는 뜻
    • Dispatcher가 주소를 가지고 있는 어떠한 곳이는 message를 보낼 수 있음
    • 예를 들어 native 토큰을 옮기는 x/supply 모듈에 의해 처리된 SendMsg를 반환하는 것이 가능
    • standard interface를 정의했다면, core 모듈을 호출할 수 있는 인터페이스를 정의하고 컨트랙트 생성자에서 native 모듈에 주소를 전달하는 것이 가능함
  • Inter Blockchain Messaging
    • Actor 모델은 다른 컨트랙트를 동기적으로 호출하는 시도를 하지 않고 메세지가 실행되어진 메세지를 반환함.
    • 이는 IBC를 이용한 cross-chain 컨트랙트 호출을 만드는 것과 잘 맞음
    • 하지만 IBC에서는 atomic execution이 지원되지 않음
    • 다른 콜은 동일한 Dispatcher 에게서 호출되지 않을 것이기 때문에, 컨트랙트 내에 intermediate state를 저장할 필요가 있음 (IBC 콜의 결과가 알려질 때 까지 state를 바꿀수 없으며 그렇기에 안전하게 적용되거나 취소될 수 있음)
    • 예를 들어 A 체인에서 B 체인으로 토큰을 전달할 때
      1. Contract A는 sender의 token supply를 줄임
      2. Contract A는 IBC 메세지 아이디, sender and receiving 체인과 연결된 토큰의 escrow를 생성함
      3. Contract A는 state를 커밋하고 체인 B에 IBC 트랜잭션을 초기화하는 메시지를 반환함
      4. 만약 IBC 전달부분이 실패할 경우, 컨트랙트는 atomically reverted
      5. 시간이 지난 후 success 또는 error/timeout이 IBC 모듈에서 토큰 컨트랙트로 반환 될 경우
        1. Contract A는 IBC 핸들러로부터 온 메세지를 검증하고 escrow에 가지고 있는 알려진 IBC 메세지 ID를 참고함
        2. 만약 성공할 경우, escrow는 삭제되고 escrow된 토큰은 Chain B의 어카운트로 전달 됨
        3. 에러가 있을 경우, escrow는 삭제되고 escrow된 토큰은 원래 sender에게 돌아감

Name and Addresses

  • 대부분의 블록체인은 public-key의 해시를 통해 external actor를 식별하기 위해 Address를 사용함
  • 이는 on-chain smart contract를 식별하기 위하여도 쓰이는 것으로 확장됨
  • Human-readable 표현이 존재
    • Bech32 : bc1qc7slrfxkknqcq2jevvvkdgvrt8080852dfjewde450xdlk4ugp7szw5tk9
    • hex : 0x8617E340B3D01FA5F11F306F4090FD50E238070D
    • checksumned hex : 0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
    • large integers : 3040783849904107057L
  • Addr
    • Cosmos SDK의 주소는 20 캐릭터이고 security check (e.g. chain-prefix in Bech32, checksums in Bech32, checksummed hex)를 포함하고 있음
    • CosmWasm은 Cosmos SDK의 확장이기에, 동일한 규칙을 따름
    • cosmos1... for gaia, wasm1... for CosmWasm testnet
    • Addr은 주소 string validation과 같은 유용한 기능을 제공하는 wrapper임
  • Naming

Querying

컨트랙트의 스테이트를 봐야하는 경우가 많음. 하나의 컨트랙트에서 다른 컨트랙트로 쿼리를 실행할 때 발생할 수 있는 디자인과 시큐리티 이슈에 대해 알 필요가 있음

  • Raw Queries
    • 가장 단순하게 key-value store에 raw read access를 하는 쿼리 방법
    • caller에게 contract storage에서 사용 가능한 raw binary key를 전달하는 것
    • 하지만 이는 실행된 실제 컨트랙트에 대한 정보를 요구하고 스토리지와 caller를 연결해야하는 단점이 있음
    • wasmd에 구현되어 있음
  • Custom Queries
    • implementation에 coupling 되지말고 interface에 의존해야함
    • Custom query를 위해서 각 컨트랙트는 read-only mode에 저장된 데이터에 접근할 수 있는 query 함수를 외부에 공개하도록 해야함
    • contract를 실행하는 것은 상당한 양의 gas를 소모할 수 있기 때문에 custom query에는 gaslimit을 적용해야함
  • External Queries
    • External query는 모든 웹이나 cli client들이 사용하는 방식
    • Cosmos SDK 에서의 abci_query는 Tendermint RPC를 호출함
    • 현재 SDK 내에 노출된 query 기능은 하드코딩 되어 있으며 실행 시간 제한은 개발자에 의해 결정됨
    • 무한 루프 wasm contract를 업로드 되거나 퍼블릭 노드에 DoS가 생길수 있음
    • 이를 방지하기 위해 외부에서 호출되는 모든 query_custom은 fixed gas limit를 정의해야 함
    • 하지만 standard value를 결정하는 것이 어렵고 노드별로 원하는 complex query와 gas limit간에 tradeoff가 존재함
    • 모든 query_custom 호출은 개별 노드 운영자들에게 수정될 수 있도록 app-specific configuration file에 정의되어야 함
    • 이를 통해 퍼블릭 노드가 complex query를 방지하고 허용된 쿼리만 처리할 수 있게함
    • 참고로 abci_query는 모듈의 현재 in-progress 스테이트를 절대 읽지 못하지만, 가장 최근에 committed된 블록 후의 스테이트 read-only 스냅샷은 사용 가능함
  • Internal Queries
    • 메세지를 보냄으로써 컨트랙트 사이의 인터랙션이 생성될 수 있는 반면에 state를 바꾸지 않으며 다른 모듈을 동기적 쿼리하고 싶은 일부 케이스가 있음 (e.g. name을 address로 변환하고 싶거나 일부 account의 KYC 상태를 체크하고 싶은 경우)
    • 이를 메세지 시리즈를 이용하여 구현하는 것도 가능하지만 한번만 쓰여지는 작업에 비해 너무 구현하기 복잡함
    • 이 디자인은 각 컨트랙트가 자신의 internal state에 대해 독점적인 접근권한을 가진다는 Actor model의 원칙을 위배함 (query_rawquery_custom 모두 이런점에서 실패함. 만약 제대로 처리되지 않으면 concurrency와 reentrancy 문제를 야기 가능)
    • 그렇기에 현재 CosmWasm 메세지 실행 전에 state snapshot에 대해 read-only 액세스만 가능한 Querier를 제공함
    • snapshot을 가지고 실행중인 컨트랙트와 쿼리된 컨트랙트 모두가 컨트랙트 실행 전, 데이터에 read-only로 접근하기 때문에 Rust의 borrowing rule로 인해 안전함. 현재 컨트랙트는 cache에 쓰여지고 성공후에는 flushed 됨
    • 또다른 이슈는 reentrancy를 피하는 것. 공식 Docs는 contract가 실행되기 전의 스냅샷의 state에 접근권하는 가지는 것이기 때문에 다른 side-effect가 없을 것이라고 설명함
    • 모든 쿼리는 transaction의 일부로 실행되기 때문에 gaslimit이 필요하고 추가적인 작업은 현재 필요 없음. 모든 스토리지 read와 쿼리의 일부로 처리되는 데이터 프로세싱은 트랜잭션의 여유분으로 실행되며 제한된 processing time이 있음
    • reentrancy나 max query depth에 대한 explicit guard를 추가할 예정

Serialization

CosmWasm에서 중요한 요소중 하나는 좋은 Developer UX를 포함하는 것. 이를 위해 블록체인으로 보내진 메세지를 조사하고 디버그할 수 있으며 복잡한 라이브러리 없이 결과를 파싱할 수 있어야함. 또한 custom schema나 ABI를 다운로드하지 않고 method call이 가능해야 함

  • JSON

    • self-describing, human-readable, 다양한 API에서 사용됨
    • 하지만 숫자 처리나 string과 base64-encoded binary 사이에 명확한 구별이 없으며 하드코딩 된 스키마가 없음
    • cosmwasm::serdecw-template를 통해 json을 지원하고 있음
  • ProtoBuf

    • JSON 보다 더 엄격한 스키마를 제공하고 더 압축된 형태임
    • Cosmos SDK v0.39.0 업그레이드에 Protobuf와 gRPC 지원이 추가됨
  • Cap'n Proto

    • zero-copy read인 super-lean coding format
    • CosmWasm 사용을 위해 제안됨

Contract Composition

  • Terminology
    • contract : 블록체인에 주소를 가진채 동적으로 업로딩 되는 CosmWasm code
    • native module : Cosmos SDK 모듈로 블록체인 바이너리 내에 컴파일 되어있음. 수정되기 위해서는 Soft or hard fork를 요구하기에 상대적으로 static하고 CosmWasm을 싱행하는 다른 블록체인들 사이에 다를 수 있음
  • Messages
    • 3가지 종류의 메세지가 존재
    • contract : 메세지에 따른 컨트랙트 주소를 호출함. caller가 API format에 액세스를 가지고 있다고 가정
    • module interface : 이식가능한 인터페이스 하의 네이티브 모듈을 expose하는 어떠한 체인이든 지원하는 standardized 인터페이스
    • custom : cusom native module을 호출하기 위해 chain-dependent extension을 메세지 타입으로 캡슐화함. 이상적으로 시간이 지남에 따라 동일한 체인에서 불변해야하지만 이식성이 보장되지 않음
  • Queries
    • 메세지와 같이 3가지 타입 존재
    • contract, module interface,custom
  • Modules
    • bank, staking 같은 모듈
    • 가능하다면 module interface 사용을 권장하고 custom type은 fast release 사이클을 지키기 위한 일시적인 수단으로 사용할 것을 권장
  • Customization
  • Design Consideration
    • Portability
    • Immutability
    • Extensibility
  • Usability
    • Checking for support
    • Type-Safe Wrappers

Comparison with Solidity Contracts

  • Ethereum은 bug-free contract를 생성하는 것이 어려움 (OpenZepellin template 사용 이유)
  • Wasm Contract의 3가지 단계
    • Upload Code : 최적화된 wasm code를 업로드 하고, state나 contract address는 부재함 (ex. ERC20 Contract)
    • Instantiate Contract : 일부 초기상태에서 코드 레퍼런스를 인스턴스화 하고, 새로운 주소를 생성함 (ex. token naem, max issuance, etc)
    • Execute Contract : 다양한 call을 지원하고, 컨트랙트 디자인에 따라 이전에 인스턴스화된 컨트랙트에 대하 권한이 없음 (ex. send ERC20 token, grant approval to other contract, etc)
  • 이더리움과 같이 컨트랙트를 인스턴스화하고 실행하는데는 가스가 필요함
  • 인스턴스화와 실행 둘다에서 signer가 토큰을 메시지를 통해 컨트랙트에 보내는 것을 허용함
  • 컨트랙트에 직접적으로 토큰을 보내는 것에서 dㅣ더리움과 큰 차이는 어떠한 Contract 코드도 실행시키지 않는 다는 것임 (e.g. SendMsg)
  • 컨트랙트의 실행은 명시적으로 요청되었을 때만 실행되어 가능한 공격을 줄일 수 있음

CosmWasm은 Reentrancy Attack and DoS Attack을 방지함

  • Reentrancy Attack

    • Contract A에서 함수 실행 도중에, 다른 Contarct B를 호출하는 것이 아이디어임
    • 다른 함수를 호출하는 것은 컨트롤을 Contract B로 넘기는 것
    • 이 때 state를 잘못 관리할 경우 실행 중인 Contract A의 2가지 버전이 있을 수 있음
      • 예를들어 Contract A에서 가스 문제 등으로 전혀 다른 행동을 할 수가 있음 (DAO hack)
    • CosmWasm은 한 Contract에서 다른 Contract를 직접 호출하는 것을 방지함
      • Security를 위해 Compsition을 포기
      • 컨트랙트는 해당 컨트랙트가 종료된 후에, 다른 컨트랙트를 호출하거나 send를 용함
      • 만약 미래의 Message가 실패하면, contract 상태를 업데이트하는 것을 포함한 전체 트랜잭션이 revert 됨
  • DoS Attack

    • malicious actor는 무한루프에 빠지는 컨트랙트를 통해 체인을 halt 시키거나 노드 disk에 불필요한 정보를 write할 수 있음
    • Web Assemblys는 OS에 디폴트 접근이 불가능한 sandbox를 지원하기에, smart contract의 resource limit에만 집중하면 됨
    • Memory Usage : Wasm VM을 초기화할 때 기본적으로 32MB RAM이 제공되어 짐. 여기에 프로세스를 실행하는데 필요한 모든 바이트 코드들이 저장됨. 이는 거의 대부분의 어떠한 컨트랙트에 대해서도 충분함. 그렇지만 복잡한 zero-knowledge circuit은 limit에 도달할 수도 있게할 수 있음. 그렇지만 이는 블록체인 메모리 사용에 영향을 최소화할만큼 충분히 작음
    • CPU Usage : Wasmer Runtime은 wasm code에 metering logic을 적용시키는 것을 가능하게 함. 이는 모든 jump statement전에 다양한 operation의 가격을 계산하고 limit등을 체크함. 컨트랙트를 실행하기 전에 was gas limit은 남은 Cosmos SDK gas에 근거하여 설정 됨. 이는 어떠한 CPU 컴퓨팅이든 hard limit을 걸게 됨
    • Disk Usage : KVStore에 읽고 쓰는 모든 disk access와 관련됨. Cosmos SDK는 KVStore access에 가스 요금을 이미 부과하고 있음. 컨트랙트의 모든 디스크 액세스는 SDK에서 callback을 통해 만들어지기 때문에 그곳에서 부과됨. 만약 누군가가 CosmWasm을 다른 runtime에서 통합할 경우, 해당 엑세스에서 부과하도록 주의해야함

Reference

좋은 웹페이지 즐겨찾기