안녕하세요.
이번 글에서는 다음의 내용에 대하여 간략하게 알아보겠습니다.
이더리움에는 두 가지 종류의 계정이 존재합니다. 하나는 일반 사용자 계정에 해당하는 EOA(Externall Owned Accounts) 와 컨트랙트 계정 CA(Contract Account)가 존재합니다.
먼저 EOA는 비트코인의 계정과 매우 유사한 개념입니다. 보통 타원곡선암호(ECDSA)로 개인키와 공개키를 생성하고, 개인키를 통해서 계정과 관련된 모든 작업을 처리합니다.
반면, 이러디움에서는 블록체인에 저장된 컨트랙트 또한 계정으로 간주하고, 이를 CA라고 부릅니다. 그래서 CA와 관련된 모든 작업은 개인키에 의해서 제어된다기보다는 컨트랙트 코드의 로직에 의해서 처리가 된다고 볼 수 있습니다.
EOA 계정의 주소는 타원곡선암호를 통해 생성된 개인키와 공개키에 해시 함수를 적용해서 계정의 주소를 만들어냅니다.
반면에 CA의 주소는 개인키와 공개키를 사용하지 않고, 컨트랙트를 배포한 계정의 주소와 배포된 트랜잭션에 포함된 논스 값에 해시 함수를 적용해서 주소를 생성합니다.
이렇게 생성된 EOA 계정과 CA 계정의 주소는 모두 160bit로 표현이 됩니다.
이더리움에서 트랜잭션의 종류는 아래와 같이 크게 3가지 종류가 있습니다.
보통 이더리움 트랜잭션에는 여러가지 정보가 담겨집니다. 주로 논스, 가스, 트랜잭션 수신자의 주소, 송금되는 이더 금액 그리고 전자서명 등의 정보가 포함됩니다.
항목 | 내용 |
---|---|
nonce | 계정에서 발생시킨 트랜잭션의 누계 |
gasPrice, gasLimit | 트랜잭션을 실행할 때 지불해야 하는 가스 비용 정보 |
to | 트랜잭션 수신 계정의 주소 |
value | 송금되는 ETH 금액(암호화폐를 송금할 때 사용) |
v, r, s | 타원곡선암호(ECDSA)를 사용하는 송신 계정의 전자서명 |
init | 스마트 컨트랙트 코드(스마트 컨트랙트를 배포할 때 사용) |
data | 스마트 컨트랙트 파라미터(스마트 컨트랙트를 실행할 때 사용) |
스마트 컨트랙트의 호출과 관련해서 계정 간의 커뮤니케이션은 트랜잭션 또는 메시지 콜, 두 가지 유형이 존재합니다.
EOA가 CA의 컨트랙트를 호출하는 것은 트랜잭션이라 하고, 어떤 CA의 컨트랙트가 다른 CA의 컨트랙트를 호출하는 것은 메시지 콜이라고 합니다.
컨트랙트 호출은 반드시 EOA로부터 CA로의 트랜잭션으로 시작되어야하며, 이후 컨트랙트 간의 호출은 메시지 콜로 실행됩니다.
스마트 컨트랙트 실행과 관련된 계정은 크게 세 가지가 있을 수 있습니다.
배포자 계정은 트랜잭션을 통해 컨트랙트를 블록체인에 저장 또는 배포하는 계정을 말합니다. 컨트랙트 계정은 스마트 컨트랙트 코드가 존재하는 계정이고, 사용자 계정은 트랜잭션을 통해 컨트랙트 함수를 호출하는 계정입니다.
트랜잭션과 메시지 콜 모두 항상 메시지(msg)라는 객체가 만들어져서 전달이 됩니다. 이 메시지 객체에는 몇 가지 속성이 있습니다.
항목 | 내용 |
---|---|
msg.sender | 메시지 발송자의 주소 |
msg.value | 송금된는 ETH 금액 |
msg.data | 컨트랙트 파라미터(calldata) |
msg.sig | msg.data의 앞 4byte로서 호출되는 함수의 식별자 |
이러한 메시지 정보(속성 정보)는 스마트 컨트랙트 코드를 작성할 때 코드 상에서 참조가 가능합니다.
pragma solidity ^0.6.4;
contract Callee {
address payable public transactionOrigin;
address payable public msgSender;
address payable public owner;
constructor() public {
owner = msg.sender;
}
function bar() public payable {
transactionOrigin = tx.origin;
msgSender = msg.sender;
}
}
contract Caller {
address payable public transactionOrigin;
address payable public msgSender;
address payable public owner;
constructor() public {
owner = msg.sender;
}
function foo(address payable _addr) public {
transactionOrigin = tx.origin;
msgSender = msg.sender;
Callee callee = Callee(_addr);
callee.bar();
}
}
Caller와 Callee를 각각 배포 후 Caller의 foo함수를 실행하면 Callee의 변수에는 어떤 값이 들어오게 될까요?
위 코드를 직접 컴파일하고 배포하여 확인해보면 트랜잭션과 메시지콜의 분명한 차이점에 대하여 바로 알 수 있습니다.
이더리움의 블록은 블록 헤더와 트랜잭션 목록으로 구성됩니다.
블록 헤더에는 이전 블록의 해시값, 작업 증명(PoW)에 사용되는 논스 값 및 메인 체인에서 채택되지 못한 엉클 블록의 헤더도 포함이 됩니다. 또한 기타 다양한 부가적 정보를 저장하는 트리에 대한 루트 등을 포함하고 있습니다.
트랜잭션 목록에서는 발생한 트랜잭션의 정보가 포함이 되며, 일반적으로 블록의 가스 총량이 허용하는 수량만큼의 트랜잭션이 하나의 블록에 포함될 수 있습니다.
블록 헤더에는 몇 가지 트리의 정보를 포함하고 있는데요. 이것을 머클 패트리샤 트리라고 합니다.
머클 패트리샤 트리는 일반적인 자료구조에서 사용되는 Radix 트리와 해시들을 트리로 엮은 머클 트리가 결합된 개념입니다.
이더리움에서는 이러한 머클 패트리샤 트리를 사용하고 있고, 머클 패트리샤 트리는 총 네가지로 유지되고 있습니다.
이더리움의 계정과 종류, 트랜잭션의 유형 및 트랜잭션과 메시지 콜의 차이점, 블록의 구성요소에 대하여 살펴보았습니다. 감사합니다.