Solidity-quick-guide
堅牢性-概要
Solidityは、スマートコントラクトを実装するためのコントラクト指向の高レベルプログラミング言語です。 Solidityは、C ++、Python、およびJavaScriptの影響を強く受けており、Ethereum Virtual Machine(EVM)をターゲットとするように設計されています。
Solidityは静的に型付けされ、継承、ライブラリ、複雑なユーザー定義型プログラミング言語をサポートします。
Solidityを使用して、投票、クラウドファンディング、ブラインドオークション、マルチ署名ウォレットなどの用途の契約を作成できます。
イーサリアムとは何ですか?
イーサリアムは分散型です。 スマートコントラクトを実行するブロックチェーンプラットフォーム ダウンタイム、検閲、詐欺、またはサードパーティの干渉の可能性なしにプログラムされたとおりに実行されるアプリケーション。
イーサリアム仮想マシン(EVM)
EVMとも呼ばれるEthereum Virtual Machineは、Ethereumのスマートコントラクトのランタイム環境です。 Ethereum Virtual Machineは、セキュリティの提供と世界中のコンピューターによる信頼できないコードの実行に焦点を当てています。
EVMは、サービス拒否攻撃の防止に特化しており、プログラムが相互の状態にアクセスできないようにし、潜在的な干渉なしに通信を確立できるようにします。
Ethereum Virtual Machineは、Ethereumに基づくスマートコントラクトのランタイム環境として機能するように設計されています。
スマートコントラクトとは何ですか?
スマートコントラクトは、契約の交渉または履行をデジタル的に促進、検証、または実施することを目的としたコンピュータープロトコルです。 スマートコントラクトにより、第三者なしで信頼できるトランザクションを実行できます。 これらのトランザクションは追跡可能であり、元に戻すことはできません。
スマートコントラクトの概念は、1994年にNick Szaboによって最初に提案されました。 Szaboは、デジタル通貨の基礎を築くことで知られる法学者および暗号学者です。
今すぐスマートコントラクトを理解していなくても大丈夫です。詳細については後で説明します。
Solidity-環境設定
この章では、CentOSマシンでSolidityコンパイラをセットアップする方法について説明します。 Linuxマシンをお持ちでない場合は、小規模な契約やSolidityをすばやく学習するために、オンラインコンパイラを使用できます。
方法1-npm/Node.js
これは、CentoSマシンにSolidityコンパイラをインストールする最も速い方法です。 Solidity Compilerをインストールする手順は次のとおりです-
Node.jsをインストールする
まず、CentOSマシンでnode.jsが使用可能であることを確認してください。 利用できない場合は、次のコマンドを使用してインストールします-
# First install epel-release
$sudo yum install epel-release
# Now install nodejs
$sudo yum install nodejs
# Next install npm (Nodejs Package Manager )
$sudo yum install npm
# Finally verify installation
$npm --version
すべてがインストールされている場合、次のような出力が表示されます-
3.10.10
solcをインストールする
Node.jsパッケージマネージャーをインストールしたら、以下のようにSolidityコンパイラーのインストールに進むことができます-
$sudonpm install -g solc
上記のコマンドは、solcjsプログラムをインストールし、システム全体でグローバルに利用できるようにします。 これで、次のコマンドを発行してSolidityコンパイラをテストできます-
$solcjs-version
すべてがうまくいけば、これは次のように何かを印刷します-
0.5.2+commit.1df8f40c.Emscripten.clang
これで、標準のSolidityコンパイラよりも機能が少ないsolcjsを使用する準備が整いましたが、出発点として適切です。
方法2-Dockerイメージ
Dockerイメージを取得し、それを使用してSolidityプログラミングを開始できます。 以下は簡単な手順です。 以下は、Solidity Dockerイメージをプルするコマンドです。
$docker pull ethereum/solc:stable
Dockerイメージがダウンロードされると、次のコマンドを使用して確認できます。
$docker run ethereum/solc:stable-version
これは次のように何かを印刷します-
$ docker run ethereum/solc:stable -version
solc, the solidity compiler commandlineinterfaceVersion: 0.5.2+commit.1df8f40c.Linux.g++
方法3:バイナリパッケージのインストール
Linuxマシンに本格的なコンパイラをインストールする場合は、公式ウェブサイトSolidity Compilerのインストールを確認してください。
堅牢性-基本的な構文
Solidityソースファイルには、任意の数のコントラクト定義、インポートディレクティブ、およびプラグマディレクティブを含めることができます。
Solidityのシンプルなソースファイルから始めましょう。 以下は、Solidityファイルの例です-
pragma solidity >=0.4.0 <0.6.0;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
プラグマ
最初の行はプラグマディレクティブで、ソースコードがSolidityバージョン0.4.0またはバージョン0.6.0を含まないが機能を分割しない新しいバージョン用に記述されていることを示します。
プラグマディレクティブは常にソースファイルに対してローカルであり、別のファイルをインポートする場合、そのファイルのプラグマはインポートファイルに自動的に適用されません。
したがって、バージョン0.4.0より前にコンパイルされず、バージョン0.5.0以降のコンパイラでも動作しないファイルのプラグマは、次のように記述されます-
pragma solidity ^0.4.0;
ここでは、^を使用して2番目の条件が追加されます。
契約する
Solidityコントラクトは、Ethereumblockchainの特定のアドレスにあるコード(その機能)とデータ(その状態)のコレクションです。
行uintstoredDataは、uint型のstoredDataという状態変数を宣言し、関数setおよびgetを使用して変数の値を変更または取得できます。
ファイルをインポートする
上記の例にはimportステートメントはありませんが、SolidityはJavaScriptで利用可能なimportステートメントに非常に類似したimportステートメントをサポートしています。
次のステートメントは、「ファイル名」からすべてのグローバルシンボルをインポートします。
import "filename";
次の例では、メンバーがすべて「filename」のグローバルシンボルである新しいグローバルシンボルsymbolNameを作成します。
import * as symbolName from "filename";
現在のファイルと同じディレクトリからファイルxをインポートするには、import "./x" as x;を使用します。 import "x"をxとして使用する場合;代わりに、グローバルな「インクルードディレクトリ」で別のファイルを参照できます。
予約済みキーワード
以下はSolidityの予約キーワードです-
abstract | after | alias | apply |
auto | case | catch | copyof |
default | define | final | immutable |
implements | in | inline | let |
macro | match | mutable | null |
of | override | partial | promise |
reference | relocatable | sealed | sizeof |
static | supports | switch | try |
typedef | typeof | unchecked |
堅牢性-最初のアプリケーション
Remix IDEを使用して、Solidity Codeベースをコンパイルおよび実行します。
- ステップ1 *-Remix IDEコードセクションで指定されたコードをコピーします。
例
pragma solidity ^0.5.0;
contract SolidityTest {
constructor() public{
}
function getResult() public view returns(uint){
uint a = 1;
uint b = 2;
uint result = a + b;
return result;
}
}
- ステップ2 *-[コンパイル]タブで、[コンパイルの開始]ボタンをクリックします。
- ステップ3 *-[実行]タブで、[展開]ボタンをクリックします。
ステップ4 *-[実行]タブで、ドロップダウンで[ *0でのソリッドテストを選択…] を選択します。
ステップ5 *- *getResult ボタンをクリックして結果を表示します。
出力
0: uint256: 3
堅牢性-コメント
Solidityは、CスタイルとC ++スタイルの両方のコメントをサポートしています。
//と行末の間のテキストはコメントとして扱われ、Solidity Compilerによって無視されます。 *文字/ と*/の間のテキストはコメントとして扱われます。 これは複数行にわたる場合があります。
例
次の例は、Solidityでコメントを使用する方法を示しています。
function getResult() public view returns(uint){
//This is a comment. It is similar to comments in C++
/*
*This is a multi-line comment in solidity
* It is very similar to comments in C Programming
*/
uint a = 1;
uint b = 2;
uint result = a + b;
return result;
}
堅牢性-タイプ
任意の言語でプログラムを作成する際、さまざまな変数を使用してさまざまな情報を保存する必要があります。 変数は、値を保存するために予約されたメモリの場所に他なりません。 これは、変数を作成するときに、メモリ内にスペースを確保することを意味します。
文字、ワイド文字、整数、浮動小数点、二重浮動小数点、ブールなどのさまざまなデータ型の情報を保存することができます。 変数のデータ型に基づいて、オペレーティングシステムはメモリを割り当て、予約メモリに保存できるものを決定します。
値タイプ
Solidityは、豊富な品揃えの組み込みおよびユーザー定義のデータ型をプログラマに提供します。 次の表は、7つの基本的なC ++データ型を示しています-
Type | Keyword | Values |
---|---|---|
Boolean | bool | true/false |
Integer | int/uint | Signed and unsigned integers of varying sizes. |
Integer | int8 to int256 | Signed int from 8 bits to 256 bits. int256 is same as int. |
Integer | uint8 to uint256 | Unsigned int from 8 bits to 256 bits. uint256 is same as uint. |
Fixed Point Numbers | fixed/unfixed | Signed and unsigned fixed point numbers of varying sizes. |
Fixed Point Numbers | fixed/unfixed | Signed and unsigned fixed point numbers of varying sizes. |
Fixed Point Numbers | fixedMxN | Signed fixed point number where M represents number of bits taken by type and N represents the decimal points. M should be divisible by 8 and goes from 8 to 256. N can be from 0 to 80. fixed is same as fixed128x18. |
Fixed Point Numbers | ufixedMxN | Unsigned fixed point number where M represents number of bits taken by type and N represents the decimal points. M should be divisible by 8 and goes from 8 to 256. N can be from 0 to 80. ufixed is same as ufixed128x18. |
住所
addressは、Ethereumアドレスのサイズを表す20バイトの値を保持します。 アドレスは、.balanceメソッドを使用して残高を取得するために使用でき、.transferメソッドを使用して残高を別のアドレスに転送するために使用できます。
address x = 0x212;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
堅牢性-変数
Solidityは3種類の変数をサポートしています。
- 状態変数-値が契約ストレージに永続的に保存される変数。
- ローカル変数-関数が実行されるまで値が存在する変数。
- グローバル変数-ブロックチェーンに関する情報を取得するために使用されるグローバル名前空間に特別な変数が存在します。
Solidityは静的に型指定された言語です。つまり、宣言中に状態またはローカル変数の型を指定する必要があります。 宣言された各変数には、その型に基づいたデフォルト値が常にあります。 「未定義」または「ヌル」の概念はありません。
状態変数
値が契約ストレージに永続的に保存される変数。
pragma solidity ^0.5.0;
contract SolidityTest {
uint storedData; //State variable
constructor() public {
storedData = 10; //Using State variable
}
}
ローカル変数
値が定義されている関数内でのみ使用可能な値を持つ変数。 関数パラメーターは、常にその関数に対してローカルです。
pragma solidity ^0.5.0;
contract SolidityTest {
uint storedData;//State variable
constructor() public {
storedData = 10;
}
function getResult() public view returns(uint){
uint a = 1;//local variable
uint b = 2;
uint result = a + b;
return result;//access the local variable
}
}
例
pragma solidity ^0.5.0;
contract SolidityTest {
uint storedData;//State variable
constructor() public {
storedData = 10;
}
function getResult() public view returns(uint){
uint a = 1;//local variable
uint b = 2;
uint result = a + b;
return storedData;//access the state variable
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: uint256: 10
グローバル変数
これらはグローバルワークスペースに存在する特別な変数であり、ブロックチェーンとトランザクションプロパティに関する情報を提供します。
Name | Returns |
---|---|
blockhash(uint blockNumber) returns (bytes32) | Hash of the given block - only works for 256 most recent, excluding current, blocks |
block.coinbase (address payable) | Current block miner’s address |
block.difficulty (uint) | Current block difficulty |
block.gaslimit (uint) | Current block gaslimit |
block.number (uint) | Current block number |
block.timestamp (uint) | Current block timestamp as seconds since unix epoch |
gasleft() returns (uint256) | Remaining gas |
msg.data (bytes calldata) | Complete calldata |
msg.sender (address payable) | Sender of the message (current caller) |
msg.sig (bytes4) | First four bytes of the calldata (function identifier) |
msg.value (uint) | Number of wei sent with the message |
now (uint) | Current block timestamp |
tx.gasprice (uint) | Gas price of the transaction |
tx.origin (address payable) | Sender of the transaction |
ソリッド変数名
Solidityで変数に名前を付けるときは、次のルールに留意してください。
- Solidityの予約済みキーワードを変数名として使用しないでください。 これらのキーワードについては、次のセクションで説明します。 たとえば、ブレークまたはブール変数名は無効です。
- Solidity変数名は数字(0-9)で始まってはなりません。 文字またはアンダースコア文字で始まる必要があります。 たとえば、123testは無効な変数名ですが、_123testは有効な変数名です。
- Solidity変数名では大文字と小文字が区別されます。 たとえば、名前と名前は2つの異なる変数です。
堅牢性-可変範囲
ローカル変数のスコープは、それらが定義されている関数に制限されますが、状態変数は3つのタイプのスコープを持つことができます。
- パブリック-パブリック状態変数は、メッセージを介してだけでなく内部的にアクセスできます。 パブリック状態変数の場合、自動取得関数が生成されます。
- Internal -内部状態変数は、これを使用せずに現在のコントラクトまたはそれに由来するコントラクトから内部的にのみアクセスできます。
- プライベート-プライベート状態変数は、派生コントラクトではなく定義されている現在のコントラクトからのみ内部的にアクセスできます。
例
pragma solidity ^0.5.0;
contract C {
uint public data = 30;
uint internal iData= 10;
function x() public returns (uint) {
data = 3;//internal access
return data;
}
}
contract Caller {
C c = new C();
function f() public view returns (uint) {
return c.data();//external access
}
}
contract D is C {
function y() public returns (uint) {
iData = 3;//internal access
return iData;
}
function getResult() public view returns(uint){
uint a = 1;//local variable
uint b = 2;
uint result = a + b;
return storedData;//access the state variable
}
}
堅牢性-オペレーター
オペレーターとは?
単純な式 4 + 5は9 に等しいとします。 ここで、4と5は*オペランド*と呼ばれ、「+」は*演算子*と呼ばれます。 Solidityは、次のタイプの演算子をサポートしています。
- 算術演算子
- 比較演算子
- 論理(またはリレーショナル)演算子
- 割り当て演算子 *条件付き(または3項)演算子
すべての演算子を1つずつ見てみましょう。
算術演算子
Solidityは次の算術演算子をサポートしています-
変数Aが10を保持し、変数Bが20を保持すると仮定します-
link:/solidity/solidity_arithmetic_operators [例を表示]
Sr.No. | Operator & Description |
---|---|
1 |
2つのオペランドを追加します 例: A + Bは30を与える |
2 |
最初のオペランドから2番目のオペランドを減算します 例: A-Bは-10を与える |
3 |
両方のオペランドを乗算します 例: *A Bは200を与える |
4 |
/(Division) 分子を分母で除算する
|
5 |
整数除算の剰余を出力します
|
6 |
整数値を1つ増やします 例: A ++は11 |
7 |
整数値を1減らします
|
比較演算子
Solidityは以下の比較演算子をサポートしています-
変数Aが10を保持し、変数Bが20を保持すると仮定します-
リンク:/solidity/solidity_comparison_operators [例を表示]
Sr.No. | Operator & Description |
---|---|
1 |
2つのオペランドの値が等しいかどうかを確認し、等しい場合は条件が真になります。 例:(A == B)は正しくありません。 |
2 |
!= (Not Equal) 2つのオペランドの値が等しいかどうかをチェックし、値が等しくない場合は条件が真になります。 例:(A!= B)は真です。 |
3 |
> (Greater than) 左のオペランドの値が右のオペランドの値よりも大きいかどうかをチェックし、そうであれば条件は真になります。 例:(A> B)は正しくありません。 |
4 |
< (Less than) 左のオペランドの値が右のオペランドの値よりも小さいかどうかを確認し、そうであれば条件は真になります。 例:(A <B)は真です。 |
5 |
>= (Greater than or Equal to) 左のオペランドの値が右のオペランドの値以上かどうかをチェックし、そうであれば条件は真になります。 例:(A> = B)は正しくありません。 |
6 |
⇐ (Less than or Equal to) 左のオペランドの値が右のオペランドの値以下かどうかをチェックし、そうであれば条件は真になります。 例:(A ⇐ B)は真です。 |
論理演算子
Solidityは次の論理演算子をサポートしています-
変数Aが10を保持し、変数Bが20を保持すると仮定します-
リンク:/solidity/solidity_logical_operators [例を表示]
Sr.No. | Operator & Description |
---|---|
1 |
&& (Logical AND) 両方のオペランドがゼロ以外の場合、条件は真になります。 例:(A && B)はtrueです。 |
2 | * |
(Logical OR)* 2つのオペランドのいずれかがゼロ以外の場合、条件は真になります。 例:(A | |
B)はtrueです。 | |
3 |
! (Logical NOT) オペランドの論理状態を反転します。 条件が真の場合、Logical NOT演算子はそれを偽にします。 例:! (A && B)は偽です。 |
ビット演算子
Solidityは、次のビット演算子をサポートしています-
変数Aが2を保持し、変数Bが3を保持すると仮定します-
link:/solidity/solidity_bitwise_operators [例を表示]
Sr.No. | Operator & Description |
---|---|
1 |
& (Bitwise AND) 整数引数の各ビットに対してブールAND演算を実行します。 例:(A&B)は2です。 |
2 | * |
(BitWise OR)* 整数引数の各ビットに対してブールOR演算を実行します。 例:(A |
B)は3です。 |
3 |
^ (Bitwise XOR) 整数引数の各ビットに対してブール排他的OR演算を実行します。 排他的ORは、オペランド1が真であるか、オペランド2が真であり、両方ではないことを意味します。 例:(A ^ B)は1です。 |
4 |
~ (Bitwise Not) これは単項演算子であり、オペランドのすべてのビットを反転することにより動作します。 例:(〜B)は-4です。 |
5 |
<< (Left Shift) 第1オペランドのすべてのビットを、第2オペランドで指定された桁数だけ左に移動します。 新しいビットはゼロで埋められます。 値を1ポジション左にシフトすることは、2を乗算することと同等です。2ポジションをシフトすることは、4を乗算することと同等です。 例:(A << 1)は4です。 |
6 |
>> (Right Shift) バイナリ右シフト演算子。 左のオペランドの値は、右のオペランドで指定されたビット数だけ右に移動します。 例:(A >> 1)は1です。 |
7 |
>>> (Right shift with Zero) この演算子は、>>演算子と同じですが、左にシフトインされるビットが常にゼロである点が異なります。 例:(A >>> 1)は1です。 |
割り当て演算子
Solidityは次の代入演算子をサポートしています-
link:/solidity/solidity_assignment_operators [例を表示]
Sr.No. | Operator & Description |
---|---|
1 |
= (Simple Assignment ) 右側のオペランドから左側のオペランドに値を割り当てます
|
2 |
右オペランドを左オペランドに追加し、結果を左オペランドに割り当てます。
|
3 |
左のオペランドから右のオペランドを減算し、結果を左のオペランドに割り当てます。
|
4 |
右オペランドと左オペランドを乗算し、結果を左オペランドに割り当てます。 例: *C = AはC = C *Aと同等 |
5 |
/= (Divide and Assignment) 左のオペランドを右のオペランドで除算し、結果を左のオペランドに割り当てます。
|
6 |
2つのオペランドを使用してモジュラスを取得し、結果を左のオペランドに割り当てます。
|
注-ビット単位演算子にも同じロジックが適用されるため、⇐=、>> =、>> =、&=、| =、^ =のようになります。
条件演算子(? :)
条件演算子は、最初に式の真または偽の値を評価してから、評価の結果に応じて2つの指定されたステートメントのいずれかを実行します。
link:/solidity/solidity_conditional_operators [例を表示]
Sr.No. | Operator and Description |
---|---|
1 |
? : (Conditional ) 条件が真の場合 次に値X:そうでなければ値Y |
堅牢性-ループ
契約の作成中に、アクションを繰り返し実行する必要がある状況が発生する場合があります。 このような状況では、ループステートメントを記述して行数を減らす必要があります。
Solidityは、プログラミングのプレッシャーを軽減するために必要なすべてのループをサポートします。
Sr.No | Loops & Description |
---|---|
1 |
Solidityの最も基本的なループは、この章で説明するwhileループです。 |
2 |
do … whileループは、ループの最後に条件チェックが発生することを除いて、whileループに似ています。 |
3 |
forループは、ループの最もコンパクトな形式です。 次の3つの重要な部分が含まれています。 |
4 |
Solidityは、ループの処理とステートメントの切り替えを完全に制御します。 |
堅牢性-意思決定
プログラムの作成中に、特定のパスのセットから1つを採用する必要がある場合があります。 そのような場合、プログラムが正しい決定を下し、正しいアクションを実行できるようにする条件文を使用する必要があります。
Solidityは、さまざまな条件に基づいてさまざまなアクションを実行するために使用される条件ステートメントをサポートしています。 ここで、 if..else ステートメントについて説明します。
if-elseのフローチャート
次のフローチャートは、if-elseステートメントの動作を示しています。
Solidityは if..else ステートメントの次の形式をサポートしています-
Sr.No | Statements & Description |
---|---|
1 |
ifステートメントは、Solidityが決定を下し、ステートメントを条件付きで実行できるようにする基本的な制御ステートメントです。 |
2 |
'if … else’ステートメントは、Solidityがより制御された方法でステートメントを実行できるようにする制御ステートメントの次の形式です。 |
3 |
if … else if … ステートメントはif … elseの高度な形式であり、Solidityがいくつかの条件から正しい決定を下せるようにします。 |
堅牢性-文字列
Solidityは、二重引用符( ")と一重引用符( ')の両方を使用した文字列リテラルをサポートしています。 String型の変数を宣言するデータ型としてstringを提供します。
pragma solidity ^0.5.0;
contract SolidityTest {
string data = "test";
}
上記の例では、「test」は文字列リテラルであり、dataは文字列変数です。 文字列操作はバイト操作と比較してより多くのガスを必要とするため、より好ましい方法は文字列ではなくバイト型を使用することです。 Solidityは、バイトから文字列へ、またはその逆への組み込み変換を提供します。 Solidityでは、文字列リテラルをbyte32型の変数に簡単に割り当てることができます。 Solidityはそれをbyte32リテラルと見なします。
pragma solidity ^0.5.0;
contract SolidityTest {
bytes32 data = "test";
}
エスケープ文字
Sr.No. | Character & Description |
---|---|
1 |
\n 新しい行を開始します。 |
2 |
\\ バックスラッシュ |
3 |
\' シングルクォート |
4 |
\" 二重引用符 |
5 |
\b バックスペース |
6 |
\f フォームフィード |
7 |
\r キャリッジリターン |
8 |
\t Tab |
9 |
\v 垂直タブ |
10 |
\xNN 16進値を表し、適切なバイトを挿入します。 |
11 |
\uNNNN Unicode値を表し、UTF-8シーケンスを挿入します。 |
バイトから文字列への変換
バイトは、string()コンストラクターを使用してストリングに変換できます。
bytes memory bstr = new bytes(10);
string message = string(bstr);
例
Solidityでの文字列の動作を理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract SolidityTest {
constructor() public{
}
function getResult() public view returns(string memory){
uint a = 1;
uint b = 2;
uint result = a + b;
return integerToString(result);
}
function integerToString(uint _i) internal pure
returns (string memory) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j/= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i/= 10;
}
return string(bstr);
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: string: 3
堅牢性-配列
配列は、同じタイプの要素の固定サイズの順次コレクションを格納するデータ構造です。 配列はデータのコレクションを格納するために使用されますが、配列を同じタイプの変数のコレクションと考える方が便利な場合がよくあります。
number0、number1、…、number99などの個々の変数を宣言する代わりに、numbersなどの1つの配列変数を宣言し、numbers [0]、numbers [1]、…、numbers [99]を使用して表現します個々の変数。 配列内の特定の要素は、インデックスによってアクセスされます。
Solidityでは、配列はコンパイル時の固定サイズでも動的サイズでもかまいません。 ストレージアレイの場合、さまざまなタイプの要素を使用することもできます。 メモリ配列の場合、要素タイプはマッピングできません。関数パラメーターとして使用する場合、要素タイプはABIタイプである必要があります。
すべての配列は、連続したメモリ位置で構成されています。 最下位アドレスは最初の要素に対応し、最上位アドレスは最後の要素に対応します。
配列の宣言
Solidityで固定サイズの配列を宣言するために、プログラマは次のように配列に必要な要素のタイプと要素の数を指定します-
type arrayName [ arraySize ];
これは、単一次元配列と呼ばれます。 arraySize はゼロより大きい整数定数でなければならず、 type は有効なSolidityデータ型であればどれでもかまいません。 たとえば、タイプuintのバランスと呼ばれる10要素の配列を宣言するには、このステートメントを使用します-
uint balance[10];
Solidityで動的なサイズの配列を宣言するには、プログラマは次のように要素のタイプを指定します-
type[] arrayName;
配列の初期化
あなたはSolidity配列要素を1つずつ、または次のように単一のステートメントを使用して初期化することができます
uint balance[3] = [1, 2, 3];
中括弧[]の間の値の数は、角括弧[]の間の配列に対して宣言する要素の数より大きくすることはできません。 以下は、配列の単一の要素を割り当てるための例です-
配列のサイズを省略すると、初期化を保持するのに十分な大きさの配列が作成されます。 したがって、あなたが書く場合-
uint balance[] = [1, 2, 3];
前の例で作成したのとまったく同じ配列を作成します。
balance[2] = 5;
上記のステートメントは、配列内の要素番号3 ^ rd ^に値5を割り当てます。
動的メモリ配列の作成
動的メモリ配列は、新しいキーワードを使用して作成されます。
uint size = 3;
uint balance[] = new uint[](size);
配列要素へのアクセス
配列名にインデックスを付けることにより、要素にアクセスします。 これは、配列の名前の後に角かっこ内に要素のインデックスを配置することによって行われます。 たとえば-
uint salary = balance[2];
上記のステートメントは、配列から3 ^ rd ^要素を取得し、その値を給与変数に割り当てます。 以下は、上記の3つの概念すべてを使用する例です。 配列の宣言、割り当て、アクセス-
メンバー
- length -lengthは配列のサイズを返します。 lengthは、動的配列のサイズを変更するために使用できます。
- push -pushを使用すると、要素を動的ストレージ配列に最後に追加できます。 配列の新しい長さを返します。
例
Solidityで配列がどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract test {
function testArray() public pure{
uint len = 7;
//dynamic array
uint[] memory a = new uint[](7);
//bytes is same as byte[]
bytes memory b = new bytes(len);
assert(a.length == 7);
assert(b.length == len);
//access array variable
a[6] = 8;
//test array variable
assert(a[6] == 8);
//static array
uint[3] memory c = [uint(1) , 2, 3];
assert(c.length == 3);
}
}
Solidity-列挙
列挙型は、変数がいくつかの事前定義された値のいずれかを持つように制限します。 この列挙リストの値は、列挙と呼ばれます。
列挙型を使用すると、コード内のバグの数を減らすことができます。
たとえば、フレッシュジュースショップのアプリケーションを検討する場合、ガラスのサイズを小、中、大に制限することができます。 これにより、小、中、大以外のサイズを誰も注文できないようになります。
例
Solidityで列挙型がどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract test {
enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
FreshJuiceSize choice;
FreshJuiceSize constant defaultChoice = FreshJuiceSize.MEDIUM;
function setLarge() public {
choice = FreshJuiceSize.LARGE;
}
function getChoice() public view returns (FreshJuiceSize) {
return choice;
}
function getDefaultChoice() public pure returns (uint) {
return uint(defaultChoice);
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
最初に setLarge ボタンをクリックして値をLARGEに設定し、次に getChoice をクリックして選択した選択肢を取得します。
出力
uint8: 2
*getDefaultChoice* ボタンをクリックして、デフォルトの選択肢を取得します。
出力
uint256: 1
堅牢性-構造
構造型は、レコードを表すために使用されます。 図書館で本を追跡したいとします。 あなたは、各本に関する次の属性を追跡することができます-
- タイトル
- 著者
- 件名
- ブックID
構造体の定義
構造体を定義するには、 struct キーワードを使用する必要があります。 structキーワードは、複数のメンバーを持つ新しいデータ型を定義します。 構造体ステートメントの形式は次のとおりです-
struct struct_name {
type1 type_name_1;
type2 type_name_2;
type3 type_name_3;
}
例
struct Book {
string title;
string author;
uint book_id;
}
構造体とその変数へのアクセス
構造体のメンバーにアクセスするには、メンバーアクセス演算子(。)を使用します。 メンバーアクセス演算子は、構造変数名とアクセスする構造メンバーの間のピリオドとしてコーディングされます。 構造体の変数を定義するには、構造体を使用します。 次の例は、プログラムで構造体を使用する方法を示しています。
例
Solidityで構造体がどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract test {
struct Book {
string title;
string author;
uint book_id;
}
Book book;
function setBook() public {
book = Book('Learn Java', 'TP', 1);
}
function getBookId() public view returns (uint) {
return book.book_id;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
最初に setBook ボタンをクリックして値をLARGEに設定し、 getBookId をクリックして選択したブックIDを取得します。
出力
uint256: 1
堅牢性-マッピング
マッピングは、配列および構造体としての参照型です。 以下は、マッピングタイプを宣言する構文です。
mapping(_KeyType => _ValueType)
どこで
- _KeyType -任意の組み込み型に加えて、バイトと文字列を指定できます。 参照型または複合オブジェクトは許可されていません。
- _ValueType -任意のタイプを指定できます。
検討事項
- マッピングのタイプは storage のみで、通常は状態変数に使用されます。
- マッピングはパブリックとしてマークできます。 Solidityは、そのためのゲッターを自動的に作成します。
例
Solidityでマッピングタイプがどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract LedgerBalance {
mapping(address => uint) public balances;
function updateBalance(uint newBalance) public {
balances[msg.sender] = newBalance;
}
}
contract Updater {
function updateBalance() public returns (uint) {
LedgerBalance ledgerBalance = new LedgerBalance();
ledgerBalance.updateBalance(10);
return ledgerBalance.balances(address(this));
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
最初に updateBalance ボタンをクリックして値を10に設定してから、ログを調べて、デコードされた出力を次のように表示します-
出力
{
"0": "uint256: 10"
}
堅牢性-変換
堅牢性により、暗黙的および明示的な変換が可能になります。 Solidityコンパイラは、暗黙的な変換が不可能であり、情報の損失がない限り、2つのデータ型間の暗黙的な変換を許可します。 たとえば、uint8はuint16に変換可能ですが、int8にはuint256では許可されない負の値を含めることができるため、int8はuint256に変換可能です。
明示的な変換
コンストラクタ構文を使用して、データ型を明示的に別の型に変換できます。
int8 y = -3;
uint x = uint(y);
//Now x = 0xfffff..fd == two complement representation of -3 in 256 bit format.
小さい型に変換すると、高位ビットがかかります。
uint32 a = 0x12345678;
uint16 b = uint16(a);//b = 0x5678
上位のタイプに変換すると、左側にパディングビットが追加されます。
uint16 a = 0x1234;
uint32 b = uint32(a);//b = 0x00001234
より小さなバイトへの変換には、より高次のデータが必要です。
bytes2 a = 0x1234;
bytes1 b = bytes1(a);//b = 0x12
大きいバイトに変換すると、右側にパディングビットが追加されます。
bytes2 a = 0x1234;
bytes4 b = bytes4(a);//b = 0x12340000
固定サイズのバイトとintの間の変換は、両方が同じサイズの場合にのみ可能です。
bytes2 a = 0x1234;
uint32 b = uint16(a);//b = 0x00001234
uint32 c = uint32(bytes4(a));//c = 0x12340000
uint8 d = uint8(uint16(a));//d = 0x34
uint8 e = uint8(bytes1(a));//e = 0x12
切り捨てが不要な場合は、16進数を任意の整数型に割り当てることができます。
uint8 a = 12;//no error
uint32 b = 1234;//no error
uint16 c = 0x123456;//error, as truncation required to 0x3456
堅牢性-エーテル単位
堅実性において、wei、finney、szabo、またはetherをリテラルの接尾辞として使用して、さまざまなエーテルベースの単位を変換することができます。 最低単位はweiで、1e12は1 x 10 ^ 12 ^を表します。
assert(1 wei == 1);
assert(1 szabo == 1e12);
assert(1 finney == 1e15);
assert(1 ether == 1e18);
assert(2 ether == 2000 fenny);
時間単位
通貨と同様に、Solidityには時間単位があり、最小単位は2番目であり、時間を示すための接尾辞として秒、分、時間、日、および週を使用できます。
assert(1 seconds == 1);
assert(1 minutes == 60 seconds);
assert(1 hours == 60 minutes);
assert(1 day == 24 hours);
assert(1 week == 7 days);
堅牢性-特殊変数
特殊変数はグローバルに利用可能な変数であり、ブロックチェーンに関する情報を提供します。 以下は、特殊変数のリストです-
Sr.No. | Special Variable & Description |
---|---|
1 |
blockhash(uint blockNumber) returns (bytes32) 指定されたブロックのハッシュ-現在のブロックを除く最新の256ブロックに対してのみ機能します。 |
2 |
block.coinbase (address payable) 現在のブロックマイナーのアドレス。 |
3 |
block.difficulty (uint) 現在のブロックの難易度。 |
4 |
block.gaslimit (uint) 現在のブロックのガス制限。 |
5 |
block.number (uint) 現在のブロック番号。 |
6 |
block.timestamp UNIXエポックからの秒数としての現在のブロックタイムスタンプ。 |
7 |
gasleft() returns (uint256) 残留ガス。 |
8 |
msg.data (bytes calldata) 完全なコールデータ。 |
9 |
msg.sender (address payable) メッセージの送信者(現在の呼び出し)。 |
10 |
msg.sig (bytes4) calldataの最初の4バイト(つまり、 関数識別子) |
11 |
msg.value (uint) メッセージとともに送信されたweiの数。 |
12 |
now (uint) 現在のブロックのタイムスタンプ(block.timestampのエイリアス)。 |
13 |
tx.gasprice (uint) トランザクションのガス価格。 |
14 |
tx.origin (address payable) トランザクションの送信者(完全な呼び出しチェーン)。 |
例
次のコードを試して、Solidityの送信者アドレスを取得する特別な変数であるmsgの使用を確認してください。
pragma solidity ^0.5.0;
contract LedgerBalance {
mapping(address => uint) public balances;
function updateBalance(uint newBalance) public {
balances[msg.sender] = newBalance;
}
}
contract Updater {
function updateBalance() public returns (uint) {
LedgerBalance ledgerBalance = new LedgerBalance();
ledgerBalance.updateBalance(10);
return ledgerBalance.balances(address(this));
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
最初に updateBalance ボタンをクリックして値を10に設定してから、ログを調べて、デコードされた出力を次のように表示します-
出力
{
"0": "uint256: 10"
}
Solidity-スタイルガイド
スタイルガイドは、コードレイアウトの一貫性を維持し、コードを読みやすくするのに役立ちます。 Solidityと契約書を作成する際のベストプラクティスは次のとおりです。
コードレイアウト
- インデント-インデントレベルを維持するには、タブの代わりに4つのスペースを使用します。 タブとスペースを混在させないでください。
- * 2つの空行ルール*-2つの契約定義の間に2つの空行を使用します。
pragma solidity ^0.5.0;
contract LedgerBalance {
//...
}
contract Updater {
//...
}
- * 1つの空行ルール*-2つの関数の間に1つの空行を使用します。 宣言のみの場合、空白行は必要ありません。
pragma solidity ^0.5.0;
contract A {
function balance() public pure;
function account() public pure;
}
contract B is A {
function balance() public pure {
//...
}
function account() public pure {
//...
}
}
- 最大行長-読者がコードを簡単に解析できるように、1行が79文字を超えてはなりません。
- ラッピングルール-最初の引数は、カッコを開けずに改行で入力します。 引数ごとに単一のインデントを使用します。 終了要素);最後でなければなりません。
function_with_a_long_name(
longArgument1,
longArgument2,
longArgument3
);
variable = function_with_a_long_name(
longArgument1,
longArgument2,
longArgument3
);
event multipleArguments(
address sender,
address recipient,
uint256 publicKey,
uint256 amount,
bytes32[] options
);
MultipleArguments(
sender,
recipient,
publicKey,
amount,
options
);
- ソースコードエンコーディング-できればUTF-8またはASCIIエンコーディングを使用してください。
- Imports -インポートステートメントは、プラグマ宣言の直後のファイルの先頭に配置する必要があります。
- 関数の順序-関数は、可視性に従ってグループ化する必要があります。
pragma solidity ^0.5.0;
contract A {
constructor() public {
//...
}
function() external {
//...
}
//External functions
//...
//External view functions
//...
//External pure functions
//...
//Public functions
//...
//Internal functions
//...
//Private functions
//...
}
- 余分な空白を避ける-括弧、括弧、または中括弧のすぐ内側の空白を避けます。
- 制御構造-中括弧は宣言と同じ行で開く必要があります。 同じインデントを維持しながら、独自の行で閉じます。 開きブレースのあるスペースを使用します。
pragma solidity ^0.5.0;
contract Coin {
struct Bank {
address owner;
uint balance;
}
}
if (x < 3) {
x += 1;
} else if (x > 7) {
x -= 1;
} else {
x = 5;
}
if (x < 3)
x += 1;
else
x -= 1;
- 関数宣言-中括弧には上記の規則を使用します。 常に可視性ラベルを追加してください。 可視性ラベルは、カスタム修飾子の前に最初に来る必要があります。
function kill() public onlyowner {
selfdestruct(owner);
}
- マッピング-マッピング変数を宣言する際に空白を避けます。
mapping(uint => uint) map;
mapping(address => bool) registeredAddresses;
mapping(uint => mapping(bool => Data[])) public data;
mapping(uint => mapping(uint => s)) data;
- 変数宣言-配列変数の宣言中に空白を避けます。
uint[] x; //not unit [] x;
- 文字列宣言-二重引用符を使用して、単一引用符の代わりに文字列を宣言します。
str = "foo";
str = "Hamlet says, 'To be or not to be...'";
レイアウトの順序
要素は次の順序でレイアウトする必要があります。
- プラグマステートメント
- インポートステートメント
- インターフェース
- 図書館
- 契約
インターフェイス、ライブラリ、または契約内では、順序は次のようになります-
- 型宣言
- 状態変数
- イベント
- 関数
命名規則
- 契約およびライブラリは、CapWordsスタイルを使用して名前を付ける必要があります。 たとえば、SmartContract、所有者など。
- 契約名とライブラリ名はファイル名と一致する必要があります。
- 1つのファイルに複数の契約/ライブラリがある場合、コア契約/ライブラリの名前を使用します。
Owned.sol
pragma solidity ^0.5.0;
//Owned.sol
contract Owned {
address public owner;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
//....
}
function transferOwnership(address newOwner) public onlyOwner {
//...
}
}
Congress.sol
pragma solidity ^0.5.0;
//Congress.sol
import "./Owned.sol";
contract Congress is Owned, TokenRecipient {
//...
}
- 構造体名 + − SmartCoinのようなCapWordsスタイルを使用します。
- イベント名 + − Deposit、AfterTransferなどのCapWordsスタイルを使用します。
- 関数名 +-initializeSupplyのようなmixedCaseスタイルを使用します。
- ローカル変数と状態変数 +-creatorAddressのようなmixedCaseスタイルを使用します。
- 定数 +-下線付きのすべての大文字を使用して、MAX_BLOCKSなどの単語を区切ります。
- 修飾子名 + − onlyAfterのようなmixCaseスタイルを使用します。
- 列挙名 + − TokenGroupのようなCapWordsスタイルを使用します。
堅牢性-機能
関数は、プログラム内のどこからでも呼び出すことができる再利用可能なコードのグループです。 これにより、同じコードを何度も記述する必要がなくなります。 プログラマーがモジュラーコードを書くのに役立ちます。 関数を使用すると、プログラマは大きなプログラムをいくつかの小さく管理可能な関数に分割できます。
他の高度なプログラミング言語と同様に、Solidityは関数を使用してモジュラーコードを記述するために必要なすべての機能もサポートしています。 このセクションでは、Solidityで独自の関数を作成する方法について説明します。
関数定義
関数を使用する前に、定義する必要があります。 Solidityで関数を定義する最も一般的な方法は、 function キーワードを使用し、その後に一意の関数名、パラメーターのリスト(空の場合がある)、および中括弧で囲まれたステートメントブロックを使用することです。
構文
基本的な構文は次のとおりです。
function function-name(parameter-list) scope returns() {
//statements
}
例
次の例を試してください。 パラメータを取らないgetResultと呼ばれる関数を定義します-
pragma solidity ^0.5.0;
contract Test {
function getResult() public view returns(uint){
uint a = 1;//local variable
uint b = 2;
uint result = a + b;
return result;
}
}
関数を呼び出す
コントラクトのどこかで関数を呼び出すには、次のコードに示すように、その関数の名前を記述するだけです。
Solidityでの文字列の動作を理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract SolidityTest {
constructor() public{
}
function getResult() public view returns(string memory){
uint a = 1;
uint b = 2;
uint result = a + b;
return integerToString(result);
}
function integerToString(uint _i) internal pure
returns (string memory) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j/= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i/= 10;
}
return string(bstr);//access local variable
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: string: 3
関数パラメーター
これまで、パラメーターのない関数を見てきました。 ただし、関数の呼び出し中に異なるパラメーターを渡す機能があります。 これらの渡されたパラメーターは関数内でキャプチャーでき、これらのパラメーターに対して任意の操作を実行できます。 関数は、コンマで区切られた複数のパラメーターを取ることができます。
例
次の例を試してください。 ここでは uint2str 関数を使用しました。 1つのパラメーターを取ります。
pragma solidity ^0.5.0;
contract SolidityTest {
constructor() public{
}
function getResult() public view returns(string memory){
uint a = 1;
uint b = 2;
uint result = a + b;
return integerToString(result);
}
function integerToString(uint _i) internal pure
returns (string memory) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j/= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i/= 10;
}
return string(bstr);//access local variable
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: string: 3
returnステートメント
Solidity関数には、オプションの return ステートメントを含めることができます。 これは、関数から値を返す場合に必要です。 このステートメントは、関数の最後のステートメントでなければなりません。
上記の例のように、uint2str関数を使用して文字列を返します。
Solidityでは、関数は複数の値を返すこともできます。 以下の例を参照してください-
pragma solidity ^0.5.0;
contract Test {
function getResult() public view returns(uint product, uint sum){
uint a = 1;//local variable
uint b = 2;
product = a * b;
sum = a + b;
//alternative return statement to return
//multiple values
//return(a*b, a+b);
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: uint256: product 2
1: uint256: sum 3
Solidity-関数修飾子
関数修飾子は、関数の動作を変更するために使用されます。 たとえば、機能に前提条件を追加します。
最初に、パラメーター付きまたはパラメーターなしの修飾子を作成します。
contract Owner {
modifier onlyOwner {
require(msg.sender == owner);
_;
}
modifier costs(uint price) {
if (msg.value >= price) {
_;
}
}
}
関数本体は、特別な記号「_;」の場所に挿入されます修飾子の定義に表示されます。 そのため、この関数の呼び出し中に修飾子の条件が満たされると、関数が実行され、そうでない場合は例外がスローされます。
以下の例を参照してください-
pragma solidity ^0.5.0;
contract Owner {
address owner;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
modifier costs(uint price) {
if (msg.value >= price) {
_;
}
}
}
contract Register is Owner {
mapping (address => bool) registeredAddresses;
uint price;
constructor(uint initialPrice) public { price = initialPrice; }
function register() public payable costs(price) {
registeredAddresses[msg.sender] = true;
}
function changePrice(uint _price) public onlyOwner {
price = _price;
}
}
Solidity-ビュー機能
ビュー関数は、状態が変更されないようにします。 関数は view として宣言できます。 関数に次のステートメントが存在する場合、状態を変更すると見なされ、そのような場合にコンパイラーは警告をスローします。
- 状態変数の変更。
- イベントを発行します。
- 他の契約を作成します。
- 自己破壊を使用します。
- 呼び出しを介してEtherを送信します。
- viewまたはpureとしてマークされていない関数を呼び出します。
- 低レベルの呼び出しを使用します。 *特定のオペコードを含むインラインアセンブリを使用します。
ゲッターメソッドは、デフォルトではビュー関数です。
ビュー関数を使用した以下の例を参照してください。
例
pragma solidity ^0.5.0;
contract Test {
function getResult() public view returns(uint product, uint sum){
uint a = 1;//local variable
uint b = 2;
product = a* b;
sum = a + b;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: uint256: product 2
1: uint256: sum 3
堅牢性-純粋な機能
純粋な関数は、状態を読み取ったり変更したりしないようにします。 関数は pure として宣言できます。 関数に次のステートメントが存在する場合、状態の読み取りと見なされ、コンパイラーはそのような場合に警告をスローします。
- 状態変数の読み取り。
- address(this).balanceまたは<address> .balanceへのアクセス。
- ブロック、tx、msg(msg.sigおよびmsg.dataを読み取ることができます)の特殊変数にアクセスします。
- pureとマークされていない関数を呼び出す。 *特定のオペコードを含むインラインアセンブリを使用します。
純粋な関数は、revert()およびrequire()関数を使用して、エラーが発生した場合に潜在的な状態の変更を元に戻すことができます。
ビュー関数を使用した以下の例を参照してください。
例
pragma solidity ^0.5.0;
contract Test {
function getResult() public pure returns(uint product, uint sum){
uint a = 1;
uint b = 2;
product = a* b;
sum = a + b;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: uint256: product 2
1: uint256: sum 3
堅牢性-フォールバック機能
フォールバック関数は、契約で使用できる特別な関数です。 次の機能があります-
- 存在しない関数がコントラクトで呼び出されたときに呼び出されます。
- 外部とマークする必要があります。
- 名前はありません。
- 引数はありません
- 何も返せません。
- 契約ごとに定義できます。
- 支払い可能とマークされていない場合、契約がデータなしのプレーンエーテルを受信すると、例外をスローします。
次の例は、契約ごとのフォールバック関数の概念を示しています。
例
pragma solidity ^0.5.0;
contract Test {
uint public x ;
function() external { x = 1; }
}
contract Sink {
function() external payable { }
}
contract Caller {
function callTest(Test test) public returns (bool) {
(bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
require(success);
//test.x is now 1
address payable testPayable = address(uint160(address(test)));
//Sending ether to Test contract,
//the transfer will fail, i.e. this returns false here.
return (testPayable.send(2 ether));
}
function callSink(Sink sink) public returns (bool) {
address payable sinkPayable = address(sink);
return (sinkPayable.send(2 ether));
}
}
堅牢性-関数のオーバーロード
同じスコープ内で同じ関数名に複数の定義を設定できます。 関数の定義は、引数リスト内の引数のタイプまたは数、あるいはその両方によって互いに異なる必要があります。 戻り型のみが異なる関数宣言をオーバーロードすることはできません。
次の例は、Solidityでオーバーロードする関数の概念を示しています。
例
pragma solidity ^0.5.0;
contract Test {
function getSum(uint a, uint b) public pure returns(uint){
return a + b;
}
function getSum(uint a, uint b, uint c) public pure returns(uint){
return a + b + c;
}
function callSumWithTwoArguments() public pure returns(uint){
return getSum(1,2);
}
function callSumWithThreeArguments() public pure returns(uint){
return getSum(1,2,3);
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
最初にcallSumWithTwoArgumentsボタンをクリックし、次にcallSumWithThreeArgumentsボタンをクリックして結果を確認します。
出力
0: uint256: 3
0: uint256: 6
Solidity-数学関数
Solidityは、組み込みの数学関数も提供します。 以下は頻繁に使用される方法です-
- * addmod(uint x、uint y、uint k)は(uint)*を返します-任意の精度で加算が実行され、2 ^ 256 ^でラップアラウンドしない(x + y)%kを計算します。
- * mulmod(uint x、uint y、uint k)は(uint)*を返します-(x * y)%kを計算します。ここで、加算は任意の精度で実行され、2 ^ 256 ^でラップアラウンドしません。
次の例は、Solidityでの数学関数の使用法を示しています。
例
pragma solidity ^0.5.0;
contract Test {
function callAddMod() public pure returns(uint){
return addmod(4, 5, 3);
}
function callMulMod() public pure returns(uint){
return mulmod(4, 5, 3);
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
最初にcallAddModボタンをクリックし、次にcallMulModボタンをクリックして結果を確認します。
出力
0: uint256: 0
0: uint256: 2
Solidity-暗号化機能
Solidityは、組み込みの暗号化機能も提供します。 以下は重要な方法です-
- * keccak256(bytes memory)は(bytes32)*を返します-入力のKeccak-256ハッシュを計算します。
- * sha256(bytes memory)は(bytes32)*を返します-入力のSHA-256ハッシュを計算します。
- * ripemd160(bytes memory)は(bytes20)*を返します-入力のRIPEMD-160ハッシュを計算します。
- * sha256(bytes memory)は(bytes32)*を返します-入力のSHA-256ハッシュを計算します。
- * ecrecover(bytes32 hash、uint8 v、bytes32 r、bytes32 s)は(アドレス)*を返します-公開鍵に関連付けられたアドレスを楕円曲線署名から復元するか、エラー時にゼロを返します。 関数パラメーターは、署名のECDSA値に対応します。r-署名の最初の32バイト。 s:署名の2番目の32バイト。 v:署名の最後の1バイト。 このメソッドは住所を返します。
次の例は、Solidityでの暗号化機能の使用法を示しています。
例
pragma solidity ^0.5.0;
contract Test {
function callKeccak256() public pure returns(bytes32 result){
return keccak256("ABC");
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: bytes32: result 0xe1629b9dda060bb30c7908346f6af189c16773fa148d3366701fbaa35d54f3c8
堅牢性-引き出しパターン
撤回パターンは、セキュリティ上の脅威となる直接転送呼び出しが行われないようにします。 次の契約は、etherを送信するための転送呼び出しの安全でない使用を示しています。
pragma solidity ^0.5.0;
contract Test {
address payable public richest;
uint public mostSent;
constructor() public payable {
richest = msg.sender;
mostSent = msg.value;
}
function becomeRichest() public payable returns (bool) {
if (msg.value > mostSent) {
//Insecure practice
richest.transfer(msg.value);
richest = msg.sender;
mostSent = msg.value;
return true;
} else {
return false;
}
}
}
上記のコントラクトは、フォールバック機能が失敗したコントラクトを最もリッチにすることにより、使用できない状態でレンダリングできます。 フォールバック関数が失敗すると、becomeRichest()関数も失敗し、コントラクトは永久にスタックします。 この問題を軽減するために、引き出しパターンを使用できます。
引き出しパターンでは、各送金の前に保留金額をリセットします。 呼び出し元の契約のみが失敗するようにします。
pragma solidity ^0.5.0;
contract Test {
address public richest;
uint public mostSent;
mapping (address => uint) pendingWithdrawals;
constructor() public payable {
richest = msg.sender;
mostSent = msg.value;
}
function becomeRichest() public payable returns (bool) {
if (msg.value > mostSent) {
pendingWithdrawals[richest] += msg.value;
richest = msg.sender;
mostSent = msg.value;
return true;
} else {
return false;
}
}
function withdraw() public {
uint amount = pendingWithdrawals[msg.sender];
pendingWithdrawals[msg.sender] = 0;
msg.sender.transfer(amount);
}
}
堅牢性-アクセス制限
契約へのアクセス制限は一般的な慣行です。 デフォルトでは、パブリックとして指定されていない限り、契約状態は読み取り専用です。
修飾子を使用して、契約の状態を変更できるユーザーを制限したり、契約の機能を呼び出したりできます。 以下で説明するように、複数の修飾子を作成して使用します-
- onlyBy -関数で使用されると、言及された呼び出し元のみがこの関数を呼び出すことができます。
- onlyAfter -関数で一度使用すると、その関数は一定時間後に呼び出すことができます。
- コスト-関数で一度使用すると、呼び出し側は特定の値が提供されている場合にのみこの関数を呼び出すことができます。
例
pragma solidity ^0.5.0;
contract Test {
address public owner = msg.sender;
uint public creationTime = now;
modifier onlyBy(address _account) {
require(
msg.sender == _account,
"Sender not authorized."
);
_;
}
function changeOwner(address _newOwner) public onlyBy(owner) {
owner = _newOwner;
}
modifier onlyAfter(uint _time) {
require(
now >= _time,
"Function called too early."
);
_;
}
function disown() public onlyBy(owner) onlyAfter(creationTime + 6 weeks) {
delete owner;
}
modifier costs(uint _amount) {
require(
msg.value >= _amount,
"Not enough Ether provided."
);
_;
if (msg.value > _amount)
msg.sender.transfer(msg.value - _amount);
}
function forceOwnerChange(address _newOwner) public payable costs(200 ether) {
owner = _newOwner;
if (uint(owner) & 0 == 1) return;
}
}
堅牢性-契約
Solidityの契約は、C ++のクラスに似ています。 契約には次のプロパティがあります。
- Constructor -コントラクトごとに1回実行され、コントラクトの作成時に呼び出されるコンストラクターキーワードで宣言された特別な関数。
- 状態変数-契約の状態を保存する契約ごとの変数。
- 関数-状態変数を変更して契約の状態を変更できる契約ごとの関数。
可視性の数量化
以下は、コントラクトの関数/状態変数のさまざまな可視性数量化子です。
- external -外部関数は、他のコントラクトによって呼び出されることを意図しています。 内部コールには使用できません。 コントラクト内で外部関数を呼び出すには、this.function_name()呼び出しが必要です。 状態変数を外部としてマークすることはできません。
- public -パブリック関数/変数は外部と内部の両方で使用できます。 パブリック状態変数の場合、Solidityはゲッター関数を自動的に作成します。
- internal -内部関数/変数は、内部的に、または派生コントラクトによってのみ使用できます。
- private -プライベート関数/変数は内部でのみ使用でき、派生コントラクトでも使用できません。
例
pragma solidity ^0.5.0;
contract C {
//private state variable
uint private data;
//public state variable
uint public info;
//constructor
constructor() public {
info = 10;
}
//private function
function increment(uint a) private pure returns(uint) { return a + 1; }
//public function
function updateData(uint a) public { data = a; }
function getData() public view returns(uint) { return data; }
function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
}
//External Contract
contract D {
function readData() public returns(uint) {
C c = new C();
c.updateData(7);
return c.getData();
}
}
//Derived Contract
contract E is C {
uint private result;
C private c;
constructor() public {
c = new C();
}
function getComputedResult() public {
result = compute(3, 5);
}
function getResult() public view returns(uint) { return result; }
function getData() public view returns(uint) { return c.info(); }
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。 契約のさまざまなメソッドを実行します。 E.getComputedResult()の後にE.getResult()が続く場合-
出力
0: uint256: 8
堅牢性-継承
継承は、契約の機能を拡張する方法です。 Solidityは、単一継承と多重継承の両方をサポートします。 主要なハイライトは次のとおりです。
- 派生コントラクトは、内部メソッドや状態変数を含むすべての非プライベートメンバーにアクセスできます。 ただし、これを使用することはできません。
- 関数のシグネチャが同じままであれば、関数のオーバーライドが許可されます。 出力パラメーターが異なる場合、コンパイルは失敗します。
- スーパーキーワードまたはスーパーコントラクト名を使用して、スーパーコントラクトの関数を呼び出すことができます。
- 多重継承の場合、superを使用した関数呼び出しは、ほとんどの派生コントラクトを優先します。
例
pragma solidity ^0.5.0;
contract C {
//private state variable
uint private data;
//public state variable
uint public info;
//constructor
constructor() public {
info = 10;
}
//private function
function increment(uint a) private pure returns(uint) { return a + 1; }
//public function
function updateData(uint a) public { data = a; }
function getData() public view returns(uint) { return data; }
function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
}
//Derived Contract
contract E is C {
uint private result;
C private c;
constructor() public {
c = new C();
}
function getComputedResult() public {
result = compute(3, 5);
}
function getResult() public view returns(uint) { return result; }
function getData() public view returns(uint) { return c.info(); }
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。 契約のさまざまなメソッドを実行します。 E.getComputedResult()の後にE.getResult()が続く場合-
出力
0: uint256: 8
Solidity-コンストラクター
コンストラクターは、 constructor キーワードを使用して宣言された特別な関数です。 これはオプションの機能であり、コントラクトの状態変数を初期化するために使用されます。 以下は、コンストラクターの主要な特性です。
- コントラクトには、コンストラクターを1つだけ含めることができます。
- コントラクトが作成されると、コンストラクターコードが1回実行され、コントラクト状態の初期化に使用されます。
- コンストラクターコードが実行された後、最終コードがブロックチェーンにデプロイされます。 このコードには、パブリック関数と、パブリック関数を介して到達可能なコードが含まれます。 コンストラクターコードまたはコンストラクターによってのみ使用される内部メソッドは、最終コードには含まれません。
- コンストラクターは、パブリックまたは内部のいずれかです。
- 内部コンストラクターは、コントラクトを抽象としてマークします。
- コンストラクターが定義されていない場合、デフォルトのコンストラクターがコントラクトに存在します。
pragma solidity ^0.5.0;
contract Test {
constructor() public {}
}
- 場合には、基本コントラクトに引数を持つコンストラクターがあり、各派生コントラクトはそれらを渡す必要があります。
- 基本コンストラクタは、次の方法を使用して直接初期化できます-
pragma solidity ^0.5.0;
contract Base {
uint data;
constructor(uint _data) public {
data = _data;
}
}
contract Derived is Base (5) {
constructor() public {}
}
*基本コンストラクタは、次の方法を使用して間接的に初期化できます-
pragma solidity ^0.5.0;
contract Base {
uint data;
constructor(uint _data) public {
data = _data;
}
}
contract Derived is Base {
constructor(uint _info) Base(_info* _info) public {}
}
- 基本コントラクトコンストラクターを初期化する直接および間接的な方法は許可されていません。
- 派生コントラクトが引数をベースコントラクトコンストラクターに渡さない場合、派生コントラクトは抽象になります。
堅牢性-抽象契約
抽象コントラクトは、実装なしで少なくとも1つの関数を含むものです。 このような契約は、基本契約として使用されます。 一般に、抽象コントラクトには、実装された関数と抽象関数の両方が含まれます。 派生コントラクトは抽象関数を実装し、必要に応じて既存の関数を使用します。
派生コントラクトが抽象関数を実装していない場合、この派生コントラクトは抽象としてマークされます。
例
Solidityで抽象コントラクトがどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract Calculator {
function getResult() public view returns(uint);
}
contract Test is Calculator {
function getResult() public view returns(uint) {
uint a = 1;
uint b = 2;
uint result = a + b;
return result;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
出力
0: uint256: 3
堅牢性-インターフェース
インターフェイスは抽象コントラクトに似ており、 interface キーワードを使用して作成されます。 インターフェイスの主な特徴は次のとおりです。
- インターフェースには、実装を伴う機能はありません。
- インターフェイスの機能は、外部タイプのみです。
- インターフェイスにコンストラクターを含めることはできません。
- インターフェイスに状態変数を含めることはできません。
- インターフェイスには列挙型の構造体があり、インターフェイス名のドット表記を使用してアクセスできます。
例
Solidityでインターフェイスがどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
interface Calculator {
function getResult() external view returns(uint);
}
contract Test is Calculator {
constructor() public {}
function getResult() external view returns(uint){
uint a = 1;
uint b = 2;
uint result = a + b;
return result;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
注-展開ボタンをクリックする前に、ドロップダウンからテストを選択します。
出力
0: uint256: 3
堅牢性-ライブラリ
ライブラリは契約に似ていますが、主に再利用を目的としています。 ライブラリには、他のコントラクトが呼び出すことができる関数が含まれています。 Solidityには、ライブラリの使用に関する特定の制限があります。 Solidity Libraryの主要な特徴は次のとおりです。
- ライブラリ関数は、状態を変更しない場合、直接呼び出すことができます。 つまり、純粋な関数またはビュー関数は、ライブラリの外部からのみ呼び出すことができます。
- ライブラリはステートレスであると想定されるため、破棄できません。
- ライブラリに状態変数を含めることはできません。
- ライブラリは要素を継承できません。
- ライブラリは継承できません。
例
Solidityでライブラリがどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
library Search {
function indexOf(uint[] storage self, uint value) public view returns (uint) {
for (uint i = 0; i < self.length; i++) if (self[i] == value) return i;
return uint(-1);
}
}
contract Test {
uint[] data;
constructor() public {
data.push(1);
data.push(2);
data.push(3);
data.push(4);
data.push(5);
}
function isValuePresent() external view returns(uint){
uint value = 4;
//search if value is present in the array using Library function
uint index = Search.indexOf(data, value);
return index;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
注-展開ボタンをクリックする前に、ドロップダウンからテストを選択します。
出力
0: uint256: 3
Forの使用
ディレクティブ using A for B; を使用して、ライブラリAのライブラリ関数を特定のタイプBにアタッチできます。 これらの関数は、最初のパラメーターとして呼び出し側タイプを使用します(selfを使用して識別されます)。
例
Solidityでライブラリがどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
library Search {
function indexOf(uint[] storage self, uint value) public view returns (uint) {
for (uint i = 0; i < self.length; i++)if (self[i] == value) return i;
return uint(-1);
}
}
contract Test {
using Search for uint[];
uint[] data;
constructor() public {
data.push(1);
data.push(2);
data.push(3);
data.push(4);
data.push(5);
}
function isValuePresent() external view returns(uint){
uint value = 4;
//Now data is representing the Library
uint index = data.indexOf(value);
return index;
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
注-展開ボタンをクリックする前に、ドロップダウンからテストを選択します。
出力
0: uint256: 3
堅牢性-アセンブリ
Solidityは、アセンブリ言語を使用してSolidityソースコード内にインラインアセンブリを記述するオプションを提供します。 また、スタンドアロンアセンブリコードを記述して、それをバイトコードに変換することもできます。 スタンドアロンアセンブリはSolidityコンパイラの中間言語であり、Solidityコードをスタンドアロンアセンブリに変換してからバイトコードに変換します。 インラインアセンブリで使用したのと同じ言語を使用して、スタンドアロンアセンブリでコードを記述できます。
インラインアセンブリ
インラインアセンブリコードをSolidityコードベース内にインターリーブして、EVMをよりきめ細かく制御することができ、特にライブラリ関数の作成中に使用されます。
アセンブリコードは、 assembly \ {… } ブロック。
例
Solidityでライブラリがどのように機能するかを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
library Sum {
function sumUsingInlineAssembly(uint[] memory _data) public pure returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i) {
assembly {
o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
}
}
}
}
contract Test {
uint[] data;
constructor() public {
data.push(1);
data.push(2);
data.push(3);
data.push(4);
data.push(5);
}
function sum() external view returns(uint){
return Sum.sumUsingInlineAssembly(data);
}
}
link:/solidity/solidity_first_application [Solidity First Application]の章に記載されている手順を使用して、上記のプログラムを実行します。
注-展開ボタンをクリックする前に、ドロップダウンからテストを選択します。
出力
0: uint256: 15
堅牢性-イベント
イベントは、コントラクトの継承可能なメンバーです。 イベントが発行され、渡された引数がトランザクションログに保存されます。 これらのログはブロックチェーンに保存され、契約がブロックチェーンに存在するまで契約のアドレスを使用してアクセスできます。 生成されたイベントには、コントラクト内からアクセスできません。また、それらを作成および発行したイベントにもアクセスできません。
イベントは、eventキーワードを使用して宣言できます。
//Declare an Event
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
//Emit an event
emit Deposit(msg.sender, _id, msg.value);
例
Solidityでイベントがどのように機能するかを理解するには、次のコードを試してください。
最初に契約を作成し、イベントを発行します。
pragma solidity ^0.5.0;
contract Test {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value);
}
}
次に、JavaScriptコードで契約のイベントにアクセスします。
var abi =/*abi as generated using compiler*/;
var ClientReceipt = web3.eth.contract(abi);
var clientReceiptContract = ClientReceipt.at("0x1234...ab67"/*address*/);
var event = clientReceiptContract.Deposit(function(error, result) {
if (!error)console.log(result);
});
次のような詳細を印刷する必要があります-
出力
{
"returnValues": {
"_from": "0x1111...FFFFCCCC",
"_id": "0x50...sd5adb20",
"_value": "0x420042"
},
"raw": {
"data": "0x7f...91385",
"topics": ["0xfd4...b4ead7", "0x7f...1a91385"]
}
}
堅牢性-エラー処理
Solidityは、エラー処理のためのさまざまな機能を提供します。 通常、エラーが発生すると、状態は元の状態に戻ります。 その他のチェックは、不正なコードアクセスを防止することです。 以下は、エラー処理で使用される重要な方法の一部です-
- * assert(bool condition)*-条件が満たされない場合、このメソッド呼び出しは無効なオペコードを引き起こし、状態に対して行われた変更は元に戻されます。 このメソッドは、内部エラーに使用されます。
- * require(bool condition)*-条件が満たされない場合、このメソッド呼び出しは元の状態に戻ります。 -このメソッドは、入力または外部コンポーネントのエラーに使用されます。
- * require(bool condition、string memory message)*-条件が満たされない場合、このメソッド呼び出しは元の状態に戻ります。 -このメソッドは、入力または外部コンポーネントのエラーに使用されます。 カスタムメッセージを提供するオプションを提供します。
- * revert()*-このメソッドは実行を中止し、状態に対して行われた変更を元に戻します。
- * revert(string memory reason)*-このメソッドは実行を中止し、状態に対して行われた変更を元に戻します。 カスタムメッセージを提供するオプションを提供します。
例
Solidityでのエラー処理の仕組みを理解するには、次のコードを試してください。
pragma solidity ^0.5.0;
contract Vendor {
address public seller;
modifier onlySeller() {
require(
msg.sender == seller,
"Only seller can call this."
);
_;
}
function sell(uint amount) public payable onlySeller {
if (amount > msg.value/2 ether)
revert("Not enough Ether provided.");
//Perform the sell operation.
}
}
revertが呼び出されると、次のように16進データが返されます。
出力
0x08c379a0 //Function selector for Error(string)
0x0000000000000000000000000000000000000000000000000000000000000020//Data offset
0x000000000000000000000000000000000000000000000000000000000000001a//String length
0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000//String data