본문으로 건너뛰기
0%

Solidity의 selfdestruct란?

작성자 John Favole

2023년 9월 25일에 게시됨4분 읽기

업데이트: Selfdestruct는 EIP-6049에 명시된 대로 Shanghai Ethereum 업그레이드 과정에서 폐기되었습니다. 이 글은 이제 오래된 정보이며, 해당 기능이 이전에 어떻게 작동했는지만 다룹니다.

_Selfdestruct_는 개발자가 컨트랙트를 종료하고자 할 때 사용하던 Solidity의 키워드입니다. 2021년 연구 논문 "Why Do Smart Contracts Self-Destruct? Investigating the Selfdestruct Function on Ethereum"에 따르면 약 800개의 컨트랙트가 selfdestruct 키워드를 포함하고 있어, Solidity를 공부하면서 알아둘 만한 중요한 개념입니다.

이 글에서는 _selfdestruct_가 무엇이었는지 정의하고, 그 목적을 설명하며, Solidity 스마트 컨트랙트에서 _selfdestruct_를 구현하는 예제를 제공합니다.

Selfdestruct란 무엇인가?

Selfdestruct는 컨트랙트를 종료하고, Ethereum 블록체인에서 바이트코드를 제거하며, 컨트랙트에 남아 있던 자금을 지정된 주소로 전송하는 데 사용되던 키워드입니다.

_Selfdestruct_는 2016년, Ethereum 블록체인과 탈중앙화 조직(DAO)이 초기 단계에 있던 시기에 등장했습니다. 초기 DAO 중 하나가 해킹으로 360만 ETH를 잃었습니다. Solidity 컨트랙트의 불변성 때문에 이 공격은 며칠간 지속되었습니다. 당시에는 컨트랙트를 파기할 방법이 없었기 때문에, 초기 DAO 개발자들은 추가 악용을 막기 위해 블록체인 전체를 포크했습니다.

이런 이유로 _selfdestruct_는 보안 위협이 발생했을 때 대피구 역할을 하도록 만들어졌습니다. 처음에는 "suicide function"이라 불렸지만, Solidity v0.5.0부터 _selfdestruct_로 이름이 바뀌었습니다.

개발자들은 왜 selfdestruct 함수를 사용했는가?

개발자들은 주로 스마트 컨트랙트 코드의 보안을 개선하고, 사용하지 않는 컨트랙트를 정리하고, Ethereum 자산을 빠르게 이전하기 위해 selfdestruct 함수를 사용했습니다.

_Selfdestruct_는 개발자가 스마트 컨트랙트를 업그레이드해야 할 때 유용했습니다. 예를 들어 ERC-20 프레임워크는 상호운용성을 위해 Ethereum상의 모든 대체 가능 토큰(fungible token)에 대한 표준 구현체입니다. ERC-20 표준과 인터페이스하지 않는 토큰은 다른 컨트랙트와 상호작용하는 데 어려움을 겪게 됩니다.

이런 경우 개발자들은 현재 컨트랙트를 업그레이드하는 대신 새로운 컨트랙트로 전환합니다. 따라서 selfdestruct 함수를 사용해 현재 컨트랙트에서 자금을 인출하고, 필요한 기능을 갖춘 새 컨트랙트를 만들 수 있었습니다.

개발자들은 또한 잠재적 보안 위협에 대비하기 위해 selfdestruct 함수를 사용했습니다. 같은 2021년 selfdestruct 스마트 컨트랙트 보고서에 따르면, 개발자가 자신의 컨트랙트에서 보안 결함을 발견했을 때 selfdestruct 함수는 결함이 있는 컨트랙트를 즉시 종료하고 안전한 컨트랙트로 교체하는 데 도움이 되었습니다.

Selfdestruct 사용의 단점은 무엇인가?

Selfdestruct 함수의 단점은 ERC-20 토큰을 복구할 수 없다는 점과, 자기 파괴 이후 토큰을 다른 곳으로 재전송할 수 없다는 점입니다.

일반적으로 selfdestruct 함수는 컨트랙트 종료를 제때 알리지 않은 개발자들에 의해 호출됩니다. 팀이 업데이트를 공지하더라도 충분히 빠르게 퍼지지 않을 수 있습니다. 그 결과 일부 사람들은 컨트랙트가 여전히 활성화되어 있다고 생각하고 파기된 컨트랙트로 자금을 보내게 될 수 있습니다. 이 경우 해당 자금은 손실됩니다.

selfdestruct 사용의 두 번째 단점은 이 함수가 Ether(ETH)만 전송할 수 있고, 알트코인이나 ERC-721 토큰 표준을 따르는 NFT와 같은 다른 ERC-20 토큰은 전송할 수 없다는 점입니다. _selfdestruct_가 호출되면 이러한 자산은 결코 복구할 수 없습니다.

일부는 왜 selfdestruct 함수를 위험하다고 여겼는가?

Selfdestruct 함수는 악의적인 개발자가 러그풀(rug pull)을 실행하기 더 쉽게 만들었습니다.

이 함수를 통해 개발자는 _selfdestruct_를 호출하고 자금을 자신의 개인 지갑으로 보낼 수 있었습니다. 이런 이유로 일부 프로토콜 사용자와 개발자들은 selfdestruct 함수 사용에 대해 엇갈린 반응을 보였습니다.

Selfdestruct는 어떻게 작동하는가?

Selfdestruct는 체인에서 컨트랙트 바이트코드를 지우고, 남아 있는 유동성을 지정된 주소로 전송한 다음, 개발자에게 가스 수수료 일부를 환급하는 방식으로 작동합니다.

컨트랙트는 상태(state)와 함수(function)라는 두 가지 요소로 구성됩니다. 이 요소들이 컨트랙트의 동작과 호출 가능한 함수를 정의합니다. 바이트코드를 제거한다는 것은 컨트랙트를 정의하는 요소가 없어진다는 뜻이며, 이로 인해 컨트랙트를 더 이상 호출할 수 없게 됩니다.

selfdestruct 함수에는 파기 후 컨트랙트 자금이 어디로 가야 하는지를 나타내는 필수 파라미터가 있었습니다.

네거티브 가스(negative gas)란 무엇이며 왜 중요한가?

네거티브 가스는 개발자가 selfdestruct 함수를 사용할 때마다 Ethereum 체인이 환급해 주는 트랜잭션 수수료의 일부를 가리킵니다.

Ethereum은 블록체인에서 데이터를 제거함으로써 발생하는 가스 절감분을 호출자에게 보상함으로써 selfdestruct 함수 사용을 장려했습니다. 컨트랙트가 selfdestruct 함수를 호출하면, 트랜잭션에 사용된 총 가스의 절반이 호출자에게 환급되었습니다.

Selfdestruct는 Ethereum 블록체인상의 컨트랙트 이력을 제거하는가?

아니요, selfdestruct 함수는 Ethereum 체인에서 컨트랙트의 이력을 제거하지 않습니다 — 이 함수는 컨트랙트의 바이트코드만 제거합니다.

Ethereum은 상호 연결된 노드 네트워크가 항상 블록체인 상태의 사본을 보관하는 퍼블릭 원장, 즉 블록체인입니다. 따라서 selfdestruct 함수를 호출하기 전에 이루어진 모든 데이터와 트랜잭션은 온체인에 영구적으로 기록되며 변경할 수 없습니다.

Selfdestruct 함수를 호출한 후 자금은 영구적으로 사라지는가?

아니오이면서 예입니다. 기존 ETH는 함수 호출자가 지정한 다른 주소로 전송되지만, ERC-20 토큰은 손실됩니다.

또한 누군가 selfdestruct된(즉, 종료된) 컨트랙트로 자금을 보내면, 그 자금은 재전송되지 않고 손실됩니다.

