This commit is contained in:
Ricardo Guilherme Schmidt 2018-04-23 02:12:55 -03:00
commit fade1238b3
5 changed files with 206 additions and 0 deletions

View File

@ -0,0 +1,35 @@
pragma solidity ^0.4.21;
/**
* @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
view
returns(address);
}

View File

@ -0,0 +1,90 @@
pragma solidity ^0.4.17;
import "../common/Controlled.sol";
contract Factory is Controlled {
event NewKernel(address newKernel, bytes32 codeHash);
struct Version {
uint256 blockNumber;
uint256 timestamp;
address kernel;
bytes32 codeHash;
}
mapping (address => uint256) versionMap;
Version[] versionLog;
uint256 latestUpdate;
address latestKernel;
function Factory(address _kernel)
public
{
_setKernel(_kernel);
}
function setKernel(address _kernel)
external
onlyController
{
_setKernel(_kernel);
}
function getVersion(uint256 index)
public
view
returns(
uint256 blockNumber,
uint256 timestamp,
address kernel,
bytes32 codeHash
)
{
return (
versionLog[index].blockNumber,
versionLog[index].timestamp,
versionLog[index].kernel,
versionLog[index].codeHash
);
}
function getCodeHash(address _addr)
public
view
returns (bytes32 codeHash)
{
bytes memory o_code;
uint size;
assembly {
// retrieve the size of the code, this needs assembly
size := extcodesize(_addr)
}
require (size > 0);
assembly {
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
o_code := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(o_code, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(o_code, 0x20), 0, size)
}
codeHash = keccak256(o_code);
}
function _setKernel(address _kernel)
internal
{
require(_kernel != latestKernel);
bytes32 _codeHash = getCodeHash(_kernel);
versionMap[_kernel] = versionLog.length;
versionLog.push(Version({blockNumber: block.number, timestamp: block.timestamp, kernel: _kernel, codeHash: _codeHash}));
latestUpdate = block.timestamp;
latestKernel = _kernel;
emit NewKernel(_kernel, _codeHash);
}
}

View File

@ -0,0 +1,38 @@
pragma solidity ^0.4.21;
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
view
returns(address)
{
return kernel;
}
}

View File

@ -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
}

View File

@ -0,0 +1,28 @@
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 {
event InstanceUpdated(address oldKernel, address newKernel);
function UpdatableInstance(address _kernel)
Instance(_kernel)
public
{
}
function updateUpdatableInstance(address _kernel) external {
require(msg.sender == address(this));
InstanceUpdated(kernel, _kernel);
kernel = _kernel;
}
}