읽는 데 8분
이 가이드에는 더 이상 적극적으로 유지 관리되지 않는 Kovan 테스트넷에 대한 내용이 포함되어 있습니다. 이 체인과 관련된 구체적인 단계는 적용되지 않을 수 있지만, 전반적인 절차는 다른 체인에도 유효할 수 있습니다. 구현을 위해 현재 이용 가능한 대안을 살펴보실 것을 권장합니다. 이 가이드의 업데이트된 버전을 보고 싶으시다면, 저희에게 알려주세요!
개요
때로는 네트워크 혼잡이나, 자신이 제시한 가스 가격보다 더 높은 가격을 제시한 대기 중인 거래가 너무 많아서, 충분한 가스를 설정하지 못한 채 이더리움에 거래를 제출하는 경우가 있습니다. 우선순위가 높은 거래인데 가스 가격이 낮다면, 거래가 처리되기까지 몇 시간 또는 며칠을 기다려야 할 수도 있습니다. 이러한 경우, 거래가 더 빨리 채굴되도록 하기 위해서는 더 높은 가스 가격과 동일한 논스를 사용하여 거래를 다시 전송해야 합니다.
이 가이드에서는 이더리움 테스트 네트워크 중 하나에서 Ethers.js를 사용하여 트랜잭션을 전송하고 동일한 트랜잭션을 재전송하는 것과 관련된 모든 용어와 정보를 살펴보겠습니다.
이더리움에서 트랜잭션이란 무엇인가요?
이더리움 네트워크에서 무언가를 추가, 업데이트 또는 수정하고자 할 때마다 트랜잭션을 수행합니다. 기본적으로 트랜잭션은 현실 세계가 이더리움 블록체인 네트워크와 상호작용하는 방식입니다. 이더리움 네트워크에서 트랜잭션을 수행할 때마다 ‘가스’라고 하는 수수료를 지불해야 합니다. 가스는 ‘wei’(ETH의 가장 작은 단위) 또는 ‘gwei’ 단위로 표시됩니다.
이더리움의 거래 유형
이더리움 네트워크에서는 일반적으로 세 가지 유형의 거래가 이루어집니다:
- 한 계정에서 다른 계정으로 ETH/이더가 이체되는 일반적인 거래입니다.
- 계약을 생성하는 트랜잭션이란, 이더리움 블록체인 네트워크에 스마트 계약을 배포하는 유형의 트랜잭션을 말합니다.
- 계약을 호출하는 트랜잭션으로, 이 트랜잭션은 특정 데이터를 포함하여 전송되며, 이전에 배포된 스마트 계약에 대한 쿼리 또는 상호 작용에 사용됩니다.
일반적인 이더리움 거래의 매개변수
- from: 발신자 주소. 거래를 시작한 계정을 나타내는 20바이트 길이의 주소입니다.
- to: 수신자 주소. 수신자의 계정 또는 계약 계정을 나타내는 20바이트 주소입니다.
- value: 이는 한 계정에서 다른 계정으로 전송된 거래 내의 ETH 금액입니다.
- data: 이 필드에는 계약 배포 트랜잭션에 사용되는 바이트코드가 포함됩니다. 계약 함수 실행의 경우, 이 필드에는 함수 시그니처와 인코딩된 인수가 포함됩니다. 자금 이체 트랜잭션에서는 이 필드가 필요하지 않거나 비워 둡니다.
- gasLimit: 트랜잭션에서 가스로 사용할 수 있는 최대량(wei 단위)입니다.
- gasPrice: 이는 송신자가 해당 거래에 지불할 의사가 있는 위(wei) 단위의 금액입니다.
- chainId: 이는 사용자의 이더리움 노드의 네트워크 ID입니다(메인넷: 1, 링케비: 4, 코반: 42 등).
- 논스(nonce): 특정 주소가 전송하는 거래의 횟수를 의미합니다. 주소가 거래를 전송할 때마다 논스는 1씩 증가합니다.
이더리움의 트랜잭션 흐름
- 트랜잭션 객체를 생성하고 필요한 모든 매개변수를 전달합니다.
- 송신자의 개인 키로 거래에 서명합니다.
- 이더리움 노드를 사용하여 이더리움 블록체인 네트워크로 트랜잭션을 전송합니다.
거래 서명
트랜잭션에 서명한다는 것은 발신자의 개인 키를 사용하여 트랜잭션 객체에 서명을 생성하는 것을 의미합니다. 이더리움에서의 서명 및 검증에 대해 더 자세히 알고 싶다면, 다음의 훌륭한 자료들을 참고하시기 바랍니다: Yos의 《이더리움 서명 및 검증》 과 Angello Pozo의 《이더리움: 서명 및 검증》.
이제 이더리움의 트랜잭션에 대해 더 잘 이해했으니, 직접 트랜잭션을 하나 보내보겠습니다.
필수 조건
- 시스템에 Node.js가 설치되어 있습니다
- 텍스트 편집기
- 터미널(일명 명령줄)
필요한 도구 설치.
NodeJS를 사용하여 라이브러리 패키지를 관리하고 자바스크립트 파일을 다룰 것입니다. 시스템에 NodeJS가 설치되어 있는지 확인하려면 터미널을 열고 다음 명령을 실행하세요:
$ node -v
설치되어 있지 않다면, 공식 웹사이트에서 NodeJS의 LTS 버전을 다운로드할 수 있습니다.
트랜잭션을 전송하기 위해 간단한 자바스크립트 코드를 사용할 것이며, ethers.js 라이브러리(버전 5.7이어야 함)를 활용할 것입니다. 명령줄/터미널에서 npm을 사용하여 설치할 수 있습니다:
$ npm install --save ethers@5.7
이 단계에서 가장 흔히 발생하는 문제는 `node-gyp`의 내부 오류입니다. 여기에서 node-gyp 설치 안내를 확인하실 수 있습니다.
또 다른 흔한 문제는 캐시가 오래되어 갱신되지 않은 경우입니다. 터미널에 아래 명령어를 입력하기만 하면 npm 캐시를 지울 수 있습니다:
$ npm cache clean
ethers .js 라이브러리에 대해 더 자세히 알아보시려면 당사의 ethers.js 가이드를 확인해 보세요.
지갑 생성하고 테스트용 ETH 받기
자, 이제 우리만의 지갑을 만들어 봅시다. 이를 위해 먼저 index.js 파일을 만들거나 원하는 이름으로 자바스크립트 파일을 생성하세요. 다음 코드를 코드 편집기에 복사하여 붙여넣으시면 됩니다:
var 이더 = require('ethers');
var privateKey = "0x0111111111111111111122222222222222222223333333333333333333344445";
var wallet = new ethers.지갑(개인키);
console.log("주소: " + 지갑.address);
여기서 어떤 일이 일어나는지 살펴보겠습니다. 앞서 설치한 ethers.js 라이브러리를 불러옵니다(1행), 우리 지갑에 특화된 개인 키를 생성합니다. 직접 생성해야 하며, 숫자라면 어떤 값이든 상관없지만 위와 동일한 자릿수를 갖도록 해야 합니다(2행), 개인 키를 사용하여 ethers로 지갑 인스턴스를 생성합니다(3행), 콘솔에 "Address"라는 텍스트와 함께 지갑 주소를 출력합니다(4행).
이제 다음 명령어를 사용하여 파일을 실행하세요:
$ node index.js
모든 것이 순조롭게 진행된다면, 터미널 창에 표시되는 출력은 다음과 같을 것입니다:
주소: 0x3f5D3070Fc7924479B5e367a83EC2b284E9c4e04
모든 거래에는 수수료로 가스가 필요하며, 거래를 전송하기 위해서도 가스가 필요하므로, 지갑에 테스트용 ETH를 조금 넣어 봅시다. 이를 위해 Kovan 노드를 사용할 예정이니, 이 Kovan 페이크트로 이동하여 테스트용 ETH를 받으세요. 위 코드를 실행하여 얻은 지갑 주소를 붙여넣고 ‘send me KETH!’를 클릭하세요.
참고: 이는 시장 가치가 없는 테스트용 ETH입니다.
Quicknode 이더리움 엔드포인트 설정하기
오늘의 목적상, Geth나 OpenEthereum(구 Parity)과 같은 거의 모든 이더리움 클라이언트를 사용할 수 있습니다. 이더리움 노드를 직접 가동하려면 먼저 클라이언트를 선택하고 구성해야 합니다. 이더리움 노드를 동기화하고 유지 관리하는 것은 까다로운 작업이며, 이더리움 풀 노드를 동기화하는 데는 며칠이 걸릴 수도 있습니다.
단일 트랜잭션을 전송하는 데만 이 정도 과정이 필요하기에는 다소 번거로우므로, Quicknode에서 제공하는 무료 엔드포인트를 활용해 작업을 간편하게 진행하겠습니다. 무료 이더리움 엔드포인트를 생성한 후, HTTP 프로바이더 엔드포인트를 복사하세요:
이 가이드에서는 Kovan 테스트넷 노드를 사용하고 있습니다.

