1. 程式人生 > >solidity測試指令碼:小心js裡坑爹的數值計算

solidity測試指令碼:小心js裡坑爹的數值計算

前天在除錯solidity程式碼時,發現一個極為詭異的行為:solidity中存數的數值,當使用web3取出的時候,數值是錯的——與solidity中的值對不上!
solidity中的程式碼大概是這樣的:

mapping (uint => uint) public data;
...
data[0] = 9901538745632159654;
data[data[0]] = 5901538745632159654;
...

測試指令碼是這樣的:

let begin= await MyContract.data(0);
let next = await MyContract.
data(begin.toNumber()); console.log("next :", next.toNumber());

結果發現next的值一直是0,而不是正確的5901538745632159654!

當我將begin這樣打出來之後,一切都瞭然了:

console.log("begin toNumber:", begin.toNumber(), ", begin toString:", begin.toString());

輸出:

begin toNumber: 9901538745632160000, begin toString:9901538745632159654 

在toNumber的過程中損失了精度!正確的測試程式碼應該這樣寫——避免使用toNumber:

let begin= await MyContract.data(0);
let next = await MyContract.data(begin);
console.log("next :", next.toString());

總結:

在需要nodejs與solidity有資料互動的時候,儘量避免使用toNumber,打日誌的時候使用toString,js傳引數給solidity的時候直接使用BigNumber,假如要在js中進行算數計算,應直接使用BigNumber的相關方法諸如plus進行算數計算。

後記:

之前solidity中使用的資料一直是比較整的,像這樣

data[0] = 1000000000000000000;
data[data[0]] = 3000000000000000000;

這樣的資料經過toNumber操作之後也是不會出問題的,只有零頭比較長的資料才會如此,就像9901538745632159654這種。