I know that I can't get the return value from a transaction (How to get values returned by non constant transaction functions?), and non-constant functions have return value because they can be called from another contract (What's the point of returning a value in a non-constant function?).
For example in the following contract the function getUserData is non-constant because it modifies array allData
in contract storage:
pragma solidity ^0.4.15;
contract Storage {
mapping (uint => uint) public users;
uint[] public allData;
event SetUserData(uint userId, uint data);
function setUserData(uint userId, uint data) public {
require(users[userId] == 0);
// Stores user data
users[userId] = data;
// Stores user id
allData.push(userId);
SetUserData(userId, data);
}
function getUserData(uint userId) public returns (uint[] data) {
if (users[userId] != 0) {
// Will return user data but modifies contract storage
allData.length = 0; // Ignore previous data
allData.push(users[userId]);
return allData;
} else {
return data;
}
}
}
But when I call a non-contant function from javascript I do not get an error, instead I got the expected return value.
Testing in a private network with geth v1.7.1 this test passes, but with testrpc v4.1.3 it fails.
const Storage = artifacts.require("./Storage.sol");
contract('Storage', function(accounts) {
let storage;
before(async () => {
storage = await Storage.deployed();
});
it("Set user data", async () => {
// Stores user data
await storage.setUserData(4321, 7890);
// Get user data
const data = await storage.getUserData.call(4321);
assert.equal(data[0], 7890, 'Return user data');
// Check contract storage is not modified
const allData = await storage.allData.call(0);
assert.equal(allData, 4321, 'Return userId');
});
});
Is is defined behavior to eth_call
a non-constant function from javascript or it is an implementation detail of geth?
I'd like it to be defined behavior, but I understand that an implementation can return an error if I call non-constant function.
One minor difference is that in a constant function I can allocate arrays in memory, but I cannot dynamically grow them. But if I can use arrays in storage I can use push to grow them dynamically.