From c273f7ec1da532e6de77b6e4f398f99c6d879e95 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Tue, 28 Nov 2017 01:33:25 -0200 Subject: [PATCH 01/12] base structure of upgradable republic --- contracts/deploy/DelegatedCall.sol | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 contracts/deploy/DelegatedCall.sol diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol new file mode 100644 index 0000000..cbed2b4 --- /dev/null +++ b/contracts/deploy/DelegatedCall.sol @@ -0,0 +1,33 @@ +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 `_target()` + */ +contract DelegatedCall { + /** + * @dev delegates the call of this function + */ + modifier delegated { + require(_target().delegatecall(msg.data)); //require successfull delegate call to remote `_target()` + 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 _target() + internal + constant + returns(address); + +} From 86cf02e5f9959366b5550fe994fded2073a235e3 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 1 Dec 2017 04:45:26 -0200 Subject: [PATCH 02/12] recovery alpha + ens based recoverer --- contracts/deploy/DelegatedCall.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol index cbed2b4..8f42dea 100644 --- a/contracts/deploy/DelegatedCall.sol +++ b/contracts/deploy/DelegatedCall.sol @@ -11,14 +11,14 @@ contract DelegatedCall { * @dev delegates the call of this function */ modifier delegated { - require(_target().delegatecall(msg.data)); //require successfull delegate call to remote `_target()` + //require successfull delegate call to remote `_target()` + require(_target().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 } 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 03/12] 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 From d4b98d1186ff50f7d8bfff7612d795285a365f6d Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Wed, 28 Feb 2018 11:47:59 -0400 Subject: [PATCH 04/12] - Added event to inform of an identity instance upgrade - Added test units for Identity factory and its kernel upgrading --- contracts/deploy/UpdatableInstance.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/deploy/UpdatableInstance.sol b/contracts/deploy/UpdatableInstance.sol index 550df8d..60f6d0a 100644 --- a/contracts/deploy/UpdatableInstance.sol +++ b/contracts/deploy/UpdatableInstance.sol @@ -10,6 +10,8 @@ import "./Instance.sol"; */ contract UpdatableInstance is Instance { + event InstanceUpdated(address oldKernel, address newKernel); + function UpdatableInstance(address _kernel) Instance(_kernel) public @@ -19,6 +21,7 @@ contract UpdatableInstance is Instance { function updateUpdatableInstance(address _kernel) external { require(msg.sender == address(this)); + InstanceUpdated(kernel, _kernel); kernel = _kernel; } From 213e76d3a5f9bc1ac3aca11c12d5d4c7795c1cff Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Wed, 28 Feb 2018 14:52:32 -0400 Subject: [PATCH 05/12] Linting to reduce problems in IDE --- contracts/deploy/Instance.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/deploy/Instance.sol b/contracts/deploy/Instance.sol index 96c18d8..f9d60cb 100644 --- a/contracts/deploy/Instance.sol +++ b/contracts/deploy/Instance.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.17; import "./InstanceStorage.sol"; import "./DelegatedCall.sol"; + /** * @title Instance * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) From 266b1c3056d5679cd08aef314befed9cb2775344 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Sun, 11 Mar 2018 22:11:42 +0700 Subject: [PATCH 06/12] avoid overwrite of target function --- contracts/deploy/DelegatedCall.sol | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol index 8f42dea..0526c76 100644 --- a/contracts/deploy/DelegatedCall.sol +++ b/contracts/deploy/DelegatedCall.sol @@ -4,7 +4,8 @@ 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 `_target()` + * @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 { /** @@ -12,20 +13,21 @@ contract DelegatedCall { */ modifier delegated { //require successfull delegate call to remote `_target()` - require(_target().delegatecall(msg.data)); + 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 _target() + function targetDelegatedCall() internal constant returns(address); From 1424baafa9974ad2c4b7e9f5fbd712b264c324c2 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Sun, 11 Mar 2018 22:12:50 +0700 Subject: [PATCH 07/12] include SOB proposal for republic --- contracts/deploy/Instance.sol | 38 ++++++++++++++++++++++++++ contracts/deploy/InstanceStorage.sol | 15 ++++++++++ contracts/deploy/UpdatableInstance.sol | 25 +++++++++++++++++ 3 files changed, 78 insertions(+) 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/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 From 5466aeed49f5b618e7fe7b2e6b72018a407bcbad Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Tue, 13 Mar 2018 13:52:44 -0400 Subject: [PATCH 08/12] Changed name to function, and added view to Factory --- contracts/deploy/Factory.sol | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contracts/deploy/Factory.sol b/contracts/deploy/Factory.sol index 19975d5..f63bf71 100644 --- a/contracts/deploy/Factory.sol +++ b/contracts/deploy/Factory.sol @@ -31,6 +31,18 @@ contract Factory is Controlled { _setKernel(_kernel, _infohash); } + function getVersion(uint256 index) public view + returns(uint256 blockNumber, + uint256 timestamp, + address kernel, + bytes infohash) + { + return (versionLog[index].blockNumber, + versionLog[index].timestamp, + versionLog[index].kernel, + versionLog[index].infohash); + } + function _setKernel(address _kernel, bytes _infohash) internal { From 27d0fc24b68cc4c4c78784431fb869ce12de7e0b Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Tue, 27 Mar 2018 23:16:51 -0300 Subject: [PATCH 09/12] democracy , constitution and factory refactor --- contracts/deploy/Factory.sol | 71 ++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/contracts/deploy/Factory.sol b/contracts/deploy/Factory.sol index f63bf71..2408a58 100644 --- a/contracts/deploy/Factory.sol +++ b/contracts/deploy/Factory.sol @@ -4,54 +4,87 @@ import "../common/Controlled.sol"; contract Factory is Controlled { - event NewKernel(address newKernel, bytes infohash); + event NewKernel(address newKernel, bytes32 codeHash); struct Version { uint256 blockNumber; uint256 timestamp; address kernel; - bytes infohash; + bytes32 codeHash; } + mapping (address => uint256) versionMap; Version[] versionLog; uint256 latestUpdate; address latestKernel; - function Factory(address _kernel, bytes _infohash) + function Factory(address _kernel) public { - _setKernel(_kernel, _infohash); + _setKernel(_kernel); } - function setKernel(address _kernel, bytes _infohash) + function setKernel(address _kernel) external onlyController { - _setKernel(_kernel, _infohash); + _setKernel(_kernel); } - function getVersion(uint256 index) public view - returns(uint256 blockNumber, - uint256 timestamp, - address kernel, - bytes infohash) + 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].infohash); + return ( + versionLog[index].blockNumber, + versionLog[index].timestamp, + versionLog[index].kernel, + versionLog[index].codeHash + ); } - function _setKernel(address _kernel, bytes _infohash) + 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), bnot(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, infohash: _infohash})); + versionLog.push(Version({blockNumber: block.number, timestamp: block.timestamp, kernel: _kernel, codeHash: _codeHash})); latestUpdate = block.timestamp; latestKernel = _kernel; - NewKernel(_kernel, _infohash); + NewKernel(_kernel, _codeHash); } - } \ No newline at end of file From 497076382bced7da68535904c23e31ef88479248 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Wed, 28 Mar 2018 18:37:17 -0300 Subject: [PATCH 10/12] fix typo --- contracts/deploy/Factory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/deploy/Factory.sol b/contracts/deploy/Factory.sol index 2408a58..525ea4a 100644 --- a/contracts/deploy/Factory.sol +++ b/contracts/deploy/Factory.sol @@ -67,7 +67,7 @@ contract Factory is Controlled { // 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), bnot(0x1f)))) + 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 From ac54537b74460c06d7b7b1398cb9cc7a4c08c5be Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 30 Mar 2018 02:31:08 -0300 Subject: [PATCH 11/12] updated to new solidity keywords and linting --- contracts/deploy/DelegatedCall.sol | 4 ++-- contracts/deploy/Instance.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol index 0526c76..861f751 100644 --- a/contracts/deploy/DelegatedCall.sol +++ b/contracts/deploy/DelegatedCall.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.17; +pragma solidity ^0.4.21; /** @@ -29,7 +29,7 @@ contract DelegatedCall { */ function targetDelegatedCall() internal - constant + view returns(address); } diff --git a/contracts/deploy/Instance.sol b/contracts/deploy/Instance.sol index 96c18d8..6243711 100644 --- a/contracts/deploy/Instance.sol +++ b/contracts/deploy/Instance.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.17; +pragma solidity ^0.4.21; import "./InstanceStorage.sol"; import "./DelegatedCall.sol"; @@ -28,7 +28,7 @@ contract Instance is InstanceStorage, DelegatedCall { */ function targetDelegatedCall() internal - constant + view returns(address) { return kernel; From 706941acb0b72ea084d34c1dbee028cc53f1d4be Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Thu, 19 Apr 2018 05:33:04 -0300 Subject: [PATCH 12/12] add return factoried contract address + add emit keyword --- contracts/deploy/Factory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/deploy/Factory.sol b/contracts/deploy/Factory.sol index 525ea4a..4ba811f 100644 --- a/contracts/deploy/Factory.sol +++ b/contracts/deploy/Factory.sol @@ -85,6 +85,6 @@ contract Factory is Controlled { versionLog.push(Version({blockNumber: block.number, timestamp: block.timestamp, kernel: _kernel, codeHash: _codeHash})); latestUpdate = block.timestamp; latestKernel = _kernel; - NewKernel(_kernel, _codeHash); + emit NewKernel(_kernel, _codeHash); } } \ No newline at end of file