Rustスマートコントラクト整数計算精度問題及び解決策

錆びたスマートコントラクト栽培日記 (7):整数計算精度問題

過去の振り返り:

  • Rustスマートコントラクト養成日記(1)合約状態データ定義とメソッド実装
  • Rustスマートコントラクト養成日記(2)編写Rustスマートコントラクト単体テスト
  • Rustスマートコントラクト育成日記(3)Rustスマートコントラクトのデプロイ、関数呼び出しおよびExplorerの使用
  • Rustスマートコントラクト育成日記(4)Rust スマートコントラクト整数オーバーフロー
  • Rustスマートコントラクト養成日記(5)重入攻撃
  • Rustスマートコントラクト養成日記(6)拒絶サービス攻撃

1. 浮動小数点演算の精度問題

Solidityとは異なり、Rustはネイティブで浮動小数点演算をサポートしています。しかし、浮動小数点演算には避けられない精度の問題があるため、特に重要な経済/金融の決定に関わる比率や金利を扱う際には、スマートコントラクトでの使用は推奨されません。

Rust は、浮動小数点数の表現に関する IEEE 754 標準に準拠しています。 f64 倍精度浮動小数点型は、コンピューターでは 2 進数科学表記法によって内部的に表されます。

いくつかの小数は有限桁数の二進数で正確に表現できます。例えば、0.8125は0.1101として表現できます。しかし、0.7のような小数は無限に循環する二進数表現が生成され、有限桁の浮動小数点数で正確に表現することができず、"丸め"の問題が存在します。

NEARブロックチェーン上で10人のユーザーに0.7 NEARトークンを配布する例:

さび #[test] fn precision_test_float() { 量を仮定します:f64 = 0.7;
除数をしましょう:f64 = 10.0;
let result_0 = amount / divisor;
println!("量の値: {:.20}", amount); assert_eq!(result_0, 0.07); }

実行結果は、amountの実際の値が0.69999999999999995559であり、result_0が0.06999999999999999であり、期待される0.07とは等しくないことを示しています。

この問題を解決するために、定点数を使用できます。NEARでは、通常1つのNEARトークンを10^24のyoctoNEARで表します。修正されたコード:


#[test] fn precision_test_integer() { N: u128 = 1_000_000_000_000_000_000_000_000_000_000_000;
量を仮定します: U128 = 700_000_000_000_000_000_000_000_000; 除数をしましょう:u128 = 10;
let result_0 = amount / divisor; assert_eq!(result_0, 70_000_000_000_000_000_000_000); }

こうすることで正確な結果が得られます:0.7 NEAR / 10 = 0.07 NEAR。

2. Rustの整数計算の精度に関する問題

整数演算は特定のシナリオで浮動小数点精度の問題を解決できますが、整数計算にも精度の問題があります。

2.1 操作の順序

同じレベルの乗除法では、順序の変更が結果に影響を与える可能性があります:

さび #[test] fn precision_test_div_before_mul() { Aを仮定します:U128 = 1_0000; Bを仮定します:U128 = 10_0000; Cを仮定します:U128 = 20;

let result_0 = a.checked_mul(c).unwrap().checked_div(b). unwrap();
result_1 = a.checked_div(b).unwrap().checked_mul(c). unwrap();

assert_eq!(result_0,result_1);

}

結果は、result_0 = 2、result_1 = 0を示しています。

理由は整数除算が除数未満の精度を切り捨てるからです。result_1を計算する際、(a / b)は最初に精度を失い0になります。一方、result_0は先に(a * c)を計算することで精度の損失を避けました。

2.2 小さすぎる数量

さび #[test] fn precision_test_decimals() { Aを仮定します:U128 = 10; Bを仮定します:u128 = 3; C:u128 = 4とします。 小数で仮定します:u128 = 100_0000;

let result_0 = a.checked_div(b).unwrap(928374656574839201.checked_mul)c(. unwrap)(;

let result_1 = a.checked_mul)decimal(.unwrap)(
                .checked_div)b(.unwrap)(
                .checked_mul)c(.unwrap)(
                .checked_div)decimal(.unwrap)(;

println!)"{}:{}", result_0, result_1(;
assert_eq!)result_0、result_1(;

}

結果はresult_0 = 12, result_1 = 13を示しており、後者は実際の値13.3333により近い。

! [])https://img-cdn.gateio.im/webp-social/moments-7bdd27c1211e1cc345bf262666a993da.webp(

3. 数値精算のためのRustスマートコントラクトの作成方法

精度を向上させるために、以下の対策を講じることができます:

) 3.1 操作の順序を調整する

整数の乗算を除算より優先させる。

3.2 整数の数の桁を増やす

より大きな数量を使用して、より大きな分子を作成します。例えば、1 NEAR = 10^24 yoctoNEARと定義します。

3.3 運用精度の累積損失

精度損失を記録し累積し、その後の計算で補償する:

さび 定数 USER_NUM: u128 = 3;

fn distribute###amount: u128, オフセット: u128( -> u128 { token_to_distribute = オフセット + 金額とします。 per_user_share = token_to_distribute / USER_NUMとします。 recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

#) fn record_offset_test[test]( { mutオフセットをしましょう:u128 = 0; 1から7までのiについて{ オフセット = distribute)10_000_000_000_000_000_000_000_000, offset(; } }

! [])https://img-cdn.gateio.im/webp-social/moments-1933a4a2dd723a847f0059d31d1780d1.webp(

) 3.4 では、Rust Crate ライブラリ rust-decimal を使用します

このライブラリは、高精度で丸め誤差のない小数金融計算を必要とする場合に適しています。

3.5 丸め機構を考慮する

スマートコントラクト設計において、丸めは通常「私に有利な」原則に従います: 下に切り捨てるのが有利であれば下に、上に切り上げるのが有利であれば上に、四捨五入はほとんど使用されません。

! []###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp(

EQ3.99%
原文表示
このページには第三者のコンテンツが含まれている場合があり、情報提供のみを目的としております(表明・保証をするものではありません)。Gateによる見解の支持や、金融・専門的な助言とみなされるべきものではありません。詳細については免責事項をご覧ください。
  • 報酬
  • 8
  • 共有
コメント
0/400
LostBetweenChainsvip
· 6時間前
整数計算すらできないのに、何の契約をするのか
原文表示返信0
WagmiWarriorvip
· 13時間前
第7篇が見えた、細かいな細かいな
原文表示返信0
MetaMisfitvip
· 23時間前
Rustこのスマートコントラクトの坑は多すぎるんじゃないかな
原文表示返信0
DuckFluffvip
· 07-22 22:44
おやおや、浮動小数点数がまた問題を起こしたな〜
原文表示返信0
MaticHoleFillervip
· 07-22 22:44
精度を犠牲にした経験を話します!
原文表示返信0
MetadataExplorervip
· 07-22 22:44
整数はしばしば無視されがちですが、非常に重要です。
原文表示返信0
MEVHuntervip
· 07-22 22:29
精度はメブハニーポットです... フロートをしっかり管理しないと、やられますよ
原文表示返信0
TrustlessMaximalistvip
· 07-22 22:16
この浮動小数点演算の罠は避けるべきです。
原文表示返信0
いつでもどこでも暗号資産取引
qrCode
スキャンしてGateアプリをダウンロード
コミュニティ
日本語
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)