1

From reading I have surmised that it is impossible to get the return value of state changing calls. Consider this example.sol:

contract F {
  function createChildContract() public returns (address child) {
    child = address(new C());
  }
}

contract C { }

If I instantiate F, then call F.createChildContract() this will return the transaction receipt. This is reasonable, because the transaction will not have been mined yet. But is there not a way to wait on the transaction, then once it is mined get that child address that it returns?

Everywhere I look, I see people telling me it can't be done, and I should use Events: How do I get the return value of a solidity function with web3? How to get return values when function with argument is called? https://github.com/ethereum/web3.js/issues/1207

Fine, I'll use events - but I would like to understand why this not possible? It seems like something that should be very much possible.

EDIT: Clearly I'm not asking what the difference between a transaction and a call is, because I make it clear that it is a call, specifically a state-changing call. The second dup - I can't even.

marked as duplicate by flygoing, shane, Ismael, Rosco Kalis, Achala Dissanayake Feb 9 at 2:21

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • But is there not a way to wait on the transaction, then once it is mined get that child address that it returns? - The "convention" is to wait at least 12 blocks (12*16 seconds on mainnet) after it is mined, which guarantees in a reasonably high probability that the transaction is there for good. – goodvibration Feb 7 at 10:16
  • why this not possible? - as you said - the transaction will not have been mined yet (so you've technically answered yourself). – goodvibration Feb 7 at 10:17
  • @goodvibration crazy idea, read what I wrote. – The Burger King Feb 7 at 10:20
  • I did, and I answered both your questions. If you're not satisfied with the answers, then I suggest that you explain why instead of responding sarcastically (!), and I might be able to update them accordingly. – goodvibration Feb 7 at 10:26
  • Perhaps you missed this: "But is there not a way to wait on the transaction, then once it is mined get that child address that it returns?" – The Burger King Feb 7 at 10:36
2

impossible to get the return value of state changing calls.

If it is state-changing, it is not a call. It's a transaction.

Consider this example.sol:

It doesn't compile.

If I instantiate F

You can't do that, because it doesn't compile.

then call F.createChildContract()

We have to make some assumptions about you want to do so we're talking about something that works.

You could create a new C and return the address:

address c = new Child();
return c;

Or, possibly return the address of child if it is a C that was properly instantiated previously/elsewhere, e.g. C child = C(addressC);

return address(child);

If you call the function, you will indeed receive an address. These just won't be a contract there because it was a read-only activity. If you send it a transaction, you will get a receipt.

But is there not a way to wait on the transaction, then once it is mined get that child address that it returns?

Yes. There are several ways to do that. It is a client-side responsibility. The blockchain is concerned with processing or rejecting the transaction. It is not concerned with client-side interpretation.

Everywhere I look, I see people telling me it can't be done, and I should use Events

That is one of the ways a client can be informed about an on-chain state transition. You can also use the receipt and poll the blockchain until you see the transaction is mined. In either case and at every stage, you have the option of inspecting the contract state.

For emphasis, it's a client-side responsibility to decide how many confirmations are acceptable, etc.. This library may help: https://gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6

A little more explanation: Optimal way of waiting for transactions to be mined in geth

So, basically:

return myContract.doSomething();})
.then(function(txnHash) {return getTransactionReceiptMined(txnHash);})
.then(function(receipt) { //... it's mined once

That can be improved for readability with async/await.

I would like to understand why this not possible

There is logical issue with relieving clients of their responsibility. Let me show you a conundrum.

Suppose we have a simple contract:

pragma solidity 0.5.1;

contract OrderMatters {

    // the children's game of tag

    address it; 

    constructor() public {
        it = msg.sender;
    }

    function tagYoureIt(address _newIt) public returns(address newIt) {
        require(msg.sender == it); // only "it" can tag someone else
        it = _newIt;
        return it;
    }
}

Further suppose we have three transactions signed and sent simultaneously:

  • A - Alice deploys the contract
  • B - Alice tags Bob
  • C - Bob tags Carol

Mining disambiguates the order.

Suppose it goes, A, B, C. B returns Bob and C returns Carol.

But wait! Suppose there is chain reorganization and the cannonical chain reverses the order, so now it goes, C, B, A. C and B are invalid because there is no contract. They return an error.

What if the order is shuffled again? Say, A, C, B? C returns an error cause Carol isn't "it". B returns Bob.

There will eventually be a stable cannonical transaction order but this is far from certain after only one or two confirmations and it can have an effect on outputs. A system that tries to address this has to deal not only with the callback and result, but also with the possibility that it needs to recall a prevision emission and revise the result. It's not an easy thing to work out a catch-all solution that somehow balances speed and confidence for all dapps.

So, clients have all the primitives they need to work out something satisfactory. That's how it probably should be because it's not a one-approach-fits-all type of problem. And the node/EVM-level teams favor minimalism in any case. I believe those are the reasons why.

Hope it helps.

  • 1. This question is not a duplicate. – Peter Prographo Feb 11 at 9:50
  • 2. The short answer is because that information is not stored on-chain. If it were stored on-chain it would be part of the consensus data as events are. Why did they chose to only have events? I am not aware of the rationale behind the design decision. If someone knows please leave a comment and let me know. – Peter Prographo Feb 11 at 9:53

Not the answer you're looking for? Browse other questions tagged or ask your own question.