Home - wogus2421/BlockChain_practice GitHub Wiki
Dapp ๊ด๋ จํ ๊ฐ๋จํ ์์ (truffle ์ด์ฉํ pet-shop)
- ์กฐ๊ฑด
- 16๋ง๋ฆฌ์ ์ ์๋๋ฌผ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
- pet shop์์ ์ ์๋๋ ์ ์๋๋ฌผ๊ณผ Ethereum ์ฃผ์๋ฅผ ์ฐ๊ด์ํค๋ Dapp์ด ๋ชฉํ์ด๋ค.
- ๊ธฐ๋ณธ ์น์ฌ์ดํธ์ ๊ตฌ์กฐ, style์ ์ ๊ณตํ๋ค(์์ ์ ๊ตฌํ๋์ด์๋ค)
- front-end ๋ก์ง๊ณผ smart-contract ๋ฅผ ์์ฑํ๋ฉด ์์ฑ๋๋ ํ์์ด๋ค.
๊ฐ๋ฐํ๊ฒฝ
- ๋ค์์ ๊ฒ๋ค์ ๊น๋ ค์์ด์ผ ํ๋ค.
- Node.js LTS_ver, npm
- Git
- Truffle
- Ganache
์์
-
tuffle์ ์ด์ฉํ์ฌ truffle ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ค
- truffle unbox (box_name) ๋ฅผ ์ด์ฉํ์ฌ ์์ฑํ๋ค. ์ด ๊ฒฝ์ฐ ์์ ์ ํ์ํ ๊ฒ๋ค์ด ๊ฐ์ด ์์ฑ๋๋ค.
- truffle init ์ ํตํ์ฌ truffle ๋ฐ์ค๋ฅผ ๋ง๋ ๋ค(init์ ์ด์ฉํ ๊ฒฝ์ฐ ๋น ํ๋ก์ ํธ๋ง ์์ฑ๋๋ค)
-
๋ง๋ค์ด์ง box์ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- contracts/ : smart contract๋ฅผ ์ํ solidityํ์ผ์ ์ ์ฅํ๋ ์ฅ์. Migrate.sol์ด๋ผ๋ ํ์ผ์ด ์ด๋ฏธ ์กด์ฌํ๋ค.
- Migrations/ : truffle์์ smart contract ๋ฐฐํฌ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ด์ฉํ๋ ์์คํ . ๋ณ๊ฒฝ์ฌํญ์ ์ถ์ ํ๋ ์ถ๊ฐ์ smart contract์ด๋ค
- test/ : smart contract์ ํ ์คํธ ์ฝ๋ JS์ Solidity ๋ชจ๋ ๊ฐ๋ฅํ๋ค.
- truffle.js : truffle ์ค์ ํ์ผ
smart contract ์์ฑ
- ๋ค์๊ณผ ๊ฐ์ Adoption.sol ํ์ผ์ ์ถ๊ฐํ์๋ค.
pragma solidity ^0.4.17;
contract Adoption {
address[16] public adopters;
function adopt(uint petId) public returns (unit) {
require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}
function getAdopters() public view returns (address[16]){
return adopters;
}
}
- public์ผ๋ก ์ ์ธํ ๋ณ์๋ ์๋์ผ๋ก getter ํจ์๋ฅผ ๊ฐ๋๋ค. key ๊ฐ์ ํตํ์ฌ ๋จ์ผ ๋ณ์์ ์ป์ด์ฌ ์์๋ค.
- ํจ์์ ๋ํ ๊ฐ๋ตํ ์ค๋ช
- ์ฌ๊ธฐ์ ์์ผ๋ ์ต๊ทผ์ ๋ฒ์ ์์ ์์ฑ์๋ฅผ ๋ง๋ค ๋ function Adoption() ์ผ๋ก๋ ๊ฐ๋ฅํ๊ณ constucter() ๋ก๋ ๊ฐ๋ฅํ๋ค.
- adopt : petId๋ฅผ ๋ฐ์ ๋ถ์ํ๊ณ , adopter์ petId ์ธ๋ฑ์ค์ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ธ(๊ณ์ฝํ) ์ฌ๋์ ์ฃผ์๋ฅผ ์ ์ฅํ๊ณ , ์ฑ๊ณต์ ๊ทธ petId๋ฅผ return ํ๋ค.
- getAdopters : ๋งค๊ฐ๋ณ์๋ ์์ผ๋ฉฐ adopters ๋ผ๊ณ ํ๋ 16๊ฐ์ง๋ฆฌ address ๋ฐฐ์ด์ returnํ๋ค.
Solidity๋ ์ปดํ์ผ ๊ธฐ๋ฐ์ ์ธ์ด์ด๊ณ , EVM ์์ ์คํ๋๊ธฐ ์ํ์ฌ ๋ฐ์ดํธ ์ฝ๋๋ก ์ปดํ์ผ ํด์ผํ๋ค.
- truffle compile ๋ช ๋ น์ด๋ฅผ ์ด์ฉํ์ฌ ์ปดํ์ผ ํ๋ฉด ๋๋ค.
- ์ปดํ์ผ ์, .\build/contracts ์ compile๋ ์ ๋ณด๋ฅผ ๋ด์ json ํ์ผ์ด ์๊ธด๋ค
- ์ฝ๋๋ฅผ ๊ณ ์ณค์ ์์๋ json ํ์ผ์ ์ง์ฐ๊ณ ๋ค์ ์ปดํ์ผ ํ๋๋ก ํ์.
migration
-
์ปดํ์ผ์ ์ฑ๊ณตํ๋ฉด ๋ค์ ๋จ๊ณ๋ก migrate ํด์ผํ๋ค
- migration์ ์ดํ๋ฆฌ์ผ์ด์ ์ contract state๋ฅผ ๋ณ๊ฒฝํ์ฌ ๋ค์ state๋ก ์ด๋์ํค๋ script๋ค. ์ฒซ ๋ฒ ์งธ migration์ ์ ์ฝ๋๋ฅผ deployํ๋ ๊ฒ์ด์ง๋ง, ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ data๋ฅผ ์ด๋ํ๊ฑฐ๋, contract๋ฅผ ์๋ก์ด ๊ฒ์ผ๋ก ๋์ฒดํ ์ ์๋ค.
-
migrations/ ํด๋์ default๋ก 1_initial_migration.js ํ์ผ์ด ์กด์ฌํ๋ค.
- ์ด js ํ์ผ์ ์ดํ smart contract์ magration์ ๊ด์ฐฐํ๊ธฐ ์ํ์ฌ Migration.sol์ deploy๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ์์ ๋์ง ์์ contract์ 2์ค ๋ฐฐํฌ๋ฅผ ๋ง๋๋ค.
-
migrations/ ๋๋ ํ ๋ฆฌ์ 2_deploy_contracts.jsํ์ผ์ ์์ฑํ๋ค. ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ๋ค.
var Adoption = artifacts.require("./Adoption.sol");
moodule.exports = funtion(deployer) {
deployer.deploy(Adoption);
}
- ๋ธ๋ก์ฒด์ธ์ผ๋ก contract๋ฅผ migrate ํ๊ธฐ ์ ์ ๋ธ๋ก์ฒด์ธ์ ์คํํด์ผํ๋ค. Ganach๋ฅผ ์ด์ฉํ private net์ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก Ganache๋ฅผ ํค๋ฉด๋๋ค.
- truffle.js ์์ Ganache๋ฅผ ์ค์ ํ๋ค. ๋ค์๊ณผ ๊ฐ์ ํํ๋กํ๋ฉด ๋๋ค.
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// for more about customizing your Truffle configuration!
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*" // Match any network id
}
}
};
- ํฐ๋ฏธ๋์์ truffle migrate ๋ช ๋ น์ด๋ฅผ ์ด์ฉํ์ฌ migration ํ๋ค.
- ์ดํ Ganache๋ฅผ ํตํ์ฌ ๋ธ๋ก์ฒด์ธ์ด transection์ ํตํ์ฌ ๋ธ๋ก์ ์์ฑํ์๋์ง ํ์ธํ๋ค. ์ด migration์ ํตํ์ฌ 100์ด๋์๋ ๊ฒ์ด ์กฐ๊ธ ๊น์ธ๋ค.
smart contract test
- test๋ Solidity ์ JavaScript ๋ชจ๋ ๊ฐ๋ฅํ๋ค.
- test/ ๋๋ ํ ๋ฆฌ์ TestAdoption.sol ํ์ผ์ ์์ฑํ๋ค.
- ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ๋ค.
pragma solidity ^0.4.17;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Adoption.sol";
contract TestAdoption{
Adoption adoption = Adoption(DeployedAddresses.Adoption());
function testUserCanAdopPet() public{
unit returnedId = adoption.adopt(8);
unit expected = 8;
Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
}
function testGetAdopterAddressByPetId() public {
address expected = this;
address adopter = adoption.adopters(8);
Assert.equal(adopter, expected, "Owner of pet ID 8 should be recoreded.");
}
function testGetAdopterAddressByPetIdInArray() public {
address expected =this;
address [16] memory adopters = adoption.getAdopters();
Assertequal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
}
}
-
imports
- Assert.sol : ํ ์คํธ์ ์ฌ์ฉํ assertion์ ์ ๊ณต, global์ด๋ค.
- DeployedAddresses.sol : ํ ์คํธ ์คํ์์ ํ ์คํธํ contract๋ฅผ ์๋ก ๋ฐฐํฌํ๋ค. ์ด๋ ๋ฐฐํฌํ contract์ address๋ฅผ ๊ฐ์ ธ์ค๋ ์ญํ . ์ด๋ํ ์ ์ญ truffle ํ์ผ์ด๋ค.
- Adoption.sol : ์ฐ๋ฆฌ๊ฐ ํ ์คํธํ๊ณ ์ ํ๋ contract
-
functions
- testUserCanAdoptPet : petId 8 ์ ์ด์ฉํ์ฌ adopt()๋ฅผ ์คํํ๊ณ , ์์ธก๊ฐ์ธ 8์ ๋ฐ๋ก์ ์ธํ์ฌ Assert๋ก ํ์ธํ๋ค.
- testGetAdopterAddressByPetId : Adoption.sol ์์ public ๋ณ์ ์ ์ธ์ผ๋ก ์ธํ getter๋ฅผ ํ์ธํ๋ ํจ์์ด๋ค.
- testGetAdopterAddressByPetIdInArray : adopters ๋ฐฐ์ด์ PetId 8 ์ ์ฒซ ์
์ํ ํ
์คํธ๋ฅผ ์๊ธฐ์ ๊ทธ contract ์ฃผ์์ ๋น๊ตํ๋ค.
- solidity์์ memory ๋ contract์ storage์ ์ ์ฅํ๋ ๊ฒ์ด ์๋ ์ผ์์ ์ธ ๊ฐ ์ ์ฅ์ ์๋ฏธํ๋ค.
-
์์ฑ์ด ๋๋ฌ๋ค๋ฉด, truffle test ๋ช ๋ น์ด๋ฅผ ์ด์ฉํ์ฌ test๋ฅผ ์งํํ๋ค.
front-end ๋ง๋ค๊ธฐ
- truffle unbox ๋ฅผ ํตํ์ฌ ๋ง๋ ๋๋ ํ ๋ฆฌ์ด๋ฏ๋ก ์ด๋ฏธ pet shop ์์ ์งํ์ ์ํ front-end ์ฝ๋๊ฐ ํฌํจ๋์ด์๋ค.
- ๋ช๊ฐ์ง ์ค์ ๋ง ๋ฐ๊ฟ์ฃผ๋ฉด ๋ฐ๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
- app.js
- src/js/app.js ํ์ผ์ ์ฐ๋ค
- initWeb3 ํจ์์ ์ฝ๋ฉํธ์ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ ์ฑ์ ๋ฃ๋๋ค.
if(typeof web3 !== 'undefined') {
App.wep3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
web3 = new Web3(App.web3provider);
- ์ด๋ฏธ ํ์ฑํ ๋ web3 ๊ฐ ์๋์ง ํ์ธํ๊ณ , ์์ผ๋ฉด ๊ทธ๊ฒ์ ์ฌ์ฉํ๊ณ ์๋๋ฉด ์์ฑํ์ฌ ์ฌ์ฉํ๋ค.
- initContract ํจ์์ ์ฝ๋ฉํธ๊ฐ ์๋ ๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ์ด ์ฑ์ ๋ฃ๋๋ค.
$.getJSON('Adoption.json', function(data) {
// Get necessary contract artifact file and instantiate it with truffle contract
var AdoptionArtifact = data;
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
// Set the provider for our contract
App.contracts.Adoption.setProvider(App.web3Provider);
// Use our contract to retrieve and mark the adopted pets
return App.markAdopted();
});
-
์ฝ๋์ ๋ํ ์ค๋ช ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ๋จผ์ smart contract ์ artifact๋ฅผ ๊ฒ์ํ๋ค. artifact๋ deploy๋ address ๋ฐ ABI์ ๊ฐ์ contract์ ๋ํ ์ ๋ณด์ด๋ค.
- callback์ artifact ๊ฐ ์๊ธฐ๋ฉด TruffleContract๋ก ์ ๋ฌํ์ฌ contract ์ instance๋ฅผ ์์ฑํ๋ค.
- instanceํ ๋ contract๋ฅผ ํตํ์ฌ web3 provider๋ฅผ ์ค์ ํ๋ค.
- ์ด์ ์ ์ด๋ฏธ ๋ถ์๋ pet ์ธ๊ฒฝ์ฐ์ markAdopted๋ฅผ ์ด์ฉํ์ฌ UI ์ ๋ฐ์ดํธ
-
markAdopted ํจ์์ ์ฃผ์์ ์ ๊ฑฐํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์ฑ์ ๋ฃ๋๋ค.
var adoptionInstance;
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptioinInstance.getAdopters.call();
}).then(function(adopters) {
for (i = 0; i< adopters.length; i++) {
if(adopters[i] !== '0x0~') { // 0~ -> 0 40๊ฐ
$('.panel-pet').eq(i).find('button').text('Success').attr('disabled',true);
}
}
}).catch(function(err) {
console.log(err.message);
});
-
์ฝ๋์ ๋ํ ์ค๋ช ์ ๋ค์๊ณผ ๊ฐ๋ค.
- deploy๋ Adoptioin contract์ ์ง์ ํ์ฌ ๊ทธ instance์ getAdopters()๋ฅผ ํธ์ถํ๋ค.
- call() ์ ์ฌ์ฉํ๋ฉด transection ์์ด ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ์ ์๋ค ์ฆ, ์ด๋๋ฅผ ์๋นํ์ง ์๋๋ค.
- getAdopters() ๋ฅผ ์ด์ฉํ์ฌ ๋ชจ๋ ํญ๋ชฉ์ ํ์ธํ๋ค. ์ด๋๋ฆฌ์์ 0์ผ๋ก ์ด๊ธฐํ ๋์ด์๊ธฐ์ 0์ด ์๋๋ฉด address๊ฐ ์ ์ฅ๋์ด ์๋๊ฒ์ด๋ค.
- ์ฃผ์๊ฐ ์กด์ฌํ๋ค๋ฉด, adopt ๋ฒํผ์ ๋นํ์ฑํ ํ๊ณ text๋ฅผ success๋ก ๋ฐ๊พธ์ด ์ค๋ค
- ๋ชจ๋ error๋ console์ ๋ก๊น ๋๋ค.
-
๋ง์ง๋ง์ผ๋ก handleAdopt ํจ์์ ์ฃผ์์ ์ง์ฐ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์ฑ์๋ฃ๋๋ค
var adoptionInstance;
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
//Execute adopt as a transection by sending account
return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(error) {
console.log(err.message);
});
});
- ์ฝ๋์ ๋ํ ์ค๋ช
์ ๋ค์๊ณผ ๊ฐ๋ค
- web3๋ฅผ ์ด์ฉํ์ฌ ์ฌ์ฉ์์ ๊ณ์ ์ ๊ฐ์ ธ์จ๋ค. error check ํ callback ์์ ์ฒซ ๋ฒ ์งธ ๊ณ์ ์ ์ ํํ๋ค.
- deploy๋ constract๋ฅผ ๊ฐ์ ธ์์ adoptionInstance์ ์ ์ฅ. transection์ ๋ณด๋ผ ๊ฒ ์ด๊ธฐ ๋๋ฌธ์ from ์ ๊ณ์ ์ด ํ์ํ๋ฉฐ ์ด๋๋ก ์ง๋ถํ๋ gas ๊ฐํ์ํ๋ค. adopt ํจ์๋ฅผ ์คํํ์ฌ transection์ ๋ณด๋ธ๋ค.
- transection ์ ์ก์ ๊ฒฐ๊ณผ๋ transection object ์ด๋ค. ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์์๋ค๋ฉด markAdopted๋ก UI๋ฅผ ๋๊ธฐํํ๋ค.
dapp ์ฌ์ฉ
- ๋ฉํ๋ง์คํฌ ์ฌ์ฉ
- ๋ฉํ๋ง์คํฌ๋ฅผ ๋ก๊ทธ์ธํ๋ค
- main network์ ์ ์ํ ์ํ์์ ์ปค์คํ ์ ๋๋ฅด๊ณ , ganache์ ์ฃผ์(private net)์ผ๋ก ์ ์ํ๋ค.
- ganache์ ๊ณ์ข๋ฅผ importํ์ฌ ๋๊ธฐํ๊ฐ ์ ๋์๋์ง ํ์ธํ๋ค.
- lite-server ์ค์น ๋ฐ ์ฌ์ฉ
- npm install lite-server -g ๋ก ๋ค์ด๋ฐ๋๋ค
- bs-config.jason ํ์ผ์ ์ด์ด์ ๋ค์๊ณผ ๊ฐ์ ๋ด์ฉ์ ํ์ธํ๋ค.
{
"server":{
"baseDir": ["./src","./build/contracts"]
}
}
- pakage.jason ํ์ผ๋ ํ์ธํ๋ค.
"scripts": {
"dev": "lite-server",
"test": "echo \"Error: no test specified\" && exit 1"
},
- ๋ชจ๋ ํ์ธํ์๋ค๋ฉด npm run dev๋ก ์คํ ์ํฌ ์์๋ค.
์ค๋ฅ
- ๋ฉํ๋ง์คํฌ ์ด์๋ก ์ธํ ์คํจ ๊ฐ๋ฅ์ฑ์ด ์๋ค
- ๊ฐ๋์๋ ๋ฉํ๋ง์คํฌ ์ฐ๋ํ ๋ ์๋ฌ๊ฐ ์ฆ๋ค............