1

What approach should be taken when a given contract requires from another to perform multiple transactions in a single call?

Should it be separated semantically, like any "normal" piece of code?

ContractA {

    changeState1() {

    }

    changeState2() {

    }
} 


ContractB {

    changeState1ContractA() {
        ContractA contractA = ContractA(address);
        contractA.changeState1();
    }

    changeState2ContractA() {
        ContractA contractA = ContractA(address);
        contractA.changeState2();
    }

    changeState1changeState2ContractA() {
        ContractA contractA = ContractA(address);
        contractA.changeState1();
        contractA.changeState2();
    }
}

Or instead should it be exposed as a new method -wrapping the 2 calls into 1, to be exposed as a single transaction? Losing that way the semantics, but favoring gass and latency economics.

ContractA {

    //Omitted

    changeState1changeState2() {
        changeState1();
        changeState2();
    }
} 


ContractB {

    //Omitted

    changeState1changeState2ContractA() {
        ContractA contractA = ContractA(address);
        contractA.changeState1changeState2();
    }
}

Which, utlimately, it leads me to my final question. How does ethereum internally compute several transactions when they have been called sequentially from another contract?

changeState1changeState2ContractA() {
    ContractA contractA = ContractA(address);
    contractA.changeState1();
    contractA.changeState2();
}

Thanks.

4

Be mindful of how to handle failure and exceptions. Fail hard, fail early, and make sure the whole thing fails together and the whole state is reverted if anything is out of place.

In practice, it usually means grouping dependencies (e.g. debits and credits) into a single operation so it can't wind up out of balance. Carefully consider what can go wrong, and prefer throw over return false - the opposite of other languages where we try to catch errors and deal with them. It's counter-intuitive, but we want it to throw hard at the first opportunity and revert the whole system to the pre-transaction state.

Re: your last question, they will execute in order. Next steps will wait for previous steps to complete. You can have quite a few interdependent contracts doing intricate work (subject to gas limit) and have the whole state change mined in a single block.

An airbags and parachutes approach would be to enclose conditions and "throw" in changeState1() and changeState2(), and return bool(success) that is true only if all goes well. You would therefore expect true and in the sender,

if(!contractA.changeState1()) throw; // halt processing and revert.
if(!contractA.changeState2()) throw; // halt processing and revert.

It's not known if contactA is known and trusted or if it's an untrusted wallet account. If it's an untrusted account, then your contract is open to re-entrance attack and you have a hidden problem. Nothing to worry about if contractA is part of your system of trusted code. Just be aware that all dialog with unknown contracts (including address.send()) needs to use defensive patterns to prevent widely understood attack methods.

Hope it helps.

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.