ERC-7562 계정 추상화 검증 범위 규칙 (Account Abstraction Validation Scope Rules)

Review · 계정·지갑 · 2023-09-01 작성

ERC-4337 계정 추상화에서 UserOperation의 검증 코드가 지켜야 할 제한을 정의해, 수수료를 내지 않는 대량 요청으로 번들러와 공용 멤풀을 마비시키는 서비스 거부(DoS) 공격을 막습니다.

왜 필요한가

일반 계정(EOA)의 트랜잭션은 잔액, 논스, 서명만 확인하면 되고 한번 유효하다고 확인된 트랜잭션은 그 계정이 수수료를 내지 않고는 무효가 되지 않습니다. 그래서 대량 전송 공격은 비용이 치솟아 경제적으로 불가능합니다. 반면 계정 추상화에서는 검증 자체가 임의의 EVM 코드로 이뤄지고 스토리지나 블록 정보에 의존할 수 있습니다. 이 때문에 멤풀에서는 통과했다가 블록에 넣을 때는 실패하는 UserOperation을 만들 수 있고 스토리지 하나를 바꿔 서로 무관한 수많은 UserOperation을 한꺼번에 무효화할 수도 있습니다. 공격자는 수수료를 거의 내지 않으면서 번들러에게 공짜 연산을 떠넘기고 유효한 UserOperation만 모은 멤풀을 유지하는 일 자체가 계산적으로 불가능해집니다. 또 노드마다 스팸 판정 기준이 다르면 서로를 스패머로 오인해 네트워크가 쪼개질 수 있으므로, 모든 노드가 공유하는 검증 규칙이 필요합니다.

심층 설명

검증 단계와 실행 단계의 분리

검증 단계(validation phase)는 최대 3개의 온체인 프레임으로 구성됩니다. sender 배포 프레임(계정당 1회), sender 검증 프레임(필수), paymaster 검증 프레임(선택)입니다. 실행 단계는 sender 실행 프레임과 paymaster의 postOp 프레임으로 이뤄집니다. 이 문서의 규칙은 검증 단계에만 적용됩니다. 검증을 통과한 UserOperation은 지불이 보장되므로, 계정의 callData나 paymaster의 postOp 같은 실행 코드에는 아무 제한이 없습니다. 각 검증 프레임은 factory, paymaster, aggregator, 스테이킹된 account 같은 단일 엔티티에 귀속되며 엔티티 컨트랙트는 반드시 온체인에 코드가 배포되어 있어야 합니다.

옵코드 제한

검증은 블록 생성 전에 오프체인에서 일어나므로, 블록마다 달라지는 정보를 읽는 옵코드는 차단됩니다. ORIGIN, GASPRICE, BLOCKHASH, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, BASEFEE, BLOBHASH, BLOBBASEFEE, INVALID, SELFDESTRUCT 등이 금지 목록입니다(OP-011). GAS 옵코드는 바로 뒤에 *CALL이 올 때만 허용되고(OP-012), 가스 한도를 노출할 수 있는 out of gas 리버트도 금지됩니다(OP-020). CREATE2는 배포 프레임에서 정확히 한 번, sender 주소의 코드를 배포할 때만 허용됩니다(OP-031). 코드가 없는 주소 접근은 금지되며 sender 주소만 예외입니다(OP-041, OP-042). value를 보내는 CALL은 EntryPoint로 보내는 경우를 빼고 금지되고(OP-061), 프리컴파일은 코어 0x1부터 0x11까지와 P256VERIFY만 허용됩니다(OP-062). EIP-1153 일시 스토리지(TLOAD/TSTORE)는 영구 스토리지와 똑같이 취급하고(OP-070), BALANCE와 SELFBALANCE는 스테이킹된 엔티티만 쓸 수 있습니다(OP-080).

스토리지 접근 규칙

검증 중 SLOAD, SSTORE, TLOAD, TSTORE로 접근할 수 있는 스토리지는 제한됩니다. 계정 자신의 스토리지는 항상 허용됩니다(STO-010). 어떤 슬롯의 값이 주소 A이거나, 슬롯 위치가 keccak(A||x)+n(n은 0부터 128)으로 계산된 경우 그 슬롯은 A의 연관 스토리지(associated storage)로 봅니다. 외부 컨트랙트에 있는 계정의 연관 스토리지는 계정이 이미 존재하거나(STO-021) initCode가 있고 factory가 스테이킹된 경우(STO-022) 접근할 수 있습니다. paymaster나 factory가 스테이킹되어 있으면 자기 스토리지 접근(STO-031), 비엔티티 컨트랙트에 있는 자기 연관 슬롯의 읽기와 쓰기(STO-032), 비엔티티 컨트랙트의 모든 스토리지 읽기 전용 접근(STO-033)이 추가로 허용됩니다. 이렇게 접근을 계정 연관 범위로 묶어야 스토리지 변경 하나가 다수의 UserOperation을 무효화하는 일을 막을 수 있습니다.

스테이킹과 평판 계산

