[마스터링 이더리움] Chapter 6. 트랜잭션

이희제·2021년 1월 7일
8

Mastering Ethereum

목록 보기
2/6
post-thumbnail

안녕하세요 스크립토 6기 이희제입니다.

오늘은 이더리움에서의 트랜잭션에 대해서 알아보겠습니다.


트랜잭션은 외부 소유 계정(EOA)에 의해 서명된 메시지로, 이더리움 네트워크에 의해 전송되고 이더리움 블록체인에 기록됩니다.


트랜잭션 구조

➡️ 트랜잭션은 다음 데이터를 포함하는 시리얼라이즈된 바이너리 메세지 입니다.

  • 논스(nonce): 발신 EOA에 의해 발행되어 메세지 재사용을 방지하는 데 사용되는 일련번호
  • 가스 가격(gas price): 발신가자 지급하는 가스의 가격(웨이, wei)

  • 가스 한도(gas limit): 이 트랜잭션을 위해 구입할 가스의 최대량

  • 수신자(recipient): 목적지 이더리움 주소

  • 값(value): 목적지에 보낼 이더의 양

  • 데이터: 가변 길이 바이너리 데이터 페이로드

  • v,r,s: EOA의 ECDSA 디지털 서명의 세 가지 구성요소


✅ 트랜잭션 구조를 살펴보면 발신자(from)의 데이터가 없다는 것을 알 수 있습니다. 이 발신자에 대한 정보는 v,r,s 구성요소로부터 알아낼 수 있고 이는 공개키를 통해 주소를 알아낼 수 있음을 의미합니다.

출처: https://medium.com/@kimjunyong/블록체인의-정의와-기술-비전공자도-이해하는-기본적-이해-6706ebb43009


트랜잭션 논스

  • 모든 트랜잭션은 일회성이고 고유합니다.
  • 논스(nonce)는 계정에서 보내는 트랜잭션에 할당 된 번호입니다.
  • 거래(transaction)를 전송시 nonce는 1씩 증가합니다.
  • 논스는 계정에서 유일하기 때문에 동일한 논스가 존재 하지 않습니다.

<논스(nonce)의 필요성>
논스는 중복되지 않고 순차적이기 때문에, 같은 논스에 여러 트랜잭션 전송이 발생하였다면 해당 논스 중 제일 높은 가스비를 지불한 트랜잭션이 처리됩니다. 이더리움에서는 이러한 방법으로 이중 지불 문제를 방지합니다.

논스 추적

✅ 논스는 각 계정에서 발생한 확인된, 트랜잭션 건수에 대한 최신 통계입니다.
➡️ 출력된 논스

결과값이 8이기 때문에 저의 계정에서 발생된 트랜잭션은 8개라는 것을 알 수 있습니다.

메타마스크 상에서 실제로 확인을 해보겠습니다.

➡️ 중간에 실패된 것을 제외하고 총 8개로 동일한 것을 확인할 수 있습니다. 😃

새로운 트랜잭션을 생성할 때, 다음 논스를 조회하여 트랜잭션에 포함해야 합니다. 그러나 트랜잭션이 블록체인에 기록(채굴)되기 전까지는 getTransactionCount() 함수의 합계에 포함되지 않습니다.



트랜잭션 가스

➡️ 트랜잭션의 구성요소 중 가스 가격(gasPrice)가스 한도(gasLimit)에 대해서 살펴보도록 하겠습니다.

가스는 이더리움의 연료입니다.
이더리움은 가스를 사용하여 트랜잭션이 사용할 수 있는 자원의 양을 제어합니다.
트랜잭션의 gasPrice 필드는 트랜잭션 생성자가 가스와 교환하여 지급할 가격을 설정할 수 있게 합니다.


⬇️ web3을 사용하여 이더리움 네트워크 평균 가스 가격을 조회할 수 있습니다.


gasLimit는 트랜잭션을 완료하기 위해 트랜잭션을 시도하는 사람이 기꺼이 구매할 수 있는 최대 가스 단위 수를 제공합니다.

단순하게 하나의 EOA에서 다른 EOA로 이더(ether)를 전송하는 트랜잭션에 필요한 가스량은 21,000개로 고정되어 있습니다.

트랜잭션을 전송할 때 첫 번째 유효성 확인 단계 중 하나는 발생된 계정이 (가스가격 * 가스요금)을 지급할 만큼 충분한 이더를 갖고 있는지 확인하는 것입니다.


트랜잭션 수신자

✅ to 필드에 트랜잭셕 수신자가 지정됩니다. 이는 20바이트 이더리움 주소를 포함하고 이는 EOA 또는 컨트랙트 주소일 수 있습니다.

이더리움은 이 필드를 더는 검증하지 않습니다. 그렇기 때문에 잘못된 주고로 이더를 보내게 되면 다시 사용할 수 없는 상태가 됩니다.


