ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

WTF Solidity 超シンプル入門: Solidity の制御フローと挿入ソート(InsertionSort)実装の落とし穴

WTF Solidity 超シンプル入門: Solidity の制御フローと挿入ソート(InsertionSort)実装の落とし穴 WTF Solidity 超シンプル入門: Solidity の制御フローと挿入ソートInsertionSort実装の落とし穴【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-SoliditySolidity の制御フローif-else・for・while・do-while・三項演算子を体系的に学び、その知識を活かして「挿入ソート」を Solidity で実装します。本記事は WTF-Solidity の第 10 講日本語版をベースに、リポジトリ内の実源码10_InsertionSort/InsertionSort.solと突き合わせながら、uintの underflow が引き起こすバグの原因と正しい回避策を解説します。読了後は、Solidity 特有の型制約符号なし整数を意識した安全なループ実装ができるようになります。Solidity の制御フローSolidity の制御フローは他のプログラミング言語JavaScript・Python などとほぼ同様で、以下の構成要素を持ちます。1.if-else条件分岐の基本形です。_number 0のときtrueを、それ以外のときfalseを返します。function ifElseTest(uint256 _number) public pure returns(bool){ if(_number 0){ return(true); }else{ return(false); } }2.forループ初期化式・条件式・更新式を 1 行にまとめた繰り返し処理です。下記は0 1 ... 9を計算して45を返します。function forLoopTest() public pure returns(uint256){ uint sum 0; for(uint i 0; i 10; i){ sum i; } return(sum); }3.whileループ条件がtrueの間、処理を繰り返します。forと同じ計算結果45を返します。function whileTest() public pure returns(uint256){ uint sum 0; uint i 0; while(i 10){ sum i; i; } return(sum); }4.do-whileループwhileと異なり、条件を後置するため、条件の真偽にかかわらず少なくとも 1 回は処理を実行します。function doWhileTest() public pure returns(uint256){ uint sum 0; uint i 0; do{ sum i; i; }while(i 10); return(sum); }5. 三項演算子条件演算子三項演算子は Solidity で唯一 3 つのオペランドを受け取る演算子です。構文は条件 ? 条件が true のときの式 : 条件が false のときの式で、if-else文のショートカットとして頻繁に使われます。// 三項演算子 ternary/conditional operator function ternaryTest(uint256 x, uint256 y) public pure returns(uint256){ // x と y の最大値を返す return x y ? x : y; }この 5 つの関数はすべてリポジトリ内の 10_InsertionSort/InsertionSort.solおよび Languages/ja/10_InsertionSort_ja/InsertionSort.solにそのまま実装されています。pure指定のため、状態変数を読まず計算のみを行う関数である点も確認できます。補足:continueとbreak上記に加えて、continue現在の反復をスキップして直ちに次のループへ進むとbreak現在のループから抜け出すキーワードが利用可能です。Solidity で挿入ソートInsertionSortを実装する先に注意: 90% 以上の人が Solidity で挿入ソートを初回実装すると間違える、と言われています。本章ではその「間違い」と「正解」の両方を追体験します。挿入ソートとはソートアルゴリズムは、順不同の数値列例:[2, 5, 3, 1]を小さい順[1, 2, 3, 5]に並べ替える問題を解きます。挿入ソートInsertionSortは最もシンプルで、コンピュータサイエンスの授業で多くの開発者が最初に学ぶアルゴリズムです。そのロジックは次の 1 点に集約されます。配列xの先頭から末尾に向かって、要素x[i]をその直前の要素x[i-1]と比較する。x[i]が小さければ位置を入れ替え、さらにx[i-2]と比較し、この過程を続ける。つまり「カードを手札に挿入していく」感覚で、左側に常にソート済みの部分配列を構築していきます。Python での実装基準となるアルゴリズムまず教科書的な Python 実装を見てみましょう。keyを基準値として、前方の要素を順にずらしながら挿入位置を探します。# Insertion Sort を実装する Python プログラム def insertionSort(arr): for i in range(1, len(arr)): key arr[i] j i-1 while j 0 and key arr[j] : arr[j1] arr[j] j - 1 arr[j1] key return arrこの実装の要点は、jが-1になる可能性があることですループ内でj - 1が実行されるため。Python の整数は符号付きなので問題ありませんが、これが Solidity に移植した際に致命傷となります。Solidity への移植バグ入りバージョンPython 版約 9 行の関数・変数・ループを Solidity 構文に置き換えると、こちらも約 9 行で書けます。// 挿入ソート間違いバージョン function insertionSortWrong(uint[] memory a) public pure returns(uint[] memory) { for (uint i 1;i a.length;i){ uint temp a[i]; uint ji-1; while( (j 0) (temp a[j])){ a[j1] a[j]; j--; } a[j1] temp; } return(a); }一見正しそうに見えます。しかし、このコードをコンパイルして[2, 5, 3, 1]をソートしようとすると、実行時にエラーrevertが発生します。Remix の decoded output にはエラー内容が表示されます。バグの正体:uintの underflow問題を特定するのに数時間を要し、最終的に判明した原因は次のとおりです。Solidity で最もよく使われる整数型uint正確にはuint256は符号なし整数であり、負の値を表現できません。上記コードでは変数jがj--によって-1になろうとします。Solidity 0.8.x 以降はデフォルトで算術オーバーフロー/アンダーフロー検査が有効化されており、uintが負方向に桁あふれunderflowするとトランザクション全体が revert します。実際にリポジトリの源码 10_InsertionSort/InsertionSort.sol には誤バージョンがそのまま残されており、ソースコード中でもuint ji-1;とj--の組み合わせが問題を生むことが確認できます。プロジェクト全体のコンパイラは foundry.toml のsolc 0.8.34で固定されており、このバージョンではデフォルトの算術検査により underflow が確実に revert として顕在化します。正しい Solidity 実装バグ修正版修正方針はシンプルです:jが決して負の値を取らないように、jに 1 を加えて基準をずらす。つまりjを「挿入位置の右隣のインデックス」として扱います。// 挿入ソート正確なバージョン function insertionSort(uint[] memory a) public pure returns(uint[] memory) { // 注意: uint 型は負の値を取れない for (uint i 1;i a.length;i){ uint temp a[i]; uint ji; while( (j 1) (temp a[j-1])){ a[j] a[j-1]; j--; } a[j] temp; } return(a); }修正点の比較:項目誤バージョン正バージョン初期値uint j i - 1;i1のときj0、その後-1に陥るuint j i;常に非負ループ条件j 0常に真になり得るj 1jが 0 になった時点で終了比較対象temp a[j]temp a[j-1]ずらし処理a[j1] a[j]a[j] a[j-1]挿入位置a[j1] tempa[j] tempjの取りうる範囲が1..a.length-1に限定されるため、a[j-1]の添え字も常に0以上となり、underflow も範囲外アクセスも発生しません。[2, 5, 3, 1]を入力すると[1, 2, 3, 5]が正しく返ります。リポジトリ内での活用例この第 10 講のソート関数は、以降の講義でも再利用されています。例えばインターフェースの講義14_Interface/Interface.solでは、挿入ソートを外部関数として抽象化した宣言function insertionSort(uint[] memory a) public pure virtual returns(uint[] memory);が定義されており、インターフェースを介してソートロジックを呼び出す実例として登場します。第 10 講の実装をマスターすることで、このような抽象化・再利用パターンも自然に理解できるようになります。なお、10_InsertionSort/readme.md中文版や Languages/en/10_InsertionSort_en/readme.md英語版にも同じ内容のチュートリアルがあり、多言語で比較学習が可能です。源码は 10_InsertionSort/InsertionSort.sol にInsertionSortコントラクトとして一式制御フロー 5 関数 誤・正 2 バージョンのソートがまとまっているため、Remix に貼り付けるか Foundry 環境forge buildでそのままコンパイル・実行して確認できます。まとめ本講では、Solidity の制御フローif-else/for/while/do-while/ 三項演算子、およびcontinue・breakを紹介し、それを用いて「一見簡単だが実はバグが発生しやすい」挿入ソートを実装しました。最大の学びは、Python など符号付き整数を扱う言語のアルゴリズムを Solidity に移植する際、uintの underflow という Solidity 特有の罠に注意しなければならないという点です。Solidity はシンプルに見えますが、型システムや算術検査の仕様に起因する罠が多く存在します。毎月、スマートコントラクトの小さなバグが原因でプロジェクトがハッキングされ、数百万ドル規模の損失が発生しています。安全なコントラクトを書くためには、基礎を確実にマスターし、継続的に練習を重ねることが不可欠です。【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表