4

Please correct me if I am wrong but I understand you cannot initialise a contract with a string array as it is a dynamic type but can I initalise a contract with a fixed type? specifically an array of addresses.

Also how would this be serialised if I am trying to deploy through bytecode?

4

Here's one solution that was used by the Whitehats distributing the retrieved ETCs to The DAO tokenholders on the Ethereum Classic chain.

From https://github.com/BitySA/whetcwithdraw/blob/master/daobalance/dao_balance_snapshot.sol:

// This contract publishes the balances of the DAO at the moment of the hardfork
// After the deployment of the contract the function fill is called many times
// in order to fill the balance of each account.


contract DAOBalanceSnapShot {

    uint constant D160 = 0x10000000000000000000000000000000000000000;

    mapping (address => uint) public balanceOf;

    address public owner;

    function DAOBalanceSnapShot() {
        owner = msg.sender;
    }


    uint public totalSupply;
    uint public totalAccounts;
    bool public sealed;

    // The 160 LSB is the address of the balance
    // The 96 MSB is the balance of that address.
    function fill(uint[] data) {
        if ((msg.sender != owner)||(sealed))
            throw;

        for (uint i=0; i<data.length; i++) {
            address a = address( data[i] & (D160-1) );
            uint amount = data[i] / D160;
            if (balanceOf[a] == 0) {   // In case it's filled two times, it only increments once
                totalAccounts ++;
                balanceOf[a] = amount;
                totalSupply += amount;
            }
        }
    }

    function seal() {
        if ((msg.sender != owner)||(sealed))
            throw;

        sealed= true;
    }
}

You can see that the addresses and balances are encoded as an array of uint256 data.

In this solution, the constructor was not used to initialise the array of addresses (and balances). But after construction, the fill(...) function was called repeatedly to construct the balanceOf mapping of addresses to balances. After all required balances were filled, the seal() function was called to indicate that the balances have all been filled.

This method of "filling" the data was the solution when over 11,000 items of addresses and balances was to be populated with the necessary data as the data would not have fitted into a single constructor call.

Reference: How do I convert my The DAO tokens into ethers on the Ethereum Classic chain?



Update With An Example

Here's an example:

pragma solidity ^0.4.4;

contract AddressArray {

    address[] addresses;

    function AddressArray(address[] addresses_) {
        for (uint i = 0; i < addresses_.length; i++) {
            addresses.push(addresses_[i]);
        }
    }

    function getNumberOfAddresses() constant returns (uint) {
        return addresses.length;
    }

    function getAddress(uint i) constant returns (address) {
        return addresses[i];
    }
}

I'll be constructing the contract using Browser Solidity with the following addresses as the parameter:

["0x000d1009bd8f0b1301cc5edc28ed1222a3ce671e", "0x0014060ff383c9b21c6840a3b14aab06741e5c49", "0x0020017ba4c67f76c76b1af8c41821ee54f37171", "0x0036f6addb6d64684390f55a92f0f4988266901b", "0x004e64833635cd1056b948b57286b7c91e62731c"]

Here's the Browser Solidity screen showing the successful deployment of the contract with the array of address parameter:

enter image description here

Here is the bytecode data from Browser Solidity:

606060405234610000576040516101f83803806101f8833981016040528080518201919060200150505b6000600090505b81518110156100f357600080548060010182818154818355818115116100825781836000526020600020918201910161008191905b8082111561007d576000816000905550600101610065565b5090565b5b505050916000526020600020900160005b848481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610030565b5b50505b60f4806101046000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b91905056

Before deploying the contract to my Dev blockchain, I switched on debug.verbosity(5) to view the transaction in raw format. Here is the data:

