Created
June 15, 2020 19:30
-
-
Save dvush/54a590b9585a00eb39696628ee00fa69 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/contracts/contracts/Bytes.sol b/contracts/contracts/Bytes.sol | |
index d9813152..756b01f0 100644 | |
--- a/contracts/contracts/Bytes.sol | |
+++ b/contracts/contracts/Bytes.sol | |
@@ -1,5 +1,12 @@ | |
pragma solidity ^0.5.0; | |
+// Functions named bytesToX, except bytesToBytes20, where X is some type of size N < 32 (size of one word) | |
+// implements the following algorithm: | |
+// f(bytes memory input, uint offset) -> X out | |
+// where byte representation of out is N bytes from input at the given offset | |
+// 1) We compute memory location of the word W such that last N bytes of W is input[offset..offset+N] | |
+// W_address = input + 32 (skip stored length of bytes) + offset - (32 - N) == input + offset + N | |
+// 2) We load W from memory into out, last N bytes of W are placed into out | |
library Bytes { | |
@@ -38,75 +45,80 @@ library Bytes { | |
bts = toBytesFromUIntTruncated(uint(self), 20); | |
} | |
+ // See comment at the top of this file for explanation of how this function works. | |
// NOTE: theoretically possible overflow of (_start + 20) | |
function bytesToAddress(bytes memory self, uint256 _start) internal pure returns (address addr) { | |
- uint256 newOffset = _start + 20; | |
- require(self.length >= newOffset, "bta11"); | |
+ uint256 offset = _start + 20; | |
+ require(self.length >= offset, "bta11"); | |
assembly { | |
- addr := mload(add(self, newOffset)) | |
+ addr := mload(add(self, offset)) | |
} | |
} | |
+ // Reasoning about why this function works is similar to that of other similar functions, except NOTE below. | |
+ // NOTE: that bytes1..32 is stored in the beginning of the word unlike other primitive types | |
// NOTE: theoretically possible overflow of (_start + 20) | |
function bytesToBytes20(bytes memory self, uint256 _start) internal pure returns (bytes20 r) { | |
require(self.length >= (_start + 20), "btb20"); | |
assembly { | |
- // Note that bytes1..32 is stored in the beginning of the word unlike other primitive types | |
r := mload(add(add(self, 0x20), _start)) | |
} | |
} | |
+ // See comment at the top of this file for explanation of how this function works. | |
// NOTE: theoretically possible overflow of (_start + 0x2) | |
function bytesToUInt16(bytes memory _bytes, uint256 _start) internal pure returns (uint16 r) { | |
- uint256 newOffset = _start + 0x2; | |
- require(_bytes.length >= newOffset, "btu02"); | |
+ uint256 offset = _start + 0x2; | |
+ require(_bytes.length >= offset, "btu02"); | |
assembly { | |
- r := mload(add(_bytes, newOffset)) | |
+ r := mload(add(_bytes, offset)) | |
} | |
} | |
+ // See comment at the top of this file for explanation of how this function works. | |
// NOTE: theoretically possible overflow of (_start + 0x3) | |
function bytesToUInt24(bytes memory _bytes, uint256 _start) internal pure returns (uint24 r) { | |
- uint256 newOffset = _start + 0x3; | |
- require(_bytes.length >= newOffset, "btu03"); | |
+ uint256 offset = _start + 0x3; | |
+ require(_bytes.length >= offset, "btu03"); | |
assembly { | |
- r := mload(add(_bytes, newOffset)) | |
+ r := mload(add(_bytes, offset)) | |
} | |
} | |
// NOTE: theoretically possible overflow of (_start + 0x4) | |
function bytesToUInt32(bytes memory _bytes, uint256 _start) internal pure returns (uint32 r) { | |
- uint256 newOffset = _start + 0x4; | |
- require(_bytes.length >= newOffset, "btu04"); | |
+ uint256 offset = _start + 0x4; | |
+ require(_bytes.length >= offset, "btu04"); | |
assembly { | |
- r := mload(add(_bytes, newOffset)) | |
+ r := mload(add(_bytes, offset)) | |
} | |
} | |
// NOTE: theoretically possible overflow of (_start + 0x10) | |
function bytesToUInt128(bytes memory _bytes, uint256 _start) internal pure returns (uint128 r) { | |
- uint256 newOffset = _start + 0x10; | |
- require(_bytes.length >= newOffset, "btu16"); | |
+ uint256 offset = _start + 0x10; | |
+ require(_bytes.length >= offset, "btu16"); | |
assembly { | |
- r := mload(add(_bytes, newOffset)) | |
+ r := mload(add(_bytes, offset)) | |
} | |
} | |
+ // See comment at the top of this file for explanation of how this function works. | |
// NOTE: theoretically possible overflow of (_start + 0x14) | |
function bytesToUInt160(bytes memory _bytes, uint256 _start) internal pure returns (uint160 r) { | |
- uint256 newOffset = _start + 0x14; | |
- require(_bytes.length >= newOffset, "btu20"); | |
+ uint256 offset = _start + 0x14; | |
+ require(_bytes.length >= offset, "btu20"); | |
assembly { | |
- r := mload(add(_bytes, newOffset)) | |
+ r := mload(add(_bytes, offset)) | |
} | |
} | |
// NOTE: theoretically possible overflow of (_start + 0x20) | |
function bytesToBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32 r) { | |
- uint256 newOffset = _start + 0x20; | |
- require(_bytes.length >= newOffset, "btb32"); | |
+ uint256 offset = _start + 0x20; | |
+ require(_bytes.length >= offset, "btb32"); | |
assembly { | |
- r := mload(add(_bytes, newOffset)) | |
+ r := mload(add(_bytes, offset)) | |
} | |
} | |
@@ -227,9 +239,30 @@ library Bytes { | |
// Convert bytes to ASCII hex representation | |
function bytesToHexASCIIBytes(bytes memory _input) internal pure returns (bytes memory _output) { | |
bytes memory outStringBytes = new bytes(_input.length * 2); | |
- for (uint i = 0; i < _input.length; ++i) { | |
- outStringBytes[i*2] = halfByteToHex(_input[i] >> 4); | |
- outStringBytes[i*2+1] = halfByteToHex(_input[i] & 0x0f); | |
+ | |
+ // code in `assembly` construction is equivalent of the next code: | |
+ // for (uint i = 0; i < _input.length; ++i) { | |
+ // outStringBytes[i*2] = halfByteToHex(_input[i] >> 4); | |
+ // outStringBytes[i*2+1] = halfByteToHex(_input[i] & 0x0f); | |
+ // } | |
+ assembly { | |
+ let input_curr := add(_input, 0x20) | |
+ let input_end := add(input_curr, mload(_input)) | |
+ | |
+ for { | |
+ let out_curr := add(outStringBytes, 0x20) | |
+ } lt(input_curr, input_end) { | |
+ input_curr := add(input_curr, 0x01) | |
+ out_curr := add(out_curr, 0x02) | |
+ } { | |
+ let curr_input_byte := shr(0xf8, mload(input_curr)) | |
+ // here outStringByte from each half of input byte calculates by the next: | |
+ // | |
+ // "FEDCBA9876543210" ASCII-encoded, shifted and automatically truncated. | |
+ // outStringByte = byte (uint8 (0x66656463626139383736353433323130 >> (uint8 (_byteHalf) * 8))) | |
+ mstore(out_curr, shl(0xf8, shr(mul(shr(0x04, curr_input_byte), 0x08), 0x66656463626139383736353433323130))) | |
+ mstore(add(out_curr, 0x01), shl(0xf8, shr(mul(and(0x0f, curr_input_byte), 0x08), 0x66656463626139383736353433323130))) | |
+ } | |
} | |
return outStringBytes; | |
} | |
diff --git a/contracts/contracts/Events.sol b/contracts/contracts/Events.sol | |
index 43dd954a..a5de3260 100644 | |
--- a/contracts/contracts/Events.sol | |
+++ b/contracts/contracts/Events.sol | |
@@ -77,30 +77,30 @@ interface UpgradeEvents { | |
/// @notice Event emitted when new upgradeable contract is added to upgrade gatekeeper's list of managed contracts | |
event NewUpgradable( | |
- uint versionId, | |
- address upgradeable | |
+ uint indexed versionId, | |
+ address indexed upgradeable | |
); | |
/// @notice Upgrade mode enter event | |
event NoticePeriodStart( | |
- uint versionId, | |
+ uint indexed versionId, | |
address[] newTargets, | |
uint noticePeriod // notice period (in seconds) | |
); | |
/// @notice Upgrade mode cancel event | |
event UpgradeCancel( | |
- uint versionId | |
+ uint indexed versionId | |
); | |
/// @notice Upgrade mode preparation status event | |
event PreparationStart( | |
- uint versionId | |
+ uint indexed versionId | |
); | |
/// @notice Upgrade mode complete event | |
event UpgradeComplete( | |
- uint versionId, | |
+ uint indexed versionId, | |
address[] newTargets | |
); | |
diff --git a/contracts/contracts/Ownable.sol b/contracts/contracts/Ownable.sol | |
index d0d6d5da..cfd6a4e0 100644 | |
--- a/contracts/contracts/Ownable.sol | |
+++ b/contracts/contracts/Ownable.sol | |
@@ -5,7 +5,7 @@ pragma solidity ^0.5.0; | |
contract Ownable { | |
/// @notice Storage position of the masters address (keccak256('eip1967.proxy.admin') - 1) | |
- bytes32 private constant masterPosition = bytes32(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103); | |
+ bytes32 private constant masterPosition = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; | |
/// @notice Contract constructor | |
/// @dev Sets msg sender address as masters address | |
diff --git a/contracts/contracts/Proxy.sol b/contracts/contracts/Proxy.sol | |
index 81aaf985..93dcea11 100644 | |
--- a/contracts/contracts/Proxy.sol | |
+++ b/contracts/contracts/Proxy.sol | |
@@ -11,7 +11,7 @@ import "./UpgradeableMaster.sol"; | |
contract Proxy is Upgradeable, UpgradeableMaster, Ownable { | |
/// @notice Storage position of "target" (actual implementation address: keccak256('eip1967.proxy.implementation') - 1) | |
- bytes32 private constant targetPosition = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); | |
+ bytes32 private constant targetPosition = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; | |
/// @notice Contract constructor | |
/// @dev Calls Ownable contract constructor and initialize target | |
diff --git a/contracts/contracts/ReentrancyGuard.sol b/contracts/contracts/ReentrancyGuard.sol | |
index 892f6ba6..2d1f67d5 100644 | |
--- a/contracts/contracts/ReentrancyGuard.sol | |
+++ b/contracts/contracts/ReentrancyGuard.sol | |
@@ -22,7 +22,7 @@ pragma solidity ^0.5.0; | |
contract ReentrancyGuard { | |
/// Address of lock flag variable. | |
/// Flag is placed at random memory location to not interfere with Storage contract. | |
- uint constant LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4; // keccak256("ReentrancyGuard") - 1; | |
+ uint constant private LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4; // keccak256("ReentrancyGuard") - 1; | |
function initializeReentrancyGuard () internal { | |
// Storing an initial non-zero value makes deployment a bit more | |
diff --git a/contracts/contracts/ZkSync.sol b/contracts/contracts/ZkSync.sol | |
index 56b976c3..4640f220 100644 | |
--- a/contracts/contracts/ZkSync.sol | |
+++ b/contracts/contracts/ZkSync.sol | |
@@ -21,7 +21,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
using SafeMath for uint256; | |
using SafeMathUInt128 for uint128; | |
- bytes32 public constant EMPTY_STRING_KECCAK = bytes32(0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); | |
+ bytes32 public constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; | |
// Upgrade functional | |
@@ -98,9 +98,10 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
uint256 balance_before = _token.balanceOf(address(this)); | |
require(Utils.sendERC20(_token, _to, _amount), "wtg11"); // wtg11 - ERC20 transfer fails | |
uint256 balance_after = _token.balanceOf(address(this)); | |
- require(balance_before.sub(balance_after) <= _maxAmount, "wtg12"); // wtg12 - rollup balance difference (before and after transfer) is bigger than _maxAmount | |
+ uint256 balance_diff = balance_before.sub(balance_after); | |
+ require(balance_diff <= _maxAmount, "wtg12"); // wtg12 - rollup balance difference (before and after transfer) is bigger than _maxAmount | |
- return SafeCast.toUint128(balance_before.sub(balance_after)); | |
+ return SafeCast.toUint128(balance_diff); | |
} | |
/// @notice executes pending withdrawals | |
@@ -110,11 +111,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
uint32 toProcess = Utils.minU32(_n, numberOfPendingWithdrawals); | |
uint32 startIndex = firstPendingWithdrawalIndex; | |
numberOfPendingWithdrawals -= toProcess; | |
- if (numberOfPendingWithdrawals == 0) { | |
- firstPendingWithdrawalIndex = 0; | |
- } else { | |
- firstPendingWithdrawalIndex += toProcess; | |
- } | |
+ firstPendingWithdrawalIndex += toProcess; | |
for (uint32 i = startIndex; i < startIndex + toProcess; ++i) { | |
uint16 tokenId = pendingWithdrawals[i].tokenId; | |
@@ -191,7 +188,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
uint16 tokenId = governance.validateTokenAddress(address(_token)); | |
uint256 balance_before = _token.balanceOf(address(this)); | |
- require(_token.transferFrom(msg.sender, address(this), uint128(_amount)), "fd012"); // token transfer failed deposit | |
+ require(_token.transferFrom(msg.sender, address(this), SafeCast.toUint128(_amount)), "fd012"); // token transfer failed deposit | |
uint256 balance_after = _token.balanceOf(address(this)); | |
uint128 deposit_amount = SafeCast.toUint128(balance_after.sub(balance_before)); | |
@@ -214,6 +211,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
/// @param _token Token address, 0 address for ether | |
function fullExit (uint32 _accountId, address _token) external nonReentrant { | |
requireActive(); | |
+ require(_accountId <= MAX_ACCOUNT_ID, "fee11"); | |
uint16 tokenId; | |
if (_token == address(0)) { | |
@@ -256,25 +254,22 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
requireActive(); | |
require(_blockNumber == totalBlocksCommitted + 1, "fck11"); // only commit next block | |
governance.requireActiveValidator(msg.sender); | |
- require(!isBlockCommitmentExpired(), "fck12"); // committed blocks had expired | |
require(_newBlockInfo.length == 1, "fck13"); // This version of the contract expects only account tree root hash | |
bytes memory publicData = _publicData; | |
- if(!triggerExodusIfNeeded()) { | |
- // Unpack onchain operations and store them. | |
- // Get priority operations number for this block. | |
- uint64 prevTotalCommittedPriorityRequests = totalCommittedPriorityRequests; | |
+ // Unpack onchain operations and store them. | |
+ // Get priority operations number for this block. | |
+ uint64 prevTotalCommittedPriorityRequests = totalCommittedPriorityRequests; | |
- bytes32 withdrawalsDataHash = collectOnchainOps(_blockNumber, publicData, _ethWitness, _ethWitnessSizes); | |
+ bytes32 withdrawalsDataHash = collectOnchainOps(_blockNumber, publicData, _ethWitness, _ethWitnessSizes); | |
- uint64 nPriorityRequestProcessed = totalCommittedPriorityRequests - prevTotalCommittedPriorityRequests; | |
+ uint64 nPriorityRequestProcessed = totalCommittedPriorityRequests - prevTotalCommittedPriorityRequests; | |
- createCommittedBlock(_blockNumber, _feeAccount, _newBlockInfo[0], publicData, withdrawalsDataHash, nPriorityRequestProcessed); | |
- totalBlocksCommitted++; | |
+ createCommittedBlock(_blockNumber, _feeAccount, _newBlockInfo[0], publicData, withdrawalsDataHash, nPriorityRequestProcessed); | |
+ totalBlocksCommitted++; | |
- emit BlockCommit(_blockNumber); | |
- } | |
+ emit BlockCommit(_blockNumber); | |
} | |
/// @notice Block verification. | |
@@ -307,6 +302,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
/// @param _maxBlocksToRevert the maximum number blocks that will be reverted (use if can't revert all blocks because of gas limit). | |
function revertBlocks(uint32 _maxBlocksToRevert) external nonReentrant { | |
require(isBlockCommitmentExpired(), "rbs11"); // trying to revert non-expired blocks. | |
+ governance.requireActiveValidator(msg.sender); | |
uint32 blocksCommited = totalBlocksCommitted; | |
uint32 blocksToRevert = Utils.minU32(_maxBlocksToRevert, blocksCommited - totalBlocksVerified); | |
@@ -337,7 +333,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
/// @dev Exodus mode must be entered in case of current ethereum block number is higher than the oldest | |
/// @dev of existed priority requests expiration block number. | |
/// @return bool flag that is true if the Exodus mode must be entered. | |
- function triggerExodusIfNeeded() public returns (bool) { | |
+ function triggerExodusIfNeeded() external returns (bool) { | |
bool trigger = block.number >= priorityRequests[firstPriorityRequestId].expirationBlock && | |
priorityRequests[firstPriorityRequestId].expirationBlock != 0; | |
if (trigger) { | |
@@ -678,7 +674,11 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
bytes22 packedBalanceKey = packAddressAndTokenId(_to, _tokenId); | |
uint128 balance = balancesToWithdraw[packedBalanceKey].balanceToWithdraw; | |
- balancesToWithdraw[packedBalanceKey].balanceToWithdraw = balance.add(_amount); | |
+ // after this all writes to this slot will cost 5k gas | |
+ balancesToWithdraw[packedBalanceKey] = BalanceToWithdraw({ | |
+ balanceToWithdraw: balance.add(_amount), | |
+ gasReserveValue: 0xff | |
+ }); | |
if (addToPendingWithdrawalsQueue) { | |
pendingWithdrawals[firstPendingWithdrawalIndex + localNumberOfPendingWithdrawals] = PendingWithdrawal(_to, _tokenId); | |
@@ -746,8 +746,9 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard { | |
function deleteRequests(uint64 _number) internal { | |
require(_number <= totalOpenPriorityRequests, "pcs21"); // number is higher than total priority requests number | |
+ uint64 numberOfRequestsToClear = Utils.minU64(_number, MAX_PRIORITY_REQUESTS_TO_DELETE_IN_VERIFY); | |
uint64 startIndex = firstPriorityRequestId; | |
- for (uint64 i = startIndex; i < startIndex + _number; i++) { | |
+ for (uint64 i = startIndex; i < startIndex + numberOfRequestsToClear; i++) { | |
delete priorityRequests[i]; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment