> THE-ARSENAL
> _

블록체인 시스템, 특히 이더리움 가상 머신(EVM)의 세계에서 모든 상호작용은 명확한 주소를 기반으로 이루어진다. 계약은 코드로 이루어진 독립적인 행위자이며, 다른 계약 혹은 외부 소유 계정(EOA)과 메시지를 주고받는다. 이 메시지의 핵심에는 항상 두 가지 불변의 진실이 존재한다. 바로 msg.sender와 msg.value다. msg.sender는 이 호출을 직접적으로 시작한 주소이며, msg.value는 이 호출에 담겨 보내진 이더의 양이다. 이 두 가지 요소는 계약 보안의 알파이자 오메가다.

 

 

1. 통상적인 대화법: CALL의 세계

우리가 일반적으로 이해하는 스마트 컨트랙트 간의 상호작용은 CALL이라는 옵코드를 통해 이루어진다. 이는 현실 세계의 전화 통화나 사무실 간의 업무 요청과 유사하다.

 

계약 A가 계약 B의 특정 함수를 호출한다고 가정해 보자.

  1. 사용자(User)가 계약 A를 호출한다. 이때 계약 A가 인지하는 msg.sender는 'User'다.
  2. 계약 A의 로직이 실행되다가, 특정 지점에서 계약 B의 도움이 필요해 CALL을 통해 B를 호출한다.
  3. 계약 B는 이 호출을 수신한다. B의 관점에서, 이 호출을 직접 시작한 주체는 계약 A다. 따라서 계약 B가 인지하는 msg.sender는 '계약 A'가 된다.

이 구조는 지극히 상식적이다. msg.sender는 언제나 바로 직전 호출자를 가리킨다. A와 B는 명확히 분리된 존재이며, 각자의 고유한 저장소(Storage)와 상태(State)를 가진다. B는 A의 요청을 받아 자신의 상태를 변경하고 그 결과를 A에게 돌려줄 뿐이다. A의 장부를 B가 직접 수정할 수는 없다. 이것이 EVM이 정의한 기본적인 격리 원칙이자 보안 모델이다.

 

 

2. 경계를 허무는 호출: DELEGATECALL의 세계

그러나 EVM에는 이 모든 격리 원칙을 무너뜨리고, 두 계약의 경계를 의도적으로 허무는 매우 특수하고 강력한 명령어가 존재한다. 바로 DELEGATECALL이다.

 

DELEGATECALL은 단순한 '호출'이 아니다. 이것은 '위임' 혹은 '빙의'에 가깝다. 계약 A가 계약 B에게 DELEGATECALL을 실행하는 순간, A는 B에게 이렇게 말하는 것과 같다. "지금부터 너(B)의 코드를 가져와서, 나의 집(A의 저장소)에서, 나의 신분(A의 맥락)으로 실행하라."

 

B의 코드는 B의 주소에 저장되어 있지만, 그 코드가 실행되는 환경(Execution Context)은 B 자신이 아닌 A가 된다. B는 자신의 코드를 A에게 빌려주는 일종의 '코드 라이브러리'가 되고, A는 그 코드를 실행하는 주체가 된다. 이 기묘한 작동 방식이 바로 프록시 패턴의 심장이다.

 

 

3. 실행자의 혼란: 나는 누구인가?

이 '빙의' 상태는 msg.sender의 정의를 완전히 뒤바꾼다. 다시 한번 사용자, A, B의 관계를 DELEGATECALL 환경에서 살펴보자.

  1. 사용자(User)가 계약 A를 호출한다. msg.value에 1 이더를 담아 보낸다.
  2. 계약 A는 이 호출을 받는다. A가 인지하는 msg.sender는 'User'이며, msg.value는 '1 이더'다.
  3. 계약 A(프록시)는 로직을 실행하기 위해 계약 B(구현체)에게 DELEGATECALL을 실행한다.

