3

I set up the following contract:

pragma solidity ^0.4.25;

contract Simplest {
    uint x;

    constructor(bool _lucky) public {
        if (_lucky == true) {
            x = 7;
        } else {
            x = 13;
        }
    }

    function view_x() public view returns (uint) {
        return x;
    }
}

with the expectation that the contract would have two different paths depending on what value the user provides in lucky_.

When I compile the contract (using Remix) to the following:

608060405234801561001057600080fd5b506040516020806101068339810180604052810190808051906020019092919050505060011515811515141561004d576007600081905550610056565b600d6000819055505b5060a1806100656000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a0be66d7146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600080549050905600a165627a7a723058206ff308044f195baf90e204067f39262c537f89c97f293ce31132bfb1d17655c20029

or

PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH2 0x106 DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE DUP2 ADD SWAP1 DUP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x1 ISZERO ISZERO DUP2 ISZERO ISZERO EQ ISZERO PUSH2 0x4D JUMPI PUSH1 0x7 PUSH1 0x0 DUP2 SWAP1 SSTORE POP PUSH2 0x56 JUMP JUMPDEST PUSH1 0xD PUSH1 0x0 DUP2 SWAP1 SSTORE POP JUMPDEST POP PUSH1 0xA1 DUP1 PUSH2 0x65 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x3F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0xA0BE66D7 EQ PUSH1 0x44 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x4F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x56 PUSH1 0x6C JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 PUSH16 0xF308044F195BAF90E204067F39262C53 PUSH32 0x89C97F293CE31132BFB1D17655C2002900000000000000000000000000000000 

Observation. As you see there is no CALLDATA related op-code in the first part of this contract.

Question. How is the contract able to load the input value for _lucky without looking at CALLDATA? Is the way constructors receive input values different from the way that normal contract functions receive input values?

1 Answer 1

5

In Solidity, arguments to the constructor are ABI encoded and appended to the compiled bytecode. The arguments are copied to the EVM memory using CODECOPY.

In Etherscan, you can see that the last bytes of a contract's "Contract Creation Code" are the ABI encoded "Constructor Arugments".

In Remix's "Compile" tab, the "Details" section has "Bytecode" and "Runtime Bytecode". When the "Bytecode", including constructor arguments, is executed in the EVM, it returns the "Runtime Bytecode". The "Runtime Bytecode" is what's on the blockchain at the contract's address.


Note that the EVM does not have functions or constructors. Functions are a result of the ABI and here is an example of How does the EVM find the entry of a called function?

This answer is how Solidity does constructors, and other languages may implement contract creation differently.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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