Skip to content

Commit

Permalink
feat(arbitrator-versioning-proxy): handle appeals and dispute creation
Browse files Browse the repository at this point in the history
  • Loading branch information
epiqueras committed Feb 22, 2018
1 parent 798dd4f commit 739a55c
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 22 deletions.
60 changes: 51 additions & 9 deletions contracts/standard/proxy/ArbitratorVersioningProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@ import "./VersioningProxy.sol";

/* Storage */


mapping (uint256 => address) public disputes;

/* Modifiers */



/* Constructor */


/**
* @notice Constructs the arbitrator versioning proxy with the first arbitrator contract version address and tags it v0.0.1.
* @param firstAddress The address of the first arbitrator contract version.
*/
function ArbitratorVersioningProxy(address firstAddress) VersioningProxy(false, "0.0.1", firstAddress) public {}

/* Fallback */

Expand Down Expand Up @@ -64,20 +68,58 @@ import "./VersioningProxy.sol";

/* Private */

function bytesToBytes32(bytes b) private pure returns (bytes32) {
bytes32 out = 0;

for (uint i = 31; i > 32; i--) { // Loop from lower order to higher order bytes
out |= bytes32(b[i]) << (i * 8); // Combine with out
}

return out;
}

/**
* @notice Called whenever 'stable' changes. We use it to transfer open disputes to the new Arbitrator contract.
* @param prevAddress The previous 'stable' contract address.
* @param nextAddress The next 'stable' contract address.
* @notice On-chain handler that gets called with call data and the 'implementation' contract's return data after a call is successfully proxied.
* @dev @overwrite Proxy.
* @param sig The function signature of the called function.
* @param data The data passed into the call.
* @param retData The return data of the 'implementation' contract for the proxied call.
*/
function handleStableChange(address prevAddress, address nextAddress) private {
KlerosPOC prevArbitrator = KlerosPOC(prevAddress);
KlerosPOC nextArbitrator = KlerosPOC(nextAddress);
function handleProxySuccess(bytes4 sig, bytes data, bytes retData) private {
if (sig == bytes4(keccak256("createDispute(uint256,bytes)"))) { // `createDispute` succeeded
uint256 disputeID = uint256(bytesToBytes32(retData)); // We know this is a uint256


disputes[disputeID] = implementation; // Remember which arbitrator this dispute belongs to
}
}

/* Private Views */

/**
* @notice Function for dynamically getting the 'implementation' contract address.
* @dev @overwrite Proxy.
* @param sig The function signature of the called function.
* @param data The data passed into the call.
* @return The resolved 'implementation' contract address.
*/
function getImplementation(bytes4 sig, bytes data) private view returns (address) {
if (sig == bytes4(keccak256("appeal(uint256,bytes)"))) { // `appeal` called
uint256 disputeID = uint256(bytesToBytes32(data)); // We know the first param is a uint256
address arbitrator = disputes[disputeID]; // The arbitrator this dispute belongs to

// We have changed arbitrators, create a new dispute
if (arbitrator != implementation) {
KlerosPOC oldArbitrator = KlerosPOC(arbitrator);
KlerosPOC newArbitrator = KlerosPOC(implementation);

uint256 choices = oldArbitrator.disputes(disputeID).choices;
newArbitrator.createDispute(choices, bytes(0)); // TODO: Extra Data?
}
}

// TODO: We might need to add disputeID as the first parameter of all calls to be able to resolve the right arbitrator

return implementation;
}

}
60 changes: 53 additions & 7 deletions contracts/standard/proxy/Proxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.4.15;
/**
* @title Proxy
* @author Enrique Piqueras - <epiquerass@gmail.com>
* @notice A proxy contract that forwards all calls to 'implementation' and optionally keeps all storage.
* @notice A base proxy contract that forwards all calls to the 'implementation' contract and optionally keeps all storage.
*/
contract Proxy {
/* Storage */
Expand All @@ -13,20 +13,32 @@ pragma solidity ^0.4.15;

/* Constructor */

/**
* @notice Constructs the proxy with the eternal storage flag and an initial 'implementation' contract address.
* @param _storageIsEternal Wether this contract should store all storage. I.e. Use 'delegatecall'.
* @param _implementation The initial 'implementation' contract address.
*/
function Proxy(bool _storageIsEternal, address _implementation) public {
storageIsEternal = _storageIsEternal;
implementation = _implementation;
}

/* Fallback */

/**
* @notice The fallback function that forwards calls to the 'implementation' contract.
* @return The result of calling the requested function on the 'implementation' contract.
*/
function () payable external {
require(implementation != address(0)); // Make sure address is valid

// Store necessary data for assembly in local memory
bool _storageIsEternal = storageIsEternal;
address _implementation = implementation;
bytes memory data = msg.data;
address _implementation = getImplementation(msg.sig, data);

// Return data
bytes memory retData;

assembly {
// Start of payload raw data (skip over size slot)
Expand All @@ -45,19 +57,53 @@ pragma solidity ^0.4.15;
result := delegatecall(gas, _implementation, dataPtr, dataSize, 0, 0)
}

let retSize := returndatasize // Size of data returned
// Size of the returned data
let retSize := returndatasize

let retPtr := mload(0x40) // Start of free memory
let retDataPtr := add(retPtr, 0x20) // Make space for 'bytes' size

returndatacopy(retPtr, 0, retSize) // Copy returned data to free memory
// Build `retData` 'bytes'
mstore(retPtr, retSize) // Copy size
returndatacopy(retDataPtr, 0, retSize) // Copy returned data

// Figure out wether ro revert or return with the returned data
// Figure out wether to revert or continue with the returned data
switch result
case 0 { // Error
revert(retPtr, retSize)
revert(retDataPtr, retSize)
}
default { // Success
return(retPtr, retSize)
retData := retPtr
}
}

// Call on-chain handler
handleProxySuccess(msg.sig, data, retData);

assembly {
return(add(retData, 0x20), mload(retData)) // Return returned data
}
}

