Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Greater than or equal operator not working correctly #2093

Closed
cryptophonic opened this issue Dec 26, 2015 · 9 comments
Closed

Greater than or equal operator not working correctly #2093

cryptophonic opened this issue Dec 26, 2015 · 9 comments

Comments

@cryptophonic
Copy link

Running geth on a private network, had a contract account with 10 ether (simple contract, testing deposits / withdrawals). Tried to withdraw exactly 10 ether and it failed. This is the contract:

contract Accounts {
    mapping(address => uint) accounts; 
    // Deposit
    function() {
        accounts[tx.origin] += msg.value;
    }
    function balance() constant returns(uint) {
        return accounts[msg.sender];
    }
    function withdraw(uint value) {
        if (accounts[tx.origin] >= value) {
            accounts[tx.origin] -= value;
            tx.origin.send(value);
        }
    }
}

The contract failed when using 10,000,000,000,000,000,000. However, it succeeded when using 9,999,999,999,999,999,999. Confirmed the account had exactly 10 ether. Therefore, it appears the geth >= operator in the EVM is failing the == part of the test.

@cryptophonic
Copy link
Author

Update: I can easily duplicate this. Using the simple contract code above and sending transactions using the 'Ethereum Wallet' Linux x64 0.3.7 client. I can deposit 10 ether, confirm the transaction, attempt to withdraw 10 ether and it will fail. If instead I attempt to withdraw 9,999,999,999,999,999,999 wei, it will succeed, leaving 1e-18 in the account when queried afterwards.

Note: this does NOT happen using the truffle/testrpc server. I only observe this running geth on my private testnet.

@karalabe
Copy link
Member

What version of solidity are you using for compiling the contract? Geth really just runs the EVM bytecode generated by solidity. Also just to note, the EVM does not have combined ">=" and "<=" opcodes, so Solidity needs to generate a more complex code to emulate these using ">" and "==". Could there be a bug in your locally installed Solidity? Not sure whether truffle uses its own Solidity compiler or the one on the machine. Might be worth a shot to update it and see.

@karalabe
Copy link
Member

@chriseth Do you know anything about a potential bug in the Solidity compiler with complex comparison operators? ^

@cryptophonic
Copy link
Author

Thanks for the feedback. I checked the versions of solidity - for the geth deploy (not working) the solc version installed in /usr/local/bin on my system is '0.2.0-0/Release-Linux/g++/int linked to libethereum-1.1.0-0/Release-Linux/g++/int'. The truffle package.json shows ""solc": "^0.1.5", but that appears to be referring to a different artifact: 'soljson-latest.js'. I'll experiment around with versions and report back if I discover anything new. Thanks..

@obscuren
Copy link
Contributor

obscuren commented Jan 4, 2016

@mjackson001 any news?

@cryptophonic
Copy link
Author

Got sidetracked with the holidays. I just attempted to duplicate from a fresh deploy and it's been working - with the same version of solc as mentioned above. It was easily duplicated previously, so I'm not sure what changed. The symptoms were so specific that I still feel like it's possible there may be a bug somewhere. At the time, I was playing with the BigNumber library so it could be there was something broken there as well.

Here's my setup:

Geth:
Version: 1.4.0-unstable
Protocol Versions: [63 62 61]
Network Id: 1
Go Version: go1.5.1
OS: linux
GOPATH=
GOROOT=/usr/lib/go

Solc:
Version: 0.2.0-0/Release-Linux/g++/int linked to libethereum-1.1.0-0/Release-Linux/g++/int

@chriseth
Copy link

chriseth commented Jan 6, 2016

I can't imagine this being a Solidity issue, it is just too basic usage.

@cryptophonic
Copy link
Author

Update: I am seeing this again and have some better information. It appears to be specifically related to using the Mist-based 'Ethereum Wallet' Linux x64 0.3.7 client to send the transactions. I can use a node.js command-line prompt to issue the web3 commands directly to geth over RPC and it works.

The procedure to duplicate is to compile the contract above to get the ABI, and deploy it. Then use the address and ABI to create a contract 'watch' in Ethereum Wallet. It should then be easy to observe, using the GUI to send transactions.

In the geth logs, it appears the transaction fails due to running out of gas. The Ethereum Wallet client tries to calculate the exact amount of gas (in this case 29018) and the 'out of gas' check in the geth logs also shows the gas consumed was exactly 29018 (cgas=29018). So, in theory it shouldn't be failing. Could the check for gas consumption be failing the equality check???? Why would sending 1 Wei less as a transaction parameter make a difference????

Note that there's no way to adjust the amount of gas from within the Ethereum Wallet gui so I'm not sure where to go from here. I'm guessing if I bumped it up to 29,019 gas the transaction might go through.

Ethereum GUI:
Estimated fee consumption: 0.0009509 ether (19,018 gas)
Provided maximum fee: 0.0014509 ether (29,018 gas)
Gas price: 0.05 ether per million gas

geth logs (verbosity 5):
I0109 17:58:52.862276 2722 worker.go:350] 🔨 Mined block (#3945 / 2a9788aa). Wait 5 blocks for confirmation
I0109 17:58:52.862617 2722 state_object.go:169] 2f6fa89c627bf2ce1ce4503cedea947cefb3074c: #408 14485516543750000000700 (- 1450900000000000)
I0109 17:58:52.862771 2722 state_object.go:169] 2f6fa89c627bf2ce1ce4503cedea947cefb3074c: #409 14485516543750000000700 (- 0)
I0109 17:58:52.862799 2722 state_object.go:161] f64d23f81ef81945525c5f38048b59d8ef2fc8c0: #0 1000000000000000001 (+ 0)
I0109 17:58:52.862942 2722 vm.go:142] running byte VM 7366c24a
I0109 17:58:52.863196 2722 vm.go:145] byte VM 7366c24a done. time: 235.113µs instrc: 75
I0109 17:58:52.863225 2722 state_transition.go:226] VM call err: Out of gas
I0109 17:58:52.863303 2722 state_object.go:161] 2f6fa89c627bf2ce1ce4503cedea947cefb3074c: #409 14485516543750000000700 (+ 0)
I0109 17:58:52.863380 2722 state_object.go:161] 2f6fa89c627bf2ce1ce4503cedea947cefb3074c: #409 14485516543750000000700 (+ 0)
I0109 17:58:52.863460 2722 state_object.go:161] 2f6fa89c627bf2ce1ce4503cedea947cefb3074c: #409 14485517994650000000700 (+ 1450900000000000)
I0109 17:58:52.863773 2722 state_processor.go:84] receipt{med=ec78ec65ba0bdd0851f5c8b10bbe72eecdcd4f1b3235e05df7707d6769284f07 cgas=29018 bloom=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[]}

@cryptophonic
Copy link
Author

I tried the identical function call directly from web3:

contract.withdraw(1000000000000000000, {gas: 50000})

and it succeeds with total gas consumed == 22082. So the 29018 gas above should have been more than enough. Very confused now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants