メインコンテンツへスキップ
Change page

スマート・コントラクトの構造

スマート・コントラクトは、イーサリアム上のアドレスで実行されるプログラムです。トランザクションを受信した際に実行できるデータと関数で構成されています。ここでは、スマート・コントラクトを構成する要素の概要を説明します。

前提条件

まず、スマート・コントラクトについて読んでおいてください。このドキュメントは、JavaScriptやPythonなどのプログラミング言語にすでに精通していることを前提としています。

データ

コントラクトのデータは、storageまたはmemoryのいずれかの場所に割り当てる必要があります。スマート・コントラクトのストレージを変更するにはコストがかかるため、データをどこに配置するかを考慮する必要があります。

ストレージ

永続的なデータはストレージと呼ばれ、状態変数によって表されます。これらの値はブロックチェーン上に永続的に保存されます。コンパイル時にコントラクトがブロックチェーン上でどれだけのストレージを必要とするかを把握できるように、型を宣言する必要があります。

// Solidityの例
contract SimpleStorage {
    uint storedData; // 状態変数
    // ...
}
# Vyperの例
storedData: int128

オブジェクト指向言語でのプログラミング経験があれば、ほとんどの型には馴染みがあるでしょう。ただし、イーサリアム開発が初めての場合、addressは新しい概念かもしれません。

address型は、20バイトまたは160ビットに相当するイーサリアムのアドレスを保持できます。先頭に0xが付いた16進数表記で返されます。

その他の型には以下のものがあります。

  • ブール値
  • 整数
  • 固定小数点数
  • 固定長バイト配列
  • 可変長バイト配列
  • 有理数および整数リテラル
  • 文字列リテラル
  • 16進数リテラル
  • 列挙型 (enum)

詳細な説明については、ドキュメントを参照してください。

メモリ

コントラクト関数の実行期間中のみ保存される値は、メモリ変数と呼ばれます。これらはブロックチェーン上に永続的に保存されないため、はるかに低コストで使用できます。

EVMがデータを保存する方法(ストレージ、メモリ、スタック)の詳細については、Solidityのドキュメント (opens in a new tab)を参照してください。

環境変数

コントラクトで定義する変数に加えて、いくつかの特別なグローバル変数が存在します。これらは主に、ブロックチェーンや現在のトランザクションに関する情報を提供するために使用されます。

例:

プロパティ状態変数説明
block.timestampuint256現在のブロックのエポックのタイムスタンプ
msg.senderaddressメッセージの送信者(現在の呼び出し)

関数

最も単純に言えば、関数は受信したトランザクションに応答して情報を取得したり、情報を設定したりすることができます。

関数呼び出しには2つのタイプがあります。

  • internal – これらはEVM呼び出しを作成しません
    • 内部関数と状態変数は、内部的に(つまり、現在のコントラクト内、またはそこから派生したコントラクト内から)のみアクセスできます。
  • external – これらはEVM呼び出しを作成します
    • 外部関数はコントラクトインターフェースの一部であり、他のコントラクトから、またはトランザクションを介して呼び出すことができます。外部関数fは内部的に呼び出すことはできません(つまり、f()は機能しませんが、this.f()は機能します)。

また、publicまたはprivateにすることもできます。

  • public関数は、コントラクト内から内部的に呼び出すことも、メッセージを介して外部から呼び出すこともできます。
  • private関数は、定義されているコントラクトでのみ可視であり、派生コントラクトでは可視ではありません。

関数と状態変数の両方をpublicまたはprivateにすることができます。

以下は、コントラクトの状態変数を更新するための関数です。

// Solidityの例
function update_name(string value) public {
    dapp_name = value;
}
  • string型のパラメータvalueが関数に渡されます: update_name
  • publicとして宣言されているため、誰でもアクセスできます。
  • viewとして宣言されていないため、コントラクトの状態を変更できます。

View関数

これらの関数は、コントラクトのデータの状態を変更しないことを保証します。一般的な例は「ゲッター」関数です。たとえば、ユーザーの残高を取得するために使用します。

// Solidityの例
function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerPizzaCount[_owner];
}
dappName: public(string)

@view
@public
def readName() -> string:
  return dappName

状態の変更とみなされる操作:

  1. 状態変数への書き込み。
  2. イベントの発行 (opens in a new tab)
  3. 他のコントラクトの作成 (opens in a new tab)
  4. selfdestructの使用。
  5. 呼び出し(call)によるイーサの送信。
  6. viewまたはpureとマークされていない関数の呼び出し。
  7. 低レベル呼び出し(low-level calls)の使用。
  8. 特定のオペコードを含むインラインアセンブリの使用。

コンストラクタ関数

constructor関数は、コントラクトが最初にデプロイされたときに1回だけ実行されます。多くのクラスベースのプログラミング言語におけるconstructorと同様に、これらの関数は多くの場合、状態変数を指定された値に初期化します。

# Vyperの例

@external
def __init__(_beneficiary: address, _bidding_time: uint256):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

組み込み関数

コントラクトで定義する変数や関数に加えて、いくつかの特別な組み込み関数が存在します。最もわかりやすい例は以下の通りです。

  • address.send() – Solidity
  • send(address) – Vyper

これらにより、コントラクトは他のアカウントにETHを送信できます。

関数の記述

関数には以下が必要です。

  • パラメータ変数と型(パラメータを受け取る場合)
  • internal/externalの宣言
  • pure/view/payableの宣言
  • 戻り値の型(値を返す場合)

完全なコントラクトは以下のようになります。ここでは、constructor関数がdapp_name変数に初期値を提供しています。

イベントとログ

イベントにより、スマート・コントラクトはフロントエンドや他のサブスクライブしているアプリケーションと通信できるようになります。トランザクションが検証されてブロックに追加されると、スマート・コントラクトはイベントを発行して情報をログに記録でき、フロントエンドはそれを処理して利用できます。

注釈付きの例

これらはSolidityで書かれたいくつかの例です。コードを試してみたい場合は、Remix (opens in a new tab)で操作できます。

Hello world

トークン

独自のデジタル資産

参考文献

スマート・コントラクトのより完全な概要については、SolidityとVyperのドキュメントを確認してください。