AA(Account Abstraction)와 ERC-4337

한나리·2023년 9월 19일
1

blockchain

목록 보기
3/6
post-thumbnail
post-custom-banner

지난번 포스팅에서 Ethereum Account에 대해서 전반적으로 살펴봤는데, 오늘 포스팅할 내용은 ERC-4337의 근간이 되는 AA(Account Abstraction, 계정추상화)에 대한 내용을 다룰 것이다.

AA란

AA란 단어 그대로, 이더리움 계정의 타입에 따른 기능 제약을 극복하기 위해 프로토콜의 상위 레이어에서 계정의 개념을 하나로 추상화하는 기술이다.

이더리움 계정에는 두가지 유형이 있다고 했는데, 정리하자면 계정 유형에 따라 EOA는 트랜잭션을 생성 및 실행할 수 있으나 스스로 온체인 코드를 수행할 수 없고, 반대로 CA는 내장된 온체인 코드를 수행할 수 있으나 트랜잭션을 생성할 수 없는 제약이 존재한다.

이러한 제약사항은 다음과 같은 불편함을 야기한다.

  • 컨트랙트에서 새로운 트랜잭션을 발생시키거나 컨트랙트를 배포해야 하는 경우 CA로 처리할 수 없다.
    -> 트랜잭션을 생성해 줄 별도의 EOA 필요
    -> 가스비 이중 지불
  • EOA를 사용함에 있어서 개인키의 안전한 보관이 아주 중요하다.
    -> 개인키가 분실된다면 그 계정을 더이상 사용할 수 없다.
  • EOA로부터의 트랜잭션 처리 과정에서 특정 조건(계정별 송신 금액 제한 또는 송신처 제한 등)을 적용하고자 하는 경우에 온체인 코드로 처리가 불가하여 오프체인 시스템으로 이를 보완해야 한다.
    -> 높은 신뢰성을 요구하는 지갑이나 결제 서비스 구현에 많은 노력과 보완 장치 구축이 필요

이와 같은 불편함을 해소하기 위해 등장한 개념이 AA이다. 계정을 추상화하여 스마트컨트랙트 형태로 구현함으로서 위와 같은 제약사항을 없애고 다양한 온체인 기능 실행과 트랜잭션의 발행을 가능하게 하는 것이다.
이를 통해 계정 관리의 불편함과 구현의 한계를 최소화 함으로서 이더리움 어플리케이션의 확장성을 높이는 것이 AA의 도입 목표라고 할 수 있다.

ERC-4337로 구현된 AA의 기본 처리 구조

ERC4337_Diagram

AA는 최초 EIP-2938을 통해 제안되었으나 구현 사항 내에 이더리움 프로토콜의 수정이 포함되어 있어 최종 반영되지 못했다. 이후 표준으로 채택된 ERC-4337에서는 이더리움 프로토콜에서 계정과 트랜잭션을 실제 처리하는 합의 레이어의 구현은 그대로 유지하되, 상위 레이어인 어플리케이션 및 인프라 레이어를 통해 EOA와 CA의 구분 없이 하나의 '계정 컨트랙트'를 통해 트랜잭션 처리와 온체인 코드 수행을 모두 가능하도록 한 것이다.

트랜잭션을 처리하듯, 추상화된 트랜잭션인 User Operation을 처리하자.

ERC-4337에서는 이더리움 합의 레이어에서 일어나는 프로토콜 처리 과정과 유사한 새로운 레이어를 통해 계정 추상화를 제공한다. 쉽게 말해, 합의 레이어에서 각 노드들이 Mempool에 수집된 여러 트랜잭션 중 높은 수수료의 트랜잭션들을 골라 하나의 블록으로 제안하는 과정을 본따 이를 어플리케이션 레이어에 구현하고, 이 과정에서 계정의 개념을 통합하여 지원하는 것이다.

추상화된 레이어에서는 노드 대신 'Bundler'라는 새로운 Actor가 등장한다. 이더리움 노드와 마찬가지로 이더리움 네트워크에서는 누구나 Bundler로 참여할 수 있으며 이는 분산화된 트랜잭션 처리를 지향하는 이더리움 철학을 반영한다.


용어 정의

- User Operation

사용자를 대신하여 전송될 트랜잭션을 설명하는 구조.

새로운 레이어에서 사용자들은 트랜잭션 대신 유효한 서명을 포함하는 'User Operation'을 생성하고 Bundler의 RPC-Endpoint들을 통해 이를 전달한다. 이 때, User Operation은 다음과 같은 데이터 구조로 구성되어 있는데, 트랜잭션과 동일하게 sender, to, calldata, maxFeePerGas, maxPriorityFee, signature, nonce 등의 필드를 포함한다.

