3

Assume that I want to implement my own version of a suicide contract function with extended functionality. More specifically, I want to copy the internal storage state of the contract to a new contract address before I invalidate it. For example, I may have a mapping that stores users' tokens and I would like this information to be available in the new contract. I know that the delegatecall function can allow access to the contract's storage to other contract but what if I want to kill the initial contract.

One way that I thought this can be done is by adding a function in the contract like the following, where I explicitly write which data I want to be copied using the call function:

pragma solidity ^0.4.2;

contract Sample {
    uint public data;

    function setData(uint data_){
        data = data_;
    }

    function mySuicide(address newContract) {
        newContract.call(bytes4(sha3("setData(uint256)")), _n);
        suicide(newContract);
    }
}


contract NewContract {
    uint public data;

    function setData(uint data_){
        data = data_;
    }
}

However, the above example is simple as it is passing just a simple number.

So my questions are:

  1. Will I be able to copy a more complex structure such as a mapping (address => address) without exceptions being thrown because of gas limit?
  2. Is there any other more general approach?
  3. Is it possible to make this copy of data off-chain?

2 Answers 2

2

Yes, you can do that if you make your contract upgradable.

A brief description of the approach - Create DataLayer of contract as a separate contract(DataStore) and design the main contract in a way so that whenever you are going to kill your contract, you can link your old DataStore to the new Contract.

You can read this blog from one of my colleague which describes the upgradeability of smart contract.

Also, you can take a look at this repo for reference, the main contract here("Organization.sol") is upgradable.

1

I have seen the approach of separating the data from the functional contract. In this way you can share the data between contracts that want to use it.

You would need to write code in your contract and data contract that you as the owner could approve a contract access to your data.

contract MyDataContract {
    address contractOwner = msg.sender;

    mapping(address => bool) approvedAccess;   
    mapping(address => bytes) dataMap;

    function approveAccess(address _addressToApprove) {
        require(msg.sender==contractOwner);
        approvedAccess[_addressToApprove] = true;
    }

    function getData(address _userAddressData) returns(bytes data) {
        require(approvedAccess[msg.sender]);
        data = dataMap[_userAddressData];
    }

    function setData(address _userAddressData, bytes data) {
        require(approvedAccess[msg.sender]);
        dataMap[_userAddressData] = data;
    }
}

contract MyConsumerContract {
    address contractOwner;
    MyDataContract dataContract;

    function MyConsumerContract(address _dataContract) {
        contractOwner = msg.sender;
        dataContract = MyDataContract(_dataContract);
    }

    function doSomething() {
       bytes data = dataContract.getData(msg.sender);
       ...
       dataContract.setData(msg.sender, data);
    }
}

You could of course structure the data contract however you like and provide finer detail in getters and setters for particular data. But now you can share the data with other contracts, even after you destruct a contract that used to access it.

1
  • 1
    I realized after I posted this, that bytes is a dynamic array and therefore can not be consumed by a calling contract to another contract. You can use other data types though. Commented Aug 4, 2017 at 2:33

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.