Commit f4343792 authored by Liam Horne's avatar Liam Horne Committed by GitHub

Merge pull request #993 from ethereum-optimism/regenesis/0.4.0

Regenesis/0.4.0
parents 42decb6e 6ad1dcb9
---
'@eth-optimism/integration-tests': patch
'@eth-optimism/contracts': patch
---
Adds ERC1271 support to default contract account
---
'@eth-optimism/contracts': patch
---
Update the ECDSAContractAccount import path in the `contract-data.ts` file for connecting ethers contracts to the L2 contracts
---
'@eth-optimism/l2geth': patch
---
Add new config `ROLLUP_GAS_PRICE_ORACLE_OWNER_ADDRESS` to set the owner of the gas price oracle at runtime
---
'@eth-optimism/contracts': minor
---
Disables EOA contract upgrades until further notice
---
'@eth-optimism/contracts': patch
---
Apply consistent styling to constants
---
'@eth-optimism/l2geth': patch
'@eth-optimism/data-transport-layer': patch
---
Add extra overflow protection for the DTL types
---
'@eth-optimism/batch-submitter': patch
'@eth-optimism/contracts': patch
---
Use dashes instead of colons in contract names
---
'@eth-optimism/contracts': patch
---
Replaces RingBuffer with a simpler Buffer library
---
'@eth-optimism/contracts': minor
'@eth-optimism/integration-tests': patch
'@eth-optimism/l2geth': patch
---
Add a new Standard Token Bridge, to handle deposits and withdrawals of any ERC20 token.
For projects developing a custom bridge, if you were previously importing `iAbs_BaseCrossDomainMessenger`, you should now
import `iOVM_CrossDomainMessenger`.
---
'@eth-optimism/contracts': minor
'@eth-optimism/data-transport-layer': minor
---
Update AddressSet event to speed search up a bit. Breaks AddressSet API.
---
'@eth-optimism/integration-tests': patch
'@eth-optimism/contracts': patch
---
Add WETH9 compatible deposit and withdraw functions to OVM_ETH
---
'@eth-optimism/data-transport-layer': patch
---
Removes a function that was previously used for backwards compatibility but is no longer necessary
---
'@eth-optimism/contracts': patch
---
Deploy new Goerli contracts at d3e743aa7a406c583f7d76f4fda607f592d03e47
---
'@eth-optimism/l2geth': patch
---
Prevent overflows in abi encoding of ovm codec transaction from geth types.Transaction
---
'@eth-optimism/l2geth': patch
---
Update queueOrigin type
---
'@eth-optimism/contracts': patch
---
ECDSA account interface contract moved to predeploys dir
---
'@eth-optimism/contracts': patch
---
Deploy v0.4.0 rc to Kovan
---
'@eth-optimism/contracts': patch
---
Moved contracts in the "accounts" folder into the "predeploys" folder
---
'@eth-optimism/data-transport-layer': patch
---
Have DTL log failed HTTP requests as ERROR instead of INFO
---
'@eth-optimism/contracts': patch
---
Use predeploy constants lib for EM wrapper
---
'@eth-optimism/data-transport-layer': patch
---
Updates the DTL to use the same L2 chain ID everywhere
---
'@eth-optimism/l2geth': patch
---
Removes config options that are no longer required. `ROLLUP_DATAPRICE`, `ROLLUP_EXECUTION_PRICE`, `ROLLUP_GAS_PRICE_ORACLE_ADDRESS` and `ROLLUP_ENABLE_L2_GAS_POLLING`. The oracle was moved to a predeploy 0x42.. address and polling is always enabled as it no longer needs to be backwards compatible
---
'@eth-optimism/contracts': patch
---
Adds a temporary way to fund hardhat accounts when testing locally
---
'@eth-optimism/integration-tests': minor
'@eth-optimism/l2geth': minor
'@eth-optimism/contracts': minor
---
Add support for ovmCALL with nonzero ETH value
---
'@eth-optimism/contracts': patch
---
Removes one-off GasPriceOracle deployment file
---
'@eth-optimism/contracts': patch
---
Updates the deployment of the L1MultiMessageRelayer to NOT set the OVM_L2MessageRelayer address in the AddressManager
---
'@eth-optimism/l2geth': patch
---
Removes the gas refund for unused gas in geth since it is instead managed in the smart contracts
---
'@eth-optimism/contracts': patch
---
Disable upgradability from the ECDSA account instead of the EOA proxy.
---
'@eth-optimism/integration-tests': patch
'@eth-optimism/l2geth': patch
'@eth-optimism/contracts': patch
---
Adds new SequencerFeeVault contract to store generated fees
---
'@eth-optimism/l2geth': patch
---
Removes the SignatureHashType from l2geth as it is deprecated and no longer required.
---
'@eth-optimism/contracts': patch
---
Token gateways pass additional information: sender and arbitrary data.
---
'@eth-optimism/contracts': patch
---
Do not RLP decode the transaction in the OVM_ECDSAContractAccount
---
'@eth-optimism/contracts': patch
---
Introduce the L1ChugSplashProxy contract
...@@ -45,18 +45,18 @@ jobs: ...@@ -45,18 +45,18 @@ jobs:
run: docker-compose run integration_tests run: docker-compose run integration_tests
# Examples Tests # Examples Tests
- name: Test & deploy hardhat-example on Ethereum (regression) # - name: Test & deploy hardhat-example on Ethereum (regression)
working-directory: ./examples/hardhat # working-directory: ./examples/hardhat
run: | # run: |
yarn # yarn
yarn deploy # yarn deploy
yarn test:integration # yarn test:integration
- name: Test & deploy hardhat-example on Optimistic Ethereum # - name: Test & deploy hardhat-example on Optimistic Ethereum
working-directory: ./examples/hardhat # working-directory: ./examples/hardhat
run: | # run: |
yarn deploy:ovm # yarn deploy:ovm
yarn test:integration:ovm # yarn test:integration:ovm
- name: Test & deploy waffle-example on Ethereum (regression) - name: Test & deploy waffle-example on Ethereum (regression)
working-directory: ./examples/waffle working-directory: ./examples/waffle
...@@ -86,13 +86,13 @@ jobs: ...@@ -86,13 +86,13 @@ jobs:
yarn test:integration:ovm yarn test:integration:ovm
yarn deploy:ovm yarn deploy:ovm
- name: Test l1-l2-deposit-withdrawal example on Optimistic Ethereum with cross-domain message passing # - name: Test l1-l2-deposit-withdrawal example on Optimistic Ethereum with cross-domain message passing
working-directory: ./examples/l1-l2-deposit-withdrawal # working-directory: ./examples/l1-l2-deposit-withdrawal
run: | # run: |
yarn # yarn
yarn compile # yarn compile
yarn compile:ovm # yarn compile:ovm
yarn test:integration:ovm # yarn test:integration:ovm
- name: Collect docker logs on failure - name: Collect docker logs on failure
if: failure() if: failure()
...@@ -110,4 +110,4 @@ jobs: ...@@ -110,4 +110,4 @@ jobs:
uses: actions/upload-artifact@master uses: actions/upload-artifact@master
with: with:
name: logs.tgz name: logs.tgz
path: ./logs.tgz path: ./logs.tgz
\ No newline at end of file
...@@ -21,6 +21,7 @@ jobs: ...@@ -21,6 +21,7 @@ jobs:
message-relayer: ${{ steps.packages.outputs.message-relayer }} message-relayer: ${{ steps.packages.outputs.message-relayer }}
data-transport-layer: ${{ steps.packages.outputs.data-transport-layer }} data-transport-layer: ${{ steps.packages.outputs.data-transport-layer }}
contracts: ${{ steps.packages.outputs.contracts }} contracts: ${{ steps.packages.outputs.contracts }}
canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }}
steps: steps:
- name: Check out source code - name: Check out source code
...@@ -72,9 +73,9 @@ jobs: ...@@ -72,9 +73,9 @@ jobs:
node ops/scripts/ci-versions.js ${{ toJSON(steps.changesets.outputs.publishedPackages) }} node ops/scripts/ci-versions.js ${{ toJSON(steps.changesets.outputs.publishedPackages) }}
- name: Docker Image Name - name: Docker Image Name
id: docker_image_name id: docker-image-name
run: | run: |
if [ -z "${CUSTOM_IMAGE_NAME}" ] if [ ${CUSTOM_IMAGE_NAME} == '' ]
then then
echo "::set-output name=canary-docker-tag::${GITHUB_SHA::8}" echo "::set-output name=canary-docker-tag::${GITHUB_SHA::8}"
else else
...@@ -89,7 +90,7 @@ jobs: ...@@ -89,7 +90,7 @@ jobs:
# while also allowing for parallelization (i.e. `l2geth` not depending on `builder`) # while also allowing for parallelization (i.e. `l2geth` not depending on `builder`)
# and all jobs executing in parallel once `builder` is built # and all jobs executing in parallel once `builder` is built
l2geth: l2geth:
name: Publish L2Geth Version ${{ needs.canary-publish.outputs.l2geth }} name: Publish L2Geth Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish needs: canary-publish
if: needs.canary-publish.outputs.l2geth != '' if: needs.canary-publish.outputs.l2geth != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -112,7 +113,7 @@ jobs: ...@@ -112,7 +113,7 @@ jobs:
context: . context: .
file: ./ops/docker/Dockerfile.geth file: ./ops/docker/Dockerfile.geth
push: true push: true
tags: ethereumoptimism/l2geth:${{ steps.docker_image_name.outputs.canary-docker-tag }} tags: ethereumoptimism/l2geth:${{ needs.canary-publish.outputs.canary-docker-tag }}
# pushes the base builder image to dockerhub # pushes the base builder image to dockerhub
builder: builder:
...@@ -127,6 +128,8 @@ jobs: ...@@ -127,6 +128,8 @@ jobs:
data-transport-layer: ${{ needs.canary-publish.outputs.data-transport-layer }} data-transport-layer: ${{ needs.canary-publish.outputs.data-transport-layer }}
contracts: ${{ needs.canary-publish.outputs.contracts }} contracts: ${{ needs.canary-publish.outputs.contracts }}
integration-tests: ${{ needs.canary-publish.outputs.integration-tests }} integration-tests: ${{ needs.canary-publish.outputs.integration-tests }}
canary-docker-tag: ${{ needs.canary-publish.outputs.canary-docker-tag }}
steps: steps:
- name: Checkout - name: Checkout
...@@ -149,7 +152,7 @@ jobs: ...@@ -149,7 +152,7 @@ jobs:
tags: ethereumoptimism/builder tags: ethereumoptimism/builder
message-relayer: message-relayer:
name: Publish Message Relayer Version ${{ needs.builder.outputs.message-relayer }} name: Publish Message Relayer Version ${{ needs.builder.outputs.canary-docker-tag }}
needs: builder needs: builder
if: needs.builder.outputs.message-relayer != '' if: needs.builder.outputs.message-relayer != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -172,10 +175,10 @@ jobs: ...@@ -172,10 +175,10 @@ jobs:
context: . context: .
file: ./ops/docker/Dockerfile.message-relayer file: ./ops/docker/Dockerfile.message-relayer
push: true push: true
tags: ethereumoptimism/message-relayer:${{ steps.docker_image_name.outputs.canary-docker-tag }} tags: ethereumoptimism/message-relayer:${{ needs.builder.outputs.canary-docker-tag }}
batch-submitter: batch-submitter:
name: Publish Batch Submitter Version ${{ needs.builder.outputs.batch-submitter }} name: Publish Batch Submitter Version ${{ needs.builder.outputs.canary-docker-tag }}
needs: builder needs: builder
if: needs.builder.outputs.batch-submitter != '' if: needs.builder.outputs.batch-submitter != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -198,10 +201,10 @@ jobs: ...@@ -198,10 +201,10 @@ jobs:
context: . context: .
file: ./ops/docker/Dockerfile.batch-submitter file: ./ops/docker/Dockerfile.batch-submitter
push: true push: true
tags: ethereumoptimism/batch-submitter:${{ steps.docker_image_name.outputs.canary-docker-tag }} tags: ethereumoptimism/batch-submitter:${{ needs.builder.outputs.canary-docker-tag }}
data-transport-layer: data-transport-layer:
name: Publish Data Transport Layer Version ${{ needs.builder.outputs.data-transport-layer }} name: Publish Data Transport Layer Version ${{ needs.builder.outputs.canary-docker-tag }}
needs: builder needs: builder
if: needs.builder.outputs.data-transport-layer != '' if: needs.builder.outputs.data-transport-layer != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -224,10 +227,10 @@ jobs: ...@@ -224,10 +227,10 @@ jobs:
context: . context: .
file: ./ops/docker/Dockerfile.data-transport-layer file: ./ops/docker/Dockerfile.data-transport-layer
push: true push: true
tags: ethereumoptimism/data-transport-layer:${{ steps.docker_image_name.outputs.canary-docker-tag }} tags: ethereumoptimism/data-transport-layer:${{ needs.builder.outputs.canary-docker-tag }}
contracts: contracts:
name: Publish Deployer Version ${{ needs.builder.outputs.contracts }} name: Publish Deployer Version ${{ needs.builder.outputs.canary-docker-tag }}
needs: builder needs: builder
if: needs.builder.outputs.contracts != '' if: needs.builder.outputs.contracts != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -250,7 +253,7 @@ jobs: ...@@ -250,7 +253,7 @@ jobs:
context: . context: .
file: ./ops/docker/Dockerfile.deployer file: ./ops/docker/Dockerfile.deployer
push: true push: true
tags: ethereumoptimism/deployer:${{ steps.docker_image_name.outputs.canary-docker-tag }} tags: ethereumoptimism/deployer:${{ needs.builder.outputs.canary-docker-tag }}
integration_tests: integration_tests:
name: Publish Integration tests ${{ needs.builder.outputs.integration-tests }} name: Publish Integration tests ${{ needs.builder.outputs.integration-tests }}
...@@ -276,4 +279,4 @@ jobs: ...@@ -276,4 +279,4 @@ jobs:
context: . context: .
file: ./ops/docker/Dockerfile.integration-tests file: ./ops/docker/Dockerfile.integration-tests
push: true push: true
tags: ethereumoptimism/integration-tests:${{ steps.docker_image_name.outputs.canary-docker-tag }} tags: ethereumoptimism/integration-tests:${{ needs.builder.outputs.canary-docker-tag }}
...@@ -24,3 +24,4 @@ packages/data-transport-layer/db ...@@ -24,3 +24,4 @@ packages/data-transport-layer/db
*.swp *.swp
.env .env
*.log
...@@ -11,7 +11,7 @@ const factory = (name, ovm = false) => { ...@@ -11,7 +11,7 @@ const factory = (name, ovm = false) => {
} }
const factory__L1_ERC20 = factory('ERC20') const factory__L1_ERC20 = factory('ERC20')
const factory__L2_ERC20 = factory('L2DepositedERC20', true) const factory__L2_ERC20 = factory('L2DepositedERC20', true)
const factory__L1_ERC20Gateway = getContractFactory('OVM_L1ERC20Gateway') const factory__L1StandardBridge = getContractFactory('OVM_L1StandardBridge')
describe(`L1 <> L2 Deposit and Withdrawal`, () => { describe(`L1 <> L2 Deposit and Withdrawal`, () => {
...@@ -50,7 +50,7 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => { ...@@ -50,7 +50,7 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => {
let L1_ERC20, let L1_ERC20,
L2_ERC20, L2_ERC20,
L1_ERC20Gateway L1StandardBridge
before(`deploy contracts`, async () => { before(`deploy contracts`, async () => {
// Deploy an ERC20 token on L1. // Deploy an ERC20 token on L1.
...@@ -75,8 +75,8 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => { ...@@ -75,8 +75,8 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => {
await L2_ERC20.deployTransaction.wait() await L2_ERC20.deployTransaction.wait()
// Create a gateway that connects the two contracts. // Create a bridge that connects the two contracts.
L1_ERC20Gateway = await factory__L1_ERC20Gateway.connect(l1Wallet).deploy( L1StandardBridge = await factory__L1StandardBridge.connect(l1Wallet).deploy(
L1_ERC20.address, L1_ERC20.address,
L2_ERC20.address, L2_ERC20.address,
l1MessengerAddress, l1MessengerAddress,
...@@ -85,12 +85,12 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => { ...@@ -85,12 +85,12 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => {
} }
) )
await L1_ERC20Gateway.deployTransaction.wait() await L1StandardBridge.deployTransaction.wait()
}) })
describe('Initialization and initial balances', async () => { describe('Initialization and initial balances', async () => {
it(`should initialize L2 ERC20`, async () => { it(`should initialize L2 ERC20`, async () => {
const tx = await L2_ERC20.init(L1_ERC20Gateway.address, { gasPrice: 0 }) const tx = await L2_ERC20.init(L1StandardBridge.address, { gasPrice: 0 })
await tx.wait() await tx.wait()
const txHashPrefix = tx.hash.slice(0, 2) const txHashPrefix = tx.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x') expect(txHashPrefix).to.eq('0x')
...@@ -107,15 +107,15 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => { ...@@ -107,15 +107,15 @@ describe(`L1 <> L2 Deposit and Withdrawal`, () => {
describe('L1 to L2 deposit', async () => { describe('L1 to L2 deposit', async () => {
let l1Tx1 let l1Tx1
it(`should approve 1234 tokens for ERC20 gateway`, async () => { it(`should approve 1234 tokens for ERC20 bridge`, async () => {
const tx = await L1_ERC20.approve(L1_ERC20Gateway.address, 1234) const tx = await L1_ERC20.approve(L1StandardBridge.address, 1234)
await tx.wait() await tx.wait()
const txHashPrefix = tx.hash.slice(0, 2) const txHashPrefix = tx.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x') expect(txHashPrefix).to.eq('0x')
}) })
it(`should deposit 1234 tokens into L2 ERC20`, async () => { it(`should deposit 1234 tokens into L2 ERC20`, async () => {
l1Tx1 = await L1_ERC20Gateway.deposit(1234, { gasPrice: 0 }) l1Tx1 = await L1StandardBridge.deposit(1234, { gasPrice: 0 })
await l1Tx1.wait() await l1Tx1.wait()
const txHashPrefix = l1Tx1.hash.slice(0, 2) const txHashPrefix = l1Tx1.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x') expect(txHashPrefix).to.eq('0x')
......
...@@ -2,10 +2,16 @@ ...@@ -2,10 +2,16 @@
pragma solidity >=0.7.0; pragma solidity >=0.7.0;
contract TestOOG { contract TestOOG {
constructor() { function runOutOfGas() public {
bytes32 h; bytes32 h;
for (uint256 i = 0; i < 100000; i++) { for (uint256 i = 0; i < 100000; i++) {
h = keccak256(abi.encodePacked(h)); h = keccak256(abi.encodePacked(h));
} }
} }
} }
contract TestOOGInConstructor is TestOOG {
constructor() {
runOutOfGas();
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;
contract ValueContext {
function getSelfBalance() external payable returns(uint256) {
uint selfBalance;
assembly {
selfBalance := selfbalance()
}
return selfBalance;
}
function getAddressThisBalance() external view returns(uint256) {
return address(this).balance;
}
function getBalance(
address _address
) external payable returns(uint256) {
return _address.balance;
}
function getCallValue() public payable returns(uint256) {
return msg.value;
}
}
contract ValueCalls is ValueContext {
receive() external payable {}
function nonPayable() external {}
function simpleSend(
address _address,
uint _value
) external payable returns (bool, bytes memory) {
return sendWithData(_address, _value, hex"");
}
function sendWithDataAndGas(
address _address,
uint _value,
uint _gasLimit,
bytes memory _calldata
) public returns (bool, bytes memory) {
return _address.call{value: _value, gas: _gasLimit}(_calldata);
}
function sendWithData(
address _address,
uint _value,
bytes memory _calldata
) public returns (bool, bytes memory) {
return _address.call{value: _value}(_calldata);
}
function verifyCallValueAndRevert(
uint256 _expectedValue
) external payable {
bool correct = _checkCallValue(_expectedValue);
// do the opposite of expected if the value is wrong.
if (correct) {
revert("expected revert");
} else {
return;
}
}
function verifyCallValueAndReturn(
uint256 _expectedValue
) external payable {
bool correct = _checkCallValue(_expectedValue);
// do the opposite of expected if the value is wrong.
if (correct) {
return;
} else {
revert("unexpected revert");
}
}
function delegateCallToCallValue(
address _valueContext
) public payable returns(bool, bytes memory) {
bytes memory data = abi.encodeWithSelector(ValueContext.getCallValue.selector);
return _valueContext.delegatecall(data);
}
function delegateCallToAddressThisBalance(
address _valueContext
) public payable returns(bool, bytes memory) {
bytes memory data = abi.encodeWithSelector(ValueContext.getAddressThisBalance.selector);
return _valueContext.delegatecall(data);
}
function _checkCallValue(
uint256 _expectedValue
) internal returns(bool) {
return getCallValue() == _expectedValue;
}
}
contract ValueGasMeasurer {
function measureGasOfTransferingEthViaCall(
address target,
uint256 value,
uint256 gasLimit
) public returns(uint256) {
uint256 gasBefore = gasleft();
assembly {
pop(call(gasLimit, target, value, 0, 0, 0, 0))
}
return gasBefore - gasleft();
}
}
contract PayableConstant {
function returnValue() external payable returns(uint256) {
return 42;
}
}
contract SendETHAwayAndDelegateCall {
function emptySelfAndDelegateCall(
address _delegateTo,
bytes memory _data
) public payable returns (bool, bytes memory) {
address(0).call{value: address(this).balance}(_data);
return _delegateTo.delegatecall(_data);
}
}
...@@ -20,7 +20,7 @@ const config: HardhatUserConfig = { ...@@ -20,7 +20,7 @@ const config: HardhatUserConfig = {
}, },
solidity: '0.7.6', solidity: '0.7.6',
ovm: { ovm: {
solcVersion: '0.7.6', solcVersion: '0.7.6+commit.3b061308',
}, },
gasReporter: { gasReporter: {
enabled: enableGasReport, enabled: enableGasReport,
......
import chai, { expect } from 'chai' import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised' import chaiAsPromised from 'chai-as-promised'
chai.use(chaiAsPromised) chai.use(chaiAsPromised)
import { BigNumber, utils } from 'ethers'
import { OptimismEnv } from './shared/env' /* Imports: External */
import { BigNumber, Contract, utils } from 'ethers'
import { TxGasLimit, TxGasPrice } from '@eth-optimism/core-utils' import { TxGasLimit, TxGasPrice } from '@eth-optimism/core-utils'
import { predeploys, getContractInterface } from '@eth-optimism/contracts'
/* Imports: Internal */
import { OptimismEnv } from './shared/env'
import { Direction } from './shared/watcher-utils'
describe('Fee Payment Integration Tests', async () => { describe('Fee Payment Integration Tests', async () => {
let env: OptimismEnv
const other = '0x1234123412341234123412341234123412341234' const other = '0x1234123412341234123412341234123412341234'
let env: OptimismEnv
before(async () => { before(async () => {
env = await OptimismEnv.new() env = await OptimismEnv.new()
}) })
let ovmSequencerFeeVault: Contract
before(async () => {
ovmSequencerFeeVault = new Contract(
predeploys.OVM_SequencerFeeVault,
getContractInterface('OVM_SequencerFeeVault'),
env.l2Wallet
)
})
it(`Should return a gasPrice of ${TxGasPrice.toString()} wei`, async () => { it(`Should return a gasPrice of ${TxGasPrice.toString()} wei`, async () => {
const gasPrice = await env.l2Wallet.getGasPrice() const gasPrice = await env.l2Wallet.getGasPrice()
expect(gasPrice).to.deep.eq(TxGasPrice) expect(gasPrice).to.deep.eq(TxGasPrice)
...@@ -36,6 +51,9 @@ describe('Fee Payment Integration Tests', async () => { ...@@ -36,6 +51,9 @@ describe('Fee Payment Integration Tests', async () => {
it('Paying a nonzero but acceptable gasPrice fee', async () => { it('Paying a nonzero but acceptable gasPrice fee', async () => {
const amount = utils.parseEther('0.5') const amount = utils.parseEther('0.5')
const balanceBefore = await env.l2Wallet.getBalance() const balanceBefore = await env.l2Wallet.getBalance()
const feeVaultBalanceBefore = await env.l2Wallet.provider.getBalance(
ovmSequencerFeeVault.address
)
expect(balanceBefore.gt(amount)) expect(balanceBefore.gt(amount))
const tx = await env.ovmEth.transfer(other, amount) const tx = await env.ovmEth.transfer(other, amount)
...@@ -43,10 +61,53 @@ describe('Fee Payment Integration Tests', async () => { ...@@ -43,10 +61,53 @@ describe('Fee Payment Integration Tests', async () => {
expect(receipt.status).to.eq(1) expect(receipt.status).to.eq(1)
const balanceAfter = await env.l2Wallet.getBalance() const balanceAfter = await env.l2Wallet.getBalance()
const feeVaultBalanceAfter = await env.l2Wallet.provider.getBalance(
ovmSequencerFeeVault.address
)
const expectedFeePaid = tx.gasPrice.mul(tx.gasLimit)
// The fee paid MUST be the receipt.gasUsed, and not the tx.gasLimit // The fee paid MUST be the receipt.gasUsed, and not the tx.gasLimit
// https://github.com/ethereum-optimism/optimism/blob/0de7a2f9c96a7c4860658822231b2d6da0fefb1d/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol#L103 // https://github.com/ethereum-optimism/optimism/blob/0de7a2f9c96a7c4860658822231b2d6da0fefb1d/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol#L103
expect(balanceBefore.sub(balanceAfter)).to.be.deep.eq( expect(balanceBefore.sub(balanceAfter)).to.deep.equal(
tx.gasPrice.mul(tx.gasLimit).add(amount) expectedFeePaid.add(amount)
)
// Make sure the fee was transferred to the vault.
expect(feeVaultBalanceAfter.sub(feeVaultBalanceBefore)).to.deep.equal(
expectedFeePaid
)
})
it('should not be able to withdraw fees before the minimum is met', async () => {
await expect(ovmSequencerFeeVault.withdraw()).to.be.rejected
})
it('should be able to withdraw fees back to L1 once the minimum is met', async () => {
const l1FeeWallet = await ovmSequencerFeeVault.l1FeeWallet()
const balanceBefore = await env.l1Wallet.provider.getBalance(l1FeeWallet)
// Transfer the minimum required to withdraw.
await env.ovmEth.transfer(
ovmSequencerFeeVault.address,
await ovmSequencerFeeVault.MIN_WITHDRAWAL_AMOUNT()
)
const vaultBalance = await env.ovmEth.balanceOf(
ovmSequencerFeeVault.address
)
// Submit the withdrawal.
const withdrawTx = await ovmSequencerFeeVault.withdraw({
gasPrice: 0, // Need a gasprice of 0 or the balances will include the fee paid during this tx.
})
// Wait for the withdrawal to be relayed to L1.
await env.waitForXDomainTransaction(withdrawTx, Direction.L2ToL1)
// Balance difference should be equal to old L2 balance.
const balanceAfter = await env.l1Wallet.provider.getBalance(l1FeeWallet)
expect(balanceAfter.sub(balanceBefore)).to.deep.equal(
BigNumber.from(vaultBalance)
) )
}) })
}) })
This diff is collapsed.
This diff is collapsed.
import { expect } from 'chai'
import { ethers } from 'hardhat'
/* Imports: External */
import { Contract, Wallet } from 'ethers'
import { OptimismEnv } from './shared/env'
import { DEFAULT_TRANSACTION } from './shared/utils'
import { getContractInterface } from '@eth-optimism/contracts'
describe('ECDSAContractAccount', () => {
let l2Wallet: Wallet
before(async () => {
const env = await OptimismEnv.new()
l2Wallet = env.l2Wallet
})
let ProxyEOA: Contract
let messageHash: string
let signature: string
before(async () => {
// Send a transaction to ensure there is a ProxyEOA deployed at l2Wallet.address
const result = await l2Wallet.sendTransaction(DEFAULT_TRANSACTION)
await result.wait()
ProxyEOA = new Contract(
l2Wallet.address,
getContractInterface('OVM_ECDSAContractAccount'),
l2Wallet
)
const message = '0x42'
messageHash = ethers.utils.hashMessage(message)
signature = await l2Wallet.signMessage(message)
})
it('should correctly evaluate isValidSignature from this wallet', async () => {
const isValid = await ProxyEOA.isValidSignature(messageHash, signature)
expect(isValid).to.equal('0x1626ba7e')
})
it('should correctly evaluate isValidSignature from other wallet', async () => {
const otherWallet = Wallet.createRandom().connect(l2Wallet.provider)
const isValid = await ProxyEOA.connect(otherWallet).isValidSignature(
messageHash,
signature
)
expect(isValid).to.equal('0x1626ba7e')
})
})
...@@ -86,8 +86,6 @@ describe('Queue Ingestion', () => { ...@@ -86,8 +86,6 @@ describe('Queue Ingestion', () => {
// The `to` addresses are defined in the previous test and // The `to` addresses are defined in the previous test and
// increment sequentially. // increment sequentially.
expect(tx.to).to.be.equal('0x' + `${i}`.repeat(40)) expect(tx.to).to.be.equal('0x' + `${i}`.repeat(40))
// The transaction type is EIP155
expect(tx.txType).to.be.equal('EIP155')
// The queue origin is Layer 1 // The queue origin is Layer 1
expect(tx.queueOrigin).to.be.equal('l1') expect(tx.queueOrigin).to.be.equal('l1')
// the L1TxOrigin is equal to the Layer one from // the L1TxOrigin is equal to the Layer one from
......
...@@ -4,10 +4,16 @@ import { ...@@ -4,10 +4,16 @@ import {
TxGasPrice, TxGasPrice,
toRpcHexString, toRpcHexString,
} from '@eth-optimism/core-utils' } from '@eth-optimism/core-utils'
import { Wallet, BigNumber, Contract } from 'ethers' import { Wallet, BigNumber, Contract, ContractFactory } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import chai, { expect } from 'chai' import chai, { expect } from 'chai'
import { sleep, l2Provider, l1Provider } from './shared/utils' import {
sleep,
l2Provider,
DEFAULT_TRANSACTION,
fundUser,
expectApprox,
} from './shared/utils'
import chaiAsPromised from 'chai-as-promised' import chaiAsPromised from 'chai-as-promised'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { import {
...@@ -22,14 +28,6 @@ describe('Basic RPC tests', () => { ...@@ -22,14 +28,6 @@ describe('Basic RPC tests', () => {
let env: OptimismEnv let env: OptimismEnv
let wallet: Wallet let wallet: Wallet
const DEFAULT_TRANSACTION = {
to: '0x' + '1234'.repeat(10),
gasLimit: 33600000000001,
gasPrice: 0,
data: '0x',
value: 0,
}
const provider = injectL2Context(l2Provider) const provider = injectL2Context(l2Provider)
let Reverter: Contract let Reverter: Contract
...@@ -154,7 +152,7 @@ describe('Basic RPC tests', () => { ...@@ -154,7 +152,7 @@ describe('Basic RPC tests', () => {
}) })
it('should correctly report OOG for contract creations', async () => { it('should correctly report OOG for contract creations', async () => {
const factory = await ethers.getContractFactory('TestOOG') const factory = await ethers.getContractFactory('TestOOGInConstructor')
await expect(factory.connect(wallet).deploy()).to.be.rejectedWith( await expect(factory.connect(wallet).deploy()).to.be.rejectedWith(
'gas required exceeds allowance' 'gas required exceeds allowance'
...@@ -207,6 +205,32 @@ describe('Basic RPC tests', () => { ...@@ -207,6 +205,32 @@ describe('Basic RPC tests', () => {
'Contract creation code contains unsafe opcodes. Did you use the right compiler or pass an unsafe constructor argument?' 'Contract creation code contains unsafe opcodes. Did you use the right compiler or pass an unsafe constructor argument?'
) )
}) })
it('should allow eth_calls with nonzero value', async () => {
// Deploy a contract to check msg.value of the call
const Factory__ValueContext: ContractFactory = await ethers.getContractFactory(
'ValueContext',
wallet
)
const ValueContext: Contract = await Factory__ValueContext.deploy()
await ValueContext.deployTransaction.wait()
// Fund account to call from
const from = wallet.address
const value = 15
await fundUser(env.watcher, env.l1Bridge, value, from)
// Do the call and check msg.value
const data = ValueContext.interface.encodeFunctionData('getCallValue')
const res = await provider.call({
to: ValueContext.address,
from,
data,
value,
})
expect(res).to.eq(BigNumber.from(value))
})
}) })
describe('eth_getTransactionReceipt', () => { describe('eth_getTransactionReceipt', () => {
...@@ -236,7 +260,7 @@ describe('Basic RPC tests', () => { ...@@ -236,7 +260,7 @@ describe('Basic RPC tests', () => {
it('correctly exposes revert data for contract creations', async () => { it('correctly exposes revert data for contract creations', async () => {
const req: TransactionRequest = { const req: TransactionRequest = {
...revertingDeployTx, ...revertingDeployTx,
gasLimit: 17700899, // override gas estimation gasLimit: 27700899, // override gas estimation
} }
const tx = await wallet.sendTransaction(req) const tx = await wallet.sendTransaction(req)
...@@ -264,7 +288,6 @@ describe('Basic RPC tests', () => { ...@@ -264,7 +288,6 @@ describe('Basic RPC tests', () => {
await result.wait() await result.wait()
const transaction = (await provider.getTransaction(result.hash)) as any const transaction = (await provider.getTransaction(result.hash)) as any
expect(transaction.txType).to.equal('EIP155')
expect(transaction.queueOrigin).to.equal('sequencer') expect(transaction.queueOrigin).to.equal('sequencer')
expect(transaction.transactionIndex).to.be.eq(0) expect(transaction.transactionIndex).to.be.eq(0)
expect(transaction.gasLimit).to.be.deep.eq(BigNumber.from(tx.gasLimit)) expect(transaction.gasLimit).to.be.deep.eq(BigNumber.from(tx.gasLimit))
...@@ -285,7 +308,6 @@ describe('Basic RPC tests', () => { ...@@ -285,7 +308,6 @@ describe('Basic RPC tests', () => {
expect(block.number).to.not.equal(0) expect(block.number).to.not.equal(0)
expect(typeof block.stateRoot).to.equal('string') expect(typeof block.stateRoot).to.equal('string')
expect(block.transactions.length).to.equal(1) expect(block.transactions.length).to.equal(1)
expect(block.transactions[0].txType).to.equal('EIP155')
expect(block.transactions[0].queueOrigin).to.equal('sequencer') expect(block.transactions[0].queueOrigin).to.equal('sequencer')
expect(block.transactions[0].l1TxOrigin).to.equal(null) expect(block.transactions[0].l1TxOrigin).to.equal(null)
}) })
...@@ -355,7 +377,8 @@ describe('Basic RPC tests', () => { ...@@ -355,7 +377,8 @@ describe('Basic RPC tests', () => {
to: DEFAULT_TRANSACTION.to, to: DEFAULT_TRANSACTION.to,
value: 0, value: 0,
}) })
expect(estimate).to.be.eq(5920012) // Expect gas to be less than or equal to the target plus 1%
expectApprox(estimate, 5920012, 1)
}) })
it('should return a gas estimate that grows with the size of data', async () => { it('should return a gas estimate that grows with the size of data', async () => {
......
...@@ -9,7 +9,8 @@ import { ...@@ -9,7 +9,8 @@ import {
l2Wallet, l2Wallet,
fundUser, fundUser,
getOvmEth, getOvmEth,
getGateway, getL1Bridge,
getL2Bridge,
} from './utils' } from './utils'
import { import {
initWatcher, initWatcher,
...@@ -23,12 +24,13 @@ import { TransactionResponse } from '@ethersproject/providers' ...@@ -23,12 +24,13 @@ import { TransactionResponse } from '@ethersproject/providers'
export class OptimismEnv { export class OptimismEnv {
// L1 Contracts // L1 Contracts
addressManager: Contract addressManager: Contract
gateway: Contract l1Bridge: Contract
l1Messenger: Contract l1Messenger: Contract
ctc: Contract ctc: Contract
// L2 Contracts // L2 Contracts
ovmEth: Contract ovmEth: Contract
l2Bridge: Contract
l2Messenger: Contract l2Messenger: Contract
// The L1 <> L2 State watcher // The L1 <> L2 State watcher
...@@ -40,9 +42,10 @@ export class OptimismEnv { ...@@ -40,9 +42,10 @@ export class OptimismEnv {
constructor(args: any) { constructor(args: any) {
this.addressManager = args.addressManager this.addressManager = args.addressManager
this.gateway = args.gateway this.l1Bridge = args.l1Bridge
this.l1Messenger = args.l1Messenger this.l1Messenger = args.l1Messenger
this.ovmEth = args.ovmEth this.ovmEth = args.ovmEth
this.l2Bridge = args.l2Bridge
this.l2Messenger = args.l2Messenger this.l2Messenger = args.l2Messenger
this.watcher = args.watcher this.watcher = args.watcher
this.l1Wallet = args.l1Wallet this.l1Wallet = args.l1Wallet
...@@ -53,18 +56,18 @@ export class OptimismEnv { ...@@ -53,18 +56,18 @@ export class OptimismEnv {
static async new(): Promise<OptimismEnv> { static async new(): Promise<OptimismEnv> {
const addressManager = getAddressManager(l1Wallet) const addressManager = getAddressManager(l1Wallet)
const watcher = await initWatcher(l1Provider, l2Provider, addressManager) const watcher = await initWatcher(l1Provider, l2Provider, addressManager)
const gateway = await getGateway(l1Wallet, addressManager) const l1Bridge = await getL1Bridge(l1Wallet, addressManager)
// fund the user if needed // fund the user if needed
const balance = await l2Wallet.getBalance() const balance = await l2Wallet.getBalance()
if (balance.isZero()) { if (balance.isZero()) {
await fundUser(watcher, gateway, utils.parseEther('10')) await fundUser(watcher, l1Bridge, utils.parseEther('20'))
} }
const ovmEth = getOvmEth(l2Wallet)
const l1Messenger = getContractFactory('iOVM_L1CrossDomainMessenger') const l1Messenger = getContractFactory('iOVM_L1CrossDomainMessenger')
.connect(l1Wallet) .connect(l1Wallet)
.attach(watcher.l1.messengerAddress) .attach(watcher.l1.messengerAddress)
const ovmEth = getOvmEth(l2Wallet)
const l2Bridge = await getL2Bridge(l2Wallet)
const l2Messenger = getContractFactory('iOVM_L2CrossDomainMessenger') const l2Messenger = getContractFactory('iOVM_L2CrossDomainMessenger')
.connect(l2Wallet) .connect(l2Wallet)
.attach(watcher.l2.messengerAddress) .attach(watcher.l2.messengerAddress)
...@@ -78,10 +81,11 @@ export class OptimismEnv { ...@@ -78,10 +81,11 @@ export class OptimismEnv {
return new OptimismEnv({ return new OptimismEnv({
addressManager, addressManager,
gateway, l1Bridge,
ctc, ctc,
l1Messenger, l1Messenger,
ovmEth, ovmEth,
l2Bridge,
l2Messenger, l2Messenger,
watcher, watcher,
l1Wallet, l1Wallet,
......
import { expect } from 'chai'
import { Direction, waitForXDomainTransaction } from './watcher-utils' import { Direction, waitForXDomainTransaction } from './watcher-utils'
import { import {
getContractFactory, getContractFactory,
getContractInterface, getContractInterface,
predeploys,
} from '@eth-optimism/contracts' } from '@eth-optimism/contracts'
import { injectL2Context, remove0x, Watcher } from '@eth-optimism/core-utils' import { injectL2Context, remove0x, Watcher } from '@eth-optimism/core-utils'
import { import {
...@@ -59,7 +62,7 @@ export const l2Wallet = l1Wallet.connect(l2Provider) ...@@ -59,7 +62,7 @@ export const l2Wallet = l1Wallet.connect(l2Provider)
// Predeploys // Predeploys
export const PROXY_SEQUENCER_ENTRYPOINT_ADDRESS = export const PROXY_SEQUENCER_ENTRYPOINT_ADDRESS =
'0x4200000000000000000000000000000000000004' '0x4200000000000000000000000000000000000004'
export const OVM_ETH_ADDRESS = '0x4200000000000000000000000000000000000006' export const OVM_ETH_ADDRESS = predeploys.OVM_ETH
export const getAddressManager = (provider: any) => { export const getAddressManager = (provider: any) => {
return getContractFactory('Lib_AddressManager') return getContractFactory('Lib_AddressManager')
...@@ -67,24 +70,37 @@ export const getAddressManager = (provider: any) => { ...@@ -67,24 +70,37 @@ export const getAddressManager = (provider: any) => {
.attach(env.ADDRESS_MANAGER) .attach(env.ADDRESS_MANAGER)
} }
// Gets the gateway using the proxy if available // Gets the bridge contract
export const getGateway = async (wallet: Wallet, AddressManager: Contract) => { export const getL1Bridge = async (wallet: Wallet, AddressManager: Contract) => {
const l1GatewayInterface = getContractInterface('OVM_L1ETHGateway') const l1BridgeInterface = getContractInterface('OVM_L1StandardBridge')
const ProxyGatewayAddress = await AddressManager.getAddress( const ProxyBridgeAddress = await AddressManager.getAddress(
'Proxy__OVM_L1ETHGateway' 'Proxy__OVM_L1StandardBridge'
) )
const addressToUse =
ProxyGatewayAddress !== constants.AddressZero if (
? ProxyGatewayAddress !utils.isAddress(ProxyBridgeAddress) ||
: await AddressManager.getAddress('OVM_L1ETHGateway') ProxyBridgeAddress === constants.AddressZero
) {
const OVM_L1ETHGateway = new Contract( throw new Error('Proxy__OVM_L1StandardBridge not found')
addressToUse, }
l1GatewayInterface,
const OVM_L1StandardBridge = new Contract(
ProxyBridgeAddress,
l1BridgeInterface,
wallet wallet
) )
return OVM_L1StandardBridge
}
export const getL2Bridge = async (wallet: Wallet) => {
const L2BridgeInterface = getContractInterface('OVM_L2StandardBridge')
return OVM_L1ETHGateway const OVM_L2StandardBridge = new Contract(
predeploys.OVM_L2StandardBridge,
L2BridgeInterface,
wallet
)
return OVM_L2StandardBridge
} }
export const getOvmEth = (wallet: Wallet) => { export const getOvmEth = (wallet: Wallet) => {
...@@ -99,14 +115,15 @@ export const getOvmEth = (wallet: Wallet) => { ...@@ -99,14 +115,15 @@ export const getOvmEth = (wallet: Wallet) => {
export const fundUser = async ( export const fundUser = async (
watcher: Watcher, watcher: Watcher,
gateway: Contract, bridge: Contract,
amount: BigNumberish, amount: BigNumberish,
recipient?: string recipient?: string
) => { ) => {
const value = BigNumber.from(amount) const value = BigNumber.from(amount)
const tx = recipient const tx = recipient
? gateway.depositTo(recipient, { value }) ? bridge.depositETHTo(recipient, 1_300_000, '0x', { value })
: gateway.deposit({ value }) : bridge.depositETH(1_300_000, '0x', { value })
await waitForXDomainTransaction(watcher, tx, Direction.L1ToL2) await waitForXDomainTransaction(watcher, tx, Direction.L1ToL2)
} }
...@@ -117,6 +134,46 @@ export const encodeSolidityRevertMessage = (_reason: string): string => { ...@@ -117,6 +134,46 @@ export const encodeSolidityRevertMessage = (_reason: string): string => {
return '0x08c379a0' + remove0x(abiCoder.encode(['string'], [_reason])) return '0x08c379a0' + remove0x(abiCoder.encode(['string'], [_reason]))
} }
export const DEFAULT_TRANSACTION = {
to: '0x' + '1234'.repeat(10),
gasLimit: 33600000000001,
gasPrice: 0,
data: '0x',
value: 0,
}
export const expectApprox = (
actual: BigNumber | number,
target: BigNumber | number,
upperDeviation: number,
lowerDeviation: number = 100
) => {
actual = BigNumber.from(actual)
target = BigNumber.from(target)
const validDeviations =
upperDeviation >= 0 &&
upperDeviation <= 100 &&
lowerDeviation >= 0 &&
lowerDeviation <= 100
if (!validDeviations) {
throw new Error(
'Upper and lower deviation percentage arguments should be between 0 and 100'
)
}
const upper = target.mul(100 + upperDeviation).div(100)
const lower = target.mul(100 - lowerDeviation).div(100)
expect(
actual.lte(upper),
`Actual value is more than ${upperDeviation}% greater than target`
).to.be.true
expect(
actual.gte(lower),
`Actual value is more than ${lowerDeviation}% less than target`
).to.be.true
}
export const waitForL2Geth = async ( export const waitForL2Geth = async (
provider: providers.JsonRpcProvider provider: providers.JsonRpcProvider
): Promise<providers.JsonRpcProvider> => { ): Promise<providers.JsonRpcProvider> => {
......
...@@ -48,8 +48,9 @@ $ USING_OVM=true ./build/bin/geth \ ...@@ -48,8 +48,9 @@ $ USING_OVM=true ./build/bin/geth \
--rollup.pollinterval 3s \ --rollup.pollinterval 3s \
--eth1.networkid $LAYER1_NETWORK_ID \ --eth1.networkid $LAYER1_NETWORK_ID \
--eth1.chainid $LAYER1_CHAIN_ID \ --eth1.chainid $LAYER1_CHAIN_ID \
--eth1.l1gatewayaddress $ETH1_L1_GATEWAY_ADDRESS \ --eth1.l1standardbridgeaddress $ETH1_L1_STANDARD_BRIDGE_ADDRESS \
--eth1.l1crossdomainmessengeraddress $ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS \ --eth1.l1crossdomainmessengeraddress $ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS \
--eth1.l1feewalletaddress $ETH1_L1_FEE_WALLET_ADDRESS \
--eth1.addressresolveraddress $ETH1_ADDRESS_RESOLVER_ADDRESS \ --eth1.addressresolveraddress $ETH1_ADDRESS_RESOLVER_ADDRESS \
--eth1.ctcdeploymentheight $CTC_DEPLOY_HEIGHT \ --eth1.ctcdeploymentheight $CTC_DEPLOY_HEIGHT \
--eth1.syncservice \ --eth1.syncservice \
......
...@@ -601,10 +601,9 @@ func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } ...@@ -601,10 +601,9 @@ func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callmsg) Value() *big.Int { return m.CallMsg.Value } func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
func (m callmsg) Data() []byte { return m.CallMsg.Data } func (m callmsg) Data() []byte { return m.CallMsg.Data }
func (m callmsg) L1MessageSender() *common.Address { return m.CallMsg.L1MessageSender } func (m callmsg) L1MessageSender() *common.Address { return m.CallMsg.L1MessageSender }
func (m callmsg) L1BlockNumber() *big.Int { return m.CallMsg.L1BlockNumber } func (m callmsg) L1BlockNumber() *big.Int { return m.CallMsg.L1BlockNumber }
func (m callmsg) QueueOrigin() *big.Int { return m.CallMsg.QueueOrigin } func (m callmsg) QueueOrigin() types.QueueOrigin { return m.CallMsg.QueueOrigin }
func (m callmsg) SignatureHashType() types.SignatureHashType { return m.CallMsg.SignatureHashType }
// filterBackend implements filters.Backend to support filtering for logs without // filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account. // taking bloom-bits acceleration structures into account.
......
...@@ -153,7 +153,8 @@ var ( ...@@ -153,7 +153,8 @@ var (
utils.Eth1SyncServiceEnable, utils.Eth1SyncServiceEnable,
utils.Eth1CanonicalTransactionChainDeployHeightFlag, utils.Eth1CanonicalTransactionChainDeployHeightFlag,
utils.Eth1L1CrossDomainMessengerAddressFlag, utils.Eth1L1CrossDomainMessengerAddressFlag,
utils.Eth1ETHGatewayAddressFlag, utils.Eth1L1FeeWalletAddressFlag,
utils.Eth1StandardBridgeAddressFlag,
utils.Eth1ChainIdFlag, utils.Eth1ChainIdFlag,
utils.RollupClientHttpFlag, utils.RollupClientHttpFlag,
utils.RollupEnableVerifierFlag, utils.RollupEnableVerifierFlag,
...@@ -163,12 +164,9 @@ var ( ...@@ -163,12 +164,9 @@ var (
utils.RollupStateDumpPathFlag, utils.RollupStateDumpPathFlag,
utils.RollupDiffDbFlag, utils.RollupDiffDbFlag,
utils.RollupMaxCalldataSizeFlag, utils.RollupMaxCalldataSizeFlag,
utils.RollupDataPriceFlag,
utils.RollupExecutionPriceFlag,
utils.RollupBackendFlag, utils.RollupBackendFlag,
utils.RollupEnableL2GasPollingFlag,
utils.RollupGasPriceOracleAddressFlag,
utils.RollupEnforceFeesFlag, utils.RollupEnforceFeesFlag,
utils.GasPriceOracleOwnerAddress,
} }
rpcFlags = []cli.Flag{ rpcFlags = []cli.Flag{
......
...@@ -68,7 +68,8 @@ var AppHelpFlagGroups = []flagGroup{ ...@@ -68,7 +68,8 @@ var AppHelpFlagGroups = []flagGroup{
utils.Eth1SyncServiceEnable, utils.Eth1SyncServiceEnable,
utils.Eth1CanonicalTransactionChainDeployHeightFlag, utils.Eth1CanonicalTransactionChainDeployHeightFlag,
utils.Eth1L1CrossDomainMessengerAddressFlag, utils.Eth1L1CrossDomainMessengerAddressFlag,
utils.Eth1ETHGatewayAddressFlag, utils.Eth1L1FeeWalletAddressFlag,
utils.Eth1StandardBridgeAddressFlag,
utils.Eth1ChainIdFlag, utils.Eth1ChainIdFlag,
utils.RollupClientHttpFlag, utils.RollupClientHttpFlag,
utils.RollupAddressManagerOwnerAddressFlag, utils.RollupAddressManagerOwnerAddressFlag,
...@@ -78,12 +79,9 @@ var AppHelpFlagGroups = []flagGroup{ ...@@ -78,12 +79,9 @@ var AppHelpFlagGroups = []flagGroup{
utils.RollupStateDumpPathFlag, utils.RollupStateDumpPathFlag,
utils.RollupDiffDbFlag, utils.RollupDiffDbFlag,
utils.RollupMaxCalldataSizeFlag, utils.RollupMaxCalldataSizeFlag,
utils.RollupDataPriceFlag,
utils.RollupExecutionPriceFlag,
utils.RollupBackendFlag, utils.RollupBackendFlag,
utils.RollupEnableL2GasPollingFlag,
utils.RollupGasPriceOracleAddressFlag,
utils.RollupEnforceFeesFlag, utils.RollupEnforceFeesFlag,
utils.GasPriceOracleOwnerAddress,
}, },
}, },
{ {
......
...@@ -823,11 +823,17 @@ var ( ...@@ -823,11 +823,17 @@ var (
Value: "0x0000000000000000000000000000000000000000", Value: "0x0000000000000000000000000000000000000000",
EnvVar: "ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS", EnvVar: "ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS",
} }
Eth1ETHGatewayAddressFlag = cli.StringFlag{ Eth1L1FeeWalletAddressFlag = cli.StringFlag{
Name: "eth1.l1ethgatewayaddress", Name: "eth1.l1feewalletaddress",
Usage: "Deployment address of the Ethereum gateway", Usage: "Address of the L1 wallet that will collect fees",
Value: "0x0000000000000000000000000000000000000000", Value: "0x0000000000000000000000000000000000000000",
EnvVar: "ETH1_L1_ETH_GATEWAY_ADDRESS", EnvVar: "ETH1_L1_FEE_WALLET_ADDRESS",
}
Eth1StandardBridgeAddressFlag = cli.StringFlag{
Name: "eth1.l1standardbridgeaddress",
Usage: "Deployment address of the Standard Bridge",
Value: "0x0000000000000000000000000000000000000000",
EnvVar: "ETH1_L1_STANDARD_BRIDGE_ADDRESS",
} }
Eth1ChainIdFlag = cli.Uint64Flag{ Eth1ChainIdFlag = cli.Uint64Flag{
Name: "eth1.chainid", Name: "eth1.chainid",
...@@ -858,7 +864,6 @@ var ( ...@@ -858,7 +864,6 @@ var (
Value: "l1", Value: "l1",
EnvVar: "ROLLUP_BACKEND", EnvVar: "ROLLUP_BACKEND",
} }
// Flag to enable verifier mode
RollupEnableVerifierFlag = cli.BoolFlag{ RollupEnableVerifierFlag = cli.BoolFlag{
Name: "rollup.verifier", Name: "rollup.verifier",
Usage: "Enable the verifier", Usage: "Enable the verifier",
...@@ -888,34 +893,16 @@ var ( ...@@ -888,34 +893,16 @@ var (
Value: eth.DefaultConfig.Rollup.MaxCallDataSize, Value: eth.DefaultConfig.Rollup.MaxCallDataSize,
EnvVar: "ROLLUP_MAX_CALLDATA_SIZE", EnvVar: "ROLLUP_MAX_CALLDATA_SIZE",
} }
RollupDataPriceFlag = BigFlag{
Name: "rollup.dataprice",
Usage: "The L1 calldata price to use for the sequencer fees",
Value: eth.DefaultConfig.Rollup.DataPrice,
EnvVar: "ROLLUP_DATAPRICE",
}
RollupExecutionPriceFlag = BigFlag{
Name: "rollup.executionprice",
Usage: "The execution gas price to use for the sequencer fees",
Value: eth.DefaultConfig.Rollup.ExecutionPrice,
EnvVar: "ROLLUP_EXECUTIONPRICE",
}
RollupGasPriceOracleAddressFlag = cli.StringFlag{
Name: "rollup.gaspriceoracleaddress",
Usage: "Address of the rollup gas price oracle",
Value: "0x0000000000000000000000000000000000000000",
EnvVar: "ROLLUP_GAS_PRICE_ORACLE_ADDRESS",
}
RollupEnableL2GasPollingFlag = cli.BoolFlag{
Name: "rollup.enablel2gaspolling",
Usage: "Poll for the L2 gas price from the L2 state",
EnvVar: "ROLLUP_ENABLE_L2_GAS_POLLING",
}
RollupEnforceFeesFlag = cli.BoolFlag{ RollupEnforceFeesFlag = cli.BoolFlag{
Name: "rollup.enforcefeesflag", Name: "rollup.enforcefeesflag",
Usage: "Disable transactions with 0 gas price", Usage: "Disable transactions with 0 gas price",
EnvVar: "ROLLUP_ENFORCE_FEES", EnvVar: "ROLLUP_ENFORCE_FEES",
} }
GasPriceOracleOwnerAddress = cli.StringFlag{
Name: "rollup.gaspriceoracleowneraddress",
Usage: "Owner of the OVM_GasPriceOracle",
EnvVar: "ROLLUP_GAS_PRICE_ORACLE_OWNER_ADDRESS",
}
) )
// MakeDataDir retrieves the currently requested data directory, terminating // MakeDataDir retrieves the currently requested data directory, terminating
...@@ -1149,9 +1136,13 @@ func setEth1(ctx *cli.Context, cfg *rollup.Config) { ...@@ -1149,9 +1136,13 @@ func setEth1(ctx *cli.Context, cfg *rollup.Config) {
addr := ctx.GlobalString(Eth1L1CrossDomainMessengerAddressFlag.Name) addr := ctx.GlobalString(Eth1L1CrossDomainMessengerAddressFlag.Name)
cfg.L1CrossDomainMessengerAddress = common.HexToAddress(addr) cfg.L1CrossDomainMessengerAddress = common.HexToAddress(addr)
} }
if ctx.GlobalIsSet(Eth1ETHGatewayAddressFlag.Name) { if ctx.GlobalIsSet(Eth1L1FeeWalletAddressFlag.Name) {
addr := ctx.GlobalString(Eth1ETHGatewayAddressFlag.Name) addr := ctx.GlobalString(Eth1L1FeeWalletAddressFlag.Name)
cfg.L1ETHGatewayAddress = common.HexToAddress(addr) cfg.L1FeeWalletAddress = common.HexToAddress(addr)
}
if ctx.GlobalIsSet(Eth1StandardBridgeAddressFlag.Name) {
addr := ctx.GlobalString(Eth1StandardBridgeAddressFlag.Name)
cfg.L1StandardBridgeAddress = common.HexToAddress(addr)
} }
if ctx.GlobalIsSet(Eth1ChainIdFlag.Name) { if ctx.GlobalIsSet(Eth1ChainIdFlag.Name) {
cfg.Eth1ChainId = ctx.GlobalUint64(Eth1ChainIdFlag.Name) cfg.Eth1ChainId = ctx.GlobalUint64(Eth1ChainIdFlag.Name)
...@@ -1189,11 +1180,9 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) { ...@@ -1189,11 +1180,9 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) {
if ctx.GlobalIsSet(RollupTimstampRefreshFlag.Name) { if ctx.GlobalIsSet(RollupTimstampRefreshFlag.Name) {
cfg.TimestampRefreshThreshold = ctx.GlobalDuration(RollupTimstampRefreshFlag.Name) cfg.TimestampRefreshThreshold = ctx.GlobalDuration(RollupTimstampRefreshFlag.Name)
} }
if ctx.GlobalIsSet(RollupDataPriceFlag.Name) { if ctx.GlobalIsSet(GasPriceOracleOwnerAddress.Name) {
cfg.DataPrice = GlobalBig(ctx, RollupDataPriceFlag.Name) addr := ctx.GlobalString(GasPriceOracleOwnerAddress.Name)
} cfg.GasPriceOracleOwnerAddress = common.HexToAddress(addr)
if ctx.GlobalIsSet(RollupExecutionPriceFlag.Name) {
cfg.ExecutionPrice = GlobalBig(ctx, RollupExecutionPriceFlag.Name)
} }
if ctx.GlobalIsSet(RollupBackendFlag.Name) { if ctx.GlobalIsSet(RollupBackendFlag.Name) {
val := ctx.GlobalString(RollupBackendFlag.Name) val := ctx.GlobalString(RollupBackendFlag.Name)
...@@ -1204,13 +1193,6 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) { ...@@ -1204,13 +1193,6 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) {
} }
cfg.Backend = backend cfg.Backend = backend
} }
if ctx.GlobalIsSet(RollupGasPriceOracleAddressFlag.Name) {
addr := ctx.GlobalString(RollupGasPriceOracleAddressFlag.Name)
cfg.GasPriceOracleAddress = common.HexToAddress(addr)
}
if ctx.GlobalIsSet(RollupEnableL2GasPollingFlag.Name) {
cfg.EnableL2GasPolling = true
}
if ctx.GlobalIsSet(RollupEnforceFeesFlag.Name) { if ctx.GlobalIsSet(RollupEnforceFeesFlag.Name) {
cfg.EnforceFees = true cfg.EnforceFees = true
} }
...@@ -1778,10 +1760,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { ...@@ -1778,10 +1760,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
gasLimit = params.GenesisGasLimit gasLimit = params.GenesisGasLimit
} }
xdomainAddress := cfg.Rollup.L1CrossDomainMessengerAddress xdomainAddress := cfg.Rollup.L1CrossDomainMessengerAddress
l1FeeWalletAddress := cfg.Rollup.L1FeeWalletAddress
addrManagerOwnerAddress := cfg.Rollup.AddressManagerOwnerAddress addrManagerOwnerAddress := cfg.Rollup.AddressManagerOwnerAddress
l1ETHGatewayAddress := cfg.Rollup.L1ETHGatewayAddress l1StandardBridgeAddress := cfg.Rollup.L1StandardBridgeAddress
gpoOwnerAddress := cfg.Rollup.GasPriceOracleOwnerAddress
stateDumpPath := cfg.Rollup.StateDumpPath stateDumpPath := cfg.Rollup.StateDumpPath
cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address, xdomainAddress, l1ETHGatewayAddress, addrManagerOwnerAddress, stateDumpPath, chainID, gasLimit) cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address, xdomainAddress, l1StandardBridgeAddress, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress, stateDumpPath, chainID, gasLimit)
if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
cfg.Miner.GasPrice = big.NewInt(1) cfg.Miner.GasPrice = big.NewInt(1)
} }
......
...@@ -98,7 +98,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester { ...@@ -98,7 +98,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create node: %v", err) t.Fatalf("failed to create node: %v", err)
} }
ethConf := &eth.Config{ ethConf := &eth.Config{
Genesis: core.DeveloperGenesisBlock(15, common.Address{}, common.Address{}, common.Address{}, common.Address{}, "", nil, 12000000), Genesis: core.DeveloperGenesisBlock(15, common.Address{}, common.Address{}, common.Address{}, common.Address{}, common.Address{}, common.Address{}, "", nil, 12000000),
Miner: miner.Config{ Miner: miner.Config{
Etherbase: common.HexToAddress(testAddress), Etherbase: common.HexToAddress(testAddress),
}, },
......
...@@ -69,9 +69,11 @@ type Genesis struct { ...@@ -69,9 +69,11 @@ type Genesis struct {
// OVM Specific, used to initialize the l1XDomainMessengerAddress // OVM Specific, used to initialize the l1XDomainMessengerAddress
// in the genesis state // in the genesis state
L1FeeWalletAddress common.Address `json:"-"`
L1CrossDomainMessengerAddress common.Address `json:"-"` L1CrossDomainMessengerAddress common.Address `json:"-"`
AddressManagerOwnerAddress common.Address `json:"-"` AddressManagerOwnerAddress common.Address `json:"-"`
L1ETHGatewayAddress common.Address `json:"-"` GasPriceOracleOwnerAddress common.Address `json:"-"`
L1StandardBridgeAddress common.Address `json:"-"`
ChainID *big.Int `json:"-"` ChainID *big.Int `json:"-"`
} }
...@@ -266,7 +268,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { ...@@ -266,7 +268,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
} }
// ApplyOvmStateToState applies the initial OVM state to a state object. // ApplyOvmStateToState applies the initial OVM state to a state object.
func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDomainMessengerAddress common.Address, l1ETHGatewayAddress common.Address, addrManagerOwnerAddress common.Address, chainID *big.Int, gasLimit uint64) { func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDomainMessengerAddress, l1StandardBridgeAddress, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress common.Address, chainID *big.Int, gasLimit uint64) {
if len(stateDump.Accounts) == 0 { if len(stateDump.Accounts) == 0 {
return return
} }
...@@ -299,22 +301,13 @@ func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDo ...@@ -299,22 +301,13 @@ func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDo
l1MessengerValue := common.BytesToHash(l1XDomainMessengerAddress.Bytes()) l1MessengerValue := common.BytesToHash(l1XDomainMessengerAddress.Bytes())
statedb.SetState(AddressManager.Address, l1MessengerSlot, l1MessengerValue) statedb.SetState(AddressManager.Address, l1MessengerSlot, l1MessengerValue)
} }
OVM_ETH, ok := stateDump.Accounts["OVM_ETH"] OVM_L2StandardBridge, ok := stateDump.Accounts["OVM_L2StandardBridge"]
if ok { if ok {
log.Info("Setting OVM_L1ETHGateway in OVM_ETH", "address", l1ETHGatewayAddress.Hex()) log.Info("Setting OVM_L1StandardBridge in OVM_L2StandardBridge", "address", l1StandardBridgeAddress.Hex())
if strings.Contains(OVM_ETH.Code, "a84ce98") { // Set the gateway of OVM_L2StandardBridge at new dump
// Set the gateway of OVM_ETH at new dump l1BridgeSlot := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001")
log.Info("Detected current OVM_ETH dump, setting slot 0x1 ") l1BridgeValue := common.BytesToHash(l1StandardBridgeAddress.Bytes())
l1GatewaySlot := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001") statedb.SetState(OVM_L2StandardBridge.Address, l1BridgeSlot, l1BridgeValue)
l1GatewayValue := common.BytesToHash(l1ETHGatewayAddress.Bytes())
statedb.SetState(OVM_ETH.Address, l1GatewaySlot, l1GatewayValue)
} else {
// Set the gateway of OVM_ETH at legacy slot
log.Info("Detected legacy OVM_ETH dump, setting slot 0x8")
l1GatewaySlot := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000008")
l1GatewayValue := common.BytesToHash(l1ETHGatewayAddress.Bytes())
statedb.SetState(OVM_ETH.Address, l1GatewaySlot, l1GatewayValue)
}
} }
ExecutionManager, ok := stateDump.Accounts["OVM_ExecutionManager"] ExecutionManager, ok := stateDump.Accounts["OVM_ExecutionManager"]
if ok { if ok {
...@@ -330,6 +323,20 @@ func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDo ...@@ -330,6 +323,20 @@ func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDo
maxTxGasLimitValue := common.BytesToHash(new(big.Int).SetUint64(gasLimit).Bytes()) maxTxGasLimitValue := common.BytesToHash(new(big.Int).SetUint64(gasLimit).Bytes())
statedb.SetState(ExecutionManager.Address, maxTxGasLimitSlot, maxTxGasLimitValue) statedb.SetState(ExecutionManager.Address, maxTxGasLimitSlot, maxTxGasLimitValue)
} }
OVM_SequencerFeeVault, ok := stateDump.Accounts["OVM_SequencerFeeVault"]
if ok {
log.Info("Setting l1FeeWallet in OVM_SequencerFeeVault", "wallet", l1FeeWalletAddress.Hex())
l1FeeWalletSlot := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")
l1FeeWalletValue := common.BytesToHash(l1FeeWalletAddress.Bytes())
statedb.SetState(OVM_SequencerFeeVault.Address, l1FeeWalletSlot, l1FeeWalletValue)
GasPriceOracle, ok := stateDump.Accounts["OVM_GasPriceOracle"]
if ok {
ownerSlot := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")
ownerValue := common.BytesToHash(gpoOwnerAddress.Bytes())
statedb.SetState(GasPriceOracle.Address, ownerSlot, ownerValue)
log.Info("Setting GasPriceOracle Owner", "owner", gpoOwnerAddress.Hex())
}
}
} }
// ToBlock creates the genesis block and writes state of a genesis specification // ToBlock creates the genesis block and writes state of a genesis specification
...@@ -342,7 +349,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { ...@@ -342,7 +349,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
if vm.UsingOVM { if vm.UsingOVM {
// OVM_ENABLED // OVM_ENABLED
ApplyOvmStateToState(statedb, g.Config.StateDump, g.L1CrossDomainMessengerAddress, g.L1ETHGatewayAddress, g.AddressManagerOwnerAddress, g.ChainID, g.GasLimit) ApplyOvmStateToState(statedb, g.Config.StateDump, g.L1CrossDomainMessengerAddress, g.L1StandardBridgeAddress, g.AddressManagerOwnerAddress, g.GasPriceOracleOwnerAddress, g.L1FeeWalletAddress, g.ChainID, g.GasLimit)
} }
for addr, account := range g.Alloc { for addr, account := range g.Alloc {
...@@ -469,7 +476,7 @@ func DefaultGoerliGenesisBlock() *Genesis { ...@@ -469,7 +476,7 @@ func DefaultGoerliGenesisBlock() *Genesis {
} }
// DeveloperGenesisBlock returns the 'geth --dev' genesis block. // DeveloperGenesisBlock returns the 'geth --dev' genesis block.
func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress common.Address, l1ETHGatewayAddress common.Address, addrManagerOwnerAddress common.Address, stateDumpPath string, chainID *big.Int, gasLimit uint64) *Genesis { func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress common.Address, l1StandardBridgeAddress common.Address, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress common.Address, stateDumpPath string, chainID *big.Int, gasLimit uint64) *Genesis {
// Override the default period to the user requested one // Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges config := *params.AllCliqueProtocolChanges
config.Clique.Period = period config.Clique.Period = period
...@@ -525,8 +532,10 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm ...@@ -525,8 +532,10 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
}, },
L1CrossDomainMessengerAddress: l1XDomainMessengerAddress, L1CrossDomainMessengerAddress: l1XDomainMessengerAddress,
L1FeeWalletAddress: l1FeeWalletAddress,
AddressManagerOwnerAddress: addrManagerOwnerAddress, AddressManagerOwnerAddress: addrManagerOwnerAddress,
L1ETHGatewayAddress: l1ETHGatewayAddress, GasPriceOracleOwnerAddress: gpoOwnerAddress,
L1StandardBridgeAddress: l1StandardBridgeAddress,
ChainID: config.ChainID, ChainID: config.ChainID,
} }
} }
......
...@@ -430,7 +430,7 @@ func TestBlockMetaStorage(t *testing.T) { ...@@ -430,7 +430,7 @@ func TestBlockMetaStorage(t *testing.T) {
index1 := uint64(1) index1 := uint64(1)
tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)
tx1Meta := types.NewTransactionMeta(nil, 0, nil, types.SighashEIP155, types.QueueOriginSequencer, &index1, nil, nil) tx1Meta := types.NewTransactionMeta(nil, 0, nil, types.QueueOriginSequencer, &index1, nil, nil)
tx1.SetTransactionMeta(tx1Meta) tx1.SetTransactionMeta(tx1Meta)
WriteTransactionMeta(db, index1, tx1.GetMeta()) WriteTransactionMeta(db, index1, tx1.GetMeta())
...@@ -442,9 +442,6 @@ func TestBlockMetaStorage(t *testing.T) { ...@@ -442,9 +442,6 @@ func TestBlockMetaStorage(t *testing.T) {
if meta.L1BlockNumber != nil { if meta.L1BlockNumber != nil {
t.Fatalf("Could not recover L1BlockNumber") t.Fatalf("Could not recover L1BlockNumber")
} }
if meta.SignatureHashType != types.SighashEIP155 {
t.Fatalf("Could not recover sighash type")
}
if meta.Index == nil { if meta.Index == nil {
t.Fatalf("Could not recover index") t.Fatalf("Could not recover index")
} }
...@@ -464,7 +461,7 @@ func TestBlockMetaStorage(t *testing.T) { ...@@ -464,7 +461,7 @@ func TestBlockMetaStorage(t *testing.T) {
index2 := uint64(2) index2 := uint64(2)
tx2 := types.NewTransaction(2, common.HexToAddress("0x02"), big.NewInt(2), 2, big.NewInt(2), nil) tx2 := types.NewTransaction(2, common.HexToAddress("0x02"), big.NewInt(2), 2, big.NewInt(2), nil)
tx2Meta := types.NewTransactionMeta(l1BlockNumber, 0, &addr, types.SighashEthSign, types.QueueOriginSequencer, nil, nil, nil) tx2Meta := types.NewTransactionMeta(l1BlockNumber, 0, &addr, types.QueueOriginSequencer, nil, nil, nil)
tx2.SetTransactionMeta(tx2Meta) tx2.SetTransactionMeta(tx2Meta)
WriteTransactionMeta(db, index2, tx2.GetMeta()) WriteTransactionMeta(db, index2, tx2.GetMeta())
...@@ -477,7 +474,4 @@ func TestBlockMetaStorage(t *testing.T) { ...@@ -477,7 +474,4 @@ func TestBlockMetaStorage(t *testing.T) {
if meta2.L1BlockNumber.Cmp(l1BlockNumber) != 0 { if meta2.L1BlockNumber.Cmp(l1BlockNumber) != 0 {
t.Fatalf("Could not recover L1BlockNumber") t.Fatalf("Could not recover L1BlockNumber")
} }
if meta2.SignatureHashType != types.SighashEthSign {
t.Fatalf("Could not recover sighash type")
}
} }
...@@ -73,15 +73,15 @@ func TestLookupStorage(t *testing.T) { ...@@ -73,15 +73,15 @@ func TestLookupStorage(t *testing.T) {
l1BlockNumber2 := big.NewInt(2) l1BlockNumber2 := big.NewInt(2)
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}) tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
tx1Meta := types.NewTransactionMeta(l1BlockNumber1, 0, &sender1, types.SighashEIP155, types.QueueOriginSequencer, nil, nil, nil) tx1Meta := types.NewTransactionMeta(l1BlockNumber1, 0, &sender1, types.QueueOriginSequencer, nil, nil, nil)
tx1.SetTransactionMeta(tx1Meta) tx1.SetTransactionMeta(tx1Meta)
tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22}) tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
tx2Meta := types.NewTransactionMeta(l1BlockNumber2, 0, &sender2, types.SighashEIP155, types.QueueOriginSequencer, nil, nil, nil) tx2Meta := types.NewTransactionMeta(l1BlockNumber2, 0, &sender2, types.QueueOriginSequencer, nil, nil, nil)
tx2.SetTransactionMeta(tx2Meta) tx2.SetTransactionMeta(tx2Meta)
tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
tx3Meta := types.NewTransactionMeta(l1BlockNumber1, 0, nil, types.SighashEIP155, types.QueueOriginSequencer, nil, nil, nil) tx3Meta := types.NewTransactionMeta(l1BlockNumber1, 0, nil, types.QueueOriginSequencer, nil, nil, nil)
tx3.SetTransactionMeta(tx3Meta) tx3.SetTransactionMeta(tx3Meta)
txs := []*types.Transaction{tx1, tx2, tx3} txs := []*types.Transaction{tx1, tx2, tx3}
......
...@@ -269,7 +269,7 @@ func (s *StateDB) GetBalance(addr common.Address) *big.Int { ...@@ -269,7 +269,7 @@ func (s *StateDB) GetBalance(addr common.Address) *big.Int {
func (s *StateDB) GetOVMBalance(addr common.Address) *big.Int { func (s *StateDB) GetOVMBalance(addr common.Address) *big.Int {
eth := common.HexToAddress("0x4200000000000000000000000000000000000006") eth := common.HexToAddress("0x4200000000000000000000000000000000000006")
position := big.NewInt(5) position := big.NewInt(0)
hasher := sha3.NewLegacyKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(common.LeftPadBytes(addr.Bytes(), 32)) hasher.Write(common.LeftPadBytes(addr.Bytes(), 32))
hasher.Write(common.LeftPadBytes(position.Bytes(), 32)) hasher.Write(common.LeftPadBytes(position.Bytes(), 32))
......
...@@ -77,8 +77,7 @@ type Message interface { ...@@ -77,8 +77,7 @@ type Message interface {
Data() []byte Data() []byte
L1MessageSender() *common.Address L1MessageSender() *common.Address
L1BlockNumber() *big.Int L1BlockNumber() *big.Int
QueueOrigin() *big.Int QueueOrigin() types.QueueOrigin
SignatureHashType() types.SignatureHashType
} }
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
...@@ -185,9 +184,7 @@ func (st *StateTransition) preCheck() error { ...@@ -185,9 +184,7 @@ func (st *StateTransition) preCheck() error {
if nonce < st.msg.Nonce() { if nonce < st.msg.Nonce() {
if vm.UsingOVM { if vm.UsingOVM {
// The nonce never increments for L1ToL2 txs // The nonce never increments for L1ToL2 txs
qo := st.msg.QueueOrigin() if st.msg.QueueOrigin() == types.QueueOriginL1ToL2 {
l1ToL2 := uint64(types.QueueOriginL1ToL2)
if qo != nil && qo.Uint64() == l1ToL2 {
return st.buyGas() return st.buyGas()
} }
} }
...@@ -283,6 +280,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -283,6 +280,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
} }
func (st *StateTransition) refundGas() { func (st *StateTransition) refundGas() {
if vm.UsingOVM {
return
}
// Apply refund counter, capped to half of the used gas. // Apply refund counter, capped to half of the used gas.
refund := st.gasUsed() / 2 refund := st.gasUsed() / 2
if refund > st.state.GetRefund() { if refund > st.state.GetRefund() {
......
...@@ -26,7 +26,7 @@ func toExecutionManagerRun(evm *vm.EVM, msg Message) (Message, error) { ...@@ -26,7 +26,7 @@ func toExecutionManagerRun(evm *vm.EVM, msg Message) (Message, error) {
tx := ovmTransaction{ tx := ovmTransaction{
evm.Context.Time, evm.Context.Time,
msg.L1BlockNumber(), msg.L1BlockNumber(),
uint8(msg.QueueOrigin().Uint64()), uint8(msg.QueueOrigin()),
*msg.L1MessageSender(), *msg.L1MessageSender(),
*msg.To(), *msg.To(),
big.NewInt(int64(msg.Gas())), big.NewInt(int64(msg.Gas())),
...@@ -73,8 +73,7 @@ func AsOvmMessage(tx *types.Transaction, signer types.Signer, decompressor commo ...@@ -73,8 +73,7 @@ func AsOvmMessage(tx *types.Transaction, signer types.Signer, decompressor commo
// sequencer entrypoint. The calldata is expected to be in the // sequencer entrypoint. The calldata is expected to be in the
// correct format when deserialized from the EVM events, see // correct format when deserialized from the EVM events, see
// rollup/sync_service.go. // rollup/sync_service.go.
qo := msg.QueueOrigin() if msg.QueueOrigin() == types.QueueOriginL1ToL2 {
if qo != nil && qo.Uint64() == uint64(types.QueueOriginL1ToL2) {
return msg, nil return msg, nil
} }
...@@ -101,13 +100,18 @@ func EncodeSimulatedMessage(msg Message, timestamp, blockNumber *big.Int, execut ...@@ -101,13 +100,18 @@ func EncodeSimulatedMessage(msg Message, timestamp, blockNumber *big.Int, execut
to = &common.Address{0} to = &common.Address{0}
} }
value := msg.Value()
if value == nil {
value = common.Big0
}
tx := ovmTransaction{ tx := ovmTransaction{
timestamp, timestamp,
blockNumber, blockNumber,
uint8(msg.QueueOrigin().Uint64()), uint8(msg.QueueOrigin()),
*msg.L1MessageSender(), *msg.L1MessageSender(),
*to, *to,
big.NewInt(int64(msg.Gas())), new(big.Int).SetUint64(msg.Gas()),
msg.Data(), msg.Data(),
} }
...@@ -115,6 +119,7 @@ func EncodeSimulatedMessage(msg Message, timestamp, blockNumber *big.Int, execut ...@@ -115,6 +119,7 @@ func EncodeSimulatedMessage(msg Message, timestamp, blockNumber *big.Int, execut
var args = []interface{}{ var args = []interface{}{
tx, tx,
from, from,
value,
stateManager.Address, stateManager.Address,
} }
...@@ -139,11 +144,6 @@ func modMessage( ...@@ -139,11 +144,6 @@ func modMessage(
data []byte, data []byte,
gasLimit uint64, gasLimit uint64,
) (Message, error) { ) (Message, error) {
queueOrigin, err := getQueueOrigin(msg.QueueOrigin())
if err != nil {
return nil, err
}
outmsg := types.NewMessage( outmsg := types.NewMessage(
from, from,
to, to,
...@@ -155,23 +155,8 @@ func modMessage( ...@@ -155,23 +155,8 @@ func modMessage(
false, false,
msg.L1MessageSender(), msg.L1MessageSender(),
msg.L1BlockNumber(), msg.L1BlockNumber(),
queueOrigin, msg.QueueOrigin(),
msg.SignatureHashType(),
) )
return outmsg, nil return outmsg, nil
} }
func getQueueOrigin(
queueOrigin *big.Int,
) (types.QueueOrigin, error) {
if queueOrigin.Cmp(big.NewInt(0)) == 0 {
return types.QueueOriginSequencer, nil
} else if queueOrigin.Cmp(big.NewInt(1)) == 0 {
return types.QueueOriginL1ToL2, nil
} else if queueOrigin.Cmp(big.NewInt(2)) == 0 {
return types.QueueOriginL1ToL2, nil
} else {
return types.QueueOriginSequencer, fmt.Errorf("invalid queue origin: %d", queueOrigin)
}
}
...@@ -13,8 +13,8 @@ import ( ...@@ -13,8 +13,8 @@ import (
var _ = (*txdataMarshaling)(nil) var _ = (*txdataMarshaling)(nil)
// TransactionMarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (t txdata) TransactionMarshalJSON() ([]byte, error) { func (t txdata) MarshalJSON() ([]byte, error) {
type txdata struct { type txdata struct {
AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"`
Price *hexutil.Big `json:"gasPrice" gencodec:"required"` Price *hexutil.Big `json:"gasPrice" gencodec:"required"`
...@@ -41,8 +41,8 @@ func (t txdata) TransactionMarshalJSON() ([]byte, error) { ...@@ -41,8 +41,8 @@ func (t txdata) TransactionMarshalJSON() ([]byte, error) {
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// TransactionUnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (t *txdata) TransactionUnmarshalJSON(input []byte) error { func (t *txdata) UnmarshalJSON(input []byte) error {
type txdata struct { type txdata struct {
AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"`
Price *hexutil.Big `json:"gasPrice" gencodec:"required"` Price *hexutil.Big `json:"gasPrice" gencodec:"required"`
......
...@@ -13,29 +13,35 @@ import ( ...@@ -13,29 +13,35 @@ import (
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (t TransactionMeta) MarshalJSON() ([]byte, error) { func (t TransactionMeta) MarshalJSON() ([]byte, error) {
type TransactionMeta struct { type TransactionMeta struct {
L1BlockNumber *big.Int `json:"l1BlockNumber"` L1BlockNumber *big.Int `json:"l1BlockNumber"`
L1MessageSender *common.Address `json:"l1MessageSender" gencodec:"required"` L1Timestamp uint64 `json:"l1Timestamp"`
SignatureHashType SignatureHashType `json:"signatureHashType" gencodec:"required"` L1MessageSender *common.Address `json:"l1MessageSender" gencodec:"required"`
QueueOrigin *big.Int `json:"queueOrigin" gencodec:"required"` QueueOrigin QueueOrigin `json:"queueOrigin" gencodec:"required"`
Index *uint64 `json:"index" gencodec:"required"` Index *uint64 `json:"index" gencodec:"required"`
QueueIndex *uint64 `json:"queueIndex" gencodec:"required"`
RawTransaction []byte `json:"rawTransaction" gencodec:"required"`
} }
var enc TransactionMeta var enc TransactionMeta
enc.L1BlockNumber = t.L1BlockNumber enc.L1BlockNumber = t.L1BlockNumber
enc.L1Timestamp = t.L1Timestamp
enc.L1MessageSender = t.L1MessageSender enc.L1MessageSender = t.L1MessageSender
enc.SignatureHashType = t.SignatureHashType
enc.QueueOrigin = t.QueueOrigin enc.QueueOrigin = t.QueueOrigin
enc.Index = t.Index enc.Index = t.Index
enc.QueueIndex = t.QueueIndex
enc.RawTransaction = t.RawTransaction
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (t *TransactionMeta) UnmarshalJSON(input []byte) error { func (t *TransactionMeta) UnmarshalJSON(input []byte) error {
type TransactionMeta struct { type TransactionMeta struct {
L1BlockNumber *big.Int `json:"l1BlockNumber"` L1BlockNumber *big.Int `json:"l1BlockNumber"`
L1MessageSender *common.Address `json:"l1MessageSender" gencodec:"required"` L1Timestamp *uint64 `json:"l1Timestamp"`
SignatureHashType *SignatureHashType `json:"signatureHashType" gencodec:"required"` L1MessageSender *common.Address `json:"l1MessageSender" gencodec:"required"`
QueueOrigin *big.Int `json:"queueOrigin" gencodec:"required"` QueueOrigin *QueueOrigin `json:"queueOrigin" gencodec:"required"`
Index *uint64 `json:"index" gencodec:"required"` Index *uint64 `json:"index" gencodec:"required"`
QueueIndex *uint64 `json:"queueIndex" gencodec:"required"`
RawTransaction []byte `json:"rawTransaction" gencodec:"required"`
} }
var dec TransactionMeta var dec TransactionMeta
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
...@@ -44,21 +50,28 @@ func (t *TransactionMeta) UnmarshalJSON(input []byte) error { ...@@ -44,21 +50,28 @@ func (t *TransactionMeta) UnmarshalJSON(input []byte) error {
if dec.L1BlockNumber != nil { if dec.L1BlockNumber != nil {
t.L1BlockNumber = dec.L1BlockNumber t.L1BlockNumber = dec.L1BlockNumber
} }
if dec.L1Timestamp != nil {
t.L1Timestamp = *dec.L1Timestamp
}
if dec.L1MessageSender == nil { if dec.L1MessageSender == nil {
return errors.New("missing required field 'l1MessageSender' for TransactionMeta") return errors.New("missing required field 'l1MessageSender' for TransactionMeta")
} }
t.L1MessageSender = dec.L1MessageSender t.L1MessageSender = dec.L1MessageSender
if dec.SignatureHashType == nil {
return errors.New("missing required field 'signatureHashType' for TransactionMeta")
}
t.SignatureHashType = *dec.SignatureHashType
if dec.QueueOrigin == nil { if dec.QueueOrigin == nil {
return errors.New("missing required field 'queueOrigin' for TransactionMeta") return errors.New("missing required field 'queueOrigin' for TransactionMeta")
} }
t.QueueOrigin = dec.QueueOrigin t.QueueOrigin = *dec.QueueOrigin
if dec.Index == nil { if dec.Index == nil {
return errors.New("missing required field 'index' for TransactionMeta") return errors.New("missing required field 'index' for TransactionMeta")
} }
t.Index = dec.Index t.Index = dec.Index
if dec.QueueIndex == nil {
return errors.New("missing required field 'queueIndex' for TransactionMeta")
}
t.QueueIndex = dec.QueueIndex
if dec.RawTransaction == nil {
return errors.New("missing required field 'rawTransaction' for TransactionMeta")
}
t.RawTransaction = dec.RawTransaction
return nil return nil
} }
...@@ -36,15 +36,6 @@ var ( ...@@ -36,15 +36,6 @@ var (
ErrInvalidSig = errors.New("invalid transaction v, r, s values") ErrInvalidSig = errors.New("invalid transaction v, r, s values")
) )
// TODO(mark): migrate from sighash type to type
type SignatureHashType uint8
const (
SighashEIP155 SignatureHashType = 0
SighashEthSign SignatureHashType = 1
CreateEOA SignatureHashType = 2
)
type Transaction struct { type Transaction struct {
data txdata data txdata
meta TransactionMeta meta TransactionMeta
...@@ -86,7 +77,6 @@ func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit u ...@@ -86,7 +77,6 @@ func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit u
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data) return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
} }
// TODO: cannot deploy contracts with SighashEthSign right until SighashEIP155 is no longer hardcoded
func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data) return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
} }
...@@ -96,7 +86,7 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit ...@@ -96,7 +86,7 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit
data = common.CopyBytes(data) data = common.CopyBytes(data)
} }
meta := NewTransactionMeta(nil, 0, nil, SighashEIP155, QueueOriginSequencer, nil, nil, nil) meta := NewTransactionMeta(nil, 0, nil, QueueOriginSequencer, nil, nil, nil)
d := txdata{ d := txdata{
AccountNonce: nonce, AccountNonce: nonce,
...@@ -197,12 +187,12 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { ...@@ -197,12 +187,12 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
// MarshalJSON encodes the web3 RPC transaction format. // MarshalJSON encodes the web3 RPC transaction format.
func (tx *Transaction) MarshalJSON() ([]byte, error) { func (tx *Transaction) MarshalJSON() ([]byte, error) {
return tx.data.TransactionMarshalJSON() return tx.data.MarshalJSON()
} }
// UnmarshalJSON decodes the web3 RPC transaction format. // UnmarshalJSON decodes the web3 RPC transaction format.
func (tx *Transaction) UnmarshalJSON(input []byte) error { func (tx *Transaction) UnmarshalJSON(input []byte) error {
err := tx.data.TransactionUnmarshalJSON(input) err := tx.data.UnmarshalJSON(input)
if err != nil { if err != nil {
return err return err
} }
...@@ -232,14 +222,7 @@ func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amo ...@@ -232,14 +222,7 @@ func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amo
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
func (tx *Transaction) CheckNonce() bool { return true } func (tx *Transaction) CheckNonce() bool { return true }
func (tx *Transaction) SetNonce(nonce uint64) { tx.data.AccountNonce = nonce } func (tx *Transaction) SetNonce(nonce uint64) { tx.data.AccountNonce = nonce }
func (tx *Transaction) SignatureHashType() SignatureHashType { return tx.meta.SignatureHashType }
func (tx *Transaction) SetSignatureHashType(sighashType SignatureHashType) {
tx.meta.SignatureHashType = sighashType
}
func (tx *Transaction) IsEthSignSighash() bool {
return tx.SignatureHashType() == SighashEthSign
}
// To returns the recipient address of the transaction. // To returns the recipient address of the transaction.
// It returns nil if the transaction is a contract creation. // It returns nil if the transaction is a contract creation.
...@@ -271,13 +254,9 @@ func (tx *Transaction) L1BlockNumber() *big.Int { ...@@ -271,13 +254,9 @@ func (tx *Transaction) L1BlockNumber() *big.Int {
return &l1BlockNumber return &l1BlockNumber
} }
// QueueOrigin returns the Queue Origin of the transaction if it exists. // QueueOrigin returns the Queue Origin of the transaction
func (tx *Transaction) QueueOrigin() *big.Int { func (tx *Transaction) QueueOrigin() QueueOrigin {
if tx.meta.QueueOrigin == nil { return tx.meta.QueueOrigin
return nil
}
queueOrigin := *tx.meta.QueueOrigin
return &queueOrigin
} }
// Hash hashes the RLP encoding of tx. // Hash hashes the RLP encoding of tx.
...@@ -319,10 +298,9 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { ...@@ -319,10 +298,9 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
data: tx.data.Payload, data: tx.data.Payload,
checkNonce: true, checkNonce: true,
l1MessageSender: tx.meta.L1MessageSender, l1MessageSender: tx.meta.L1MessageSender,
l1BlockNumber: tx.meta.L1BlockNumber, l1BlockNumber: tx.meta.L1BlockNumber,
signatureHashType: tx.meta.SignatureHashType, queueOrigin: tx.meta.QueueOrigin,
queueOrigin: tx.meta.QueueOrigin,
} }
var err error var err error
...@@ -535,13 +513,12 @@ type Message struct { ...@@ -535,13 +513,12 @@ type Message struct {
data []byte data []byte
checkNonce bool checkNonce bool
l1MessageSender *common.Address l1MessageSender *common.Address
l1BlockNumber *big.Int l1BlockNumber *big.Int
signatureHashType SignatureHashType queueOrigin QueueOrigin
queueOrigin *big.Int
} }
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool, l1MessageSender *common.Address, l1BlockNumber *big.Int, queueOrigin QueueOrigin, signatureHashType SignatureHashType) Message { func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool, l1MessageSender *common.Address, l1BlockNumber *big.Int, queueOrigin QueueOrigin) Message {
return Message{ return Message{
from: from, from: from,
to: to, to: to,
...@@ -552,10 +529,9 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b ...@@ -552,10 +529,9 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
data: data, data: data,
checkNonce: checkNonce, checkNonce: checkNonce,
l1BlockNumber: l1BlockNumber, l1BlockNumber: l1BlockNumber,
l1MessageSender: l1MessageSender, l1MessageSender: l1MessageSender,
signatureHashType: signatureHashType, queueOrigin: queueOrigin,
queueOrigin: big.NewInt(int64(queueOrigin)),
} }
} }
...@@ -568,7 +544,6 @@ func (m Message) Nonce() uint64 { return m.nonce } ...@@ -568,7 +544,6 @@ func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data } func (m Message) Data() []byte { return m.data }
func (m Message) CheckNonce() bool { return m.checkNonce } func (m Message) CheckNonce() bool { return m.checkNonce }
func (m Message) L1MessageSender() *common.Address { return m.l1MessageSender } func (m Message) L1MessageSender() *common.Address { return m.l1MessageSender }
func (m Message) L1BlockNumber() *big.Int { return m.l1BlockNumber } func (m Message) L1BlockNumber() *big.Int { return m.l1BlockNumber }
func (m Message) SignatureHashType() SignatureHashType { return m.signatureHashType } func (m Message) QueueOrigin() QueueOrigin { return m.queueOrigin }
func (m Message) QueueOrigin() *big.Int { return m.queueOrigin }
...@@ -12,7 +12,7 @@ import ( ...@@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type QueueOrigin int64 type QueueOrigin uint8
const ( const (
// Possible `queue_origin` values // Possible `queue_origin` values
...@@ -20,14 +20,24 @@ const ( ...@@ -20,14 +20,24 @@ const (
QueueOriginL1ToL2 QueueOrigin = 1 QueueOriginL1ToL2 QueueOrigin = 1
) )
func (q QueueOrigin) String() string {
switch q {
case QueueOriginSequencer:
return "sequencer"
case QueueOriginL1ToL2:
return "l1"
default:
return ""
}
}
//go:generate gencodec -type TransactionMeta -out gen_tx_meta_json.go //go:generate gencodec -type TransactionMeta -out gen_tx_meta_json.go
type TransactionMeta struct { type TransactionMeta struct {
L1BlockNumber *big.Int `json:"l1BlockNumber"` L1BlockNumber *big.Int `json:"l1BlockNumber"`
L1Timestamp uint64 `json:"l1Timestamp"` L1Timestamp uint64 `json:"l1Timestamp"`
L1MessageSender *common.Address `json:"l1MessageSender" gencodec:"required"` L1MessageSender *common.Address `json:"l1MessageSender" gencodec:"required"`
SignatureHashType SignatureHashType `json:"signatureHashType" gencodec:"required"` QueueOrigin QueueOrigin `json:"queueOrigin" gencodec:"required"`
QueueOrigin *big.Int `json:"queueOrigin" gencodec:"required"`
// The canonical transaction chain index // The canonical transaction chain index
Index *uint64 `json:"index" gencodec:"required"` Index *uint64 `json:"index" gencodec:"required"`
// The queue index, nil for queue origin sequencer transactions // The queue index, nil for queue origin sequencer transactions
...@@ -36,22 +46,20 @@ type TransactionMeta struct { ...@@ -36,22 +46,20 @@ type TransactionMeta struct {
} }
// NewTransactionMeta creates a TransactionMeta // NewTransactionMeta creates a TransactionMeta
func NewTransactionMeta(l1BlockNumber *big.Int, l1timestamp uint64, l1MessageSender *common.Address, sighashType SignatureHashType, queueOrigin QueueOrigin, index *uint64, queueIndex *uint64, rawTransaction []byte) *TransactionMeta { func NewTransactionMeta(l1BlockNumber *big.Int, l1timestamp uint64, l1MessageSender *common.Address, queueOrigin QueueOrigin, index *uint64, queueIndex *uint64, rawTransaction []byte) *TransactionMeta {
return &TransactionMeta{ return &TransactionMeta{
L1BlockNumber: l1BlockNumber, L1BlockNumber: l1BlockNumber,
L1Timestamp: l1timestamp, L1Timestamp: l1timestamp,
L1MessageSender: l1MessageSender, L1MessageSender: l1MessageSender,
SignatureHashType: sighashType, QueueOrigin: queueOrigin,
QueueOrigin: big.NewInt(int64(queueOrigin)), Index: index,
Index: index, QueueIndex: queueIndex,
QueueIndex: queueIndex, RawTransaction: rawTransaction,
RawTransaction: rawTransaction,
} }
} }
// TxMetaDecode deserializes bytes as a TransactionMeta struct. // TxMetaDecode deserializes bytes as a TransactionMeta struct.
// The schema is: // The schema is:
// varbytes(SignatureHashType) ||
// varbytes(L1BlockNumber) || // varbytes(L1BlockNumber) ||
// varbytes(L1MessageSender) || // varbytes(L1MessageSender) ||
// varbytes(QueueOrigin) || // varbytes(QueueOrigin) ||
...@@ -61,14 +69,6 @@ func TxMetaDecode(input []byte) (*TransactionMeta, error) { ...@@ -61,14 +69,6 @@ func TxMetaDecode(input []byte) (*TransactionMeta, error) {
meta := TransactionMeta{} meta := TransactionMeta{}
b := bytes.NewReader(input) b := bytes.NewReader(input)
sb, err := common.ReadVarBytes(b, 0, 1024, "SignatureHashType")
if err != nil {
return nil, err
}
var sighashType SignatureHashType
binary.Read(bytes.NewReader(sb), binary.LittleEndian, &sighashType)
meta.SignatureHashType = sighashType
lb, err := common.ReadVarBytes(b, 0, 1024, "l1BlockNumber") lb, err := common.ReadVarBytes(b, 0, 1024, "l1BlockNumber")
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -94,7 +94,7 @@ func TxMetaDecode(input []byte) (*TransactionMeta, error) { ...@@ -94,7 +94,7 @@ func TxMetaDecode(input []byte) (*TransactionMeta, error) {
} }
if !isNullValue(qo) { if !isNullValue(qo) {
queueOrigin := new(big.Int).SetBytes(qo) queueOrigin := new(big.Int).SetBytes(qo)
meta.QueueOrigin = queueOrigin meta.QueueOrigin = QueueOrigin(queueOrigin.Uint64())
} }
l, err := common.ReadVarBytes(b, 0, 1024, "L1Timestamp") l, err := common.ReadVarBytes(b, 0, 1024, "L1Timestamp")
...@@ -138,10 +138,6 @@ func TxMetaDecode(input []byte) (*TransactionMeta, error) { ...@@ -138,10 +138,6 @@ func TxMetaDecode(input []byte) (*TransactionMeta, error) {
func TxMetaEncode(meta *TransactionMeta) []byte { func TxMetaEncode(meta *TransactionMeta) []byte {
b := new(bytes.Buffer) b := new(bytes.Buffer)
s := new(bytes.Buffer)
binary.Write(s, binary.LittleEndian, &meta.SignatureHashType)
common.WriteVarBytes(b, 0, s.Bytes())
L1BlockNumber := meta.L1BlockNumber L1BlockNumber := meta.L1BlockNumber
if L1BlockNumber == nil { if L1BlockNumber == nil {
common.WriteVarBytes(b, 0, getNullValue()) common.WriteVarBytes(b, 0, getNullValue())
...@@ -161,13 +157,9 @@ func TxMetaEncode(meta *TransactionMeta) []byte { ...@@ -161,13 +157,9 @@ func TxMetaEncode(meta *TransactionMeta) []byte {
} }
queueOrigin := meta.QueueOrigin queueOrigin := meta.QueueOrigin
if queueOrigin == nil { q := new(bytes.Buffer)
common.WriteVarBytes(b, 0, getNullValue()) binary.Write(q, binary.LittleEndian, queueOrigin)
} else { common.WriteVarBytes(b, 0, q.Bytes())
q := new(bytes.Buffer)
binary.Write(q, binary.LittleEndian, queueOrigin.Bytes())
common.WriteVarBytes(b, 0, q.Bytes())
}
l := new(bytes.Buffer) l := new(bytes.Buffer)
binary.Write(l, binary.LittleEndian, &meta.L1Timestamp) binary.Write(l, binary.LittleEndian, &meta.L1Timestamp)
......
...@@ -17,7 +17,6 @@ var ( ...@@ -17,7 +17,6 @@ var (
l1BlockNumber *big.Int l1BlockNumber *big.Int
l1Timestamp uint64 l1Timestamp uint64
msgSender *common.Address msgSender *common.Address
sighashType SignatureHashType
queueOrigin QueueOrigin queueOrigin QueueOrigin
rawTransaction []byte rawTransaction []byte
}{ }{
...@@ -25,7 +24,6 @@ var ( ...@@ -25,7 +24,6 @@ var (
l1BlockNumber: l1BlockNumber, l1BlockNumber: l1BlockNumber,
l1Timestamp: 100, l1Timestamp: 100,
msgSender: &addr, msgSender: &addr,
sighashType: SighashEthSign,
queueOrigin: QueueOriginL1ToL2, queueOrigin: QueueOriginL1ToL2,
rawTransaction: []byte{255, 255, 255, 255}, rawTransaction: []byte{255, 255, 255, 255},
}, },
...@@ -33,7 +31,6 @@ var ( ...@@ -33,7 +31,6 @@ var (
l1BlockNumber: nil, l1BlockNumber: nil,
l1Timestamp: 45, l1Timestamp: 45,
msgSender: &addr, msgSender: &addr,
sighashType: SighashEthSign,
queueOrigin: QueueOriginL1ToL2, queueOrigin: QueueOriginL1ToL2,
rawTransaction: []byte{42, 69, 42, 69}, rawTransaction: []byte{42, 69, 42, 69},
}, },
...@@ -41,7 +38,6 @@ var ( ...@@ -41,7 +38,6 @@ var (
l1BlockNumber: l1BlockNumber, l1BlockNumber: l1BlockNumber,
l1Timestamp: 0, l1Timestamp: 0,
msgSender: nil, msgSender: nil,
sighashType: SighashEthSign,
queueOrigin: QueueOriginSequencer, queueOrigin: QueueOriginSequencer,
rawTransaction: []byte{0, 0, 0, 0}, rawTransaction: []byte{0, 0, 0, 0},
}, },
...@@ -49,7 +45,6 @@ var ( ...@@ -49,7 +45,6 @@ var (
l1BlockNumber: l1BlockNumber, l1BlockNumber: l1BlockNumber,
l1Timestamp: 0, l1Timestamp: 0,
msgSender: &addr, msgSender: &addr,
sighashType: SighashEthSign,
queueOrigin: QueueOriginSequencer, queueOrigin: QueueOriginSequencer,
rawTransaction: []byte{0, 0, 0, 0}, rawTransaction: []byte{0, 0, 0, 0},
}, },
...@@ -57,7 +52,6 @@ var ( ...@@ -57,7 +52,6 @@ var (
l1BlockNumber: nil, l1BlockNumber: nil,
l1Timestamp: 0, l1Timestamp: 0,
msgSender: nil, msgSender: nil,
sighashType: SighashEthSign,
queueOrigin: QueueOriginL1ToL2, queueOrigin: QueueOriginL1ToL2,
rawTransaction: []byte{0, 0, 0, 0}, rawTransaction: []byte{0, 0, 0, 0},
}, },
...@@ -65,30 +59,15 @@ var ( ...@@ -65,30 +59,15 @@ var (
l1BlockNumber: l1BlockNumber, l1BlockNumber: l1BlockNumber,
l1Timestamp: 0, l1Timestamp: 0,
msgSender: &addr, msgSender: &addr,
sighashType: SighashEthSign,
queueOrigin: QueueOriginL1ToL2, queueOrigin: QueueOriginL1ToL2,
rawTransaction: []byte{0, 0, 0, 0}, rawTransaction: []byte{0, 0, 0, 0},
}, },
} }
txMetaSighashEncodeTests = []struct {
input SignatureHashType
output SignatureHashType
}{
{
input: SighashEIP155,
output: SighashEIP155,
},
{
input: SighashEthSign,
output: SighashEthSign,
},
}
) )
func TestTransactionMetaEncode(t *testing.T) { func TestTransactionMetaEncode(t *testing.T) {
for _, test := range txMetaSerializationTests { for _, test := range txMetaSerializationTests {
txmeta := NewTransactionMeta(test.l1BlockNumber, test.l1Timestamp, test.msgSender, test.sighashType, test.queueOrigin, nil, nil, test.rawTransaction) txmeta := NewTransactionMeta(test.l1BlockNumber, test.l1Timestamp, test.msgSender, test.queueOrigin, nil, nil, test.rawTransaction)
encoded := TxMetaEncode(txmeta) encoded := TxMetaEncode(txmeta)
decoded, err := TxMetaDecode(encoded) decoded, err := TxMetaDecode(encoded)
...@@ -103,22 +82,6 @@ func TestTransactionMetaEncode(t *testing.T) { ...@@ -103,22 +82,6 @@ func TestTransactionMetaEncode(t *testing.T) {
} }
} }
func TestTransactionSighashEncode(t *testing.T) {
for _, test := range txMetaSighashEncodeTests {
txmeta := NewTransactionMeta(l1BlockNumber, 0, &addr, test.input, QueueOriginSequencer, nil, nil, nil)
encoded := TxMetaEncode(txmeta)
decoded, err := TxMetaDecode(encoded)
if err != nil {
t.Fatal(err)
}
if decoded.SignatureHashType != test.output {
t.Fatal("SighashTypes do not match")
}
}
}
func isTxMetaEqual(meta1 *TransactionMeta, meta2 *TransactionMeta) bool { func isTxMetaEqual(meta1 *TransactionMeta, meta2 *TransactionMeta) bool {
// Maybe can just return this // Maybe can just return this
if !reflect.DeepEqual(meta1, meta2) { if !reflect.DeepEqual(meta1, meta2) {
...@@ -149,18 +112,7 @@ func isTxMetaEqual(meta1 *TransactionMeta, meta2 *TransactionMeta) bool { ...@@ -149,18 +112,7 @@ func isTxMetaEqual(meta1 *TransactionMeta, meta2 *TransactionMeta) bool {
} }
} }
if meta1.SignatureHashType != meta2.SignatureHashType { if meta1.QueueOrigin != meta2.QueueOrigin {
return false
}
if meta1.QueueOrigin == nil || meta2.QueueOrigin == nil {
// Note: this only works because it is the final comparison
if meta1.QueueOrigin == nil && meta2.QueueOrigin == nil {
return true
}
}
if !bytes.Equal(meta1.QueueOrigin.Bytes(), meta2.QueueOrigin.Bytes()) {
return false return false
} }
......
...@@ -263,8 +263,4 @@ func TestOVMMetaDataHash(t *testing.T) { ...@@ -263,8 +263,4 @@ func TestOVMMetaDataHash(t *testing.T) {
if emptyTx.Hash() != emptyTxEmptyL1Sender.Hash() { if emptyTx.Hash() != emptyTxEmptyL1Sender.Hash() {
t.Errorf("L1MessageSender, should not affect the hash, want %x, got %x with L1MessageSender", emptyTx.Hash(), emptyTxEmptyL1Sender.Hash()) t.Errorf("L1MessageSender, should not affect the hash, want %x, got %x with L1MessageSender", emptyTx.Hash(), emptyTxEmptyL1Sender.Hash())
} }
if emptyTx.Hash() != emptyTxSighashEthSign.Hash() {
t.Errorf("SignatureHashType, should not affect the hash, want %x, got %x with SighashEthSign", emptyTx.Hash(), emptyTxSighashEthSign.Hash())
}
} }
...@@ -200,6 +200,7 @@ type Context struct { ...@@ -200,6 +200,7 @@ type Context struct {
OvmSafetyChecker dump.OvmDumpAccount OvmSafetyChecker dump.OvmDumpAccount
OvmL2CrossDomainMessenger dump.OvmDumpAccount OvmL2CrossDomainMessenger dump.OvmDumpAccount
OvmETH dump.OvmDumpAccount OvmETH dump.OvmDumpAccount
OvmL2StandardBridge dump.OvmDumpAccount
} }
// EVM is the Ethereum Virtual Machine base object and provides // EVM is the Ethereum Virtual Machine base object and provides
...@@ -252,6 +253,7 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon ...@@ -252,6 +253,7 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
ctx.OvmSafetyChecker = chainConfig.StateDump.Accounts["OVM_SafetyChecker"] ctx.OvmSafetyChecker = chainConfig.StateDump.Accounts["OVM_SafetyChecker"]
ctx.OvmL2CrossDomainMessenger = chainConfig.StateDump.Accounts["OVM_L2CrossDomainMessenger"] ctx.OvmL2CrossDomainMessenger = chainConfig.StateDump.Accounts["OVM_L2CrossDomainMessenger"]
ctx.OvmETH = chainConfig.StateDump.Accounts["OVM_ETH"] ctx.OvmETH = chainConfig.StateDump.Accounts["OVM_ETH"]
ctx.OvmL2StandardBridge = chainConfig.StateDump.Accounts["OVM_L2StandardBridge"]
} }
id := make([]byte, 4) id := make([]byte, 4)
...@@ -404,7 +406,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas ...@@ -404,7 +406,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if evm.Context.IsL1ToL2Message && evm.depth == 3 { if evm.Context.IsL1ToL2Message && evm.depth == 3 {
var isValidMessageTarget = true var isValidMessageTarget = true
// 0x420... addresses are not valid targets except for the ETH predeploy. // 0x420... addresses are not valid targets except for the ETH predeploy.
if bytes.HasPrefix(addr.Bytes(), fortyTwoPrefix) && addr != evm.Context.OvmETH.Address { if bytes.HasPrefix(addr.Bytes(), fortyTwoPrefix) && addr != evm.Context.OvmL2StandardBridge.Address {
isValidMessageTarget = false isValidMessageTarget = false
} }
// 0xdead... addresses are not valid targets. // 0xdead... addresses are not valid targets.
......
...@@ -321,14 +321,6 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) ...@@ -321,14 +321,6 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
if len(signedTx.Data()) > b.MaxCallDataSize { if len(signedTx.Data()) > b.MaxCallDataSize {
return fmt.Errorf("Calldata cannot be larger than %d, sent %d", b.MaxCallDataSize, len(signedTx.Data())) return fmt.Errorf("Calldata cannot be larger than %d, sent %d", b.MaxCallDataSize, len(signedTx.Data()))
} }
// If there is a value field set then reject transactions that
// contain calldata. The feature of sending transactions with value
// and calldata will be added in the future.
if signedTx.Value().Cmp(common.Big0) != 0 {
if len(signedTx.Data()) > 0 {
return errors.New("Cannot send transactions with value and calldata")
}
}
} }
return b.eth.syncService.ValidateAndApplySequencerTransaction(signedTx) return b.eth.syncService.ValidateAndApplySequencerTransaction(signedTx)
} }
......
...@@ -226,7 +226,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { ...@@ -226,7 +226,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
log.Info("Backend Config", "max-calldata-size", config.Rollup.MaxCallDataSize, "gas-limit", config.Rollup.GasLimit, "is-verifier", config.Rollup.IsVerifier, "using-ovm", vm.UsingOVM, "data-price", config.Rollup.DataPrice, "execution-price", config.Rollup.ExecutionPrice) log.Info("Backend Config", "max-calldata-size", config.Rollup.MaxCallDataSize, "gas-limit", config.Rollup.GasLimit, "is-verifier", config.Rollup.IsVerifier, "using-ovm", vm.UsingOVM)
eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil, nil, config.Rollup.IsVerifier, config.Rollup.GasLimit, vm.UsingOVM, config.Rollup.MaxCallDataSize} eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil, nil, config.Rollup.IsVerifier, config.Rollup.GasLimit, vm.UsingOVM, config.Rollup.MaxCallDataSize}
gpoParams := config.GPO gpoParams := config.GPO
if gpoParams.Default == nil { if gpoParams.Default == nil {
...@@ -234,7 +234,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { ...@@ -234,7 +234,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
} }
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
// create the Rollup GPO and allow the API backend and the sync service to access it // create the Rollup GPO and allow the API backend and the sync service to access it
rollupGpo := gasprice.NewRollupOracle(config.Rollup.DataPrice, config.Rollup.ExecutionPrice) rollupGpo := gasprice.NewRollupOracle()
eth.APIBackend.rollupGpo = rollupGpo eth.APIBackend.rollupGpo = rollupGpo
eth.syncService.RollupGpo = rollupGpo eth.syncService.RollupGpo = rollupGpo
return eth, nil return eth, nil
......
...@@ -81,8 +81,6 @@ var DefaultConfig = Config{ ...@@ -81,8 +81,6 @@ var DefaultConfig = Config{
// is additional overhead that is unaccounted. Round down to 127000 for // is additional overhead that is unaccounted. Round down to 127000 for
// safety. // safety.
MaxCallDataSize: 127000, MaxCallDataSize: 127000,
DataPrice: big.NewInt(100 * params.GWei),
ExecutionPrice: big.NewInt(0),
}, },
DiffDbCache: 256, DiffDbCache: 256,
} }
......
...@@ -17,10 +17,12 @@ type RollupOracle struct { ...@@ -17,10 +17,12 @@ type RollupOracle struct {
} }
// NewRollupOracle returns an initialized RollupOracle // NewRollupOracle returns an initialized RollupOracle
func NewRollupOracle(l1GasPrice *big.Int, l2GasPrice *big.Int) *RollupOracle { func NewRollupOracle() *RollupOracle {
return &RollupOracle{ return &RollupOracle{
l1GasPrice: l1GasPrice, l1GasPrice: new(big.Int),
l2GasPrice: l2GasPrice, l2GasPrice: new(big.Int),
l1GasPriceLock: sync.RWMutex{},
l2GasPriceLock: sync.RWMutex{},
} }
} }
......
...@@ -120,10 +120,9 @@ type CallMsg struct { ...@@ -120,10 +120,9 @@ type CallMsg struct {
Value *big.Int // amount of wei sent along with the call Value *big.Int // amount of wei sent along with the call
Data []byte // input data, usually an ABI-encoded contract method invocation Data []byte // input data, usually an ABI-encoded contract method invocation
L1MessageSender *common.Address L1MessageSender *common.Address
L1BlockNumber *big.Int L1BlockNumber *big.Int
QueueOrigin *big.Int QueueOrigin types.QueueOrigin
SignatureHashType types.SignatureHashType
} }
// A ContractCaller provides contract calls, essentially transactions that are executed by // A ContractCaller provides contract calls, essentially transactions that are executed by
......
...@@ -933,7 +933,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo ...@@ -933,7 +933,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
// Create new call message // Create new call message
var msg core.Message var msg core.Message
msg = types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false, &addr, nil, types.QueueOriginSequencer, 0) msg = types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false, &addr, nil, types.QueueOriginSequencer)
if vm.UsingOVM { if vm.UsingOVM {
cfg := b.ChainConfig() cfg := b.ChainConfig()
executionManager := cfg.StateDump.Accounts["OVM_ExecutionManager"] executionManager := cfg.StateDump.Accounts["OVM_ExecutionManager"]
...@@ -1364,14 +1364,8 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber ...@@ -1364,14 +1364,8 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
if meta.L1BlockNumber != nil { if meta.L1BlockNumber != nil {
result.L1BlockNumber = (*hexutil.Big)(meta.L1BlockNumber) result.L1BlockNumber = (*hexutil.Big)(meta.L1BlockNumber)
} }
if meta.QueueOrigin != nil {
switch meta.QueueOrigin.Uint64() { result.QueueOrigin = fmt.Sprint(meta.QueueOrigin)
case uint64(types.QueueOriginSequencer):
result.QueueOrigin = "sequencer"
case uint64(types.QueueOriginL1ToL2):
result.QueueOrigin = "l1"
}
}
if meta.Index != nil { if meta.Index != nil {
index := (hexutil.Uint64)(*meta.Index) index := (hexutil.Uint64)(*meta.Index)
...@@ -1381,15 +1375,6 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber ...@@ -1381,15 +1375,6 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
queueIndex := (hexutil.Uint64)(*meta.QueueIndex) queueIndex := (hexutil.Uint64)(*meta.QueueIndex)
result.QueueIndex = &queueIndex result.QueueIndex = &queueIndex
} }
switch meta.SignatureHashType {
case types.SighashEthSign:
result.TxType = "EthSign"
case types.SighashEIP155:
result.TxType = "EIP155"
case types.CreateEOA:
result.TxType = "CreateEOA"
}
} }
return result return result
} }
...@@ -1622,9 +1607,8 @@ type SendTxArgs struct { ...@@ -1622,9 +1607,8 @@ type SendTxArgs struct {
Data *hexutil.Bytes `json:"data"` Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"` Input *hexutil.Bytes `json:"input"`
L1BlockNumber *big.Int `json:"l1BlockNumber"` L1BlockNumber *big.Int `json:"l1BlockNumber"`
L1MessageSender *common.Address `json:"l1MessageSender"` L1MessageSender *common.Address `json:"l1MessageSender"`
SignatureHashType types.SignatureHashType `json:"signatureHashType"`
} }
// setDefaults is a helper function that fills in default values for unspecified tx fields. // setDefaults is a helper function that fills in default values for unspecified tx fields.
...@@ -1697,13 +1681,13 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { ...@@ -1697,13 +1681,13 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
if args.To == nil { if args.To == nil {
tx := types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) tx := types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
raw, _ := rlp.EncodeToBytes(tx) raw, _ := rlp.EncodeToBytes(tx)
txMeta := types.NewTransactionMeta(args.L1BlockNumber, 0, nil, types.SighashEIP155, types.QueueOriginSequencer, nil, nil, raw) txMeta := types.NewTransactionMeta(args.L1BlockNumber, 0, nil, types.QueueOriginSequencer, nil, nil, raw)
tx.SetTransactionMeta(txMeta) tx.SetTransactionMeta(txMeta)
return tx return tx
} }
tx := types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) tx := types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
raw, _ := rlp.EncodeToBytes(tx) raw, _ := rlp.EncodeToBytes(tx)
txMeta := types.NewTransactionMeta(args.L1BlockNumber, 0, args.L1MessageSender, args.SignatureHashType, types.QueueOriginSequencer, nil, nil, raw) txMeta := types.NewTransactionMeta(args.L1BlockNumber, 0, args.L1MessageSender, types.QueueOriginSequencer, nil, nil, raw)
tx.SetTransactionMeta(txMeta) tx.SetTransactionMeta(txMeta)
return tx return tx
} }
...@@ -1800,7 +1784,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod ...@@ -1800,7 +1784,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
return common.Hash{}, err return common.Hash{}, err
} }
// L1Timestamp and L1BlockNumber will be set right before execution // L1Timestamp and L1BlockNumber will be set right before execution
txMeta := types.NewTransactionMeta(nil, 0, nil, types.SighashEIP155, types.QueueOriginSequencer, nil, nil, encodedTx) txMeta := types.NewTransactionMeta(nil, 0, nil, types.QueueOriginSequencer, nil, nil, encodedTx)
tx.SetTransactionMeta(txMeta) tx.SetTransactionMeta(txMeta)
return SubmitTransaction(ctx, s.b, tx) return SubmitTransaction(ctx, s.b, tx)
} }
...@@ -2157,7 +2141,6 @@ func (api *PrivateDebugAPI) IngestTransactions(txs []*RPCTransaction) error { ...@@ -2157,7 +2141,6 @@ func (api *PrivateDebugAPI) IngestTransactions(txs []*RPCTransaction) error {
l1Timestamp := uint64(tx.L1Timestamp) l1Timestamp := uint64(tx.L1Timestamp)
rawTransaction := tx.RawTransaction rawTransaction := tx.RawTransaction
sighashType := types.SighashEIP155
var queueOrigin types.QueueOrigin var queueOrigin types.QueueOrigin
switch tx.QueueOrigin { switch tx.QueueOrigin {
case "sequencer": case "sequencer":
...@@ -2176,14 +2159,13 @@ func (api *PrivateDebugAPI) IngestTransactions(txs []*RPCTransaction) error { ...@@ -2176,14 +2159,13 @@ func (api *PrivateDebugAPI) IngestTransactions(txs []*RPCTransaction) error {
} }
meta := types.TransactionMeta{ meta := types.TransactionMeta{
L1BlockNumber: l1BlockNumber, L1BlockNumber: l1BlockNumber,
L1Timestamp: l1Timestamp, L1Timestamp: l1Timestamp,
L1MessageSender: tx.L1TxOrigin, L1MessageSender: tx.L1TxOrigin,
SignatureHashType: sighashType, QueueOrigin: queueOrigin,
QueueOrigin: big.NewInt(int64(queueOrigin)), Index: (*uint64)(tx.Index),
Index: (*uint64)(tx.Index), QueueIndex: (*uint64)(tx.QueueIndex),
QueueIndex: (*uint64)(tx.QueueIndex), RawTransaction: rawTransaction,
RawTransaction: rawTransaction,
} }
transaction.SetTransactionMeta(&meta) transaction.SetTransactionMeta(&meta)
transactions[i] = transaction transactions[i] = transaction
......
...@@ -128,7 +128,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai ...@@ -128,7 +128,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
from := statedb.GetOrNewStateObject(bankAddr) from := statedb.GetOrNewStateObject(bankAddr)
from.SetBalance(math.MaxBig256) from.SetBalance(math.MaxBig256)
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil, types.QueueOriginSequencer, 0)} msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil, types.QueueOriginSequencer)}
context := core.NewEVMContext(msg, header, bc, nil) context := core.NewEVMContext(msg, header, bc, nil)
vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
...@@ -142,7 +142,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai ...@@ -142,7 +142,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
header := lc.GetHeaderByHash(bhash) header := lc.GetHeaderByHash(bhash)
state := light.NewState(ctx, header, lc.Odr()) state := light.NewState(ctx, header, lc.Odr())
state.SetBalance(bankAddr, math.MaxBig256) state.SetBalance(bankAddr, math.MaxBig256)
msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil, types.QueueOriginSequencer, 0)} msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil, types.QueueOriginSequencer)}
context := core.NewEVMContext(msg, header, lc, nil) context := core.NewEVMContext(msg, header, lc, nil)
vmenv := vm.NewEVM(context, state, config, vm.Config{}) vmenv := vm.NewEVM(context, state, config, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
......
...@@ -194,7 +194,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain ...@@ -194,7 +194,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
// Perform read-only call. // Perform read-only call.
st.SetBalance(testBankAddress, math.MaxBig256) st.SetBalance(testBankAddress, math.MaxBig256)
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false, nil, nil, types.QueueOriginSequencer, 0)} msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false, nil, nil, types.QueueOriginSequencer)}
context := core.NewEVMContext(msg, header, chain, nil) context := core.NewEVMContext(msg, header, chain, nil)
vmenv := vm.NewEVM(context, st, config, vm.Config{}) vmenv := vm.NewEVM(context, st, config, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
......
...@@ -869,7 +869,7 @@ func (w *worker) commitNewTx(tx *types.Transaction) error { ...@@ -869,7 +869,7 @@ func (w *worker) commitNewTx(tx *types.Transaction) error {
// transactions as the timestamp cannot be malleated // transactions as the timestamp cannot be malleated
if parent.Time() > tx.L1Timestamp() { if parent.Time() > tx.L1Timestamp() {
log.Error("Monotonicity violation", "index", num) log.Error("Monotonicity violation", "index", num)
if tx.QueueOrigin().Uint64() == uint64(types.QueueOriginSequencer) { if tx.QueueOrigin() == types.QueueOriginSequencer {
tx.SetL1Timestamp(parent.Time()) tx.SetL1Timestamp(parent.Time())
prev := parent.Transactions() prev := parent.Transactions()
if len(prev) == 1 { if len(prev) == 1 {
...@@ -1073,7 +1073,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st ...@@ -1073,7 +1073,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st
bn = new(big.Int) bn = new(big.Int)
} }
log.Info("New block", "index", block.Number().Uint64()-uint64(1), "l1-timestamp", tx.L1Timestamp(), "l1-blocknumber", bn.Uint64(), "tx-hash", tx.Hash().Hex(), log.Info("New block", "index", block.Number().Uint64()-uint64(1), "l1-timestamp", tx.L1Timestamp(), "l1-blocknumber", bn.Uint64(), "tx-hash", tx.Hash().Hex(),
"queue-orign", tx.QueueOrigin(), "type", tx.SignatureHashType(), "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) "queue-orign", tx.QueueOrigin(), "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start)))
case <-w.exitCh: case <-w.exitCh:
log.Info("Worker has exited") log.Info("Worker has exited")
......
...@@ -74,7 +74,6 @@ type transaction struct { ...@@ -74,7 +74,6 @@ type transaction struct {
Origin *common.Address `json:"origin"` Origin *common.Address `json:"origin"`
Data hexutil.Bytes `json:"data"` Data hexutil.Bytes `json:"data"`
QueueOrigin string `json:"queueOrigin"` QueueOrigin string `json:"queueOrigin"`
Type string `json:"type"`
QueueIndex *uint64 `json:"queueIndex"` QueueIndex *uint64 `json:"queueIndex"`
Decoded *decoded `json:"decoded"` Decoded *decoded `json:"decoded"`
} }
...@@ -105,8 +104,8 @@ type decoded struct { ...@@ -105,8 +104,8 @@ type decoded struct {
Signature signature `json:"sig"` Signature signature `json:"sig"`
Value hexutil.Uint64 `json:"value"` Value hexutil.Uint64 `json:"value"`
GasLimit uint64 `json:"gasLimit,string"` GasLimit uint64 `json:"gasLimit,string"`
GasPrice uint64 `json:"gasPrice"` GasPrice uint64 `json:"gasPrice,string"`
Nonce uint64 `json:"nonce"` Nonce uint64 `json:"nonce,string"`
Target *common.Address `json:"target"` Target *common.Address `json:"target"`
Data hexutil.Bytes `json:"data"` Data hexutil.Bytes `json:"data"`
} }
...@@ -241,7 +240,6 @@ func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) { ...@@ -241,7 +240,6 @@ func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) {
blockNumber, blockNumber,
timestamp, timestamp,
&origin, &origin,
types.SighashEIP155,
types.QueueOriginL1ToL2, types.QueueOriginL1ToL2,
enqueue.Index, enqueue.Index,
enqueue.QueueIndex, enqueue.QueueIndex,
...@@ -327,7 +325,6 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe ...@@ -327,7 +325,6 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe
} else { } else {
return nil, fmt.Errorf("Unknown queue origin: %s", res.QueueOrigin) return nil, fmt.Errorf("Unknown queue origin: %s", res.QueueOrigin)
} }
sighashType := types.SighashEIP155
// Transactions that have been decoded are // Transactions that have been decoded are
// Queue Origin Sequencer transactions // Queue Origin Sequencer transactions
if res.Decoded != nil { if res.Decoded != nil {
...@@ -352,7 +349,6 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe ...@@ -352,7 +349,6 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe
new(big.Int).SetUint64(res.BlockNumber), new(big.Int).SetUint64(res.BlockNumber),
res.Timestamp, res.Timestamp,
res.Origin, res.Origin,
sighashType,
queueOrigin, queueOrigin,
&res.Index, &res.Index,
res.QueueIndex, res.QueueIndex,
...@@ -393,7 +389,6 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe ...@@ -393,7 +389,6 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe
new(big.Int).SetUint64(res.BlockNumber), new(big.Int).SetUint64(res.BlockNumber),
res.Timestamp, res.Timestamp,
origin, origin,
sighashType,
queueOrigin, queueOrigin,
&res.Index, &res.Index,
res.QueueIndex, res.QueueIndex,
......
...@@ -21,9 +21,10 @@ type Config struct { ...@@ -21,9 +21,10 @@ type Config struct {
// HTTP endpoint of the data transport layer // HTTP endpoint of the data transport layer
RollupClientHttp string RollupClientHttp string
L1CrossDomainMessengerAddress common.Address L1CrossDomainMessengerAddress common.Address
L1FeeWalletAddress common.Address
AddressManagerOwnerAddress common.Address AddressManagerOwnerAddress common.Address
L1ETHGatewayAddress common.Address GasPriceOracleOwnerAddress common.Address
GasPriceOracleAddress common.Address L1StandardBridgeAddress common.Address
// Turns on checking of state for L2 gas price // Turns on checking of state for L2 gas price
EnableL2GasPolling bool EnableL2GasPolling bool
// Deployment Height of the canonical transaction chain // Deployment Height of the canonical transaction chain
...@@ -34,10 +35,6 @@ type Config struct { ...@@ -34,10 +35,6 @@ type Config struct {
PollInterval time.Duration PollInterval time.Duration
// Interval for updating the timestamp // Interval for updating the timestamp
TimestampRefreshThreshold time.Duration TimestampRefreshThreshold time.Duration
// The gas price to use when estimating L1 calldata publishing costs
DataPrice *big.Int
// The gas price to use for L2 congestion costs
ExecutionPrice *big.Int
// Represents the source of the transactions that is being synced // Represents the source of the transactions that is being synced
Backend Backend Backend Backend
// Only accept transactions with fees // Only accept transactions with fees
......
...@@ -31,6 +31,7 @@ var errShortRemoteTip = errors.New("Unexpected remote less than tip") ...@@ -31,6 +31,7 @@ var errShortRemoteTip = errors.New("Unexpected remote less than tip")
// L2GasPrice slot refers to the storage slot that the execution price is stored // L2GasPrice slot refers to the storage slot that the execution price is stored
// in the L2 predeploy contract, the GasPriceOracle // in the L2 predeploy contract, the GasPriceOracle
var l2GasPriceSlot = common.BigToHash(big.NewInt(1)) var l2GasPriceSlot = common.BigToHash(big.NewInt(1))
var l2GasPriceOracleAddress = common.HexToAddress("0x420000000000000000000000000000000000000F")
// SyncService implements the main functionality around pulling in transactions // SyncService implements the main functionality around pulling in transactions
// and executing them. It can be configured to run in both sequencer mode and in // and executing them. It can be configured to run in both sequencer mode and in
...@@ -57,8 +58,6 @@ type SyncService struct { ...@@ -57,8 +58,6 @@ type SyncService struct {
timestampRefreshThreshold time.Duration timestampRefreshThreshold time.Duration
chainHeadCh chan core.ChainHeadEvent chainHeadCh chan core.ChainHeadEvent
backend Backend backend Backend
gpoAddress common.Address
enableL2GasPolling bool
enforceFees bool enforceFees bool
} }
...@@ -112,8 +111,6 @@ func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *co ...@@ -112,8 +111,6 @@ func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *co
pollInterval: pollInterval, pollInterval: pollInterval,
timestampRefreshThreshold: timestampRefreshThreshold, timestampRefreshThreshold: timestampRefreshThreshold,
backend: cfg.Backend, backend: cfg.Backend,
gpoAddress: cfg.GasPriceOracleAddress,
enableL2GasPolling: cfg.EnableL2GasPolling,
enforceFees: cfg.EnforceFees, enforceFees: cfg.EnforceFees,
} }
...@@ -435,11 +432,6 @@ func (s *SyncService) updateL1GasPrice() error { ...@@ -435,11 +432,6 @@ func (s *SyncService) updateL1GasPrice() error {
// price oracle at the state that corresponds to the state root. If no state // price oracle at the state that corresponds to the state root. If no state
// root is passed in, then the tip is used. // root is passed in, then the tip is used.
func (s *SyncService) updateL2GasPrice(hash *common.Hash) error { func (s *SyncService) updateL2GasPrice(hash *common.Hash) error {
// TODO(mark): this is temporary and will be able to be rmoved when the
// OVM_GasPriceOracle is moved into the predeploy contracts
if !s.enableL2GasPolling {
return nil
}
var state *state.StateDB var state *state.StateDB
var err error var err error
if hash != nil { if hash != nil {
...@@ -450,7 +442,7 @@ func (s *SyncService) updateL2GasPrice(hash *common.Hash) error { ...@@ -450,7 +442,7 @@ func (s *SyncService) updateL2GasPrice(hash *common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
result := state.GetState(s.gpoAddress, l2GasPriceSlot) result := state.GetState(l2GasPriceOracleAddress, l2GasPriceSlot)
s.RollupGpo.SetL2GasPrice(result.Big()) s.RollupGpo.SetL2GasPrice(result.Big())
return nil return nil
} }
...@@ -649,7 +641,7 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error { ...@@ -649,7 +641,7 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
// Queue Origin L1 to L2 transactions must have a timestamp that is set by // Queue Origin L1 to L2 transactions must have a timestamp that is set by
// the L1 block that holds the transaction. This should never happen but is // the L1 block that holds the transaction. This should never happen but is
// a sanity check to prevent fraudulent execution. // a sanity check to prevent fraudulent execution.
if tx.QueueOrigin().Uint64() == uint64(types.QueueOriginL1ToL2) { if tx.QueueOrigin() == types.QueueOriginL1ToL2 {
if tx.L1Timestamp() == 0 { if tx.L1Timestamp() == 0 {
return fmt.Errorf("Queue origin L1 to L2 transaction without a timestamp: %s", tx.Hash().Hex()) return fmt.Errorf("Queue origin L1 to L2 transaction without a timestamp: %s", tx.Hash().Hex())
} }
...@@ -676,7 +668,7 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error { ...@@ -676,7 +668,7 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
bn := tx.L1BlockNumber() bn := tx.L1BlockNumber()
s.SetLatestL1Timestamp(ts) s.SetLatestL1Timestamp(ts)
s.SetLatestL1BlockNumber(bn.Uint64()) s.SetLatestL1BlockNumber(bn.Uint64())
log.Debug("Updating OVM context based on new transaction", "timestamp", ts, "blocknumber", bn.Uint64(), "queue-origin", tx.QueueOrigin().Uint64()) log.Debug("Updating OVM context based on new transaction", "timestamp", ts, "blocknumber", bn.Uint64(), "queue-origin", tx.QueueOrigin())
} else if tx.L1Timestamp() < s.GetLatestL1Timestamp() { } else if tx.L1Timestamp() < s.GetLatestL1Timestamp() {
log.Error("Timestamp monotonicity violation", "hash", tx.Hash().Hex()) log.Error("Timestamp monotonicity violation", "hash", tx.Hash().Hex())
} }
...@@ -795,11 +787,8 @@ func (s *SyncService) ValidateAndApplySequencerTransaction(tx *types.Transaction ...@@ -795,11 +787,8 @@ func (s *SyncService) ValidateAndApplySequencerTransaction(tx *types.Transaction
log.Trace("Sequencer transaction validation", "hash", tx.Hash().Hex()) log.Trace("Sequencer transaction validation", "hash", tx.Hash().Hex())
qo := tx.QueueOrigin() qo := tx.QueueOrigin()
if qo == nil { if qo != types.QueueOriginSequencer {
return errors.New("invalid transaction with no queue origin") return fmt.Errorf("invalid transaction with queue origin %d", qo)
}
if qo.Uint64() != uint64(types.QueueOriginSequencer) {
return fmt.Errorf("invalid transaction with queue origin %d", qo.Uint64())
} }
err := s.txpool.ValidateTx(tx) err := s.txpool.ValidateTx(tx)
if err != nil { if err != nil {
......
...@@ -121,7 +121,6 @@ func TestSyncServiceTransactionEnqueued(t *testing.T) { ...@@ -121,7 +121,6 @@ func TestSyncServiceTransactionEnqueued(t *testing.T) {
l1BlockNumber, l1BlockNumber,
timestamp, timestamp,
&l1TxOrigin, &l1TxOrigin,
types.SighashEIP155,
types.QueueOriginL1ToL2, types.QueueOriginL1ToL2,
&index, &index,
&queueIndex, &queueIndex,
...@@ -178,7 +177,6 @@ func TestTransactionToTipNoIndex(t *testing.T) { ...@@ -178,7 +177,6 @@ func TestTransactionToTipNoIndex(t *testing.T) {
l1BlockNumber, l1BlockNumber,
timestamp, timestamp,
&l1TxOrigin, &l1TxOrigin,
types.SighashEIP155,
types.QueueOriginL1ToL2, types.QueueOriginL1ToL2,
nil, // The index is `nil`, expect it to be set afterwards nil, // The index is `nil`, expect it to be set afterwards
nil, nil,
...@@ -518,8 +516,6 @@ func TestSyncServiceL2GasPrice(t *testing.T) { ...@@ -518,8 +516,6 @@ func TestSyncServiceL2GasPrice(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
service.enableL2GasPolling = true
service.gpoAddress = common.HexToAddress("0xF20b338752976878754518183873602902360704")
price, err := service.RollupGpo.SuggestL2GasPrice(context.Background()) price, err := service.RollupGpo.SuggestL2GasPrice(context.Background())
if err != nil { if err != nil {
...@@ -535,7 +531,7 @@ func TestSyncServiceL2GasPrice(t *testing.T) { ...@@ -535,7 +531,7 @@ func TestSyncServiceL2GasPrice(t *testing.T) {
t.Fatal("Cannot get state db") t.Fatal("Cannot get state db")
} }
l2GasPrice := big.NewInt(100000000000) l2GasPrice := big.NewInt(100000000000)
state.SetState(service.gpoAddress, l2GasPriceSlot, common.BigToHash(l2GasPrice)) state.SetState(l2GasPriceOracleAddress, l2GasPriceSlot, common.BigToHash(l2GasPrice))
root, _ := state.Commit(false) root, _ := state.Commit(false)
service.updateL2GasPrice(&root) service.updateL2GasPrice(&root)
...@@ -571,7 +567,6 @@ func TestSyncServiceSync(t *testing.T) { ...@@ -571,7 +567,6 @@ func TestSyncServiceSync(t *testing.T) {
l1BlockNumber, l1BlockNumber,
timestamp, timestamp,
&l1TxOrigin, &l1TxOrigin,
types.SighashEIP155,
types.QueueOriginL1ToL2, types.QueueOriginL1ToL2,
&index, &index,
&queueIndex, &queueIndex,
...@@ -623,7 +618,6 @@ func TestInitializeL1ContextPostGenesis(t *testing.T) { ...@@ -623,7 +618,6 @@ func TestInitializeL1ContextPostGenesis(t *testing.T) {
l1BlockNumber, l1BlockNumber,
timestamp, timestamp,
&l1TxOrigin, &l1TxOrigin,
types.SighashEIP155,
types.QueueOriginL1ToL2, types.QueueOriginL1ToL2,
&index, &index,
&queueIndex, &queueIndex,
...@@ -699,7 +693,7 @@ func newTestSyncService(isVerifier bool) (*SyncService, chan core.NewTxsEvent, e ...@@ -699,7 +693,7 @@ func newTestSyncService(isVerifier bool) (*SyncService, chan core.NewTxsEvent, e
return nil, nil, nil, fmt.Errorf("Cannot initialize syncservice: %w", err) return nil, nil, nil, fmt.Errorf("Cannot initialize syncservice: %w", err)
} }
service.RollupGpo = gasprice.NewRollupOracle(big.NewInt(0), big.NewInt(0)) service.RollupGpo = gasprice.NewRollupOracle()
txCh := make(chan core.NewTxsEvent, 1) txCh := make(chan core.NewTxsEvent, 1)
sub := service.SubscribeNewTxsEvent(txCh) sub := service.SubscribeNewTxsEvent(txCh)
...@@ -721,7 +715,7 @@ type mockClient struct { ...@@ -721,7 +715,7 @@ type mockClient struct {
func setupMockClient(service *SyncService, responses map[string]interface{}) { func setupMockClient(service *SyncService, responses map[string]interface{}) {
client := newMockClient(responses) client := newMockClient(responses)
service.client = client service.client = client
service.RollupGpo = gasprice.NewRollupOracle(big.NewInt(0), big.NewInt(0)) service.RollupGpo = gasprice.NewRollupOracle()
} }
func newMockClient(responses map[string]interface{}) *mockClient { func newMockClient(responses map[string]interface{}) *mockClient {
...@@ -871,7 +865,6 @@ func mockTx() *types.Transaction { ...@@ -871,7 +865,6 @@ func mockTx() *types.Transaction {
l1BlockNumber, l1BlockNumber,
timestamp, timestamp,
&l1TxOrigin, &l1TxOrigin,
types.SighashEIP155,
types.QueueOriginSequencer, types.QueueOriginSequencer,
nil, nil,
nil, nil,
......
...@@ -6,10 +6,10 @@ REPO=$DIR/.. ...@@ -6,10 +6,10 @@ REPO=$DIR/..
IS_VERIFIER= IS_VERIFIER=
ROLLUP_SYNC_SERVICE_ENABLE=true ROLLUP_SYNC_SERVICE_ENABLE=true
DATADIR=$HOME/.ethereum DATADIR=$HOME/.ethereum
TARGET_GAS_LIMIT=9000000 TARGET_GAS_LIMIT=11000000
CHAIN_ID=10 CHAIN_ID=10
ETH1_CTC_DEPLOYMENT_HEIGHT=12410807 ETH1_CTC_DEPLOYMENT_HEIGHT=12410807
ETH1_L1_GATEWAY_ADDRESS=0xe681F80966a8b1fFadECf8068bD6F99034791c95 ETH1_L1_STANDARD_BRIDGE_ADDRESS=0xe681F80966a8b1fFadECf8068bD6F99034791c95
ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS=0x902e5fF5A99C4eC1C21bbab089fdabE32EF0A5DF ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS=0x902e5fF5A99C4eC1C21bbab089fdabE32EF0A5DF
ADDRESS_MANAGER_OWNER_ADDRESS=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A ADDRESS_MANAGER_OWNER_ADDRESS=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A
ROLLUP_STATE_DUMP_PATH=https://storage.googleapis.com/optimism/mainnet/4.json ROLLUP_STATE_DUMP_PATH=https://storage.googleapis.com/optimism/mainnet/4.json
...@@ -33,6 +33,7 @@ CLI Arguments: ...@@ -33,6 +33,7 @@ CLI Arguments:
--eth1.chainid - eth1 chain id --eth1.chainid - eth1 chain id
--eth1.ctcdeploymentheight - eth1 ctc deploy height --eth1.ctcdeploymentheight - eth1 ctc deploy height
--eth1.l1crossdomainmessengeraddress - eth1 l1 xdomain messenger address --eth1.l1crossdomainmessengeraddress - eth1 l1 xdomain messenger address
--eth1.l1feewalletaddress - eth l1 fee wallet address
--rollup.statedumppath - http path to the initial state dump --rollup.statedumppath - http path to the initial state dump
--rollup.clienthttp - rollup client http --rollup.clienthttp - rollup client http
--rollup.pollinterval - polling interval for the rollup client --rollup.pollinterval - polling interval for the rollup client
...@@ -109,27 +110,27 @@ while (( "$#" )); do ...@@ -109,27 +110,27 @@ while (( "$#" )); do
exit 1 exit 1
fi fi
;; ;;
--eth1.l1gatewayaddress) --eth1.l1crossdomainmessengeraddress)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
ETH1_L1_GATEWAY_ADDRESS="$2" ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS="$2"
shift 2 shift 2
else else
echo "Error: Argument for $1 is missing" >&2 echo "Error: Argument for $1 is missing" >&2
exit 1 exit 1
fi fi
;; ;;
--eth1.l1crossdomainmessengeraddress) --eth1.l1feewalletaddress)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS="$2" ETH1_L1_FEE_WALLET_ADDRESS="$2"
shift 2 shift 2
else else
echo "Error: Argument for $1 is missing" >&2 echo "Error: Argument for $1 is missing" >&2
exit 1 exit 1
fi fi
;; ;;
--eth1.l1ethgatewayaddress) --eth1.l1standardbridgeaddress)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
ETH1_L1_ETH_GATEWAY_ADDRESS="$2" ETH1_L1_STANDARD_BRIDGE_ADDRESS="$2"
shift 2 shift 2
else else
echo "Error: Argument for $1 is missing" >&2 echo "Error: Argument for $1 is missing" >&2
...@@ -230,10 +231,11 @@ if [[ ! -z "$ROLLUP_SYNC_SERVICE_ENABLE" ]]; then ...@@ -230,10 +231,11 @@ if [[ ! -z "$ROLLUP_SYNC_SERVICE_ENABLE" ]]; then
fi fi
cmd="$cmd --datadir $DATADIR" cmd="$cmd --datadir $DATADIR"
cmd="$cmd --eth1.l1crossdomainmessengeraddress $ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS" cmd="$cmd --eth1.l1crossdomainmessengeraddress $ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS"
cmd="$cmd --eth1.l1feewalletaddress $ETH1_L1_FEE_WALLET_ADDRESS"
cmd="$cmd --rollup.addressmanagerowneraddress $ADDRESS_MANAGER_OWNER_ADDRESS" cmd="$cmd --rollup.addressmanagerowneraddress $ADDRESS_MANAGER_OWNER_ADDRESS"
cmd="$cmd --rollup.statedumppath $ROLLUP_STATE_DUMP_PATH" cmd="$cmd --rollup.statedumppath $ROLLUP_STATE_DUMP_PATH"
cmd="$cmd --eth1.ctcdeploymentheight $ETH1_CTC_DEPLOYMENT_HEIGHT" cmd="$cmd --eth1.ctcdeploymentheight $ETH1_CTC_DEPLOYMENT_HEIGHT"
cmd="$cmd --eth1.l1ethgatewayaddress $ETH1_L1_GATEWAY_ADDRESS" cmd="$cmd --eth1.l1standardbridgeaddress $ETH1_L1_STANDARD_BRIDGE_ADDRESS"
cmd="$cmd --rollup.clienthttp $ROLLUP_CLIENT_HTTP" cmd="$cmd --rollup.clienthttp $ROLLUP_CLIENT_HTTP"
cmd="$cmd --rollup.pollinterval $ROLLUP_POLL_INTERVAL" cmd="$cmd --rollup.pollinterval $ROLLUP_POLL_INTERVAL"
cmd="$cmd --rollup.timestamprefresh $ROLLUP_TIMESTAMP_REFRESH" cmd="$cmd --rollup.timestamprefresh $ROLLUP_TIMESTAMP_REFRESH"
......
...@@ -78,10 +78,9 @@ type SendTxArgs struct { ...@@ -78,10 +78,9 @@ type SendTxArgs struct {
Data *hexutil.Bytes `json:"data"` Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"` Input *hexutil.Bytes `json:"input"`
L1MessageSender *common.MixedcaseAddress `json:"l1MessageSender"` L1MessageSender *common.MixedcaseAddress `json:"l1MessageSender"`
L1BlockNumber *big.Int `json:"l1BlockNumber"` L1BlockNumber *big.Int `json:"l1BlockNumber"`
SignatureHashType types.SignatureHashType `json:"signatureHashType"` QueueOrigin types.QueueOrigin `json:"queueOrigin"`
QueueOrigin types.QueueOrigin `json:"queueOrigin"`
} }
func (args SendTxArgs) String() string { func (args SendTxArgs) String() string {
...@@ -111,7 +110,7 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { ...@@ -111,7 +110,7 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
} }
tx := types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), input) tx := types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), input)
txMeta := types.NewTransactionMeta(l1BlockNumber, 0, l1MessageSender, args.SignatureHashType, args.QueueOrigin, nil, nil, nil) txMeta := types.NewTransactionMeta(l1BlockNumber, 0, l1MessageSender, args.QueueOrigin, nil, nil, nil)
tx.SetTransactionMeta(txMeta) tx.SetTransactionMeta(txMeta)
return tx return tx
} }
...@@ -279,7 +279,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { ...@@ -279,7 +279,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) {
return nil, fmt.Errorf("invalid tx data %q", dataHex) return nil, fmt.Errorf("invalid tx data %q", dataHex)
} }
msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true, nil, nil, types.QueueOriginSequencer, 0) msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true, nil, nil, types.QueueOriginSequencer)
return msg, nil return msg, nil
} }
......
...@@ -33,5 +33,5 @@ IPC_DISABLE=true ...@@ -33,5 +33,5 @@ IPC_DISABLE=true
NETWORK_ID=420 NETWORK_ID=420
NO_USB=true NO_USB=true
NO_DISCOVER=true NO_DISCOVER=true
TARGET_GAS_LIMIT=9000000 TARGET_GAS_LIMIT=11000000
USING_OVM=true USING_OVM=true
...@@ -21,9 +21,9 @@ if [[ ! -z "$URL" ]]; then ...@@ -21,9 +21,9 @@ if [[ ! -z "$URL" ]]; then
envSet ROLLUP_ADDRESS_MANAGER_OWNER_ADDRESS Deployer envSet ROLLUP_ADDRESS_MANAGER_OWNER_ADDRESS Deployer
# set the address to the proxy gateway if possible # set the address to the proxy gateway if possible
envSet ETH1_L1_ETH_GATEWAY_ADDRESS Proxy__OVM_L1ETHGateway envSet ETH1_L1_STANDARD_BRIDGE_ADDRESS Proxy__OVM_L1StandardBridge
if [ $ETH1_L1_ETH_GATEWAY_ADDRESS == null ]; then if [ $ETH1_L1_STANDARD_BRIDGE_ADDRESS == null ]; then
envSet ETH1_L1_ETH_GATEWAY_ADDRESS OVM_L1ETHGateway envSet ETH1_L1_STANDARD_BRIDGE_ADDRESS OVM_L1StandardBridge
fi fi
fi fi
......
...@@ -622,7 +622,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -622,7 +622,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
) )
const addr = await manager.getAddress( const addr = await manager.getAddress(
'OVM_ChainStorageContainer:CTC:batches' 'OVM_ChainStorageContainer-CTC-batches'
) )
const container = new Contract( const container = new Contract(
addr, addr,
......
...@@ -9,7 +9,7 @@ import sinon from 'sinon' ...@@ -9,7 +9,7 @@ import sinon from 'sinon'
import { Web3Provider } from '@ethersproject/providers' import { Web3Provider } from '@ethersproject/providers'
import scc from '@eth-optimism/contracts/artifacts/contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol/OVM_StateCommitmentChain.json' import scc from '@eth-optimism/contracts/artifacts/contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol/OVM_StateCommitmentChain.json'
import { getContractInterface } from '@eth-optimism/contracts' import { getContractInterface, predeploys } from '@eth-optimism/contracts'
import { smockit, MockContract } from '@eth-optimism/smock' import { smockit, MockContract } from '@eth-optimism/smock'
/* Internal Imports */ /* Internal Imports */
...@@ -37,7 +37,6 @@ import { ...@@ -37,7 +37,6 @@ import {
} from '@eth-optimism/core-utils' } from '@eth-optimism/core-utils'
import { Logger, Metrics } from '@eth-optimism/common-ts' import { Logger, Metrics } from '@eth-optimism/common-ts'
const DECOMPRESSION_ADDRESS = '0x4200000000000000000000000000000000000008'
const DUMMY_ADDRESS = '0x' + '00'.repeat(20) const DUMMY_ADDRESS = '0x' + '00'.repeat(20)
const EXAMPLE_STATE_ROOT = const EXAMPLE_STATE_ROOT =
'0x16b7f83f409c7195b1f4fde5652f1b54a4477eacb6db7927691becafba5f8801' '0x16b7f83f409c7195b1f4fde5652f1b54a4477eacb6db7927691becafba5f8801'
...@@ -97,7 +96,7 @@ describe('BatchSubmitter', () => { ...@@ -97,7 +96,7 @@ describe('BatchSubmitter', () => {
) )
await AddressManager.setAddress( await AddressManager.setAddress(
'OVM_DecompressionPrecompileAddress', 'OVM_DecompressionPrecompileAddress',
DECOMPRESSION_ADDRESS predeploys.OVM_SequencerEntrypoint
) )
Mock__OVM_ExecutionManager = await smockit( Mock__OVM_ExecutionManager = await smockit(
...@@ -483,7 +482,7 @@ describe('Batch Submitter with Ganache', () => { ...@@ -483,7 +482,7 @@ describe('Batch Submitter with Ganache', () => {
gasPrices.push(gasPrice) gasPrices.push(gasPrice)
const tx = signer.sendTransaction({ const tx = signer.sendTransaction({
to: DECOMPRESSION_ADDRESS, to: predeploys.OVM_SequencerEntrypoint,
value: 88, value: 88,
nonce: 0, nonce: 0,
gasPrice, gasPrice,
......
...@@ -5,6 +5,7 @@ import * as mkdirp from 'mkdirp' ...@@ -5,6 +5,7 @@ import * as mkdirp from 'mkdirp'
const env = process.env const env = process.env
const CHAIN_ID = env.CHAIN_ID || '420' const CHAIN_ID = env.CHAIN_ID || '420'
const GAS_PRICE_ORACLE_OWNER = env.GAS_PRICE_ORACLE_OWNER || '0x' + 'FF'.repeat(20)
/* Internal Imports */ /* Internal Imports */
import { makeStateDump } from '../src/state-dump/make-dump' import { makeStateDump } from '../src/state-dump/make-dump'
...@@ -18,6 +19,10 @@ import { RollupDeployConfig } from '../src/contract-deployment' ...@@ -18,6 +19,10 @@ import { RollupDeployConfig } from '../src/contract-deployment'
ovmGlobalContext: { ovmGlobalContext: {
ovmCHAINID: parseInt(CHAIN_ID, 10), ovmCHAINID: parseInt(CHAIN_ID, 10),
}, },
gasPriceOracleConfig: {
owner: GAS_PRICE_ORACLE_OWNER,
initialGasPrice: 0,
}
} }
const dump = await makeStateDump(config as RollupDeployConfig) const dump = await makeStateDump(config as RollupDeployConfig)
......
This diff is collapsed.
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title iL1ChugSplashDeployer
*/
interface iL1ChugSplashDeployer {
function isUpgrading()
external
view
returns (
bool
);
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iAbs_BaseCrossDomainMessenger } from "../../../iOVM/bridge/messaging/iAbs_BaseCrossDomainMessenger.sol";
/**
* @title Abs_BaseCrossDomainMessenger
* @dev The Base Cross Domain Messenger is an abstract contract providing the interface and common
* functionality used in the L1 and L2 Cross Domain Messengers. It can also serve as a template for
* developers wishing to implement a custom bridge contract to suit their needs.
*
* Compiler used: defined by child contract
* Runtime target: defined by child contract
*/
abstract contract Abs_BaseCrossDomainMessenger is iAbs_BaseCrossDomainMessenger {
/*************
* Constants *
*************/
// The default x-domain message sender being set to a non-zero value makes
// deployment a bit more expensive, but in exchange the refund on every call to
// `relayMessage` by the L1 and L2 messengers will be higher.
address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD;
/*************
* Variables *
*************/
mapping (bytes32 => bool) public relayedMessages;
mapping (bytes32 => bool) public successfulMessages;
mapping (bytes32 => bool) public sentMessages;
uint256 public messageNonce;
address internal xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
/***************
* Constructor *
***************/
constructor() {}
/********************
* Public Functions *
********************/
function xDomainMessageSender()
public
override
view
returns (
address
)
{
require(xDomainMsgSender != DEFAULT_XDOMAIN_SENDER, "xDomainMessageSender is not set");
return xDomainMsgSender;
}
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
msg.sender,
_message,
messageNonce
);
messageNonce += 1;
sentMessages[keccak256(xDomainCalldata)] = true;
_sendXDomainMessage(xDomainCalldata, _gasLimit);
emit SentMessage(xDomainCalldata);
}
/**********************
* Internal Functions *
**********************/
/**
* Generates the correct cross domain calldata for a message.
* @param _target Target contract address.
* @param _sender Message sender address.
* @param _message Message to send to the target.
* @param _messageNonce Nonce for the provided message.
* @return ABI encoded cross domain calldata.
*/
function _getXDomainCalldata(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce
)
internal
pure
returns (
bytes memory
)
{
return abi.encodeWithSignature(
"relayMessage(address,address,bytes,uint256)",
_target,
_sender,
_message,
_messageNonce
);
}
/**
* Sends a cross domain message.
* param // Message to send.
* param // Gas limit for the provided message.
*/
function _sendXDomainMessage(
bytes memory, // _message,
uint256 // _gasLimit
)
virtual
internal
{
revert("Implement me in child contracts!");
}
}
...@@ -3,19 +3,18 @@ pragma solidity >0.5.0 <0.8.0; ...@@ -3,19 +3,18 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_OVMCodec } from "../../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol"; import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_OVMCodec } from "../../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManager.sol"; import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManager.sol";
import { Lib_SecureMerkleTrie } from "../../../libraries/trie/Lib_SecureMerkleTrie.sol"; import { Lib_SecureMerkleTrie } from "../../../libraries/trie/Lib_SecureMerkleTrie.sol";
import { Lib_PredeployAddresses } from "../../../libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_CrossDomainUtils } from "../../../libraries/bridge/Lib_CrossDomainUtils.sol";
/* Interface Imports */ /* Interface Imports */
import { iOVM_L1CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L1CrossDomainMessenger.sol"; import { iOVM_L1CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_CanonicalTransactionChain } from "../../../iOVM/chain/iOVM_CanonicalTransactionChain.sol"; import { iOVM_CanonicalTransactionChain } from "../../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_StateCommitmentChain } from "../../../iOVM/chain/iOVM_StateCommitmentChain.sol"; import { iOVM_StateCommitmentChain } from "../../../iOVM/chain/iOVM_StateCommitmentChain.sol";
/* Contract Imports */
import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
/* External Imports */ /* External Imports */
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
...@@ -32,7 +31,6 @@ import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/ ...@@ -32,7 +31,6 @@ import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/
*/ */
contract OVM_L1CrossDomainMessenger is contract OVM_L1CrossDomainMessenger is
iOVM_L1CrossDomainMessenger, iOVM_L1CrossDomainMessenger,
Abs_BaseCrossDomainMessenger,
Lib_AddressResolver, Lib_AddressResolver,
OwnableUpgradeable, OwnableUpgradeable,
PausableUpgradeable, PausableUpgradeable,
...@@ -51,11 +49,24 @@ contract OVM_L1CrossDomainMessenger is ...@@ -51,11 +49,24 @@ contract OVM_L1CrossDomainMessenger is
bytes32 indexed _xDomainCalldataHash bytes32 indexed _xDomainCalldataHash
); );
/*************
* Constants *
*************/
// The default x-domain message sender being set to a non-zero value makes
// deployment a bit more expensive, but in exchange the refund on every call to
// `relayMessage` by the L1 and L2 messengers will be higher.
address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD;
/********************** /**********************
* Contract Variables * * Contract Variables *
**********************/ **********************/
mapping (bytes32 => bool) public blockedMessages; mapping (bytes32 => bool) public blockedMessages;
mapping (bytes32 => bool) public relayedMessages;
mapping (bytes32 => bool) public successfulMessages;
address internal xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
/*************** /***************
* Constructor * * Constructor *
...@@ -155,6 +166,48 @@ contract OVM_L1CrossDomainMessenger is ...@@ -155,6 +166,48 @@ contract OVM_L1CrossDomainMessenger is
emit MessageAllowed(_xDomainCalldataHash); emit MessageAllowed(_xDomainCalldataHash);
} }
function xDomainMessageSender()
public
override
view
returns (
address
)
{
require(xDomainMsgSender != DEFAULT_XDOMAIN_SENDER, "xDomainMessageSender is not set");
return xDomainMsgSender;
}
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
)
override
public
{
address ovmCanonicalTransactionChain = resolve("OVM_CanonicalTransactionChain");
// Use the CTC queue length as nonce
uint40 nonce = iOVM_CanonicalTransactionChain(ovmCanonicalTransactionChain).getQueueLength();
bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target,
msg.sender,
_message,
nonce
);
address l2CrossDomainMessenger = resolve("OVM_L2CrossDomainMessenger");
_sendXDomainMessage(ovmCanonicalTransactionChain, l2CrossDomainMessenger, xDomainCalldata, _gasLimit);
emit SentMessage(xDomainCalldata);
}
/** /**
* Relays a cross domain message to a contract. * Relays a cross domain message to a contract.
* @inheritdoc iOVM_L1CrossDomainMessenger * @inheritdoc iOVM_L1CrossDomainMessenger
...@@ -172,7 +225,7 @@ contract OVM_L1CrossDomainMessenger is ...@@ -172,7 +225,7 @@ contract OVM_L1CrossDomainMessenger is
onlyRelayer onlyRelayer
whenNotPaused whenNotPaused
{ {
bytes memory xDomainCalldata = _getXDomainCalldata( bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target, _target,
_sender, _sender,
_message, _message,
...@@ -232,25 +285,40 @@ contract OVM_L1CrossDomainMessenger is ...@@ -232,25 +285,40 @@ contract OVM_L1CrossDomainMessenger is
address _target, address _target,
address _sender, address _sender,
bytes memory _message, bytes memory _message,
uint256 _messageNonce, uint256 _queueIndex,
uint32 _gasLimit uint32 _gasLimit
) )
override override
public public
{ {
bytes memory xDomainCalldata = _getXDomainCalldata( // Verify that the message is in the queue:
_target, address canonicalTransactionChain = resolve("OVM_CanonicalTransactionChain");
_sender, Lib_OVMCodec.QueueElement memory element = iOVM_CanonicalTransactionChain(canonicalTransactionChain).getQueueElement(_queueIndex);
_message,
_messageNonce address l2CrossDomainMessenger = resolve("OVM_L2CrossDomainMessenger");
// Compute the transactionHash
bytes32 transactionHash = keccak256(
abi.encode(
address(this),
l2CrossDomainMessenger,
_gasLimit,
_message
)
); );
require( require(
sentMessages[keccak256(xDomainCalldata)] == true, transactionHash == element.transactionHash,
"Provided message has not already been sent." "Provided message has not been enqueued."
);
bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target,
_sender,
_message,
_queueIndex
); );
_sendXDomainMessage(xDomainCalldata, _gasLimit); _sendXDomainMessage(canonicalTransactionChain, l2CrossDomainMessenger, xDomainCalldata, _gasLimit);
} }
...@@ -340,7 +408,7 @@ contract OVM_L1CrossDomainMessenger is ...@@ -340,7 +408,7 @@ contract OVM_L1CrossDomainMessenger is
bool exists, bool exists,
bytes memory encodedMessagePassingAccount bytes memory encodedMessagePassingAccount
) = Lib_SecureMerkleTrie.get( ) = Lib_SecureMerkleTrie.get(
abi.encodePacked(0x4200000000000000000000000000000000000000), abi.encodePacked(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER),
_proof.stateTrieWitness, _proof.stateTrieWitness,
_proof.stateRoot _proof.stateRoot
); );
...@@ -364,18 +432,21 @@ contract OVM_L1CrossDomainMessenger is ...@@ -364,18 +432,21 @@ contract OVM_L1CrossDomainMessenger is
/** /**
* Sends a cross domain message. * Sends a cross domain message.
* @param _canonicalTransactionChain Address of the OVM_CanonicalTransactionChain instance.
* @param _l2CrossDomainMessenger Address of the OVM_L2CrossDomainMessenger instance.
* @param _message Message to send. * @param _message Message to send.
* @param _gasLimit OVM gas limit for the message. * @param _gasLimit OVM gas limit for the message.
*/ */
function _sendXDomainMessage( function _sendXDomainMessage(
address _canonicalTransactionChain,
address _l2CrossDomainMessenger,
bytes memory _message, bytes memory _message,
uint256 _gasLimit uint256 _gasLimit
) )
override
internal internal
{ {
iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")).enqueue( iOVM_CanonicalTransactionChain(_canonicalTransactionChain).enqueue(
resolve("OVM_L2CrossDomainMessenger"), _l2CrossDomainMessenger,
_gasLimit, _gasLimit,
_message _message
); );
......
...@@ -4,14 +4,15 @@ pragma experimental ABIEncoderV2; ...@@ -4,14 +4,15 @@ pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol"; import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_CrossDomainUtils } from "../../../libraries/bridge/Lib_CrossDomainUtils.sol";
/* Interface Imports */ /* Interface Imports */
import { iOVM_L2CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L2CrossDomainMessenger.sol"; import { iOVM_L2CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L2CrossDomainMessenger.sol";
import { iOVM_L1MessageSender } from "../../../iOVM/predeploys/iOVM_L1MessageSender.sol"; import { iOVM_L1MessageSender } from "../../../iOVM/predeploys/iOVM_L1MessageSender.sol";
import { iOVM_L2ToL1MessagePasser } from "../../../iOVM/predeploys/iOVM_L2ToL1MessagePasser.sol"; import { iOVM_L2ToL1MessagePasser } from "../../../iOVM/predeploys/iOVM_L2ToL1MessagePasser.sol";
/* Contract Imports */ /* External Imports */
import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/* External Imports */ /* External Imports */
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
...@@ -26,11 +27,29 @@ import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.s ...@@ -26,11 +27,29 @@ import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.s
*/ */
contract OVM_L2CrossDomainMessenger is contract OVM_L2CrossDomainMessenger is
iOVM_L2CrossDomainMessenger, iOVM_L2CrossDomainMessenger,
Abs_BaseCrossDomainMessenger,
Lib_AddressResolver, Lib_AddressResolver,
ReentrancyGuard ReentrancyGuard
{ {
/*************
* Constants *
*************/
// The default x-domain message sender being set to a non-zero value makes
// deployment a bit more expensive, but in exchange the refund on every call to
// `relayMessage` by the L1 and L2 messengers will be higher.
address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD;
/*************
* Variables *
*************/
mapping (bytes32 => bool) public relayedMessages;
mapping (bytes32 => bool) public successfulMessages;
mapping (bytes32 => bool) public sentMessages;
uint256 public messageNonce;
address internal xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
/*************** /***************
* Constructor * * Constructor *
***************/ ***************/
...@@ -38,18 +57,53 @@ contract OVM_L2CrossDomainMessenger is ...@@ -38,18 +57,53 @@ contract OVM_L2CrossDomainMessenger is
/** /**
* @param _libAddressManager Address of the Address Manager. * @param _libAddressManager Address of the Address Manager.
*/ */
constructor( constructor(address _libAddressManager) Lib_AddressResolver(_libAddressManager) ReentrancyGuard() {}
address _libAddressManager
)
Lib_AddressResolver(_libAddressManager)
ReentrancyGuard()
{}
/******************** /********************
* Public Functions * * Public Functions *
********************/ ********************/
function xDomainMessageSender()
public
override
view
returns (
address
)
{
require(xDomainMsgSender != DEFAULT_XDOMAIN_SENDER, "xDomainMessageSender is not set");
return xDomainMsgSender;
}
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target,
msg.sender,
_message,
messageNonce
);
messageNonce += 1;
sentMessages[keccak256(xDomainCalldata)] = true;
_sendXDomainMessage(xDomainCalldata, _gasLimit);
emit SentMessage(xDomainCalldata);
}
/** /**
* Relays a cross domain message to a contract. * Relays a cross domain message to a contract.
* @inheritdoc iOVM_L2CrossDomainMessenger * @inheritdoc iOVM_L2CrossDomainMessenger
...@@ -69,7 +123,7 @@ contract OVM_L2CrossDomainMessenger is ...@@ -69,7 +123,7 @@ contract OVM_L2CrossDomainMessenger is
"Provided message could not be verified." "Provided message could not be verified."
); );
bytes memory xDomainCalldata = _getXDomainCalldata( bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target, _target,
_sender, _sender,
_message, _message,
...@@ -150,7 +204,6 @@ contract OVM_L2CrossDomainMessenger is ...@@ -150,7 +204,6 @@ contract OVM_L2CrossDomainMessenger is
bytes memory _message, bytes memory _message,
uint256 // _gasLimit uint256 // _gasLimit
) )
override
internal internal
{ {
iOVM_L2ToL1MessagePasser(resolve("OVM_L2ToL1MessagePasser")).passMessageToL1(_message); iOVM_L2ToL1MessagePasser(resolve("OVM_L2ToL1MessagePasser")).passMessageToL1(_message);
......
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
import { iOVM_L2DepositedToken } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedToken.sol";
/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
/**
* @title Abs_L1TokenGateway
* @dev An L1 Token Gateway is a contract which stores deposited L1 funds that are in use on L2.
* It synchronizes a corresponding L2 representation of the "deposited token", informing it
* of new deposits and releasing L1 funds when there are newly finalized withdrawals.
*
* NOTE: This abstract contract gives all the core functionality of an L1 token gateway,
* but provides easy hooks in case developers need extensions in child contracts.
* In many cases, the default OVM_L1ERC20Gateway will suffice.
*
* Compiler used: solc
* Runtime target: EVM
*/
abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnabled {
/********************************
* External Contract References *
********************************/
address public l2DepositedToken;
/***************
* Constructor *
***************/
/**
* @param _l2DepositedToken iOVM_L2DepositedToken-compatible address on the chain being deposited into.
* @param _l1messenger L1 Messenger address being used for cross-chain communications.
*/
constructor(
address _l2DepositedToken,
address _l1messenger
)
OVM_CrossDomainEnabled(_l1messenger)
{
l2DepositedToken = _l2DepositedToken;
}
/********************************
* Overridable Accounting logic *
********************************/
// Default gas value which can be overridden if more complex logic runs on L2.
uint32 internal constant DEFAULT_FINALIZE_DEPOSIT_L2_GAS = 1200000;
/**
* @dev Core logic to be performed when a withdrawal is finalized on L1.
* In most cases, this will simply send locked funds to the withdrawer.
*
* param _to Address being withdrawn to.
* param _amount Amount being withdrawn.
*/
function _handleFinalizeWithdrawal(
address, // _to,
uint256 // _amount
)
internal
virtual
{
revert("Implement me in child contracts");
}
/**
* @dev Core logic to be performed when a deposit is initiated on L1.
* In most cases, this will simply send locked funds to the withdrawer.
*
* param _from Address being deposited from on L1.
* param _to Address being deposited into on L2.
* param _amount Amount being deposited.
*/
function _handleInitiateDeposit(
address, // _from,
address, // _to,
uint256 // _amount
)
internal
virtual
{
revert("Implement me in child contracts");
}
/**
* @dev Overridable getter for the L2 gas limit, in the case it may be
* dynamic, and the above public constant does not suffice.
*
*/
function getFinalizeDepositL2Gas()
public
view
virtual
returns(
uint32
)
{
return DEFAULT_FINALIZE_DEPOSIT_L2_GAS;
}
/**************
* Depositing *
**************/
/**
* @dev deposit an amount of the ERC20 to the caller's balance on L2
* @param _amount Amount of the ERC20 to deposit
*/
function deposit(
uint _amount
)
external
override
virtual
{
_initiateDeposit(msg.sender, msg.sender, _amount);
}
/**
* @dev deposit an amount of ERC20 to a recipients's balance on L2
* @param _to L2 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to deposit
*/
function depositTo(
address _to,
uint _amount
)
external
override
virtual
{
_initiateDeposit(msg.sender, _to, _amount);
}
/**
* @dev Performs the logic for deposits by informing the L2 Deposited Token
* contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)
*
* @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2
* @param _amount Amount of the ERC20 to deposit.
*/
function _initiateDeposit(
address _from,
address _to,
uint _amount
)
internal
{
// Call our deposit accounting handler implemented by child contracts.
_handleInitiateDeposit(
_from,
_to,
_amount
);
// Construct calldata for l2DepositedToken.finalizeDeposit(_to, _amount)
bytes memory data = abi.encodeWithSelector(
iOVM_L2DepositedToken.finalizeDeposit.selector,
_to,
_amount
);
// Send calldata into L2
sendCrossDomainMessage(
l2DepositedToken,
data,
getFinalizeDepositL2Gas()
);
emit DepositInitiated(_from, _to, _amount);
}
/*************************
* Cross-chain Functions *
*************************/
/**
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ERC20 token.
* This call will fail if the initialized withdrawal from L2 has not been finalized.
*
* @param _to L1 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to withdraw
*/
function finalizeWithdrawal(
address _to,
uint _amount
)
external
override
virtual
onlyFromCrossDomainAccount(l2DepositedToken)
{
// Call our withdrawal accounting handler implemented by child contracts.
_handleFinalizeWithdrawal(
_to,
_amount
);
emit WithdrawalFinalized(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L2DepositedToken } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedToken.sol";
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
/**
* @title Abs_L2DepositedToken
* @dev An L2 Deposited Token is an L2 representation of funds which were deposited from L1.
* Usually contract mints new tokens when it hears about deposits into the L1 ERC20 gateway.
* This contract also burns the tokens intended for withdrawal, informing the L1 gateway to release L1 funds.
*
* NOTE: This abstract contract gives all the core functionality of a deposited token implementation except for the
* token's internal accounting itself. This gives developers an easy way to implement children with their own token code.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomainEnabled {
/*******************
* Contract Events *
*******************/
event Initialized(iOVM_L1TokenGateway _l1TokenGateway);
/********************************
* External Contract References *
********************************/
iOVM_L1TokenGateway public l1TokenGateway;
/********************************
* Constructor & Initialization *
********************************/
/**
* @param _l2CrossDomainMessenger L1 Messenger address being used for cross-chain communications.
*/
constructor(
address _l2CrossDomainMessenger
)
OVM_CrossDomainEnabled(_l2CrossDomainMessenger)
{}
/**
* @dev Initialize this contract with the L1 token gateway address.
* The flow: 1) this contract gets deployed on L2, 2) the L1
* gateway is deployed with addr from (1), 3) L1 gateway address passed here.
*
* @param _l1TokenGateway Address of the corresponding L1 gateway deployed to the main chain
*/
function init(
iOVM_L1TokenGateway _l1TokenGateway
)
public
{
require(address(l1TokenGateway) == address(0), "Contract has already been initialized");
l1TokenGateway = _l1TokenGateway;
emit Initialized(l1TokenGateway);
}
/**********************
* Function Modifiers *
**********************/
modifier onlyInitialized() {
require(address(l1TokenGateway) != address(0), "Contract has not yet been initialized");
_;
}
/********************************
* Overridable Accounting logic *
********************************/
// Default gas value which can be overridden if more complex logic runs on L1.
uint32 internal constant DEFAULT_FINALIZE_WITHDRAWAL_L1_GAS = 100000;
/**
* @dev Core logic to be performed when a withdrawal from L2 is initialized.
* In most cases, this will simply burn the withdrawn L2 funds.
*
* param _to Address being withdrawn to
* param _amount Amount being withdrawn
*/
function _handleInitiateWithdrawal(
address, // _to,
uint // _amount
)
internal
virtual
{
revert("Accounting must be implemented by child contract.");
}
/**
* @dev Core logic to be performed when a deposit from L2 is finalized on L2.
* In most cases, this will simply _mint() to credit L2 funds to the recipient.
*
* param _to Address being deposited to on L2
* param _amount Amount which was deposited on L1
*/
function _handleFinalizeDeposit(
address, // _to
uint // _amount
)
internal
virtual
{
revert("Accounting must be implemented by child contract.");
}
/**
* @dev Overridable getter for the *L1* gas limit of settling the withdrawal, in the case it may be
* dynamic, and the above public constant does not suffice.
*/
function getFinalizeWithdrawalL1Gas()
public
view
virtual
returns(
uint32
)
{
return DEFAULT_FINALIZE_WITHDRAWAL_L1_GAS;
}
/***************
* Withdrawing *
***************/
/**
* @dev initiate a withdraw of some tokens to the caller's account on L1
* @param _amount Amount of the token to withdraw
*/
function withdraw(
uint _amount
)
external
override
virtual
onlyInitialized()
{
_initiateWithdrawal(msg.sender, _amount);
}
/**
* @dev initiate a withdraw of some token to a recipient's account on L1
* @param _to L1 adress to credit the withdrawal to
* @param _amount Amount of the token to withdraw
*/
function withdrawTo(
address _to,
uint _amount
)
external
override
virtual
onlyInitialized()
{
_initiateWithdrawal(_to, _amount);
}
/**
* @dev Performs the logic for deposits by storing the token and informing the L2 token Gateway of the deposit.
*
* @param _to Account to give the withdrawal to on L1
* @param _amount Amount of the token to withdraw
*/
function _initiateWithdrawal(
address _to,
uint _amount
)
internal
{
// Call our withdrawal accounting handler implemented by child contracts (usually a _burn)
_handleInitiateWithdrawal(_to, _amount);
// Construct calldata for l1TokenGateway.finalizeWithdrawal(_to, _amount)
bytes memory data = abi.encodeWithSelector(
iOVM_L1TokenGateway.finalizeWithdrawal.selector,
_to,
_amount
);
// Send message up to L1 gateway
sendCrossDomainMessage(
address(l1TokenGateway),
data,
getFinalizeWithdrawalL1Gas()
);
emit WithdrawalInitiated(msg.sender, _to, _amount);
}
/************************************
* Cross-chain Function: Depositing *
************************************/
/**
* @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this
* L2 token.
* This call will fail if it did not originate from a corresponding deposit in OVM_l1TokenGateway.
*
* @param _to Address to receive the withdrawal at
* @param _amount Amount of the token to withdraw
*/
function finalizeDeposit(
address _to,
uint _amount
)
external
override
virtual
onlyInitialized()
onlyFromCrossDomainAccount(address(l1TokenGateway))
{
_handleFinalizeDeposit(_to, _amount);
emit DepositFinalized(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
import { Abs_L1TokenGateway } from "./Abs_L1TokenGateway.sol";
import { iOVM_ERC20 } from "../../../iOVM/predeploys/iOVM_ERC20.sol";
/**
* @title OVM_L1ERC20Gateway
* @dev The L1 ERC20 Gateway is a contract which stores deposited L1 funds that are in use on L2.
* It synchronizes a corresponding L2 ERC20 Gateway, informing it of deposits, and listening to it
* for newly finalized withdrawals.
*
* NOTE: This contract extends Abs_L1TokenGateway, which is where we
* takes care of most of the initialization and the cross-chain logic.
* If you are looking to implement your own deposit/withdrawal contracts, you
* may also want to extend the abstract contract in a similar manner.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1ERC20Gateway is Abs_L1TokenGateway {
/********************************
* External Contract References *
********************************/
iOVM_ERC20 public l1ERC20;
/***************
* Constructor *
***************/
/**
* @param _l1ERC20 L1 ERC20 address this contract stores deposits for
* @param _l2DepositedERC20 L2 Gateway address on the chain being deposited into
*/
constructor(
iOVM_ERC20 _l1ERC20,
address _l2DepositedERC20,
address _l1messenger
)
Abs_L1TokenGateway(
_l2DepositedERC20,
_l1messenger
)
{
l1ERC20 = _l1ERC20;
}
/**************
* Accounting *
**************/
/**
* @dev When a deposit is initiated on L1, the L1 Gateway
* transfers the funds to itself for future withdrawals
*
* @param _from L1 address ETH is being deposited from
* param _to L2 address that the ETH is being deposited to
* @param _amount Amount of ERC20 to send
*/
function _handleInitiateDeposit(
address _from,
address, // _to,
uint256 _amount
)
internal
override
{
// Hold on to the newly deposited funds
l1ERC20.transferFrom(
_from,
address(this),
_amount
);
}
/**
* @dev When a withdrawal is finalized on L1, the L1 Gateway
* transfers the funds to the withdrawer
*
* @param _to L1 address that the ERC20 is being withdrawn to
* @param _amount Amount of ERC20 to send
*/
function _handleFinalizeWithdrawal(
address _to,
uint _amount
)
internal
override
{
// Transfer withdrawn funds out to withdrawer
l1ERC20.transfer(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1ETHGateway } from "../../../iOVM/bridge/tokens/iOVM_L1ETHGateway.sol";
import { iOVM_L2DepositedToken } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedToken.sol";
/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManager.sol";
/**
* @title OVM_L1ETHGateway
* @dev The L1 ETH Gateway is a contract which stores deposited ETH that is in use on L2.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_AddressResolver {
/********************
* Public Constants *
********************/
uint32 public constant override getFinalizeDepositL2Gas = 1200000;
/********************************
* External Contract References *
********************************/
address public ovmEth;
/***************
* Constructor *
***************/
// This contract lives behind a proxy, so the constructor parameters will go unused.
constructor()
OVM_CrossDomainEnabled(address(0))
Lib_AddressResolver(address(0))
public
{}
/******************
* Initialization *
******************/
/**
* @param _libAddressManager Address manager for this OE deployment
* @param _ovmEth L2 OVM_ETH implementation of iOVM_DepositedToken
*/
function initialize(
address _libAddressManager,
address _ovmEth
)
public
{
require(libAddressManager == Lib_AddressManager(0), "Contract has already been initialized.");
libAddressManager = Lib_AddressManager(_libAddressManager);
ovmEth = _ovmEth;
messenger = resolve("Proxy__OVM_L1CrossDomainMessenger");
}
/**************
* Depositing *
**************/
receive()
external
payable
{
_initiateDeposit(msg.sender, msg.sender);
}
/**
* @dev deposit an amount of the ETH to the caller's balance on L2
*/
function deposit()
external
override
payable
{
_initiateDeposit(msg.sender, msg.sender);
}
/**
* @dev deposit an amount of ETH to a recipients's balance on L2
* @param _to L2 address to credit the withdrawal to
*/
function depositTo(
address _to
)
external
override
payable
{
_initiateDeposit(msg.sender, _to);
}
/**
* @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of the deposit.
*
* @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2
*/
function _initiateDeposit(
address _from,
address _to
)
internal
{
// Construct calldata for l2ETHGateway.finalizeDeposit(_to, _amount)
bytes memory data =
abi.encodeWithSelector(
iOVM_L2DepositedToken.finalizeDeposit.selector,
_to,
msg.value
);
// Send calldata into L2
sendCrossDomainMessage(
ovmEth,
data,
getFinalizeDepositL2Gas
);
emit DepositInitiated(_from, _to, msg.value);
}
/*************************
* Cross-chain Functions *
*************************/
/**
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ETH token.
* Since only the xDomainMessenger can call this function, it will never be called before the withdrawal is finalized.
*
* @param _to L1 address to credit the withdrawal to
* @param _amount Amount of the ETH to withdraw
*/
function finalizeWithdrawal(
address _to,
uint256 _amount
)
external
override
onlyFromCrossDomainAccount(ovmEth)
{
_safeTransferETH(_to, _amount);
emit WithdrawalFinalized(_to, _amount);
}
/**********************************
* Internal Functions: Accounting *
**********************************/
/**
* @dev Internal accounting function for moving around L1 ETH.
*
* @param _to L1 address to transfer ETH to
* @param _value Amount of ETH to send to
*/
function _safeTransferETH(
address _to,
uint256 _value
)
internal
{
(bool success, ) = _to.call{value: _value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
/*****************************
* Temporary - Migrating ETH *
*****************************/
/**
* @dev Migrates entire ETH balance to another gateway
* @param _to Gateway Proxy address to migrate ETH to
*/
function migrateEth(address payable _to) external {
address owner = Lib_AddressManager(libAddressManager).owner();
require(msg.sender == owner, "Only the owner can migrate ETH");
uint256 balance = address(this).balance;
OVM_L1ETHGateway(_to).donateETH{value:balance}();
}
/**
* @dev Adds ETH balance to the account. This is meant to allow for ETH
* to be migrated from an old gateway to a new gateway
*/
function donateETH() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
/* Contract Imports */
import { UniswapV2ERC20 } from "../../../libraries/standards/UniswapV2ERC20.sol";
/* Library Imports */
import { Abs_L2DepositedToken } from "./Abs_L2DepositedToken.sol";
/**
* @title OVM_L2DepositedERC20
* @dev The L2 Deposited ERC20 is an ERC20 implementation which represents L1 assets deposited into L2.
* This contract mints new tokens when it hears about deposits into the L1 ERC20 gateway.
* This contract also burns the tokens intended for withdrawal, informing the L1 gateway to release L1 funds.
*
* NOTE: This contract implements the Abs_L2DepositedToken contract using Uniswap's ERC20 as the implementation.
* Alternative implementations can be used in this similar manner.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 {
/***************
* Constructor *
***************/
/**
* @param _l2CrossDomainMessenger Cross-domain messenger used by this contract.
* @param _name ERC20 name
* @param _symbol ERC20 symbol
*/
constructor(
address _l2CrossDomainMessenger,
string memory _name,
string memory _symbol
)
Abs_L2DepositedToken(_l2CrossDomainMessenger)
UniswapV2ERC20(_name, _symbol)
{}
// When a withdrawal is initiated, we burn the withdrawer's funds to prevent subsequent L2 usage.
function _handleInitiateWithdrawal(
address, // _to,
uint _amount
)
internal
override
{
_burn(msg.sender, _amount);
}
// When a deposit is finalized, we credit the account on L2 with the same amount of tokens.
function _handleFinalizeDeposit(
address _to,
uint _amount
)
internal
override
{
_mint(_to, _amount);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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