I0110 15:40:29.061385 core/tx_pool.go:542] Promoting queued transaction: TX(4856cf602e31c38000279f3fb1bdf3f13c475fac4e35f9cc67811e34ef0ceda4) Contract: false From: 000d1009bd8f0b1301cc5edc28ed1222a3ce671e To: [contract creation] Nonce: 17 GasPrice: 20000000000 GasLimit 281531 Value: 0 Data: 0x606060405234610000576040516101f83803806101f8833981016040528080518201919060200150505b6000600090505b81518110156100f357600080548060010182818154818355818115116100825781836000526020600020918201910161008191905b8082111561007d576000816000905550600101610065565b5090565b5b505050916000526020600020900160005b848481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610030565b5b50505b60f4806101046000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b9190505600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c490000000000000000000000000020017ba4c67f76c76b1af8c41821ee54f371710000000000000000000000000036f6addb6d64684390f55a92f0f4988266901b000000000000000000000000004e64833635cd1056b948b57286b7c91e62731c

In the data above, I have highlighted in bold the additional bytecode representing the parameters during the deployment of the contract.

Let us now reverse engineer the bytecode you need to build if you are planning to deploy through bytecode.

Here is the bolded data from the deployed bytecode, separated out:

0000000000000000000000000000000000000000000000000000000000000020 // 0x20 = 32. This is probably the offset to the start of the array data
0000000000000000000000000000000000000000000000000000000000000005 // There are five items in the array
000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e // 1st address
0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c49 // 2nd address
0000000000000000000000000020017ba4c67f76c76b1af8c41821ee54f37171 // 3rd address
0000000000000000000000000036f6addb6d64684390f55a92f0f4988266901b // 4th address
000000000000000000000000004e64833635cd1056b948b57286b7c91e62731c // 5th address

See the 2nd link below to try reverse engineering the parameter format, including the offset.

Lets Try Another Combination Of Parameters

Here another contract with additional constructor parameters:

pragma solidity ^0.4.4;

contract AddressArray {

    address[] addresses;

    function AddressArray(uint dummy1, address[] addresses_, uint dummy2) {
        for (uint i = 0; i < addresses_.length; i++) {
            addresses.push(addresses_[i]);
        }
    }

    function getNumberOfAddresses() constant returns (uint) {
        return addresses.length;
    }

    function getAddress(uint i) constant returns (address) {
        return addresses[i];
    }
}

I deployed the contract with the following parameters from Browser Solidity:

123, ["0x000d1009bd8f0b1301cc5edc28ed1222a3ce671e", "0x0014060ff383c9b21c6840a3b14aab06741e5c49"], 456

Here's the bytecode from Browser Solidity:

6060604052346100005760405161020c38038061020c833981016040528080519060200190919080518201919060200180519060200190919050505b6000600090505b825181101561010557600080548060010182818154818355818115116100945781836000526020600020918201910161009391905b8082111561008f576000816000905550600101610077565b5090565b5b505050916000526020600020900160005b858481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610042565b5b505050505b60f4806101186000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b91905056

Here's the geth transaction trace data, again with the additional parameter bytecode data bolded:

0x6060604052346100005760405161020c38038061020c833981016040528080519060200190919080518201919060200180519060200190919050505b6000600090505b825181101561010557600080548060010182818154818355818115116100945781836000526020600020918201910161009391905b8082111561008f576000816000905550600101610077565b5090565b5b505050916000526020600020900160005b858481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610042565b5b505050505b60f4806101186000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b91905056000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c80000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c49

And here's the parameter data, decoded:

000000000000000000000000000000000000000000000000000000000000007b // new BigNumber("7b",16) = 123
0000000000000000000000000000000000000000000000000000000000000060 // new BigNumber("60",16) = 96 or 3 x 32. This is the offset of the second parameter.
00000000000000000000000000000000000000000000000000000000000001c8 // new BigNumber("1c8",16) = 456
0000000000000000000000000000000000000000000000000000000000000002 // 2 array items
000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e // 1st address
0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c49 // 2nd address

See also:

  • I see for their use case but I wish to simply build and array of addresses with no mapping in the constructor by passing the 'data' type or otherwise. – Samuel Barnes Jan 10 '17 at 2:30
  • 1
    I understand myself how this could be adapted but for future reference I might have to add a more precise answer. – Samuel Barnes Jan 10 '17 at 2:36
  • 1
    See updated answer. – The Officious BokkyPooBah Jan 10 '17 at 4:57
  • 1
    I've added another example to show you the offset methodology of encoding the parameters. – The Officious BokkyPooBah Jan 10 '17 at 5:23

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.