Documentation for upgradeability contracts (#332)

This commit is contained in:
Kirill Fedoseev 2019-12-27 18:52:03 +07:00 committed by Alexander Kolotov
parent 3b4220ee44
commit 0241a264bb
3 changed files with 36 additions and 0 deletions

View File

@ -2,6 +2,13 @@ pragma solidity 0.4.24;
import "./EternalStorageProxy.sol";
/**
* @title ClassicEternalStorageProxy
* @dev This proxy holds the storage of the token contract and delegates every call to the current implementation set.
* Besides, it allows to upgrade the token's behaviour towards further implementations, and provides basic
* authorization control functionalities.
* The only differency between this contract and EternalStorageProxy is a provided support of pre-Byzantium environment.
*/
contract ClassicEternalStorageProxy is EternalStorageProxy {
// solhint-disable-next-line no-complex-fallback
function() public payable {
@ -11,6 +18,10 @@ contract ClassicEternalStorageProxy is EternalStorageProxy {
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
/*
instead of reading `returndatasize` and `returdatacopy` later,
this stores the returned data directly into the memory
*/
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, len)
switch result
@ -23,6 +34,11 @@ contract ClassicEternalStorageProxy is EternalStorageProxy {
}
}
/**
* @dev Tells the called function return data size
* @param sig representing the signature of a called function
* @return size of return data in bytes
*/
function getSize(bytes4 sig) public view returns (uint256) {
uint256 ret = uintStorage[keccak256(abi.encodePacked("dataSizes", sig))];
if (ret == 0) {

View File

@ -0,0 +1,14 @@
# Upgradeability contracts
This directory contains contracts needed for the idea of upgradeable contracts. The source code for this contracts was originally taken from [openzeppelin-labs](https://github.com/OpenZeppelin/openzeppelin-labs/tree/8212ac638ce0a6517fd1c4c7f445fe9665925020/upgradeability_using_eternal_storage) repository.
Since the original code is not recommended for production use, it is not directly imported into this project.
During the development process and performing security audits, the following minor changes were introduced:
- Required solidity compiler version was fixed at `0.4.24`, since this version is used in the source code of other contracts. Deprecated syntax for constructors and emitting events was also updated to a new one.
- Access modifier `onlyProxyOwner` was renamed to `onlyUpgradeabilityOwner`. Function calls to `proxyOwner()` in `OwnedUpgradeabilityProxy.sol` were directly replaced by calls to `upgradeabilityOwner()`, in order to avoid possible ambiguity. See [#195](https://github.com/poanetwork/tokenbridge-contracts/issues/195).
- Functions modifier `public` was replaced by `external` where possible.
- Version field type was changed from `string` to `uint256`, as it reduces possible complexity and allows to easily introduce a version mutability requirement (`require(version > _version);` in `UpgradeabilityProxy.sol`).
- Additional assembly operation was introduced in `Proxy.sol`, opcodes in line `mstore(0x40, add(ptr, returndatasize))` guarantee the correct value of free memory pointer for execution of next instructions.
- Additional check in `UpgradeabilityProxy.sol` was added, `require(AddressUtils.isContract(implementation))` verifies that new implementation is not a regular address, but a contract. See [#256](https://github.com/poanetwork/tokenbridge-contracts/pull/256).
- Contract `ClassicEternalStorageProxy.sol` was added for the use in pre-Byzantium Ethereum Classic network, which does not support [EIP-211](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-211.md). See this comment in [#161](https://github.com/poanetwork/tokenbridge-contracts/pull/161#issuecomment-473888305).

View File

@ -23,8 +23,14 @@ contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
*/
function _upgradeTo(uint256 version, address implementation) internal {
require(_implementation != implementation);
// This additional check verifies that provided implementation is at least a contract
require(AddressUtils.isContract(implementation));
// This additional check guarantees that new version will be at least greater than the privios one,
// so it is impossible to reuse old versions, or use the last version twice
require(version > _version);
_version = version;
_implementation = implementation;
emit Upgraded(version, implementation);