여기서 결정적인 차이가 발생한다. DELEGATECALL은 호출의 '맥락'을 그대로 보존하여 전달한다. 계약 B의 코드가 실행되는 순간, B의 코드가 msg.sender를 확인하면, 그 값은 계약 A가 아니다. msg.sender는 이 모든 연쇄 호출의 최초 시작자인 'User'다.

 

B의 코드는 자신이 누구에 의해 실행되는지 혼란에 빠질 수 있다. 코드는 분명 B의 것이지만, 그 코드가 바라보는 msg.sender는 A를 건너뛴 User를 가리킨다. 이는 B의 코드를 작성할 때 극도의 주의가 필요함을 의미한다. 만약 B의 코드에 require(msg.sender == owner, "Only owner") 같은 보안 구문이 있다면, 여기서 말하는 owner는 B의 owner가 아니라, 이 코드를 실행하는 주체인 A의 저장소(Storage)에 저장된 owner 변수를 의미하게 된다. B는 완벽하게 A의 시점으로 세상을 보게 된다.

 

 

4. 자산의 흐름: 돈은 어디로 가는가

msg.value 역시 마찬가지다. 사용자가 1 이더를 담아 A에게 보냈을 때, 이 1 이더는 계약 A의 잔고로 들어간다. DELEGATECALL이 B의 코드를 실행할 때, B의 코드가 인지하는 msg.value 역시 A가 전달받은 '1 이더'다.

 

만약 B의 코드에 "입금된 msg.value를 장부에 기록한다"는 로직이 있다면, 이 로직은 B의 장부가 아닌 A의 장부(Storage)에 1 이더를 기록한다. 1 이더라는 자산은 물리적으로 계약 A에 귀속되며, B의 잔고는 0을 유지한다. B는 A의 자산을 처리하는 논리적 대리인일 뿐, 자산을 소유하지 않는다.

 

이것이 프록시가 업그레이드되어도 자산이 안전한 이유다. 모든 자산(토큰 잔액, 소유권 등)은 영구적인 주소를 가진 프록시 계약 A에 저장된다. 로직을 담은 구현 계약 B, C, D는 언제든 교체될 수 있지만, 이들은 A의 자산을 직접 소유하지 않고 오직 A의 맥락 안에서 A의 자산을 조작하는 코드 조각일 뿐이다.

 

 

5. 완벽한 빙의: 맥락이라는 이름의 유산

DELEGATECALL은 단순한 함수 호출이 아니라, EVM이 허용하는 가장 깊은 수준의 신뢰이자 위임이다. 계약 A는 계약 B의 코드에 자신의 모든 것을 내어준다. 자신의 정체성(address(this)조차 A를 가리킴), 자신의 모든 자산(Storage), 그리고 자신을 호출한 사용자의 신원(msg.sender)과 자금(msg.value)까지도.

 

이 모든 것을 통틀어 '맥락(Context)'이라 부른다. CALL이 두 주체가 각자의 맥락을 유지한 채 대화하는 것이라면, DELEGATECALL은 A가 자신의 맥락을 그대로 유지한 채 B의 두뇌(코드)만 빌려와 사용하는 것이다.

 

이 완벽한 빙의야말로 수정 불가능한 블록체인 위에서 '업그레이드'라는 마법을 가능하게 하는 핵심 기제다. 프록시(A)라는 영속적인 신체는 그대로 두고, 그 신체를 움직이는 논리(B)만을 교체할 수 있는 이유. 그것은 DELEGATECALL이 B의 코드를 A의 시점, A의 자산, A의 권한으로 실행시키기 때문이다. 즉, B는 A 그 자체가 되어 행동한다.

 

3줄 요약

[1] 일반 CALL은 A가 B를 호출하면, B의 msg.sender는 A가 되며 각자의 저장소를 사용한다.

[2] DELEGATECALL은 A가 B의 코드를 빌려와 A의 저장소와 맥락(Context)에서 실행하는 '빙의'다.

[3] DELEGATECALL 실행 시, B의 코드가 보는 msg.sender와 msg.value는 A가 아닌, A를 호출한 '최초 사용자'의 것이 된다.