Commit 5bb6f2c7 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

feat(contracts): add `isOutputFinalized` function (#2598)

* feat(contracts): add `isOutputFinalize` function

An `external` function that can be used for apps to
check to see if a particular output is finalized.

* bindings: regenerate

* contracts: update gas-snapshot

* contracts-bedrock: update `isOutputFinalized`
Co-authored-by: default avatarMaurelian <maurelian@protonmail.ch>

* contracts-bedrock: add `isOutputFinalized`

* op-bindings: regenerate
Co-authored-by: default avatarMaurelian <maurelian@protonmail.ch>
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent 3799bb6f
---
'@eth-optimism/contracts-bedrock': patch
---
Add `OptimismPortal.isOutputFinalized`
This diff is collapsed.
......@@ -27,14 +27,14 @@ L1CrossDomainMessenger_Test:testCannot_L1MessengerPause() (gas: 10844)
L1CrossDomainMessenger_Test:testCannot_L1MessengerUnpause() (gas: 10858)
L1CrossDomainMessenger_Test:test_L1MessengerMessageVersion() (gas: 8388)
L1CrossDomainMessenger_Test:test_L1MessengerPause() (gas: 31860)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageSucceeds() (gas: 61261)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageToSystemContract() (gas: 44881)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageSucceeds() (gas: 61283)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageToSystemContract() (gas: 44903)
L1CrossDomainMessenger_Test:test_L1MessengerRelayShouldRevertIfPaused() (gas: 41587)
L1CrossDomainMessenger_Test:test_L1MessengerSendMessage() (gas: 172193)
L1CrossDomainMessenger_Test:test_L1MessengerTwiceSendMessage() (gas: 1254199)
L1CrossDomainMessenger_Test:test_L1MessengerUnpause() (gas: 23804)
L1CrossDomainMessenger_Test:test_L1MessengerXDomainSenderReverts() (gas: 10599)
L1CrossDomainMessenger_Test:test_L1MessengerxDomainMessageSenderResets() (gas: 58579)
L1CrossDomainMessenger_Test:test_L1MessengerxDomainMessageSenderResets() (gas: 58601)
L1StandardBridge_Test:test_depositERC20() (gas: 452856)
L1StandardBridge_Test:test_depositERC20To() (gas: 454632)
L1StandardBridge_Test:test_depositETH() (gas: 247077)
......@@ -113,19 +113,21 @@ OptimismMintableTokenFactory_Test:test_createStandardL2Token() (gas: 1100125)
OptimismMintableTokenFactory_Test:test_createStandardL2TokenSameTwice() (gas: 2181161)
OptimismMintableTokenFactory_Test:test_createStandardL2TokenShouldRevertIfRemoteIsZero() (gas: 9374)
OptimismMintableTokenFactory_Test:test_initializeShouldRevert() (gas: 12696)
OptimismPortal_Test:test_OptimismPortalConstructor() (gas: 11413)
OptimismPortal_Test:test_OptimismPortalContractCreationReverts() (gas: 9214)
OptimismPortal_Test:test_OptimismPortalReceiveEth() (gas: 121706)
OptimismPortal_Test:test_cannotVerifyRecentWithdrawal() (gas: 21908)
OptimismPortal_Test:test_OptimismPortalConstructor() (gas: 11435)
OptimismPortal_Test:test_OptimismPortalContractCreationReverts() (gas: 9192)
OptimismPortal_Test:test_OptimismPortalReceiveEth() (gas: 121771)
OptimismPortal_Test:test_cannotVerifyRecentWithdrawal() (gas: 21886)
OptimismPortal_Test:test_depositTransaction_NoValueContract() (gas: 70746)
OptimismPortal_Test:test_depositTransaction_NoValueEOA() (gas: 71114)
OptimismPortal_Test:test_depositTransaction_createWithZeroValueForContract() (gas: 70773)
OptimismPortal_Test:test_depositTransaction_createWithZeroValueForEOA() (gas: 71117)
OptimismPortal_Test:test_depositTransaction_NoValueEOA() (gas: 71092)
OptimismPortal_Test:test_depositTransaction_createWithZeroValueForContract() (gas: 70751)
OptimismPortal_Test:test_depositTransaction_createWithZeroValueForEOA() (gas: 71095)
OptimismPortal_Test:test_depositTransaction_withEthValueAndContractContractCreation() (gas: 77795)
OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation() (gas: 69947)
OptimismPortal_Test:test_depositTransaction_withEthValueFromContract() (gas: 77478)
OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA() (gas: 78049)
OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation() (gas: 69925)
OptimismPortal_Test:test_depositTransaction_withEthValueFromContract() (gas: 77456)
OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA() (gas: 78072)
OptimismPortal_Test:test_invalidWithdrawalProof() (gas: 33769)
OptimismPortal_Test:test_isOutputFinalized() (gas: 109379)
OptimismPortal_Test:test_simple_isOutputFinalized() (gas: 17076)
Proxy_Test:test_clashingFunctionSignatures() (gas: 101427)
Proxy_Test:test_implementationKey() (gas: 20942)
Proxy_Test:test_implementationProxyCallIfNotAdmin() (gas: 30021)
......
......@@ -141,6 +141,36 @@ contract OptimismPortal is ResourceMetering {
emit TransactionDeposited(from, _to, msg.value, _value, _gasLimit, _isCreation, _data);
}
/**
* @notice Determine if an L2 Output is finalized.
*
* @param _l2BlockNumber The number of the L2 block.
*/
function isOutputFinalized(uint256 _l2BlockNumber) external view returns (bool) {
L2OutputOracle.OutputProposal memory proposal = L2_ORACLE.getL2Output(_l2BlockNumber);
if (proposal.outputRoot == bytes32(uint256(0))) {
uint256 interval = L2_ORACLE.SUBMISSION_INTERVAL();
uint256 startingBlockNumber = L2_ORACLE.STARTING_BLOCK_NUMBER();
// Prevent underflow
if (startingBlockNumber > _l2BlockNumber) {
return false;
}
// Find the distance between the _l2BlockNumber, and the checkpoint block before it.
uint256 offset = (_l2BlockNumber - startingBlockNumber) % interval;
// Look up the checkpoint block after it.
proposal = L2_ORACLE.getL2Output(_l2BlockNumber + (interval - offset));
// False if that block is not yet appended.
if (proposal.outputRoot == bytes32(uint256(0))) {
return false;
}
}
return block.timestamp > proposal.timestamp + FINALIZATION_PERIOD_SECONDS;
}
/**
* @notice Finalizes a withdrawal transaction.
*
......
......@@ -268,4 +268,54 @@ contract OptimismPortal_Test is L2OutputOracle_Initializer {
vm.expectRevert("OptimismPortal: invalid output root proof");
op.finalizeWithdrawalTransaction(0, alice, alice, 0, 0, hex"", 0, outputRootProof, hex"");
}
function test_simple_isOutputFinalized() external {
vm.mockCall(
address(op.L2_ORACLE()),
abi.encodeWithSelector(
L2OutputOracle.getL2Output.selector
),
abi.encode(
L2OutputOracle.OutputProposal(
bytes32(uint256(1)),
0
)
)
);
// warp to the finalization period
vm.warp(op.FINALIZATION_PERIOD_SECONDS());
assertEq(op.isOutputFinalized(0), false);
// warp past the finalization period
vm.warp(op.FINALIZATION_PERIOD_SECONDS() + 1);
assertEq(op.isOutputFinalized(0), true);
}
function test_isOutputFinalized() external {
uint256 checkpoint = oracle.nextBlockNumber();
vm.roll(checkpoint);
vm.warp(oracle.computeL2Timestamp(checkpoint) + 1);
vm.prank(oracle.sequencer());
oracle.appendL2Output(keccak256(abi.encode(2)), checkpoint, 0, 0);
// warp to the final second of the finalization period
uint256 finalizationHorizon = block.timestamp + op.FINALIZATION_PERIOD_SECONDS();
vm.warp(finalizationHorizon);
// The checkpointed block should not be finalized until 1 second from now.
assertEq(op.isOutputFinalized(checkpoint), false);
// Nor should a block after it
assertEq(op.isOutputFinalized(checkpoint + 1), false);
// Nor a block before it, even though the finalization period has passed, there is
// not yet a checkpoint block on top of it for which that is true.
assertEq(op.isOutputFinalized(checkpoint - 1), false);
// warp past the finalization period
vm.warp(finalizationHorizon + 1);
// It should now be finalized.
assertEq(op.isOutputFinalized(checkpoint), true);
// So should the block before it.
assertEq(op.isOutputFinalized(checkpoint - 1), true);
// But not the block after it.
assertEq(op.isOutputFinalized(checkpoint + 1), false);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment