메타트랜잭션이란
이더리움 상에서 메타 트랜잭션(meta transaction)이란 무엇인가에 대해 이야기해볼까 합니다. 본격적인 시작에 앞서, 한 가지 가상의 시나리오를 먼저 제시하고 싶습니다. 블록체인에 대해서 잘 모르는 사용자가, DApp을 이용하려고 한다면 사용자는 손쉽게 목적을 이룰 수 있을까요?
이더리움은 물론이고 블록체인에 대해서도 잘 모르는 사용자가 알아서 지갑을 생성하고, 이더를 어떤 방법을 써서든 본인 지갑에 보유하고, 이를 통해 가스를 지불하며 트랜잭션을 실행시킬 능력이 있을까요? 모두들 예상했겠지만 답은 ‘불가’입니다. 누군가는 이렇게 말할 수도 있습니다. 충분한 가이드라인을 안내한다면, 혹은 블록체인에 대해 사용자가 공부한다면 가능하지 않겠느냐고. 하지만 사용자가 DApp을 이용하기 위해 공부를 해야 할 필요가 있을까요? 없습니다. 이렇게 DApp을 이용하려는 사용자들이 높은 진입장벽으로 인해 DApp을 이용하지 않으려 한다면, 우리가 DApp을 개발하는데 의미가 있을까요?
위와 같은 고민으로 인해 나타난 개념이 바로 메타 트랜잭션입니다. 메타 트랜잭션, 말만 놓고 보면 굉장히 추상적인데 쉽게 이야기 하자면 ‘실 사용자가 가스를 지불하지 않는 트랜잭션’을 의미합니다. 대납 처리되는 트랜잭션 내에 실질적인 트랜잭션 정보가 있기 때문에 정보에 대한 정보, 즉 ‘메타’ 트랜잭션이라고 명명되었습니다.
meta transaction = gasless transaction (on the user side)
엄밀히 말하면 가스는 지불해야 합니다. 단, 그것을 트랜잭션을 요청하는 실 사용자가 수행하지 않고 ‘대납자’가 수행합니다. 사용자는 일반적인 트랜잭션이 생성되는 방식과 유사한 방식으로 트랜잭션을 만들 수 있으며, 자체 개인키로 서명하지만 체인에 직접 보내는 대신 대납자(relayer, sender, payer, … etc)에게 트랜잭션을 전송합니다. 대납자는 도구일 수도 있고, 서비스 또는 가스 요금을 기꺼이 지불하려는 사람일 수도 있습니다.
메타 트랜잭션 처리 방식에 대해 범용적인 표준이 정해져 있진 않습니다. 메타 트랜잭션 처리방식에 대한 제안들이 여러가지 많은 상태이며, 각각 상황에 맞는 방식으로 저마다의 메타 트랜잭션을 구현하고 있는 상황입니다.
아래는 이더리움 플랫폼 상에서 제안된 메타 트랜잭션 처리 방식들 입니다. 관심이 있다면 자세히 살펴보세요.
메타 트랜잭션 처리를 위한 토큰 표준
ERC-1776 Native Meta Transactions
ERC-865 Pay transfers in tokens instead of gas, in one transaction
ERC-1003 Token Standard (ERC20 Extension)
ERC-1228 Delegated Execution
EVM 변경을 통한 메타 트랜잭션 처리 방식
EIP1035 Transaction execution batching and delegation
Relayer Network를 통한 메타 트랜잭션 처리 방식
메타 트랜잭션 위한 서명 표준
ERC-1077 Executable Signed Messages refunded by the contract
이 글에서는 ERC-865, EIP-1613과 루니버스 플랫폼의 메타 트랜잭션 처리 방식을 이야기 할 것입니다.
ERC-865: Pay transfers in tokens instead of gas, in one transaction
사용자가 DApp을 이용함으로써, 혹은 다른 어떤 방법으로 토큰을 보유하게 되었습니다. 해당 토큰을 누군가에게 전송하고 싶은데 트랜잭션을 수행하기 위해서는 이더가 필요한 상황입니다. 즉 사용자에게 이더가 없고 토큰만 있다면, 해당 토큰은 누군가에게 전송할 수도 없고 본인만 갖고 있어야 하는 상황이 되어버립니다. 이럴 때 제 3자가 트랜잭션을 본인이 소유한 이더로 가스를 대신 지불해주고, 그 대가로 토큰을 받을 수 있다면 이 문제를 해결 할 수 있지 않을까요?
사용자(토큰 보유자)가 트랜잭션을 실행할 때, 가스대신 토큰으로 지불하는 방식에 대하여 정의한 내용입니다. 온체인, 또는 오프체인으로 수행 가능합니다. 사용자가 토큰전송을 제 3자에게 위임할 수 있도록 토큰 컨트랙트를 구현하는 표준을 정의하였으며, 제 3자는 토큰전송에 대한 가스를 대납 해주는 대가로 토큰을 수수료로 얻을 수 있습니다.
A: 발신자
B: 수신자
D: 대납자
T: 토큰
X: A에서 B로 이동 되는 T의 총량
Y: 트랜잭션 수행을 위해 A가 D에게 지불해야 할 Token 수수료
N: nonce
- 발신자 A는 1개의 트랜잭션에 대한 수수료 Y의 값에 대하여 D를 통해 견적 받습니다. 이 때 결과는 이더의 가스 가격, 토큰 가치에 따라 다릅니다.
- 발신자 A의 PK를 사용하여 페이로드 P { N, A, B, D, X, Y, T }의 sha3에 대한 {V, R, S}를 생성합니다.
- 발신자 A는 {V, R, S} 및 해시, 서명되지 않은 페이로드 P를 대납자 D에게 보냅니다.
- 대납자 D는 Y와 D가 변경되지 않았음을 검증하고 T.delegatedTransfer(N,A,B,X,Y,V,R,S)를 호출해 트랜잭션을 수행합니다.
delegatedTransfer 메소드는 페이로드 P의 sha3 H를 재구성합니다. 여기서 T는 현재 토큰 컨트랙트의 주소이고, D는 msg.sender입니다. 그런 다음 ecrecover(H, V, R, S)를 호출하고 결과가 A와 일치한다면, X만큼의 토큰을 A에서 B로 전송하고 Y만큼의 토큰을 A에서 D로 전송합니다.
자세한 구현 방법에 대해서 살펴보고 싶다면 여기를 참조하세요.
EIP-1613: Gas stations network
네트워크에 변경사항이 없으며, 컨트랙트와 DApp, 프레임워크에 최소한의 변경만을 통해 메타 트랜잭션을 수행할 수 있도록 하고자 Gas station network가 설계되었습니다.
각각의 노드가 가스를 대납해주는 주유소가 된다면 어떨까요? 이를 이후부터 릴레이 노드라고 칭하겠습니다. 트랜잭션을 실행할 때, 체인에 바로 요청하지 않고 릴레이 노드를 통해 호출하면, 마치 콜렉트 콜(ex. 1541)과 같이 릴레이 노드가 트랜잭션에 대한 비용을 대신 지불하도록 하는 것입니다. 이를 위해선 주유소 역할을 하는 릴레이 노드에게는 메타 트랜잭션 수행 노력에 대한 인센티브를 지급해야 할 필요성이 있습니다.
EIP-1613 아키텍처는 정직하게 대납을 수행하는 주유소 노드가 하나라도 있는 한 다른 주유소 노드들이 트랜잭션을 검열할 수 없도록 설계되어 있습니다. 이 시스템을 훼손하려 시도한다면 이는 체인에 기록되기 때문에 증거로써 활용 할 수 있고, 이를 통해 처벌 가능 합니다.
이 시스템은 크게 싱글톤 컨트랙트인 릴레이 허브, 릴레이 수신자(Relay Recipient) 컨트랙트를 상속받아 구현함으로써 시스템에 참여하는 DApp 컨트랙트들, Gas station이라고 알려진 릴레이 노드들, 릴레이를 통해 컨트랙트와 상호작용하는 DApp들로 이루어져있습니다. 릴레이 허브는 릴레이의 등록자 역할을 하고, 릴레이와 DApp 컨트랙트 간의 거래를 중재하며, 사용자가 릴레이를 찾고 그들의 명성을 평가할 수 있도록 정보를 제공합니다. 릴레이 허브는 DApp으로부터 ETH를 수취하고, 이를 릴레이 노드가 가스를 대납한 트랜잭션을 DApp 컨트랙트까지 릴레이 한 것에 대해 보상하는 데 사용합니다. 이를 통해 노드는 채굴 없이도 수익을 얻을 수 있습니다. 이더리움 네트워크는 노드를 확장함으로써 이익을 얻습니다.
A: 발신자
H: 릴레이 허브
N: 릴레이 노드
C: 릴레이 수신자 기반 DApp 컨트랙트
트랜잭션 처리 프로세스는 아래와 같습니다.
- 발신자 A는 릴레이 허브 H를 통해서 현재 동작하는 릴레이 N을 선택합니다. 이 때, 해당 릴레이 N의 거래 수수료, 릴레이의 지분 크기, 최근 릴레이 된 트랜잭션 등을 고려할 수 있습니다.
- 발신자 A는 발신자 A의 주소, DApp 컨트랙트의 주소 C, 실제 트랜잭션 정보, 릴레이 트랜잭션에 따른 수수료, 가스 가격, 가스 한도, 릴레이 허브 H를 통해 얻는 현재 논스 값, 릴레이 허브 H의 주소, 릴레이 N의 주소 등을 통해 트랜잭션 데이터를 구성하고 사인(T)합니다.
- 발신자 A는 릴레이 허브 H가 관리하고 있는 DApp 컨트랙트 C의 밸런스 정보를 조회하여 릴레이에 따른 보상 지급이 가능한 만큼의 밸런스를 보유하고 있는지 확인합니다.
- 발신자 A는 릴레이 노드 N이 트랜잭션 전송(가스 대납)을 위한 밸런스를 충분히 보유하고 있는지 확인합니다.
- 발신자 A는 서명된 트랜잭션 정보와 메타 데이터를 릴레이 노드 N의 인터페이스를 통해 전송합니다.
- 릴레이 노드 N은 릴레이 허브 H가 수신하도록 트랜잭션 정보(meta transaction = T)를 ETH가 0인 트랜잭션 정보로 감싼 뒤(T`), 해당 트랜잭션(T`)을 가스 지불을 위해 사인하고 온 체인에 제출합니다.
- 릴레이 허브 H가 트랜잭션(T`)을 수신하고, 데이터를 검증합니다. 이후 DApp 컨트랙트 C의 acceptRelayedCall 함수를 호출하여 트랜잭션 수행 가능 여부를 확인합니다. 수행 가능하다면 DApp 컨트랙트 C의 preRelayedCall 함수를 호출하고 트랜잭션을 DApp 컨트랙트 C에게 전송합니다.
- DApp 컨트랙트 C는 트랜잭션(T`)을 처리합니다. 릴레이 허브 H는 DApp 컨트랙트 C의 PostRelayedCall을 호출합니다. 이후 Dapp 컨트랙트 C로부터 전달 받은 ETH를 릴레이 노드 N으로 이전하여 릴레이 수수료를 지불토록 합니다.
자세한 내용을 보고 싶다면 여기를 살펴보세요.
루니버스 메타 트랜잭션 처리 방법
루니버스는 하나의 메인체인을 기반으로 여러 개의 사이드 체인이 동작하는 BaaS 플랫폼입니다. 사이드 체인 내 트랜잭션은 수수료가 없으나, 메인체인에서 일어나는 트랜잭션에 대해서는 사이드체인 오너가 엔드유저의 수수료를 대납하는 형식입니다.
루니버스에서 메타 트랜잭션은 아래와 같이 처리 됩니다.
A: 발신자
B: 수신자
C: Delegation contract, 대납 요청 수락/거부 기준으로 EOA White List 관리, 사이드 체인이 생성될 때 마다 각각의 Delegation contract 생성
- A가 C에게 A의 EOA를 White List에 등록하도록 요청합니다.
- A가 Luniverse API를 통해 트랜잭션을 요청합니다.
- Luniverse API가 응답값으로 rawTx를 리턴하며, 이 때 postFix로 C의 주소가 붙습니다.
- A가 rawTx를 서명한 뒤, Luniverse API를 통해 트랜잭션 처리를 요청합니다.
- 루니버스 메인체인 노드 중 하나가 트랜잭션 풀에서 트랜잭션 데이터를 읽을 때, 해당 트랜잭션을 디코드하고 postfix가 존재하는지 확인합니다.
- postfix가 존재하고 해당 값이 C의 주소를 가리킨다면, 해당 트랜잭션 요청자 A의 EOA가 C의 White List에 등록되어있는지 확인합니다.
- 위 조건이 모두 일치한다면 트랜잭션 실행 후 가스 차감 수행 시점에 A의 EOA에서 가스를 지불하지않고 C로부터 가스를 차감하여 대납 처리합니다.
위와 같은 동작방식은 geth의 트랜잭션 처리 모듈을 수정함으로써 가능합니다. 만약 delegation contract의 자산이 부족해진다면, 사이드 체인의 오너가 자산을 충전하는 식으로 대납을 계속 수행할 수 있습니다.
루니버스 메타 트랜잭션 처리를 위해 DApp 개발자가 소스코드를 수정하는 등 추가로 수행할 액션은 없습니다. 루니버스 플랫폼을 이용하여 DApp을 만든다면, 루니버스에서 제공하는 Luniverse API를 이용하여 사용자의 UX를 크게 향상시킬 수 있습니다. 자세한 내용은 루니버스 사이트에서 확인하세요.
참조
The State of Meta Transactions — https://medium.com/hackernoon/the-state-of-meta-transactions-d00735a4e3af
ERC865: Pay transfers in tokens instead of gas, in one transaction — https://github.com/ethereum/EIPs/issues/865
1–800-Ethereum: Gas Stations Network for Toll Free Transactions — https://medium.com/tabookey/1-800-ethereum-gas-stations-network-for-toll-free-transactions-4bbfc03a0a56
EIP 1613: Gas stations network — https://eips.ethereum.org/EIPS/eip-1613