0

recently I am learning how to deploy and call smart contract on ethereum. I am working on a very simple contract as follows:

pragma solidity >=0.4.24 <0.6.0;
contract TestContract{

   uint public a;

   constructor() public 
   { 
       a = 2;
   }

   function addNumber(uint b) public
   {
       a = a + b;
   }

   function read() public view returns (uint)
   {
       return a;
   }
}

I firstly tried to deploy the contract on my private chain, with the geth compilied from current master default go-ethereum source code. Though the contract can be successfully deployed, calling function addNumber through web3 throws the following errors gas required exceeds allowance (1726103387) or always failing transaction。I have no idea why it is the case, because my private chain is on mining, and my account has enough ether given so small contract code.

Then I deployed the contract on an old version of go-ethereum, both deployment and calling function addNumber seemed fine in the first place, the web3 calling didn't return any error, but then I found function addNumber actually did't increase (b = 1 in my test case), a reamined to 0 despite many times of calling. I also checked the corresponding transactions in geth and learn they were already exits in a mined block.

Then I changed to compile the contract code using solidity ^0.4.0 (also remove constructor and keyword view as solidity ^0.4.0 does not support them), and deployed on chain. In this case, the contract works fine for both version of go-ethereum. namely, a is increased whenever calling function addNumber with b = 1

So my question is:

  1. why calling addNumber in a recent version of go-ethereum throws error: gas required exceeds allowance (1726103387) or always failing transaction.
  2. why the same contract behaves totally different in different version of go-ethereum and solidity.
  3. In my opinion, the smart contract is 'too smart'. Is there any idea to choose between different version of go-ethereum and solidity?
  • The first question was just solved by specifying gas usage by changing from var hash = contract.addNumber.sendTransaction(1, {from: web3.eth.accounts[1]}) to var hash = contract.addNumber.sendTransaction(1, {from: web3.eth.accounts[1], gas: 30000000}) – X.S. Oct 30 at 7:14
0

Nothing in your contract should burn anywhere near 3 million gas, so you can be pretty sure it is a panicy gas burn to make the contract revert. Very often, all remaining gas is destroyed to make the evm abort and no amount of gas will address original problem.

Then I changed to compile the contract code using solidity ^0.4.0

You're in the ballpark.

The issue is EVM changes. You don't say what version of Geth and what version of Solidity, but those are the critical factors.

Generally, I do not like ^ in the pragma because it doesn't make clear, from a quick glance at the code, what compiler is being used, or what compiler one should use to replicate a result. And, here is the thing ...

Hard forks are protocol changes. With Byzantium, those changes affected the interface. The expected length was added, to support strings and other variable-length arguments in function signatures. Consequently, it was necessary to move to newer compilers that supported that feature.

In practice, that means if you compile your code with a compiler < 0.4.2.(4?) then you must use geth, ganache-cli, etc., below a certain version (pre-Byzantium) or it will not work. Similarly, if geth, ganache-cli are more recent, then you must compile with a more recent compiler.

Hope it helps.

p.s. As a style thing, I tend to use precise pragma's in top-level contracts because that removes the ambiguity, and ^ in inherited modules, for convenience and to try to strictly avoid tinkering with well-solved libraries.

Something like

pragma solidity 0.5.8;

contract MyContract {

   using SafeMath for uint;

Even if SafeMath contains ^ or >= <=, there is still no doubt it was compiled and tested with 0.5.8.

  • Thanks Rob, I just tested the contract on Rinkeby testnet with solidity compilier v0.5.12 and it worked fine. Towards my local private chain, the geth version is 1.9.6 and and solidity compilier is 0.5.12, in this case 'a' always remains as 0. The contract works fine for my private chain when geth is v1.9.6 and solidity compilier is v0.4.0. – X.S. Oct 31 at 5:26
  • One more question, you mentation that "if geth, ganache-cli are more recent, then you must compile with a more recent compiler.". So, how to interact with a contract that was deployed in very early geth compilied with early version of solidity, as all things have changed a lot. Is the contract even compatiable with current version of geth? If not, ethereum on-chain Dapps cannot be consistent and usable. – X.S. Oct 31 at 5:37
  • I'm not 100% sure about the precise reason, but I imagine it has to do with a newer compiler not supporting deprecated methods legacy contracts continue to use and deep down, the EVM still supports. Perhaps a kind soul will chime in the details. In any case, the practical side for contract devs is to know about the incompatibility. Thanks for accepting the answer if it was helpful. – Rob Hitchens - B9lab Oct 31 at 16:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.