Commit 3093c21b authored by kf's avatar kf Committed by Kelvin Fichter

feat: separate l1blocknumber

parent 92c9692d
......@@ -2,7 +2,15 @@
pragma solidity >=0.7.0;
// Can't do this until the package is published.
//import { iOVM_L1BlockNumber } from "@eth-optimism/contracts/iOVM_L1BlockNumber";
interface iOVM_L1BlockNumber {
function getL1BlockNumber() external view returns (uint256);
}
contract OVMContextStorage {
mapping (uint256 => uint256) public l1BlockNumbers;
mapping (uint256 => uint256) public blockNumbers;
mapping (uint256 => uint256) public timestamps;
mapping (uint256 => uint256) public difficulty;
......@@ -10,6 +18,9 @@ contract OVMContextStorage {
uint256 public index = 0;
fallback() external {
l1BlockNumbers[index] = iOVM_L1BlockNumber(
0x4200000000000000000000000000000000000013
).getL1BlockNumber();
blockNumbers[index] = block.number;
timestamps[index] = block.timestamp;
difficulty[index] = block.difficulty;
......
......@@ -22,6 +22,10 @@ pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
// Can't do this until the package is published.
//import { iOVM_L1BlockNumber } from "@eth-optimism/contracts/iOVM_L1BlockNumber";
import { iOVM_L1BlockNumber } from "./OVMContextStorage.sol";
/// @title OVMMulticall - Aggregate results from multiple read-only function calls
contract OVMMulticall {
struct Call {
......@@ -44,8 +48,14 @@ contract OVMMulticall {
timestamp = block.timestamp;
}
function getCurrentBlockNumber() public view returns (uint256 blockNumber) {
blockNumber = block.number;
function getCurrentL1BlockNumber() public view returns (uint256) {
return iOVM_L1BlockNumber(
0x4200000000000000000000000000000000000013
).getL1BlockNumber();
}
function getCurrentBlockNumber() public view returns (uint256) {
return block.number;
}
function getChainID() external view returns (uint256) {
......
......@@ -47,32 +47,37 @@ describe('OVM Context: Layer 2 EVM Context', () => {
numTxs = 1
}
it('enqueue: `block.number` and `block.timestamp` have L1 values', async () => {
it('enqueue: L1 contextual values are correctly set in L2', async () => {
for (let i = 0; i < numTxs; i++) {
// Send a transaction from L1 to L2. This will automatically update the L1 contextual
// information like the L1 block number and L1 timestamp.
const tx = await env.l1Messenger.sendMessage(
OVMContextStorage.address,
'0x',
2_000_000
)
const receipt = await tx.wait()
// Get the receipt
// The transaction did not revert
expect(receipt.status).to.equal(1)
await env.waitForXDomainTransaction(tx, Direction.L1ToL2)
// Wait for the transaction to be sent over to L2.
await tx.wait()
const pair = await env.waitForXDomainTransaction(tx, Direction.L1ToL2)
// Get the L1 block that the enqueue transaction was in so that
// the timestamp can be compared against the layer two contract
const block = await l1Provider.getBlock(receipt.blockNumber)
const l1Block = await l1Provider.getBlock(pair.receipt.blockNumber)
const l2Block = await l2Provider.getBlock(pair.remoteReceipt.blockNumber)
// block.number should return the value of the L2 block number.
const l2BlockNumber = await OVMContextStorage.blockNumbers(i)
expect(l2BlockNumber.toNumber()).to.deep.equal(l2Block.number)
// L1BLOCKNUMBER opcode should return the value of the L1 block number.
const l1BlockNumber = await OVMContextStorage.l1BlockNumbers(i)
expect(l1BlockNumber.toNumber()).to.deep.equal(l1Block.number)
// The contact is a fallback function that keeps `block.number`
// and `block.timestamp` in a mapping based on an index that
// increments each time that there is a transaction.
const blockNumber = await OVMContextStorage.blockNumbers(i)
expect(receipt.blockNumber).to.deep.equal(blockNumber.toNumber())
// L1 and L2 blocks will have the same timestamp.
const timestamp = await OVMContextStorage.timestamps(i)
expect(block.timestamp).to.deep.equal(timestamp.toNumber())
expect(timestamp.toNumber()).to.deep.equal(l1Block.timestamp)
expect(timestamp.toNumber()).to.deep.equal(l2Block.timestamp)
// Difficulty should always be zero.
const difficulty = await OVMContextStorage.difficulty(i)
......@@ -106,16 +111,24 @@ describe('OVM Context: Layer 2 EVM Context', () => {
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData('getCurrentBlockNumber'),
],
[
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData(
'getCurrentL1BlockNumber'
),
],
],
{ blockTag: block.number }
)
const timestamp = BigNumber.from(returnData[0])
const blockNumber = BigNumber.from(returnData[1])
const l1BlockNumber = BigNumber.from(returnData[2])
const tx = block.transactions[0] as any
expect(tx.l1BlockNumber).to.deep.equal(blockNumber.toNumber())
expect(tx.l1BlockNumber).to.deep.equal(l1BlockNumber.toNumber())
expect(block.timestamp).to.deep.equal(timestamp.toNumber())
expect(block.number).to.deep.equal(blockNumber.toNumber())
}
})
......@@ -138,7 +151,7 @@ describe('OVM Context: Layer 2 EVM Context', () => {
],
[
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData('getCurrentBlockNumber'),
OVMMulticall.interface.encodeFunctionData('getCurrentL1BlockNumber'),
],
]),
])
......
......@@ -67,12 +67,13 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
GetHash: GetHashFn(header, chain),
Origin: msg.From(),
Coinbase: dump.OvmFeeWallet, // Coinbase is the fee vault.
BlockNumber: msg.L1BlockNumber(),
BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).SetUint64(msg.L1Timestamp()),
Difficulty: new(big.Int), // Difficulty always returns zero.
GasLimit: header.GasLimit,
GasPrice: new(big.Int).Set(msg.GasPrice()),
L1MessageSender: l1MessageSender,
L1BlockNumber: msg.L1BlockNumber(),
}
} else {
return vm.Context{
......
......@@ -115,6 +115,7 @@ type Context struct {
// OVM information
L1MessageSender common.Address // Provides information for L1MESSAGESENDER
L1BlockNumber *big.Int // Provides information for L1BLOCKNUMBER
}
// EVM is the Ethereum Virtual Machine base object and provides
......
......@@ -973,3 +973,8 @@ func opL1MessageSender(pc *uint64, interpreter *EVMInterpreter, contract *Contra
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.L1MessageSender.Bytes()))
return nil, nil
}
func opL1BlockNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.L1BlockNumber)))
return nil, nil
}
......@@ -1162,5 +1162,12 @@ func newFrontierInstructionSet() JumpTable {
maxStack: maxStack(0, 1),
valid: true,
},
L1BLOCKNUMBER: {
execute: opL1BlockNumber,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true,
},
}
}
......@@ -105,6 +105,7 @@ const (
SELFBALANCE = 0x47
L1MESSAGESENDER = 0x4A
L1BLOCKNUMBER = 0x4B
)
// 0x50 range - 'storage' and execution.
......@@ -287,6 +288,7 @@ var opCodeToString = map[OpCode]string{
// OVM opcodes
// 0x4A
L1MESSAGESENDER: "L1MESSAGESENDER",
L1BLOCKNUMBER: "L1BLOCKNUMBER",
// 0x50 range - 'storage' and execution.
POP: "POP",
......@@ -547,6 +549,7 @@ var stringToOp = map[string]OpCode{
// OVM opcodes
"L1MESSAGESENDER": L1MESSAGESENDER,
"L1BLOCKNUMBER": L1BLOCKNUMBER,
}
// StringToOp finds the opcode whose name is stored in `str`.
......
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title iOVM_L1BlockNumber
*/
interface iOVM_L1BlockNumber {
/********************
* Public Functions *
********************/
function getL1BlockNumber() external view returns (uint256);
}
......@@ -5,14 +5,16 @@ pragma solidity >0.5.0 <0.8.0;
* @title Lib_PredeployAddresses
*/
library Lib_PredeployAddresses {
// solhint-disable max-line-length
address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;
address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;
address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;
address payable internal constant OVM_ETH = 0x4200000000000000000000000000000000000006;
// solhint-disable-next-line max-line-length
address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007;
address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;
address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;
address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;
address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;
address internal constant L2_STANDARD_TOKEN_FACTORY = 0x4200000000000000000000000000000000000012;
address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;
}
......@@ -74,6 +74,9 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
// directly used in Solidity (yet). This bytecode string simply executes the 0x4A opcode
// and returns the address given by that opcode.
dump[predeployAddress].code = '0x4A60005260206000F3'
} else if (predeployName === 'OVM_L1BlockNumber') {
// Same as above but for OVM_L1BlockNumber (0x4B).
dump[predeployAddress].code = '0x4B60005260206000F3'
} else {
const artifact = getContractArtifact(predeployName)
dump[predeployAddress].code = artifact.deployedBytecode
......
......@@ -17,4 +17,5 @@ export const predeploys = {
OVM_L2StandardBridge: '0x4200000000000000000000000000000000000010',
OVM_SequencerFeeVault: '0x4200000000000000000000000000000000000011',
OVM_L2StandardTokenFactory: '0x4200000000000000000000000000000000000012',
OVM_L1BlockNumber: '0x4200000000000000000000000000000000000013',
}
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