スマートコントラクトを作成するためのプログラミング言語であるSolidityの変数について記載します。
Solidityの変数
Solidity は静的に型付けされたプログラミング言語です。
よって、変数の宣言時に状態(値が入っているか等)または変数の型を指定する必要があります。
宣言された変数には、常にその型に基づいたデフォルトの値が定義されており、”undefined”または”null”の概念はありません。
Solidity 変数名の命名規則
Solidity で変数に名前を付けるときは、次の規則に従う必要があります。
- Solidityの変数名は、数字 (0 ~ 9) で始めることは出来ません。文字またはアンダースコア文字で始まる必要があります。たとえば、0xbrokersは頭文字が0のため数値です。変数としては無効ですが、_0xbrokerは有効な変数名として定義できます。
- Solidity 変数名は大文字と小文字が区別されます。たとえば、_0xBrokers と _0xBROKERS は 2 つの異なる変数として判断されます。
- Solidity の予約済みキーワードを変数名として使用出来ません。
Solidityで事前に定義されている予約語の一覧はこちらを参照ください。
3つ種類の変数
Solidityには主に下記3つの種類の変数が用意されています。
- ローカル変数
- グローバル変数
- ステート変数
Local変数(ローカル変数)
値が定義されている関数内でのみ使用でき、関数が実行されるまで値が存在する変数。
ローカル変数は通常、一時的に変数に値を格納するために使用することを想定しています。
下記のSampleLocalコントラクトでは、ローカル変数aとbを宣言し、2 つのローカル変数の合計をローカル変数のresultへ格納し、resultを返すgetファンクション(関数)を定義しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleLocal { uint testData; // State変数(状態変数) constructor() public { testData = 10; } function get() public view returns(uint){ uint a = 1; // ローカル変数 uint b = 2; // ローカル変数 uint result = a + b; // ローカル変数 return result; //ローカル変数で定義されたresultを戻り値とする } } |
Global変数(グローバル変数)
Solidityではブロックチェーンに関する情報を取得するために全てのスコープからアクセスできるグローバル変数を用意しています。
Solidityのグローバル変数は下記の通り。
名前 | 戻り値 |
---|---|
blockhash(uint blockNumber)
returns (bytes32) |
指定されたブロックのハッシュ – 現在のブロックを除く、最新の 256 個のブロックに対してのみ有効 |
block.coinbase(address payable) | 現在のブロックのマイナーのアドレス |
block.difficulty(uint) | 現在のブロック難易度 |
block.gaslimit(uint) | 現在のブロックガスリミット |
block.number(uint) | 現在のブロックナンバー |
block.timestamp(uint) | 現在のunixのタイムスタンプ(秒) |
gasleft() returns (uint256) | 残りのガス |
msg.data(bytes calldata) | コールデータ |
msg.sender(address payable) | メッセージの送信者 (現在の発信者) |
msg.sig(bytes4) | calldataの最初の 4 バイト(ファンクションの識別子) |
msg.value(uint) | メッセージとともに送信された wei の量 |
now(uint) | 現在のブロックのタイムスタンプ(block.timestampのエイリアス) |
tx.gasprice(uint) | トランザクションのガス代 |
tx.origin(address payable) | トランザクションの送信者 |
下記のSampleGlobalコントラクトでは、グローバル変数であるmsg.senderを使用して、コントラクトを展開している人物のアドレスにアクセスするコントラクトを定義しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; // Creating a contract contract SampleGlobal { // State変数を定義 address public admin; // State変数を利用したコンストラクタを定義 constructor() public { // グローバル変数のmsg.senderを使用して個のコントラクトをDeployしている人物を確認 admin = msg.sender; } } |
State変数(ステート変数)
ステート変数は、日本語では状態変数とも呼ばれています。
ステート変数で定義された変数およびその変数の値はコントラクトのストレージに永続的に保存される仕様となっています。
イーサリアムであれば、ステート変数で定義された値はブロックチェーンの台帳へ保存をされることを意味します。
下記のSampleStateコントラクトの例ではvauleをState変数(状態変数)として定義しています。
1 2 3 4 5 6 7 8 9 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleState { uint value; // これがState変数(状態変数) constructor() public { value = 10; // 定義したState変数に10を代入。 } } |
ステート変数の4つのスコープ
ローカル変数のスコープは、それらが定義されている関数で利用される場合に限定されていますが、このState変数(状態変数)には4種類のスコープを持つことができる仕様となっています。
Public
Publicステート変数には、メッセージを介してだけでなく内部的にもアクセスできる仕様となっています。
public 状態変数の場合、自動 getter 関数が生成されます。
下記ソースコードは、publicステート変数を定義したコントラクトです。
publicステート変数であるdataのデフォルト値は10、getファンクションを呼び出した場合、100を設定するコントラクトなっています。publicなので外部からも呼び出しが可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //Publid State変数を定義し、デフォルト値として10を定義。 uint public data = 10; //publicステート変数dataに100を設定するgetファンクションを定義 function get() public returns (uint) { data = 100; return data; } } |
下記は外部コントラクトのanotherContractからSampleDataコントラクトのpublicステート変数を取得するコードです。
publicステート変数は外部コントラクトからのアクセスも可能な変数です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //Publid State変数を定義し、デフォルト値として10を定義。 uint public data = 10; } //外部コントラクトからSampleDataコントラクトのpublicステート変数dataを呼び出す contract anotherContract { SampleData SampleData2 = new SampleData(); function get() public view returns (uint) { return SampleData2.data(); //外部からのアクセス } } |
Internal
Internalステート変数は、現在のコントラクトまたはそのコントラクトから派生したコントラクトから内部的にのみアクセスできる仕様となっています。
SolidityではState変数にスコープ範囲を明記しなかった場合、このInternalがデフォルトで設定される仕様となっています。
下記例では、インターナルState変数としてiDataを定義し、getファンションの中でpublic変数のdataにiDataを設定するスマートコントラクトを記載しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //Publid State変数を定義。 uint public data; //internal State変数を定義し、デフォルト値として10を定義。 uint internal iData = 10; //publicステート変数dataにinternalステート変数のiDataを設定するgetファンクションを定義 function get() public returns (uint) { data = iData; //内部アクセス return data; } } |
下記は外部コントラクトからSampleDataコントラクトのinternalステート変数であるdataにアクセスしようとしているソースコードです。
このソースコードではmember data not found or not visibleというコンパイルエラーが発生し,Solidityをコンパイルすることが出来ません。
外部コントラクトからinternalステート変数にアクセスしようとしているためです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //internal State変数を定義し、デフォルト値として10を定義。 uint internal data = 10; } //外部コントラクトからSampleDataコントラクトのinternalステート変数dataを呼び出す contract anotherContract { SampleData SampleData2 = new SampleData(); function get() public view returns (uint) { return SampleData2.data(); //外部からのアクセス } } |
Private
Privateステート変数は、コントラクト内でのみアクセスできます。
プライベート関数は、他の関数に継承できない唯一の関数でもあります。
下記例では、同一のコントラクト内でprivateステート変数にアクセスしているスマートコントラクトとなります。
基本的に同じコントラクト内で利用する場合は、Internalステート変数と同じ処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //Publid State変数を定義。 uint public data; //Private State変数を定義し、デフォルト値として10を定義。 uint private pData = 10; //publicステート変数dataにPrivateステート変数のpDataを設定するgetファンクションを定義 function get() public returns (uint) { data = pData; //内部アクセス return data; } } |
下記は外部コントラクトからSampleDataコントラクトのprivateステート変数であるdataにアクセスしようとしているソースコードです。
このソースコードではmember data not found or not visibleというコンパイルエラーが発生し,Solidityをコンパイルすることが出来ません。
挙動はInternalステート変数と全く同じになりますが、外部コントラクトからprivateステート変数にアクセスしようとしているためコンパイルエラーとなっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //private State変数を定義し、デフォルト値として10を定義。 uint private data = 10; } //外部コントラクトからSampleDataコントラクトのprivateステート変数dataを呼び出す contract anotherContract { SampleData SampleData2 = new SampleData(); function get() public view returns (uint) { return SampleData2.data(); //外部からのアクセス } } |
InternalとPrivateの違い
InternalとPrivateの違いですが、クラスを継承してアクセスをした場合に違いが出てきます。
- Internal:アクセス可能
- Private:アクセス不可能
下記例では、SampleDataを継承したSampleData2のコントラクトから継承元のinternalステート変数を呼び出しています。internalステート変数の場合は問題なく利用可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //internal State変数を定義し、デフォルト値として10を定義。 uint internal data = 10; } contract SampleData2 is SampleData { function get() public view returns(uint){ // SampleDataコントラクトのdataを参照し、ローカル変数resultに格納 uint result = data; return result; } } |
一方下記の例では、privateステート変数で宣言しているため、継承先からもアクセスが出来ない形となります。
declaration error undeclared identifierというSolidityのコンパイルエラーが発生してコンパイルできない形となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract SampleData { //private State変数を定義し、デフォルト値として10を定義。 uint private data = 10; } contract SampleData2 is SampleData { function get() public view returns(uint){ // SampleDataコントラクトのdataを参照し、ローカル変数resultに格納 uint result = data; return result; } } |
最後に
今回紹介したSolidityの仕様やコードをRemix IDEやHardhatで実際に実行やテストをして確認してみましょう。
実際に動かしたり、テストすることで理解が深まるかと思います。
hardhatのインストール手順
HardhatでスマートコントラクトのDeploy手順