Solidity documentation says it is possible to use anything as mapping value, which I assume includes a contract:

_ValueType can actually be any type, including mappings.

but I couldn't find an example or documentation on how to work with it.

If I have the following mapping, how can I know if the contract in the mapping exists, or have suicided?

pragma solidity ^0.4.0;

contract MyContract {
  // ...
}

contract MappingExample {
    mapping(uint32 => MyContract) inner_contracts;

    function do_something(uint32 key) {
        MyContract c;
        if(/* inner_contracts[key] exists??? */) {
            c = inner_contracts[key];
        } else {
            c = new MyContract;
            inner_contracts[key] = c;
        }

        // do stuff with c
    }
}
  • I believe Solidity's contracts are not really types, in that they are special compared to other types. You should use mapping(uint32 => address) instead, and refer to this answer for checking whether the contract on a particular address exists. – Thegaram Dec 3 '17 at 19:46

Here is an example.

pragma solidity ^0.4.19;


contract InnerContract {
    uint public value;
    function setValue(uint new_value) {
        value = new_value;
    }
}

contract Contract {
    mapping(address => InnerContract) public contracts;

    function makeNew() {
        contracts[msg.sender] = new InnerContract();
    }
    function initialize() {
      contracts[msg.sender].setValue(3);
    }
    function get() constant returns (uint) {
      return contracts[msg.sender].value();
    }
}

If you play with this code, you'll notice that calling initialize before makeNew doesn't work. The reason is that mapping has default value filled with zeros. In case of contract it's not a good idea.

how can I know if the contract in the mapping exists, or have suicided?

Let's use another mapping for flags!

mapping(address => InnerContract) public is_contract_initialized;

If value is false(which is by default) then you should initialize your contract.

Even if it works it will probably be very expensive. A couple of suggestions.

  1. Store the deployed contract addresses (small), then instantiate the contracts as you need them: MyContract c = MyContract(theAddress);
  2. Avoid suicide/selfdestruct. It just creates sinks and invalid OPCODES. Instead, if you want to ensure a contract is retired, flip a bit and use a modifier like onlyIfRunning. You can make that variable public and then easily inspect it: if(c.isRunning()) {}
  3. You can potentially prune the list of deployed contracts but it's a rather more complex structure and it might be enough to just keep an append-only list as you go and use that isRunning() idea to ascertain which contracts are "shut down" and rejecting state-changes.

I made an example over here: Is There a Simple Contract Factory Pattern?

Hope it helps.

  • Are you sure mapping(uint32 => MyContract) isn't just a syntactic sugar for mapping(uint32 => address)? I thought MyContract(theAddress) was just a cast... – lvella Dec 3 '17 at 21:02
  • MyContract isn't an address. Variables cast as MyContract will have all the methods in the contract, whereas an address only has the methods that go with addresses. The sugar that might confuse the issue is that contract types are directly convertible to addresses. You can get away with returns(address theContract) { return c; }. I guess by "directly" they mean we don't have to explicitly recast them with something like return address(c); – Rob Hitchens B9lab Dec 3 '17 at 21:13
  • @RobHitchens,Storing it as MyContract enables us to call methods of that contract directly, but I couldn't validate the "being very expensive" statement. Why would it be? What extra information other than contract address would this "Contract type" include? Solidity at compile time verifies that methods you are calling are present. I was curious, so I tried it ethfiddle.com/yug3vEjOBk and whether you call addDbAsAddress or addDbAsInstance, it consumes about same amount of gas. The IdDatabase contract is long to verify that DbController doesn't stores contrat's function names/signatures – Patrik Stas Jun 16 at 5:41
  • You're bringing the whole bytecode of MyContract into MappingExample. The code for MyContract isn't shown, but let's say it's near the gasLimit because it's a complex beast. MappingExample will be that big plus additional bytecode for its own function. Multiple layers of this style lead to contracts that are too large to be deployed. This is what happens when you say MyContract c. You could just as well say MyContractInterface c and it would be smaller. ethereum.stackexchange.com/questions/5726/… – Rob Hitchens B9lab Jun 16 at 17:09

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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