Skip to content

Commit

Permalink
Merge pull request #101 from 0xPolygonHermez/feature/updateForkID
Browse files Browse the repository at this point in the history
Upgradability contract/scripts for forkID
  • Loading branch information
krlosMata authored Mar 14, 2023
2 parents ec421a4 + d81267e commit d1cba89
Show file tree
Hide file tree
Showing 27 changed files with 675 additions and 737 deletions.
108 changes: 106 additions & 2 deletions compiled-contracts/PolygonZkEVM.json

Large diffs are not rendered by default.

122 changes: 78 additions & 44 deletions compiled-contracts/PolygonZkEVMMock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compiled-contracts/PolygonZkEVMTimelock.json

Large diffs are not rendered by default.

99 changes: 91 additions & 8 deletions contracts/PolygonZkEVM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,6 @@ contract PolygonZkEVM is
// Rounded to 300000 bytes
uint256 internal constant _MAX_TRANSACTIONS_BYTE_LENGTH = 300000;

// Force batch timeout
uint64 internal constant _FORCE_BATCH_TIMEOUT = 5 days;

// If a sequenced batch exceeds this timeout without being verified, the contract enters in emergency mode
uint64 internal constant _HALT_AGGREGATION_TIMEOUT = 1 weeks;

Expand All @@ -131,6 +128,12 @@ contract PolygonZkEVM is
// Min value batch fee
uint256 internal constant _MIN_BATCH_FEE = 1 gwei;

// Goldilocks prime field
uint256 internal constant _GOLDILOCKS_PRIME_FIELD = 0xFFFFFFFF00000001; // 2 ** 64 - 2 ** 32 + 1

// Max uint64
uint256 internal constant _MAX_UINT_64 = type(uint64).max; // 0xFFFFFFFFFFFFFFFF

// MATIC token address
IERC20Upgradeable public immutable matic;

Expand Down Expand Up @@ -223,6 +226,12 @@ contract PolygonZkEVM is
// This account will be able to accept the admin role
address public pendingAdmin;

// Force batch timeout
uint64 public forceBatchTimeout;

// Indicates if forced batches are disallowed
bool public isForcedBatchDisallowed;

/**
* @dev Emitted when the trusted sequencer sends a new batch of transactions
*/
Expand Down Expand Up @@ -305,6 +314,16 @@ contract PolygonZkEVM is
*/
event SetVerifyBatchTimeTarget(uint64 newVerifyBatchTimeTarget);

/**
* @dev Emitted when the admin update the force batch timeout
*/
event SetForceBatchTimeout(uint64 newforceBatchTimeout);

/**
* @dev Emitted when activate force batches
*/
event ActivateForceBatches();

/**
* @dev Emitted when the admin starts the two-step transfer role setting a new pending admin
*/
Expand Down Expand Up @@ -401,10 +420,12 @@ contract PolygonZkEVM is
trustedAggregatorTimeout = initializePackedParameters
.trustedAggregatorTimeout;

// Constant variables
batchFee = 10 ** 18; // 1 Matic
// Constant deployment variables
batchFee = 0.1 ether; // 0.1 Matic
verifyBatchTimeTarget = 30 minutes;
multiplierBatchFee = 1002;
forceBatchTimeout = 5 days;
isForcedBatchDisallowed = true;

// Initialize OZ contracts
__Ownable_init_unchained();
Expand Down Expand Up @@ -434,6 +455,13 @@ contract PolygonZkEVM is
_;
}

modifier isForceBatchAllowed() {
if (isForcedBatchDisallowed) {
revert ForceBatchNotAllowed();
}
_;
}

