로컬 노드에 컨트랙트 배포하기
컴파일은 코드를 EVM 바이트코드로 번역하는 일까지입니다. 그 바이트코드가 실제로 체인 위에 자리를 잡고 주소를 갖는 것이 배포입니다. 배포되기 전의 컨트랙트는 호출할 수 없습니다. 주소가 없기 때문입니다.
이번 랩에서는 내 컴퓨터에 가짜 이더리움 네트워크를 띄우고, 거기에 컨트랙트를 배포해 주소를 받아 봅니다.
1단계 — 로컬 노드 실행
터미널을 열고 프로젝트 폴더에서 실행합니다.
npx hardhat node이 명령은 내 컴퓨터 안에서만 도는 이더리움 노드를 띄웁니다. 실행하면 이런 내용이 출력됩니다.
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
Accounts
========
Account #0: 0xf39F...2266 (10000 ETH)
Private Key: 0xac09...ff80
...
Account #19: 0x8626...4199 (10000 ETH)각각 10000 ETH 를 가진 테스트 계정 20개와 그 개인키가 그대로 화면에 찍힙니다. 실제 네트워크라면 상상할 수 없는 일이지만, 이 노드는 내 컴퓨터에만 존재하고 여기의 ETH 는 아무 가치가 없으므로 안전합니다.
화면에 출력된 개인키를 실제 지갑이나 메인넷에서 절대 사용하지 마세요. 전 세계에 공개된 값이라 누구나 그 계정을 통제할 수 있습니다.
이 터미널 창은 닫지 말고 계속 켜 두세요. 노드가 꺼지면 배포한 컨트랙트와 모든 데이터가 사라집니다. 이어지는 작업은 새 터미널 창을 하나 더 열어서 진행합니다.
2단계 — 배포할 컨트랙트 작성
앞 랩에서 만든 프로젝트에는 Hardhat 이 예제로 넣어 둔 contracts/Counter.sol 과 그것을 검사하는
테스트 두 개(contracts/Counter.t.sol, test/Counter.ts)가 이미 들어 있습니다. 여기서는 Counter 를
다른 모양(생성자 인자·increase·get)으로 새로 쓸 것이라, 예제 테스트를 그대로 두면 옛
Counter 의 함수를 찾지 못해 컴파일이 실패합니다. 먼저 두 테스트 파일을 지웁니다.
rm contracts/Counter.t.sol test/Counter.ts이 단계를 건너뛰면 npx hardhat compile 이 Counter.t.sol 에서 inc 를 찾을 수 없다는 오류로
실패합니다. 오류 메시지에 Counter.t.sol 이 보이면 이 단계로 돌아오세요.
이제 contracts/Counter.sol 을 아래 내용으로 덮어씁니다. Chapter 5 에서 배운 생성자와 view 함수가 모두 들어 있습니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Counter {
uint256 public count;
// 배포할 때 시작값을 인자로 받는다
constructor(uint256 _start) {
count = _start;
}
// 상태를 바꾸는 함수 — 트랜잭션이 필요하다
function increase(uint256 _amount) public {
count += _amount;
}
// 상태를 읽기만 하는 함수 — 트랜잭션이 필요 없다
function get() public view returns (uint256) {
return count;
}
}새 터미널에서 컴파일합니다.
npx hardhat compile3단계 — 배포 스크립트 작성
scripts/deploy.js 파일을 만듭니다. 배포는 결국 "생성자 인자를 담아 트랜잭션을 보내고, 채굴된 뒤 주소를 받아오는" 절차입니다.
// scripts/deploy.js
import { network } from 'hardhat'
// 실행할 때 지정한 네트워크에 연결한다
const { ethers } = await network.getOrCreate()
// 생성자 인자 배열을 두 번째 인자로 넘긴다 (시작값 10)
const counter = await ethers.deployContract('Counter', [10n])
// 배포 트랜잭션이 블록에 담길 때까지 기다린다
await counter.waitForDeployment()
console.log('Counter 배포 완료')
console.log('주소:', await counter.getAddress())10n 처럼 숫자 뒤에 n 을 붙인 것은 자바스크립트의 bigint 리터럴입니다. uint256 은 자바스크립트의 일반 number 로는 안전하게 표현할 수 없는 큰 값을 담을 수 있어서, ethers.js v6 는 모든 정수를 bigint 로 주고받습니다.
4단계 — 로컬 노드에 배포
노드가 켜져 있는 상태에서, 다른 터미널에서 실행합니다.
npx hardhat run scripts/deploy.js --network localhost--network localhost 가 핵심입니다. 이 옵션이 없으면 Hardhat 은 임시 인메모리 네트워크를 잠깐 띄웠다가 스크립트가 끝나는 순간 통째로 버립니다. 그러면 배포된 컨트랙트도 함께 사라져서 다음 랩에서 호출할 수 없습니다.
성공하면 0x 로 시작하는 40자리 컨트랙트 주소가 출력됩니다. 이 주소를 메모해 두세요. 다음 랩에서 그대로 사용합니다.
5단계 — 노드 쪽 로그 확인
노드를 켜 둔 터미널로 돌아가 보면, 방금 벌어진 일이 기록되어 있습니다.
eth_sendTransaction
Contract deployment: Counter
Contract address: 0x5fbd...0aa3
Transaction: 0x8d7e...41c2
From: 0xf39f...2266
Gas used: 142351 of 30000000
Block #1: 0x1f2a...9b04배포도 결국 하나의 트랜잭션이며, 가스를 소모하고, 블록에 담긴다는 사실이 여기서 그대로 보입니다. 사용한 계정은 노드가 출력했던 Account #0 입니다.