[이더리움 메모] 트랜잭션의 실전적 종류 구분.
이더리움에서는 각종 함수콜에 관련된 용어와 용도가 난무하여 혼동을 가중 시키고 있는데요. 일반적으로 트랜잭션은 쓰기를 말하고, 콜은 읽기를 말합니다. (CQRS처럼 커맨드와 쿼리가 더 일반적이죠) 하지만 이것은 너무 대략적으로 말한것이라 좀 더 구체적으로 구분해 볼 필요가 생겨서 본 글을 쓰게 되었습니다. (오류가 있을 수 있으며, 이더리움이 업데이트 될 수 있습니다. 재진입같은 보안 이슈는 다루지 않습니다.)
호출 방식
1. Message (Internal tranaction) : 컨트랙트에서 컨트랙트로 호출 하는 것 or 컨트랙트에서 EOA 로 이더전송. 채굴 할 때 까지 대기하지 않으며 즉시 호출. 처음 발생되는 Transaction 호출에 의해 일어나는 부분이다. 따라서 message 에 소모되는 가스 비용은 처음 tranaction 에 포함된다. 최대 1024 Depth 까지 호출될 수 있다.
1-1. 컨트랙트 -> 컨트랙트에는 로우레벨적으로 (메세지) Call 과 (메세지) DelegateCall 이 있다.
Delegatecall은 호출하는 컨트렉트의 context에서 타켓 주소의 코드가 실행되고 msg.sender와 msg.value의 값이 변경되지 않는다는 점을 제외하면 그냥 메시지 콜과 동일하다. (사실 큰 차이이다) 이는 컨트렉트가 실행될 때 다른 주소로부터 코드를 다이내믹하게 읽어들일수 있다는 것을 의미한다. 저장 장소, 현재 주소, 잔액은 여전히 호출하는 주소를 참조하고, 코드만이 호출된 주소로부터 읽어 들이게 된다. msg.sender / tx.origin 는 최초 호출한 EOA 가 되며, this 는 호출한 컨트랙트가 된다. 이는 library함수를 호출할 때와 동일한데 library 를 그냥 콜할때 내부적으로 delegateCall이 호출되기 때문이다. (간단하게 말하면 일반 컨트랜트간 일반 CALL은 저장소 니꺼 사용, DelegateCall은 내꺼 사용)
1-2. 컨트랙트에서 이더 전송 에는 SEND/TRANSFER/CALL 이 있다. 모두 OPCODE 로는 CALL 이다. (
send is now deprecated.)
- (opcode) call 함수가 value와 함께 호출될 때 call함수는 받은 모든 가스를 전달한다. 즉 send/transfer 는 2300가스 고정이고, call 을 이용하면 set(gaslimit) 할수 있다.
- (opcode) call 을 직접적으로 사용해서 컨트랙트를 호출하지 않는것을 권장한다. 그냥 함수이름으로 호출 ㄱㄱ
2. Transaction: EOA 에서 호출하는 것
2-1. sendTransaction: 네트워크에 보내지며 채굴에 의해 확인 받아야 한다. 서명이 필요하며, 채굴 받될 때까지 결과를 얻을 수 없다. 가스를 소모하며 보통 상태를 변경하다. ( 새로운 컨트랙트 만들기, 컨트렉트 호출, 다른 EOA 로 이더보내기)
sendTransaction vs sendRawTransaction
sendTransaction 는 매개변수로 from Address가 필요한데, 트랜잭션에 필요한 개인키를 그걸 통해서 찾기 때문이다. Ethereum client에서 관리하는 개인키를 찾아서 사인해 주세요의 의미이다.
sendRawTransaction 는 from Address가 필요없는데, 개인키 관리를 클라이언트가 알아서 하기 때문이다. 지갑같은 것을 통해 자기가 직접 가져와서 트랜잭션을 직접 서명함. 서명된 데이터(그 안의 private key) 로 부터 public key가 추출되고 그것으로 부터 from Address도 추출되기 때문에 굳이 매개변수로 넣어주지 않는 것이다.
2-2. call: 자신의 노드에서만 실행된다. read-only로 실행되며 즉각적으로 결과를 알 수 있으며, 비용이 들지 않는다.
* yellow paper 에 나오는 "메세지 콜" 이라는 용어는 혼동을 초래하므로 제외 하는게 좋다. 위에 말했다시피, call은 컨트랙트간 호출에서도 사용되는 용어이며, 컨트랙트에서 EOA로 이더를 전송하는 OPCODE에도 CALL이 있다.
아래 3가지 web3 호출 의 차이점
1.testInstance.testfunc({from:eth.accounts[0]})
2.testInstance.testfunc.sendTransaction({from:eth.accounts[0]})
3.testInstance.testfunc.call({from:eth.accounts[0]})
-
testfunc
가 constant 라벨이 붙었으면, #3번과 같고, 그렇지 않다면 #2와 같다.
* solc 0.4.17 부터 제거 되었으며, view 나 pure 를 사용한다. - 위의 구분에서 sendTransaction 를 말한다.
- 위의 구분에서 call 을 말한다.
정리
* OP 코드에 따라 아래와 같은 가스 소모가든다.
Operation Name | Gas Cost | Remark |
---|---|---|
step | 1 | default amount per an execution cycle |
stop | 0 | free |
suicide | 0 | free |
sha3 | 20 | |
sload | 20 | get from permanent storage |
sstore | 100 | put into permanent storage |
balance | 20 | |
create | 100 | contract creation |
call | 20 | initiating a read only call |
memory | 1 | every additional word when expanding memory |
txdata | 5 | every byte of data or code for a transaction |
transaction | 500 | base fee transaction |
contract creation | 53000 |
changed in homestead from 21000
|