추가 공부 [Solidity - 1]

Lumi·2022년 2월 2일
0

Block_Chain_Project

목록 보기
26/30
post-thumbnail

🔥 Solidity - 1

🔨 Scope 설정 및 가스비 절감

가스비를 절감하는 코드는 사용자들에게 많은 유익함을 줍니다.

가스비 절감이 실질적으로 수수료를 절감시키는 행위가 되기 떄문입니다.

  • 실제로 Uniswap에서 가장 낮은 스왑 수수료를 지원하고 있는 이유가
  • 앞으로 말할 내용떄문입니다.

Solidity는 스택이라는 메모리 구조안에 실행되는 코드를 넣고

한번 실행에 스택이라는 곳을 채워가면서 실행이 일어나면 스택을 비워주게 됩니다.

이떄 스택에 담기게 되는 메모리 = 코드 가 많을수록 더 많은 가스비가 발생이 되기 때문에

개발자들은 불편하더라도 가능하다면 스택의 메모리를 비울수 있는 부분에 대해서 고민을 해봐야 합니다.

이런 부분을 지원하기 위해서 등장하는 개념이 Scope설절 입니다.

생각보다 매우 간단한 방식으로 스택의 메모리를 절감할수 있습니다.

function test() external {

 // 이곳에서는 어떠한 코드가 있다고 가정을 하겠습니다. === A
// 코드 작성을 함에 따라 스택이라는 공간에 메모리가 쌓이게 되고
// 메모리가 많이 쌓이고 비워주지 않으면 실행하는데에 더 많은 가스비가 소요 될 것입니다.
// 이때 특정 행위부터 끝까지의 메모리를 비워주고자 한다면

	{
		// 이런식으로 중괄호를 적어줌으로써 해당 영역은 별개의 메모리 영역으로 사용한다는 표시를 해주고
		// 안에 코드를 적어 주면 됩니다. === B
	}
}

A영역에 있는 코드와 B영역에 있는 코드를 생각해 보겠습니다.

이 두 코드는 test()라는 함수 내에 있는 코드입니다.

만약 test()라는 함수가 실행이 되면 일반적인 경우에는 스택에 A+B가 쌓이게 되고

종료되는 시점에 A+B라는 메모리를 사용하게 될 것입니다.

  • 이후 다른 함수도 호출이 되면 더 많은 메모리가 사용이 될 것입니다.

하지만 test()라는 함수안에 예시처럼 {}를 추가하게 된다면
저 영역은 실행이되고 메모리를 비우라는 의미로 사용이 됩니다.

예를들면

test()함수가 종료되는 시점에 A+B라는 메모리가 스택에 쌓여잇을 것 입니다.

이떄 다른 함수도 실행이 된다는 가정하에 총 메모리는 A+B라는 메모리보다 더 많은 메모리가 쌓이게 될 것입니다.

근데 만약 B라는 코드가 {}로 감싸져 있다면

완전히 실행이 종료되는 시점의 스택에 있는 메모리는 A+알파가 될 것입니다.

이것이 무슨 말이냐면
중괄호가 들어가 있는 부분의 코드는 중괄호 까지만 실행이 되고 메모리를 비워준다는 의미가 됩니다.

  • 그렇다고 상태에 영향을 안주는 것이 아니라 영향은 주되 스택에서 해당 부분의 메모리를 없앤다는 의미입니다.

{}안에 들어가는 코드는 해당 영역에서 모두 처리가 끝나야 합니다.

  • 왜냐하면 스택에 들어가는 메모리가 삭제가 되기 떄문입니다.

이런 방식으로 사용이 되면 스택에 메모리가 가벼운 상태로 다른 코드를 또 실행시킬수 있기 떄문에 가스비가 그만큼 절감이 되게 됩니다.

  • 뷔페에서 많이 먹다가 화장실을 갔다오면 더 먹을수 있는 공간이 생간다?? 이런 식으로 이해를 하였습니다 저 같은 경우에는;; ㅎ

대부분의 Solidity코드는 이러한 부분을 크게 고려하지 않고 있지만
대표적으로 Uniswap이 이러한 부분을 잘 고려하여 코드가 짜져 있습니다!!

