1

I am trying to call a Smart contract that is supposed to return an address. I have tried the contract in Remix and It all works fine. I am know trying to execute the same contract using We3JS.

To do so I call web3.eth.sendTransaction(), then I wait for the blocked to be mined by comparing transactionReceit.gasUsed < transactionMinedResult.gas. When the block is mined I try to access to the block by calling web3.eth.getBlock(blockHash); It all seems to work and after a few seconds I get my block data back, it looks like this:

{
   "blockData":{
      "difficulty":"2004806",
      "extraData":"0xd783010509846765746887676f312e372e33856c696e7578",
      "gasLimit":4712388,
      "gasUsed":44328,
      "hash":"0xdaba1b785abec44f369dd661f457f829acc12ba02ed3e096db71a63801b2e02f",
      "logsBloom":"0x00000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000080000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000010000000000000000000000000000000000000000000000001000000000000000000000040000000000000000000000000200000000000",
      "miner":"0x5e5fd76c0ddbf6e594c33cde0c3fa8627d84d116",
      "mixHash":"0xc47e161dcf3f2c3d480bd7dfd5f1a8cbac45582d380d8203bd5a4949f4280fdf",
      "nonce":"0x4ee6e771c2773b25",
      "number":235186,
      "parentHash":"0x5cd9b5db1c3e000faa45ab6e92dae2b678fd00eb84c179f77b4f7fdcf689d047",
      "receiptsRoot":"0xa95a03ebe37e272941e71d357dc10dd57b64c7892bcd303c7cb4fdbd80281083",
      "sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
      "size":783,
      "stateRoot":"0x2b34eab5aa15aa6502785fb09ea9ae507306be88b0fb9317ab788bbcedd8e28c",
      "timestamp":1492124244,
      "totalDifficulty":"460326490665",
      "transactions":[
         "0xfb214080f50c9fae296b6ec928aeca9c2d3e3a15c33bd5a888845e0aff3950da",
         "0x533638638b9f97b05916a039d0e9da7200f2a1b944cd36294c6c293f0ca064bd"
      ],
      "transactionsRoot":"0xcc4c3f395caaf03b4a98d80cf5578b91fc33f078e4382539daf5824093402fd5",
      "uncles":[

      ]
   }
}

Like I said above my contract is returning an address, where can i find this returned data in the block data ?

EDIT 1

Here is the contract I am trying to call:

address[] public patients;
function getPatientAddress(uint id) public constant returns(address){
    LogPatientAddress(patients[id]);
    return patients[id];
}

Following the first answer it is indeed constant, therefore where is the data available from web3js ?

1

Javascript VM in Browser Solidity/Remix will return values to the external environment (like web3.js) for non-constant functions, however this is contrary to behaviour on the actual blockchain where non-constant functions only return a TX receipt to the external environment.

Constant functions eg, function foo() constant returns(uint) can return values to both environments.

This may leave a programmer (as in me) wondering why non-constant functions can return values. The fact is that they can return values to calls made from within the transaction.

So, consider to two following contracts ak and bk.

contract ak {
    uint public a;
    function set(uint val) returns (uint)
    {
        a = val;
        return a;
    }
}

If ak.set(123) is called by the client, then the state variable a is set to the value 123, but, though the function specifies return a, the client only receives the transaction receipt. For the client to get the actual value of a a second call to the public getter ak.a() is required.

Contrasting this to an inter-contract call where bk.set() calls ak.set() and receives an actual return value from ak.set() to successfully set bk.b.

contract bk {
    uint public b;
    function set(address _ak, uint val) returns (uint)
    {
        b = ak(_ak).set(val);
        return b;
    }
}

Running this code against an actual blockchain or TestRPC (by selecting Web3 provider in Browser Solidity or Remix) shows that a single client call to bk.set(<ak_address>,123) will set both ak.a and bk.b to the value 123 before returning the transaction receipt to the client but not the value of bk.b.

--Edit in response to OP edit--

Even though getPatientAddress(uint id) is modified as constant, a transaction is still generated because it calls the (presumably) non-constant function LogPatientAddress(patients[id]); which overrides the constant status.

However as this look like it should be a trivial getter we can simply modify the state variable declaration with public which will trigger the compiler to generate a constant getter function for us.

uint[] public patientIds;

will generate the getter function

function patientIds(uint _id) constant returns(uint);

Which can then be called from the JS client's contract instance (k)

var patientID = k.patientIds(<some_Value>);   
  • Ok understood, I have edited my question above with the function I am trying to call, as you can see it is a public constant function, therefore in web3js how could I get the value that this contract is returning ? – Rémi Apr 14 '17 at 1:27
  • Have updated answer accordingly. Is LogPatientAddress(patients[id]) intending to keep a log of all calls made to it? Is there a reason you need to do this? – o0ragman0o Apr 14 '17 at 1:51
  • No, not particularly it's just to verify that the contract works when i run it with Remix. – Rémi Apr 14 '17 at 1:52
  • Are you aware that a Solidity public state variable creates it's own getter function? So declaring something like mapping (uint => uint) public patientIds; will generate the getter function function patientIds(uint _id) constant returns (uint) which will return the value to your client – o0ragman0o Apr 14 '17 at 1:57
  • I was not no, so instead of having a simple address[] I could just have a mapping (uint => address) public patientIds; ? How then would I access this from web3JS ? – Rémi Apr 14 '17 at 2:00
2

If I understood you correctly you just need to call the function. It's not that complicated:

You said you're using web3js and the function of your contract is (solidity):

function getPatientAddress(uint id) public constant returns(address){
    LogPatientAddress(patients[id]);
    return patients[id];
}

In order to call this function from web3js the following should be enough (JavaScript):

// 1a) Get an object of your contract either by deploying it
var MyContract = MyContract.new([arg1] [, arg2], {data: '0x12345...', from: myAccount, gas: 1000000});

// 1b) or by using an existing intance
var MyContract = web3.eth.contract(abiArray);

// 2) instantiate your contract by address
var contractInstance = MyContract.at([address]);

// call your function and pass your result to a callback:
contractInstance.getPatientAddress.call(id, function(result) {
    // do something with your result
    console.log(result);
});

A transaction is a write-only operation on the blockchain. If you want to read a value from the blockchain you have to perform a call. You might want to look at this question for more information about the difference.

The Web3JS docs might help you, too.

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.