1

I have found a very interesting behaviour of the EVM and probably a missing check in solidity compilation.

Consider the following code:

contract RootContract {
    Simple public s;
    string public data;
    function RootContract() { s= new Simple();}
    function getSimpleData() constant returns(string out) {
        s.fillData(this);
        out=data;
    }
    function setData(string d) {data=d;}
}

contract Simple  {
    string public data;
    function setData(string d ){data=d;}
    function fillData(RootContract r) public {r.setData(data);}

}

The function getSimpleData is "constant" and therefore should not allow to modify any state data. But it calls Simple.fillData, that in turns call RootContract.setData.

But it compiles, and it works, except that the root contract data is not set, but the Simple contract data gets returned by the getSimpleData constant function.

> var comp=eth.compile.solidity("import '/Users/guenole/Ethereum/sources/Simple.sol';")
> var root=comp['/Users/xxx/sources/Simple.sol:RootContract']
> var RContract=contract(root.info.abiDefinition)
> var RContract=eth.contract(root.info.abiDefinition)
> var R=RContract.new( {from: eth.coinbase, data: root.code, gas:1000000})
> R.address // after mining
"0x51ecec3c403159dafc05538dc0783559772874d9"
> R.s()
"0x92f2700514a8ab3ac026d1d3119ab2677d1d083a"
> var simple=comp['/Users/xxx/sources/Simple.sol:Simple']
> var SContract=eth.contract(simple.info.abiDefinition)
> var S = SContract.at(R.s())
> S.setData("un test de chaine", {from: eth.coinbase, gas:100000})
> S.data() // after mining
"un test de chaine"
> R.getSimpleData() // without mining
"un test de chaine"
> R.data() // the data of R is not set
""

So this is actually odd. Anyone has a view that justify such behaviour? Now, the funny thing is that it tricks the EVM that is not able to have in RootContract a function like

function getSimpleData() constant returns(string) {
    return s.data();  // fails with usual Error: Return argument type inaccessible dynamic type is not implicitly convertible to expected type (type of first return variable) string memory
}
1

There's an explanation, partially illuminated here: http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions

The compiler does not enforce yet that a constant method is not modifying state.

As an informal explanation, when you call the constant function, you're requesting local execution, so no transaction will be submitted to the network; therefore, no state change for that function.

However, the locally running function calls a state-changing function. r.setData(data) would be an on-chain transaction, and nothing I can see prevents it from being submitted to the network. We can expect that much to create a state change. I believe this is what the docs allude to when they say "does not enforce".

Interesting that the docs (above) say "yet" which seems to imply a possible future breaking change to a contract like your example. I'd be leery about structuring things this way since expected behavior might depend on a tenuous assumption about a compiler edge case.

I'm not 100% sure what you're getting at with the last bit about return(string). In case it helps, it's not possible to pass strings between contracts at this time. Possibly not trickery and merely a known limitation.

Hope it helps.

  • Thanks. That clarifies. So maybe, when they will enforce the constant function check, they will allow returning variable data between contracts also. – Guenole de Cadoudal Feb 21 '17 at 0:14

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.