Selfdestruct 함수 예제

이 프로그램의 목표는 컨트랙트 내 ETH가 특정 금액에 도달할 때까지 NFT 민팅을 허용하는 것입니다. 해당 금액에 도달하면 프로그램은 보너스로 모든 Ether를 마지막 민터의 지갑으로 전송합니다. 각 사용자는 1 Ether로 여러 개의 NFT를 민팅할 수 있지만 한 번에 하나씩만 가능합니다. 이 컨트랙트는 프로덕션 환경에서 사용하기 위한 것이 아니라 예제 목적으로만 작성되었습니다.

이 민트 컨트랙트의 주요 문제는 "this.balance"를 사용해 종료 조건을 트리거할 만큼 컨트랙트에 충분한 자금이 있는지를 확인한다는 점입니다. 따라서 공격자는 지정된 한도를 넘기도록 손쉽게 금액을 보낸 다음, selfdestruct 키워드를 사용해 자금을 자신이 선언한 생성자(constructor) 주소로 리다이렉트할 수 있습니다.

따라서 _selfdestruct_를 사용할 때 개발자는 특정 조건을 만족시키기 위해 사용하는 변수에 주의해야 합니다. 컨트랙트 주소나 컨트랙트 내 자금에 대한 참조는 인위적으로 조작될 수 있으므로 사용을 피해야 합니다.

Selfdestruct 함수 사용 방법

Selfdestruct 함수를 초기화하는 것은 간단합니다. 함수 내에서 selfdestruct 키워드를 사용하고, selfdestruct 함수 호출 후 컨트랙트 자금을 받을 수 있는 payable 주소를 지정하면 됩니다.

다음은 Solidity 강좌에서 일반적으로 가르치는 selfdestruct 함수의 예입니다:

이 코드가 하는 일은 다음과 같습니다:

  • 함수의 이름은 destroy입니다
  • 파라미터는 apocalypse라는 이름으로 주소를 지정합니다
  • destroy 함수가 호출되면 apocalypse 변수를 통해 주소가 지정됩니다
  • 함수 가시성(visibility)은 public으로 선언되어 다른 컨트랙트도 이를 호출할 수 있습니다
  • 그런 다음 selfdestruct 키워드를 사용하고, apocalypse 변수를 payable로 선언한 뒤 전달합니다

이 함수는 public이기 때문에 잠재적인 보안 결함을 안고 있습니다. 이를 방지하려면 onlyOwner modifier를 추가하거나, require 구문을 사용해 오직 소유자만 destroy 함수를 호출할 수 있도록 확인하는 것을 고려할 수 있습니다.

Alchemy의 Solidity 개발자 과정으로 Solidity와 selfdestruct 함수 배우기

Selfdestruct는 보안 침해가 발생했을 때, 개발자가 컨트랙트를 업그레이드하고자 할 때, 또는 오래된 컨트랙트를 제거하고자 할 때 컨트랙트를 종료하는 안전장치 역할을 합니다. _selfdestruct_의 사용 여부는 Solidity 개발자 커뮤니티에서 여전히 논쟁의 대상이지만, 이 함수의 도입은 많은 잠재적 해킹을 막는 데 도움이 되었습니다.

_selfdestruct_와 같은 중요한 함수에 대해 더 알아보고 더 나은 Solidity 개발자가 되고 싶다면 Alchemy University의 무료 7주 Ethereum Bootcamp에 등록해 보세요. 개발 자체가 처음인 분이라면, Ethereum bootcamp를 시작하기 전 사전 과정으로 Alchemy의 3주 JavaScript 속성 과정을 추천합니다.

Background gradient

블록체인 매직을 만드세요

Alchemy는 가장 강력한 Web3 개발자 제품 및 도구를 리소스, 커뮤니티, 그리고 전설적인 지원과 결합합니다.