مشكلة دقة حسابات الأعداد الصحيحة في العقود الذكية بلغة Rust وحلولها

Rust العقود الذكية养成日记(7):整数计算精度问题

نظرة على الفترات السابقة:

  • يوميات تطوير العقود الذكية بلغة راست (1) تعريف بيانات حالة العقد وتنفيذ الطرق
  • يوميات تطوير العقود الذكية Rust (2) كتابة اختبارات وحدة للعقود الذكية Rust
  • Rust العقود الذكية养成日记(3)Rust العقود الذكية部署、函数调用及Explorer的使用
  • Rust العقود الذكية养成日记(4)Rust العقود الذكية整数溢出
  • Rust العقود الذكية养成日记(5)重入攻击
  • Rust العقود الذكية养成日记(6)拒绝服务攻击

1. مشكلة دقة العمليات العشرية

على عكس Solidity، تدعم Rust العمليات الرياضية العائمة بشكل أصلي. ولكن توجد مشاكل دقة لا مفر منها في العمليات العائمة، لذلك لا يُوصى باستخدامها في العقود الذكية، لا سيما عند التعامل مع النسب أو أسعار الفائدة التي تتعلق بالقرارات الاقتصادية/المالية الهامة.

تتبع Rust معيار IEEE 754 لتمثيل الأعداد العشرية. يتم تمثيل نوع النقطة العائمة مزدوج الدقة f64 في الداخل الكمبيوتر باستخدام الصيغة العلمية الثنائية.

يمكن تمثيل بعض الأعداد العشرية بدقة باستخدام عدد محدود من الأرقام الثنائية، مثل 0.8125 التي يمكن تمثيلها كـ 0.1101. لكن الأعداد العشرية مثل 0.7 ستنتج تمثيلًا ثنائيًا دوريًا غير محدود، مما يجعل من المستحيل تمثيلها بدقة باستخدام عدد محدود من الأرقام العشرية، مما يؤدي إلى مشكلة "التقريب".

في مثال توزيع 0.7 من رموز NEAR على 10 مستخدمين على سلسلة NEAR العامة:

صدأ #[test] الجبهة precision_test_float() { دع المبلغ: F64 = 0.7 ؛
دع المقسوم عليه: F64 = 10.0 ؛
دع result_0 = الكمية / القاسم ؛
println!("قيمة المبلغ: {:.20}", amount); assert_eq!(result_0 ، 0.07) ؛ }

نتيجة التشغيل تظهر أن القيمة الفعلية للمبلغ هي 0.69999999999999995559، وresult_0 هي 0.06999999999999999، وهي لا تساوي المتوقع 0.07.

لحل هذه المشكلة، يمكن استخدام الأعداد العشرية الثابتة. في NEAR، يتم عادةً تمثيل 1 رمز NEAR بـ 10^24 yoctoNEAR. الكود المعدل:

صدأ #[test] الجبهة الوطنية precision_test_integer() { دع N: u128 = 1_000_000_000_000_000_000_000_000_000 ؛
المبلغ اليدخ: U128 = 700_000_000_000_000_000_000_000 ؛ دع المقسوم: U128 = 10 ؛
دع result_0 = الكمية / القاسم ؛ assert_eq!(result_0, 70_000_000_000_000_000_000_000); }

يمكن الحصول على نتائج دقيقة بهذه الطريقة: 0.7 NEAR / 10 = 0.07 NEAR.

2. مشكلة دقة حسابات الأعداد الصحيحة في Rust

على الرغم من أن العمليات على الأعداد الصحيحة يمكن أن تحل بعض مشاكل دقة الأعداد العشرية في سيناريوهات معينة، إلا أن هناك أيضًا مشاكل في الدقة عند حساب الأعداد الصحيحة.

2.1 ترتيب العمليات

قد تؤثر تغييرات الترتيب على النتائج في ضرب وقسمة الأعداد من نفس المستوى:

صدأ #[test] الجبهة precision_test_div_before_mul() { دع أ: U128 = 1_0000 ؛ دع ب: U128 = 10_0000 ؛ دع C: U128 = 20 ؛

دع 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] الجبهة precision_test_decimals() { دع أ: u128 = 10 ؛ دع ب: u128 = 3 ؛ دع C: U128 = 4 ؛ دع الرقم العشري: U128 = 100_0000 ؛

دع result_0 = a.checked_div(b).unwrap().checked_mul(c). unwrap().

دع 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.

!

3. كيفية كتابة العقود الذكية Rust للتقييم العددي

لزيادة الدقة، يمكن اتخاذ التدابير التالية:

3.1 تعديل ترتيب عمليات الحساب

اجعل ضرب الأعداد الصحيحة أولوية على القسمة.

3.2 زيادة مرتبة العدد الصحيح

استخدم أعدادًا أكبر لإنشاء جزيئات أكبر. كما هو محدد 1 NEAR = 10^24 yoctoNEAR.

3.3 فقدان دقة العمليات التراكمية

تسجيل وتراكم خسارة الدقة، وتعويضها في العمليات الحسابية اللاحقة:

صدأ كونست USER_NUM: U128 = 3 ؛

الجبهة 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 }

#[test] الجبهة الوطنية record_offset_test() { دع إزاحة MUT: U128 = 0 ؛ للـ i في 1..7 { الإزاحة = distribute(10_000_000_000_000_000_000_000_000 ، offset) ؛ } }

!

3.4 استخدام مكتبة Rust Crate rust-decimal

تتناسب هذه المكتبة مع الحسابات المالية العشرية التي تتطلب دقة عالية وبدون أخطاء تقريب.

3.5 اعتبر آلية التقريب

في تصميم العقود الذكية، عادةً ما تتبع عملية التقريب مبدأ "في صالحي": إذا كان التقريب لأسفل في صالحي، يتم التقريب لأسفل، وإذا كان التقريب لأعلى في صالحي، يتم التقريب لأعلى، نادرًا ما يتم استخدام طريقة التقريب المعتادة.

!

EQ0.16%
شاهد النسخة الأصلية
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
  • أعجبني
  • 8
  • مشاركة
تعليق
0/400
LostBetweenChainsvip
· 07-25 17:53
لا يستطيعون حتى التعامل مع العمليات الحسابية الصحيحة، فما الذي سيلعبونه في العقود؟
شاهد النسخة الأصليةرد0
WagmiWarriorvip
· 07-25 11:45
رأيت المقال السابع، دقيق، دقيق.
شاهد النسخة الأصليةرد0
MetaMisfitvip
· 07-25 01:13
يبدو أن هناك الكثير من الفخاخ في العقود الذكية الخاصة بـ 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
الدقة هي وعاء العسل mev... احتفظ ب floats الخاصة بك محكمة أو ستتعرض للضرر يا صديقي
شاهد النسخة الأصليةرد0
TrustlessMaximalistvip
· 07-22 22:16
يجب تجنب هذه الفخاخ في العمليات العشرية.
شاهد النسخة الأصليةرد0
  • تثبيت