Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Base contract that all upgradeable contracts should use.
- *
- * Contracts implementing this interface are all called using delegatecall from
- * a dispatcher. As a result, the _sizes and _dest variables are shared with the
- * dispatcher contract, which allows the called contract to update these at will.
- *
- * _sizes is a map of function signatures to return value sizes. Due to EVM
- * limitations, these need to be populated by the target contract, so the
- * dispatcher knows how many bytes of data to return from called functions.
- * Unfortunately, this makes variable-length return values impossible.
- *
- * _dest is the address of the contract currently implementing all the
- * functionality of the composite contract. Contracts should update this by
- * calling the internal function `replace`, which updates _dest and calls
- * `initialize()` on the new contract.
- *
- * When upgrading a contract, restrictions on permissible changes to the set of
- * storage variables must be observed. New variables may be added, but existing
- * ones may not be deleted or replaced. Changing variable names is acceptable.
- * Structs in arrays may not be modified, but structs in maps can be, following
- * the same rules described above.
- */
- contract Upgradeable {
- mapping(bytes4=>uint32) _sizes;
- address _dest;
- /**
- * This function is called using delegatecall from the dispatcher when the
- * target contract is first initialized. It should use this opportunity to
- * insert any return data sizes in _sizes, and perform any other upgrades
- * necessary to change over from the old contract implementation (if any).
- *
- * Implementers of this function should either perform strictly harmless,
- * idempotent operations like setting return sizes, or use some form of
- * access control, to prevent outside callers.
- */
- function initialize();
- /**
- * Performs a handover to a new implementing contract.
- */
- function replace(address target) internal {
- _dest = target;
- target.delegatecall(bytes4(sha3("initialize()")));
- }
- }
- /**
- * The dispatcher is a minimal 'shim' that dispatches calls to a targeted
- * contract. Calls are made using 'delegatecall', meaning all storage and value
- * is kept on the dispatcher. As a result, when the target is updated, the new
- * contract inherits all the stored data and value from the old contract.
- */
- contract Dispatcher is Upgradeable {
- function Dispatcher(address target) {
- replace(target);
- }
- function initialize() {
- // Should only be called by on target contracts, not on the dispatcher
- throw;
- }
- function() {
- bytes4 sig;
- assembly { sig := calldataload(0) }
- var len = _sizes[sig];
- var target = _dest;
- assembly {
- // return _dest.delegatecall(msg.data)
- calldatacopy(0x0, 0x0, calldatasize)
- delegatecall(sub(gas, 10000), target, 0x0, calldatasize, 0, len)
- return(0, len)
- }
- }
- }
- contract Example is Upgradeable {
- uint _value;
- function initialize() {
- _sizes[bytes4(sha3("getUint()"))] = 32;
- }
- function getUint() returns (uint) {
- return _value;
- }
- function setUint(uint value) {
- _value = value;
- }
- }
Add Comment
Please, Sign In to add comment