コンテンツへスキップ
0%

Solidityのselfdestructとは?

執筆者 John Favole

2023年9月25日 公開読了時間 1 分

アップデート: EIP-6049で提唱された通り、SelfdestructはShanghai Ethereumアップグレードで非推奨となりました。この記事は現在では古くなっており、この機能が以前どのように動作していたかのみを反映しています。

_Selfdestruct_はSolidityのキーワードで、開発者がコントラクトを終了させたいときに使われていました。2021年の研究論文「Why Do Smart Contracts Self-Destruct? Investigating the Selfdestruct Function on Ethereum」によると、約800のコントラクトが_selfdestruct_キーワードを含んでおり、Solidityを学ぶ上で重要な概念となっています。

この記事では、_selfdestruct_とは何だったかを定義し、その目的を説明し、Solidityスマートコントラクトでの_selfdestruct_の実装例を示します。

Selfdestructとは何か

Selfdestructは、コントラクトを終了させ、バイトコードをEthereumブロックチェーンから削除し、コントラクト内の資金を指定されたアドレスに送るために使われていたキーワードです。

_Selfdestruct_は2016年、EthereumブロックチェーンとDAO(分散型自律組織)がまだ形成期にあった頃に生まれました。最初期のDAOの1つがハッキングにより360万ETHを失いました。この攻撃はSolidityコントラクトの不変性のため、何日も続きました。当時はコントラクトを破棄する手段が存在しなかったため、初期のDAO開発者たちはさらなる悪用を防ぐためにブロックチェーン全体をフォークしました。

そのため、_selfdestruct_はセキュリティ上の脅威が発生した場合の非常口として作られました。当初は「suicide function」と呼ばれていましたが、Solidity v0.5.0以降、_selfdestruct_に名称が変更されました。

なぜ開発者はselfdestruct関数を使っていたのか

開発者が主にselfdestruct関数を使っていたのは、スマートコントラクトコードのセキュリティを向上させ、使われなくなったコントラクトを整理し、Ethereum資産を素早く移動させるためです。

_Selfdestruct_はスマートコントラクトをアップグレードする必要がある際に役立ちました。例えば、ERC-20フレームワークは、相互運用性のためにEthereum上のすべての代替可能トークンに対する標準実装です。ERC-20標準とインターフェースしないトークンは、他のコントラクトとやり取りするのが困難になります。

このような場合、開発者は現行のコントラクトをアップグレードするのではなく、新しいコントラクトに切り替えることになります。そのため、_selfdestruct_関数を使って現行のコントラクトから資金を取り出し、必要な機能を持つ新しいコントラクトを構築することができました。

開発者はまた、潜在的なセキュリティ上の脅威から守るために_selfdestruct_関数を使っていました。同じ2021年のselfdestructスマートコントラクトレポートによると、開発者がコントラクトのセキュリティ上の欠陥を発見した場合、_selfdestruct_関数によって欠陥のあるコントラクトを即座に終了させ、安全なコントラクトに置き換えることができました。

Selfdestructを使用する欠点は何か

Selfdestruct関数の欠点は、ERC-20トークンを回復できないことと、自己破壊後にトークンを再ルーティングできないことです。

通常、_selfdestruct_関数は、コントラクトの終了について適時に周知しなかった開発者によって呼び出されます。チームがアップデートを周知した場合でも、その情報が十分な速さで広まらないことがあります。その結果、一部の人々は破棄されたコントラクトがまだ稼働していると思い込んで資金を送ってしまう可能性があります。このような場合、資金は失われます。

_selfdestruct_を使用することの2つ目の欠点は、Ether(ETH)しか送金できず、アルトコインやERC-721トークン標準に従うNFTなどの他のERC-20トークンには対応していないことです。_selfdestruct_が一度呼び出されると、これらの資産は二度と回復できません。

なぜselfdestruct関数は危険だと考える人がいたのか

Selfdestruct関数は、悪意ある開発者がラグプルを実行しやすくしていました。

この関数により、開発者が_selfdestruct_を呼び出し、資金を自分の個人ウォレットに送ることが可能になっていました。このため、一部のプロトコルユーザーや開発者は、_selfdestruct_関数の使用について複雑な感情を抱いていました。

Selfdestructはどのように機能していたか

Selfdestructは、チェーンからコントラクトのバイトコードを消去し、流動性を指定されたアドレスに送り、その後開発者にガス代の一部を返金することで機能していました。

コントラクトはstateとfunctionsという2つの要素で構成されています。これらの要素がコントラクトの動作と呼び出し可能な関数を定義します。バイトコードを削除するということは、コントラクトを定義する要素が何もなくなり、コントラクトが呼び出し不可能になることを意味します。

