delegation proxy refactor

This commit is contained in:
Ricardo Guilherme Schmidt 2018-03-27 23:15:36 -03:00
parent 3c40812a52
commit 1544368968
5 changed files with 171 additions and 173 deletions

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity ^0.4.21;
import "../token/MiniMeTokenInterface.sol";
import "./DelegationProxyInterface.sol";
@ -11,26 +11,9 @@ import "./DelegationProxyInterface.sol";
*/
contract DelegationProxy is DelegationProxyInterface {
//default delegation proxy, being used when user didn't set any delegation at this level.
address public parentProxy;
//snapshots of changes, allow delegation changes be done at any time without compromising vote results.
mapping (address => Delegation[]) public delegations;
//storage of indexes of the addresses to `delegations[to].from`
mapping (address => uint256) toIndexes;
//storage of preprocessed view of FinalDelegate
mapping(bytes32 => FinalDelegate) delegationView;
struct FinalDelegate {
address delegate;
bool found;
}
struct Delegation {
uint128 fromBlock; //when this was updated
address to; //who recieved this delegaton
address[] from; //list of addresses that delegated to this address
}
/**
* @notice Calls Constructor
*/
@ -48,82 +31,6 @@ contract DelegationProxy is DelegationProxyInterface {
_updateDelegate(msg.sender, _to);
}
/**
* @notice Dig into delegate chain to find final delegate, makes delegationOfAt cheaper to call;
* Should be used when you want to track an isolated long delegation chain FinalDelegate
* @param _delegator Address to lookup final delegate.
* @param _block From what block.
* @return True when found final delegate.
*/
function findFinalDelegate(
address _delegator,
uint256 _block,
uint256 loopLimit
)
external
returns (bool)
{
bytes32 searchIndex = keccak256(_delegator,_block);
FinalDelegate memory search = delegationView[searchIndex];
require(!search.found);
for (uint i = 0; i < loopLimit; i++) {
if (search.delegate == address(0)) {
search.delegate = _delegator;
}
address delegateFrom = delegatedToAt(search.delegate, _block);
if (delegateFrom == address(0)) {
search.found = true;
} else {
search.delegate = delegateFrom;
}
if (search.found) {
break;
}
}
delegationView[searchIndex] = search;
return search.found;
}
/**
* @notice Explore the chain from `_delegator`, saving FinalDelegate indexes for all delegates, makes delegationOfAt cheaper to call.
* Should be used to track a common FinalDelegates in a small delegation chain, saving gas on repetitive lookups;
* @param _delegator Address to lookup final delegate.
* @param _block From what block.
* @param _stackLimit how much deep explore to build the indexes
* @return address of delegate when found, or the last top delegate found if stacklimit reached without getting into FinalDelegate.
*/
function buildFinalDelegateChain(
address _delegator,
uint256 _block,
uint256 _stackLimit
)
public
returns (address delegate, bool found)
{
require(_block > block.number); //cannot renderize current state view ?
bytes32 searchIndex = keccak256(_delegator, _block);
FinalDelegate memory search = delegationView[searchIndex];
if (!search.found) {
if (search.delegate == address(0)) {
delegate = delegatedToAt(_delegator, _block);
if (delegate == address(0)) {
//`_delegator` FinalDelegate is itself
delegate = _delegator;
found = true;
}
}
if (!found && _stackLimit > 0) {
//`_delegator` FinalDelegate is the same FinalDelegate of it's `delegate`
(delegate, found) = buildFinalDelegateChain(delegate, _block, _stackLimit - 1);
}
delegationView[searchIndex] = FinalDelegate(delegate, found);
}
return (delegate, found);
}
/**
* @notice Reads `_who` configured delegation in this level,
* or from parent level if `_who` never defined/defined to parent address.
@ -217,7 +124,7 @@ contract DelegationProxy is DelegationProxyInterface {
)
public
constant
returns (address addr)
returns (address directDelegate)
{
Delegation[] storage checkpoints = delegations[_who];
@ -231,7 +138,7 @@ contract DelegationProxy is DelegationProxyInterface {
}
Delegation memory d = _getMemoryAt(checkpoints, _block);
// Case user set delegate to parentProxy address
if (d.to == parentProxy && parentProxy != 0x0) {
if (d.to == parentProxy && d.to != 0x0) {
return DelegationProxy(parentProxy).delegatedToAt(_who, _block);
}
return d.to;
@ -249,22 +156,15 @@ contract DelegationProxy is DelegationProxyInterface {
)
public
constant
returns(address delegate)
returns(address finalDelegate)
{
bytes32 searchIndex = keccak256(_who, _block);
FinalDelegate memory search = delegationView[searchIndex];
if (search.found) {
delegate = search.delegate;
} else if (search.delegate != address(0)) {
_who = search.delegate;
delegate = delegatedToAt(_who, _block);
delegate = delegate == 0x0 ? _who : delegate;
}
if (delegate != _who) { //_who is delegating?
return delegationOfAt(delegate, _block); //load the delegation of _who delegation
finalDelegate = delegatedToAt(_who, _block);
if (finalDelegate != _who) { //_who is delegating?
return delegationOfAt(finalDelegate, _block); //load the delegation of _who delegation
} else {
return _who; //reached the endpoint of delegation
}
}
}
/**

View File

@ -1,30 +1,29 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.21;
import "./DelegationProxyModel.sol";
import "../deploy/RecoverableSystem.sol";
import "../deploy/KillableModel.sol";
import "./DelegationProxyInterface.sol";
import "./DelegationProxyKernel.sol";
import "../deploy/Factory.sol";
import "../deploy/Instance.sol";
/**
* @title DelegationProxyFactory
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Upgradable delegation proxy factory
*/
contract DelegationProxyFactory {
contract DelegationProxyFactory is Factory {
address public systemModel;
address public recover;
address public watchdog;
function DelegationProxyFactory()
Factory(new DelegationProxyKernel())
public
{ }
function DelegationProxyFactory(address _recover, address _watchdog) public {
watchdog = _watchdog;
recover = _recover;
systemModel = new DelegationProxyModel(watchdog);
}
function create(address _parent) external returns (DelegationProxy) {
DelegationProxyModel instance = DelegationProxyModel(address(new RecoverableSystem(systemModel, recover)));
instance.initialize(_parent);
return DelegationProxy(address(instance));
function createDelegationProxy(address _parent)
external
returns (DelegationProxyInterface)
{
DelegationProxyKernel instance = DelegationProxyKernel(address(new Instance(latestKernel)));
instance.initializeDelegationProxy(_parent);
return DelegationProxyInterface(address(instance));
}
}

View File

@ -1,10 +1,21 @@
pragma solidity ^0.4.17;
pragma solidity ^0.4.21;
import "../token/MiniMeTokenInterface.sol";
contract DelegationProxyInterface {
struct Delegation {
uint128 fromBlock; //when this was updated
address to; //who recieved this delegaton
address[] from; //list of addresses that delegated to this address
}
//default delegation proxy, being used when user didn't set any delegation at this level.
address public parentProxy;
//snapshots of changes, allow delegation changes be done at any time without compromising vote results.
mapping (address => Delegation[]) public delegations;
event Delegate(address who, address to);
/**
@ -15,38 +26,6 @@ contract DelegationProxyInterface {
*/
function delegate(address _to) external;
/**
* @notice Dig into delegate chain to find final delegate, makes delegationOfAt cheaper to call;
* Should be used when you want to track an isolated long delegation chain FinalDelegate
* @param _delegator Address to lookup final delegate.
* @param _block From what block.
* @return True when found final delegate.
*/
function findFinalDelegate(
address _delegator,
uint256 _block,
uint256 loopLimit
)
external
returns (bool);
/**
* @notice Explore the chain from `_delegator`, saving FinalDelegate indexes for all delegates, makes delegationOfAt cheaper to call.
* Should be used to track a common FinalDelegates in a small delegation chain, saving gas on repetitive lookups;
* @param _delegator Address to lookup final delegate.
* @param _block From what block.
* @param _stackLimit how much deep explore to build the indexes
* @return address of delegate when found, or the last top delegate found if stacklimit reached without getting into FinalDelegate.
*/
function buildFinalDelegateChain(
address _delegator,
uint256 _block,
uint256 _stackLimit
)
public
returns (address delegate, bool found);
/**
* @notice Reads `_who` configured delegation in this level,
* or from parent level if `_who` never defined/defined to parent address.
@ -56,7 +35,7 @@ contract DelegationProxyInterface {
function delegatedTo(address _who)
public
constant
returns (address);
returns (address directDelegate);
/**
* @notice Reads the final delegate of `_who` at block number `_block`.
@ -66,7 +45,7 @@ contract DelegationProxyInterface {
function delegationOf(address _who)
public
constant
returns(address);
returns(address finalDelegate);
/**
* @notice Reads the sum of votes a `_who' have at block number `_block`.
@ -125,7 +104,7 @@ contract DelegationProxyInterface {
)
public
constant
returns (address addr);
returns (address directDelegate);
/**
* @notice Reads the final delegate of `_who` at block number `_block`.
@ -139,7 +118,7 @@ contract DelegationProxyInterface {
)
public
constant
returns(address delegate);
returns(address finalDelegate);
/**
* @dev Reads amount delegated influence received from other addresses.

View File

@ -1,27 +1,27 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.21;
import "../deploy/KillableModel.sol";
import "./DelegationProxy.sol";
import "../deploy/InstanceStorage.sol";
import "./DelegationProxyView.sol";
/**
* @title DelegationProxyModel
* @title DelegationProxyKernel
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Creates a delegation proxy killable model for cheap redeploy and upgradability.
*/
contract DelegationProxyModel is KillableModel, DelegationProxy {
bool private ready = false;
contract DelegationProxyKernel is InstanceStorage, DelegationProxyView {
bool private ready = false; //TODO: abstract initialized flag
/**
* @notice Constructor of the model - only knows about watchdog that can trigger upgrade
*/
function DelegationProxyModel(address _watchdog) KillableModel(_watchdog) DelegationProxy(0x0) public {
ready = true;
function DelegationProxyKernel() DelegationProxy(0x0) public {
ready = true;
}
/**
* @notice Creates a new DelegationProxy with `_parentProxy` as default delegation.
*/
function initialize(address _parentProxy) public {
function initializeDelegationProxy(address _parentProxy) public {
require(!ready);
ready = true;
parentProxy = _parentProxy;

View File

@ -0,0 +1,120 @@
pragma solidity ^0.4.21;
import "./DelegationProxy.sol";
/**
* @title DelegationProxy
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Creates a delegation proxy layer for MiniMeTokenInterface.
*/
contract DelegationProxyView is DelegationProxy {
//storage of preprocessed view of FinalDelegate
mapping(bytes32 => FinalDelegate) public delegationView;
struct FinalDelegate {
address delegate;
bool found;
}
/**
* @notice Reads the final delegate of `_who` at block number `_block`.
* @param _who Address to lookup.
* @param _block From what block.
* @return Final delegate address.
*/
function delegationOfAt(
address _who,
uint _block
)
public
constant
returns(address finalDelegate)
{
bytes32 searchIndex = keccak256(_who, _block);
FinalDelegate memory search = delegationView[searchIndex];
if (search.found) {
return search.delegate;
} else {
return super.delegationOfAt(_who, _block);
}
}
/**
* @notice Dig into delegate chain to find final delegate, makes delegationOfAt cheaper to call;
* Should be used when you want to track an isolated long delegation chain FinalDelegate
* @param _delegator Address to lookup final delegate.
* @param _block From what block.
* @return True when found final delegate.
*/
function findFinalDelegate(
address _delegator,
uint256 _block,
uint256 loopLimit
)
external
returns (bool)
{
bytes32 searchIndex = keccak256(_delegator,_block);
FinalDelegate memory search = delegationView[searchIndex];
require(!search.found);
for (uint i = 0; i < loopLimit; i++) {
if (search.delegate == address(0)) {
search.delegate = _delegator;
}
address delegateFrom = delegatedToAt(search.delegate, _block);
if (delegateFrom == address(0)) {
// search.delegate demonsted this address didnt delegated,
search.found = true; // so its the final delegate
} else {
search.delegate = delegateFrom;
}
if (search.found) {
break;
}
}
delegationView[searchIndex] = search; //save search
return search.found;
}
/**
* @notice Explore the chain from `_delegator`, saving FinalDelegate indexes for all delegates, makes delegationOfAt cheaper to call.
* Should be used to track a common FinalDelegates in a small delegation chain, saving gas on repetitive lookups;
* @param _delegator Address to lookup final delegate.
* @param _block From what block.
* @param _stackLimit how much deep explore to build the indexes
* @return address of delegate when found, or the last top delegate found if stacklimit reached without getting into FinalDelegate.
*/
function buildFinalDelegateChain(
address _delegator,
uint256 _block,
uint256 _stackLimit
)
public
returns (address lastDelegate, bool found)
{
require(_block > block.number); //cannot renderize current state view ?
bytes32 searchIndex = keccak256(_delegator, _block);
FinalDelegate memory search = delegationView[searchIndex];
if (!search.found) {
if (search.delegate == address(0)) {
lastDelegate = delegatedToAt(_delegator, _block);
if (lastDelegate == address(0)) {
//`_delegator` FinalDelegate is itself
lastDelegate = _delegator;
found = true;
}
}
if (!found && _stackLimit > 0) {
//`_delegator` FinalDelegate is the same FinalDelegate of it's `delegate`
(lastDelegate, found) = buildFinalDelegateChain(lastDelegate, _block, _stackLimit - 1);
}
delegationView[searchIndex] = FinalDelegate(lastDelegate, found);
}
return (lastDelegate, found);
}
}