1648110000
独自のブロックチェーンアプリケーションを作成する方法を考えたことはありますか?イーサリアムに関して言えば、それはスマートコントラクトから始まります。
このチュートリアルでは、Solidity言語で記述されたスマートコントラクトに焦点を当てます。Truffle Suiteを使用して、ローカルバージョンのEthereumブロックチェーンをデプロイし、Ethereum仮想マシン(EVM)を使用してスマートコントラクトをコンパイルします。
上記のテクノロジーに精通していない場合は、最初にWeb3.jsを使用したイーサリアムブロックチェーン開発のガイドを読むことをお勧めします。
イーサリアムは、アプリケーションを実行できるようにするブロックチェーンです。コードは、スマートコントラクトの形式でSolidity言語で記述されています。これらのコントラクトをコンパイルするには、スマートコントラクトを機械可読コードに変換するEthereumコンパイラが必要です。
Truffle Suiteは、イーサリアムでのブロックチェーン開発用に特別に作成されたツールのコレクションです。スイートには、次の3つのソフトウェアが含まれています。
このチュートリアルでは、Ethereumブロックチェーン、スマートコントラクトコンパイラ、通信用のJavaScriptライブラリなど、いくつかのノードパッケージとソフトウェアが必要です。
スマートコントラクトはイーサリアムブロックチェーンで実行されるため、展開とテストにスマートコントラクトが必要です。ライブチェーンにデプロイすることもできますが、ガス料金としてEtherが必要になります。それでは、ローカルチェーンを設定して、そこでテストを行いましょう。コードについて確信があり、アプリケーションを配布する準備ができたら、ライブチェーンにデプロイできます。
Ganacheは、コンピューターにインストールされ、ローカルホストで実行されるローカルチェーンです。TruffleSuiteのWebサイトからGanacheをダウンロードしてインストールします。
Ganacheがそれぞれ100ETHで10個のアカウントを提供したことがわかります。これらは偽のエーテルなので、興奮しないでください。また、チェーンは7545ポートの127.0.0.1で実行されています。これらのアカウントを使用して、このチェーンにスマートコントラクトを展開します。エーテルは私たちがガス料金を支払うのを助けます。
このプロジェクトにはNode.jsが必要なので、システムにインストールされていることを確認してください。Node.jsの公式ウェブサイトからダウンロードできます。
Web3.jsは、JavaScriptを介したイーサリアムブロックチェーンとの通信を可能にするJavaScriptライブラリです。開発に役立つ機能がたくさん組み込まれています。
npm
またはを使用してWeb3.jsをインストールできますyarn
。
npm install web3 -g
Truffleは、スマートコントラクト用のコンパイラを提供します。SolidityコードをGanacheブロックチェーンにデプロイできる機械可読コードに変換するために必要です。
次のコマンドを使用してTruffleをインストールします。
npm install truffle -g
スマートコントラクトを作成するには、最初に、すべてのSolidityファイルを保持するプロジェクトディレクトリを作成する必要があります。solidity
名前を付けて作成し、を使用してターミナルのディレクトリに移動しましょうcd solidity
。
現在、私たちのプロジェクトは空です。それを操作するには、ボイラープレートコードが必要です。たとえば、ReactでUIを作成する場合は、Reactをインストールする必要があります。
Truffleは、ボックスと呼ばれるいくつかのパッケージをすでに提供しています。これらのパッケージは、Truffle、Ganache、React、Web3、Reduxなどのさまざまなフレームワークのバンドルであり、Vue.js開発者向けのパッケージがあります。これらは一緒になって、クライアントUIからブロックチェーンスマートコントラクトまで、エンドツーエンドのアプリケーション開発を完了します。
この記事では、Truffleが提供するReactボックスを使用します。
Reactボックスをインストールするには、次のコマンドを実行します。
truffle unbox react
これにより、Web3.js、React、Ganache CLI、Truffle、およびEthereumがインストールされます。ある意味では、最初のステップでこれらすべてのユーティリティをインストールする必要はありませんでした。
このチュートリアルでは、ReactやブラウザーベースのUIには焦点を当てません。代わりに、スマートコントラクトを作成し、ターミナルのみで処理します。
プロジェクトのディレクトリ構造は次のようになります。
client
これは、アプリケーションのUIを作成できるReactプロジェクトフォルダーです。その中には、コンパイルされたスマートコントラクトをJSON形式で保持するフォルダー(client
/ src
/ )があります。contracts
これらのファイルは、スマートコントラクトをコンパイルするときに生成されます。これらには、ABI、バイトコード、およびその他の情報が含まれています。
上の画像から、2つのJSONファイルがあることがわかります。これは、Reactバンドルを箱から出したときに、Truffleがすでに2つのスマートコントラクトを提供していたためです。それらのいずれかを開くと、次のようなコードが見つかります。
{
"contractName": "SimpleStorage",
"abi": [
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "x",
"type": "uint256"
}
],
"name": "set",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "get",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
"metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"project:/contracts/SimpleStorage.sol\":\"SimpleStorage\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"project:/contracts/SimpleStorage.sol\":{\"keccak256\":\"0x512df1603c5f878921707d236bc53d974afe05b4d9de4b6094249bac5ab60efe\",\"urls\":[\"bzz-raw://0d6de97971b1c387f984fa7ea1d9ec10f8a63d68cc63bf8bd00d8c3a7c9e3ee1\",\"dweb:/ipfs/Qmbt92T34sHzedfJjDsvbisvLhRtghNwS6VW8tqrGkrqTD\"]}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5060c68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea265627a7a7231582044ccb2c2d46346d523107088f3e26a4c8a2ec3ec8b2e3a6edb1bc8574d5c5f5264736f6c63430005100032",
"deployedBytecode": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea265627a7a7231582044ccb2c2d46346d523107088f3e26a4c8a2ec3ec8b2e3a6edb1bc8574d5c5f5264736f6c63430005100032",
"sourceMap": "66:176:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66:176:1;;;;;;;",
"deployedSourceMap": "66:176:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66:176:1;;;;;;;;;;;;;;;;;;;;;;;;113:53;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;113:53:1;;;;;;;;;;;;;;;;;:::i;:::-;;170:70;;;:::i;:::-;;;;;;;;;;;;;;;;;;;113:53;160:1;147:10;:14;;;;113:53;:::o;170:70::-;206:4;225:10;;218:17;;170:70;:::o",
"source": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.21 <0.7.0;\n\ncontract SimpleStorage {\n uint storedData;\n\n function set(uint x) public {\n storedData = x;\n }\n\n function get() public view returns (uint) {\n return storedData;\n }\n}\n",
"sourcePath": "C:\\Users\\akash\\Desktop\\solidity\\contracts\\SimpleStorage.sol",
"ast": {
"absolutePath": "project:/contracts/SimpleStorage.sol",
"exportedSymbols": {
"SimpleStorage": [
59
]
},
"id": 60,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 38,
"literals": [
"solidity",
">=",
"0.4",
".21",
"<",
"0.7",
".0"
],
"nodeType": "PragmaDirective",
"src": "32:32:1"
},
{
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": true,
"id": 59,
"linearizedBaseContracts": [
59
],
"name": "SimpleStorage",
"nodeType": "ContractDefinition",
"nodes": [
{
"constant": false,
"id": 40,
"name": "storedData",
"nodeType": "VariableDeclaration",
"scope": 59,
"src": "93:15:1",
"stateVariable": true,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 39,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "93:4:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
},
{
"body": {
"id": 49,
"nodeType": "Block",
"src": "141:25:1",
"statements": [
{
"expression": {
"argumentTypes": null,
"id": 47,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftHandSide": {
"argumentTypes": null,
"id": 45,
"name": "storedData",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40,
"src": "147:10:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"nodeType": "Assignment",
"operator": "=",
"rightHandSide": {
"argumentTypes": null,
"id": 46,
"name": "x",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 42,
"src": "160:1:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"src": "147:14:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"id": 48,
"nodeType": "ExpressionStatement",
"src": "147:14:1"
}
]
},
"documentation": null,
"id": 50,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "set",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 43,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 42,
"name": "x",
"nodeType": "VariableDeclaration",
"scope": 50,
"src": "126:6:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 41,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "126:4:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "125:8:1"
},
"returnParameters": {
"id": 44,
"nodeType": "ParameterList",
"parameters": [],
"src": "141:0:1"
},
"scope": 59,
"src": "113:53:1",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
},
{
"body": {
"id": 57,
"nodeType": "Block",
"src": "212:28:1",
"statements": [
{
"expression": {
"argumentTypes": null,
"id": 55,
"name": "storedData",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40,
"src": "225:10:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"functionReturnParameters": 54,
"id": 56,
"nodeType": "Return",
"src": "218:17:1"
}
]
},
"documentation": null,
"id": 58,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "get",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 51,
"nodeType": "ParameterList",
"parameters": [],
"src": "182:2:1"
},
"returnParameters": {
"id": 54,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 53,
"name": "",
"nodeType": "VariableDeclaration",
"scope": 58,
"src": "206:4:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 52,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "206:4:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "205:6:1"
},
"scope": 59,
"src": "170:70:1",
"stateMutability": "view",
"superFunction": null,
"visibility": "public"
}
],
"scope": 60,
"src": "66:176:1"
}
],
"src": "32:211:1"
},
"legacyAST": {
"attributes": {
"absolutePath": "project:/contracts/SimpleStorage.sol",
"exportedSymbols": {
"SimpleStorage": [
59
]
}
},
"children": [
{
"attributes": {
"literals": [
"solidity",
">=",
"0.4",
".21",
"<",
"0.7",
".0"
]
},
"id": 38,
"name": "PragmaDirective",
"src": "32:32:1"
},
{
"attributes": {
"baseContracts": [
null
],
"contractDependencies": [
null
],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": true,
"linearizedBaseContracts": [
59
],
"name": "SimpleStorage",
"scope": 60
},
"children": [
{
"attributes": {
"constant": false,
"name": "storedData",
"scope": 59,
"stateVariable": true,
"storageLocation": "default",
"type": "uint256",
"value": null,
"visibility": "internal"
},
"children": [
{
"attributes": {
"name": "uint",
"type": "uint256"
},
"id": 39,
"name": "ElementaryTypeName",
"src": "93:4:1"
}
],
"id": 40,
"name": "VariableDeclaration",
"src": "93:15:1"
},
{
"attributes": {
"documentation": null,
"implemented": true,
"isConstructor": false,
"kind": "function",
"modifiers": [
null
],
"name": "set",
"scope": 59,
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
},
"children": [
{
"children": [
{
"attributes": {
"constant": false,
"name": "x",
"scope": 50,
"stateVariable": false,
"storageLocation": "default",
"type": "uint256",
"value": null,
"visibility": "internal"
},
"children": [
{
"attributes": {
"name": "uint",
"type": "uint256"
},
"id": 41,
"name": "ElementaryTypeName",
"src": "126:4:1"
}
],
"id": 42,
"name": "VariableDeclaration",
"src": "126:6:1"
}
],
"id": 43,
"name": "ParameterList",
"src": "125:8:1"
},
{
"attributes": {
"parameters": [
null
]
},
"children": [],
"id": 44,
"name": "ParameterList",
"src": "141:0:1"
},
{
"children": [
{
"children": [
{
"attributes": {
"argumentTypes": null,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"operator": "=",
"type": "uint256"
},
"children": [
{
"attributes": {
"argumentTypes": null,
"overloadedDeclarations": [
null
],
"referencedDeclaration": 40,
"type": "uint256",
"value": "storedData"
},
"id": 45,
"name": "Identifier",
"src": "147:10:1"
},
{
"attributes": {
"argumentTypes": null,
"overloadedDeclarations": [
null
],
"referencedDeclaration": 42,
"type": "uint256",
"value": "x"
},
"id": 46,
"name": "Identifier",
"src": "160:1:1"
}
],
"id": 47,
"name": "Assignment",
"src": "147:14:1"
}
],
"id": 48,
"name": "ExpressionStatement",
"src": "147:14:1"
}
],
"id": 49,
"name": "Block",
"src": "141:25:1"
}
],
"id": 50,
"name": "FunctionDefinition",
"src": "113:53:1"
},
{
"attributes": {
"documentation": null,
"implemented": true,
"isConstructor": false,
"kind": "function",
"modifiers": [
null
],
"name": "get",
"scope": 59,
"stateMutability": "view",
"superFunction": null,
"visibility": "public"
},
"children": [
{
"attributes": {
"parameters": [
null
]
},
"children": [],
"id": 51,
"name": "ParameterList",
"src": "182:2:1"
},
{
"children": [
{
"attributes": {
"constant": false,
"name": "",
"scope": 58,
"stateVariable": false,
"storageLocation": "default",
"type": "uint256",
"value": null,
"visibility": "internal"
},
"children": [
{
"attributes": {
"name": "uint",
"type": "uint256"
},
"id": 52,
"name": "ElementaryTypeName",
"src": "206:4:1"
}
],
"id": 53,
"name": "VariableDeclaration",
"src": "206:4:1"
}
],
"id": 54,
"name": "ParameterList",
"src": "205:6:1"
},
{
"children": [
{
"attributes": {
"functionReturnParameters": 54
},
"children": [
{
"attributes": {
"argumentTypes": null,
"overloadedDeclarations": [
null
],
"referencedDeclaration": 40,
"type": "uint256",
"value": "storedData"
},
"id": 55,
"name": "Identifier",
"src": "225:10:1"
}
],
"id": 56,
"name": "Return",
"src": "218:17:1"
}
],
"id": 57,
"name": "Block",
"src": "212:28:1"
}
],
"id": 58,
"name": "FunctionDefinition",
"src": "170:70:1"
}
],
"id": 59,
"name": "ContractDefinition",
"src": "66:176:1"
}
],
"id": 60,
"name": "SourceUnit",
"src": "32:211:1"
},
"compiler": {
"name": "solc",
"version": "0.5.16+commit.9c3226ce.Emscripten.clang"
},
"networks": {
"5777": {
"events": {},
"links": {},
"address": "0xc21DB75B9B17Cb43Cd983A16BaA6c73b314B1E8f",
"transactionHash": "0xada7b561df968c3d23485d25cbd22a66d1d4b76a86137dbf1bef858e816ff0c2"
}
},
"schemaVersion": "3.4.3",
"updatedAt": "2021-10-29T10:14:41.665Z",
"networkType": "ethereum",
"devdoc": {
"methods": {}
},
"userdoc": {
"methods": {}
}
}
上記の大規模なコードブロックには、ABI、バイトコード、ソースコード、およびその他の大量の情報が含まれています。ABIから、呼び出し可能な関数のリストを取得できます。このファイルには、ネットワークID、契約アドレス、トランザクションハッシュ、コンパイラの詳細、チェーンの詳細などのすべての情報が含まれています。
なぜこのファイルがUIディレクトリにあるのか疑問に思われるかもしれません。これは、Web3.jsが操作に使用するためです。このファイルにより、Web3.jsはチェーン上のスマートコントラクトを認識できます。また、ABIは関数のリストを取得するのに役立ちます。
contracts
Solidityファイルを保持するディレクトリです。ここにすべてのソースコードを配置しますmigrations
どのSolidityファイルをチェーンに移行する必要があるかをTruffleに通知するファイルですtest
テストファイルを作成するためのものですtruffle-config.js
Truffleのいくつかの構成設定が含まれています。内容は次のtruffle-config.js
とおりです。
const path = require("path");
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
contracts_build_directory: path.join(__dirname, "client/src/contracts"),
networks: {
develop: {
port: 8545
}
}
};
ご覧のとおり、client/src/contracts
コンパイルされたコードを保持するように設定されています。開発ネットワークはポート8545に設定されています。これは、このボックスがGanacheを実行しているポートです。
Ganacheをインストールした上部を見ると、7545ポートで実行されていたことがわかりますが、インストールされたGanacheで7545がすでに使用されているため、これは8545で実行されています。必要に応じて、このポートを7545に変更できます。トリュフは、ボックスで提供されるアカウントの代わりに、ガナッシュとインストールしたアカウントを使用します。私はそれを8545に保っています。
次に、コードを記述します。CRUD操作を行い、果物のリストを管理します。
基本的に、私たちのアプリケーションはさまざまな果物のリストを表示します。フルーツを追加、更新、削除できます。
以前にアプリを開発したことがある場合は、必ずおなじみの手順に従います。
それでは、Solidityでコードを書いてみましょう。
ディレクトリに新しいファイルを作成し、contracts
それを呼び出しますFruits.sol
。サポートしているライセンスとSolidityバージョンを示すことからファイルを開始します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
次に、すべてのコードを記述するスコープを宣言しcontract
ます。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
}
果物を保持する配列を作成します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
}
これはプライベート修飾子を持つ文字列配列です。つまり、コントラクトの外部からアクセスできないため、値を直接変更することはできません。
次に、新しい値を追加する関数を作成します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
}
addFruit
文字列をパラメータとして受け入れる、という関数を作成しましたfruitName
。これはパブリックとして宣言されているため、UIまたはターミナルから呼び出すことができます。関数本体では、値を配列にプッシュするだけです。
値を更新します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
function updateFruit(uint fruitIndex, string memory newFruitName) public returns (bool) {
if(myFruits.length > fruitIndex){
myFruits[fruitIndex] = newFruitName;
return true;
}
return false;
}
}
updateFruitfruitIndex
2つの引数とを受け入れnewFruitName
、ブール値を返します。これは次のように機能します。インデックスが配列の範囲外の場合は、を返しますfalse
。それ以外の場合は、指定されたインデックスで新しく提供されたフルーツ名で配列の値を変更し、を返しtrue
ます。
次の手順は、削除機能を作成することです。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
function updateFruit(uint fruitIndex, string memory newFruitName) public returns (bool) {
if(myFruits.length > fruitIndex){
myFruits[fruitIndex] = newFruitName;
return true;
}
return false;
}
function deleteFruit(uint fruitIndex) public returns (bool) {
if(myFruits.length > fruitIndex){
for(uint i=fruitIndex; i < myFruits.length-1; i++){
myFruits[i] = myFruits[i+1];
}
myFruits.pop();
return true;
}
return false;
}
}
ここでは、インデックスの範囲外条件をチェックしてから、値を指定されたインデックスの次の値に置き換えることで配列を更新しています。このように、提供されたインデックスの値は失われます。最後に、最後の値を取り出して返しtrue
ます。
最後のステップは、配列を返すことです。配列のすべての値を読み取るには:
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
function updateFruit(uint fruitIndex, string memory newFruitName) public returns (bool) {
if(myFruits.length > fruitIndex){
myFruits[fruitIndex] = newFruitName;
return true;
}
return false;
}
function deleteFruit(uint fruitIndex) public returns (bool) {
if(myFruits.length > fruitIndex){
for(uint i=fruitIndex; i < myFruits.length-1; i++){
myFruits[i] = myFruits[i+1];
}
myFruits.pop();
return true;
}
return false;
}
function getFruits() public view returns (string[] memory) {
return myFruits;
}
}
スマートコントラクトのコーディングが完了したので、Truffleを使用してコンパイルします。ただし、最初に移行ファイルを作成して、これをチェーンに移行することをTruffleに示す必要があります。
フォルダをチェックインすると、migration
2つのJavaScriptファイルが見つかります。
それぞれ番号で始まるので、3番目のファイルは3で始まります。コードはほぼ標準です。それ2_deploy_contracts
は:
var SimpleStorage = artifacts.require("./SimpleStorage.sol");
module.exports = function(deployer) {
deployer.deploy(SimpleStorage);
};
移行ファイルを追加しましょう3_fruits_contracts
:
var FruitsList = artifacts.require("./Fruits.sol");
module.exports = function(deployer) {
deployer.deploy(FruitsList);
};
フルーツコントラクトをコンパイルして移行する準備が整いました。ターミナルに移動し、以下を実行します。
> truffle develop
このコマンドは、トリュフコンソールを起動します。また、チェーンネットワーク、アカウント、ニーモニックなどの情報も表示されます。
Ganacheはデフォルトで10個のアカウントを提供します。彼らはあなたのために異なります。これらの秘密鍵は、この記事のすべての訪問者に表示されるため、ライブチェーンでは使用しないでください。つまり、誰でもこれらのアカウントにアクセスできます。
次に、次のコマンドを使用してコントラクトをコンパイルします。
> compile
ファイルが作成されてclient/src/contracts
いるかどうかを確認できます。Fruits.json
次のコマンドを使用して、コンパイルされたファイルをチェーンに移行できます。
> migrate
これにより、3つのスマートコントラクトすべてがチェーンに移行されます。
最後に、私たちのアプリケーションはイーサリアムチェーン上にあります。ガス料金に0.00153イーサを費やし、トランザクションが最初のアカウントから発生したことがわかります。デフォルトでは、常に最初のアカウントが使用されます。さまざまな操作ができるようになりました。
Web3.jsを使用して、さまざまな値に反応して書き込むことができます。まず、コントラクトのインスタンスを変数に格納しましょう。
let instance = await Fruits.deployed()
await
ブロックチェーン内のすべてが非同期であり、promiseを返すため、使用しています。
次に、このインスタンスを使用して配列を取得します。
> let fruits = instance.getFruits()
undefined
> fruits
[]
現在、fruits配列には値がないため、空の配列が返されます。
いくつかの果物を追加しましょう:
> let result = await instance.addFruit("Apple")
undefined
はresult
トランザクションを保持します。すべての読み取り操作は無料ですが、ブロックチェーンの変更につながる操作にはガス料金がかかることを忘れないでください。この操作は、配列に値を追加し、データを変更します。したがって、トランザクションとして記録されます。
これで、配列を再度読み取って内容を確認できます。
リストにさらにいくつかの果物を追加しましょう。
> await instance.addFruit("Mango")
> await instance.addFruit("Banana")
> await instance.addFruit("Orange")
> await instance.addFruit("Guava")
> await instance.addFruit("Pineapple")
> await instance.addFruit("Water Melon")
> await instance.addFruit("Papaya")
> await instance.addFruit("Strawberry")
これらすべての操作にはEtherのコストがかかることを忘れないでください。一度に複数の果物の値を受け入れるための関数をコントラクトに作成することで、手数料を節約できます。
今すぐ配列を読んでください:
上の画像で、「Guava」のつづりを「Guavva」と間違えたことがわかります。updateFruit
関数を使って修正しましょう。インデックスと新しい値を受け入れます。インデックスは4です。
> await instance.updateFruit(4, "Guava")
今すぐ配列を読んでみましょう:
スペルは正常に修正されました。
最後の操作は、値を削除することです。
> await instance.deleteFruit(4)
値を読み取ります。
ご覧のとおり、「Guava」アイテムはリストから削除されています。
スマートコントラクトを作成してブロックチェーンにデプロイするのは楽しくて強力です。これは、従来のプログラミングからの新しい視点を提供します。これらの手法を使用して、オンライン投票、デジタルバンク、ウォレット、オークションなど、あらゆる種類のアプリケーションを作成できます。
このチュートリアルでは、スマートコントラクトを作成してローカルチェーンにデプロイする方法を示しました。これで、イーサリアムのテストネットワークにデプロイしてみることができます。
一度に複数のフルーツを追加してトランザクションコストを節約するなど、より多くの機能を導入することで、現在のアプリを改善できます。また、ユニークな果物のみを許可するようにチェックを入れることもできます。配列の代わりに、マッピングを使用してみてください。
ハッピーコーディング!
出典:https ://blog.logrocket.com/truffle-suite
1648110000
独自のブロックチェーンアプリケーションを作成する方法を考えたことはありますか?イーサリアムに関して言えば、それはスマートコントラクトから始まります。
このチュートリアルでは、Solidity言語で記述されたスマートコントラクトに焦点を当てます。Truffle Suiteを使用して、ローカルバージョンのEthereumブロックチェーンをデプロイし、Ethereum仮想マシン(EVM)を使用してスマートコントラクトをコンパイルします。
上記のテクノロジーに精通していない場合は、最初にWeb3.jsを使用したイーサリアムブロックチェーン開発のガイドを読むことをお勧めします。
イーサリアムは、アプリケーションを実行できるようにするブロックチェーンです。コードは、スマートコントラクトの形式でSolidity言語で記述されています。これらのコントラクトをコンパイルするには、スマートコントラクトを機械可読コードに変換するEthereumコンパイラが必要です。
Truffle Suiteは、イーサリアムでのブロックチェーン開発用に特別に作成されたツールのコレクションです。スイートには、次の3つのソフトウェアが含まれています。
このチュートリアルでは、Ethereumブロックチェーン、スマートコントラクトコンパイラ、通信用のJavaScriptライブラリなど、いくつかのノードパッケージとソフトウェアが必要です。
スマートコントラクトはイーサリアムブロックチェーンで実行されるため、展開とテストにスマートコントラクトが必要です。ライブチェーンにデプロイすることもできますが、ガス料金としてEtherが必要になります。それでは、ローカルチェーンを設定して、そこでテストを行いましょう。コードについて確信があり、アプリケーションを配布する準備ができたら、ライブチェーンにデプロイできます。
Ganacheは、コンピューターにインストールされ、ローカルホストで実行されるローカルチェーンです。TruffleSuiteのWebサイトからGanacheをダウンロードしてインストールします。
Ganacheがそれぞれ100ETHで10個のアカウントを提供したことがわかります。これらは偽のエーテルなので、興奮しないでください。また、チェーンは7545ポートの127.0.0.1で実行されています。これらのアカウントを使用して、このチェーンにスマートコントラクトを展開します。エーテルは私たちがガス料金を支払うのを助けます。
このプロジェクトにはNode.jsが必要なので、システムにインストールされていることを確認してください。Node.jsの公式ウェブサイトからダウンロードできます。
Web3.jsは、JavaScriptを介したイーサリアムブロックチェーンとの通信を可能にするJavaScriptライブラリです。開発に役立つ機能がたくさん組み込まれています。
npm
またはを使用してWeb3.jsをインストールできますyarn
。
npm install web3 -g
Truffleは、スマートコントラクト用のコンパイラを提供します。SolidityコードをGanacheブロックチェーンにデプロイできる機械可読コードに変換するために必要です。
次のコマンドを使用してTruffleをインストールします。
npm install truffle -g
スマートコントラクトを作成するには、最初に、すべてのSolidityファイルを保持するプロジェクトディレクトリを作成する必要があります。solidity
名前を付けて作成し、を使用してターミナルのディレクトリに移動しましょうcd solidity
。
現在、私たちのプロジェクトは空です。それを操作するには、ボイラープレートコードが必要です。たとえば、ReactでUIを作成する場合は、Reactをインストールする必要があります。
Truffleは、ボックスと呼ばれるいくつかのパッケージをすでに提供しています。これらのパッケージは、Truffle、Ganache、React、Web3、Reduxなどのさまざまなフレームワークのバンドルであり、Vue.js開発者向けのパッケージがあります。これらは一緒になって、クライアントUIからブロックチェーンスマートコントラクトまで、エンドツーエンドのアプリケーション開発を完了します。
この記事では、Truffleが提供するReactボックスを使用します。
Reactボックスをインストールするには、次のコマンドを実行します。
truffle unbox react
これにより、Web3.js、React、Ganache CLI、Truffle、およびEthereumがインストールされます。ある意味では、最初のステップでこれらすべてのユーティリティをインストールする必要はありませんでした。
このチュートリアルでは、ReactやブラウザーベースのUIには焦点を当てません。代わりに、スマートコントラクトを作成し、ターミナルのみで処理します。
プロジェクトのディレクトリ構造は次のようになります。
client
これは、アプリケーションのUIを作成できるReactプロジェクトフォルダーです。その中には、コンパイルされたスマートコントラクトをJSON形式で保持するフォルダー(client
/ src
/ )があります。contracts
これらのファイルは、スマートコントラクトをコンパイルするときに生成されます。これらには、ABI、バイトコード、およびその他の情報が含まれています。
上の画像から、2つのJSONファイルがあることがわかります。これは、Reactバンドルを箱から出したときに、Truffleがすでに2つのスマートコントラクトを提供していたためです。それらのいずれかを開くと、次のようなコードが見つかります。
{
"contractName": "SimpleStorage",
"abi": [
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "x",
"type": "uint256"
}
],
"name": "set",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "get",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
"metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"project:/contracts/SimpleStorage.sol\":\"SimpleStorage\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"project:/contracts/SimpleStorage.sol\":{\"keccak256\":\"0x512df1603c5f878921707d236bc53d974afe05b4d9de4b6094249bac5ab60efe\",\"urls\":[\"bzz-raw://0d6de97971b1c387f984fa7ea1d9ec10f8a63d68cc63bf8bd00d8c3a7c9e3ee1\",\"dweb:/ipfs/Qmbt92T34sHzedfJjDsvbisvLhRtghNwS6VW8tqrGkrqTD\"]}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5060c68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea265627a7a7231582044ccb2c2d46346d523107088f3e26a4c8a2ec3ec8b2e3a6edb1bc8574d5c5f5264736f6c63430005100032",
"deployedBytecode": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea265627a7a7231582044ccb2c2d46346d523107088f3e26a4c8a2ec3ec8b2e3a6edb1bc8574d5c5f5264736f6c63430005100032",
"sourceMap": "66:176:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66:176:1;;;;;;;",
"deployedSourceMap": "66:176:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66:176:1;;;;;;;;;;;;;;;;;;;;;;;;113:53;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;113:53:1;;;;;;;;;;;;;;;;;:::i;:::-;;170:70;;;:::i;:::-;;;;;;;;;;;;;;;;;;;113:53;160:1;147:10;:14;;;;113:53;:::o;170:70::-;206:4;225:10;;218:17;;170:70;:::o",
"source": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.21 <0.7.0;\n\ncontract SimpleStorage {\n uint storedData;\n\n function set(uint x) public {\n storedData = x;\n }\n\n function get() public view returns (uint) {\n return storedData;\n }\n}\n",
"sourcePath": "C:\\Users\\akash\\Desktop\\solidity\\contracts\\SimpleStorage.sol",
"ast": {
"absolutePath": "project:/contracts/SimpleStorage.sol",
"exportedSymbols": {
"SimpleStorage": [
59
]
},
"id": 60,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 38,
"literals": [
"solidity",
">=",
"0.4",
".21",
"<",
"0.7",
".0"
],
"nodeType": "PragmaDirective",
"src": "32:32:1"
},
{
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": true,
"id": 59,
"linearizedBaseContracts": [
59
],
"name": "SimpleStorage",
"nodeType": "ContractDefinition",
"nodes": [
{
"constant": false,
"id": 40,
"name": "storedData",
"nodeType": "VariableDeclaration",
"scope": 59,
"src": "93:15:1",
"stateVariable": true,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 39,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "93:4:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
},
{
"body": {
"id": 49,
"nodeType": "Block",
"src": "141:25:1",
"statements": [
{
"expression": {
"argumentTypes": null,
"id": 47,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftHandSide": {
"argumentTypes": null,
"id": 45,
"name": "storedData",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40,
"src": "147:10:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"nodeType": "Assignment",
"operator": "=",
"rightHandSide": {
"argumentTypes": null,
"id": 46,
"name": "x",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 42,
"src": "160:1:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"src": "147:14:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"id": 48,
"nodeType": "ExpressionStatement",
"src": "147:14:1"
}
]
},
"documentation": null,
"id": 50,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "set",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 43,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 42,
"name": "x",
"nodeType": "VariableDeclaration",
"scope": 50,
"src": "126:6:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 41,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "126:4:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "125:8:1"
},
"returnParameters": {
"id": 44,
"nodeType": "ParameterList",
"parameters": [],
"src": "141:0:1"
},
"scope": 59,
"src": "113:53:1",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
},
{
"body": {
"id": 57,
"nodeType": "Block",
"src": "212:28:1",
"statements": [
{
"expression": {
"argumentTypes": null,
"id": 55,
"name": "storedData",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40,
"src": "225:10:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"functionReturnParameters": 54,
"id": 56,
"nodeType": "Return",
"src": "218:17:1"
}
]
},
"documentation": null,
"id": 58,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "get",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 51,
"nodeType": "ParameterList",
"parameters": [],
"src": "182:2:1"
},
"returnParameters": {
"id": 54,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 53,
"name": "",
"nodeType": "VariableDeclaration",
"scope": 58,
"src": "206:4:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 52,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "206:4:1",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "205:6:1"
},
"scope": 59,
"src": "170:70:1",
"stateMutability": "view",
"superFunction": null,
"visibility": "public"
}
],
"scope": 60,
"src": "66:176:1"
}
],
"src": "32:211:1"
},
"legacyAST": {
"attributes": {
"absolutePath": "project:/contracts/SimpleStorage.sol",
"exportedSymbols": {
"SimpleStorage": [
59
]
}
},
"children": [
{
"attributes": {
"literals": [
"solidity",
">=",
"0.4",
".21",
"<",
"0.7",
".0"
]
},
"id": 38,
"name": "PragmaDirective",
"src": "32:32:1"
},
{
"attributes": {
"baseContracts": [
null
],
"contractDependencies": [
null
],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": true,
"linearizedBaseContracts": [
59
],
"name": "SimpleStorage",
"scope": 60
},
"children": [
{
"attributes": {
"constant": false,
"name": "storedData",
"scope": 59,
"stateVariable": true,
"storageLocation": "default",
"type": "uint256",
"value": null,
"visibility": "internal"
},
"children": [
{
"attributes": {
"name": "uint",
"type": "uint256"
},
"id": 39,
"name": "ElementaryTypeName",
"src": "93:4:1"
}
],
"id": 40,
"name": "VariableDeclaration",
"src": "93:15:1"
},
{
"attributes": {
"documentation": null,
"implemented": true,
"isConstructor": false,
"kind": "function",
"modifiers": [
null
],
"name": "set",
"scope": 59,
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
},
"children": [
{
"children": [
{
"attributes": {
"constant": false,
"name": "x",
"scope": 50,
"stateVariable": false,
"storageLocation": "default",
"type": "uint256",
"value": null,
"visibility": "internal"
},
"children": [
{
"attributes": {
"name": "uint",
"type": "uint256"
},
"id": 41,
"name": "ElementaryTypeName",
"src": "126:4:1"
}
],
"id": 42,
"name": "VariableDeclaration",
"src": "126:6:1"
}
],
"id": 43,
"name": "ParameterList",
"src": "125:8:1"
},
{
"attributes": {
"parameters": [
null
]
},
"children": [],
"id": 44,
"name": "ParameterList",
"src": "141:0:1"
},
{
"children": [
{
"children": [
{
"attributes": {
"argumentTypes": null,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"operator": "=",
"type": "uint256"
},
"children": [
{
"attributes": {
"argumentTypes": null,
"overloadedDeclarations": [
null
],
"referencedDeclaration": 40,
"type": "uint256",
"value": "storedData"
},
"id": 45,
"name": "Identifier",
"src": "147:10:1"
},
{
"attributes": {
"argumentTypes": null,
"overloadedDeclarations": [
null
],
"referencedDeclaration": 42,
"type": "uint256",
"value": "x"
},
"id": 46,
"name": "Identifier",
"src": "160:1:1"
}
],
"id": 47,
"name": "Assignment",
"src": "147:14:1"
}
],
"id": 48,
"name": "ExpressionStatement",
"src": "147:14:1"
}
],
"id": 49,
"name": "Block",
"src": "141:25:1"
}
],
"id": 50,
"name": "FunctionDefinition",
"src": "113:53:1"
},
{
"attributes": {
"documentation": null,
"implemented": true,
"isConstructor": false,
"kind": "function",
"modifiers": [
null
],
"name": "get",
"scope": 59,
"stateMutability": "view",
"superFunction": null,
"visibility": "public"
},
"children": [
{
"attributes": {
"parameters": [
null
]
},
"children": [],
"id": 51,
"name": "ParameterList",
"src": "182:2:1"
},
{
"children": [
{
"attributes": {
"constant": false,
"name": "",
"scope": 58,
"stateVariable": false,
"storageLocation": "default",
"type": "uint256",
"value": null,
"visibility": "internal"
},
"children": [
{
"attributes": {
"name": "uint",
"type": "uint256"
},
"id": 52,
"name": "ElementaryTypeName",
"src": "206:4:1"
}
],
"id": 53,
"name": "VariableDeclaration",
"src": "206:4:1"
}
],
"id": 54,
"name": "ParameterList",
"src": "205:6:1"
},
{
"children": [
{
"attributes": {
"functionReturnParameters": 54
},
"children": [
{
"attributes": {
"argumentTypes": null,
"overloadedDeclarations": [
null
],
"referencedDeclaration": 40,
"type": "uint256",
"value": "storedData"
},
"id": 55,
"name": "Identifier",
"src": "225:10:1"
}
],
"id": 56,
"name": "Return",
"src": "218:17:1"
}
],
"id": 57,
"name": "Block",
"src": "212:28:1"
}
],
"id": 58,
"name": "FunctionDefinition",
"src": "170:70:1"
}
],
"id": 59,
"name": "ContractDefinition",
"src": "66:176:1"
}
],
"id": 60,
"name": "SourceUnit",
"src": "32:211:1"
},
"compiler": {
"name": "solc",
"version": "0.5.16+commit.9c3226ce.Emscripten.clang"
},
"networks": {
"5777": {
"events": {},
"links": {},
"address": "0xc21DB75B9B17Cb43Cd983A16BaA6c73b314B1E8f",
"transactionHash": "0xada7b561df968c3d23485d25cbd22a66d1d4b76a86137dbf1bef858e816ff0c2"
}
},
"schemaVersion": "3.4.3",
"updatedAt": "2021-10-29T10:14:41.665Z",
"networkType": "ethereum",
"devdoc": {
"methods": {}
},
"userdoc": {
"methods": {}
}
}
上記の大規模なコードブロックには、ABI、バイトコード、ソースコード、およびその他の大量の情報が含まれています。ABIから、呼び出し可能な関数のリストを取得できます。このファイルには、ネットワークID、契約アドレス、トランザクションハッシュ、コンパイラの詳細、チェーンの詳細などのすべての情報が含まれています。
なぜこのファイルがUIディレクトリにあるのか疑問に思われるかもしれません。これは、Web3.jsが操作に使用するためです。このファイルにより、Web3.jsはチェーン上のスマートコントラクトを認識できます。また、ABIは関数のリストを取得するのに役立ちます。
contracts
Solidityファイルを保持するディレクトリです。ここにすべてのソースコードを配置しますmigrations
どのSolidityファイルをチェーンに移行する必要があるかをTruffleに通知するファイルですtest
テストファイルを作成するためのものですtruffle-config.js
Truffleのいくつかの構成設定が含まれています。内容は次のtruffle-config.js
とおりです。
const path = require("path");
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
contracts_build_directory: path.join(__dirname, "client/src/contracts"),
networks: {
develop: {
port: 8545
}
}
};
ご覧のとおり、client/src/contracts
コンパイルされたコードを保持するように設定されています。開発ネットワークはポート8545に設定されています。これは、このボックスがGanacheを実行しているポートです。
Ganacheをインストールした上部を見ると、7545ポートで実行されていたことがわかりますが、インストールされたGanacheで7545がすでに使用されているため、これは8545で実行されています。必要に応じて、このポートを7545に変更できます。トリュフは、ボックスで提供されるアカウントの代わりに、ガナッシュとインストールしたアカウントを使用します。私はそれを8545に保っています。
次に、コードを記述します。CRUD操作を行い、果物のリストを管理します。
基本的に、私たちのアプリケーションはさまざまな果物のリストを表示します。フルーツを追加、更新、削除できます。
以前にアプリを開発したことがある場合は、必ずおなじみの手順に従います。
それでは、Solidityでコードを書いてみましょう。
ディレクトリに新しいファイルを作成し、contracts
それを呼び出しますFruits.sol
。サポートしているライセンスとSolidityバージョンを示すことからファイルを開始します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
次に、すべてのコードを記述するスコープを宣言しcontract
ます。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
}
果物を保持する配列を作成します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
}
これはプライベート修飾子を持つ文字列配列です。つまり、コントラクトの外部からアクセスできないため、値を直接変更することはできません。
次に、新しい値を追加する関数を作成します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
}
addFruit
文字列をパラメータとして受け入れる、という関数を作成しましたfruitName
。これはパブリックとして宣言されているため、UIまたはターミナルから呼び出すことができます。関数本体では、値を配列にプッシュするだけです。
値を更新します。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
function updateFruit(uint fruitIndex, string memory newFruitName) public returns (bool) {
if(myFruits.length > fruitIndex){
myFruits[fruitIndex] = newFruitName;
return true;
}
return false;
}
}
updateFruitfruitIndex
2つの引数とを受け入れnewFruitName
、ブール値を返します。これは次のように機能します。インデックスが配列の範囲外の場合は、を返しますfalse
。それ以外の場合は、指定されたインデックスで新しく提供されたフルーツ名で配列の値を変更し、を返しtrue
ます。
次の手順は、削除機能を作成することです。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
function updateFruit(uint fruitIndex, string memory newFruitName) public returns (bool) {
if(myFruits.length > fruitIndex){
myFruits[fruitIndex] = newFruitName;
return true;
}
return false;
}
function deleteFruit(uint fruitIndex) public returns (bool) {
if(myFruits.length > fruitIndex){
for(uint i=fruitIndex; i < myFruits.length-1; i++){
myFruits[i] = myFruits[i+1];
}
myFruits.pop();
return true;
}
return false;
}
}
ここでは、インデックスの範囲外条件をチェックしてから、値を指定されたインデックスの次の値に置き換えることで配列を更新しています。このように、提供されたインデックスの値は失われます。最後に、最後の値を取り出して返しtrue
ます。
最後のステップは、配列を返すことです。配列のすべての値を読み取るには:
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract Fruits {
string[] myFruits;
function addFruit(string memory fruitName) public {
myFruits.push(fruitName);
}
function updateFruit(uint fruitIndex, string memory newFruitName) public returns (bool) {
if(myFruits.length > fruitIndex){
myFruits[fruitIndex] = newFruitName;
return true;
}
return false;
}
function deleteFruit(uint fruitIndex) public returns (bool) {
if(myFruits.length > fruitIndex){
for(uint i=fruitIndex; i < myFruits.length-1; i++){
myFruits[i] = myFruits[i+1];
}
myFruits.pop();
return true;
}
return false;
}
function getFruits() public view returns (string[] memory) {
return myFruits;
}
}
スマートコントラクトのコーディングが完了したので、Truffleを使用してコンパイルします。ただし、最初に移行ファイルを作成して、これをチェーンに移行することをTruffleに示す必要があります。
フォルダをチェックインすると、migration
2つのJavaScriptファイルが見つかります。
それぞれ番号で始まるので、3番目のファイルは3で始まります。コードはほぼ標準です。それ2_deploy_contracts
は:
var SimpleStorage = artifacts.require("./SimpleStorage.sol");
module.exports = function(deployer) {
deployer.deploy(SimpleStorage);
};
移行ファイルを追加しましょう3_fruits_contracts
:
var FruitsList = artifacts.require("./Fruits.sol");
module.exports = function(deployer) {
deployer.deploy(FruitsList);
};
フルーツコントラクトをコンパイルして移行する準備が整いました。ターミナルに移動し、以下を実行します。
> truffle develop
このコマンドは、トリュフコンソールを起動します。また、チェーンネットワーク、アカウント、ニーモニックなどの情報も表示されます。
Ganacheはデフォルトで10個のアカウントを提供します。彼らはあなたのために異なります。これらの秘密鍵は、この記事のすべての訪問者に表示されるため、ライブチェーンでは使用しないでください。つまり、誰でもこれらのアカウントにアクセスできます。
次に、次のコマンドを使用してコントラクトをコンパイルします。
> compile
ファイルが作成されてclient/src/contracts
いるかどうかを確認できます。Fruits.json
次のコマンドを使用して、コンパイルされたファイルをチェーンに移行できます。
> migrate
これにより、3つのスマートコントラクトすべてがチェーンに移行されます。
最後に、私たちのアプリケーションはイーサリアムチェーン上にあります。ガス料金に0.00153イーサを費やし、トランザクションが最初のアカウントから発生したことがわかります。デフォルトでは、常に最初のアカウントが使用されます。さまざまな操作ができるようになりました。
Web3.jsを使用して、さまざまな値に反応して書き込むことができます。まず、コントラクトのインスタンスを変数に格納しましょう。
let instance = await Fruits.deployed()
await
ブロックチェーン内のすべてが非同期であり、promiseを返すため、使用しています。
次に、このインスタンスを使用して配列を取得します。
> let fruits = instance.getFruits()
undefined
> fruits
[]
現在、fruits配列には値がないため、空の配列が返されます。
いくつかの果物を追加しましょう:
> let result = await instance.addFruit("Apple")
undefined
はresult
トランザクションを保持します。すべての読み取り操作は無料ですが、ブロックチェーンの変更につながる操作にはガス料金がかかることを忘れないでください。この操作は、配列に値を追加し、データを変更します。したがって、トランザクションとして記録されます。
これで、配列を再度読み取って内容を確認できます。
リストにさらにいくつかの果物を追加しましょう。
> await instance.addFruit("Mango")
> await instance.addFruit("Banana")
> await instance.addFruit("Orange")
> await instance.addFruit("Guava")
> await instance.addFruit("Pineapple")
> await instance.addFruit("Water Melon")
> await instance.addFruit("Papaya")
> await instance.addFruit("Strawberry")
これらすべての操作にはEtherのコストがかかることを忘れないでください。一度に複数の果物の値を受け入れるための関数をコントラクトに作成することで、手数料を節約できます。
今すぐ配列を読んでください:
上の画像で、「Guava」のつづりを「Guavva」と間違えたことがわかります。updateFruit
関数を使って修正しましょう。インデックスと新しい値を受け入れます。インデックスは4です。
> await instance.updateFruit(4, "Guava")
今すぐ配列を読んでみましょう:
スペルは正常に修正されました。
最後の操作は、値を削除することです。
> await instance.deleteFruit(4)
値を読み取ります。
ご覧のとおり、「Guava」アイテムはリストから削除されています。
スマートコントラクトを作成してブロックチェーンにデプロイするのは楽しくて強力です。これは、従来のプログラミングからの新しい視点を提供します。これらの手法を使用して、オンライン投票、デジタルバンク、ウォレット、オークションなど、あらゆる種類のアプリケーションを作成できます。
このチュートリアルでは、スマートコントラクトを作成してローカルチェーンにデプロイする方法を示しました。これで、イーサリアムのテストネットワークにデプロイしてみることができます。
一度に複数のフルーツを追加してトランザクションコストを節約するなど、より多くの機能を導入することで、現在のアプリを改善できます。また、ユニークな果物のみを許可するようにチェックを入れることもできます。配列の代わりに、マッピングを使用してみてください。
ハッピーコーディング!