솔리디티 문법 (함수 변경자, 이벤트, 예외 처리, 이더 송수신)

taeheeyoon·2022년 11월 26일
0

Blockchain 이론

목록 보기
12/14
post-thumbnail

함수 변경자(Function Modifiers)

솔리디티에는 함수에 작업을 추가하는 함수 변경자, 즉 Function modifier라고 불리는 개념이 있습니다. 함수 변경자는 modifier라는 키워드로 시작하며 변경자의 이름, 그리고 실행할 코드로 구성이 됩니다.

modifier check{
	require(msg.sender == owner);
    	mutex++;
        _;
        mutex--;
}

function getWithCheck() public check {
	if(mutex == 1)
    	exeCount = exeCout + 1;
}

코드 내부에서는 밑줄( _; )이 등장합니다. 이는 변경자가 적용된 함수가 실행될 위치를 의미합니다.
변경자를 적용할 함수는 시그니처의 맨 뒤에 변경자 이름을 표시하면 됩니다.

이벤트(Event)

컨트랙트 실행 중에 발생하는 정보를 블록체인 상에 저장하는 것도 가능한데요. 이를 보통 이벤트라고 부릅니다. 이벤트는 컨트랙트의 실행이 끝나면 트랜잭션 receipt에 기록이 되어서 블록체인상에 영속적으로 저장이 됩니다.

contract ClientReceipt{
	event Deposit(
    	address indexed _from,
        bytes32 indexed _id,
        uint _value
    );
    
    function deposit(bytes32 _id) public payable {
    	emit Deposit(msg.sender, _id, msg.value);
    }
}

기록할 정보의 구조는 이벤트라는 키워드로 정의가 되는데요. 이는 구조체를 정의하는 방법과 유사합니다.
그리고 컨트랙트 코드의 실행중에 emit이라는 키워드를 사용하여 event 구조를 따르는 일련의 데이터를 발생시킬 수 있습니다.
event 구조에서는 최대 3개의 indexed라는 키워드를 사용할 수 있는데요. indexed가 붙은 항목은 나중에 이벤트 내용을 블록체인 상에서 검색할 때 인덱스 역할을 합니다. 그래서 특정 정보를 검색하거나 필터링해서 원하는 정보를 찾을 때 도와주는 역할을 하게 됩니다.

  • 최대 3개까지 indexed 지정가능
    • 로그의 topics에 기록 : 이벤트 내용을 블록체인상에서 검색할 때 인덱스 역할

이벤트 구독

컨트랙트에서 발생시킨 이벤트 정보는 애플리케이션에서 검색 및 구독이 가능합니다. 솔리디티 컨트랙트 코드에서는 이벤트 정보를 직접 접근할 수는 없고, 다만 web3.js 라는 라이브러리를 통해서 블록체인의 트랜잭션 receipt에 기록된 이벤트 정보를 접근하는 것이 가능합니다.
이벤트 정보를 읽는 방법은 여러가지가 있는데, 특히 web3.eth.subscribe라는 JavaScript API가 많이 사용됩니다.
이 함수에서는 options라는 파라미터를 이용하여 원하는 정보가 포함된 이벤트만을 선별적으로 구독하는 것을 가능하게 합니다.

예외(exception) 처리

솔리디티에서는 3가지의 예외, 즉, exception을 처리하는 방법이 있습니다. 3가지 방법 모두 공통적으로 트랜잭션의 작업을 종료시키고, 현재까지 트랜잭션에 의해 변경되었던 블록체인상의 모든 상태를 원래의 초기상태로 복원을 시킵니다.
예외를 처리하는 방법은 아래의 3가지 방법이 있습니다.

  • Assert(bool condition)
    • 내부적인 상태 및 불변성(invariant) 검사 등에 적용
  • Require (bool condition, string memory message)
    • 입력 파라미터 또는 출력값 검사 등에 적용
    • message는 optional
  • Revert (string memory reason)
    • 예외를 즉시 발생시키고 상태를 복원(reason는 optional)

Assert 함수는 임의의 조건을 검사하여, 조건이 참이 아니면 상태복원, 즉 revert 행위를 발생 시킵니다. assert는 주로 컨트랙트의 내부적인 상태나 컨트랙트 코드 상에서 항상 성립해야하는 성질, 보통 invariant라고 하는데요. 그러한 성질들을 검사하는데 주로 사용됩니다.

