ethereum / go-ethereum

Go implementation of the Ethereum protocol
https://geth.ethereum.org
GNU Lesser General Public License v3.0
47.3k stars 20.01k forks source link

int256 incorrectly converted to BigNumber #15716

Open 3sGgpQ8H opened 6 years ago

3sGgpQ8H commented 6 years ago

Hi there,

System information

Geth version: 1.7.3-stable-4bb3c89d OS & Version: Darwin MacBookPro 17.3.0

Expected behaviour

Constant method of smart contract has result type int256. It returns value: 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF (valid positive value for int256 type). When called via JS wrapper generated by geth based on contract ABI, return value is converted to BigNumber javascript object with value 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.

Actual behaviour

When called via JS wrapper generated by geth based on contract ABI, return value is converted to BigNumber javascript object with value -0x8000000000000000000000000000000000000000000000000000000000000001 (negative value that is actually not valid for int256 type)

Steps to reproduce the behaviour

Compile the following smart contract using Solidity 0.4.16:

pragma solidity ^0.4.16;
contract Bug {
  function x () pure returns (int256) {
    return 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
  }
}

Deploy contract, call function z() on it, convert returned BigNumber to string using .toString(16) and print it. The following will be printed:

-8000000000000000000000000000000000000000000000000000000000000001
favadi commented 6 years ago

This should be fixed with https://github.com/ethereum/go-ethereum/pull/17583.

3sGgpQ8H commented 5 years ago

Still reproducible on geth 1.8.23

adamschmideg commented 5 years ago

Explore first if it's an issue with web3.js or elsewhere.

karalabe commented 4 years ago

Repro:

var bugContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"x","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"pure","type":"function"}]);

var bug = bugContract.new(
   {
     from: web3.eth.accounts[0], 
     data: '0x6080604052348015600f57600080fd5b5060b78061001e6000396000f300608060405260043610603e5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630c55699c81146043575b600080fd5b348015604e57600080fd5b5060556067565b60408051918252519081900360200190f35b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905600a165627a7a7230582068e59c67b74dd0b0bc3a6fa39c7f327b41e3584c453b697b1eea3ca371295bbf0029', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

bug.x()
-5.7896044618658097711785492504343953926634992332820282019728792003956564819969e+76

bug.x().toString(16)
"-8000000000000000000000000000000000000000000000000000000000000001"

Note, Geth returns the correct value to web3.js:

eth.call({to: "0x8552f996da07efbf63b09fb4b727c5d24eefce9d", data: "0x0c55699c"})
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
karalabe commented 4 years ago

This is an issue in the web3.js version included in the Geth console. We'd need to update it, but it's not simple as web3.js changed their blocking APIs to promises. One day we'll probably get around to updating it, but for now I'd recommend not interacting with contracts via the console.