_selfdestruct_関数には、破壊後にコントラクトの資金をどこに送りたいかを呼び出し元が示すための必須パラメータがありました。

ネガティブガスとは何か、なぜ重要なのか

ネガティブガスとは、開発者がselfdestruct関数を使用した際にEthereumチェーンが返金する取引手数料の一部を指します。

Ethereumは、ブロックチェーンからデータを削除することで生じるガスの節約分を呼び出し元に報酬として与えることで、_selfdestruct_関数の使用を促していました。コントラクトが_selfdestruct_関数を呼び出すと、取引に使用された総ガスの半分が呼び出し元に返金されました。

Selfdestructはコントラクトの履歴をEthereumブロックチェーンから削除するのか

いいえ、selfdestruct関数はEthereumチェーン上のコントラクトの履歴を削除しません — コントラクトのバイトコードのみを削除します。

Ethereumはブロックチェーンであり、公開台帳であり、相互接続されたノードのネットワークが常にブロックチェーンの状態のコピーを保持しています。そのため、_selfdestruct_関数を呼び出す前に行われたすべてのデータと取引は、オンチェーンに恒久的に記録され、変更することはできません。

Selfdestruct関数を呼び出した後、資金は永久に失われるのか

いいえとはい、両方です。既存のETHは関数の呼び出し元が指定した別のアドレスに送られますが、ERC-20トークンは失われます。

さらに、誰かがselfdestructされたコントラクト(つまり終了したコントラクト)に資金を送った場合、それらは再ルーティングされず、失われます。

Selfdestruct関数の例

このプログラムの目的は、コントラクト内のETHが一定量に達するまでNFTのミントを許可することです。その量に達すると、プログラムはすべてのEtherを最後にミントしたウォレットにボーナスとして送ります。各人は1 Etherで複数のNFTをミントできますが、一度に1つずつです。このコントラクトは本番環境での使用を意図したものではなく、あくまで例示目的です。

このミントコントラクトの主な問題は、コントラクトが終了条件を満たすのに十分な資金を持っているかどうかを確認するために「this.balance」を使用していることです。そのため、攻撃者は簡単に指定された上限を超える金額を送り込み、その後_selfdestruct_キーワードを使って資金を自分が宣言したコンストラクタにリダイレクトすることができます。

そのため、_selfdestruct_を使用する際、開発者は特定の条件を満たすために使う変数に注意を払う必要があります。コントラクトアドレスやコントラクト内の資金への参照は、人為的に操作される可能性があるため、使用を避けるべきです。

Selfdestruct関数の使い方

selfdestruct関数を初期化するのは簡単です。関数内で_selfdestruct_キーワードを使用し、selfdestruct関数が呼び出された後にコントラクトの資金を受け取れるpayableアドレスを指定するだけです。

Solidityのコースで一般的に教えられている_selfdestruct_関数の例を以下に示します。

このコードが行っていることは以下の通りです。

  • 関数の名前はdestroyです
  • パラメータはアドレスをapocalypseとして指定します
  • destroy関数が呼び出されると、アドレスはapocalypse変数を通じて指定されます
  • 関数の可視性はpublicとして宣言されているため、他のコントラクトからアクセスできます
  • 次に、_selfdestruct_キーワードを使用し、apocalypse変数をpayableとして宣言した後に渡します

さて、この関数はpublicであるため、潜在的なセキュリティ上の欠陥を表しています。これに対処するため、_onlyOwner_修飾子を追加するか、require文を使ってオーナーのみがdestroy関数を呼び出せることを確認することを検討できます。

Alchemyの Solidity開発者コースでSolidityとselfdestruct関数を学ぶ

_Selfdestruct_は、セキュリティ侵害が発生した際、開発者がコントラクトをアップグレードしたい場合、または古いコントラクトを削除する場合に、コントラクトを終了させるためのフェイルセーフとして機能していました。_selfdestruct_の使用についてはSolidity開発者コミュニティ内で今なお議論がありますが、この関数が導入されたことで多くの潜在的なハッキングから保護するのに役立ちました。

_selfdestruct_のような重要な関数についてさらに学び、より優れたSolidity開発者になるには、Alchemy Universityの無料の7週間Ethereumブートキャンプに申し込んでください。開発全般が初めての開発者であれば、Ethereumブートキャンプを始める前の前提条件として、Alchemyの3週間JavaScriptクラッシュコースが最適です。

Background gradient

ブロックチェーンで魔法を生み出す

Alchemyは、最も強力なweb3開発者向けプロダクトとツールを、豊富なリソース、コミュニティ、そして卓越したサポートと組み合わせて提供します。