Commit 1341ddb9 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge branch 'develop' into debug/devnet-ci

parents ab7f5402 9d435aec
---
'@eth-optimism/foundry': minor
---
Initial release, pin to b7b1ec471bdd38221773e1a569dc4f20297bd7db
---
'@eth-optimism/contracts-bedrock': patch
---
Port RLPWriter tests
---
'@eth-optimism/ci-builder': patch
---
Use ethereumoptimism/foundry:latest
......@@ -2,4 +2,4 @@
'@eth-optimism/contracts-bedrock': patch
---
Move encoding and hashing into Encoding and Hashing libraries
Cleans up natspec in MerkleTrie and SecureMerkleTrie contracts
---
'@eth-optimism/contracts-bedrock': patch
---
Fix solc warnings in ProxyAdmin
---
'@eth-optimism/contracts-bedrock': patch
---
Remove unnecessary DefaultValues library
---
'@eth-optimism/contracts-bedrock': patch
---
Fixes a bug that caused L2 timestamps to be computed incorrectly
---
'@eth-optimism/contracts-bedrock': patch
---
Standardizes comments, errors, and events for contracts in the /universal package
---
'@eth-optimism/contracts-bedrock': patch
---
Bump typechain to 8.1.0
---
'@eth-optimism/contracts-bedrock': patch
---
Clean up comments and errors for legacy contracts
---
'@eth-optimism/contracts-bedrock': patch
---
Cleaned up enums, should be CapitalCase enums and UPPER_CASE values
---
'@eth-optimism/contracts-bedrock': patch
---
Update to new L2 tx hash style for deposits
---
'@eth-optimism/contracts-bedrock': patch
---
Standardizes initialization logic for L1 contracts
---
'@eth-optimism/contracts-bedrock': patch
---
Move contracts written by external parties into a vendor folder
......@@ -2,4 +2,4 @@
'@eth-optimism/contracts-bedrock': patch
---
Use external version of ExcessivelySafeCall
Minor cleanups to initialization and semver for L1 contracts
---
'@eth-optimism/contracts-bedrock': patch
---
Reduce the number of compiler warnings
---
'@eth-optimism/contracts-bedrock': patch
---
Remove storage slot buffer in xdomain messengers
---
'@eth-optimism/contracts-bedrock': patch
---
Cleans up initialization logic everywhere
---
'@eth-optimism/contracts-bedrock': patch
---
Rename OptimismMintableTokenFactory to OptimismMintableERC20Factory
---
'@eth-optimism/foundry': patch
---
Use alpine:3.14
---
'@eth-optimism/contracts-bedrock': patch
---
Fix initialization logic
---
'@eth-optimism/contracts-bedrock': patch
---
Clean up the PredeployAddresses library
---
'@eth-optimism/hardhat-deploy-config': patch
---
Use lazyObject
---
'@eth-optimism/contracts-bedrock': patch
---
Tests for RLPReader
---
'@eth-optimism/indexer': patch
---
Fix contract bindings
---
'@eth-optimism/contracts-bedrock': patch
'@eth-optimism/contracts-periphery': patch
---
Bump forge-std to 62caef29b0f87a2c6aaaf634b2ca4c09b6867c92
---
'@eth-optimism/contracts-bedrock': patch
---
Add semver to L2 contracts
---
'@eth-optimism/contracts-bedrock': patch
---
Resolve compiler warnings in Proxy.sol
---
'@eth-optimism/contracts-periphery': minor
---
Fixes a bug in the OptimismMintableERC721. Requires an interface change, so this is a minor and not patch.
---
'@eth-optimism/l2geth': patch
---
fix NPE in debug_standardTraceBlockToFile
---
'@eth-optimism/contracts-bedrock': patch
'@eth-optimism/core-utils': patch
---
Move the `DepositTx` type to `core-utils`. This way it can be more easily used across projects
---
'@eth-optimism/ci-builder': minor
---
Update foundry in ci builder
---
'@eth-optimism/contracts-bedrock': minor
---
Remove Lib* and OVM* prefixes from all contracts
---
'@eth-optimism/contracts-bedrock': patch
---
Remove "not implemented" errors in virtual functions
---
'@eth-optimism/contracts-bedrock': patch
---
Update typechain pipeline
---
'@eth-optimism/contracts-bedrock': patch
'@eth-optimism/contracts-periphery': patch
'@eth-optimism/fault-detector': patch
'@eth-optimism/hardhat-deploy-config': patch
---
Update dev deps
......@@ -127,7 +127,9 @@ jobs:
working_directory: packages/contracts-bedrock
- run:
name: slither
command: yarn slither || exit 0
command: |
slither --version
yarn slither || exit 0
working_directory: packages/contracts-bedrock
- run:
name: test
......@@ -137,12 +139,30 @@ jobs:
name: gas snapshot
command: |
forge --version
forge snapshot --check
forge snapshot --check || exit 0
working_directory: packages/contracts-bedrock
- run:
name: storage snapshot
command: yarn storage-snapshot && git diff --exit-code .storage-layout
working_directory: packages/contracts-bedrock
op-bindings-build:
docker:
- image: ethereumoptimism/ci-builder:latest
resource_class: medium
steps:
- restore_cache:
keys:
- v2-cache-yarn-build-{{ .Revision }}
- checkout
- run:
name: Check if we should run
command: |
shopt -s inherit_errexit
CHANGED=$(check-changed "(contracts-bedrock|op-bindings)")
if [[ "$CHANGED" = "FALSE" ]]; then
circleci step halt
fi
- run:
name: check go bindings
command: make && git diff --exit-code
......@@ -399,6 +419,9 @@ jobs:
environment:
DOCKER_BUILDKIT: 1
steps:
- run:
name: temporary pause
command: circleci step halt
- checkout
- run:
name: Check if we should run
......@@ -545,6 +568,9 @@ workflows:
- contracts-bedrock-tests:
requires:
- yarn-monorepo
- op-bindings-build:
requires:
- yarn-monorepo
- js-lint-test:
name: contracts-governance-tests
package_name: contracts-governance
......
......@@ -232,7 +232,7 @@ jobs:
- name: Publish ci-builder
uses: docker/build-push-action@v2
with:
context: .
context: ./ops/docker/ci-builder
file: ./ops/docker/ci-builder/Dockerfile
push: true
tags: ethereumoptimism/ci-builder:${{ needs.release.outputs.ci-builder }},ethereumoptimism/ci-builder:latest
......
# @eth-optimism/indexer
## 0.1.3
### Patch Changes
- f30a5d39: Fix contract bindings
## 0.1.2
### Patch Changes
......
{
"name": "@eth-optimism/indexer",
"version": "0.1.2",
"version": "0.1.3",
"private": true,
"license": "MIT"
}
......@@ -29,10 +29,10 @@
},
"devDependencies": {
"@babel/eslint-parser": "^7.5.4",
"@eth-optimism/contracts": "^0.5.29",
"@eth-optimism/contracts-periphery": "^0.1.3",
"@eth-optimism/core-utils": "0.9.0",
"@eth-optimism/sdk": "1.2.0",
"@eth-optimism/contracts": "^0.5.30",
"@eth-optimism/contracts-periphery": "^0.2.0",
"@eth-optimism/core-utils": "0.9.1",
"@eth-optimism/sdk": "1.3.0",
"@ethersproject/abstract-provider": "^5.6.1",
"@ethersproject/providers": "^5.6.8",
"@ethersproject/transactions": "^5.6.2",
......
......@@ -4,8 +4,8 @@ import { ethers } from 'hardhat'
import { getChainId } from '@eth-optimism/core-utils'
import { predeploys } from '@eth-optimism/contracts'
import Artifact__TestERC721 from '@eth-optimism/contracts-periphery/artifacts/contracts/testing/helpers/TestERC721.sol/TestERC721.json'
import Artifact__L1ERC721Bridge from '@eth-optimism/contracts-periphery/artifacts/contracts/L1/messaging/L1ERC721Bridge.sol/L1ERC721Bridge.json'
import Artifact__L2ERC721Bridge from '@eth-optimism/contracts-periphery/artifacts/contracts/L2/messaging/L2ERC721Bridge.sol/L2ERC721Bridge.json'
import Artifact__L1ERC721Bridge from '@eth-optimism/contracts-periphery/artifacts/contracts/L1/L1ERC721Bridge.sol/L1ERC721Bridge.json'
import Artifact__L2ERC721Bridge from '@eth-optimism/contracts-periphery/artifacts/contracts/L2/L2ERC721Bridge.sol/L2ERC721Bridge.json'
import Artifact__OptimismMintableERC721Factory from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/op-erc721/OptimismMintableERC721Factory.sol/OptimismMintableERC721Factory.json'
import Artifact__OptimismMintableERC721 from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/op-erc721/OptimismMintableERC721.sol/OptimismMintableERC721.json'
......
# Changelog
## 0.5.23
### Patch Changes
- c3363225: fix NPE in debug_standardTraceBlockToFile
## 0.5.22
### Patch Changes
......
{
"name": "@eth-optimism/l2geth",
"version": "0.5.22",
"version": "0.5.23",
"private": true,
"devDependencies": {}
}
......@@ -2,6 +2,8 @@ FROM golang:1.18.0-alpine3.15 as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
# build op-batcher with local monorepo go modules
COPY ./op-batcher/docker.go.work /app/go.work
COPY ./op-bindings /app/op-bindings
COPY ./op-node /app/op-node
COPY ./op-proposer /app/op-proposer
......
go 1.18
use (
./op-batcher
./op-bindings
./op-node
./op-proposer
)
......@@ -3,8 +3,8 @@ module github.com/ethereum-optimism/optimism/op-batcher
go 1.18
require (
github.com/ethereum-optimism/optimism/op-node v0.0.0
github.com/ethereum-optimism/optimism/op-proposer v0.0.0
github.com/ethereum-optimism/optimism/op-node v0.3.0
github.com/ethereum-optimism/optimism/op-proposer v0.3.0
github.com/ethereum/go-ethereum v1.10.17
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
github.com/urfave/cli v1.22.5
......@@ -21,7 +21,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.0.0 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.3.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
......@@ -54,10 +54,4 @@ require (
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
replace (
github.com/ethereum-optimism/optimism/op-bindings v0.0.0 => ../op-bindings
github.com/ethereum-optimism/optimism/op-node v0.0.0 => ../op-node
github.com/ethereum-optimism/optimism/op-proposer v0.0.0 => ../op-proposer
)
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d
......@@ -161,6 +161,12 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/optimism/op-bindings v0.0.0-20220614233543-0d8fa52afca2/go.mod h1:e9mMYiVsdJf9BI//FdaA77BwNNgNMR043JtB7CPXNxY=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0 h1:d2Mwb8FzR2zuhW0sS5xFKWz/6VFPTEIE+XINqZj0Rv4=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0/go.mod h1:CrvUVIISKcyJ7o27ub/HY4Kq9wEJQxrGmWthTqxPSGo=
github.com/ethereum-optimism/optimism/op-node v0.3.0 h1:jep/cbIbP7fjBSAR48yk5NJVEoGYvoNlYI00KpBI6Mw=
github.com/ethereum-optimism/optimism/op-node v0.3.0/go.mod h1:iF9AhYjr8jNeoCDNP/Vs/ywQ2USZU5L66AxZbSAUi0E=
github.com/ethereum-optimism/optimism/op-proposer v0.3.0 h1:K1ipZt3TLD0BJi7tKOmx8tCLXj9i4f4baBIhbPmUxk4=
github.com/ethereum-optimism/optimism/op-proposer v0.3.0/go.mod h1:GcQ9VCWz2zEVexecq5IYo/2eadK/y7IBOEfx4YV1QJk=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d h1:AYFFbxrz7kLyFbvNHGhUPZQT8KnN1PPjCj4oAcgaVCk=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d/go.mod h1:8AfU1epKggKxDt9wr7rH5KmCeiT3yT0sEvroru1mO6Q=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
......
This diff is collapsed.
......@@ -3,10 +3,10 @@ module github.com/ethereum-optimism/optimism/op-e2e
go 1.18
require (
github.com/ethereum-optimism/optimism/op-batcher v0.0.0
github.com/ethereum-optimism/optimism/op-bindings v0.0.0
github.com/ethereum-optimism/optimism/op-node v0.0.0
github.com/ethereum-optimism/optimism/op-proposer v0.0.0
github.com/ethereum-optimism/optimism/op-batcher v0.3.0
github.com/ethereum-optimism/optimism/op-bindings v0.3.0
github.com/ethereum-optimism/optimism/op-node v0.3.0
github.com/ethereum-optimism/optimism/op-proposer v0.3.0
github.com/ethereum/go-ethereum v1.10.17
github.com/libp2p/go-libp2p v0.18.1
github.com/libp2p/go-libp2p-core v0.15.0
......@@ -160,11 +160,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace (
github.com/ethereum-optimism/optimism/op-batcher v0.0.0 => ../op-batcher
github.com/ethereum-optimism/optimism/op-bindings v0.0.0 => ../op-bindings
github.com/ethereum-optimism/optimism/op-node v0.0.0 => ../op-node
github.com/ethereum-optimism/optimism/op-proposer v0.0.0 => ../op-proposer
)
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d
......@@ -249,7 +249,15 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/optimism/op-batcher v0.3.0 h1:rNEUyu7ZTUZc1W1lM9lO71w/HZ9pjQtnNwR/e1I0XyQ=
github.com/ethereum-optimism/optimism/op-batcher v0.3.0/go.mod h1:1imFCpIIA70WVZX7gp4dH/ZSnfqcG/WNvVp8Xm2s2VU=
github.com/ethereum-optimism/optimism/op-bindings v0.0.0-20220614233543-0d8fa52afca2/go.mod h1:e9mMYiVsdJf9BI//FdaA77BwNNgNMR043JtB7CPXNxY=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0 h1:d2Mwb8FzR2zuhW0sS5xFKWz/6VFPTEIE+XINqZj0Rv4=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0/go.mod h1:CrvUVIISKcyJ7o27ub/HY4Kq9wEJQxrGmWthTqxPSGo=
github.com/ethereum-optimism/optimism/op-node v0.3.0 h1:jep/cbIbP7fjBSAR48yk5NJVEoGYvoNlYI00KpBI6Mw=
github.com/ethereum-optimism/optimism/op-node v0.3.0/go.mod h1:iF9AhYjr8jNeoCDNP/Vs/ywQ2USZU5L66AxZbSAUi0E=
github.com/ethereum-optimism/optimism/op-proposer v0.3.0 h1:K1ipZt3TLD0BJi7tKOmx8tCLXj9i4f4baBIhbPmUxk4=
github.com/ethereum-optimism/optimism/op-proposer v0.3.0/go.mod h1:GcQ9VCWz2zEVexecq5IYo/2eadK/y7IBOEfx4YV1QJk=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d h1:AYFFbxrz7kLyFbvNHGhUPZQT8KnN1PPjCj4oAcgaVCk=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d/go.mod h1:8AfU1epKggKxDt9wr7rH5KmCeiT3yT0sEvroru1mO6Q=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
......
......@@ -2,15 +2,12 @@ FROM golang:1.18.0-alpine3.15 as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
COPY ./op-node/go.mod /app/op-node/go.mod
COPY ./op-node/go.sum /app/op-node/go.sum
# build op-node with local monorepo go modules
COPY ./op-node/docker.go.work /app/go.work
COPY ./op-bindings /app/op-bindings
COPY ./op-node /app/op-node
WORKDIR /app/op-node
RUN go mod download -x
COPY ./op-node /app/op-node
RUN make op-node
......
go 1.18
use (
./op-bindings
./op-node
)
......@@ -3,7 +3,7 @@ module github.com/ethereum-optimism/optimism/op-node
go 1.18
require (
github.com/ethereum-optimism/optimism/op-bindings v0.0.0
github.com/ethereum-optimism/optimism/op-bindings v0.3.0
github.com/ethereum/go-ethereum v1.10.17
github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.5.8
......@@ -173,8 +173,6 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/ethereum-optimism/optimism/op-bindings v0.0.0 => ../op-bindings
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d
// For local debugging:
......
......@@ -232,6 +232,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/optimism/op-bindings v0.0.0-20220614233543-0d8fa52afca2/go.mod h1:e9mMYiVsdJf9BI//FdaA77BwNNgNMR043JtB7CPXNxY=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0 h1:d2Mwb8FzR2zuhW0sS5xFKWz/6VFPTEIE+XINqZj0Rv4=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0/go.mod h1:CrvUVIISKcyJ7o27ub/HY4Kq9wEJQxrGmWthTqxPSGo=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d h1:AYFFbxrz7kLyFbvNHGhUPZQT8KnN1PPjCj4oAcgaVCk=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d/go.mod h1:8AfU1epKggKxDt9wr7rH5KmCeiT3yT0sEvroru1mO6Q=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
......
package derive
import (
"context"
"fmt"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
// L1ReceiptsFetcher fetches L1 header info and receipts for the payload attributes derivation (the info tx and deposits)
type L1ReceiptsFetcher interface {
InfoByHash(ctx context.Context, hash common.Hash) (eth.L1Info, error)
Fetch(ctx context.Context, blockHash common.Hash) (eth.L1Info, types.Transactions, types.Receipts, error)
}
// PreparePayloadAttributes prepares a PayloadAttributes template that is ready to build a L2 block with deposits only, on top of the given l2Parent, with the given epoch as L1 origin.
// The template defaults to NoTxPool=true, and no sequencer transactions: the caller has to modify the template to add transactions,
// by setting NoTxPool=false as sequencer, or by appending batch transactions as verifier.
// The severity of the error is returned; a crit=false error means there was a temporary issue, like a failed RPC or time-out.
// A crit=true error means the input arguments are inconsistent or invalid.
func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1ReceiptsFetcher, l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, crit bool, err error) {
var l1Info eth.L1Info
var depositTxs []hexutil.Bytes
var seqNumber uint64
// If the L1 origin changed this block, then we are in the first block of the epoch. In this
// case we need to fetch all transaction receipts from the L1 origin block so we can scan for
// user deposits.
if l2Parent.L1Origin.Number != epoch.Number {
info, _, receipts, err := dl.Fetch(ctx, epoch.Hash)
if err != nil {
return nil, false, fmt.Errorf("failed to fetch L1 block info and receipts: %w", err)
}
if l2Parent.L1Origin.Hash != info.ParentHash() {
return nil, true, fmt.Errorf("cannot create new block with L1 origin %s (parent %s) on top of L1 origin %s", epoch, info.ParentHash(), l2Parent.L1Origin)
}
deposits, err := DeriveDeposits(receipts, cfg.DepositContractAddress)
if err != nil {
return nil, true, fmt.Errorf("failed to derive some deposits: %w", err)
}
l1Info = info
depositTxs = deposits
seqNumber = 0
} else {
if l2Parent.L1Origin.Hash != epoch.Hash {
return nil, true, fmt.Errorf("cannot create new block with L1 origin %s in conflict with L1 origin %s", epoch, l2Parent.L1Origin)
}
info, err := dl.InfoByHash(ctx, epoch.Hash)
if err != nil {
return nil, false, fmt.Errorf("failed to fetch L1 block info: %w", err)
}
l1Info = info
depositTxs = nil
seqNumber = l2Parent.SequenceNumber + 1
}
l1InfoTx, err := L1InfoDepositBytes(seqNumber, l1Info)
if err != nil {
return nil, true, fmt.Errorf("failed to create l1InfoTx: %w", err)
}
txs := make([]hexutil.Bytes, 0, 1+len(depositTxs))
txs = append(txs, l1InfoTx)
txs = append(txs, depositTxs...)
return &eth.PayloadAttributes{
Timestamp: hexutil.Uint64(l2Parent.Time + cfg.BlockTime),
PrevRandao: eth.Bytes32(l1Info.MixDigest()),
SuggestedFeeRecipient: cfg.FeeRecipientAddress,
Transactions: txs,
NoTxPool: true,
}, false, nil
}
......@@ -8,16 +8,9 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
type L1ReceiptsFetcher interface {
Fetch(ctx context.Context, blockHash common.Hash) (eth.L1Info, types.Transactions, types.Receipts, error)
}
type AttributesQueueOutput interface {
AddSafeAttributes(attributes *eth.PayloadAttributes)
SafeL2Head() eth.L2BlockRef
......@@ -55,82 +48,43 @@ func (aq *AttributesQueue) Step(ctx context.Context, outer Progress) error {
if changed, err := aq.progress.Update(outer); err != nil || changed {
return err
}
attr, err := aq.DeriveL2Inputs(ctx, aq.next.SafeL2Head())
if err != nil {
return err
}
aq.next.AddSafeAttributes(attr)
return nil
}
func (aq *AttributesQueue) ResetStep(ctx context.Context, l1Fetcher L1Fetcher) error {
aq.batches = aq.batches[:0]
aq.progress = aq.next.Progress()
return io.EOF
}
func (aq *AttributesQueue) SafeL2Head() eth.L2BlockRef {
return aq.next.SafeL2Head()
}
// DeriveL2Inputs turns the next L2 batch into an Payload Attributes that builds off of the safe head
func (aq *AttributesQueue) DeriveL2Inputs(ctx context.Context, l2SafeHead eth.L2BlockRef) (*eth.PayloadAttributes, error) {
if len(aq.batches) == 0 {
return nil, io.EOF
return io.EOF
}
batch := aq.batches[0]
seqNumber := l2SafeHead.SequenceNumber + 1
// Check if we need to advance an epoch & update local state
if l2SafeHead.L1Origin != batch.Epoch() {
aq.log.Info("advancing epoch in the attributes queue", "l2SafeHead", l2SafeHead, "l2SafeHead_origin", l2SafeHead.L1Origin, "batch_timestamp", batch.Timestamp, "batch_epoch", batch.Epoch())
seqNumber = 0
}
fetchCtx, cancel := context.WithTimeout(ctx, 20*time.Second)
defer cancel()
l1Info, _, receipts, err := aq.dl.Fetch(fetchCtx, batch.EpochHash)
attrs, crit, err := PreparePayloadAttributes(fetchCtx, aq.config, aq.dl, aq.next.SafeL2Head(), batch.Epoch())
if err != nil {
aq.log.Error("failed to fetch L1 block info", "l1Origin", batch.Epoch(), "err", err)
return nil, err
}
// Fill in deposits if we are the first block of the epoch
var deposits []hexutil.Bytes
if seqNumber == 0 {
var errs []error
deposits, errs = DeriveDeposits(receipts, aq.config.DepositContractAddress)
for _, err := range errs {
aq.log.Error("Failed to derive a deposit", "l1Origin", batch.Epoch(), "err", err)
}
if len(errs) != 0 {
// TODO: Multierror here
return nil, fmt.Errorf("failed to derive some deposits: %v", errs)
if crit {
return fmt.Errorf("failed to prepare payload attributes for batch: %v", err)
} else {
aq.log.Error("temporarily failing to prepare payload attributes for batch", "err", err)
return nil
}
}
var txns []eth.Data
l1InfoTx, err := L1InfoDepositBytes(seqNumber, l1Info)
if err != nil {
return nil, fmt.Errorf("failed to create l1InfoTx: %w", err)
}
txns = append(txns, l1InfoTx)
if seqNumber == 0 {
txns = append(txns, deposits...)
}
txns = append(txns, batch.Transactions...)
attrs := &eth.PayloadAttributes{
Timestamp: hexutil.Uint64(batch.Timestamp),
PrevRandao: eth.Bytes32(l1Info.MixDigest()),
SuggestedFeeRecipient: aq.config.FeeRecipientAddress,
Transactions: txns,
// we are verifying, not sequencing, we've got all transactions and do not pull from the tx-pool
// (that would make the block derivation non-deterministic)
NoTxPool: true,
}
aq.log.Info("generated attributes in payload queue", "tx_count", len(txns), "timestamp", batch.Timestamp)
attrs.NoTxPool = true
attrs.Transactions = append(attrs.Transactions, batch.Transactions...)
aq.log.Info("generated attributes in payload queue", "txs", len(attrs.Transactions), "timestamp", batch.Timestamp)
// Slice off the batch once we are guaranteed to succeed
aq.batches = aq.batches[1:]
return attrs, nil
aq.next.AddSafeAttributes(attrs)
return nil
}
func (aq *AttributesQueue) ResetStep(ctx context.Context, l1Fetcher L1Fetcher) error {
aq.batches = aq.batches[:0]
aq.progress = aq.next.Progress()
return io.EOF
}
func (aq *AttributesQueue) SafeL2Head() eth.L2BlockRef {
return aq.next.SafeL2Head()
}
package derive
import (
"context"
"io"
"math/big"
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
type MockAttributesQueueOutput struct {
MockOriginStage
}
func (m *MockAttributesQueueOutput) AddSafeAttributes(attributes *eth.PayloadAttributes) {
m.Mock.MethodCalled("AddSafeAttributes", attributes)
}
func (m *MockAttributesQueueOutput) ExpectAddSafeAttributes(attributes *eth.PayloadAttributes) {
m.Mock.On("AddSafeAttributes", attributes).Once().Return()
}
func (m *MockAttributesQueueOutput) SafeL2Head() eth.L2BlockRef {
return m.Mock.MethodCalled("SafeL2Head").Get(0).(eth.L2BlockRef)
}
func (m *MockAttributesQueueOutput) ExpectSafeL2Head(head eth.L2BlockRef) {
m.Mock.On("SafeL2Head").Once().Return(head)
}
var _ AttributesQueueOutput = (*MockAttributesQueueOutput)(nil)
func TestAttributesQueue_Step(t *testing.T) {
// test config, only init the necessary fields
cfg := &rollup.Config{
BlockTime: 2,
L1ChainID: big.NewInt(101),
L2ChainID: big.NewInt(102),
FeeRecipientAddress: common.Address{0xaa},
DepositContractAddress: common.Address{0xbb},
}
rng := rand.New(rand.NewSource(1234))
l1Info := testutils.RandomL1Info(rng)
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l1Fetcher.ExpectInfoByHash(l1Info.InfoHash, l1Info, nil)
out := &MockAttributesQueueOutput{}
out.progress = Progress{
Origin: l1Info.BlockRef(),
Closed: false,
}
defer out.AssertExpectations(t)
safeHead := testutils.RandomL2BlockRef(rng)
safeHead.L1Origin = l1Info.ID()
out.ExpectSafeL2Head(safeHead)
batch := &BatchData{BatchV1{
EpochNum: rollup.Epoch(l1Info.InfoNum),
EpochHash: l1Info.InfoHash,
Timestamp: 12345,
Transactions: []eth.Data{eth.Data("foobar"), eth.Data("example")},
}}
l1InfoTx, err := L1InfoDepositBytes(safeHead.SequenceNumber+1, l1Info)
require.NoError(t, err)
attrs := eth.PayloadAttributes{
Timestamp: eth.Uint64Quantity(safeHead.Time + cfg.BlockTime),
PrevRandao: eth.Bytes32(l1Info.InfoMixDigest),
SuggestedFeeRecipient: cfg.FeeRecipientAddress,
Transactions: []eth.Data{l1InfoTx, eth.Data("foobar"), eth.Data("example")},
NoTxPool: true,
}
out.ExpectAddSafeAttributes(&attrs)
aq := NewAttributesQueue(testlog.Logger(t, log.LvlError), cfg, l1Fetcher, out)
require.NoError(t, RepeatResetStep(t, aq.ResetStep, l1Fetcher, 1))
aq.AddBatch(batch)
require.NoError(t, aq.Step(context.Background(), out.progress), "adding batch to next stage, no EOF yet")
require.Equal(t, io.EOF, aq.Step(context.Background(), out.progress), "done with batches")
}
package derive
import (
"context"
"errors"
"fmt"
"math/big"
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)
func TestPreparePayloadAttributes(t *testing.T) {
// test config, only init the necessary fields
cfg := &rollup.Config{
BlockTime: 2,
L1ChainID: big.NewInt(101),
L2ChainID: big.NewInt(102),
FeeRecipientAddress: common.Address{0xaa},
DepositContractAddress: common.Address{0xbb},
}
t.Run("inconsistent next height origin", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
l1Info := testutils.RandomL1Info(rng)
l1Info.InfoNum = l2Parent.L1Origin.Number + 1
epoch := l1Info.ID()
l1Fetcher.ExpectFetch(epoch.Hash, l1Info, nil, nil, nil)
_, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.NotNil(t, err, "inconsistent L1 origin error expected")
require.True(t, crit, "inconsistent L1 origin transition must be handled like a critical error with reorg")
})
t.Run("inconsistent equal height origin", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
l1Info := testutils.RandomL1Info(rng)
l1Info.InfoNum = l2Parent.L1Origin.Number
epoch := l1Info.ID()
_, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.NotNil(t, err, "inconsistent L1 origin error expected")
require.True(t, crit, "inconsistent L1 origin transition must be handled like a critical error with reorg")
})
t.Run("rpc fail Fetch", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
epoch := l2Parent.L1Origin
epoch.Number += 1
mockRPCErr := errors.New("mock rpc error")
l1Fetcher.ExpectFetch(epoch.Hash, nil, nil, nil, mockRPCErr)
_, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.ErrorIs(t, err, mockRPCErr, "mock rpc error expected")
require.False(t, crit, "rpc errors should not be critical, it is not necessary to reorg")
})
t.Run("rpc fail InfoByHash", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
epoch := l2Parent.L1Origin
mockRPCErr := errors.New("mock rpc error")
l1Fetcher.ExpectInfoByHash(epoch.Hash, nil, mockRPCErr)
_, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.ErrorIs(t, err, mockRPCErr, "mock rpc error expected")
require.False(t, crit, "rpc errors should not be critical, it is not necessary to reorg")
})
t.Run("next origin without deposits", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
l1Info := testutils.RandomL1Info(rng)
l1Info.InfoParentHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number + 1
epoch := l1Info.ID()
l1InfoTx, err := L1InfoDepositBytes(0, l1Info)
require.NoError(t, err)
l1Fetcher.ExpectFetch(epoch.Hash, l1Info, nil, nil, nil)
attrs, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.NoError(t, err)
require.False(t, crit)
require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao)
require.Equal(t, cfg.FeeRecipientAddress, attrs.SuggestedFeeRecipient)
require.Equal(t, 1, len(attrs.Transactions))
require.Equal(t, l1InfoTx, []byte(attrs.Transactions[0]))
require.True(t, attrs.NoTxPool)
})
t.Run("next origin with deposits", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
l1Info := testutils.RandomL1Info(rng)
l1Info.InfoParentHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number + 1
receipts, depositTxs := makeReceipts(rng, l1Info.InfoHash, cfg.DepositContractAddress, []receiptData{
{goodReceipt: true, DepositLogs: []bool{true, false}},
{goodReceipt: true, DepositLogs: []bool{true}},
{goodReceipt: false, DepositLogs: []bool{true}},
{goodReceipt: false, DepositLogs: []bool{false}},
})
usedDepositTxs, err := encodeDeposits(depositTxs)
require.NoError(t, err)
epoch := l1Info.ID()
l1InfoTx, err := L1InfoDepositBytes(0, l1Info)
require.NoError(t, err)
l2Txs := append(append(make([]eth.Data, 0), l1InfoTx), usedDepositTxs...)
// txs are ignored, API is a bit bloated to previous approach. Only l1Info and receipts matter.
l1Txs := make(types.Transactions, len(receipts))
l1Fetcher.ExpectFetch(epoch.Hash, l1Info, l1Txs, receipts, nil)
attrs, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.NoError(t, err)
require.False(t, crit)
require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao)
require.Equal(t, cfg.FeeRecipientAddress, attrs.SuggestedFeeRecipient)
require.Equal(t, len(l2Txs), len(attrs.Transactions), "Expected txs to equal l1 info tx + user deposit txs")
require.Equal(t, l2Txs, attrs.Transactions)
require.True(t, attrs.NoTxPool)
})
t.Run("same origin again", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
l1Info := testutils.RandomL1Info(rng)
l1Info.InfoHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number
epoch := l1Info.ID()
l1InfoTx, err := L1InfoDepositBytes(l2Parent.SequenceNumber+1, l1Info)
require.NoError(t, err)
l1Fetcher.ExpectInfoByHash(epoch.Hash, l1Info, nil)
attrs, crit, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l2Parent, epoch)
require.NoError(t, err)
require.False(t, crit)
require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao)
require.Equal(t, cfg.FeeRecipientAddress, attrs.SuggestedFeeRecipient)
require.Equal(t, 1, len(attrs.Transactions))
require.Equal(t, l1InfoTx, []byte(attrs.Transactions[0]))
require.True(t, attrs.NoTxPool)
})
}
func encodeDeposits(deposits []*types.DepositTx) (out []eth.Data, err error) {
for i, tx := range deposits {
opaqueTx, err := types.NewTx(tx).MarshalBinary()
if err != nil {
return nil, fmt.Errorf("bad deposit %d: %v", i, err)
}
out = append(out, opaqueTx)
}
return
}
......@@ -6,8 +6,10 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUnmarshalLogEvent(t *testing.T) {
......@@ -43,32 +45,9 @@ type receiptData struct {
DepositLogs []bool
}
type DeriveUserDepositsTestCase struct {
name string
// generate len(receipts) receipts
receipts []receiptData
}
func TestDeriveUserDeposits(t *testing.T) {
testCases := []DeriveUserDepositsTestCase{
{"no deposits", []receiptData{}},
{"other log", []receiptData{{true, []bool{false}}}},
{"success deposit", []receiptData{{true, []bool{true}}}},
{"failed deposit", []receiptData{{false, []bool{true}}}},
{"mixed deposits", []receiptData{{true, []bool{true}}, {false, []bool{true}}}},
{"success multiple logs", []receiptData{{true, []bool{true, true}}}},
{"failed multiple logs", []receiptData{{false, []bool{true, true}}}},
{"not all deposit logs", []receiptData{{true, []bool{true, false, true}}}},
{"random", []receiptData{{true, []bool{false, false, true}}, {false, []bool{}}, {true, []bool{true}}}},
}
for i, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
rng := rand.New(rand.NewSource(1234 + int64(i)))
var receipts []*types.Receipt
var expectedDeposits []*types.DepositTx
func makeReceipts(rng *rand.Rand, blockHash common.Hash, depositContractAddr common.Address, testReceipts []receiptData) (receipts []*types.Receipt, expectedDeposits []*types.DepositTx) {
logIndex := uint(0)
blockHash := testutils.RandomHash(rng)
for txIndex, rData := range testCase.receipts {
for txIndex, rData := range testReceipts {
var logs []*types.Log
status := types.ReceiptStatusSuccessful
if !rData.goodReceipt {
......@@ -82,7 +61,7 @@ func TestDeriveUserDeposits(t *testing.T) {
if status == types.ReceiptStatusSuccessful {
expectedDeposits = append(expectedDeposits, dep)
}
ev = MarshalDepositLogEvent(MockDepositContractAddr, dep)
ev = MarshalDepositLogEvent(depositContractAddr, dep)
} else {
ev = testutils.GenerateLog(testutils.RandomAddress(rng), nil, nil)
}
......@@ -101,12 +80,38 @@ func TestDeriveUserDeposits(t *testing.T) {
TransactionIndex: uint(txIndex),
})
}
got, errs := UserDeposits(receipts, MockDepositContractAddr)
assert.Equal(t, len(errs), 0)
assert.Equal(t, len(got), len(expectedDeposits))
return
}
type DeriveUserDepositsTestCase struct {
name string
// generate len(receipts) receipts
receipts []receiptData
}
func TestDeriveUserDeposits(t *testing.T) {
testCases := []DeriveUserDepositsTestCase{
{"no deposits", []receiptData{}},
{"other log", []receiptData{{true, []bool{false}}}},
{"success deposit", []receiptData{{true, []bool{true}}}},
{"failed deposit", []receiptData{{false, []bool{true}}}},
{"mixed deposits", []receiptData{{true, []bool{true}}, {false, []bool{true}}}},
{"success multiple logs", []receiptData{{true, []bool{true, true}}}},
{"failed multiple logs", []receiptData{{false, []bool{true, true}}}},
{"not all deposit logs", []receiptData{{true, []bool{true, false, true}}}},
{"random", []receiptData{{true, []bool{false, false, true}}, {false, []bool{}}, {true, []bool{true}}}},
}
for i, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
rng := rand.New(rand.NewSource(1234 + int64(i)))
blockHash := testutils.RandomHash(rng)
receipts, expectedDeposits := makeReceipts(rng, blockHash, MockDepositContractAddr, testCase.receipts)
got, err := UserDeposits(receipts, MockDepositContractAddr)
require.NoError(t, err)
require.Equal(t, len(got), len(expectedDeposits))
for d, depTx := range got {
expected := expectedDeposits[d]
assert.Equal(t, expected, depTx)
require.Equal(t, expected, depTx)
}
})
}
......
......@@ -3,16 +3,17 @@ package derive
import (
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
// UserDeposits transforms the L2 block-height and L1 receipts into the transaction inputs for a full L2 block
func UserDeposits(receipts []*types.Receipt, depositContractAddr common.Address) ([]*types.DepositTx, []error) {
func UserDeposits(receipts []*types.Receipt, depositContractAddr common.Address) ([]*types.DepositTx, error) {
var out []*types.DepositTx
var errs []error
var result error
for i, rec := range receipts {
if rec.Status != types.ReceiptStatusSuccessful {
continue
......@@ -21,26 +22,30 @@ func UserDeposits(receipts []*types.Receipt, depositContractAddr common.Address)
if log.Address == depositContractAddr && len(log.Topics) > 0 && log.Topics[0] == DepositEventABIHash {
dep, err := UnmarshalDepositLogEvent(log)
if err != nil {
errs = append(errs, fmt.Errorf("malformatted L1 deposit log in receipt %d, log %d: %w", i, j, err))
result = multierror.Append(result, fmt.Errorf("malformatted L1 deposit log in receipt %d, log %d: %w", i, j, err))
} else {
out = append(out, dep)
}
}
}
}
return out, errs
return out, result
}
func DeriveDeposits(receipts []*types.Receipt, depositContractAddr common.Address) ([]hexutil.Bytes, []error) {
userDeposits, errs := UserDeposits(receipts, depositContractAddr)
func DeriveDeposits(receipts []*types.Receipt, depositContractAddr common.Address) ([]hexutil.Bytes, error) {
var result error
userDeposits, err := UserDeposits(receipts, depositContractAddr)
if err != nil {
result = multierror.Append(result, err)
}
encodedTxs := make([]hexutil.Bytes, 0, len(userDeposits))
for i, tx := range userDeposits {
opaqueTx, err := types.NewTx(tx).MarshalBinary()
if err != nil {
errs = append(errs, fmt.Errorf("failed to encode user tx %d", i))
result = multierror.Append(result, fmt.Errorf("failed to encode user tx %d", i))
} else {
encodedTxs = append(encodedTxs, opaqueTx)
}
}
return encodedTxs, errs
return encodedTxs, result
}
......@@ -9,8 +9,6 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
......@@ -27,70 +25,16 @@ func (d *outputImpl) createNewBlock(ctx context.Context, l2Head eth.L2BlockRef,
fetchCtx, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel()
var l1Info eth.L1Info
var receipts types.Receipts
var err error
seqNumber := l2Head.SequenceNumber + 1
// If the L1 origin changed this block, then we are in the first block of the epoch. In this
// case we need to fetch all transaction receipts from the L1 origin block so we can scan for
// user deposits.
if l2Head.L1Origin.Number != l1Origin.Number {
if l2Head.L1Origin.Hash != l1Origin.ParentHash {
d.log.Error("SEQUENCING BUG: cannot create new block on top of l2Head with new origin", "head", l2Head,
"head_origin", l2Head.L1Origin, "head_seq_nr", l2Head.SequenceNumber, "new_origin", l1Origin, "new_origin_parent", l1Origin.ParentID())
return l2Head, nil, fmt.Errorf("cannot create new block with L1 origin %s (parent %s) on top of L1 origin %s", l1Origin, l1Origin.ParentID(), l2Head.L1Origin)
}
l1Info, _, receipts, err = d.dl.Fetch(fetchCtx, l1Origin.Hash)
seqNumber = 0 // reset sequence number at the start of the epoch
} else {
if l2Head.L1Origin.Hash != l1Origin.Hash {
d.log.Error("SEQUENCING BUG: cannot create new block on top of l2Head with different origin at same height",
"head", l2Head, "head_origin", l2Head.L1Origin, "head_seq_nr", l2Head.SequenceNumber, "new_origin", l1Origin, "new_origin_parent", l1Origin.ParentID())
return l2Head, nil, fmt.Errorf("cannot create new block with L1 origin %s (parent %s) on top of L1 origin %s", l1Origin, l1Origin.ParentID(), l2Head.L1Origin)
}
l1Info, err = d.dl.InfoByHash(fetchCtx, l1Origin.Hash)
}
if err != nil {
return l2Head, nil, fmt.Errorf("failed to fetch L1 block info of %s: %v", l1Origin, err)
}
// Start building the list of transactions to include in the new block.
var txns []eth.Data
// First transaction in every block is always the L1 info transaction.
l1InfoTx, err := derive.L1InfoDepositBytes(seqNumber, l1Info)
attrs, _, err := derive.PreparePayloadAttributes(fetchCtx, d.Config, d.dl, l2Head, l1Origin.ID())
if err != nil {
return l2Head, nil, err
}
txns = append(txns, l1InfoTx)
// Next we append user deposits. If we're not the first block in an epoch, then receipts will
// be empty and no deposits will be derived.
deposits, errs := derive.DeriveDeposits(receipts, d.Config.DepositContractAddress)
d.log.Info("Derived deposits", "deposits", deposits, "l2Parent", l2Head, "l1Origin", l1Origin)
for _, err := range errs {
d.log.Error("Failed to derive a deposit", "l1OriginHash", l1Origin.Hash, "err", err)
}
// TODO: Should we halt if len(errs) > 0? Opens up a denial of service attack, but prevents lockup of funds.
txns = append(txns, deposits...)
// If our next L2 block timestamp is beyond the Sequencer drift threshold, then we must produce
// empty blocks (other than the L1 info deposit and any user deposits). We handle this by
// setting NoTxPool to true, which will cause the Sequencer to not include any transactions
// from the transaction pool.
nextL2Time := l2Head.Time + d.Config.BlockTime
shouldProduceEmptyBlock := nextL2Time >= l1Origin.Time+d.Config.MaxSequencerDrift
// Put together our payload attributes.
attrs := &eth.PayloadAttributes{
Timestamp: hexutil.Uint64(nextL2Time),
PrevRandao: eth.Bytes32(l1Info.MixDigest()),
SuggestedFeeRecipient: d.Config.FeeRecipientAddress,
Transactions: txns,
NoTxPool: shouldProduceEmptyBlock,
}
attrs.NoTxPool = uint64(attrs.Timestamp) >= l1Origin.Time+d.Config.MaxSequencerDrift
// And construct our fork choice state. This is our current fork choice state and will be
// updated as a result of executing the block based on the attributes described above.
......
......@@ -13,6 +13,15 @@ type MockL1Source struct {
mock.Mock
}
func (m *MockL1Source) InfoByHash(ctx context.Context, hash common.Hash) (eth.L1Info, error) {
out := m.Mock.MethodCalled("InfoByHash", hash)
return *out[0].(*eth.L1Info), *out[1].(*error)
}
func (m *MockL1Source) ExpectInfoByHash(hash common.Hash, info eth.L1Info, err error) {
m.Mock.On("InfoByHash", hash).Once().Return(&info, &err)
}
func (m *MockL1Source) L1BlockRefByNumber(ctx context.Context, u uint64) (eth.L1BlockRef, error) {
out := m.Mock.MethodCalled("L1BlockRefByNumber", u)
return out[0].(eth.L1BlockRef), *out[1].(*error)
......@@ -33,11 +42,11 @@ func (m *MockL1Source) ExpectL1BlockRefByHash(hash common.Hash, ref eth.L1BlockR
func (m *MockL1Source) Fetch(ctx context.Context, blockHash common.Hash) (eth.L1Info, types.Transactions, types.Receipts, error) {
out := m.Mock.MethodCalled("Fetch", blockHash)
return out[0].(eth.L1Info), out[1].(types.Transactions), out[2].(types.Receipts), *out[3].(*error)
return *out[0].(*eth.L1Info), out[1].(types.Transactions), out[2].(types.Receipts), *out[3].(*error)
}
func (m *MockL1Source) ExpectFetch(hash common.Hash, info eth.L1Info, transactions types.Transactions, receipts types.Receipts, err error) {
m.Mock.On("Fetch", hash).Once().Return(info, transactions, receipts, &err)
m.Mock.On("Fetch", hash).Once().Return(&info, transactions, receipts, &err)
}
func (m *MockL1Source) InfoAndTxsByHash(ctx context.Context, hash common.Hash) (eth.L1Info, types.Transactions, error) {
......
......@@ -2,6 +2,8 @@ FROM golang:1.18.0-alpine3.15 as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
# build op-proposer with local monorepo go modules
COPY ./op-proposer/docker.go.work /app/go.work
COPY ./op-bindings /app/op-bindings
COPY ./op-node /app/op-node
COPY ./op-proposer /app/op-proposer
......
go 1.18
use (
./op-bindings
./op-node
./op-proposer
)
......@@ -3,8 +3,8 @@ module github.com/ethereum-optimism/optimism/op-proposer
go 1.18
require (
github.com/ethereum-optimism/optimism/op-bindings v0.0.0
github.com/ethereum-optimism/optimism/op-node v0.0.0
github.com/ethereum-optimism/optimism/op-bindings v0.3.0
github.com/ethereum-optimism/optimism/op-node v0.3.0
github.com/ethereum/go-ethereum v1.10.17
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
github.com/stretchr/testify v1.8.0
......@@ -60,8 +60,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/ethereum-optimism/optimism/op-node v0.0.0 => ../op-node
replace github.com/ethereum-optimism/optimism/op-bindings v0.0.0 => ../op-bindings
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d
......@@ -191,6 +191,10 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/optimism/op-bindings v0.0.0-20220614233543-0d8fa52afca2/go.mod h1:e9mMYiVsdJf9BI//FdaA77BwNNgNMR043JtB7CPXNxY=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0 h1:d2Mwb8FzR2zuhW0sS5xFKWz/6VFPTEIE+XINqZj0Rv4=
github.com/ethereum-optimism/optimism/op-bindings v0.3.0/go.mod h1:CrvUVIISKcyJ7o27ub/HY4Kq9wEJQxrGmWthTqxPSGo=
github.com/ethereum-optimism/optimism/op-node v0.3.0 h1:jep/cbIbP7fjBSAR48yk5NJVEoGYvoNlYI00KpBI6Mw=
github.com/ethereum-optimism/optimism/op-node v0.3.0/go.mod h1:iF9AhYjr8jNeoCDNP/Vs/ywQ2USZU5L66AxZbSAUi0E=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d h1:AYFFbxrz7kLyFbvNHGhUPZQT8KnN1PPjCj4oAcgaVCk=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220711171946-f579014dc46d/go.mod h1:8AfU1epKggKxDt9wr7rH5KmCeiT3yT0sEvroru1mO6Q=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
......
......@@ -79,7 +79,7 @@ fi
(
cd ops-bedrock
echo "Bringing up L1..."
DOCKER_BUILDKIT=1 docker-compose build
DOCKER_BUILDKIT=1 docker-compose build --progress plain
docker-compose up -d l1
wait_up $L1_URL
)
......
......@@ -42,7 +42,7 @@ services:
- l2
build:
context: ../
dockerfile: ./ops-bedrock/Dockerfile.node
dockerfile: ./op-node/Dockerfile
command: >
op-node
--l1=ws://l1:8546
......@@ -81,7 +81,7 @@ services:
- op-node
build:
context: ../
dockerfile: ./ops-bedrock/Dockerfile.proposer
dockerfile: ./op-proposer/Dockerfile
environment:
L1_ETH_RPC: http://l1:8545
L2_ETH_RPC: http://l2:8545
......@@ -102,7 +102,7 @@ services:
- op-node
build:
context: ../
dockerfile: ./ops-bedrock/Dockerfile.batcher
dockerfile: ./op-batcher/Dockerfile
environment:
L1_ETH_RPC: http://l1:8545
L2_ETH_RPC: http://l2:8545
......
# @eth-optimism/ci-builder
## 0.1.2
### Patch Changes
- 184f13b6: Retrigger release of ci-builder
## 0.1.1
### Patch Changes
- 7bf30513: Fix publishing
- a60502f9: Install new version of bash
## 0.1.0
### Minor Changes
- 8c121ece: Update foundry in ci builder
### Patch Changes
- 445efe9d: Use ethereumoptimism/foundry:latest
......@@ -13,7 +13,7 @@ COPY --from=geth /usr/local/bin/abigen /usr/local/bin/abigen
COPY check-changed.sh /usr/local/bin/check-changed
RUN apt-get update && \
apt-get install -y curl openssh-client git build-essential ca-certificates jq musl && \
apt-get install -y bash curl openssh-client git build-essential ca-certificates jq musl && \
curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh && \
curl -sL https://go.dev/dl/go1.18.2.linux-amd64.tar.gz -o go1.18.2.linux-amd64.tar.gz && \
tar -C /usr/local/ -xzvf go1.18.2.linux-amd64.tar.gz && \
......@@ -51,4 +51,8 @@ RUN echo "downloading solidity compilers" && \
mkdir -p ~/.svm/0.8.10 && \
cp solc-linux-amd64-v0.8.10+commit.fc410830 ~/.svm/0.8.10/solc-0.8.10 && \
mkdir -p ~/.svm/0.8.12 && \
cp solc-linux-amd64-v0.8.12+commit.f00d7308 ~/.svm/0.8.12/solc-0.8.12
cp solc-linux-amd64-v0.8.12+commit.f00d7308 ~/.svm/0.8.12/solc-0.8.12 && \
rm solc-linux-amd64-v0.5.17+commit.d19bba13 && \
rm solc-linux-amd64-v0.8.9+commit.e5eed63a && \
rm solc-linux-amd64-v0.8.10+commit.fc410830 && \
rm solc-linux-amd64-v0.8.12+commit.f00d7308
{
"name": "@eth-optimism/ci-builder",
"version": "0.0.0",
"version": "0.1.2",
"scripts": {},
"license": "MIT",
"dependencies": {}
......
# @eth-optimism/foundry
## 0.1.0
### Minor Changes
- 5ae9c133: Initial release, pin to b7b1ec471bdd38221773e1a569dc4f20297bd7db
### Patch Changes
- d4de18ea: Use alpine:3.14
{
"name": "@eth-optimism/foundry",
"version": "0.0.0",
"version": "0.1.0",
"scripts": {},
"license": "MIT",
"dependencies": {}
}
# @eth-optimism/common-ts
## 0.6.1
### Patch Changes
- Updated dependencies [f9fee446]
- @eth-optimism/core-utils@0.9.1
## 0.6.0
### Minor Changes
......
{
"name": "@eth-optimism/common-ts",
"version": "0.6.0",
"version": "0.6.1",
"description": "[Optimism] Advanced typescript tooling used by various services",
"main": "dist/index",
"types": "dist/index",
......@@ -32,7 +32,7 @@
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"dependencies": {
"@eth-optimism/core-utils": "0.9.0",
"@eth-optimism/core-utils": "0.9.1",
"@sentry/node": "^6.3.1",
"bcfg": "^0.1.7",
"body-parser": "^1.20.0",
......
GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_0() (gas: 158608)
GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_1() (gas: 75017)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 249829)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 116083)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 249851)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 116058)
GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_0() (gas: 158650)
GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_1() (gas: 75059)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 249871)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 116125)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 249893)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 116100)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 45413)
GasBenchMark_L2OutputOracle:test_appendL2Output_benchmark() (gas: 68673)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 75069)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 35373)
DeployerWhitelist_Test:test_owner() (gas: 7658)
DeployerWhitelist_Test:test_storageSlots() (gas: 33494)
Encoding_Test:test_encodeDepositTransaction() (gas: 64610)
GasPriceOracle_Test:test_baseFee() (gas: 8370)
GasPriceOracle_Test:test_gasPrice() (gas: 8381)
GasPriceOracle_Test:test_l1BaseFee() (gas: 10582)
......@@ -23,7 +24,8 @@ GasPriceOracle_Test:test_setL1BaseFeeReverts() (gas: 11717)
GasPriceOracle_Test:test_setOverhead() (gas: 36767)
GasPriceOracle_Test:test_setScalar() (gas: 36818)
GasPriceOracle_Test:test_storageLayout() (gas: 86683)
Hashing_Test:test_l2TransactionHash() (gas: 104047)
Hashing_Test:test_hashDepositSource() (gas: 673)
Hashing_Test:test_hashDepositTransaction() (gas: 39129)
L1BlockTest:test_basefee() (gas: 7531)
L1BlockTest:test_hash() (gas: 7575)
L1BlockTest:test_number() (gas: 7630)
......@@ -35,20 +37,20 @@ L1BlockNumberTest:test_getL1BlockNumber() (gas: 10657)
L1BlockNumberTest:test_receive() (gas: 25437)
L1CrossDomainMessenger_Test:testCannot_L1MessengerPause() (gas: 24517)
L1CrossDomainMessenger_Test:testCannot_L1MessengerUnpause() (gas: 24509)
L1CrossDomainMessenger_Test:test_L1MessengerMessageVersion() (gas: 24671)
L1CrossDomainMessenger_Test:test_L1MessengerMessageVersion() (gas: 24716)
L1CrossDomainMessenger_Test:test_L1MessengerPause() (gas: 47995)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageSucceeds() (gas: 77935)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageToSystemContract() (gas: 67946)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageSucceeds() (gas: 77773)
L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageToSystemContract() (gas: 67784)
L1CrossDomainMessenger_Test:test_L1MessengerRelayShouldRevertIfPaused() (gas: 60472)
L1CrossDomainMessenger_Test:test_L1MessengerSendMessage() (gas: 196861)
L1CrossDomainMessenger_Test:test_L1MessengerTwiceSendMessage() (gas: 1273524)
L1CrossDomainMessenger_Test:test_L1MessengerSendMessage() (gas: 196878)
L1CrossDomainMessenger_Test:test_L1MessengerTwiceSendMessage() (gas: 1273626)
L1CrossDomainMessenger_Test:test_L1MessengerUnpause() (gas: 40890)
L1CrossDomainMessenger_Test:test_L1MessengerXDomainSenderReverts() (gas: 24272)
L1CrossDomainMessenger_Test:test_L1MessengerxDomainMessageSenderResets() (gas: 86782)
L1StandardBridge_Test:test_depositERC20() (gas: 474966)
L1StandardBridge_Test:test_depositERC20To() (gas: 477147)
L1StandardBridge_Test:test_depositETH() (gas: 268899)
L1StandardBridge_Test:test_depositETHTo() (gas: 226721)
L1CrossDomainMessenger_Test:test_L1MessengerxDomainMessageSenderResets() (gas: 86701)
L1StandardBridge_Test:test_depositERC20() (gas: 475008)
L1StandardBridge_Test:test_depositERC20To() (gas: 477189)
L1StandardBridge_Test:test_depositETH() (gas: 268941)
L1StandardBridge_Test:test_depositETHTo() (gas: 226763)
L1StandardBridge_Test:test_finalizeERC20Withdrawal() (gas: 490759)
L1StandardBridge_Test:test_finalizeETHWithdrawal() (gas: 64409)
L1StandardBridge_Test:test_initialize() (gas: 26336)
......@@ -56,17 +58,17 @@ L1StandardBridge_Test:test_onlyEOADepositERC20() (gas: 22363)
L1StandardBridge_Test:test_onlyEOADepositETH() (gas: 40882)
L1StandardBridge_Test:test_onlyL2BridgeFinalizeERC20Withdrawal() (gas: 36271)
L1StandardBridge_Test:test_onlyPortalFinalizeERC20Withdrawal() (gas: 35600)
L1StandardBridge_Test:test_receive() (gas: 413479)
L1StandardBridge_Test:test_receive() (gas: 413521)
L2CrossDomainMessenger_Test:testCannot_L2MessengerPause() (gas: 10821)
L2CrossDomainMessenger_Test:test_L2MessengerMessageVersion() (gas: 8400)
L2CrossDomainMessenger_Test:test_L2MessengerMessageVersion() (gas: 8445)
L2CrossDomainMessenger_Test:test_L2MessengerPause() (gas: 31815)
L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageSucceeds() (gas: 57494)
L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageToSystemContract() (gas: 36221)
L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageSucceeds() (gas: 57332)
L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageToSystemContract() (gas: 36140)
L2CrossDomainMessenger_Test:test_L2MessengerRelayShouldRevertIfPaused() (gas: 41664)
L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 119619)
L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 133146)
L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 119627)
L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 133248)
L2CrossDomainMessenger_Test:test_L2MessengerXDomainSenderReverts() (gas: 10599)
L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 54925)
L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 54844)
L2OutputOracleTest:testCannot_AppendWithUnmatchedBlockhash() (gas: 26811)
L2OutputOracleTest:testCannot_appendEmptyOutput() (gas: 24086)
L2OutputOracleTest:testCannot_appendFutureTimetamp() (gas: 26075)
......@@ -90,14 +92,14 @@ L2OutputOracleUpgradeable_Test:test_cannotInitImpl() (gas: 8476)
L2OutputOracleUpgradeable_Test:test_cannotInitProxy() (gas: 13497)
L2OutputOracleUpgradeable_Test:test_initValuesOnProxy() (gas: 38865)
L2OutputOracleUpgradeable_Test:test_upgrading() (gas: 230843)
L2StandardBridge_Test:test_ERC20BridgeFailed_whenLocalTokenIsBridge() (gas: 133158)
L2StandardBridge_Test:test_ERC20BridgeFailed_whenLocalTokenIsBridge() (gas: 133200)
L2StandardBridge_Test:test_cannotWithdrawEthWithoutSendingIt() (gas: 21656)
L2StandardBridge_Test:test_finalizeDeposit() (gas: 93203)
L2StandardBridge_Test:test_finalizeDeposit_failsToCompleteOutboundTransfer() (gas: 140168)
L2StandardBridge_Test:test_finalizeDeposit_failsToCompleteOutboundTransfer() (gas: 140210)
L2StandardBridge_Test:test_initialize() (gas: 14802)
L2StandardBridge_Test:test_receive() (gas: 136483)
L2StandardBridge_Test:test_withdraw() (gas: 352780)
L2StandardBridge_Test:test_withdrawTo() (gas: 353464)
L2StandardBridge_Test:test_receive() (gas: 136525)
L2StandardBridge_Test:test_withdraw() (gas: 352813)
L2StandardBridge_Test:test_withdrawTo() (gas: 353498)
L2StandardBridge_Test:test_withdraw_onlyEOA() (gas: 252006)
L2ToL1MessagePasserTest:test_burn() (gas: 112037)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract() (gas: 67892)
......@@ -252,13 +254,13 @@ RLPWriter_Test:test_writeUint_smallint3() (gas: 7372)
RLPWriter_Test:test_writeUint_smallint4() (gas: 7351)
RLPWriter_Test:test_writeUint_zero() (gas: 7798)
ResourceMetering_Test:test_initialResourceParams() (gas: 8964)
ResourceMetering_Test:test_updateNoGasDelta() (gas: 2008269)
ResourceMetering_Test:test_updateOneEmptyBlock() (gas: 18123)
ResourceMetering_Test:test_updateParamsNoChange() (gas: 13860)
ResourceMetering_Test:test_updateTenEmptyBlocks() (gas: 20523)
ResourceMetering_Test:test_updateTwoEmptyBlocks() (gas: 20546)
ResourceMetering_Test:test_useMaxSucceeds() (gas: 8017023)
ResourceMetering_Test:test_useMoreThanMaxReverts() (gas: 16002)
ResourceMetering_Test:test_updateNoGasDelta() (gas: 2008317)
ResourceMetering_Test:test_updateOneEmptyBlock() (gas: 18171)
ResourceMetering_Test:test_updateParamsNoChange() (gas: 13956)
ResourceMetering_Test:test_updateTenEmptyBlocks() (gas: 20571)
ResourceMetering_Test:test_updateTwoEmptyBlocks() (gas: 20594)
ResourceMetering_Test:test_useMaxSucceeds() (gas: 8017119)
ResourceMetering_Test:test_useMoreThanMaxReverts() (gas: 16047)
Semver_Test:test_behindProxy() (gas: 504908)
Semver_Test:test_major() (gas: 5406)
Semver_Test:test_minor() (gas: 5430)
......@@ -267,4 +269,4 @@ SequencerFeeVault_Test:test_constructor() (gas: 7656)
SequencerFeeVault_Test:test_minWithdrawalAmount() (gas: 5407)
SequencerFeeVault_Test:test_receive() (gas: 17258)
SequencerFeeVault_Test:test_revertWithdraw() (gas: 9332)
SequencerFeeVault_Test:test_withdraw() (gas: 147281)
SequencerFeeVault_Test:test_withdraw() (gas: 147323)
......@@ -31,7 +31,7 @@
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
| xDomainMsgSender | address | 202 | 0 | 20 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
| msgNonce | uint256 | 203 | 0 | 32 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger |
| msgNonce | uint240 | 203 | 0 | 30 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
| otherMessenger | address | 204 | 0 | 20 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
......@@ -192,7 +192,7 @@
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
| xDomainMsgSender | address | 202 | 0 | 20 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
| msgNonce | uint256 | 203 | 0 | 32 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger |
| msgNonce | uint240 | 203 | 0 | 30 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
| otherMessenger | address | 204 | 0 | 20 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
......
# @eth-optimism/contracts-bedrock
## 0.5.0
### Minor Changes
- 42a4cc30: Remove Lib* and OVM* prefixes from all contracts
### Patch Changes
- 0cb3929e: Move encoding and hashing into Encoding and Hashing libraries
- 28bd76ae: Cleans up hashing and encoding library natspec and function names
- 4279647f: Port RLPWriter tests
- ce6cb121: Use external version of ExcessivelySafeCall
- 8986f165: Fix solc warnings in ProxyAdmin
- 69ee689f: Remove unnecessary DefaultValues library
- 2e89f634: Fixes a bug that caused L2 timestamps to be computed incorrectly
- 49d33b08: Standardizes comments, errors, and events for contracts in the /universal package
- 821907e2: Bump typechain to 8.1.0
- 91b31168: Clean up comments and errors for legacy contracts
- 3c5726d4: Cleaned up enums, should be CapitalCase enums and UPPER_CASE values
- eb11a5bb: Add comments to RLP libraries
- 092b0901: Update to new L2 tx hash style for deposits
- 4ea33e13: Standardizes initialization logic for L1 contracts
- 297af083: Move contracts written by external parties into a vendor folder
- 71800503: Reduce the number of compiler warnings
- 611d93a1: Remove storage slot buffer in xdomain messengers
- 75089d0a: Cleans up initialization logic everywhere
- b9a90f32: Rename OptimismMintableTokenFactory to OptimismMintableERC20Factory
- 50e20ea1: Fix initialization logic
- 6f74ca9f: Clean up the PredeployAddresses library
- c031ec95: Tests for RLPReader
- 9c8b1f00: Bump forge-std to 62caef29b0f87a2c6aaaf634b2ca4c09b6867c92
- 89d01f2e: Add semver to L2 contracts
- 7d9820b6: Resolve compiler warnings in Proxy.sol
- f9fee446: Move the `DepositTx` type to `core-utils`. This way it can be more easily used across projects
- 5050e0fb: Remove "not implemented" errors in virtual functions
- 78d7c2ec: Update typechain pipeline
- 89d01f2e: Update dev deps
- Updated dependencies [f9fee446]
- @eth-optimism/core-utils@0.9.1
## 0.4.1
### Patch Changes
......
......@@ -2,8 +2,7 @@
## Install
The repo currently uses a mix of typescript tests (run with HardHat) and solidity tests (run with Forge). The project
uses the default hardhat directory structure, and all build/test steps should be run using the yarn scripts to ensure
The repo currently uses solidity tests (run with Forge). The project uses the default hardhat directory structure, and all build/test steps should be run using the yarn scripts to ensure
the correct options are set.
Install node modules with yarn (v1), and Node.js (14+).
......@@ -22,28 +21,12 @@ yarn build
## Running Tests
First get the dependencies:
`git submodule init` and `git submodule update`
Then the full test suite can be executed via `yarn`:
```shell
yarn test
```
To run only typescript tests:
```shell
yarn test:hh
```
To run only solidity tests:
```shell
yarn test:forge
```
## Deployment
Create a file that corresponds to the network name in the `deploy-config`
......@@ -52,7 +35,7 @@ directory and then run the command:
```shell
L1_RPC=<ETHEREUM L1 RPC endpoint> \
PRIVATE_KEY_DEPLOYER=<PRIVATE KEY TO PAY FOR THE DEPLOYMENT> \
npx hardhat deploy --network <network-name>
npx hardhat deploy --network <network-name>
```
In the `hardhat.config.ts`, there is a `deployConfigSpec` field that validates that the types
......
......@@ -86,6 +86,8 @@ contract L1StandardBridge is StandardBridge, Semver {
);
/**
* @custom:semver 0.0.1
*
* @param _messenger Address of the L1CrossDomainMessenger.
*/
constructor(address payable _messenger) Semver(0, 0, 1) {
......
......@@ -99,12 +99,11 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
constructor(L2OutputOracle _l2Oracle, uint256 _finalizationPeriodSeconds) Semver(0, 0, 1) {
L2_ORACLE = _l2Oracle;
FINALIZATION_PERIOD_SECONDS = _finalizationPeriodSeconds;
initialize();
}
/**
* @notice Intializes mutable variables.
* @notice Initializer;
*/
function initialize() public initializer {
l2Sender = DEFAULT_L2_SENDER;
......@@ -242,13 +241,13 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// Verify that the output root can be generated with the elements in the proof.
require(
proposal.outputRoot == Hashing._deriveOutputRoot(_outputRootProof),
proposal.outputRoot == Hashing.hashOutputRootProof(_outputRootProof),
"OptimismPortal: invalid output root proof"
);
// All withdrawals have a unique hash, we'll use this as the identifier for the withdrawal
// and to prevent replay attacks.
bytes32 withdrawalHash = Hashing.withdrawalHash(
bytes32 withdrawalHash = Hashing.hashWithdrawal(
_nonce,
_sender,
_target,
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import { FixedPointMathLib } from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
......@@ -11,7 +12,7 @@ import { Burn } from "../libraries/Burn.sol";
* @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing
* updates automatically based on current demand.
*/
contract ResourceMetering {
abstract contract ResourceMetering is Initializable {
/**
* @notice Represents the various parameters that control the way in which resources are
* metered. Corresponds to the EIP-1559 resource metering system.
......@@ -62,19 +63,11 @@ contract ResourceMetering {
*/
uint256[49] private __gap;
/**
* @notice Set the initial values. In order to enable this contract to be used in an upgradable
* context, the constructor calls a separate init function.
*/
constructor() {
__ResourceMetering_init();
}
/**
* @notice Sets initial resource parameter values. This function must either be called by the
* initializer function of an upgradeable child contract.
*/
function __ResourceMetering_init() internal {
function __ResourceMetering_init() internal onlyInitializing {
params = ResourceParams({
prevBaseFee: INITIAL_BASE_FEE,
prevBoughtGas: 0,
......
......@@ -79,7 +79,7 @@ contract L2ToL1MessagePasser is Semver {
uint256 _gasLimit,
bytes memory _data
) public payable {
bytes32 withdrawalHash = Hashing.withdrawalHash(
bytes32 withdrawalHash = Hashing.hashWithdrawal(
nonce,
msg.sender,
_target,
......
......@@ -10,73 +10,58 @@ import { RLPWriter } from "./rlp/RLPWriter.sol";
*/
library Encoding {
/**
* 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.
* @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent
* to the L2 system. Useful for searching for a deposit in the L2 system.
*
* @param _from Address of the sender of the deposit.
* @param _to Address of the receiver of the deposit.
* @param _value ETH value to send to the receiver.
* @param _mint ETH value to mint on L2.
* @param _gasLimit Gas limit to use for the transaction.
* @param _isCreation Whether or not the transaction is a contract creation.
* @param _data Data to send with the transaction.
* @param _l1BlockHash Hash of the L1 block where the deposit was included.
* @param _logIndex Index of the deposit event in the L1 block.
*
* @return RLP encoded L2 deposit transaction.
*/
function encodeXDomainCalldata(
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
);
}
/**
* @notice RLP encode a deposit transaction
* This only works for user deposits, not system deposits
* TODO: better name + rearrange the input param ordering?
*/
function L2Transaction(
bytes32 _l1BlockHash,
uint256 _logIndex,
function encodeDepositTransaction(
address _from,
address _to,
bool _isCreate,
uint256 _mint,
uint256 _value,
uint256 _gas,
bytes memory _data
uint256 _mint,
uint64 _gasLimit,
bool _isCreation,
bytes memory _data,
bytes32 _l1BlockHash,
uint256 _logIndex
) internal pure returns (bytes memory) {
bytes32 source = Hashing.sourceHash(_l1BlockHash, _logIndex);
bytes32 source = Hashing.hashDepositSource(_l1BlockHash, _logIndex);
bytes[] memory raw = new bytes[](7);
raw[0] = RLPWriter.writeBytes(abi.encodePacked(source));
raw[1] = RLPWriter.writeAddress(_from);
if (_isCreate == true) {
require(_to == address(0));
raw[2] = RLPWriter.writeBytes("");
} else {
raw[2] = RLPWriter.writeAddress(_to);
}
raw[2] = _isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_to);
raw[3] = RLPWriter.writeUint(_mint);
raw[4] = RLPWriter.writeUint(_value);
raw[5] = RLPWriter.writeUint(_gas);
raw[5] = RLPWriter.writeUint(uint256(_gasLimit));
raw[6] = RLPWriter.writeBytes(_data);
bytes memory encoded = RLPWriter.writeList(raw);
return abi.encodePacked(uint8(0x7e), uint8(0x0), encoded);
return abi.encodePacked(uint8(0x7e), uint8(0x0), RLPWriter.writeList(raw));
}
/**
* @notice Encodes the cross domain message based on the version that
* is encoded in the nonce
* @notice Encodes the cross domain message based on the version that is encoded into the
* message nonce.
*
* @param _nonce Message nonce with version encoded into the first two bytes.
* @param _sender Address of the sender of the message.
* @param _target Address of the target of the message.
* @param _value ETH value to send to the target.
* @param _gasLimit Gas limit to use for the message.
* @param _data Data to send with the message.
*
* @return Encoded cross domain message.
*/
function getVersionedEncoding(
function encodeCrossDomainMessage(
uint256 _nonce,
address _sender,
address _target,
......@@ -84,32 +69,55 @@ library Encoding {
uint256 _gasLimit,
bytes memory _data
) internal pure returns (bytes memory) {
uint16 version = getVersionFromNonce(_nonce);
(, uint16 version) = decodeVersionedNonce(_nonce);
if (version == 0) {
return getEncodingV0(_target, _sender, _data, _nonce);
return encodeCrossDomainMessageV0(_target, _sender, _data, _nonce);
} else if (version == 1) {
return getEncodingV1(_nonce, _sender, _target, _value, _gasLimit, _data);
return encodeCrossDomainMessageV1(_nonce, _sender, _target, _value, _gasLimit, _data);
} else {
revert("Encoding: unknown cross domain message version");
}
revert("Unknown version.");
}
/**
* @notice Compute the legacy cross domain serialization
* @notice Encodes a cross domain message based on the V0 (legacy) encoding.
*
* @param _target Address of the target of the message.
* @param _sender Address of the sender of the message.
* @param _data Data to send with the message.
* @param _nonce Message nonce.
*
* @return Encoded cross domain message.
*/
function getEncodingV0(
function encodeCrossDomainMessageV0(
address _target,
address _sender,
bytes memory _data,
uint256 _nonce
) internal pure returns (bytes memory) {
return encodeXDomainCalldata(_target, _sender, _data, _nonce);
return
abi.encodeWithSignature(
"relayMessage(address,address,bytes,uint256)",
_target,
_sender,
_data,
_nonce
);
}
/**
* @notice Compute the V1 cross domain serialization
* @notice Encodes a cross domain message based on the V1 (current) encoding.
*
* @param _nonce Message nonce.
* @param _sender Address of the sender of the message.
* @param _target Address of the target of the message.
* @param _value ETH value to send to the target.
* @param _gasLimit Gas limit to use for the message.
* @param _data Data to send with the message.
*
* @return Encoded cross domain message.
*/
function getEncodingV1(
function encodeCrossDomainMessageV1(
uint256 _nonce,
address _sender,
address _target,
......@@ -130,24 +138,36 @@ library Encoding {
}
/**
* @notice Adds the version to the nonce
* @notice Adds a version number into the first two bytes of a message nonce.
*
* @param _nonce Message nonce to encode into.
* @param _version Version number to encode into the message nonce.
*
* @return Message nonce with version encoded into the first two bytes.
*/
function addVersionToNonce(uint256 _nonce, uint16 _version)
internal
pure
returns (uint256 nonce)
{
function encodeVersionedNonce(uint240 _nonce, uint16 _version) internal pure returns (uint256) {
uint256 nonce;
assembly {
nonce := or(shl(240, _version), _nonce)
}
return nonce;
}
/**
* @notice Gets the version out of the nonce
* @notice Pulls the version out of a version-encoded nonce.
*
* @param _nonce Message nonce with version encoded into the first two bytes.
*
* @return Nonce without encoded version.
* @return Version of the message.
*/
function getVersionFromNonce(uint256 _nonce) internal pure returns (uint16 version) {
function decodeVersionedNonce(uint256 _nonce) internal pure returns (uint240, uint16) {
uint240 nonce;
uint16 version;
assembly {
nonce := and(_nonce, 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
version := shr(240, _nonce)
}
return (nonce, version);
}
}
......@@ -8,7 +8,10 @@ import { Encoding } from "./Encoding.sol";
* @notice Hashing handles Optimism's various different hashing schemes.
*/
library Hashing {
/// @notice A struct containing the elements hashed together to generate the output root.
/**
* @notice Struct representing the elements that are hashed together to generate an output root
* which itself represents a snapshot of the L2 state.
*/
struct OutputRootProof {
bytes32 version;
bytes32 stateRoot;
......@@ -17,66 +20,81 @@ library Hashing {
}
/**
* @notice Compute the L2 transaction hash given
* data about an L1 deposit transaction. This is useful for
* environments that do not have access to arbitrary
* RLP encoding functionality but have access to the
* standard web3 API
* TODO: rearrange args in a sane way
* @param _l1BlockHash The L1 block hash corresponding to the block
* the deposit was included in
* @param _logIndex The log index of the event that the deposit was
* created from. This can be found on the transaction receipt
* @param _from The sender of the deposit
* @param _to The L2 contract to be called by the deposit transaction
* @param _isCreate Indicates if the deposit creates a contract
* @param _mint The amount of ETH being minted by the transaction
* @param _value The amount of ETH send in the L2 call
* @param _gas The gas limit for the L2 call
* @notice Computes the hash of the RLP encoded L2 transaction that would be generated when a
* given deposit is sent to the L2 system. Useful for searching for a deposit in the L2
* system.
*
* @param _from Address of the sender of the deposit.
* @param _to Address of the receiver of the deposit.
* @param _value ETH value to send to the receiver.
* @param _mint ETH value to mint on L2.
* @param _gasLimit Gas limit to use for the transaction.
* @param _isCreation Whether or not the transaction is a contract creation.
* @param _data Data to send with the transaction.
* @param _l1BlockHash Hash of the L1 block where the deposit was included.
* @param _logIndex Index of the deposit event in the L1 block.
*
* @return Hash of the RLP encoded L2 deposit transaction.
*/
function L2TransactionHash(
bytes32 _l1BlockHash,
uint256 _logIndex,
function hashDepositTransaction(
address _from,
address _to,
bool _isCreate,
uint256 _mint,
uint256 _value,
uint256 _gas,
bytes memory _data
uint256 _mint,
uint64 _gasLimit,
bool _isCreation,
bytes memory _data,
bytes32 _l1BlockHash,
uint256 _logIndex
) internal pure returns (bytes32) {
bytes memory raw = Encoding.L2Transaction(
_l1BlockHash,
_logIndex,
bytes memory raw = Encoding.encodeDepositTransaction(
_from,
_to,
_isCreate,
_mint,
_value,
_gas,
_data
_mint,
_gasLimit,
_isCreation,
_data,
_l1BlockHash,
_logIndex
);
return keccak256(raw);
}
/**
* @notice Compute the deposit transaction source hash.
* This value ensures that the L2 transaction hash is unique
* and deterministic based on L1 execution
* @param l1BlockHash The L1 blockhash corresponding to the block including
* the deposit
* @param logIndex The index of the log that created the deposit transaction
* @notice Computes the deposit transaction's "source hash", a value that guarantees the hash
* of the L2 transaction that corresponds to a deposit is unique and is
* deterministically generated from L1 transaction data.
*
* @param _l1BlockHash Hash of the L1 block where the deposit was included.
* @param _logIndex The index of the log that created the deposit transaction.
*
* @return Hash of the deposit transaction's "source hash".
*/
function sourceHash(bytes32 l1BlockHash, uint256 logIndex) internal pure returns (bytes32) {
bytes32 depositId = keccak256(abi.encode(l1BlockHash, logIndex));
function hashDepositSource(bytes32 _l1BlockHash, uint256 _logIndex)
internal
pure
returns (bytes32)
{
bytes32 depositId = keccak256(abi.encode(_l1BlockHash, _logIndex));
return keccak256(abi.encode(bytes32(0), depositId));
}
/**
* @notice Compute the cross domain hash based on the versioned nonce
* @notice Hashes the cross domain message based on the version that is encoded into the
* message nonce.
*
* @param _nonce Message nonce with version encoded into the first two bytes.
* @param _sender Address of the sender of the message.
* @param _target Address of the target of the message.
* @param _value ETH value to send to the target.
* @param _gasLimit Gas limit to use for the message.
* @param _data Data to send with the message.
*
* @return Hashed cross domain message.
*/
function getVersionedHash(
function hashCrossDomainMessage(
uint256 _nonce,
address _sender,
address _target,
......@@ -84,32 +102,48 @@ library Hashing {
uint256 _gasLimit,
bytes memory _data
) internal pure returns (bytes32) {
uint16 version = Encoding.getVersionFromNonce(_nonce);
(, uint16 version) = Encoding.decodeVersionedNonce(_nonce);
if (version == 0) {
return getHashV0(_target, _sender, _data, _nonce);
return hashCrossDomainMessageV0(_target, _sender, _data, _nonce);
} else if (version == 1) {
return getHashV1(_nonce, _sender, _target, _value, _gasLimit, _data);
return hashCrossDomainMessageV1(_nonce, _sender, _target, _value, _gasLimit, _data);
} else {
revert("Hashing: unknown cross domain message version");
}
revert("Unknown version.");
}
/**
* @notice Compute the legacy hash of a cross domain message
* @notice Hashes a cross domain message based on the V0 (legacy) encoding.
*
* @param _target Address of the target of the message.
* @param _sender Address of the sender of the message.
* @param _data Data to send with the message.
* @param _nonce Message nonce.
*
* @return Hashed cross domain message.
*/
function getHashV0(
function hashCrossDomainMessageV0(
address _target,
address _sender,
bytes memory _data,
uint256 _nonce
) internal pure returns (bytes32) {
return keccak256(Encoding.getEncodingV0(_target, _sender, _data, _nonce));
return keccak256(Encoding.encodeCrossDomainMessageV0(_target, _sender, _data, _nonce));
}
/**
* @notice Compute the V1 hash of a cross domain message
* @notice Hashes a cross domain message based on the V1 (current) encoding.
*
* @param _nonce Message nonce.
* @param _sender Address of the sender of the message.
* @param _target Address of the target of the message.
* @param _value ETH value to send to the target.
* @param _gasLimit Gas limit to use for the message.
* @param _data Data to send with the message.
*
* @return Hashed cross domain message.
*/
function getHashV1(
function hashCrossDomainMessageV1(
uint256 _nonce,
address _sender,
address _target,
......@@ -118,7 +152,16 @@ library Hashing {
bytes memory _data
) internal pure returns (bytes32) {
return
keccak256(Encoding.getEncodingV1(_nonce, _sender, _target, _value, _gasLimit, _data));
keccak256(
Encoding.encodeCrossDomainMessageV1(
_nonce,
_sender,
_target,
_value,
_gasLimit,
_data
)
);
}
/**
......@@ -130,7 +173,7 @@ library Hashing {
* @param _gasLimit Gas to be forwarded to the target.
* @param _data Data to send to the target.
*/
function withdrawalHash(
function hashWithdrawal(
uint256 _nonce,
address _sender,
address _target,
......@@ -142,11 +185,14 @@ library Hashing {
}
/**
* @notice Derives the output root corresponding to the elements provided in the proof.
* @param _outputRootProof The elements which were hashed together to generate the output root.
* @return Whether or not the output root matches the hashed output of the proof.
* @notice Hashes the various elements of an output root proof into an output root hash which
* can be used to check if the proof is valid.
*
* @param _outputRootProof Output root proof which should hash to an output root.
*
* @return Hashed output root proof.
*/
function _deriveOutputRoot(OutputRootProof memory _outputRootProof)
function hashOutputRootProof(OutputRootProof memory _outputRootProof)
internal
pure
returns (bytes32)
......
......@@ -2,41 +2,42 @@
pragma solidity ^0.8.9;
/**
* @custom:attribution https://github.com/hamdiallam/Solidity-RLP
* @title RLPReader
* @dev Adapted from "RLPReader" by Hamdi Allam (hamdi.allam97@gmail.com).
* @notice RLPReader is a library for parsing RLP-encoded byte arrays into Solidity types. Adapted
* from Solidity-RLP (https://github.com/hamdiallam/Solidity-RLP) by Hamdi Allam with
* various tweaks to improve readability.
*/
library RLPReader {
/*************
* Constants *
*************/
/**
* @notice Max list length that this library will accept.
*/
uint256 internal constant MAX_LIST_LENGTH = 32;
/*********
* Enums *
*********/
/**
* @notice RLP item types.
*
* @custom:value DATA_ITEM Represents an RLP data item (NOT a list).
* @custom:value LIST_ITEM Represents an RLP list item.
*/
enum RLPItemType {
DATA_ITEM,
LIST_ITEM
}
/***********
* Structs *
***********/
/**
* @notice Struct representing an RLP item.
*/
struct RLPItem {
uint256 length;
uint256 ptr;
}
/**********************
* Internal Functions *
**********************/
/**
* Converts bytes to a reference to memory position and length.
* @notice Converts bytes to a reference to memory position and length.
*
* @param _in Input bytes to convert.
*
* @return Output memory reference.
*/
function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) {
......@@ -49,8 +50,10 @@ library RLPReader {
}
/**
* Reads an RLP list value into a list of RLP items.
* @notice Reads an RLP list value into a list of RLP items.
*
* @param _in RLP list value.
*
* @return Decoded RLP list items.
*/
function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) {
......@@ -88,8 +91,10 @@ library RLPReader {
}
/**
* Reads an RLP list value into a list of RLP items.
* @notice Reads an RLP list value into a list of RLP items.
*
* @param _in RLP list value.
*
* @return Decoded RLP list items.
*/
function readList(bytes memory _in) internal pure returns (RLPItem[] memory) {
......@@ -97,8 +102,10 @@ library RLPReader {
}
/**
* Reads an RLP bytes value into bytes.
* @notice Reads an RLP bytes value into bytes.
*
* @param _in RLP bytes value.
*
* @return Decoded bytes.
*/
function readBytes(RLPItem memory _in) internal pure returns (bytes memory) {
......@@ -110,8 +117,10 @@ library RLPReader {
}
/**
* Reads an RLP bytes value into bytes.
* @notice Reads an RLP bytes value into bytes.
*
* @param _in RLP bytes value.
*
* @return Decoded bytes.
*/
function readBytes(bytes memory _in) internal pure returns (bytes memory) {
......@@ -119,8 +128,10 @@ library RLPReader {
}
/**
* Reads an RLP string value into a string.
* @notice Reads an RLP string value into a string.
*
* @param _in RLP string value.
*
* @return Decoded string.
*/
function readString(RLPItem memory _in) internal pure returns (string memory) {
......@@ -128,8 +139,10 @@ library RLPReader {
}
/**
* Reads an RLP string value into a string.
* @notice Reads an RLP string value into a string.
*
* @param _in RLP string value.
*
* @return Decoded string.
*/
function readString(bytes memory _in) internal pure returns (string memory) {
......@@ -137,8 +150,10 @@ library RLPReader {
}
/**
* Reads an RLP bytes32 value into a bytes32.
* @notice Reads an RLP bytes32 value into a bytes32.
*
* @param _in RLP bytes32 value.
*
* @return Decoded bytes32.
*/
function readBytes32(RLPItem memory _in) internal pure returns (bytes32) {
......@@ -163,8 +178,10 @@ library RLPReader {
}
/**
* Reads an RLP bytes32 value into a bytes32.
* @notice Reads an RLP bytes32 value into a bytes32.
*
* @param _in RLP bytes32 value.
*
* @return Decoded bytes32.
*/
function readBytes32(bytes memory _in) internal pure returns (bytes32) {
......@@ -172,8 +189,10 @@ library RLPReader {
}
/**
* Reads an RLP uint256 value into a uint256.
* @notice Reads an RLP uint256 value into a uint256.
*
* @param _in RLP uint256 value.
*
* @return Decoded uint256.
*/
function readUint256(RLPItem memory _in) internal pure returns (uint256) {
......@@ -181,8 +200,10 @@ library RLPReader {
}
/**
* Reads an RLP uint256 value into a uint256.
* @notice Reads an RLP uint256 value into a uint256.
*
* @param _in RLP uint256 value.
*
* @return Decoded uint256.
*/
function readUint256(bytes memory _in) internal pure returns (uint256) {
......@@ -190,8 +211,10 @@ library RLPReader {
}
/**
* Reads an RLP bool value into a bool.
* @notice Reads an RLP bool value into a bool.
*
* @param _in RLP bool value.
*
* @return Decoded bool.
*/
function readBool(RLPItem memory _in) internal pure returns (bool) {
......@@ -209,8 +232,10 @@ library RLPReader {
}
/**
* Reads an RLP bool value into a bool.
* @notice Reads an RLP bool value into a bool.
*
* @param _in RLP bool value.
*
* @return Decoded bool.
*/
function readBool(bytes memory _in) internal pure returns (bool) {
......@@ -218,8 +243,10 @@ library RLPReader {
}
/**
* Reads an RLP address value into a address.
* @notice Reads an RLP address value into a address.
*
* @param _in RLP address value.
*
* @return Decoded address.
*/
function readAddress(RLPItem memory _in) internal pure returns (address) {
......@@ -233,8 +260,10 @@ library RLPReader {
}
/**
* Reads an RLP address value into a address.
* @notice Reads an RLP address value into a address.
*
* @param _in RLP address value.
*
* @return Decoded address.
*/
function readAddress(bytes memory _in) internal pure returns (address) {
......@@ -242,8 +271,10 @@ library RLPReader {
}
/**
* Reads the raw bytes of an RLP item.
* @notice Reads the raw bytes of an RLP item.
*
* @param _in RLP item to read.
*
* @return Raw RLP bytes.
*/
function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) {
......@@ -255,8 +286,10 @@ library RLPReader {
*********************/
/**
* Decodes the length of an RLP item.
* @notice Decodes the length of an RLP item.
*
* @param _in RLP item to decode.
*
* @return Offset of the encoded data.
* @return Length of the encoded data.
* @return RLP item type (LIST_ITEM or DATA_ITEM).
......@@ -333,10 +366,12 @@ library RLPReader {
}
/**
* Copies the bytes from a memory location.
* @notice Copies the bytes from a memory location.
*
* @param _src Pointer to the location to read from.
* @param _offset Offset to start reading from.
* @param _length Number of bytes to read.
*
* @return Copied bytes.
*/
function _copy(
......@@ -378,8 +413,10 @@ library RLPReader {
}
/**
* Copies an RLP item into bytes.
* @notice Copies an RLP item into bytes.
*
* @param _in RLP item to copy.
*
* @return Copied bytes.
*/
function _copy(RLPItem memory _in) private pure returns (bytes memory) {
......
......@@ -2,17 +2,18 @@
pragma solidity ^0.8.9;
/**
* @custom:attribution https://github.com/bakaoh/solidity-rlp-encode
* @title RLPWriter
* @author Bakaoh (with modifications)
* @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's
* RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor
* modifications to improve legibility.
*/
library RLPWriter {
/**********************
* Internal Functions *
**********************/
/**
* RLP encodes a byte string.
* @notice RLP encodes a byte string.
*
* @param _in The byte string to encode.
*
* @return The RLP encoded string in bytes.
*/
function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
......@@ -28,8 +29,10 @@ library RLPWriter {
}
/**
* RLP encodes a list of RLP encoded byte byte strings.
* @notice RLP encodes a list of RLP encoded byte byte strings.
*
* @param _in The list of RLP encoded byte strings.
*
* @return The RLP encoded list of items in bytes.
*/
function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
......@@ -38,8 +41,10 @@ library RLPWriter {
}
/**
* RLP encodes a string.
* @notice RLP encodes a string.
*
* @param _in The string to encode.
*
* @return The RLP encoded string in bytes.
*/
function writeString(string memory _in) internal pure returns (bytes memory) {
......@@ -47,8 +52,10 @@ library RLPWriter {
}
/**
* RLP encodes an address.
* @notice RLP encodes an address.
*
* @param _in The address to encode.
*
* @return The RLP encoded address in bytes.
*/
function writeAddress(address _in) internal pure returns (bytes memory) {
......@@ -56,8 +63,10 @@ library RLPWriter {
}
/**
* RLP encodes a uint.
* @notice RLP encodes a uint.
*
* @param _in The uint256 to encode.
*
* @return The RLP encoded uint256 in bytes.
*/
function writeUint(uint256 _in) internal pure returns (bytes memory) {
......@@ -65,8 +74,10 @@ library RLPWriter {
}
/**
* RLP encodes a bool.
* @notice RLP encodes a bool.
*
* @param _in The bool to encode.
*
* @return The RLP encoded bool in bytes.
*/
function writeBool(bool _in) internal pure returns (bytes memory) {
......@@ -75,14 +86,12 @@ library RLPWriter {
return encoded;
}
/*********************
* Private Functions *
*********************/
/**
* Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
* @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.
*
* @param _len The length of the string or the payload.
* @param _offset 128 if item is string, 192 if item is list.
*
* @return RLP encoded bytes.
*/
function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
......@@ -110,9 +119,10 @@ library RLPWriter {
}
/**
* Encode integer in big endian binary form with no leading zeroes.
* @notice TODO: This should be optimized with assembly to save gas costs.
* @notice Encode integer in big endian binary form with no leading zeroes.
*
* @param _x The integer to encode.
*
* @return RLP encoded bytes.
*/
function _toBinary(uint256 _x) private pure returns (bytes memory) {
......@@ -134,8 +144,9 @@ library RLPWriter {
}
/**
* Copies a piece of memory to another location.
* @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol.
* @custom:attribution https://github.com/Arachnid/solidity-stringutils
* @notice Copies a piece of memory to another location.
*
* @param _dest Destination location.
* @param _src Source location.
* @param _len Length of memory to copy.
......@@ -169,9 +180,11 @@ library RLPWriter {
}
/**
* Flattens a list of byte strings into one byte string.
* @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol.
* @custom:attribution https://github.com/sammayo/solidity-rlp-encoder
* @notice Flattens a list of byte strings into one byte string.
*
* @param _list List of byte strings to flatten.
*
* @return The flattened byte string.
*/
function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { BytesUtils } from "../BytesUtils.sol";
import { RLPReader } from "../rlp/RLPReader.sol";
import { RLPWriter } from "../rlp/RLPWriter.sol";
/**
* @title MerkleTrie
* @notice MerkleTrie is a small library for verifying standard Ethereum Merkle-Patricia trie
* inclusion proofs. By default, this library assumes a hexary trie. One can change the
* trie radix constant to support other trie radixes.
*/
library MerkleTrie {
/*******************
* Data Structures *
*******************/
/**
* @notice Struct representing a node in the trie.
*/
struct TrieNode {
bytes encoded;
RLPReader.RLPItem[] decoded;
}
/**********************
* Contract Constants *
**********************/
// TREE_RADIX determines the number of elements per branch node.
/**
* @notice Determines the number of elements per branch node.
*/
uint256 constant TREE_RADIX = 16;
// Branch nodes have TREE_RADIX elements plus an additional `value` slot.
/**
* @notice Branch nodes have TREE_RADIX elements and one value element.
*/
uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1;
// Leaf nodes and extension nodes always have two elements, a `path` and a `value`.
/**
* @notice Leaf nodes and extension nodes have two elements, a `path` and a `value`.
*/
uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2;
// Prefixes are prepended to the `path` within a leaf or extension node and
// allow us to differentiate between the two node types. `ODD` or `EVEN` is
// determined by the number of nibbles within the unprefixed `path`. If the
// number of nibbles if even, we need to insert an extra padding nibble so
// the resulting prefixed `path` has an even number of nibbles.
/**
* @notice Prefix for even-nibbled extension node paths.
*/
uint8 constant PREFIX_EXTENSION_EVEN = 0;
/**
* @notice Prefix for odd-nibbled extension node paths.
*/
uint8 constant PREFIX_EXTENSION_ODD = 1;
/**
* @notice Prefix for even-nibbled leaf node paths.
*/
uint8 constant PREFIX_LEAF_EVEN = 2;
/**
* @notice Prefix for odd-nibbled leaf node paths.
*/
uint8 constant PREFIX_LEAF_ODD = 3;
// Just a utility constant. RLP represents `NULL` as 0x80.
/**
* @notice RLP representation of `NULL`.
*/
bytes1 constant RLP_NULL = bytes1(0x80);
/**********************
* Internal Functions *
**********************/
/**
* @notice Verifies a proof that a given key/value pair is present in the
* Merkle trie.
* @notice Verifies a proof that a given key/value pair is present in the trie.
*
* @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike
* traditional Merkle trees, this proof is executed top-down and consists
* of a list of RLP-encoded nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle
* trees, this proof is executed top-down and consists of a list of RLP-encoded
* nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the included proof is
* correctly constructed.
*
* @return Whether or not the proof is valid.
*/
function verifyInclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _verified) {
) internal pure returns (bool) {
(bool exists, bytes memory value) = get(_key, _proof, _root);
return (exists && BytesUtils.equal(_value, value));
}
/**
* @notice Retrieves the value associated with a given key.
*
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie.
* @return _exists Whether or not the key exists.
* @return _value Value of the key if it exists.
*
* @return Whether or not the key exists.
* @return Value of the key if it exists.
*/
function get(
bytes memory _key,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _exists, bytes memory _value) {
) internal pure returns (bool, bytes memory) {
TrieNode[] memory proof = _parseProof(_proof);
(uint256 pathLength, bytes memory keyRemainder, bool isFinalNode) = _walkNodePath(
proof,
......@@ -99,18 +114,16 @@ library MerkleTrie {
return (exists, value);
}
/*********************
* Private Functions *
*********************/
/**
* @notice Walks through a proof using a provided key.
*
* @param _proof Inclusion proof to walk through.
* @param _key Key to use for the walk.
* @param _root Known root of the trie.
* @return _pathLength Length of the final path
* @return _keyRemainder Portion of the key remaining after the walk.
* @return _isFinalNode Whether or not we've hit a dead end.
*
* @return Length of the final path
* @return Portion of the key remaining after the walk.
* @return Whether or not we've hit a dead end.
*/
function _walkNodePath(
TrieNode[] memory _proof,
......@@ -120,9 +133,9 @@ library MerkleTrie {
private
pure
returns (
uint256 _pathLength,
bytes memory _keyRemainder,
bool _isFinalNode
uint256,
bytes memory,
bool
)
{
uint256 pathLength = 0;
......@@ -223,10 +236,12 @@ library MerkleTrie {
/**
* @notice Parses an RLP-encoded proof into something more useful.
*
* @param _proof RLP-encoded proof to parse.
* @return _parsed Proof parsed into easily accessible structs.
*
* @return Proof parsed into easily accessible structs.
*/
function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory _parsed) {
function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory) {
RLPReader.RLPItem[] memory nodes = RLPReader.readList(_proof);
TrieNode[] memory proof = new TrieNode[](nodes.length);
......@@ -239,13 +254,14 @@ library MerkleTrie {
}
/**
* @notice Picks out the ID for a node. Node ID is referred to as the
* "hash" within the specification, but nodes < 32 bytes are not actually
* hashed.
* @notice Picks out the ID for a node. Node ID is referred to as the "hash" within the
* specification, but nodes < 32 bytes are not actually hashed.
*
* @param _node Node to pull an ID for.
* @return _nodeID ID for the node, depending on the size of its contents.
*
* @return ID for the node, depending on the size of its contents.
*/
function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes32 _nodeID) {
function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes32) {
bytes memory nodeID;
if (_node.length < 32) {
......@@ -261,33 +277,38 @@ library MerkleTrie {
/**
* @notice Gets the path for a leaf or extension node.
*
* @param _node Node to get a path for.
* @return _path Node path, converted to an array of nibbles.
*
* @return Node path, converted to an array of nibbles.
*/
function _getNodePath(TrieNode memory _node) private pure returns (bytes memory _path) {
function _getNodePath(TrieNode memory _node) private pure returns (bytes memory) {
return BytesUtils.toNibbles(RLPReader.readBytes(_node.decoded[0]));
}
/**
* @notice Gets the path for a node.
*
* @param _node Node to get a value for.
* @return _value Node value, as hex bytes.
*
* @return Node value, as hex bytes.
*/
function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory _value) {
function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory) {
return RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]);
}
/**
* @notice Utility; determines the number of nibbles shared between two
* nibble arrays.
* @notice Utility; determines the number of nibbles shared between two nibble arrays.
*
* @param _a First nibble array.
* @param _b Second nibble array.
* @return _shared Number of shared nibbles.
*
* @return Number of shared nibbles.
*/
function _getSharedNibbleLength(bytes memory _a, bytes memory _b)
private
pure
returns (uint256 _shared)
returns (uint256)
{
uint256 i = 0;
while (_a.length > i && _b.length > i && _a[i] == _b[i]) {
......
......@@ -6,61 +6,60 @@ import { MerkleTrie } from "./MerkleTrie.sol";
/**
* @title SecureMerkleTrie
* @notice SecureMerkleTrie is a thin wrapper around the MerkleTrie library that hashes the input
* keys. Ethereum's state trie hashes input keys before storing them.
*/
library SecureMerkleTrie {
/**********************
* Internal Functions *
**********************/
/**
* @notice Verifies a proof that a given key/value pair is present in the
* Merkle trie.
* @notice Verifies a proof that a given key/value pair is present in the Merkle trie.
*
* @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike
* traditional Merkle trees, this proof is executed top-down and consists
* of a list of RLP-encoded nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle
* trees, this proof is executed top-down and consists of a list of RLP-encoded
* nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the included proof is
* correctly constructed.
*
* @return Whether or not the proof is valid.
*/
function verifyInclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _verified) {
) internal pure returns (bool) {
bytes memory key = _getSecureKey(_key);
return MerkleTrie.verifyInclusionProof(key, _value, _proof, _root);
}
/**
* @notice Retrieves the value associated with a given key.
*
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie.
* @return _exists Whether or not the key exists.
* @return _value Value of the key if it exists.
*
* @return Whether or not the key exists.
* @return Value of the key if it exists.
*/
function get(
bytes memory _key,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _exists, bytes memory _value) {
) internal pure returns (bool, bytes memory) {
bytes memory key = _getSecureKey(_key);
return MerkleTrie.get(key, _proof, _root);
}
/*********************
* Private Functions *
*********************/
/**
* Computes the secure counterpart to a key.
* @param _key Key to get a secure key from.
* @return _secureKey Secure version of the key.
* @notice Computes the hashed version of the input key.
*
* @param _key Key to hash.
*
* @return Hashed version of the key.
*/
function _getSecureKey(bytes memory _key) private pure returns (bytes memory _secureKey) {
function _getSecureKey(bytes memory _key) private pure returns (bytes memory) {
return abi.encodePacked(keccak256(_key));
}
}
......@@ -6,8 +6,29 @@ import { Encoding } from "../libraries/Encoding.sol";
contract Encoding_Test is CommonTest {
function test_nonceVersioning(uint240 _nonce, uint16 _version) external {
uint256 nonce = Encoding.addVersionToNonce(uint256(_nonce), _version);
uint16 version = Encoding.getVersionFromNonce(nonce);
(uint240 nonce, uint16 version) = Encoding.decodeVersionedNonce(
Encoding.encodeVersionedNonce(_nonce, _version)
);
assertEq(version, _version);
assertEq(nonce, _nonce);
}
function test_encodeDepositTransaction() external {
bytes memory raw = Encoding.encodeDepositTransaction(
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,
0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244,
0xde0b6b3a7640000,
0xe043da617250000,
0x2dc6c0,
false,
hex"",
0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959,
0x1
);
assertEq(
raw,
hex"7e00f862a0f923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc94f39fd6e51aad88f6f4ce6ab8827279cfffb9226694b79f76ef2c5f0286176833e7b2eee103b1cc3244880e043da617250000880de0b6b3a7640000832dc6c080"
);
}
}
......@@ -8,54 +8,29 @@ import { Encoding } from "../libraries/Encoding.sol";
contract Hashing_Test is CommonTest {
// TODO(tynes): turn this into differential fuzzing
// it is very easy to do so with the typescript
function test_l2TransactionHash() external {
bytes32 l1BlockHash = 0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959;
uint256 logIndex = 0x1;
address from = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address to = 0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244;
bool isCreate = false;
uint256 mint = 0xe043da617250000;
uint256 value = 0xde0b6b3a7640000;
uint256 gas = 0x2dc6c0;
bytes memory data = hex"";
bytes32 sourceHash = Hashing.sourceHash(
l1BlockHash,
logIndex
function test_hashDepositSource() external {
bytes32 sourceHash = Hashing.hashDepositSource(
0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959,
0x1
);
assertEq(
sourceHash,
0xf923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc
);
}
bytes memory raw = Encoding.L2Transaction(
l1BlockHash,
logIndex,
from,
to,
isCreate,
mint,
value,
gas,
data
);
assertEq(
raw,
hex"7e00f862a0f923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc94f39fd6e51aad88f6f4ce6ab8827279cfffb9226694b79f76ef2c5f0286176833e7b2eee103b1cc3244880e043da617250000880de0b6b3a7640000832dc6c080"
);
bytes32 digest = Hashing.L2TransactionHash(
l1BlockHash,
logIndex,
from,
to,
isCreate,
mint,
value,
gas,
data
function test_hashDepositTransaction() external {
bytes32 digest = Hashing.hashDepositTransaction(
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,
0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244,
0xde0b6b3a7640000,
0xe043da617250000,
0x2dc6c0,
false,
hex"",
0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959,
0x1
);
assertEq(
......
......@@ -56,8 +56,9 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
// the version is encoded in the nonce
function test_L1MessengerMessageVersion() external {
(,uint16 version) = Encoding.decodeVersionedNonce(L1Messenger.messageNonce());
assertEq(
Encoding.getVersionFromNonce(L1Messenger.messageNonce()),
version,
L1Messenger.MESSAGE_VERSION()
);
}
......@@ -75,7 +76,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
0,
100 + L1Messenger.baseGas(hex"ff"),
false,
Encoding.getVersionedEncoding(
Encoding.encodeCrossDomainMessage(
L1Messenger.messageNonce(),
alice,
recipient,
......@@ -95,7 +96,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
0,
100 + L1Messenger.baseGas(hex"ff"),
false,
Encoding.getVersionedEncoding(
Encoding.encodeCrossDomainMessage(
L1Messenger.messageNonce(),
alice,
recipient,
......@@ -145,7 +146,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
vm.expectEmit(true, true, true, true);
bytes32 hash = Hashing.getVersionedHash(0, sender, target, 0, 0, hex"1111");
bytes32 hash = Hashing.hashCrossDomainMessage(0, sender, target, 0, 0, hex"1111");
emit RelayedMessage(hash);
......
......@@ -31,8 +31,9 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer {
}
function test_L2MessengerMessageVersion() external {
(, uint16 version) = Encoding.decodeVersionedNonce(L2Messenger.messageNonce());
assertEq(
Encoding.getVersionFromNonce(L2Messenger.messageNonce()),
version,
L2Messenger.MESSAGE_VERSION()
);
}
......@@ -44,7 +45,7 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer {
L2ToL1MessagePasser.initiateWithdrawal.selector,
address(L1Messenger),
100 + L2Messenger.baseGas(hex"ff"),
Encoding.getVersionedEncoding(
Encoding.encodeCrossDomainMessage(
L2Messenger.messageNonce(),
alice,
recipient,
......@@ -63,7 +64,7 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer {
address(L1Messenger),
0,
100 + L2Messenger.baseGas(hex"ff"),
Encoding.getVersionedEncoding(
Encoding.encodeCrossDomainMessage(
L2Messenger.messageNonce(),
alice,
recipient,
......@@ -104,7 +105,7 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer {
vm.expectEmit(true, true, true, true);
bytes32 hash = Hashing.getVersionedHash(
bytes32 hash = Hashing.hashCrossDomainMessage(
0,
sender,
target,
......
......@@ -64,7 +64,7 @@ contract L2ToL1MessagePasserTest is CommonTest {
data
);
bytes32 withdrawalHash = Hashing.withdrawalHash(
bytes32 withdrawalHash = Hashing.hashWithdrawal(
nonce,
alice,
target,
......
......@@ -7,6 +7,10 @@ import { Proxy } from "../universal/Proxy.sol";
contract MeterUser is ResourceMetering {
constructor() {
initialize();
}
function initialize() public initializer {
__ResourceMetering_init();
}
......
......@@ -111,7 +111,7 @@ abstract contract CrossDomainMessenger is
* messageNonce getter which will insert the message version into the nonce to give you
* the actual nonce to be used for the message.
*/
uint256 internal msgNonce;
uint240 internal msgNonce;
/**
* @notice Address of the paired CrossDomainMessenger contract on the other chain.
......@@ -172,7 +172,7 @@ abstract contract CrossDomainMessenger is
* @return Nonce of the next message to be sent, with added message version.
*/
function messageNonce() public view returns (uint256) {
return Encoding.addVersionToNonce(msgNonce, MESSAGE_VERSION);
return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION);
}
/**
......@@ -250,7 +250,7 @@ abstract contract CrossDomainMessenger is
uint256 _minGasLimit,
bytes calldata _message
) external payable nonReentrant whenNotPaused {
bytes32 versionedHash = Hashing.getVersionedHash(
bytes32 versionedHash = Hashing.hashCrossDomainMessage(
_nonce,
_sender,
_target,
......
{
"name": "@eth-optimism/contracts-bedrock",
"version": "0.4.1",
"version": "0.5.0",
"description": "Contracts for Optimism Specs",
"main": "dist/index",
"types": "dist/index",
......@@ -34,7 +34,7 @@
"typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'"
},
"dependencies": {
"@eth-optimism/core-utils": "^0.9.0",
"@eth-optimism/core-utils": "^0.9.1",
"@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/contracts-upgradeable": "^4.5.2",
"@rari-capital/solmate": "https://github.com/rari-capital/solmate.git#8f9b23f8838670afda0fd8983f2c41e8037ae6bc",
......@@ -49,7 +49,7 @@
"rlp": "^2.2.7"
},
"devDependencies": {
"@eth-optimism/hardhat-deploy-config": "^0.2.0",
"@eth-optimism/hardhat-deploy-config": "^0.2.1",
"@defi-wonderland/smock": "^2.0.2",
"@foundry-rs/hardhat-forge": "^0.1.12",
"@nomiclabs/hardhat-ethers": "^2.0.0",
......
# @eth-optimism/contracts-governance
## 0.1.4
### Patch Changes
- dc9cf2b6: Clean up the hardhat config
- Updated dependencies [f9fee446]
- @eth-optimism/core-utils@0.9.1
- @eth-optimism/sdk@1.2.1
## 0.1.3
### Patch Changes
......
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.
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