Require는 Assrert와 비슷합니다. 다만, 조건 검사에서 실패할 경우 예외와 관련된 메시지를 추가로 리턴한다는 점이 다릅니다. require는 일반적으로 입력 파라미터 또는 출력값의 유효성을 검사하는데 주로 사용됩니다.

마지막으로 revert 함수는 조건 검사는 없고 이 revert 함수가 실행이 되면 즉시 컨트랙트 코드상에서 예외를 발생시키고 상태를 원래의 초기상태로 복원하는 행위를 실행합니다.

이더리움 송수신 방법

이더 송금을 위한 함수

이더리움을 송금하려면 address 자료형의 멤버함수인, transfer, send, call 함수를 이용해야합니다. 이 때 address에는 이더리움 수신자의 주소를 사용해야 합니다.

  • address.transfer()
    • 실패시 예외(exception) 발생, 컨트랙트 실행을 중단하고 revert
  • address.send()
    • 실패시 bool 값을 반환, 컨트랙트 실행을 계속
  • address.call()
    • 실패시 bool 값을 반환, 컨트랙트 실행을 계속

transfer 함수는 송금이 실패할 경우 예외를 발생시키면서 컨트랙트 실행을 중단하고 상태를 복원합니다.
send 함수는 송금이 실패하더라도 컨트랙트의 나머지 코드 실행을 계속하며, 송금작업의 성공 또는 실패를 알려주는 bool 자료형 값을 리턴합니다.
call 함수는 원래 이더리움을 송금하는 용도로 만들어진 것은 아니고 주소를 이용해서 그 해당 주소 상의 컨트랙트가 제공하는 함수를 호출하기 위해서 만들어진 함수입니다. 그러나 이 call 함수를 통해서 특정 함수를 선택해서 호출하는 것은 물론이고 동시에 이더를 전송하는 것도 가능합니다.
따라서 이 call 함수도 이더를 보내는 방법 중 하나라고 볼 수 있습니다.

이더 수신을 위한 함수

송금된 이더를 수신하는 방법에도 여러가지 방법이 있습니다.

  • payable 함수 : 상태변경성이 payable로 지정된 함수
    • 함수를 호출할 때 이더(ether)를 함께 송금할 수 있으며, 호출된 함수가 payable로 지정되면 이더(ether)를 수신할 수 있음
  • receive() 함수 : 컨트랙트별 최대 하나의 이더 수신 함수 receive 허용
    • function 키워드가 생략되고 인자값과 리턴값을 가지지 않음
    • 형식 : receive() external payable {...}
  • fallback 함수 : 함수 호출 조건이 만족되지 않을 경우 대신 실행되는 함수
    • payable로 지정될 경우 이더 수신 가능
    • 형식 : fallback() external [payable]

첫 번째 방법은 특정 함수의 상태변경성을 payable로 지정하는 것입니다. 이더리움에서는 함수를 호출할 때 이더(ether)를 같이 실어서 송금하는 것이 가능한데요. 만약에 그 때 호출된 함수가 payable로 지정되어 있다면 그 이더를 수신하는 것이 가능합니다.
두 번째 방법은 컨트랙트에 receive라는 특별한 함수를 정의하는 것입니다. 컨트랙트의 특정한 함수를 호출하지 않고, 상대쪽에서 send 또는 transfer를 통해 이더리움만 송금할 경우가 있는데요. 이럴 경우에는 컨트랙트의 receive 함수가 자동으로 호출이 되면서 보내진 이더리움을 송금하는 작업을 실행하도록 되어 있습니다.
receive 함수는 function 키워드가 생략이 되고, 보통 인자와 리턴 값도 가지지않는 특수한 형태의 함수라고 볼 수 있습니다.

마지막으로 조금 특별한 fallback 함수가 있습니다.
원래 fallback 함수의 용도는 컨트랙트에 존재하지 않는 함수가 호출되거나 또는 파라미터의 어떤 형식이나 타입이 잘못됐을 때처럼 만일의 경우를 대배해서 호출되는 함수를 말합니다.
이런 fallback 함수가 payable로 지정되어 있다면 이더리움이 보내졌을 때 송금된 이더리움을 수신하는 함수로도 활용이 가능합니다.

profile
생각하는 대로 살지 않으면, 사는 대로 생각하게 된다.

0개의 댓글