I am running into some very strange state inconsistencies in my solidity contract.. its within a Library about 6 calls deep.
The repo is here: https://github.com/slothbag/hierarchical-dao
The problem area is here: https://github.com/slothbag/hierarchical-dao/blob/master/contracts/libdao_proposal.sol#L77
If I do this
for (uint a = 0; a < state.members[prop.proposedBy].compulsoryApprovers.length; a++)
it works fine, but if I do this:
LibDAO_State.Member proposedByMember = state.members[prop.proposedBy];
for (uint a = 0; a < proposedByMember.compulsoryApprovers.length; a++)
Then length has some random value in it like 17893473586 and the contract consumes all gas.
That is very strange already, but I discovered if I do something like this:
LibDAO_State.Member proposedByMember = state.members[prop.proposedBy];
log0(bytes32(proposedByMember.compulsoryApprovers.length));
for (uint a = 0; a < proposedByMember.compulsoryApprovers.length; a++)
Then it works again.. now why would a log0() fix the values within the struct??
It seems to me the values in the struct are ok, but the reference to them is not correct.
There are other inconsistencies in the function too, but the example above is the one i tested the most.
This is really tricky to reproduce.. probably easiest if I set up the steps on testnet and produce the failed tx for others to check using getTransactionReceipt. Or maybe I just run it and post the Receipt here??
well first we'd have to see the generic types of the struct. Would you mind sharing?
It's all contained in the repo linked to in the OP.
All the state structs can be found in this contract https://github.com/slothbag/hierarchical-dao/blob/master/contracts/libdao_state.sol
I was just playing around with that remix web based contract debugger, its not bad.. I could probably set up the reproducible error locally and allow access to my geth RPC to any devs who want to step through the tx and see whats going on.
Or perhaps I can trigger the error on testnet, then anyone can step through the tx I guess.
actually sounds nice
I am having a similar problem as OP. I managed to reproduce the effect with a small set of contract code. If you deploy this contract and call the Trigger method, the public value Debug will be set to a consistently invalid value.
My interim solution was to eliminate nested calls, btw.
EDIT: Eliminating nested calls didn't help, actually. Arrays of Arrays, similar to OP's situation, were demonstrating the inconsistency regardless of nesting. I switched to Mappings of Mappings, and the problem went away.
EDIT2: Also worth noting that Mappings of Arrays didn't fix the problem.
EDIT3: For clarity, in my example linked above we have an outer array of structs, with each struct containing an inner array (effectively, an "Array of Arrays"). This didn't work. What worked was a mapping to a struct containing another mapping (a "Mapping of Mappings"). I incur a little overhead keeping track of the mapping keys but otherwise it does the job.
Well done @chejazi, hard to tell if its exactly the same issue as both contracts operate quite differently.. but it seems somewhere along the line solidity is getting 'out of sync' with reality the deeper in the call stack you get. :(
I'm surprised this issue has not received much attention given the demonstrated dire consequences of contracts not performing as they are designed. To me this seems like a critical issue??
It's on my list of things to do. Trust me. I have not forgotten.
@VoR0220 starting on this now
I was able to reproduce the behaviour two days ago using https://gist.github.com/chejazi/ccfc84342261e61923b05340744145cd , but not able anymore now.
Ah ok, it seems to be a problem with the optimizer (I thought I reproduced it without optimizer).
I found there was a strange sequence of events to trigger the issue, like after several txs trying to zero out an array element (as opposed to setting it to something non zero)..
I can try recreate the problem for you, but its going to take me a while to remember the sequence.. lol
I reproduced "something", not sure if it is the same bug
I updated the Github repo links in the OP. They work now :)
Simplified the contract: https://gist.github.com/chriseth/3514a465ab4b7d8168f53d786bd0df7c
Well done @chriseth! I will try it out when the latest solidity builds are released.
Most helpful comment
@VoR0220 starting on this now