Solidity를 하다보면, onlyOwner라는 이름의 modifier가 많이 쓰인다. 그냥 항상 송금/출금 등의 함수에서 당연히 붙이는거니까~ 하면서 쓰고있었는데, 정확한 문법에 대한 이해가 필요할 듯 해 정리해보려고 한다.
modifier onlyOwner() {
require(msg.sender == owner, "caller is not the owner");
_;
}
function withdraw() public onlyOwner {
payable(owner).transfer(address(this).balance);
}
줄마다 보면서 해석해봐야할 것 같다.
1. modifier 함수변경자의 의미
modifier는 "함수변경자, 제어자" 라는 이름으로도 불린다. 즉, 함수의 기능에 있어 특정 기능을 제한/변경할 수 있다는 것이다.
맨 위의 코드를 한번 보자.
modifier onlyOwner()
onlyOwner라는 이름의 modifier를 만들어준다.
onlyOwner는 기본적으로 함수에 이 modifier를 추가해주면, 오직 컨트랙트의 소유자만이 해당 함수를 호출할 수 있게 된다.
정확한 내용을 살펴보자.
require(msg.sender == owner, "caller is not the owner");
_;
msg.sender의 주소가 owner의 주소와 같지 않다면, 에러메시지 "caller is not the owner"를 출력하고, 함수의 실행을 막는다. 여기까진 오케이. 그 다음에 등장하는 "_;"는 대체 무엇일까?
이는, 다시 modifier를 호출한 함수로 돌아가라는 말이다.
이게 무슨 말이지?
다시 맨 위의 코드를 보자.
위 코드에서 withdraw() 함수의 위치에서 onlyOwner modifier가 사용되었고, 그 즉시 컨트랙트는 onlyOwner modfier가 선언된 곳으로 가서 해당 함수를 호출한 사람의 주소와 컨트랙트 소유자의 주소가 같은지를 비교한다.
비교를 한 이후, '_;'부분은, 이제 onlyOwner를 호출한 함수의 나머지 부분을 실행하라는 말이다 즉, 위 코드는 다음과 같다고 할 수 있다.
function withdraw() public {
require(msg.sender == owner, "caller is not the owner");
payable(owner).transfer(address(this).balance);
}
이와 똑같은 코드라고 생각하면 된다.
그래서, '_;'는 모든 modifier의 마지막에 항상 넣어준다고 생각하면 된다.
그럼, 저렇게 쓰면 되는데 왜 굳이 modifier라는걸 만들어서 사용하지..?
확장성을 위함이겠지..ㅎ
2. onlyOwner는 왜 있을까?
onlyOwner는 ownable이라는 컨트랙트에 내장되어있다.
이렇게까지 라이브러리화 하여 사용하는 이유가 있을까?
그 이유는, 블록체인이라는 기술의 특성에 있다.
모두 알겠지만, 블록체인의 중요한 특성 중 하나는 바로, 그 기록들의 '불변성'이다.
이게 무슨말이냐면, 제아무리 컨트랙트를 직접 만든 개발자라고 하더라도, 그 코드를 맘대로 바꿀 수는 없다는 것이다.
EVM(Ethereum Virtual Machine)은 그 구조적 특성상, 컨트랙트 코드의 컴파일 결과물인 바이트코드는 EVM 내의 불변의 영역인 'Storage'에 들어가있다. 때문에 미리 정의된 코드는 그 내용을 절대 바꿀 수 없게 된다.
이로 인해서, 솔리디티 코드를 작성할 때 가장 중요한 것은 보안 다음으로, 유지보수성이다. 즉, 지금 짠 코드를 나중에 어떠한 일이 생겼을 때 언제든 바꿀 수 있어야 한다는 것이다.
따라서 modifier와 같은 제어자 또한 사용해주고, constructor 등의 메서드, 상수 사용의 최소화 등을 해야 한다.
말을 하다 보니 onlyOwner의 필요성은 좀 뒷전으로 하긴 했는데, 이렇게 변수의 사용이 자주 바뀔 수 있게 되다 보니 (owner 등의 변수 포함) 컨트랙트의 ownership 또한 중요하기도 하고, 토큰을 거래하는 데 주로 초점이 맞추어져있는 solidity의 특성 상, 송금 또는 출금을 하는 함수도 많다보니 편리성을 위해 존재하기도 하는, 아주 요긴한 녀석이다.
'web3 > Web3 dev&sec' 카테고리의 다른 글
[Web3 개발/보안] Reentrancy attack(재진입 공격)과 send(), transfer() 그리고 call() (1) | 2024.05.31 |
---|---|
[Web3 개발/보안] contract 함수 직접호출 vs 저수준 호출 (0) | 2024.05.19 |
[Web3 개발/보안] Solidity payable / transfer, call, send / 송금 관련 함수 다루기 (0) | 2024.04.12 |