🔨 DelegateCall

이 영역은 저도 알고 있는 부분이지만 제가 생각했던 부분과 틀린부분을 알게되어 다시 정리를 하였습니다.

DelegateCall은 기본적으로 msg.sender를 유지하는 호출 입니다.

A라는 컨트랙트를 x가 실행시켰을떄 A의 msg.sender은 X가 되고 A라는 컨트랙트가 B를 호출하면

일반적인 경우에는 B의 msg.sender은 A가 됩니다.

하지만 delegateCall을 사용하면 B의 msg.sender은 A가 됩니다.

위와 같은 결과가 틀린말은 아니고 결과적으로는 맞습니다.

하지만 중간 과정에서 살짝 틀린 부분이 있습니다.

저는 기존에 A라는 컨트랙트가 B를 호출한다로 이해를 하고 있었지만

사실은 A라는 컨트랙트에서 B를 가져온다가 맞습니다.

A가 msg.sender를 유지시키면 B를 실행시키는 것이 아닌 A에 B의 코드를 가져와서 실행을 시키는 것으로 이해를 하면 될것 같습니다.

  • 저도 이번에 공부를 하면서 새롭게 알게된 사실입니다!!!

🔨 SelfDestruct

실제로 사용을 해보지는 않았지만 해당 내용에 대해서도 공부를 살짝 하였기 떄문에 정리를 하고자 합니다.

일단 이 코드의 역할은 컨트랙트를 블록체인 네트워크 내에서 삭제하는 코드 입니다.

실행이 되면 해당 컨트랙트를 사용불가능 하지만 실제로 삭제되는 것은 아니고 따로 메모리에 보관이 됩니다.

하지만 굉장히 비효율적이고 위험성이 있는 방법이기 떄문에 이런 부분보다는

Deactivate/Disable를 활용하는 것이 더 뛰어납니다.

이 코드는 별거 없이 bool타입을 활용하여 코드에 제약을 거는 것 입니다.

pragma solidity 0.6.0;

contract Example {
    bool _isActive = true;

    modifier checkActive() {
        require (_isActive);
        _;
    }

    function do1() checkActive public {
        // do something
    }

    function do2() checkActive public {
        // do something else
    }

    function setActivity(bool isActive) public {
        // restrict access to this function
        _isActive = isActive;
    }
}

간단한 예시 코드 입니다.

  • 사실상 코드를 보면 알수 있듯이 단순히 modifier를 활용하는 것과 같습니다.

🔨 create2

특정한 opcode로 컨트랙트가 다른 컨트랙트를 생성하는 방법 입니다.

  • 즉 컨트랙트 내에서 컨트랙트를 생성하는 방법을 말합니다.

이 코도를 통해 만들어지는 컨트랙트는 호출하는 컨트랙트 주소와 nonce값으로 만들어 지게 됩니다.

A라는 컨트랙트에서 B를 생성하면

B를 호출하는 주체는 A이며 A의 nonce값을 가지게 됩니다.

Uniswap을 확인해 보면

assembly {
    pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
        
        === 
        
assembly {
	pair := create2(0, 인자1, 인자2, keccack256)
}

라는 코드가 있고 Uniswap기준 이 코드는 Pair pool을 형성해 새로운 컨트랙트를 만들어주는 코드 입니다.

형식에 대해서는 저도 자세히는 잘 알수가 없었습니다 아직까지는..ㅠ

assmebly안에 적어주는 이유는 create2를 사용하기 위한 공간을 설정해 준다는 의미이며

사실 create2말고도 단순히 new 키워드를 활용해 salt값을 넣어서 새로운 인스턴스를 만들어 줄수도 있지만

대부분의 코드는 create2를 활용을 하였고 이러한 이유는 new 키워드보다 좀더 명시적이기 떄문입니다.

  • 실제로 Uniswap에서도 명시적으로 활용을 하였습니다.

salt는 간단히 말해서 비밀키?? 와 비슷한 역할을 합니다.
저희가 jwt를 활용하여 sign할떄 secret_key를 넣어주는것과 같은 역할을 합니다!

profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글