教材の内容に関係のない質問や教材とは異なる環境・バージョンで進めている場合のエラーなど、教材に関係しない質問は推奨していないため回答できない場合がございます。
その場合、teratailなどの外部サイトを利用して質問することをおすすめします。教材の誤字脱字や追記・改善の要望は「文章の間違いや改善点の指摘」からお願いします。
名前とEmailアドレスを記録する名簿を作りましょう。mapping
によるデータ構造と関数のアクセス制限について学びます。
javascript123456789101112131415161718192021222324252627282930313233343536373839404142 Copied!pragma solidity ^0.4.25;
contract addressBook {
// ①コントラクトオーナーのアドレス
address private owner;
uint private numUser; // 登録件数
// ②登録情報を保存するデータ構造体
struct userInfo {
string name; // 名前
string email; // Emailアドレス
}
mapping(uint => userInfo) private accounts;
// ③コンストラクタ
// コントラクトを公開した際に実行されます
constructor() public {
owner = msg.sender; // コントラクトを公開したアドレスをオーナーに指定する
numUser = 0; // 登録数の初期化
}
// ④アクセス制限の実装
modifier onlyOwner {
// コントラクトを呼び出したアドレスがオーナーと一致するか確認する
// 一致しない場合は処理を止める
require(msg.sender == owner);
_; // modifierの末尾に必要
}
// ⑤modifierを関数に付与する
// ユーザー情報を登録する関数
function setInfo(string _name, string _email) public onlyOwner {
accounts[numUser].name = _name;
accounts[numUser].email = _email;
numUser++;
}
// ユーザー情報を取得する関数
function getInfo(uint _numUser) view public onlyOwner returns(string, string) {
return (accounts[_numUser].name, accounts[_numUser].email);
}
}
javascript1 Copied!address private owner;
Ethereumではアカウントやスマートコントラクトをアドレスと呼ばれる固有の文字列で識別します。
Copied!アドレスの例
0xca35b7d915458ef540ade6068dfe2f44e8fa733c
Ethアドレスを保存するための変数はaddress
型で宣言します。
javascript12345 Copied!struct userInfo {
string name; // 名前
string email; // Emailアドレス
}
mapping(uint => userInfo) private accounts;
まずは名前とEmailアドレスをメンバに持つuserInfo
という構造体を宣言します。mapping
はkeyと値を組み合わせたデータ構造です。ここではuint
型のkeyとuserInfo
型の値を持つaccounts
というデータ構造体を宣言しています。accounts
には例えば以下の様にデータを保存します。
Copied!accounts[0].name = "kappa";
accounts[0].email = "kappa@uma.com";
accounts[1].name = "kamonohashi";
accounts[1].email = "kamo@uma.com";
accounts[2].name = "baku";
accounts[2].email = "baku@uma.com";
key | 値 | name | |
---|---|---|---|
0 | accounts[0] | kappa | kappa@uma.com |
1 | accounts[1] | kamonohashi | kamo@uma.com |
2 | accounts[2] | baku | baku@uma.com |
javascript1234 Copied!constructor() public {
owner = msg.sender; // コントラクトを公開したアドレスをオーナーに指定する
numUser = 0; // 登録件数の初期化
}
コンストラクタはスマートコントラクトをデプロイした際に自動的に呼び出される関数です。msg.sender
は関数を呼び出したアカウントのアドレスを取得します。コンストラクタの中ではmsg.sender
はスマートコントラクトをデプロイしたアドレスを示します。登録件数の初期化もコンストラクタで行っています。
javascript1234 Copied!modifier onlyOwner {
require(msg.sender == owner);
_; // modifierの末尾に必要
}
modifier
は関数に付与する修飾子を定義します。modifier
が付与された関数は,関数が呼び出されるとmodifier
の処理が先に実行されます。require
は条件を満たさなかった場合,処理を止めます。ここでは関数の呼び出したEthアドレスとスマートコントラクトをデプロイしたEthアドレスowner
が一致しなければ後の処理を行いません。修飾子はmodifier
によって自由に定義できますが,代表的な予約語として以下があります。
Copied!・payable
送金を伴う関数に必要な修飾子です。payableを付与しない関数はEthの授受ができないため,誤った送金を防ぐことができます。
・view
変数の変化を伴わない関数に付与する修飾子です。
・pure
変数の変化を伴わないことに加え,変数の参照もしない関数に付与する修飾子です。
・event
トランザクションへログを出力する際に使用します。
javascript1234567891011 Copied!// ユーザー情報を登録する関数
function setInfo(string _name, string _email) public onlyOwner {
accounts[numUser].name = _name;
accounts[numUser].email = _email;
numUser++;
}
// ユーザー情報を取得する関数
function getInfo(uint _numUser) view public onlyOwner returns(string, string) {
return (accounts[_numUser].name, accounts[_numUser].email);
}
setInfo
はaccounts
に名前とEmailアドレスを登録するための関数です。情報が登録される度にnumUser
が1だけ増加します。getInfo
はaccounts
のゲッターです。accounts
のkeyを指定するためにuint
型の引数_numUser
を持ちます。これらの関数はonlyOwner
が付与されているため,スマートコントラクトをデプロイしたアドレスからのみ実行できます。
1.1と同じやり方で名簿スマートコントラクトをデプロイし,いくつか名前とEmailアドレスを入力してみましょう。
次にアカウントを変更してコントラクトを実行してみて下さい。modifierが働き処理が実行されないことが確認できます。
お疲れさまでした!次の章ではいよいよフリマアプリのスマートコントラクトを実装して行きます。