공용으로 쓰이는 엔티티가 계정 연관 밖의 스토리지를 쓰려면 스테이킹이 필요합니다. 스테이킹 엔티티는 MIN_STAKE_VALUE(체인별 조정, 대략 1000달러 상당 권장) 이상을 MIN_UNSTAKE_DELAY(86400초, 1일) 이상의 해제 지연으로 잠근 엔티티입니다. 번들러는 엔티티마다 opsSeen(유효한 UserOperation을 받은 횟수)과 opsIncluded(실제 포함된 횟수)를 세고 두 값을 매시간 value * 23 // 24로 줄여 4일이 지나면 1% 수준이 되게 합니다. max_seen = opsSeen // 10으로 계산해 max_seen이 opsIncluded + 50(BAN_SLACK)을 넘으면 BANNED, opsIncluded + 10(THROTTLING_SLACK)을 넘으면 THROTTLED입니다. THROTTLED 엔티티는 멤풀 4건, 번들당 4건, 멤풀 체류 10블록으로 제한되고 BANNED 주소의 UserOperation은 모두 멤풀에서 제거됩니다. 스테이크는 슬래시되지 않고 오프체인 탐지에만 쓰이지만 자금 잠금이 시빌 공격의 자본 비용을 크게 올립니다.

두 번의 검증과 스패머 차단

번들러는 UserOperation을 멤풀에 받기 전에 한 번, 번들에 넣기 전에 다시 한 번 전체 검증을 수행하고 제출 전에 번들 전체를 추적하는 세 번째 시뮬레이션도 해야 합니다. 스테이킹되지 않은 엔티티는 규칙 덕분에 시뮬레이션과 실행 사이에 동작을 바꿀 수 없지만 악의적인 스테이킹 엔티티는 번들 검증 중임을 감지해 리버트시킬 수 있기 때문입니다. P2P로 받은 UserOperation이 현재 블록에서 실패하면 원래 검증된 블록해시로 재시도하고 성공하면 조용히 버리되 연결은 유지하며 그래도 실패하면 보낸 피어를 스패머로 영구 차단합니다. 규칙에는 두 종류가 있습니다. 네트워크 전체 규칙 위반은 보낸 피어의 평판을 깎지만 번들러마다 상태가 다른 로컬 규칙(STO-040, STO-041) 위반은 평판에 영향을 주지 않습니다.

엔티티별 세부 규칙

스테이킹 안 한 sender는 멤풀에 UserOperation을 4건(SAME_SENDER_MEMPOOL_COUNT)까지만 둘 수 있습니다(UREP-010). 스테이킹 안 한 paymaster의 허용량은 opsAllowed = SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT(10) + inclusionRate * min(opsIncluded, 10000)으로, 포함 실적이 쌓이면 늘어납니다(UREP-020). 스테이킹 안 한 paymaster는 context를 반환할 수 없고(EREP-050), aggregator는 스토리지 사용과 무관하게 반드시 스테이킹해야 합니다(EREP-040). 번들러는 paymaster를 쓰는 멤풀 내 모든 UserOperation의 최대 가스 비용 합이 그 paymaster의 예치금을 넘지 않도록 추적해야 합니다(EREP-010). factory나 계정의 실패로 paymaster나 aggregator의 opsSeen이 억울하게 오르지 않도록 보정하는 규칙(EREP-015, EREP-016)과, initCode가 있는 UserOperation의 검증 실패를 스테이킹된 factory 책임으로 돌리는 규칙(EREP-020)도 있습니다.

EIP-7702 위임과 알트 멤풀

UserOperation은 EIP-7702 권한 부여 튜플을 하나만 포함할 수 있습니다(AUTH-010). EIP-7702로 위임된 계정은 UserOperation의 sender로만 쓸 수 있고 다른 종류의 엔티티로는 쓸 수 없으며(AUTH-020), *CALL이나 EXTCODE* 옵코드로 접근하는 것도 그 계정이 현재 UserOperation의 sender일 때만 허용됩니다(AUTH-030). 같은 sender의 권한 부여 튜플이 멤풀에 여러 건 있으면 모두 같은 위임 주소여야 합니다(AUTH-040). 한편 번들러들은 기본(canonical) 멤풀 외에 별도 합의 규칙을 가진 알트 멤풀에 참여할 수 있습니다. 알트 멤풀의 토픽은 규칙 문서의 IPFS 해시로 식별되고 기본 규칙을 위반한 UserOperation만 알트 멤풀 규칙으로 검사합니다(ALT-020). 엔티티의 opsSeen과 opsIncluded는 알트 멤풀별로 따로 관리되어, 한 멤풀에서 차단된 엔티티가 다른 멤풀에서는 활동할 수 있습니다(ALT-040).

크기·가스 제한과 표준의 현재 상태

번들 생성 시 EVM의 메모리 확장 한계에 걸리지 않도록 크기 제한이 있습니다. 패킹과 ABI 인코딩을 거친 UserOperation 하나는 8192바이트(MAX_USEROP_SIZE)를 넘을 수 없고 paymaster가 반환하는 context는 건당 2048바이트(MAX_CONTEXT_SIZE), 번들 전체로는 65536바이트(MAX_BUNDLE_CONTEXT_SIZE)가 한도입니다. handleOps 번들 호출은 262144바이트(MAX_BUNDLE_SIZE)를 넘지 않아야 합니다. verificationGasLimit과 paymasterVerificationGasLimit은 각각 MAX_VERIFICATION_GAS(500000)보다 낮아야 하고 실제 검증 사용량보다 VALIDATION_GAS_SLACK(4000)만큼 여유가 있어야 합니다. preVerificationGas는 UserOperation 직렬화 칼데이터 가스에 PRE_VERIFICATION_OVERHEAD_GAS(50000)를 더해 충분히 높아야 합니다. 이 표준은 현재 Review 상태이므로 내용이 아직 바뀔 수 있는 제안입니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs