以太坊DApp開発-無知から門を見つけるまで
15940 ワード
目次
文書ディレクトリ
ゼロ、関連ツール
本明細書で直接使用するツール:Remix,truffle(v 5.1.0)、ganache(v 2.1.2)、MetaMaskなど
0.1ローカルテストノード
0.2 MetaMask
Chromeプラグイン.異なるノードを接続することを選択できます.ユーザー秘密鍵をインポートした後、ユーザーのEthernet通貨の数を表示することもできます.関連口座後に一部の取引が発生した場合、ポップアップウィンドウを開いてユーザーに取引を確認させることができます.
0.3 Remixの使用
Remix: http://remix.ethereum.org
File explorers
では新規契約の作成、契約の編集などの操作ができます.Solidity compiler
でSolidityコンパイラバージョンを選択し、まずコンパイルして文法に問題があるかどうかを検証し、Deploy & run transactions
で環境を選択します.Environment
選択Injected Web3
はnetmaskプラグインをポップアップしてアカウントバインドを行います(EnvironmentはWeb 3 Providerも選択できます.エーテル坊ノードに接続するように提示されます.localhost:8545に接続してテストすることができます.)Deploy & run transactions
パネルの契約選択ドロップダウンボックスの下にはDeployとAt Addressがあり、前者はコンストラクション関数で契約を作成し、後者は契約のアドレスを入力して取得します(接続?)契約は、作成(/接続)に成功すると、契約で呼び出す方法が下に表示され、このパネルで契約を呼び出す関数を操作できます(アドレス接続の契約を入力することで、口座などの情報を構成して取引を実行する必要があります).契約作成ウィンドウの下にはコンソールがあり、Web 3のAPIを介して命令を実行することができる.eth.getBalance(“0x04555018d100bd9ad75544de623ec8e3692e423a”);
一、テンプレート項目テスト
1.1プロジェクトの初期化
# truffle unbox react
✔ Preparing to download
✔ Downloading
✔ Cleaning up temporary files
......
✔ Setting up box
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
Test dapp: cd client && npm test
Run dev server: cd client && npm run start
Build for production: cd client && npm run build
(直接ダウンロードは遅く、プロキシダウンロードを考慮)実行コマンド
truffle unbox react
はテンプレートアイテムをダウンロードします.ここでclientディレクトリの下にはReactプロジェクトがあり、Setting up box
まで実行すると、client/node_で時間がかかります.modulesディレクトリの下で必要な依存度(100+MB)をダウンロードします.TRUFFLE BOXESでboxの名前を検索してダウンロードすることもできます.https://www.trufflesuite.com/boxes/react、ダウンロードボタンをクリックしてダウンロードできますが、クライアントディレクトリにnode_がありません.modules、依存問題を自分で解決する必要があります.
truffleのWebサイトから直接ダウンロードされるプロジェクトディレクトリの構造は、次のとおりです.
.
├── box-img-lg.png
├── box-img-sm.png
├── client
│ ├── package.json
│ ├── package-lock.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── README.md
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── getWeb3.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── serviceWorker.js
│ └── yarn.lock
├── contracts
│ ├── Migrations.sol
│ └── SimpleStorage.sol
├── LICENSE
├── migrations
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── README.md
├── test
│ ├── simplestorage.js
│ └── TestSimpleStorage.sol
├── truffle-box.json
└── truffle-config.js
1.2契約のコンパイル
root@kali:/BlockChain/react-box-master# truffle compile
Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/SimpleStorage.sol
> Artifacts written to /BlockChain/react-box-master/client/src/contracts
> Compiled successfully using:
- solc: 0.5.12+commit.7709ece9.Emscripten.clang
プロジェクトディレクトリの下で
truffle compile
を実行してコンパイルし、コンパイル後にclient/src/contractsディレクトリを生成し、このディレクトリの下に2つのファイルがあります:Migrations.json SimpleStorage.json
、1.3導入契約
1.3.1 ganacheの起動
1.3.2 truffle-configを修正する.js
ノード情報を設定します.変更されたファイルの内容は次のとおりです.
const path = require("path");
module.exports = {
// See
// to customize your Truffle configuration!
contracts_build_directory: path.join(__dirname, "client/src/contracts"),
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*"
}
}
};
1.3.3配置
truffle migrate
を使用して導入:root@kali:/BlockChain/react-box-master# 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: 0x6691b7
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0x872c9be81fc25005dc3535821e9fe52375b0ccb409cbdf4b85e2483d76bbcfe0
> Blocks: 0 Seconds: 0
> contract address: 0xe7536a28473dFF0875b81bDdb7dCe10CA1e95cDe
> block number: 1
> block timestamp: 1574910360
> account: 0xA5D2948e8fd43D6d0C8eD7bCe0fEba3039A8D009
> balance: 99.99472518
> gas used: 263741
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00527482 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00527482 ETH
2_deploy_contracts.js
=====================
Deploying 'SimpleStorage'
-------------------------
> transaction hash: 0xba46904f988290f25d36918c7f731f9d4bdb3d2b6b3c2520f2b79f90f0df5173
> Blocks: 0 Seconds: 0
> contract address: 0x0D7C49CFfD2e82B5C124F455fCEaDC27d1cdC41D
> block number: 3
> block timestamp: 1574910361
> account: 0xA5D2948e8fd43D6d0C8eD7bCe0fEba3039A8D009
> balance: 99.99173734
> gas used: 107369
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00214738 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00214738 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.0074222 ETH
1.4テスト
1.4.1 Remixでのテスト
オンラインIDEで契約をテストし、まずMetaMaskをganacheが起動したノードに接続し、そのうちの1つのテストアカウントをインポートします.SimpleStorage.solはRemix Solidity IDEにコピーしてコンパイルし、
Deploy & run transactions
ウィンドウで契約を選択し、At Address
ボタンの後の入力ボックスに上記配置した契約アドレス0x0D7C49CFfD2e82B5C124F455fCEaDC27d1cdC41D
を入力し、ボタンをクリックして契約インスタンスを取得する.下に表示される契約メソッドのリストで、パラメータを入力してsetメソッド名を表示するボタンをクリックしてメソッドを呼び出し、MetaMaskウィンドウをポップアップし、取引を確認し、完了するとganacheにブロックが追加され、
CONTRACT CALL
のタイプの取引が表示されます.さらにオンラインIDEのページでgetメソッドをクリックすると、先ほど保存した値が返されます.1.4.2 Reactプロジェクトを起動してテストを行う
client/src/App.jsにはReactコンポーネントが定義されており、ライフサイクルメソッドcomponentDidMountが呼び出されると、web 3、アカウント、契約インスタンスを取得し、ステータスを更新し、runExampleメソッドを呼び出す.runExampleメソッドでは、まず契約を呼び出すsetメソッドに値5を書き、契約のgetメソッドで書き込まれたばかりの値を取得し、取得した値をコンポーネントの状態に更新した後、コンポーネントのrenderメソッドが呼び出され、この値とHTMLがDOMにレンダリングされます.App.jsコードは以下の通りです.
import React, { Component } from "react";
import SimpleStorageContract from "./contracts/SimpleStorage.json";
import getWeb3 from "./getWeb3";
import "./App.css";
class App extends Component {
state = { storageValue: 0, web3: null, accounts: null, contract: null };
componentDidMount = async () => {
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
// Get the contract instance.
const networkId = await web3.eth.net.getId();
const deployedNetwork = SimpleStorageContract.networks[networkId];
const instance = new web3.eth.Contract(
SimpleStorageContract.abi,
deployedNetwork && deployedNetwork.address,
);
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ web3, accounts, contract: instance }, this.runExample);
} catch (error) {
// Catch any errors for any of the above operations.
alert(
`Failed to load web3, accounts, or contract. Check console for details.`,
);
console.error(error);
}
};
runExample = async () => {
const { accounts, contract } = this.state;
// Stores a given value, 5 by default.
await contract.methods.set(5).send({ from: accounts[0] });
// Get the value from the contract to prove it worked.
const response = await contract.methods.get().call();
// Update state with the result.
this.setState({ storageValue: response });
};
render() {
if (!this.state.web3) {
return Loading Web3, accounts, and contract...;
}
return (
Good to Go!
Your Truffle Box is installed and ready.
Smart Contract Example
If your contracts compiled and migrated successfully, below will show
a stored value of 5 (by default).
Try changing the value stored on line 40 of App.js.
The stored value is: {this.state.storageValue}
);
}
}
export default App;
await contract.methods.set(5).send({ from: accounts[0] });
という行のコードを注釈し、クライアントディレクトリの下でnpm start
を実行してサービスを開始し、ブラウザはlocalhost:3000
にアクセスし、ページには前のステップでオンラインIDEから書き込まれた値が表示されます.二、DIY
2.1プロジェクトの修正&契約のコンパイル
テンプレートの項目について修正を行い、まず項目目次のcontracts目次の下に契約Votingを新規作成する.sol(あるチュートリアルからコピーされ、solidityバージョンに基づいて少し変更された簡単な投票契約):
pragma solidity ^0.5.0;
contract Voting {
bytes32[] candidates;
mapping(bytes32 => uint) candidatesVotingCount;
// https://stackoverflow.com/questions/53460851/typeerror-data-location-must-be-memory-for-parameter-in-function-but-none-wa
// google remix bytes32[] :https://blog.csdn.net/github_38575699/article/details/101269929
// remix solidity ?Deploy , , bytes32 32
// ["A", "B"] :
/* ["0x4100000000000000000000000000000000000000000000000000000000000000",
"0x4200000000000000000000000000000000000000000000000000000000000000"]
*/
constructor(bytes32[] memory _candidates) public {
candidates = _candidates;
}
function votingToPerson(bytes32 person) public {
assert(isValidToPerson(person));
candidatesVotingCount[person] += 1;
}
function votingTotalToPerson(bytes32 person) view public returns(uint) {
require(isValidToPerson(person));
return candidatesVotingCount[person];
}
function isValidToPerson(bytes32 person) view public returns(bool) {
for (uint i = 0; i < candidates.length; i++) {
if (candidates[i] == person) {
return true;
}
}
return false;
}
}
その後
truffle compile
コンパイル契約を実行し、コンパイル完了後client/src/contractsは以前よりVoting.json
増加した.2.2導入契約
migrationsディレクトリの
2_deploy_contracts.js
を変更し、その中のテンプレートプロジェクト契約名SimpleStorage
をすべてVoting
に変更し、truffle migrate
の導入を実行し、エラーを報告します.......
Error: Error: Error: *** Deployment Failed ***
"Voting" -- Invalid number of parameters for "undefined". Got 0 expected 1!.
at Object.run (/node-v12.13.0-linux-x64/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:92:1)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
Truffle v5.1.0 (core: 5.1.0)
Node v12.13.0
いくつかの解決策(https://stackoverflow.com/questions/54304214/truffle-smart-contract-error-invalid-number-of-parameter)、
2_deploy_contracts.js
のdeployer.deployは2番目のパラメータを伝えることができ、何回か試した後、2番目のパラメータが契約の構造関数のパラメータであることを発見し、2_deploy_contracts.js
の内容を以下のように修正した.var Voting = artifacts.require("./Voting.sol");
module.exports = function(deployer) {
deployer.deploy(Voting, ["0x4100000000000000000000000000000000000000000000000000000000000000", "0x4200000000000000000000000000000000000000000000000000000000000000"]);
};
その後、
truffle migrate
を使用して配備され、配備後、出力された契約アドレスに基づいてオンラインIDEでテストできるようになった.2.3 React項目の修正
まずAppを保存します.jsをバックアップとして、Appを変更します.jsの内容は以下の通りです.
import React, { Component } from "react";
import Voting from "./contracts/Voting.json";
import getWeb3 from "./getWeb3";
import "./App.css";
class App extends Component {
state = {voting: [], web3: null, accounts: null, contract: null};
componentDidMount = async () => {
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
// Get the contract instance.
const networkId = await web3.eth.net.getId();
const deployedNetwork = Voting.networks[networkId];
const instance = new web3.eth.Contract(
Voting.abi,
deployedNetwork && deployedNetwork.address,
);
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ web3, accounts, contract: instance}, this.getVoting);
} catch (error) {
// Catch any errors for any of the above operations.
alert(
`Failed to load web3, accounts, or contract. Check console for details.`,
);
console.error(error);
}
};
getVoting = async () => {
const { contract } = this.state;
let candidates = ["0x4100000000000000000000000000000000000000000000000000000000000000", "0x4200000000000000000000000000000000000000000000000000000000000000"];
let voting = new Array();
await Promise.all(candidates.map(async (elem, index) => {
voting.push({
name: elem,
//
count: await contract.methods.votingTotalToPerson(elem).call(),
key: index
})
}));
this.setState({ voting});
};
render() {
if (!this.state.web3) {
return Loading Web3, accounts, and contract...;
}
return (
Voting
{
this.state.voting.map((candidate) => {
return (チケットを
)
})
}
);
}
}
export default App;
クライアントディレクトリの下でコマンド
npm start
でサービスを開始し、ブラウザからlocalhost:3000
にアクセスすると、リストされた投票数が表示されます.ページ上の入力ボックスとボタンで投票することもできます.