FieldTypeDesc.
senderaddress작업을 수행하는 계정
nonceuin256anti-repay 파라미터. 최초 계정 생성을 위한 salt로도 사용
initCodebytes계정이 아직 on-chain에 없을 때 필요
callDatabytesmain execution call 중에 sender에게 보낼 데이터
callGasLimituint256main execution call에 할당할 가스의 양
verificationGasLimituint256verification 단계에서 할당할 가스의 양
preVerificationGasuint256pre-verification execution과 callData를 처리한 bundler에게 보상으로 지불할 가스의 양
maxFeePerGasuint256EIP-1559 max_fee_per_gas
maxPriorityFeePerGasuint256EIP-1559 max_priority_fee_per_gas
paymasteraddress트랜잭션 수수료를 대납하는 paymaster 주소 (주소가 0일 경우 수수료는 직접 지불
paymasterDatabytespaymaster에게 보낼 추가 데이터
signaturebytesverification step에서 nonce와 함께 계정으로 전달된 데이터

- Sender

User operation을 보내는 Account Contract

- EntryPoint

User Operations Bundle을 처리하는 싱글톤 컨트랙트. Bundler/client는 EntryPoint를 화이트리스트에 추가해야한다.
Bundler가 제출한 bundle transaction의 유효성을 검증하고, 이를 실제 온체인에서 실행시키는 역할을 수행한다. EntryPoint는 User Operation의 검증 단계와 실행 단계를 나눠 진행하며, 모든 User Operation의 검증이 끝난 이후 실행 단계가 진행된다.

- Bundler

User Operation을 처리하고, 유효한 EntryPoint.handleOps() 트랜잭션을 생성하고, 블록에 추가할 수 있는 노드(block-builder)

  • Bundler는 block-builder 자체의 역할을 수행할 수 있음.
  • Bundler가 block-builder가 아닌 경우, 블록 구축 인프라와 함께 작동해야 함.
  • Bundler는 실험적인 RPC API를 사용할 수 있음. (예)eth_sendRawTransactionConditional

Bundler는 사용자 대신 이더리움 네트워크에 트랜잭션을 제출하는 역할을 하는 객체이다. 번들러는 대체 멤풀에 제출된 User Operation 객체들을 묶어 bundle Transaction을 생성한다. 제출한 bundle Transaction이 정상적으로 실행되면 사용자나 페이마스터로부터 수수료를 받는다.

Bundler는 수신한 UserOperation들을 대체 Mempool에 수집한 뒤 높은 수수료를 지불하는 UserOperation들을 모아 Bundling하여 Bundle Transaction으로 만든 뒤, 이를 검증하고 처리하기 위해 'EntryPoint' 컨트랙트를 호출

- Paymaster

paymaster는 사용자 대신 트랜잭션 제출에 대한 수수료를 지불하는 컨트랙트이다. 이 컨트랙트는 EntryPoint와 상호 작용하며, 수수료 지불 의사 확인 및 수수료를 Bundler에게 전달하는 역할을 한다.


🖍️ Consensus Layer vs Application Layer

Consensus LayerApplication Layer
NodeBundler
TransationUser Operation
MempoolUserOperation Mempool (Alternative mempool)
BlockBundle Transaction

비유적으로 비슷한 역할을 하는 개념을 표로 정리한 것이고, 사실 전체 과정으로 보면 User Operation이 Bundle Transation이 되고, 이것이 최종적으로 우리가 아는 그 Transation과 같이 이더리움 블록에 포함된다.

User Operation

eip-4337

사용자는 transation 객체를 만들어 txPool (Transaction mempool)에 보냈던것 처럼 User Operation mempool에 'User Operation' 객체를 만들어서 보낸다.

참고 : Consensus Layer
ethereum

이더리움 노드와 같은 역할을 하는 Bundler는 User Operation Mempool안에 쌓인 여러개의 User Operation을 하나의 Bundle Transaction으로 묶어 Ethereum Block에 넣는다.

User Operation을 Bundle Transaction으로 만든 뒤 이를 검증하고 처리하기 위해 EntryPoint 컨트랙트를 호출한다. 여기서 EntryPoint 컨트랙트는 User Operation들을 검증하고 처리하기 위한 공통 로직이 구현된 스마트 컨트랙트로서 전체 이더리움 네트워크에서 표준을 정의된 싱글톤 컨트랙트로 존재하는 것을 말한다.

또한, replay attack을 막기 위해 이더리움 트랜잭션의 특수서명값 중 v(v,r,s 중 v)에 chainId가 포함되듯이, User Operation의 signature 또한 chainId가 들어가고 추가로 EntryPoint컨트랙트 주소도 포함된다.
signature 필드는 프로토콜에 의해 정의되지 않고, 각 계정 구현에 따라 정의된다.

handleOps

User Operation verification

** 그림에서 2,3번 과정

consensus layer에서 트랜잭션 검증 및 블록 생성 등의 로직이 프로토콜 레벨에서 지원되었다면, AA에서는 이런 로직을 EntryPoint 컨트랙트로 구현해 온체인 로직 처리가 가능하도록 만든 것이다.
EntryPoint 컨트랙트에서 지원하는 다양한 인터페이스 중 simulateValidation(UserOperation userOp)handleOps(UserOperation[] ops, address beneficiary) 함수가 기본적인 User Operation 처리에 사용된다.

  • simulateValidation : 노드가 프로토콜에 따라 트랜잭션의 nonce와 내용, 서명을 검증하는 것과 같이 Bundler가 Mempool로 수집된 User Operation의 서명 및 수수료 지불 가능성을 검증하고자 할 때 호출. 이러한 검증을 통해 Bundler는 잘못된 User Operation을 요청 처리 실패로 인해 발생하는 불필요한 가스소모를 최소화할 수 있다.
  • handleOps : simulateValidation에서 검증이 완료된 User Operation들을 Bundle Transaction으로 가공한 뒤 handleOps 함수를 통해 EntryPoint로 전달되어 verification과 Execution을 통해 최종 검증 및 실행이 완료

The core interface of the entry point contract is as follows:

function handleOps(UserOperation[] calldata ops, address payable beneficiary);

function handleAggregatedOps(
    UserOpsPerAggregator[] calldata opsPerAggregator,
    address payable beneficiary
);

    
struct UserOpsPerAggregator {
    UserOperation[] userOps;
    IAggregator aggregator;
    bytes signature;
}
function simulateValidation(UserOperation calldata userOp);

error ValidationResult(ReturnInfo returnInfo,
    StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo);

error ValidationResultWithAggregation(ReturnInfo returnInfo,
    StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo,
    AggregatorStakeInfo aggregatorInfo);

struct ReturnInfo {
  uint256 preOpGas;
  uint256 prefund;
  bool sigFailed;
  uint48 validAfter;
  uint48 validUntil;
  bytes paymasterContext;
}

struct StakeInfo {
  uint256 stake;
  uint256 unstakeDelaySec;
}

struct AggregatorStakeInfo {
    address actualAggregator;
    StakeInfo stakeInfo;
}

User Operation execution

** 그림에서 4,5번 과정

비즈니스 로직 처리는 EntryPoint 컨트랙트 내부가 아닌, User Operation의 sender에 해당하는 계정 컨트랙트(Account Contract)로 위임되어 처리된다. 즉, EntryPoint 컨트랙트는 이름 그대로 Bundle Transation을 앞단에서 받아 처리하는 일종의 프록시로서, 프로토콜과 같은 역할을 수행한 뒤 실제 User Operation 실행은 계정 컨트랙트의 구현부 호출을 통해 진행하는 것이다.

  • 검증 루프에서는 계정 컨트랙트에 구현된 validateUserOp함수로 User Operation이 전달되어 정의된 로직에 따른 검증이 수행
  • 실행 루프에서는 User Operation에 포함된 calldata를 통한 계정 컨트랙트 호출이 발생하며, 이때 계정 컨트랙트의 구현에 따른 다양한 custom 기능이 실행될 수 있다.

이후 미리 지불된 가스 중 남는 가스에 대한 환불을 마지막으로 User Operation의 처리는 완료된다.

Account Contract (Wallet Contract)

Account Contract는 일종의 지갑 컨트랙트이고 두 가지 함수를 반드시 구현해야 한다.

  • validateUserOp : User Operation을 input값으로 갖는 이 함수는, User Operation의 signature와 nonce를 검증하고 검증이 완료되면 가스비를 지불하고 nonce를 증가시킨다. (검증에 실패하면 exception을 던짐)
  • op executation function(비즈니스 로직 구현부) : 해당 계정이 실행할 코드에 대한 호출이 발생하도록 구현된 함수

Account Contract의 로직을 단순화 하기 위해, 스마트 컨트랙트의 보안적인 부분은 Account Contract가 아닌 global 컨트랙트인 EntryPoint 컨트랙트에서 수행된다.
대신, Account Contract의 validateUserOpop execution function(비즈니스 로직 구현부)는 컨트랙트 호출 제약사항으로 require(msg.sender == ENTRY_POINT)을 가지고 있어서 오직 신뢰성있는 EntryPoint만이 호출할 수 있고, 액션 수행 후 가스비를 지불할 수 있다.

The core interface required for an account to have is:

interface IAccount {
  function validateUserOp
      (UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
      external returns (uint256 validationData);
}

여기서 userOpHashuserOp(서명제외), EntryPoint, chainId에 대한 해시이다.

flow

결론

요약하자면, 새로운 레이어에서 사용자들은 트랜잭션 대신 유효한 서명을 포함하는 'User Operation'을 생성하고, Bundler의 RPC-EndPoint를 통해 이를 전달한다. 이때 Bundler는 Bundle Transaction을 만들기 위한 EOA를 가지고 있으며 생성된 Bundle Transaction(유효한 EntryPoint.handleOps() 호출하는 단일의 트랜잭션을 생성)은 consensus layer에서 블록으로 채굴되어 EntryPoint로 전달된다.

다음 포스팅에서는 ERC-4337의 동작방식에 대해 조금 더 자세히 다뤄볼 예정이다.

profile
내가 떠나기 전까지는 망하지 마라, 블록체인 개발자
post-custom-banner

0개의 댓글