/////////////////////////////////////
// Sequence/Verify batches functions
////////////////////////////////////
Expand Down Expand Up @@ -980,7 +1008,7 @@ contract PolygonZkEVM is
function forceBatch(
bytes calldata transactions,
uint256 maticAmount
) public virtual ifNotEmergencyState {
) public isForceBatchAllowed ifNotEmergencyState {
// Calculate matic collateral
uint256 maticFee = getCurrentBatchFee();

Expand Down Expand Up @@ -1030,7 +1058,7 @@ contract PolygonZkEVM is
*/
function sequenceForceBatches(
ForcedBatchData[] calldata batches
) external virtual ifNotEmergencyState {
) external isForceBatchAllowed ifNotEmergencyState {
uint256 batchesNum = batches.length;

if (batchesNum == 0) {
Expand Down Expand Up @@ -1087,7 +1115,7 @@ contract PolygonZkEVM is
if (i == (batchesNum - 1)) {
// The last batch will have the most restrictive timestamp
if (
currentBatch.minForcedTimestamp + _FORCE_BATCH_TIMEOUT >
currentBatch.minForcedTimestamp + forceBatchTimeout >
block.timestamp
) {
revert ForceBatchTimeoutNotExpired();
Expand Down Expand Up @@ -1236,6 +1264,40 @@ contract PolygonZkEVM is
emit SetVerifyBatchTimeTarget(newVerifyBatchTimeTarget);
}

/**
* @notice Allow the admin to set the forcedBatchTimeout
* The new value can only be lower, except if emergency state is active
* @param newforceBatchTimeout New force batch timeout
*/
function setForceBatchTimeout(
uint64 newforceBatchTimeout
) external onlyAdmin {
if (newforceBatchTimeout > _HALT_AGGREGATION_TIMEOUT) {
revert InvalidRangeForceBatchTimeout();
}

if (!isEmergencyState) {
if (newforceBatchTimeout >= forceBatchTimeout) {
revert InvalidRangeForceBatchTimeout();
}
}

forceBatchTimeout = newforceBatchTimeout;
emit SetForceBatchTimeout(newforceBatchTimeout);
}

/**
* @notice Allow the admin to turn on the force batches
* This action is not reversible
*/
function activateForceBatches() external onlyAdmin {
if (!isForcedBatchDisallowed) {
revert ForceBatchesAlreadyActive();
}
isForcedBatchDisallowed = false;
emit ActivateForceBatches();
}

/**
* @notice Starts the admin role transfer
* This is a two step process, the pending admin must accepted to finalize the process
Expand Down Expand Up @@ -1582,6 +1644,11 @@ contract PolygonZkEVM is
revert NewAccInputHashDoesNotExist();
}

// Check that new state root is inside goldilocks field
if (!checkStateRootInsidePrime(uint256(newStateRoot))) {
revert NewStateRootNotInsidePrime();
}

return
abi.encodePacked(
msg.sender,
Expand All @@ -1596,4 +1663,20 @@ contract PolygonZkEVM is
finalNewBatch
);
}

function checkStateRootInsidePrime(
uint256 newStateRoot
) public pure returns (bool) {
if (
((newStateRoot & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) &&
(((newStateRoot >> 64) & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) &&
(((newStateRoot >> 128) & _MAX_UINT_64) <
_GOLDILOCKS_PRIME_FIELD) &&
((newStateRoot >> 192) < _GOLDILOCKS_PRIME_FIELD)
) {
return true;
} else {
return false;
}
}
}
20 changes: 20 additions & 0 deletions contracts/interfaces/IPolygonZkEVMErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ interface IPolygonZkEVMErrors {
*/
error InvalidRangeBatchTimeTarget();

/**
* @dev Thrown when attempting to set a force batch timeout in an invalid range of values
*/
error InvalidRangeForceBatchTimeout();

/**
* @dev Thrown when the caller is not the pending admin
*/
Expand Down Expand Up @@ -188,4 +193,19 @@ interface IPolygonZkEVMErrors {
* @dev Thrown when the new accumulate input hash does not exist
*/
error NewAccInputHashDoesNotExist();

/**
* @dev Thrown when the new state root is not inside prime
*/
error NewStateRootNotInsidePrime();

/**
* @dev Thrown when force batch is not allowed
*/
error ForceBatchNotAllowed();

/**
* @dev Thrown when try to activate force batches when they are already active
*/
error ForceBatchesAlreadyActive();
}
150 changes: 0 additions & 150 deletions contracts/mocks/PolygonZkEVMMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ import "../PolygonZkEVM.sol";
* To enter and exit of the L2 network will be used a PolygonZkEVM Bridge smart contract
*/
contract PolygonZkEVMMock is PolygonZkEVM {
// Define if forced batches will be allowed
// Defined as a uint256 because it will be easy to updgrade afterwards
uint256 public forcedBatchesAllowed;

// Define if the force batch timeout
// Defined as a uint256 because it will be easy to updgrade afterwards
uint256 public forceBatchTimeout;

/**
* @param _globalExitRootManager Global exit root manager address
* @param _matic MATIC token address
Expand All @@ -43,148 +35,6 @@ contract PolygonZkEVMMock is PolygonZkEVM {
)
{}

/**
* @dev Thrown when force batch is not allowed
*/
error ForceBatchNowAllowed();

modifier isForceBatchAllowed() {
if (forcedBatchesAllowed != 0) {
revert ForceBatchNowAllowed();
}
_;
}

// Override methods
function forceBatch(
bytes calldata transactions,
uint256 maticAmount
) public override isForceBatchAllowed {
super.forceBatch(transactions, maticAmount);
}

function sequenceForceBatches(
ForcedBatchData[] calldata batches
) external override isForceBatchAllowed ifNotEmergencyState {
uint256 batchesNum = batches.length;

if (batchesNum == 0) {
revert SequenceZeroBatches();
}

if (batchesNum > _MAX_VERIFY_BATCHES) {
revert ExceedMaxVerifyBatches();
}

if (
uint256(lastForceBatchSequenced) + batchesNum >
uint256(lastForceBatch)
) {
revert ForceBatchesOverflow();
}

// Store storage variables in memory, to save gas, because will be overrided multiple times
uint64 currentBatchSequenced = lastBatchSequenced;
uint64 currentLastForceBatchSequenced = lastForceBatchSequenced;
bytes32 currentAccInputHash = sequencedBatches[currentBatchSequenced]
.accInputHash;

// Sequence force batches
for (uint256 i = 0; i < batchesNum; i++) {
// Load current sequence
ForcedBatchData memory currentBatch = batches[i];
currentLastForceBatchSequenced++;

// Store the current transactions hash since it's used more than once for gas saving
bytes32 currentTransactionsHash = keccak256(
currentBatch.transactions
);

// Check forced data matches
bytes32 hashedForcedBatchData = keccak256(
abi.encodePacked(
currentTransactionsHash,
currentBatch.globalExitRoot,
currentBatch.minForcedTimestamp
)
);

if (
hashedForcedBatchData !=
forcedBatches[currentLastForceBatchSequenced]
) {
revert ForcedDataDoesNotMatch();
}

// Delete forceBatch data since won't be used anymore
delete forcedBatches[currentLastForceBatchSequenced];

if (i == (batchesNum - 1)) {
// The last batch will have the most restrictive timestamp
if (
currentBatch.minForcedTimestamp + getForceBatchTimeout() >
block.timestamp
) {
revert ForceBatchTimeoutNotExpired();
}
}
// Calculate next acc input hash
currentAccInputHash = keccak256(
abi.encodePacked(
currentAccInputHash,
currentTransactionsHash,
currentBatch.globalExitRoot,
uint64(block.timestamp),
msg.sender
)
);
}
// Update currentBatchSequenced
currentBatchSequenced += uint64(batchesNum);

lastTimestamp = uint64(block.timestamp);

// Store back the storage variables
sequencedBatches[currentBatchSequenced] = SequencedBatchData({
accInputHash: currentAccInputHash,
sequencedTimestamp: uint64(block.timestamp),
previousLastBatchSequenced: lastBatchSequenced
});
lastBatchSequenced = currentBatchSequenced;
lastForceBatchSequenced = currentLastForceBatchSequenced;

emit SequenceForceBatches(currentBatchSequenced);
}

function getForceBatchTimeout() public view returns (uint64) {
if (forceBatchTimeout == 0) {
return _FORCE_BATCH_TIMEOUT;
} else {
return uint64(forceBatchTimeout);
}
}

/**
* @notice Set new forcedBatchTimeout
* @param newforceBatchTimeout new forced batches timeout
*/
function setForceBatchTimeout(
uint64 newforceBatchTimeout
) public onlyOwner {
forceBatchTimeout = newforceBatchTimeout;
}

/**
* @notice Set new forced batches allowed
* Defined as a uint256 because it will be easy to updgrade afterwards
* @param newForcedBatchesAllowed new forced batches allowed
*/
function setForcedBatchesAllowed(
uint256 newForcedBatchesAllowed
) public onlyOwner {
forcedBatchesAllowed = newForcedBatchesAllowed;
}

/**
* @notice calculate accumulate input hash from parameters
* @param currentAccInputHash Accumulate input hash
Expand Down
Loading

0 comments on commit d1cba89

Please sign in to comment.