챕터 6 : 트랜잭션
트랜잭션은 외부 소유 계정(EOA)에 의해 서명된 메세지인데, 이더리움 네트워크에 의해 전송되고 이더리움 블록체인에 기록된다. 이 기본 정의는 놀라울 정도로 매력적인 의미를 담고 있다. 다른 관점으로 바라보면, 트랜잭션은 EVM에서 상태 변경을 유발하거나 컨트랙트를 실행할 수 있는 유일한 방법이라는 것이다. 이더리움은 글로벌 싱글톤 상태 머신이며, 트랜잭션은 이 상태 머신을 움직여서 상태를 변경할 수 있도록 만든다. 컨트랙트는 독자적으로 실행되지 않는다. 또한 이더리움도 자율적으로 실행되지 않는다. 모든 것은 트랜잭션으로부터 시작된다.
다 중요한 말이라 그대로 가져왔다.
이더리움 네트워크에서 모든 상태변화는 트랜잭션으로 이뤄진다.
이더리움 혼자 실행되고 돌아갈 수 있는 게 아니라
그러한 트랜잭션을 전송하는 사용자들과, 그 트랜잭션을 받아줄 노드가 이더리움이라는 커다란 네트워크를 형성하는 것이다.
트랜잭션 구조
트랜잭션은 다음 데이터를 포함하느 시리얼라이즈된 바이너리 메세지다.
논스(nonce)
발신 EOA에 의해 발행되어 메세지 재사용을 방지하는 데 사용되는 일련번호
가스 가격(gas price)
발신자가 지급하는 가스의 가격(웨이)
가스 한도(gas limit)
이 트랜잭션을 위해 구입할 가스의 최대량
수신자(recipient)
목적지 이더리움 주소
값(value)
목적지에 보낼 이더의 양
데이터(data)
가변 길이 바이너리 데이터 페이로드
v, r, s
EOA의 ECDSA 디지털 서명의 세 가지 구성요소
여기서 발신자 정보는 v,r,s로 알아 낼 수 있으므로 따로 담진 않는다.
발신자 정보, 블록번호, 트랜잭션 ID는 블록에 담겨있는 내용이 아니라 클라이언트 소프트웨어에 의해 따로 추가된 정보이다.
트랜잭션 논스
논스 : 해당 주소에서 보낸 트랜잭션 건수 또는 연결된 코드가 있는 계정의 경우 이 계정에서 만든 컨트랙트 생성 건수와 동일한 스칼라 값
논스는 발신 주소의 속성이며 단지 발신 주소의 컨텍스트 안에서만 의미를 갖는다. 그러나 논스는 명시적으로 블록체인 계정 상태에 저장되지 않고, 해당 주소에서 발생한 확인된 트랜잭션 건수를 세어서 동적으로 계산되는 값이다.
논스는 트랜잭션의 생성 위계와 복제 방지를 위해서 필요하다.
이는 비트코인과 달리 이더리움에서 UTXO를 사용하지 않기 때문에 필요한 것이다.
이더리움과 같은 계정 기반 프로토콜에서는 논스가 필수적이다.
1. 생성 위계
블록체인 네트워크에서는 누가 먼저 어떤 트랜잭션을 받을지 장담을 하지 못한다.
따라서 한 지갑에서 2개의 트랜잭션을 보냈을 때, 순서가 엉키는 일이 발생할 수도 있다.
그러한 경우 논스에서 방지를 해준다.
노드는 트랜잭션을 받고 해당 계정에 바로 직전 논스값을 지닌 트랜잭션이 있는지 확인한다.
없다면 해정 트랜잭션을 무시한다.
2. 복제 방지
논스가 없다면 여러분들의 트랜잭션은 그대로 재사용 될 수 있다.
100이더가 담긴 계좌에서 2이더를 다른 사람에게 보낸다고 하자.
해당 트랜잭션을 서명해서 블록에 얹힌다.
하지만 같은 2이더를 같은 계좌에 보내는 트랜잭션의 값은 동일하기 때문에 서명을 했을 때 같은 값이 나오므로
만약 이더를 받은 사람이, 악의적으로 같은 트랜잭션을 계속해서 전송하면 계좌에 잔고가 없어질때까지 그 트랜잭션은 허용된다.
논스추척
web3는 이더리움 네트워크와 인터넷을 연결시켜주는 라이브러리라고 생각하면 될 것 같다.
책에서 메타마스크를 이용해서 web3를 사용하는데 해당 명령어를 콘솔창에 쳐보니 다음과 같이 떳다
해당 주소이다.
https://docs.metamask.io/guide/provider-migration.html#table-of-contents
자세한 내용은 잘 모르겠지만 보안적인 측면 때문에 더이상 유지 관리가 되지 않을거라 삭제했다는 것 같다.
웹3에 getTransactionCount 함수가 있는데, 이 함수는 보낸 트랜잭션이 컨펌될 때까지 값을 증가시키지 않는다.
getTransactionCount 함수를 이용해서 지갑을 만들게 되면, 여러 트랜잭션을 연속적으로 보냈을 때 nonce값이 중복되어 하나의 트랜잭션만 랜덤하게 수락될 것이다.
패리티는 연속적으로 트랜잭션을 전송하더라도 올바르게 계산하는 parity_nextNonce 함수를 제공한다.
논스의 간격, 중복 논스 및 확인
이더리움 네트워크는 논스에 따라 트랜잭션을 순차적으로 처리한다. 즉, 논스가 0인 트랜잭션을 전송한 다음 논스가 2인 트랜잭션을 전송하면, 두 번째 트랜잭션은 어떤 블록에도 포함되지 않는다. 이더리움 네트워크가 누락된 논스가 나타날 때까지 기다리는 동안 두 번째 트랜잭션은 멤풀(mempool)에 저장된다. 모든 노드는 누락된 논스가 단순히 지연되었고 논스가 2인 트랜잭션은 순서가 맞지 않게 수신되었다고 가정한다.
논스사이에 갭이 생기면 그 갭이 메꿔질 때까지 트랜잭션은 실행되지 않고 보류된다.
그 갭이 메꿔지면 보류됐던 트랜잭션도 함께 실행된다. 트랜잭션을 취소하는 것은 불가능하다.
대신 중복 논스 값을 보냄으로써, 앞서 보냈던 트랜잭션을 거부시킬 수 있다.
하지만 이 또한 가스비가 든다는 사실을 알아두어야한다.
https://wookoa.tistory.com/381
동시 실행, 트랜잭션 생성 및 논스
동일한 지갑, 다른 환경에서 동시에 트랜잭션을 생성하는 경우에 어떻게 모든 트랜잭션을 성공시킬 수 있을까?
단일 컴퓨터를 사용하여 트랜잭션에 서명하는 컴퓨터에 선착순으로 논스를 할당할 수 있다. 그러나 이 컴퓨터는 이제 단일 실패 지점이다. 더욱이 여러 논스가 할당되고 그중 하나가 사용되지 않으면 (해당 논스로 트랜잭션을 처리하는 컴퓨터 오류로 인해) 모든 후속 트랜재션이 중단된다.
트랜잭션을 생성하고 논스를 할당하지 않고 하나의 노드의 대기열에 올려서 이 노드가 논스를 작성하고 서명을 하도록 시키면 된다.
이것이 병목지점이 될 수는 있지만, 병렬처리 문제를 고민하지 않아도 된다는 장점이 있다.
트랜잭션 가스
가스는 이더리움의 연료다. 가스는 이더가 아니라 이더에 대한 자체 환율을 가진 별도의 가상화폐다. 이더리움은 가스를 사용하여 트랜잭션이 사용할 수 있는 자원의 양을 제어한다. 이는 전 세계 수천 대의 컴퓨터에서 처리되기 때문이다. 개방형(튜링 완전) 계산 모델은 DoS(Denial-of-Service) 공격이나 실수로 막대한 자원을 소모하는 트랜잭션을 피하기 위해 특정한 형태의 미터링(metering)이 필요하다.
가스는 이더 가치의 급격한 변화와 함께 발생할 수 있는 변동성으로부터 시스템을 보호하고, 가스가 지급하는 다양한 자원(즉, 계산,
메모리 및 저장)의 비용 사이의 중요하고 민감한 비율을 관리하기 위해 가스를 이더와 분리한다.
가스는 이더와 별도의 가상화폐이고, 트랜잭션의 gasPrice 필드를 통해서 가스를 몇 이더에 살건지 정한다.
gasPrice가 높을수록 트랜잭션 컨펌이 빨리 진행된다.
gasPrice는 0원으로 설정할 수도 있고, 이 또한 가능성은 낮지만 블록에 포함될 수 있다.
(실제로 포함된 사례가 있다고 한다)
gasLimit은 트랜잭션을 위해 가스를 최대 몇개까지 사용할 것인지 설정하는 것이다.
단순 송금의 경우 가스가 21000개로 고정이다.
따라서 gasPrice에 21000을 곱하면 트랜잭션 수수료를 확인 할 수 있다.
컨트랙트로 트랜잭션을 전송하는 경우 필요한 가스양을 추정할 수 있지만, 정확하게 결정할 수는 없다.
컨트랙트는 어떤 변수가 있을지 모르기 때문에 확정할수는 없다. 따라서 리밋을 정해놓고 컨트랙트의 연산량 만큼만 빠져나간다.
트랜잭션을 전송할 때 첫 번째 유효성 확인 단계 중 하나는 그것이 발생된 계정이 (가스가격 * 가스 요금)을 지급할 만큼 충분한 이더를 갖고 있는지 확인하는 것이다. 그러나 트랜잭션이 완료될 떄까지 여러분의 계좌에서 금액이 실제로 차감되지 않는다. 트랜잭션에 의해 실제로 소비된 가스의 요금만 청구되지만, 트랜잭션을 보내기 전에 지급할 의사가 있는 최대 금액만큼 충분한 잔액이 있어야 한다.
트랜잭션 수신자
to 필드에 트랜잭션 수신자가 지정된다. 이것은 20바이트 이더리움 주소를 포함한다. 주소는 EOA 또는 컨트랙트 주소일 수 있다.
이더리움에서 이 필드는 검사하지 않고 모두 유효한 값으로 간주한다.
상응하는 주소가 없더라도 유효하다. 이더리움은 주소가 공개키에서 올바르게 파생되었는지 여부를 알 수 있는 방법이 없다.
(랜덤 값에서 해싱하는 것이고 어떤 값이 나올 지 모르기 때문에 모든 값을 올바르게 처리하는 것이 맞는 것이다)
책에서 유효성 검사는 인터페이스 수준에서 처리해야한다고 말한다.(전에 다뤘던 체크섬과 같은 방식으로)
트랜잭션 값과 데이터
트랜잭션의 주요 '페이로드(payload)'는 값(value)과 데이터(data)라는 2개의 필드에 포함된다.
트랜잭션은 값과 데이터, 값만, 데이터 또는 값이나 데이터를 모두 가지지 않는 네가지 조합이 모두 유효하다.
값만 있는 트랜잭션은 지급(payment)이다. 데이터만 있는 트랜잭션은 호출(invocation)이다. 값과 데이터 모두를 사용한 트랜잭션은 지급과 호출이다. 값과 데이터가 모두 없는 트랜잭션은 단지 가스 낭비일 뿐이다! 그러나 가능하긴 하다.
특별 트랜잭션 : 컨트랙트 생성
우리가 언급해야 할 특별한 경우 중 하나는 블록체인에 새로운 컨트랙트를 만들어 향후 사용을 위해 배포하는 트랜잭션이다. 컨트랙트 생성 트랜잭션은 제로 어드레스라고 하는 특수 대상 주소로 전송된다. 컨트랙트 등록 트랜잭션의 to 필드는 0x0 주소를 포함한다. 이 주소는 EOA(해당하는 개인키-공개키 쌍이 없음)나 컨트랙트를 나타내지 않는다. 결코 이더를 소비하거나 트랜잭션을 시작할 수 없다. 이 필드는 목적지로만 사용되며, '컨트랙트 작성'이라는 틀별한 의미로 사용된다.
가끔 실수나, 의도적인 연소를 목적으로 제로 어드레스에 이더를 전송하는 경우가 있다.
이더의 의도적인 연소를 원하면 네트워크에 의도를 분명히하고 '0x000000000000000000000000000000000000dEaD'라는 지정된 주소를 사용해야한다.
http://www.umlcert.com/mastering_ethereum-4/
'블록체인 > 책' 카테고리의 다른 글
스마트 컨트랙트와 바이퍼 | 마스터링 이더리움 (0) | 2021.09.28 |
---|---|
스마트 컨트랙트와 솔리디티 | 마스터링 이더리움 (0) | 2021.08.29 |
지갑 | 마스터링 이더리움 (0) | 2021.07.25 |
암호학 | 마스터링 이더리움 (0) | 2021.05.10 |
이더리움 클라이언트 | 마스터링 이더리움 (0) | 2021.04.24 |