나중에 필요할 테니, 복사해서 저장해 두세요.
거래 전송 및 재전송
이제 지갑이 준비되었고, 그 안에 테스트용 ETH도 들어 있습니다. 그럼 이제 다른 계정이나 지갑으로 ETH를 이체하는 트랜잭션을 보내보겠습니다. 이를 위해 index.js 파일에 몇 가지 기능을 더 추가해 봅시다. 다음 코드를 복사하여 코드 편집기에 붙여넣으세요:
var ethers = require('ethers');
var url = 'ADD_YOUR_ETHEREUM_NODE_URL';
var customHttpProvider = new ethers.providers.JsonRpcProvider(url);
var privateKey = "0x0111111111111111111122222222222222222223333333333333333333344445";
var wallet = new ethers.Wallet(privateKey);
console.log("Address: " + wallet.address);
tx = {
to: "0x6E0d01A76C3Cf4288372a29124A26D4353EE51BE",
value: ethers.utils.parseEther("0.05"),
chainId: 42,
nonce: 3
}
customHttpProvider.estimateGas(tx).then(function(estimate) {
tx.gasLimit = estimate;
tx.gasPrice = ethers.utils.parseUnits("0.14085197", "gwei");
wallet.signTransaction(tx).then((signedTX)=>{
customHttpProvider.sendTransaction(signedTX).then(console.log);
});
});
그러니 `ADD_YOUR_ETHEREUM_NODE_URL`을 위 섹션에 나와 있는 HTTP 제공자로 대체해 주세요.
위의 코드에 대한 간단한 설명입니다. 먼저 앞서 설치한 ethers 라이브러리를 임포트하고(1행), 이더리움 노드 URL을 설정하고(2행), ethers의 JsonRpcProvider 인스턴스를 생성합니다(3행). 다음으로, 지갑에 특화된 개인 키를 생성합니다. 직접 키를 생성해야 하며, 숫자 개수는 상관없지만 자릿수는 동일해야 합니다(4행). 이 개인 키를 사용하여 ethers로 지갑 인스턴스를 생성하고(5행), 콘솔에 "Address"라는 텍스트와 함께 지갑 주소를 출력하며(6행), 트랜잭션 객체를 생성하고 수신자의 주소를 'to' 필드에 추가합니다. `var wallet = Wallet.createRandom();`을 사용하여 임의의 주소를 생성할 수 있습니다.`를 사용하여 임의의 주소를 생성할 수 있습니다. 또한, 전송할 ETH의 가치를 명시하는 'value' 필드, Kovan을 사용 중이므로 42로 설정된 'chainId' 필드, 3으로 설정된 nonce 필드를 추가합니다(7~12행). 노드를 통해 gasLimit을 추정하고 gas 가격을 설정합니다(13~15행), 지갑의 개인 키로 트랜잭션 객체에 서명하고 전송하며, 콘솔에 트랜잭션을 출력합니다(16~18행).
이걸 실행해 봅시다:
$ node index.js
다음과 같은 결과가 나올 것입니다:

해시 필드의 문자열(예: '0xe49c8122656c612bf5f1e10b251f56671acf01d831b6876c37c5a52053035642')을 복사하여 Kovan Etherscan의 검색창에 붙여넣고 거래 상태를 확인해 보세요. 거래가 아직 블록체인의 새 블록에 추가되지 않았으며 '보류 중(pending)' 상태임을 확인할 수 있습니다. 이는 가스 값을 상당히 낮게 입력했기 때문입니다.
이제, 동일한 논스(nonce)를 사용하되 가스 값을 늘려서 같은 트랜잭션을 전송해 봅시다. 코드의 15번째 줄에 있는 gasPrice 값을 '0.14085197'에서 '2.14085197'로 변경한 후 코드를 다시 실행해 보세요:
$ node index.js
새로운 출력창에서 해시 문자열을 복사한 다음, Kovan Etherscan의 검색창에 붙여넣어 트랜잭션 상태를 확인하세요. 이번에는 적절한 gasPrice 값을 높여 전송했기 때문에, 우리 트랜잭션이 블록에 포함되고 성공 상태로 표시될 것입니다.
참고: 두 거래에서 “nonce” 값이 동일해야 한다는 점을 유의해야 합니다. 앞서 언급했듯이, nonce는 이더리움 주소가 가진 거래 횟수를 가리키는 포인터입니다. 더 높은 가스 비용을 설정하여 거래를 다시 제출하려면, 원래 거래와 동일한 nonce를 사용해야 합니다. nonce 값을 늘려 사용하면 이는 새로운 거래로 간주되어, 의도한 것보다 더 많은 ETH가 소모될 수 있습니다.
결론
따라서 위 예시에서 보았듯이, 거래가 승인되려면 해당 거래의 가스 요금이 경쟁력 있어야 합니다. 블록체인의 채굴자들은 사용 가능한 블록 공간과 그 공간을 차지하기 위해 각 거래가 지불하려는 금액을 바탕으로 가스 요금을 책정하며, 가스 요금이 기준값보다 낮은 거래는 승인되지 않습니다. 다른 거래에 비해 가스 요금이 높은 거래일수록 빠르게 승인됩니다.
이더리움에 관한 더 많은 기사와 가이드를 받아보시려면 뉴스레터를 구독해 주세요. 의견이 있으시면 트위터를 통해 언제든지 연락 주시기 바랍니다. 또한 궁금한 점이 있으시면 디스코드 커뮤니티 서버에서 저희와 대화하실 수 있습니다. 그곳에는 정말 멋진 개발자들이 모여 있으니, 감사합니다 :)
