浮動小数点数は「魔法の鍵」? それとも「泥棒の抜け道」?:Solidityの計算の罠を攻略する
こんにちは!Web3セキュリティの世界へようこそ。
普段、私たちが電卓アプリで「0.1 + 0.2」と打つと、当たり前のように「0.3」と表示されますよね。でも、ブロックチェーンの世界、特にSolidityという言語を使っていると、この「当たり前」が通用しなくなります。
今日は、スマートコントラクトを開発する新人の皆さんが最初にぶつかる壁、「浮動小数点数(ふどうしょうてんすう)問題」について、身近な例えを交えてお話しします。ここを理解しておかないと、あなたのコントラクトから大事な資産が少しずつ漏れ出す「泥棒の抜け道」を作ってしまうことになるかもしれません。
—
なぜSolidityは「小数」を使わせないのか?
まず、なぜSolidityには小数(0.5とか3.14とか)がないのでしょうか。
例えるなら、「Solidityは、極めて厳格でアナログな金庫の番人」だからです。
金庫に「0.5枚のコイン」を入れることはできませんよね?1枚か、0枚か。この世界では「整数(1, 2, 3…)」だけが正義なのです。
もし無理やり小数を使おうとすると、計算の過程で「端数(あまった0.000…1の部分)」が発生します。現実の銀行システムなら誤差は許容されますが、ブロックチェーン上でこれをやると、「塵も積もれば山となる」方式で、攻撃者がその誤差の隙間を縫ってコインを盗み出せてしまうのです。
攻撃者の狙い:誤差の隙間を突く「1円抜き」
攻撃者は、あなたがコードの中で適当に処理した「小数点以下の切り捨て」や「丸め誤差」を虎視眈々と狙っています。1回の取引では0.00001円の誤差でも、数万回繰り返せば……あなたのコントラクトの残高は空っぽになります。
—
対策:スケーリング係数で「整数」に変換しよう!
では、どうすれば小数を扱えるのでしょうか?
答えはシンプルです。「全部、拡大して整数にしてしまえばいい」のです。
これを「スケーリング」と呼びます。例えば、「1.23」という数値を扱いたいなら、すべてを100倍して「123」として計算するのです。
実践:固定小数点ライブラリの考え方
コードで見てみましょう。Solidityで最もよく使われる手法です。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleMath {
// 18桁の精度で計算するためのスケール係数(10の18乗)
// 通貨の単位を「円」から「0.00...1円」のレベルまで細分化するイメージです
uint256 constant SCALE = 10**18;
// 1.23を表現したい場合、1.23 * 10^18 として扱います
uint256 public myValue = 123 * 10**16;
// 計算を行う関数
function multiply(uint256 _amount, uint256 _rate) public pure returns (uint256) {
// 整数同士で掛け算をしてから、最後にスケール分を割ることで精度を維持します
// これなら小数を一切使わずに、正確な計算が可能です
return (_amount * _rate) / SCALE;
}
}
このコードのポイント
1. SCALEの定義: 10の18乗を使うのがWeb3の業界標準です(イーサリアムのwei単位と同じですね)。
2. 計算の順序: 必ず「掛け算をしてから、最後に割り算」をします。先に割り算をすると、その時点で値が切り捨てられてしまい、誤差が生まれるからです。
—
今日からできる「防犯対策」チェックリスト
スマートコントラクトを開発する際、以下のポイントを「家の鍵」を確認するようにチェックしてください。
- 「除算(割り算)」は最後にする: 途中で割り算を挟むと、値が削れてしまいます。
- 信頼できるライブラリを使う: 「Solmate」や「OpenZeppelin」といった有名プロジェクトが提供している数学ライブラリ(
FixedPointMathLibなど)を使いましょう。車輪の再発明は、セキュリティ事故の元です。 - 変数のオーバーフローに注意: 整数を使うと、数値を増やしすぎて限界(
2^256 - 1)を超えてしまうリスクがあります。Solidity 0.8.0以降であれば自動でエラーになりますが、常に「数値の桁数」は意識してください。
—
最後に:セキュリティは「泥臭い積み重ね」から
「小数の計算を避ける」なんて、最初は面倒に感じるかもしれません。でも、セキュリティのプロがやっていることは、実はこういう地味なルールの徹底です。
防犯と同じで、「完璧な金庫を作る」ことよりも、「隙間を作らない」ことが最も重要です。
今日学んだスケーリングの考え方をマスターして、あなたの書くコードを、誰にも破れない堅牢な金庫に育てていきましょう!
一歩ずつ、着実に。それが最強のセキュリティへの近道ですよ!
コメント