From b3025a5d80e179c242c11486d392bc0fe30caa87 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Wed, 28 Feb 2018 01:36:48 -0300 Subject: [PATCH] add upgradable instance factory and needed architecture --- contracts/deploy/DelegatedCall.sol | 35 ++++++++++++++++++++ contracts/deploy/Factory.sol | 45 ++++++++++++++++++++++++++ contracts/deploy/Instance.sol | 38 ++++++++++++++++++++++ contracts/deploy/InstanceStorage.sol | 15 +++++++++ contracts/deploy/UpdatableInstance.sol | 25 ++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 contracts/deploy/DelegatedCall.sol create mode 100644 contracts/deploy/Factory.sol create mode 100644 contracts/deploy/Instance.sol create mode 100644 contracts/deploy/InstanceStorage.sol create mode 100644 contracts/deploy/UpdatableInstance.sol diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol new file mode 100644 index 0000000..0526c76 --- /dev/null +++ b/contracts/deploy/DelegatedCall.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.4.17; + + +/** + * @title DelegatedCall + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Abstract contract that delegates calls by `delegated` modifier to result of `targetDelegatedCall()` + * Important to avoid overwriting wrong storage pointers is that never define storage to this contract + */ +contract DelegatedCall { + /** + * @dev delegates the call of this function + */ + modifier delegated { + //require successfull delegate call to remote `_target()` + require(targetDelegatedCall().delegatecall(msg.data)); + assembly { + let outSize := returndatasize + let outDataPtr := mload(0x40) //load memory + returndatacopy(outDataPtr, 0, outSize) //copy last return into pointer + return(outDataPtr, outSize) + } + assert(false); //should never reach here + _; //never will execute local logic + } + + /** + * @dev defines the address for delegation of calls + */ + function targetDelegatedCall() + internal + constant + returns(address); + +} diff --git a/contracts/deploy/Factory.sol b/contracts/deploy/Factory.sol new file mode 100644 index 0000000..19975d5 --- /dev/null +++ b/contracts/deploy/Factory.sol @@ -0,0 +1,45 @@ +pragma solidity ^0.4.17; + +import "../common/Controlled.sol"; + +contract Factory is Controlled { + + event NewKernel(address newKernel, bytes infohash); + + struct Version { + uint256 blockNumber; + uint256 timestamp; + address kernel; + bytes infohash; + } + mapping (address => uint256) versionMap; + + Version[] versionLog; + uint256 latestUpdate; + address latestKernel; + + function Factory(address _kernel, bytes _infohash) + public + { + _setKernel(_kernel, _infohash); + } + + function setKernel(address _kernel, bytes _infohash) + external + onlyController + { + _setKernel(_kernel, _infohash); + } + + function _setKernel(address _kernel, bytes _infohash) + internal + { + require(_kernel != latestKernel); + versionMap[_kernel] = versionLog.length; + versionLog.push(Version({blockNumber: block.number, timestamp: block.timestamp, kernel: _kernel, infohash: _infohash})); + latestUpdate = block.timestamp; + latestKernel = _kernel; + NewKernel(_kernel, _infohash); + } + +} \ No newline at end of file diff --git a/contracts/deploy/Instance.sol b/contracts/deploy/Instance.sol new file mode 100644 index 0000000..96c18d8 --- /dev/null +++ b/contracts/deploy/Instance.sol @@ -0,0 +1,38 @@ +pragma solidity ^0.4.17; + +import "./InstanceStorage.sol"; +import "./DelegatedCall.sol"; + +/** + * @title Instance + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Contract that forward everything through delegatecall to defined kernel + */ +contract Instance is InstanceStorage, DelegatedCall { + + function Instance(address _kernel) public { + kernel = _kernel; + } + + /** + * @dev delegatecall everything (but declared functions) to `_target()` + * @notice Verify `kernel()` code to predict behavior + */ + function () external delegated { + //all goes to kernel + } + + /** + * @dev returns kernel if kernel that is configured + * @return kernel address + */ + function targetDelegatedCall() + internal + constant + returns(address) + { + return kernel; + } + + +} \ No newline at end of file diff --git a/contracts/deploy/InstanceStorage.sol b/contracts/deploy/InstanceStorage.sol new file mode 100644 index 0000000..ba84f64 --- /dev/null +++ b/contracts/deploy/InstanceStorage.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.17; + + +/** + * @title InstanceStorage + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Defines kernel vars that Kernel contract share with Instance. + * Important to avoid overwriting wrong storage pointers is that + * InstanceStorage should be always the first contract at heritance. + */ +contract InstanceStorage { + // protected zone start (InstanceStorage vars) + address public kernel; + // protected zone end +} \ No newline at end of file diff --git a/contracts/deploy/UpdatableInstance.sol b/contracts/deploy/UpdatableInstance.sol new file mode 100644 index 0000000..550df8d --- /dev/null +++ b/contracts/deploy/UpdatableInstance.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.4.17; + +import "./Instance.sol"; + + +/** + * @title UpdatableInstance + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Contract that can be updated by a call from itself. + */ +contract UpdatableInstance is Instance { + + function UpdatableInstance(address _kernel) + Instance(_kernel) + public + { + + } + + function updateUpdatableInstance(address _kernel) external { + require(msg.sender == address(this)); + kernel = _kernel; + } + +} \ No newline at end of file