29

What would be on your list to warn other developers about?

What works in most other languages that does not work, or behave as expected, in Solidity?

For example only: what parameters can be passed to functions, what can be returned from functions?

1

6 Answers 6

21

Declaring a local array (or other reference type) and assuming that it will be created in memory but will actually overwrite storage:

/// THIS CONTRACT CONTAINS AN ERROR
contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x;
        x.push(2);
        data = x;
    }
}

The type of the local variable x is uint[] storage, but since storage is not dynamically allocated, it has to be assigned from a state variable before it can be used. So no space in storage will be allocated for x, but instead it functions only as an alias for a pre-existing variable in storage.

What will happen is that the compiler interprets x as a storage pointer and will make it point to the storage slot 0 by default. This has the effect that someVariable (which resides at storage slot 0) is modified by x.push(2).

The correct way to do this is the following:

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x = data;
        x.push(2);
    }
}

OR

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] memory x = new uint[](1);
        x[0] = 2;
        data = x;
    }
}
2
  • Can you PLEASE provide a code example? Commented Jun 15, 2017 at 9:04
  • @JossieCalderon Good call, thank you, hope it is much clearer.
    – eth
    Commented Jun 23, 2017 at 6:43
16

From the docs

In for (var i = 0; i < arrayName.length; i++) { ... }, the type of i will be uint8, because this is the smallest type that is required to hold the value 0. If the array has more than 255 elements, the loop will not terminate.

also

It is not yet possible to use arrays of arrays in external functions. ... You can only use one level of dynamic arrays [anywhere].

and

Due to limitations of the EVM, it is not possible to return dynamic content from external function calls. The function f in contract C { function f() returns (uint[]) { ... } } will return something if called from web3.js, but not if called from Solidity. The only workaround for now is to use large statically-sized arrays.

9
  • Always provide enough gas for a transaction (90% rookie bugs are because of not enough gas)
  • Exceptions will consume the whole transaction gas (use with caution)
  • It can't be verified easily if your contract throw an exception
  • It is not easy to check if your transaction run out of gas
  • Things may work with testnet, but can fail in a private testnet (check to make it working in both)
  • There's limited support for string without external libraries
  • Some functions can fail (like send), check the return value
  • Watch for reentrancy issues (specially when sending money or other kind of token)
6

string[] are not allowed in function parameters or returns.

refer to discussion here:
Is it impossible to use an array of strings as the argument to solidity function?

3

returns with named output parameters introduces new local variable.

E.g. from this question:

contract Test {
    address owner;

    function Test(){
        owner = msg.sender;
    }

    function getOwner() returns (address owner) {
        return owner;
    }
}

Here in getOwner new variable owner is introduced and initialized to zero. Coincidentally it overrides state variable owner which leads to unexpected result.


Mappings are only allowed for state variables (or as storage reference types in internal functions).

E.g. from this question:

function getBalance(address addr) returns (uint, uint) {
    mapping(address => uint)  balancers;
    balancers[msg.sender] = 500;

    return (balancesA[addr], balancesB[addr]);
}

Here mapping(address => uint) balances does not allocate new mapping but introduces uninitialized variable. Hence accessing balancers[msg.sender] is invalid.

2
  • Using delete on an array leaves a gap, so you need to shift items manually and update the length property.

  • string is the same as bytes but doesn't allow length or index access.

  • bytes is the same byte[] but packed tightly (more expensive).

  • Date suffixes can't be applied to variables.

  • Solidity inherits scoping rules from JavaScript; there is no block scoping.

For more solidity gotchas, check out https://github.com/miguelmota/solidity-idiosyncrasies

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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