Masalah presisi perhitungan integer dalam smart contract Rust dan solusi

Rust smart contract pengembangan jurnal (7): masalah presisi perhitungan bilangan bulat

Tinjauan Masa Lalu:

  • Buku Harian Pengembangan Smart Contract Rust (1) Definisi Data Status Kontrak dan Implementasi Metode
  • Buku Harian Pengembangan Smart Contract Rust ( Menulis Unit Test Smart Contract Rust
  • Rust smart contract pengembangan jurnal )3( Penerapan smart contract Rust, pemanggilan fungsi, dan penggunaan Explorer
  • Rust smart contract diary )4( Rust smart contract integer overflow
  • Buku Harian Pengembangan Smart Contract Rust )5( Serangan Reentrancy
  • Buku Harian Pengembangan Kontrak Pintar Rust )6( serangan penolakan layanan

1. Masalah presisi dalam perhitungan floating point

Berbeda dengan Solidity, Rust mendukung operasi angka desimal secara native. Namun, operasi angka desimal memiliki masalah presisi yang tidak dapat dihindari, sehingga tidak disarankan untuk digunakan dalam smart contract, terutama saat menangani rasio atau suku bunga yang berkaitan dengan keputusan ekonomi/keuangan yang penting.

Rust mengikuti standar IEEE 754 untuk merepresentasikan angka floating point. Tipe floating point ganda f64 di dalam komputer diwakili dengan notasi ilmiah biner.

Beberapa desimal dapat direpresentasikan secara tepat dalam jumlah bit biner yang terbatas, seperti 0.8125 yang dapat direpresentasikan sebagai 0.1101. Namun, desimal seperti 0.7 akan menghasilkan representasi biner yang berulang tanpa henti, sehingga tidak dapat direpresentasikan dengan tepat menggunakan floating point yang terbatas, dan terdapat masalah "pembulatan".

Dalam contoh distribusi 0,7 token NEAR kepada 10 pengguna di blockchain NEAR:

karat #) fn precision_test_float[test]( { let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
println!)"Nilai dari jumlah: {:.20}", amount(; assert_eq!)result_0, 0.07(; }

Hasil yang ditampilkan menunjukkan bahwa nilai sebenarnya dari amount adalah 0.69999999999999995559, result_0 adalah 0.06999999999999999, yang tidak sama dengan yang diharapkan yaitu 0.07.

Untuk menyelesaikan masalah ini, dapat digunakan bilangan tetap. Di NEAR, biasanya 1 token NEAR dinyatakan dengan 10^24 yoctoNEAR. Kode yang telah dimodifikasi:

karat
#) fn precision_test_integer[test]( { let N: u128 = 1_000_000_000_000_000_000_000_000;
let amount: u128 = 700_000_000_000_000_000_000_000; let divisor: u128 = 10;
let result_0 = amount / divisor; assert_eq!)result_0, 70_000_000_000_000_000_000_000(; }

Dengan cara ini, kita bisa mendapatkan hasil yang akurat: 0,7 NEAR / 10 = 0,07 NEAR.

2. Masalah Presisi Perhitungan Integer Rust

Meskipun operasi bilangan bulat dapat menyelesaikan masalah presisi angka desimal dalam beberapa skenario, namun perhitungan bilangan bulat juga memiliki masalah presisi.

) 2.1 Urutan Operasi

Operasi perkalian dan pembagian pada tingkat yang sama, perubahan urutan dapat mempengaruhi hasil:

karat

fn precision_test_div_before_mul[test]( { let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;

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

assert_eq!)result_0,result_1(;

}

Hasil menunjukkan result_0 = 2, result_1 = 0.

Alasannya adalah bahwa pembagian bilangan bulat akan mengabaikan presisi yang kurang dari pembagi. Saat menghitung result_1, )a / b( kehilangan presisi menjadi 0; sedangkan result_0 terlebih dahulu menghitung )a * c( yang menghindari kehilangan presisi.

) 2.2 jumlah yang terlalu kecil

karat

fn precision_test_decimals[test]( { let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;

let result_0 = a.checked_div)b(.unwrap)(.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(;

}

Hasil menunjukkan result_0 = 12, result_1 = 13, yang terakhir lebih mendekati nilai aktual 13.3333.

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

3. Bagaimana Menulis Kontrak Pintar Rust untuk Aktuaria Numerik

Untuk meningkatkan akurasi, langkah-langkah berikut dapat diambil:

) 3.1 Menyesuaikan Urutan Operasi

Biarkan perkalian bilangan bulat diutamakan dibandingkan pembagian.

3.2 Meningkatkan urutan angka bulat

Gunakan skala yang lebih besar untuk menciptakan molekul yang lebih besar. Misalnya, definisikan 1 NEAR = 10^24 yoctoNEAR.

3.3 kehilangan akurasi perhitungan akumulasi

Mencatat dan mengakumulasi kehilangan presisi, kemudian mengompensasi dalam perhitungan selanjutnya:

karat const USER_NUM: u128 = 3;

u128 { let token_to_distribute = offset + amount; let per_user_share = token_to_distribute / USER_NUM; let recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

fn record_offset_test() { let mut offset: u128 = 0; untuk i dalam 1..7 { offset = distribute[test]10_000_000_000_000_000_000_000_000, offset(; } }

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

) 3.4 Menggunakan pustaka Rust Crate rust-decimal

Perpustakaan ini cocok untuk perhitungan finansial desimal yang memerlukan presisi tinggi dan tanpa kesalahan pembulatan.

( 3.5 Pertimbangkan mekanisme pembulatan

Dalam desain smart contract, pembulatan biasanya mengikuti prinsip "menguntungkan saya": jika pembulatan ke bawah menguntungkan saya, maka ke bawah; jika pembulatan ke atas menguntungkan saya, maka ke atas; jarang menggunakan pembulatan empat dan lima.

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

EQ2%
Lihat Asli
Halaman ini mungkin berisi konten pihak ketiga, yang disediakan untuk tujuan informasi saja (bukan pernyataan/jaminan) dan tidak boleh dianggap sebagai dukungan terhadap pandangannya oleh Gate, atau sebagai nasihat keuangan atau profesional. Lihat Penafian untuk detailnya.
  • Hadiah
  • 8
  • Bagikan
Komentar
0/400
LostBetweenChainsvip
· 07-25 17:53
Tidak bisa menghitung bilangan bulat, bermain kontrak apa?
Lihat AsliBalas0
WagmiWarriorvip
· 07-25 11:45
Melihat artikel ke-7, halus sekali.
Lihat AsliBalas0
MetaMisfitvip
· 07-25 01:13
Rust ini banyak sekali jebakan kontrak cerdas, ya.
Lihat AsliBalas0
DuckFluffvip
· 07-22 22:44
Wah, angka desimal sekali lagi bermasalah~
Lihat AsliBalas0
MaticHoleFillervip
· 07-22 22:44
Akibat pengalaman buruk dengan presisi!
Lihat AsliBalas0
MetadataExplorervip
· 07-22 22:44
Bagian integer ini sering diabaikan, padahal sangat penting.
Lihat AsliBalas0
MEVHuntervip
· 07-22 22:29
presisi adalah sebuah mev honeypot... jaga flotasi Anda ketat atau akan terkena ser
Lihat AsliBalas0
TrustlessMaximalistvip
· 07-22 22:16
Operasi floating point ini harus dihindari.
Lihat AsliBalas0
Perdagangkan Kripto Di Mana Saja Kapan Saja
qrCode
Pindai untuk mengunduh aplikasi Gate
Komunitas
Bahasa Indonesia
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)