Rust contratos inteligentes numéricos: guia de prevenção de armadilhas e melhores práticas

Rust contratos inteligentes中的数值精算

Na programação de contratos inteligentes, a precisão dos cálculos numéricos é especialmente importante. Este artigo explorará os problemas comuns de cálculo numérico em contratos inteligentes Rust e suas soluções.

1. Problema de precisão em operações de ponto flutuante

A linguagem Rust suporta nativamente operações com números de ponto flutuante, mas essas operações apresentam problemas de precisão de cálculo que não podem ser evitados. Ao lidar com taxas ou juros que envolvem decisões econômicas/financeiras importantes, não é recomendável utilizar operações com números de ponto flutuante.

O tipo de ponto flutuante de dupla precisão f64 na linguagem Rust segue o padrão IEEE 754 e utiliza a notação científica com base 2. Certos números decimais (, como 0.7), não podem ser representados com precisão por números de ponto flutuante de comprimento fixo, resultando em fenômenos de "arredondamento".

Por exemplo, ao distribuir 0.7 tokens NEAR na blockchain NEAR para 10 usuários:

ferrugem let amount: f64 = 0.7;
let divisor: f64 = 10.0; let result_0 = amount / divisor;

o valor real de amount é 0.69999999999999995559, o resultado de result_0 é 0.06999999999999999, e não o esperado 0.07.

Para resolver este problema, pode-se considerar o uso da representação de números fixos. No Protocolo NEAR, normalmente usa-se 10^24 como denominador, ou seja, 1 NEAR = 10^24 yoctoNEAR. A forma de cálculo modificada é a seguinte:

ferrugem 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;

Desta forma, é possível obter resultados de cálculo precisos: 0,7 NEAR / 10 = 0,07 NEAR.

2. Problema da precisão no cálculo de inteiros em Rust

Embora o uso de cálculos inteiros possa resolver problemas de precisão de ponto flutuante em certos cenários, ainda existem alguns fatores que afetam a precisão dos cálculos.

2.1 Ordem das operações

A mudança na ordem de multiplicação e divisão com a mesma prioridade aritmética pode afetar diretamente o resultado do cálculo. Por exemplo:

ferrugem let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;

// result_0 = a * c / b let result_0 = a.checked_mul(c).expect("ERR_MUL").checked_div(b).expect("ERR_DIV");

// result_1 = a / b * c let result_1 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");

O resultado de result_0 e result_1 é diferente porque a divisão inteira descarta a precisão inferior ao divisor.

2.2 quantidade muito pequena

Quando se trata de cálculos em escalas menores, isso também pode levar a problemas de precisão:

ferrugem let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;

// result_0 = (a / b) * c let result_0 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");

// result_1 = (a * decimal / b) * c / decimal;
let result_1 = a.checked_mul(decimal).expect("ERR_MUL") .checked_div(b).expect("ERR_DIV") .checked_mul(c).expect("ERR_MUL") .checked_div(decimal).expect("ERR_DIV");

o resultado da operação entre result_0 e result_1 é diferente, e result_1 está mais próximo do valor esperado real.

3. Como escrever contratos inteligentes de cálculo numérico em Rust

Para aumentar a precisão dos cálculos numéricos em contratos inteligentes Rust, podem ser tomadas as seguintes medidas:

3.1 Ajustar a ordem das operações

Deixe a multiplicação de inteiros ter prioridade sobre a divisão de inteiros.

3.2 aumentar a ordem de grandeza dos inteiros

Usar uma magnitude maior para criar moléculas maiores e aumentar a precisão dos cálculos.

3.3 perda de precisão nos cálculos acumulados

Para os problemas de precisão de cálculo inteiro que não podem ser evitados, pode-se considerar registrar a perda de precisão acumulada nas operações. Por exemplo:

ferrugem 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 }

Este método pode compensar gradualmente a perda de precisão em múltiplas distribuições.

( 3.4 Usando a biblioteca Rust Crate rust-decimal

Esta biblioteca é adequada para cálculos financeiros decimais que requerem precisão eficaz e não apresentam erro de arredondamento.

) 3.5 Considerar o mecanismo de arredondamento

Ao projetar contratos inteligentes, os problemas de arredondamento geralmente seguem o princípio "Quero me beneficiar, os outros não podem me explorar". Escolha arredondar para baixo, arredondar para cima ou arredondar para o mais próximo, conforme a situação.

Ao adotar esses métodos, é possível aumentar significativamente a precisão e a confiabilidade dos cálculos numéricos em contratos inteligentes Rust.

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

Ver original
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
  • Recompensa
  • 3
  • Partilhar
Comentar
0/400
MaticHoleFillervip
· 17h atrás
Passar o dia preso em problemas de precisão e perder esforços em vão.
Ver originalResponder0
StablecoinAnxietyvip
· 17h atrás
É um pouco complicado ter que lidar com algoritmos e finanças ao mesmo tempo~
Ver originalResponder0
GhostAddressMinervip
· 18h atrás
Mais um caso típico de transferir a responsabilidade de um problema de precisão para o padrão, sem saber quanto dinheiro foi liquidado em segredo, os dados na cadeia não mentem.
Ver originalResponder0
  • Pino
Negocie cripto em qualquer lugar e a qualquer hora
qrCode
Digitalizar para transferir a aplicação Gate
Novidades
Português (Portugal)
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)