궁금한 주제를 찾아보세요

비트코인, 스테이블코인, 온체인 데이터처럼 주제로 검색하세요.

다시 읽을 이야기

저장한 글은 이 브라우저에만 보관됩니다.

해설블록체인 기술

EVM CALL·DELEGATECALL·STATICCALL의 상태와 실행 문맥 비교

세 호출 opcode가 실행할 코드, storage 주소, msg.sender·msg.value와 상태 변경 권한을 어떻게 다르게 정하는지 프록시 사례로 설명합니다.

난이도 중급주제 카테고리와 개념 밀도 기준
호출 대상의 코드와 상태 금고, 위임된 코드, 쓰기가 제한된 유리 덮개를 나눈 EVM 호출 방식 비교
주제의 이해를 돕기 위한 개념 일러스트
먼저 읽는 핵심

CALL은 대상 상태를, DELEGATECALL은 호출자 상태를 변경합니다.
STATICCALL은 하위 호출까지 상태 변경 금지를 전파합니다.
프록시는 storage layout과 반환 데이터 처리를 함께 검증해야 합니다.

CALL은 대상 주소의 코드를 대상의 저장소(storage)·잔액 문맥에서 실행하며, 대상이 보는 msg.sender는 호출한 계약입니다. DELEGATECALL은 대상의 코드만 빌려 와 호출자의 주소·저장소·잔액 위에서 실행하고, 원래의 msg.sender와 msg.value를 그대로 유지합니다. STATICCALL은 CALL과 비슷하지만 송금액 인수가 없고, 현재 호출과 하위 호출에 정적 플래그를 넘겨 SSTORE, LOG, CREATE, 송금 같은 상태 변경을 예외로 막습니다. 세 옵코드 모두 성공 여부와 반환 데이터(returndata)를 돌려주므로, 저수준 호출 결과를 확인하지 않으면 실패를 성공처럼 처리할 수 있습니다.

코드 주소와 상태 주소부터 나눕니다

계약 A가 B를 CALL하면 EVM은 B 주소의 바이트코드를 B 계정 문맥에서 실행합니다. B의 SLOAD·SSTORE는 B의 저장소를 읽고 쓰며, ADDRESS는 B를, BALANCE 관련 문맥도 B를 가리킵니다. B가 보는 msg.sender는 A이고, CALL에 송금액이 실려 있으면 msg.value로 전달됩니다. 외부 사용자가 A를 불렀다는 사실은 B에서 msg.sender만 봐서는 직접 알 수 없습니다.

DELEGATECALL은 B의 바이트코드를 가져오지만 실행 주소는 A로 유지합니다. 그래서 B 코드가 slot 0에 접근하면 B가 아니라 A slot 0을 건드립니다. ADDRESS는 A이고, 원래 외부 호출의 msg.sender와 msg.value가 보존됩니다. 프록시가 이 성질 덕분에 작동하지만, 구현 계약의 변수 순서가 프록시 상태와 다르면 멀쩡한 코드가 관리자 주소나 잔액을 덮어쓸 수 있습니다.

DELEGATECALL은 다른 계약의 상태로 이동하는 호출이 아니라, 다른 주소의 코드를 현재 계약의 상태 위에서 실행하는 방식입니다.

JOBCOIN 해설

그림으로 보기프로토콜 실행의 기본 구조
입력이 실행 규칙을 통과할 때 상태가 바뀌는 프로토콜 개념도
그림과 함께 짚어볼 본문 내용

그림은 이 주제의 공통 개념을 단순화한 설명입니다. 아래 항목에서 이 글의 구체적인 조건과 예외를 함께 읽어보세요.

  1. 코드 주소와 상태 주소부터 나눕니다

    계약 A가 B를 CALL하면 EVM은 B 주소의 바이트코드를 B 계정 문맥에서 실행합니다.

  2. 세 옵코드가 보는 문맥을 표로 비교합니다

    STATICCALL은 대상 코드를 별도의 대상 문맥에서 실행하되 정적 플래그를 참으로 둡니다.

  3. 프록시 호출 한 번을 단계별로 따라갑니다

    사용자 U가 프록시 P의 transfer 함수를 부르면, P의 폴백 함수는 호출 데이터를 구현 계약 I에 DELEGATECALL로 넘깁니다.

설명을 위한 개념도 · 실제 가격·거래 내역·통계가 아닙니다.

세 옵코드가 보는 문맥을 표로 비교합니다

STATICCALL은 대상 코드를 별도의 대상 문맥에서 실행하되 정적 플래그를 참으로 둡니다. EIP-214는 SSTORE, CREATE·CREATE2, LOG0부터 LOG4, SELFDESTRUCT, 그리고 송금액이 0이 아닌 CALL을 상태 변경으로 보고 예외를 내도록 정합니다. 호출된 코드가 다시 다른 계약을 불러도 정적 플래그가 그대로 복사되므로 우회해서 저장할 수 없습니다.

Solidity의 view 표시는 컴파일러가 STATICCALL을 고르는 데 도움을 줄 뿐, 임의 바이트코드의 의미를 믿어도 된다는 보증은 아닙니다. 정적 문맥에서는 로그조차 상태 변경으로 금지됩니다. 호출이 실패해도 바깥 거래 전체가 자동으로 되돌려지지 않고, 저수준 성공 값으로만 돌아올 수 있습니다.