트랜잭션 값과 데이터

✅ 트랜잭션의 주요 페이로드(payload)는 값(value)과 데이터(data)라는 2개의 필드에 포함됩니다.

트랜잭션은 값과 데이터, 갑만, 데이터만, 또는 값이나 데이터를 모두 가지지 않는 네 가지 조합이 모두 유효합니다.

  • 값만 있는 트랜잭션은 지급(payment)이라고 합니다.
  • 데이터만 있는 트랜잭션은 호출(invocation)이라고 합니다.

EOA 및 컨트랙트에 값 전달

값을 포함하는 이더리움 트랜잭션을 구성하면 지급(payment)과 동일합니다. 이런 트랜잭션은 대상 주소가 컨트랙트인지 여부에 따라 다르게 작동합니다.

  • EOA 주소인 경우:

이더리움은 상태 변경을 기록하여 주소 잔액에 보낸 값을 추가한다.

  • 컨트랙트인 경우:

EVM은 컨트랙트를 실행하고 트랜잭션의 데이터 페이로드에 지정된 함수를 호출하려고 시도한다.
트랜잭션에 data가 없으면 EVM에서 대상 컨트랙트의 이름없는(fallback) 함수를 호출한다.
그리고 해당 함수가 송금가능(payable)인 경우에는 다음에 수행할 작업을 결정하기 위해 해당 함수를 실행한다.
송금가능(payable) 함수가 성공적으로 실행완료되면 컨트랙트의 ether 잔액에 송금된 금액을 반영하여 컨트랙트 상태가 업데이트된다.


EOA 또는 컨트랙트에 데이터 페이로드 전달

트랜잭션에 데이터가 포함되어 있으면 받는 주소는 컨트랙트 주소가 될 가능성이 큽니다.

트랜잭션이 컨트랙트 주소로 데이터를 전달한다고 하면 데이터는 EVM에 의해 컨트랙트 호출(contract invocation)로서 해석됩니다.

대부분의 컨트랙트에서는 이 데이터를 함수 호출(function invocation)로 사용하며, 함수를 호출하고 인코딩된 인수를 함수에 전달합니다.

✅ ABI 호환 컨트랙트로 전송된 데이터 페이로드는 다음을 16진수로 시리얼라이즈한 인코딩입니다.

함수 선택기(function selector)

➡️ 함수 선택기는 함수 프로토타입의 Keccak-256 해시의 처음 4바이트입니다.


➕➕ 여기서 프로토타입(Prototype)이란?

함수의 프로토타입은 함수의 이름을 포함하는 문자열로 정의되고 각 인수의 데이터 유형이 괄호에 들어가고 쉼표로 구분됩니다.

function withdraw(uint withdraw_amount) public { }

이 함수의 이름은 withdraw이고 인자는 1개밖에 없고 인자의 데이터 유형은 uint입니다.

따라서 이 함수의 프로토타입은withdraw(uint256)이 됩니다.

아래의 그림은 프로토타입 문자열을 keccak-256 해시를 한 결과이고 앞의 4바이트인 0x2e1a7d4d함수 선택기 값이 됩니다.


함수 인수(function argument)

➡️ 함수의 인수는 ABI 사양에 정의된 다양한 기본 유형에 대한 규칙에 따라 인코딩됩니다.

아래의 그림은 인수로 전달할 값을 계산한 것입니다.

최종 트랜잭션 데이터 페이로드

✨ 최종 데이터 페이로드는 함수 선택기와 인수에 있는 값을 합친 아래의 형태가 됩니다.(32바이트)

2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000


특별 트랜잭션: 컨트랙트 생성


디지털 서명

✅ 디지털 서명은 이더리움에서 세 가지 용도로 사용됩니다.

  1. 서명은 이더리움 계정과 개인키의 소유자가 이더 지출 또는 컨트랜트 이행을 승인했음을 증명한다.

  2. 부인 방지(non-repudiation)를 보장한다.

  3. 서명은 트랜잭션이 서명된 후에는 트랜잭션 데이터가 수정되지 않았고 어느 누구도 트랜잭션 데이터를 수정할 수 없음을 증명한다.

디지털 서명 작동 방법

디지털 서명은 두 단계로 구성된 수학적 체계입니다.

  1. 트랜잭션에서 개인키를 사용하여 서명을 만드는 알고리즘

  2. 누구나 메세지와 공개키만 사용하여 서명을 검증할 수 있게 해주는 알고리즘


디지털 서명 만들기

➡️ 디지털 서명은 다음과 같습니다.

S i g = F sig ( F keccak256 ( m ) , k )


마무리

profile
남는 것을 좋아하는 프론트엔드 개발자입니다.

0개의 댓글