このページは以下のサイトを参照して作業しています。
参照先 サイト https://www.trufflesuite.com/tutorials
参照先 サイト イーサリアムペットショップ-初めてのDAPP
(https://www.trufflesuite.com/tutorials/pet-shop)
参考サイト Truffleの「イーサリアム・ペットショップ」
イーサリアムペットショップ
チュートリアル=>イーサリアムペットショップ-初めてのDAPPへ進む。
このチュートリアルでは、初めてのdappを構築するプロセスについて説明します。
ペットショップ向けの採用追跡システムを作成します。
ペットの養子縁組を処理する効率的な方法としてイーサリアムを使用する。
店には、同時に16匹のペットを収容できるスペースがあり、ペットのデータベースがすでにあります。
以下の手順で進みます。
- 開発環境のセットアップ
- Truffle Boxを使用してTruffleプロジェクトを作成する
- スマートコントラクトを書く
- スマートコントラクトのコンパイルと移行
- スマートコントラクトのテスト
- スマートコントラクトと対話するためのユーザーインターフェイスの作成
- ブラウザーでdappを操作する
開発環境のセットアップ
Node.js v8 + LTS(Node.jsは、サーバーサイドのJavaScript実行環境)およびnpm(Nodeに付属)およびGitのインストール。
Truffleインストール
npm install -g truffle の実行。
Truffle v5.1.42 (core: 5.1.42)
Solidity v0.5.16 (solc-js)
Node v12.18.3
Web3.js v1.2.1
Ganacheインストール
Ganacheをインストールする。
Ganacheは、チェーンの動作を制御しながらテストの実行、コマンドの実行、状態の検査に使用できる個人用Ethereumブロックチェーンをすばやく起動します。
Truffle Boxを使用してTruffleプロジェクトを作成
Truffle Boxは、Ethereumブロックチェーン上に分散アプリケーションをすばやく構築するのに役立つボイラープレートのセット。
TruffleとSolidityコントラクトとライブラリ、フロントエンドビューなどが含まれています。
ディレクトリを作成し、Truffle Boxを解凍する。
mkdir pet-shop-tutorial
cd pet-shop-tutorial
truffle unbox pet-shopコマンドを実行
C:\Windows\System32\pet-shop-tutorial のディレクトリ 2020/09/02 09:38 <DIR> . 2020/09/02 09:38 <DIR> .. 2020/06/22 13:20 33 .gitattributes 2020/09/02 09:38 <DIR> .github 2020/06/22 13:20 59,064 box-img-lg.png 2020/06/22 13:20 7,619 box-img-sm.png 2020/06/22 13:20 68 bs-config.json 2020/09/02 09:38 <DIR> contracts 2020/06/22 13:20 1,075 LICENSE 2020/09/02 09:38 <DIR> migrations 2020/09/02 09:38 <DIR> node_modules 2020/09/02 09:38 120,807 package-lock.json 2020/06/22 13:20 331 package.json 2020/09/02 09:38 <DIR> src 2020/09/02 09:38 <DIR> test 2020/06/22 13:20 320 truffle-config.js 8 個のファイル 189,317 バイト 8 個のディレクトリ 58,234,421,248 バイトの空き領域スマートコントラクトの作成
C:\Windows\System32\pet-shop-tutorial\contracts>type Adoption.sol pragma solidity ^0.5.0; contract Adoption { address[16] public adopters; // Adopting a pet function adopt(uint petId) public returns (uint) { require(petId >= 0 && petId <= 15); adopters[petId] = msg.sender; return petId; } // Retrieving the adopters function getAdopters() public view returns (address[16] memory) { return adopters; } }C:\Windows\System32\pet-shop-tutorial>truffle compile Compiling your contracts... =========================== > Compiling .\contracts\Adoption.sol > Compiling .\contracts\Migrations.sol > Artifacts written to C:\Windows\System32\pet-shop-tutorial\build\contracts > Compiled successfully using: - solc: 0.5.16+commit.9c3226ce.Emscripten.clangマイグレーション
migrationsは、アプリケーションのコントラクト状態を変更します。
コントラクトをある状態から次の状態に移行することを目的としたスクリプトです。
Ganasheを起動してブロックチェーンを実行する。
コントラクトファイルの確認
C:\Windows\System32\pet-shop-tutorial\migrations>type 2_deploy_contracts.js ・ソvar Adoption = artifacts.require("Adoption"); module.exports = function(deployer) { deployer.deploy(Adoption); };2020/09/02 10:31 <DIR> . 2020/09/02 10:31 <DIR> .. 2020/06/22 13:20 129 1_initial_migration.js 2020/09/02 10:26 123 2_deploy_contracts.js 2 個のファイル 252 バイト 2 個のディレクトリ 58,223,267,840 バイトの空き領域デプロイ(マイグレート)の実施
C:\Windows\System32\pet-shop-tutorial>truffle migrate Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Starting migrations... ====================== > Network name: 'development' > Network id: 5777 > Block gas limit: 6721975 (0x6691b7) 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0xf01da0aafd8d23b941d05773f139e76dfa1dd9650621aa84c8b91863a7369500 > Blocks: 0 Seconds: 0 > contract address: 0x5c8f7Adfe135391061b66093D9FD4F71D118364c > block number: 1 > block timestamp: 1599011129 > account: 0x94dc5D7a73041512cBba5b3cC444646F2ddd7C47 > balance: 99.99671674 > gas used: 164163 (0x28143) > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00328326 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00328326 ETH 2_deploy_contracts.js ===================== Deploying 'Adoption' -------------------- > transaction hash: 0xce87b171b7354010dd4381553d44aa1e79cdb7532373ceddc7d983e2af6c3f18 > Blocks: 0 Seconds: 0 > contract address: 0x3e292B83F3C671B2a1F209abEDB9BCd840112204 > block number: 3 > block timestamp: 1599011129 > account: 0x94dc5D7a73041512cBba5b3cC444646F2ddd7C47 > balance: 99.99179362 > gas used: 203815 (0x31c27) > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.0040763 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.0040763 ETH Summary ======= > Total deployments: 2 > Final cost: 0.00735956 ETHスマートコントラクト実行後のイーサリウムブロックチェーン
以上で、最初のスマートコントラクトを記述し、
ローカルで実行しているブロックチェーンにデプロイが完了しました。Solidityを使用したスマートコントラクトのテスト
adopt()関数のテスト
// Testing the adopt() function function testUserCanAdoptPet() public { uint returnedId = adoption.adopt(expectedPetId); Assert.equal(returnedId, expectedPetId, "Adoption of the expected pet should match what is returned."); }単一のペットの飼い主の取得のテスト
Assert.equal()でexpectedとadopterのアドレスが同じものかを判定します。
テスト通りに動けば、ぺットを採用した人と採用されたペットが正しく関連付けされていることを確認できます。
// Testing retrieval of a single pet's owner function testGetAdopterAddressByPetId() public { address adopter = adoption.adopters(expectedPetId); Assert.equal(adopter, expectedAdopter, "Owner of the expected pet should be this contract"); }すべてのペット所有者の検索のテスト
採用された全てのペットを正しく出力できているかをテストします。
expectedには現在のコントラクトを呼び出しているアドレスが格納されます。
adoptersには採用された全てのペットデータが一時的に記録されます。
Assert.equal()でID8のペットを採用したアドレスと、
現在のコントラクトを呼び出しているアドレスが同じかを判定します。// Testing retrieval of all pet owners function testGetAdopterAddressByPetIdInArray() public { // Store adopters in memory rather than contract's storage address[16] memory adopters = adoption.getAdopters(); Assert.equal(adopters[expectedPetId], expectedAdopter, "Owner of the expected pet should be this contract"); }テストコントラクト
pragma solidity ^0.5.0; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Adoption.sol"; contract TestAdoption { // The address of the adoption contract to be tested Adoption adoption = Adoption(DeployedAddresses.Adoption()); // The id of the pet that will be used for testing uint expectedPetId = 8; //The expected owner of adopted pet is this contract address expectedAdopter = address(this); // Testing the adopt() function function testUserCanAdoptPet() public { uint returnedId = adoption.adopt(expectedPetId); Assert.equal(returnedId, expectedPetId, "Adoption of the expected pet should match what is returned."); } // Testing retrieval of a single pet's owner function testGetAdopterAddressByPetId() public { address adopter = adoption.adopters(expectedPetId); Assert.equal(adopter, expectedAdopter, "Owner of the expected pet should be this contract"); } // Testing retrieval of all pet owners function testGetAdopterAddressByPetIdInArray() public { // Store adopters in memory rather than contract's storage address[16] memory adopters = adoption.getAdopters(); Assert.equal(adopters[expectedPetId], expectedAdopter, "Owner of the expected pet should be this contract"); } }テストを実行する
truffle test
C:\Users\■■■\Desktop\pet-shop-tutorial\test>truffle test Using network 'development'. Compiling your contracts... =========================== > Compiling .\contracts\Adoption.sol > Compiling .\contracts\Migrations.sol > Compiling .\contracts\Adoption.sol > Compiling .\test\TestAdoption.sol > Artifacts written to C:\Users\■■■\AppData\Local\Temp\test--11340-4bUA2FwvQduD > Compiled successfully using: - solc: 0.5.16+commit.9c3226ce.Emscripten.clang TestAdoption √ testUserCanAdoptPet (197ms) √ testGetAdopterAddressByPetId (159ms) √ testGetAdopterAddressByPetIdInArray (176ms) 3 passing (10s)テスト後のブロックチェーン
テスト実行時のトランザクションの動き
以上でペットショップテスト動作が完了しました。
以上でスマートコントラクトを作成し、ローカルテストブロックチェーンに展開し、コンソールを介してそれを操作できることを確認。
ユーザーインターフェイスの作成へ
/src/js/app.jsを指示通りに変更する
App = { web3Provider: null, contracts: {}, init: async function() { // Load pets. $.getJSON('../pets.json', function(data) { var petsRow = $('#petsRow'); var petTemplate = $('#petTemplate'); for (i = 0; i < data.length; i ++) { petTemplate.find('.panel-title').text(data[i].name); petTemplate.find('img').attr('src', data[i].picture); petTemplate.find('.pet-breed').text(data[i].breed); petTemplate.find('.pet-age').text(data[i].age); petTemplate.find('.pet-location').text(data[i].location); petTemplate.find('.btn-adopt').attr('data-id', data[i].id); petsRow.append(petTemplate.html()); } }); return await App.initWeb3(); }, initWeb3: async function() { // Modern dapp browsers... if (window.ethereum) { App.web3Provider = window.ethereum; try { // Request account access await window.ethereum.enable(); } catch (error) { // User denied account access... console.error("User denied account access") } } // Legacy dapp browsers... else if (window.web3) { App.web3Provider = window.web3.currentProvider; } // If no injected web3 instance is detected, fall back to Ganache else { App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545'); } web3 = new Web3(App.web3Provider); return App.initContract(); }, initContract: function() { $.getJSON('Adoption.json', function(data) { // Get the 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(); }); return App.bindEvents(); }, bindEvents: function() { $(document).on('click', '.btn-adopt', App.handleAdopt); }, markAdopted: function(adopters, account) { var adoptionInstance; App.contracts.Adoption.deployed().then(function(instance) { adoptionInstance = instance; return adoptionInstance.getAdopters.call(); }).then(function(adopters) { for (i = 0; i < adopters.length; i++) { if (adopters[i] !== '0x0000000000000000000000000000000000000000') { $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true); } } }).catch(function(err) { console.log(err.message); }); }, handleAdopt: function(event) { event.preventDefault(); var petId = parseInt($(event.target).data('id')); 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 transaction by sending account return adoptionInstance.adopt(petId, {from: account}); }).then(function(result) { return App.markAdopted(); }).catch(function(err) { console.log(err.message); }); }); } }; $(function() { $(window).load(function() { App.init(); }); });MetaMaskインストール
crom拡張機能。
http://127.0.0.1:7545[ 新しいネットワーク]に接続。dappの使用
ローカルWebサーバーを起動します。
npm run dev
C:\Users\■■■\Desktop\pet-shop-tutorial>npm run dev
> pet-shop@1.0.0 dev C:\Users\■■■\Desktop\pet-shop-tutorial > lite-server ** browser-sync config ** { injectChanges: false, files: [ './**/*.{html,htm,css,js}' ], watchOptions: { ignored: 'node_modules' }, server: { baseDir: [ './src', './build/contracts' ], middleware: [ [Function], [Function] ] } } [Browsersync] Access URLs: -------------------------------------- Local: http://localhost:3000 External: http://192.168.2.109:3000 -------------------------------------- UI: http://localhost:3001 UI External: http://localhost:3001 -------------------------------------- [Browsersync] Serving files from: ./src [Browsersync] Serving files from: ./build/contracts [Browsersync] Watching files... 20.09.03 08:42:30 304 GET /index.html 20.09.03 08:42:30 304 GET /css/bootstrap.min.css 20.09.03 08:42:30 304 GET /js/bootstrap.min.js 20.09.03 08:42:30 304 GET /js/web3.min.js 20.09.03 08:42:30 304 GET /js/truffle-contract.js 20.09.03 08:42:30 304 GET /js/app.js (node:8132) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated 20.09.03 08:42:30 304 GET /pets.json 20.09.03 08:42:30 304 GET /images/scottish-terrier.jpeg 20.09.03 08:42:30 304 GET /images/french-bulldog.jpeg 20.09.03 08:42:30 304 GET /images/boxer.jpeg 20.09.03 08:42:30 304 GET /images/golden-retriever.jpeg 20.09.03 08:42:30 304 GET /Adoption.jsonブラウザ起動時
App.init();が実行される。
引用元 サイト https://www.trufflesuite.com/tutorials
引用元 サイト イーサリアムペットショップ-初めてのDAPP
(https://www.trufflesuite.com/tutorials/pet-shop)The architecture of Ethereum DApp
Client’s Browser
It is just like a normal browser of any web application written in HTML, CSS, and JavaScript.
Web3.js
Web3.js is a collection of libraries that enables your browser to interact with the blockchain. It enables you to read and write data from smart contracts, transfer ethers between accounts and much more.
Web3 Provider
Ethereum network contains nodes and all nodes share the same copy of data. Setting a “web3 provider” in web3.js tells our code which node we are going to read and write data from. We are using Metamask in our implementation that injects its web3 provider in the browser. Metamask is a browser extension for Chrome and Firefox that lets users securely manage their Ethereum accounts and private keys, and use these accounts to interact with websites that are using Web3.js.
Ethereum Virtual Machine
Every Ethereum node in Ethereum network runs their own EVM implementation and is responsible for running the same instructions of smart contracts over the Ethereum network.
引用元 Ethereum Dapp Development(https://www.c-sharpcorner.com/article/build-your-ethereum-dapp-on-windows-with-truffle-ganache-and-metamask-beginne/)