호출 opcode 문맥 비교
항목 CALL DELEGATECALL STATICCALL
실행 코드 대상 대상 대상
저장소 주소 대상 호출자 대상
msg.sender 호출자 계약 원래 호출자 유지 호출자 계약
msg.value 지정한 송금액 원래 송금액 유지 0
상태 변경 허용 호출자 상태에 허용 현재·하위 실행 단위 금지

프록시 호출 한 번을 단계별로 따라갑니다

사용자 U가 프록시 P의 transfer 함수를 부르면, P의 폴백 함수는 호출 데이터를 구현 계약 I에 DELEGATECALL로 넘깁니다. I 코드가 balances[msg.sender]를 읽을 때 msg.sender는 U이고 저장소는 P의 것입니다. I 주소에 따로 저장된 잔액을 읽지 않습니다. I 코드가 address(this)를 확인하면 I가 아니라 P가 나옵니다.

반대로 P가 I를 CALL했다면 I의 저장소를 읽고 msg.sender는 P가 됩니다. onlyOwner 권한 검사가 사용자 U를 기대했다면 실패하거나, P 자체가 권한자로 취급될 수 있습니다. 호출 종류 한 단어가 인증과 자산 위치를 동시에 바꾸므로 실행 추적 기록에는 옵코드, 코드 주소, 문맥 주소, 호출자, 송금액을 함께 남깁니다.

  • 프록시와 구현 계약의 저장 슬롯 표를 비교합니다.
  • 추적 기록에서 CALL 계열 옵코드와 호출 깊이를 확인합니다.
  • 실행 단위마다 msg.sender·msg.value·address(this)를 기록합니다.
  • 성공 비트와 반환 데이터를 ABI 기준으로 해독합니다.
  • 업그레이드 전에 delegatecall 회귀 테스트를 돌립니다.

실패와 반환 데이터를 나눠서 처리합니다

CALL 계열 옵코드는 피호출 계약이 되돌리거나 가스가 바닥나면 성공 값 0과 반환 데이터를 돌려줍니다. Solidity의 고수준 외부 호출은 보통 예외를 위로 전파하지만, address.call 같은 저수준 API는 불리언 결과를 직접 확인해야 합니다. 반환값을 버리면 토큰 전송이나 관리자 호출이 실패한 뒤에도 내부 로직이 계속 진행될 수 있습니다.

반환 데이터가 Error(string), Panic(uint256), 사용자 정의 오류 형식인지, 아니면 빈 바이트인지 구분합니다. 공격 대상 계약은 아무 바이트나 정상 ABI 오류처럼 꾸밀 수 있으므로 선택자만 보고 신뢰하지 않습니다. 가스 전달도 EIP-150의 63/64 규칙과 피호출 계약의 작업량에 영향을 받으며, 가스를 넉넉히 줬다고 호출이 안전해지지는 않습니다.

STATICCALL도 읽은 값이 최신이라고 보장하지 않습니다

정적 실행은 해당 실행 단위 동안 상태 쓰기를 막을 뿐, 조회한 블록 상태가 최종 확정됐다는 뜻은 아닙니다. eth_call의 블록 태그가 latest이면 체인 재구성으로 결과가 바뀔 수 있고, 함수는 타임스탬프·블록 번호·다른 계약 상태에 따라 매번 다른 값을 돌려줄 수 있습니다.

진단할 때는 옵코드 수준의 쓰기 금지와 RPC 조회 기준을 따로 봅니다. 안전한 프록시는 구현 코드 해시, 업그레이드 권한, 저장소 배치를 검증하고, 조회 서비스는 safe 또는 finalized 블록 기준과 실패 반환을 기록해야 합니다.

자주 묻는 질문

DELEGATECALL 대상은 msg.sender를 프록시로 보나요?

아닙니다. DELEGATECALL은 호출 직전 실행 단위의 msg.sender와 msg.value를 보존하므로, 일반적인 프록시에서는 원래 사용자를 봅니다.

STATICCALL 안에서 이벤트를 내보낼 수 있나요?

내보낼 수 없습니다. LOG 옵코드는 EIP-214의 상태 변경 금지 목록에 들어 있어 정적 문맥에서는 예외가 납니다.

저수준 호출이 false를 돌려주면 거래 전체가 되돌려지나요?

해당 호출 단위가 실패했다는 뜻입니다. 호출자가 false를 확인해 직접 되돌리지 않으면 바깥 실행은 계속될 수 있습니다.

더 깊이 읽기

본문에서 다룬 개념과 확인 절차를 다음 글에서 이어서 살펴보세요.

참고한 원문 자료

자료 확인 기준일 2026.09.27
  1. Solidity Documentation — Delegatecall and Librariesdocs.soliditylang.org
  2. EIP-214: New opcode STATICCALLeips.ethereum.org
작성 방식과 확인 범위
출처 수집
원문 링크 2개 제공
작성·확인
공식 기관 자료를 근거로 AI 도구를 활용해 작성했고, 운영자가 발행 전에 읽어 확인합니다.
전문가 검토
세무·법률 전문가 검토는 거치지 않았습니다.

투자·세무 판단은 전문가와 상의하세요. 제도와 거래소 안내는 바뀔 수 있으니 원문의 적용 대상과 최신 안내를 함께 확인해 주세요.

이해를 위한 정보 콘텐츠

이 글은 특정 자산의 매수·매도 또는 수익을 권유하지 않습니다. 자료의 발표 시점과 이후 변경 사항을 함께 확인해 주세요.

편집 원칙 보기 →이 기사 정정 제보 →