/* Private */

/**
* @notice On-chain handler that gets called with call data and the 'implementation' contract's return data after a call is successfully proxied.
* @dev Overwrite this function to handle the results of proxied calls in this contract.
* @param sig The function signature of the called function.
* @param data The data passed into the call.
* @param retData The return data of the 'implementation' contract for the proxied call.
*/
function handleProxySuccess(bytes4 sig, bytes data, bytes retData) private {}

/* Private Views */

/**
* @notice Function for dynamically getting the 'implementation' contract address.
* @dev Overwrite this function to implement custom resolving logic based on the function being called and the data passed in.
* @param sig The function signature of the called function.
* @param data The data passed into the call.
* @return The resolved 'implementation' contract address.
*/
function getImplementation(bytes4 sig, bytes data) private view returns (address) { return implementation; }
}
16 changes: 10 additions & 6 deletions contracts/standard/proxy/VersioningProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "./Proxy.sol";
/**
* @title VersioningProxy
* @author Enrique Piqueras - <epiquerass@gmail.com>
* @notice A base contract for managing the deployment of versions of another contract.
* @notice A base contract derived from Proxy for managing the deployment of versions of another contract, the managed contract.
*/
contract VersioningProxy is Proxy {
/* Structs */
Expand Down Expand Up @@ -50,18 +50,20 @@ contract VersioningProxy is Proxy {
/* Constructor */

/**
* @notice Constructs the version proxy with the first version of the managed contract, `firstTag`, at `firstAddress`.
* @notice Constructs the versioning proxy with the proxy eternal storage flag and the first version of the managed contract, `firstTag`, at `firstAddress`.
* @param storageIsEternal Wether this contract should store all storage. I.e. Use 'delegatecall'.
* @param firstTag The version tag of the first version of the managed contract.
* @param firstAddress The address of the first verion of the managed contract.
*/
function VersioningProxy(bytes32 firstTag, address firstAddress) Proxy(false, firstAddress) public {
function VersioningProxy(bool storageIsEternal, bytes32 firstTag, address firstAddress) Proxy(storageIsEternal, firstAddress) public {
publish(firstTag, firstAddress);
}

/* External */

/**
* @notice Rolls back 'stable' to the previous deployment, and returns true, if one exists, returns false otherwise.
* @return True if there was a previous version and the rollback succeeded, false otherwise.
*/
function rollback() external onlyOwner returns(bool) {
uint256 tagsLen = tags.length;
Expand All @@ -78,6 +80,7 @@ contract VersioningProxy is Proxy {

/**
* @notice Returns all deployed version tags.
* @return All of the deployed version tags.
*/
function allTags() external view returns(bytes32[]) {
return tags;
Expand All @@ -95,7 +98,7 @@ contract VersioningProxy is Proxy {
tags.push(nextTag); // Push next tag
addresses[nextTag] = nextAddress; // Set next address

// Set stable
// Set 'stable'
setStable(nextTag);
}

Expand All @@ -112,7 +115,7 @@ contract VersioningProxy is Proxy {
bytes32 prevTag = stable.tag;
address prevAddress = stable._address;

// Set stable
// Set 'stable'
stable = Deployment({tag: nextTag, _address: nextAddress});

// Call handler and fire event
Expand All @@ -127,10 +130,11 @@ contract VersioningProxy is Proxy {

/**
* @notice Called whenever 'stable' changes for on-chain handling.
* @dev Overwrite this function to handle 'stable' changes on-chain.
* @param prevTag The previous 'stable' managed contract version tag.
* @param prevAddress The previous 'stable' managed contract address.
* @param nextTag The next 'stable' managed contract version tag.
* @param nextAddress The next 'stable' managed contract address.
*/
function handleStableChange(bytes32 prevTag, address prevAddress, bytes32 nextTag, address nextAddress) private;
function handleStableChange(bytes32 prevTag, address prevAddress, bytes32 nextTag, address nextAddress) private {}
}

0 comments on commit 739a55c

Please sign in to comment.