7

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.

Ismael
  • 30,570
  • 21
  • 53
  • 96

0 Answers0