Solidity

솔리디티의 이상한 상속 계층구조

pangyoelon 2023. 4. 26. 16:43
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/* Inheritance tree
   A
 /  \
B   C
 \ /
  D
*/

contract A {
    function foo() public virtual {
        emit Log("A.foo called");
    }

    function bar() public virtual {
        emit Log("A.bar called");
    }
}

contract B is A {
    function foo() public virtual override {
        emit Log("B.foo called");
        A.foo();
    }

    function bar() public virtual override {
        emit Log("B.bar called");
        super.bar();
    }
}

contract C is A {
    function foo() public virtual override {
        emit Log("C.foo called");
        A.foo();
    }

    function bar() public virtual override {
        emit Log("C.bar called");
        super.bar();
    }
}

contract D is C,B {

    function foo() public override(B, C) {
        super.foo();
    }

    function bar() public override(B, C) {
        super.bar();
    }
}

위와 같은 예제 코드를 보았다

 

일반적으로 생각해 봤을 때 해당 컨트랙트들의 상속구조는 아래와 같다

   A
 /  \
B   C
 \ /
  D

여기서 D컨트랙트를 배포 후 foo함수를 실행시켜보면 예상대로 동작할 것이다

 

그런데 문제는 D컨트랙트의 bar함수인데, bar함수를 실행시켜보면 아래와 같은 로그가 나온다

A -> C -> B

어째서일까? 답을 얻기 위해 코드에서 하나의 변인을 조작해보았다

contract D is B,C {
//            👆 순서를 C,B에서 B,C로 바꿔보았다
    function foo() public override(B, C) {
        super.foo();
    }

    function bar() public override(B, C) {
        super.bar();
    }
}

is 뒤의 두 컨트랙트의 순서를 바꾼 뒤, D의 bar를 실행시켜보면 결과가 전과 다르다

A -> B -> C

그렇다! 

is 뒤에서 선순위 컨트랙트를 후순위 컨트랙트가 오버라이딩을 한다는 뜻은, 단지 덮어쓴다는 게 아니라

 

후순위 컨트랙트가 선순위 컨트랙트의 자식이 된다는 뜻이다!

 

즉 B와 C가 동일선상에 있는 계층구조가 아닌

A
|
B
|
C
|
D

위와 같은 직선형의 계층구조라는 것!