-
[SmartContract] Truffle ๋ก Solidity ์ปดํ์ผ ๋ฐ Ganache ์ ๋ฐฐํฌSECURITY/Blockchain 2022. 1. 11. 14:51
* ์ด์ ํฌ์คํ ์ ์ด์ด์ง๋ ๋ด์ฉ์ ๋๋ค.
SmartContract ๋ฅผ Solidity ๋ก ์์ฑํ๊ณ , truffle ๋ก ์ปดํ์ผํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ์ดํด๋ด ์๋ค.
๋ํ, ์ปดํ์ผํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ง๊ณ ๋ฐฐํฌ๊น์ง ์งํํด๋ณด๊ฒ ์ต๋๋ค.
Truffle ์์ Solidity ์ปดํ์ผํ๊ธฐ
์ง๋ ํฌ์คํ ์์์ฒ๋ผ, truffle ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ฉด ๋ค์์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ต๋๋ค.
- contracts: solidity ์์คํ์ผ (.sol)
- migrations: ๋ฐฐํฌ script (.js)
- test: ํ ์คํธ script (.js or .sol)
- truffe.js: ์ค์ ํ์ผ
truffle ์ ์ด ๊ตฌ์กฐ๋ฅผ ๋ฐํ์ผ๋ก solidity ํ์ผ์ ์ปดํ์ผํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค๋๋ค.
์ง๊ธ์ ์ด๋ป๊ฒ ์ปดํ์ผ ๋ฐ ๋ฐฐํฌ๋ฅผ ํ๋์ง ์ดํด๋ณด๋ ๋จ๊ณ์ด๋ฏ๋ก, truffle ์ ๊ธฐ๋ณธ ์ ๊ณต ์ฝ๋๋ฅผ ์ด์ฉํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ค์์ truffle ์ Migrations.sol ์ ๋๋ค.
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; contract Migrations { address public owner = msg.sender; uint public last_completed_migration; modifier restricted() { require( msg.sender == owner, "This function is restricted to the contract's owner" ); _; } function setCompleted(uint completed) public restricted { last_completed_migration = completed; } }
truffle ์์ solidity ๋ฅผ ์ปดํ์ผํ๊ธฐ ์ํด์๋ contracts ํด๋์ sol ํ์ผ์ ์์ฑํ๊ณ , ํฐ๋ฏธ๋์ ๋ค์๊ณผ ๊ฐ์ด ์ ๋ ฅํด์ค๋๋ค.
$ truffle compile
๊ทธ๋ผ ๋ค์๊ณผ ๊ฐ์ด ์ปดํ์ผ์ด ์งํ๋๊ณ , ์ฑ๊ณต์ ์ผ๋ก ๋๋๋ฉด build ํด๋์ ์ปดํ์ผ ๊ฒฐ๊ณผ๊ฐ ์์ฑ๋ฉ๋๋ค.
solidity ์ปดํ์ผ ๊ฒฐ๊ณผ๋ 'abi' ์ 'bytecode' ๋ก, ํด๋น ๋ด์ฉ์ด ๋ค์ด์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
* abi: application binary interface (contract ์ ๋ช ์ธ ์ญํ )
๋ฐฐํฌ script ์์ฑ
smart contract ๋ฅผ ๋ฐฐํฌํ๊ธฐ ์ํด์๋ ๋ฐฐํฌ script ๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
deploy (๋๋ migrate) ๋ฅผ ์ํด์ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ๋ฅผ migrations ํด๋์ ์์ฑํ๋ฉด ๋๋๋ฐ, ํ์ผ๋ช ํ์์ ์ ํด์ง ๊ท์น์ด ์์ต๋๋ค.
{์ซ์}_{์ด๋ฆ}.js
์ซ์๋ truffle ์์ ๊ด๋ฆฌํ๋ '๋ฐฐํฌ ์์' ์ ๋๋ค.
์ฒ์ truffle ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๋ฉด 1_initial_migration.js ๋ผ๋ ํ์ผ์ด ์๋๋ฐ, ์ด ์น๊ตฌ๊ฐ 1๋ฒ์ด๊ณ ์ฐ๋ฆฌ๋ 2 ๋ถํฐ ์์ํด์ ์์ฑํ๋ฉด ๋ฉ๋๋ค. ex. 2_HelloWorld_migration.js
๋ฐฐํฌ ์คํฌ๋ฆฝํธ๋ ๋ค์๊ณผ ๊ฐ์ ํ์์ ๋ฐ๋ฆ ๋๋ค.
const Migrations = artifacts.require("Migrations"); module.exports = function (deployer) { deployer.deploy(Migrations); };
- artifacts.require("CONTRACT_NAME"): contract name (๋๋ ํ์ผ๋ช ) ์ ์ ์ด์ค๋๋ค.
- deployer.deploy(Migrations)
- ๋ ๋ฒ์งธ parameter ๋ก ํด๋น contract ์ ์์ฑ์ ์ธ์๋ฅผ ๋ฃ์ด์ค ์ ์์ต๋๋ค. ์ฆ, contract ์ consrtuctor ์ ํ๋ผ๋ฏธํฐ๊ฐ ์์๋ค๋ฉด, ํด๋น ๋ด์ฉ์ ์ฑ์์ค๋๋ค.
- ex. deployer.deploy(Migrations, "Hello");
- * ์ด๋ 'argv' ์ ๋ฃ์ด์ค๋ค๊ณ ์ดํดํ๋ฉด ํธํ ๊ฒ ๊ฐ์ต๋๋ค.
๋ฐฐํฌ๋ฅผ ์ํด์๋ contract ์ ์ปดํ์ผ ๊ฒฐ๊ณผ์ธ abi ์ bytecode ๋ฅผ ์์์ผ ํ๋๋ฐ, truffle ์์๋ ์ฐ๋ฆฌ๊ฐ ์ง์ ์ ์ ๋ณด์ ์ ๊ทผํ์ง ์๊ณ ๋ ์์ฝ๊ฒ ๋ฐฐํฌํ ์ ์๋๋ก ํด์ค๋๋ค.
Ganache test net ์ ๋ฐฐํฌํ๊ธฐ
์ด์ contract ๋ ์์ฑํด์ ์ปดํ์ผํ๊ณ , ๋ฐฐํฌ ์คํฌ๋ฆฝํธ๋ ์์ฑํ์ต๋๋ค.
๋จ์ ๊ฒ์ contract ๋ฅผ ์ด๋์ ๋ฐฐํฌํ๋๋, ์ฆ ๋ฐฐํฌ ํ๊ฒ์ ์ ํด์ผ ํฉ๋๋ค.
'๋ฐฐํฌ ํ๊ฒ'์ contract ๋ฅผ ์ด๋์ ๋ฐฐํฌํ๊ฒ ๋๋ ๊ฒ์ผ๋ก, ๋ก์ปฌ (Ganache, geth ๋ฑ), ์ด๋๋ฆฌ์ ํ ์คํธ๋ท, ์ด๋๋ฆฌ์ ๋ฉ์ธ๋ท(๋ฉ์ธ ์๋ฒ) ๋ฑ์ด ์์ต๋๋ค.
- Ganache, geth ๋ฅผ ์ด์ฉํด์ ๋ก์ปฌ ํ ์คํธ๋ท์ ๋ฐฐํฌ
- geth ๋ก ๋ฉ์ธ๋ท ๋๋ ํ ์คํธ๋ท์ ๋ฐฐํฌ
- infura ๋ผ๋ ํ์ฌ๊ฐ ์ ๊ณตํ๋ provider ๋ฅผ ํตํด ๋ฉ์ธ๋ท ๋๋ ํ ์คํธ๋ท์ ๋ฐฐํฌ
์ด๋ truffle-config.js ์์ ์ค์ ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
* ์ด์ truffle ์์๋ ์ด์์ฒด์ ์ ๋ฐ๋ผ tuffle.js ๋๋ truffle-config.js ๋ก ์ค์ ํ์ผ์ด ๋ถ๋ฆฌ๋์ด ์์๋๋ฐ, ์ต์ truffle ์์๋ truffle-config.js ๋ก ํต์ผ๋์์ต๋๋ค.
truffle-config.js ์์๋ ๋ํดํธ๋ก ๋ค์๊ณผ ๊ฐ์ด ๋์ด์์์ต๋๋ค. (์ฃผ์์ผ๋ก ์์ฑ๋์ด ์์ต๋๋ค)
module.exports = { networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 8545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) } };
์์ ์์์์์ฒ๋ผ ํ๊ฒ networks ๋ฅผ ์ง์ ํด์ฃผ๋ฉด ๋๋๋ฐ, s ๊ฐ ๋ถ์ ๊ฒ์ผ๋ก ์ง์ํ ์ ์๋ฏ์ด ํ๋ฒ์ ์ฌ๋ฌ network ๋ฅผ ์ง์ ํ์ฌ ๋ค์ค ๋ฐฐํฌ๋ฅผ ํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ 'network' ์ ์ด๋ฆ์ ๋ง์๋๋ก ์ ํด์ค๋ ๋์ง๋ง, 'development' ๋ tuffle ์ด ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋คํธ์ํฌ์์ ์ฃผ์ํด์ผ ํฉ๋๋ค.
๋ํ, network ๋ฅผ ์์ฑํ ๋๋ 'host', 'port', 'network_id' ์ด ์ธ ๊ฐ์ง ์์๋ฅผ ๋ฐ๋์ ์์ฑํด์ผ ํฉ๋๋ค.
์ด๋ ๋ค์๊ณผ ๊ฐ์ด, tuffle command ๋ฅผ ํตํด ํน์ network ๋ฅผ ์ ํด์ ํ ์คํธ๋ฅผ ํ ์ ์์ต๋๋ค.
$ truffle test --network <NETWORK_NAME>
๋ค์์ ๋ค์ค ๋คํธ์ํฌ ์ค์ ์ ๋ํ ์์์ ๋๋ค.
module.exports = { networks: { development: { host: "127.0.0.1", port: 8545, network_id: "*", }, dev-ganache: { host: "127.0.0.1", port: 7545, netword_id: "777", }, advanced: { host:"192.168.0.x", port: 8777, network_id: 1342, gas: 8500000, gasPrice: 20000000000, }, };
์ด๋ฒ ํฌ์คํ ์์๋ Ganache ๋ก ๋ก์ปฌ ํ ์คํธ๋ท์ ๋ฐฐํฌ๋ฅผ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋จผ์ ์ด์ ์ ์ค์นํด๋ Ganache ๋ฅผ ์คํํด์ฃผ๊ณ , test net ์ ๋ง๋ค์ด์ค๋๋ค. (์ ์ ๊ฒฝ์ฐ, QuickStart ๋ก ๋ง๋ค์ด์ฃผ์์ต๋๋ค)
Auto mining ์ผ๋ก ๋์๊ฐ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๊ทธ ์๋๋ก๋ Ganache ๊ฐ ์คํ ์ ๋ง๋ค์ด์ฃผ๋ 10๊ฐ์ ํ ์คํธ ๊ณ์ ์ ๋ณผ ์ ์์ต๋๋ค.
truffle-config.js ์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํด์ค๋๋ค.
(์์ ์ Ganache ๋ฒ์ ์ ๋ง๊ฒ port, network_id ๋ฅผ ๋ณ๊ฒฝํ์๋ฉด ๋ฉ๋๋ค)
module.exports = { networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 7545, // Standard Ethereum port (default: none) network_id: 5777, // Any network (default: none) } }, };
์ด์ ํฐ๋ฏธ๋์ ์ด์ด์, ๋ค์๊ณผ ๊ฐ์ด ์ ๋ ฅํด์ฃผ๋ฉด ๋ฐฐํฌ ์คํฌ๋ฆฝํธ๊ฐ ์ฐจ๋ก๋ก ์งํ๋๋ฉฐ ๋ฐฐํฌ๋ ์ฃผ์๊ฐ ๋์ต๋๋ค.
$ truffle migrate --network development
- migrate: Run migrations to deply contracts
(ํน์, ์ด๋ ํ ์ด์ ๋ก ์ ์๋๋ค๋ฉด, power shell ์์ ์๋ํด๋ณด์ธ์.)
๋ฐฐํฌ๋ ์ปดํ์ผ ํ ์คํ๋ฉ๋๋ค.
contract address ๋ฅผ ์ด์ฉํด์ ๋ฐฐํฌ๋ contract ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ, Ganache ๋ local test net ์ด๋ฏ๋ก, ์ข ๋ฃ์ํค๋ฉด ๋ฐฐํฌํ๋ ๋ด์ฉ์ด ๋ชจ๋ ์ฌ๋ผ์ง๋๋ค.
Ganache ๋ฅผ ๋ณด๋ฉด ํ ๊ณ์ ์ ์ด๋๊ฐ ๊ฐ์ํ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ๊ธฐ๋ณธ Solidity ์ฝ๋๋ฅผ Truffle ์ ์ด์ฉํด์ ์ปดํ์ผํ๊ณ , Ganache ์ ๋ฐฐํฌํ๋ ๊ฒ๊น์ง ํด๋ดค์ต๋๋ค.
'SECURITY > Blockchain' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