Commit 7d6bfe20 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into aj/e2e-cleanup

parents a7b143c5 fc10d4a3
......@@ -53,7 +53,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -80,7 +80,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -107,7 +107,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -134,7 +134,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -161,7 +161,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -188,7 +188,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -226,7 +226,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......
......@@ -78,7 +78,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -115,7 +115,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -142,7 +142,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -169,7 +169,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -196,7 +196,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -223,7 +223,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......@@ -250,7 +250,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
......
......@@ -156,19 +156,21 @@ def devnet_l1_genesis(paths):
'--rpc.allow-unprotected-txs'
])
forge = ChildProcess(deploy_contracts, paths)
forge.start()
forge.join()
err = forge.get_error()
if err:
raise Exception(f"Exception occurred in child process: {err}")
res = debug_dumpBlock('127.0.0.1:8545')
response = json.loads(res)
allocs = response['result']
write_json(paths.allocs_path, allocs)
geth.terminate()
try:
forge = ChildProcess(deploy_contracts, paths)
forge.start()
forge.join()
err = forge.get_error()
if err:
raise Exception(f"Exception occurred in child process: {err}")
res = debug_dumpBlock('127.0.0.1:8545')
response = json.loads(res)
allocs = response['result']
write_json(paths.allocs_path, allocs)
finally:
geth.terminate()
# Bring up the devnet where the contracts are deployed to L1
......
......@@ -4,7 +4,6 @@ ignore:
- "**/*.t.sol"
- "op-bindings/bindings/*.go"
- "packages/contracts-bedrock/contracts/vendor/WETH9.sol"
- "packages/contracts-bedrock/contracts/cannon" # tested through Go tests
- 'packages/contracts-bedrock/contracts/EAS/**/*.sol'
coverage:
status:
......@@ -31,6 +30,5 @@ flag_management:
- name: common-ts-tests
- name: contracts-tests
- name: core-utils-tests
- name: dtl-tests
- name: chain-mon-tests
- name: sdk-tests
......@@ -35,7 +35,7 @@ func runIndexer(ctx *cli.Context) error {
return err
}
db, err := database.NewDB(cfg.DB)
db, err := database.NewDB(log, cfg.DB)
if err != nil {
log.Error("failed to connect to database", "err", err)
return err
......@@ -59,7 +59,7 @@ func runApi(ctx *cli.Context) error {
return err
}
db, err := database.NewDB(cfg.DB)
db, err := database.NewDB(log, cfg.DB)
if err != nil {
log.Error("failed to connect to database", "err", err)
return err
......@@ -79,7 +79,7 @@ func runMigrations(ctx *cli.Context) error {
return err
}
db, err := database.NewDB(cfg.DB)
db, err := database.NewDB(log, cfg.DB)
if err != nil {
log.Error("failed to connect to database", "err", err)
return err
......
......@@ -121,4 +121,52 @@ var Presets = map[int]Preset{
L1StartingHeight: 8942381,
},
},
11155420: {
Name: "OP Sepolia",
ChainConfig: ChainConfig{
Preset: 11155420,
L1Contracts: L1Contracts{
AddressManager: common.HexToAddress("0x9bFE9c5609311DF1c011c47642253B78a4f33F4B"),
SystemConfigProxy: common.HexToAddress("0x034edD2A225f7f429A63E0f1D2084B9E0A93b538"),
OptimismPortalProxy: common.HexToAddress("0x16Fc5058F25648194471939df75CF27A2fdC48BC"),
L2OutputOracleProxy: common.HexToAddress("0x90E9c4f8a994a250F6aEfd61CAFb4F2e895D458F"),
L1CrossDomainMessengerProxy: common.HexToAddress("0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef"),
L1StandardBridgeProxy: common.HexToAddress("0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1"),
L1ERC721BridgeProxy: common.HexToAddress("0xd83e03D576d23C9AEab8cC44Fa98d058D2176D1f"),
},
L1StartingHeight: 4071408,
},
},
424: {
Name: "PGN",
ChainConfig: ChainConfig{
Preset: 424,
L1Contracts: L1Contracts{
AddressManager: common.HexToAddress("0x09d5DbA52F0ee2C4A5E94FD5C802bD74Ca9cAD3e"),
SystemConfigProxy: common.HexToAddress("0x7Df716EAD1d83a2BF35B416B7BC84bd0700357C9"),
OptimismPortalProxy: common.HexToAddress("0xb26Fd985c5959bBB382BAFdD0b879E149e48116c"),
L2OutputOracleProxy: common.HexToAddress("0xA38d0c4E6319F9045F20318BA5f04CDe94208608"),
L1CrossDomainMessengerProxy: common.HexToAddress("0x97BAf688E5d0465E149d1d5B497Ca99392a6760e"),
L1StandardBridgeProxy: common.HexToAddress("0xD0204B9527C1bA7bD765Fa5CCD9355d38338272b"),
L1ERC721BridgeProxy: common.HexToAddress("0xaFF0F8aaB6Cc9108D34b3B8423C76d2AF434d115"),
},
L1StartingHeight: 17672702,
},
},
58008: {
Name: "PGN Sepolia",
ChainConfig: ChainConfig{
Preset: 58008,
L1Contracts: L1Contracts{
AddressManager: common.HexToAddress("0x0Ad91488288BBe60ff38258785568A6D1EB3B983"),
SystemConfigProxy: common.HexToAddress("0x4BCCC52151f0ad7C62D45Ce0aA77d9d8ffCE534e"),
OptimismPortalProxy: common.HexToAddress("0xF04BdD5353Bb0EFF6CA60CfcC78594278eBfE179"),
L2OutputOracleProxy: common.HexToAddress("0xD5bAc3152ffC25318F848B3DD5dA6C85171BaEEe"),
L1CrossDomainMessengerProxy: common.HexToAddress("0x97f3558Ce48FE71B8CeFA5497708A49531D5A8E1"),
L1StandardBridgeProxy: common.HexToAddress("0xFaE6abCAF30D23e233AC7faF747F2fC3a5a6Bfa3"),
L1ERC721BridgeProxy: common.HexToAddress("0xBA8397B6f255618D5985d0fB427D8c0496F3a5FA"),
},
L1StartingHeight: 17672702,
},
},
}
......@@ -12,9 +12,10 @@ import (
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/pkg/errors"
"github.com/ethereum/go-ethereum/log"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var (
......@@ -35,7 +36,7 @@ type DB struct {
BridgeTransactions BridgeTransactionsDB
}
func NewDB(dbConfig config.DBConfig) (*DB, error) {
func NewDB(log log.Logger, dbConfig config.DBConfig) (*DB, error) {
retryStrategy := &retry.ExponentialStrategy{Min: 1000, Max: 20_000, MaxJitter: 250}
dsn := fmt.Sprintf("host=%s dbname=%s sslmode=disable", dbConfig.Host, dbConfig.Name)
......@@ -52,21 +53,22 @@ func NewDB(dbConfig config.DBConfig) (*DB, error) {
gormConfig := gorm.Config{
// The indexer will explicitly manage the transactions
SkipDefaultTransaction: true,
Logger: logger.Default.LogMode(logger.Silent),
Logger: newLogger(log),
}
gorm, err := retry.Do[*gorm.DB](context.Background(), 10, retryStrategy, func() (*gorm.DB, error) {
gorm, err := gorm.Open(postgres.Open(dsn), &gormConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to connect to database")
return nil, fmt.Errorf("failed to connect to database: %w", err)
}
return gorm, nil
})
if err != nil {
return nil, errors.Wrap(err, "failed to connect to database after multiple retries")
return nil, fmt.Errorf("failed to connect to database after multiple retries: %w", err)
}
db := &DB{
gorm: gorm,
Blocks: newBlocksDB(gorm),
......@@ -75,6 +77,7 @@ func NewDB(dbConfig config.DBConfig) (*DB, error) {
BridgeMessages: newBridgeMessagesDB(gorm),
BridgeTransactions: newBridgeTransactionsDB(gorm),
}
return db, nil
}
......
package database
import (
"context"
"fmt"
"strings"
"time"
"github.com/ethereum/go-ethereum/log"
"gorm.io/gorm/logger"
)
var (
_ logger.Interface = Logger{}
SlowThresholdMilliseconds = 200
)
type Logger struct {
log log.Logger
}
func newLogger(log log.Logger) Logger {
return Logger{log.New("module", "db")}
}
func (l Logger) LogMode(lvl logger.LogLevel) logger.Interface {
return l
}
func (l Logger) Info(ctx context.Context, msg string, data ...interface{}) {
l.log.Info(fmt.Sprintf(msg, data...))
}
func (l Logger) Warn(ctx context.Context, msg string, data ...interface{}) {
l.log.Warn(fmt.Sprintf(msg, data...))
}
func (l Logger) Error(ctx context.Context, msg string, data ...interface{}) {
l.log.Error(fmt.Sprintf(msg, data...))
}
func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
elapsedMs := time.Since(begin).Milliseconds()
// omit any values for batch inserts as they can be very long
sql, rows := fc()
if i := strings.Index(strings.ToLower(sql), "values"); i > 0 {
sql = fmt.Sprintf("%sVALUES (...)", sql[:i])
}
if elapsedMs < 200 {
l.log.Debug("database operation", "duration_ms", elapsedMs, "rows_affected", rows, "sql", sql)
} else {
l.log.Warn("database operation", "duration_ms", elapsedMs, "rows_affected", rows, "sql", sql)
}
}
......@@ -86,7 +86,8 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
MetricsServer: config.ServerConfig{Host: "127.0.0.1", Port: 0},
}
db, err := database.NewDB(indexerCfg.DB)
// Emit debug log levels
db, err := database.NewDB(testlog.Logger(t, log.LvlDebug).New("role", "db"), indexerCfg.DB)
require.NoError(t, err)
t.Cleanup(func() { db.Close() })
......@@ -138,9 +139,13 @@ func setupTestDatabase(t *testing.T) string {
Password: "",
}
// NewDB will create the database schema
db, err := database.NewDB(dbConfig)
silentLog := log.New()
silentLog.SetHandler(log.DiscardHandler())
db, err := database.NewDB(silentLog, dbConfig)
require.NoError(t, err)
defer db.Close()
err = db.ExecuteSQLMigration("../migrations")
require.NoError(t, err)
......
# Chain configures l1 chain addresses
# Can configure them manually or use a preset l2 ChainId for known chains including OP Mainnet, OP Goerli, Base, Base Goerli, Zora, and Zora goerli
# Can configure them manually or use a preset L2 ChainId for known chains
# - i.e OP Mainnet, OP Goerli, Base, Base Goerli, Zora, Zora Goerli, etc
[chain]
preset = $INDEXER_CHAIN_PRESET
# L1 Config
......@@ -15,17 +15,12 @@ l2-polling-interval = 0
l2-header-buffer-size = 0
l2-confirmation-depth = 0
[rpcs]
l1-rpc = "${INDEXER_RPC_URL_L1}"
l2-rpc = "${INDEXER_RPC_URL_L2}"
[db]
host = "$INDEXER_DB_HOST"
# this port may be problematic once we depoly
# the DATABASE_URL looks like this for previous services and didn't include a port
# DATABASE_URL="postgresql://${INDEXER_DB_USER}:${INDEXER_DB_PASS}@localhost/${INDEXER_DB_NAME}?host=${INDEXER_DB_HOST}"
# If not problematic delete these comments
port = $INDEXER_DB_PORT
user = "$INDEXER_DB_USER"
password = "$INDEXER_DB_PASS"
......
{
"npmClient": "pnpm",
"useWorkspaces": true,
"version": "independent",
"packages": [
"packages/*"
]
}
......@@ -109,6 +109,9 @@ type DeployConfig struct {
// L2GenesisRegolithTimeOffset is the number of seconds after genesis block that Regolith hard fork activates.
// Set it to 0 to activate at genesis. Nil to disable regolith.
L2GenesisRegolithTimeOffset *hexutil.Uint64 `json:"l2GenesisRegolithTimeOffset,omitempty"`
// L2GenesisSpanBatchTimeOffset is the number of seconds after genesis block that Span Batch hard fork activates.
// Set it to 0 to activate at genesis. Nil to disable SpanBatch.
L2GenesisSpanBatchTimeOffset *hexutil.Uint64 `json:"l2GenesisSpanBatchTimeOffset,omitempty"`
// L2GenesisBlockExtraData is configurable extradata. Will default to []byte("BEDROCK") if left unspecified.
L2GenesisBlockExtraData []byte `json:"l2GenesisBlockExtraData"`
// ProxyAdminOwner represents the owner of the ProxyAdmin predeploy on L2.
......@@ -441,6 +444,17 @@ func (d *DeployConfig) RegolithTime(genesisTime uint64) *uint64 {
return &v
}
func (d *DeployConfig) SpanBatchTime(genesisTime uint64) *uint64 {
if d.L2GenesisSpanBatchTimeOffset == nil {
return nil
}
v := uint64(0)
if offset := *d.L2GenesisSpanBatchTimeOffset; offset > 0 {
v = genesisTime + uint64(offset)
}
return &v
}
// RollupConfig converts a DeployConfig to a rollup.Config
func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHash common.Hash, l2GenesisBlockNumber uint64) (*rollup.Config, error) {
if d.OptimismPortalProxy == (common.Address{}) {
......@@ -478,6 +492,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHas
DepositContractAddress: d.OptimismPortalProxy,
L1SystemConfigAddress: d.SystemConfigProxy,
RegolithTime: d.RegolithTime(l1StartBlock.Time()),
SpanBatchTime: d.SpanBatchTime(l1StartBlock.Time()),
}, nil
}
......
......@@ -30,7 +30,6 @@ type ClaimLoader interface {
type Agent struct {
metrics metrics.Metricer
fdgAddr common.Address
solver *solver.GameSolver
loader ClaimLoader
responder Responder
......@@ -40,10 +39,9 @@ type Agent struct {
log log.Logger
}
func NewAgent(m metrics.Metricer, addr common.Address, loader ClaimLoader, maxDepth int, trace types.TraceProvider, responder Responder, updater types.OracleUpdater, agreeWithProposedOutput bool, log log.Logger) *Agent {
func NewAgent(m metrics.Metricer, loader ClaimLoader, maxDepth int, trace types.TraceProvider, responder Responder, updater types.OracleUpdater, agreeWithProposedOutput bool, log log.Logger) *Agent {
return &Agent{
metrics: m,
fdgAddr: addr,
solver: solver.NewGameSolver(maxDepth, trace),
loader: loader,
responder: responder,
......@@ -198,7 +196,6 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (types.Game, error) {
if len(claims) == 0 {
return nil, errors.New("no claims")
}
a.metrics.RecordGameClaimCount(a.fdgAddr.String(), len(claims))
game := types.NewGameState(a.agreeWithProposedOutput, claims[0], uint64(a.maxDepth))
if err := game.PutAll(claims[1:]); err != nil {
return nil, fmt.Errorf("failed to load claims into the local state: %w", err)
......
......@@ -10,11 +10,10 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/testlog"
)
// TestShouldResolve tests the resolution logic.
......@@ -111,12 +110,11 @@ func TestLoadClaimsWhenGameNotResolvable(t *testing.T) {
func setupTestAgent(t *testing.T, agreeWithProposedOutput bool) (*Agent, *stubClaimLoader, *stubResponder) {
logger := testlog.Logger(t, log.LvlInfo)
claimLoader := &stubClaimLoader{}
addr := common.HexToAddress("0x1234")
depth := 4
trace := alphabet.NewTraceProvider("abcd", uint64(depth))
responder := &stubResponder{}
updater := &stubUpdater{}
agent := NewAgent(metrics.NoopMetrics, addr, claimLoader, depth, trace, responder, updater, agreeWithProposedOutput, logger)
agent := NewAgent(metrics.NoopMetrics, claimLoader, depth, trace, responder, updater, agreeWithProposedOutput, logger)
return agent, claimLoader, responder
}
......
......@@ -106,7 +106,7 @@ func NewGamePlayer(
}
return &GamePlayer{
act: NewAgent(m, addr, loader, int(gameDepth), provider, responder, updater, cfg.AgreeWithProposedOutput, logger).Act,
act: NewAgent(m, loader, int(gameDepth), provider, responder, updater, cfg.AgreeWithProposedOutput, logger).Act,
agreeWithProposedOutput: cfg.AgreeWithProposedOutput,
loader: loader,
logger: logger,
......
......@@ -25,8 +25,6 @@ type Metricer interface {
RecordGameMove()
RecordCannonExecutionTime(t float64)
RecordGameClaimCount(addr string, count int)
RecordGamesStatus(inProgress, defenderWon, challengerWon int)
RecordGameUpdateScheduled()
......@@ -55,8 +53,6 @@ type Metrics struct {
cannonExecutionTime prometheus.Histogram
gameClaimCount prometheus.GaugeVec
trackedGames prometheus.GaugeVec
inflightGames prometheus.Gauge
}
......@@ -111,13 +107,6 @@ func NewMetrics() *Metrics {
[]float64{1.0, 10.0},
prometheus.ExponentialBuckets(30.0, 2.0, 14)...),
}),
gameClaimCount: *factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "game_claim_count",
Help: "Number of claims in the game",
}, []string{
"game_address",
}),
trackedGames: *factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "tracked_games",
......@@ -190,10 +179,6 @@ func (m *Metrics) DecIdleExecutors() {
m.executors.WithLabelValues("idle").Dec()
}
func (m *Metrics) RecordGameClaimCount(addr string, count int) {
m.gameClaimCount.With(prometheus.Labels{"game_address": addr}).Set(float64(count))
}
func (m *Metrics) RecordGamesStatus(inProgress, defenderWon, challengerWon int) {
m.trackedGames.WithLabelValues("in_progress").Set(float64(inProgress))
m.trackedGames.WithLabelValues("defender_won").Set(float64(defenderWon))
......
......@@ -27,5 +27,3 @@ func (*NoopMetricsImpl) IncActiveExecutors() {}
func (*NoopMetricsImpl) DecActiveExecutors() {}
func (*NoopMetricsImpl) IncIdleExecutors() {}
func (*NoopMetricsImpl) DecIdleExecutors() {}
func (*NoopMetricsImpl) RecordGameClaimCount(addr string, count int) {}
......@@ -58,6 +58,7 @@ func MakeDeployParams(t require.TestingT, tp *TestParams) *DeployParams {
deployConfig.ChannelTimeout = tp.ChannelTimeout
deployConfig.L1BlockTime = tp.L1BlockTime
deployConfig.L2GenesisRegolithTimeOffset = nil
deployConfig.L2GenesisSpanBatchTimeOffset = SpanBatchTimeOffset()
require.NoError(t, deployConfig.Check())
require.Equal(t, addresses.Batcher, deployConfig.BatchSenderAddress)
......@@ -156,6 +157,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
DepositContractAddress: deployConf.OptimismPortalProxy,
L1SystemConfigAddress: deployConf.SystemConfigProxy,
RegolithTime: deployConf.RegolithTime(uint64(deployConf.L1GenesisBlockTimestamp)),
SpanBatchTime: deployConf.SpanBatchTime(uint64(deployConf.L1GenesisBlockTimestamp)),
}
require.NoError(t, rollupCfg.Check())
......@@ -181,3 +183,11 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System
GasLimit: uint64(deployConfig.L2GenesisBlockGasLimit),
}
}
func SpanBatchTimeOffset() *hexutil.Uint64 {
if os.Getenv("OP_E2E_USE_SPAN_BATCH") == "true" {
offset := hexutil.Uint64(0)
return &offset
}
return nil
}
......@@ -85,6 +85,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
require.NoError(t, err)
deployConfig := config.DeployConfig.Copy()
deployConfig.L1GenesisBlockTimestamp = hexutil.Uint64(time.Now().Unix())
deployConfig.L2GenesisSpanBatchTimeOffset = e2eutils.SpanBatchTimeOffset()
require.NoError(t, deployConfig.Check(), "Deploy config is invalid, do you need to run make devnet-allocs?")
l1Deployments := config.L1Deployments.Copy()
require.NoError(t, l1Deployments.Check())
......@@ -418,6 +419,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
DepositContractAddress: cfg.DeployConfig.OptimismPortalProxy,
L1SystemConfigAddress: cfg.DeployConfig.SystemConfigProxy,
RegolithTime: cfg.DeployConfig.RegolithTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
SpanBatchTime: cfg.DeployConfig.SpanBatchTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy,
}
}
......
package metrics
import (
"fmt"
"time"
"github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/prometheus/client_golang/prometheus"
)
type EventMetrics struct {
Total prometheus.Counter
LastTime prometheus.Gauge
}
func (e *EventMetrics) RecordEvent() {
e.Total.Inc()
e.LastTime.Set(float64(time.Now().Unix()))
}
func NewEventMetrics(factory metrics.Factory, ns string, name string, displayName string) *EventMetrics {
return &EventMetrics{
Total: factory.NewCounter(prometheus.CounterOpts{
Namespace: ns,
Name: fmt.Sprintf("%s_total", name),
Help: fmt.Sprintf("Count of %s events", displayName),
}),
LastTime: factory.NewGauge(prometheus.GaugeOpts{
Namespace: ns,
Name: fmt.Sprintf("last_%s_unix", name),
Help: fmt.Sprintf("Timestamp of last %s event", displayName),
}),
}
}
......@@ -3,7 +3,6 @@ package metrics
import (
"context"
"encoding/binary"
"errors"
"fmt"
"net"
......@@ -50,7 +49,7 @@ type Metricer interface {
RecordPublishingError()
RecordDerivationError()
RecordReceivedUnsafePayload(payload *eth.ExecutionPayload)
recordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash)
RecordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash)
RecordL1Ref(name string, ref eth.L1BlockRef)
RecordL2Ref(name string, ref eth.L2BlockRef)
RecordUnsafePayloadsBuffer(length uint64, memSize uint64, next eth.BlockID)
......@@ -99,11 +98,11 @@ type Metrics struct {
DerivationIdle prometheus.Gauge
PipelineResets *EventMetrics
UnsafePayloads *EventMetrics
DerivationErrors *EventMetrics
SequencingErrors *EventMetrics
PublishingErrors *EventMetrics
PipelineResets *metrics.Event
UnsafePayloads *metrics.Event
DerivationErrors *metrics.Event
SequencingErrors *metrics.Event
PublishingErrors *metrics.Event
P2PReqDurationSeconds *prometheus.HistogramVec
P2PReqTotal *prometheus.CounterVec
......@@ -111,8 +110,8 @@ type Metrics struct {
PayloadsQuarantineTotal prometheus.Gauge
SequencerInconsistentL1Origin *EventMetrics
SequencerResets *EventMetrics
SequencerInconsistentL1Origin *metrics.Event
SequencerResets *metrics.Event
L1RequestDurationSeconds *prometheus.HistogramVec
......@@ -125,23 +124,16 @@ type Metrics struct {
UnsafePayloadsBufferLen prometheus.Gauge
UnsafePayloadsBufferMemSize prometheus.Gauge
RefsNumber *prometheus.GaugeVec
RefsTime *prometheus.GaugeVec
RefsHash *prometheus.GaugeVec
RefsSeqNr *prometheus.GaugeVec
RefsLatency *prometheus.GaugeVec
// hash of the last seen block per name, so we don't reduce/increase latency on updates of the same data,
// and only count the first occurrence
LatencySeen map[string]common.Hash
metrics.RefMetrics
L1ReorgDepth prometheus.Histogram
TransactionsSequencedTotal prometheus.Counter
// Channel Bank Metrics
headChannelOpenedEvent *EventMetrics
channelTimedOutEvent *EventMetrics
frameAddedEvent *EventMetrics
headChannelOpenedEvent *metrics.Event
channelTimedOutEvent *metrics.Event
frameAddedEvent *metrics.Event
// P2P Metrics
PeerCount prometheus.Gauge
......@@ -247,14 +239,14 @@ func NewMetrics(procName string) *Metrics {
Help: "1 if the derivation pipeline is idle",
}),
PipelineResets: NewEventMetrics(factory, ns, "pipeline_resets", "derivation pipeline resets"),
UnsafePayloads: NewEventMetrics(factory, ns, "unsafe_payloads", "unsafe payloads"),
DerivationErrors: NewEventMetrics(factory, ns, "derivation_errors", "derivation errors"),
SequencingErrors: NewEventMetrics(factory, ns, "sequencing_errors", "sequencing errors"),
PublishingErrors: NewEventMetrics(factory, ns, "publishing_errors", "p2p publishing errors"),
PipelineResets: metrics.NewEvent(factory, ns, "", "pipeline_resets", "derivation pipeline resets"),
UnsafePayloads: metrics.NewEvent(factory, ns, "", "unsafe_payloads", "unsafe payloads"),
DerivationErrors: metrics.NewEvent(factory, ns, "", "derivation_errors", "derivation errors"),
SequencingErrors: metrics.NewEvent(factory, ns, "", "sequencing_errors", "sequencing errors"),
PublishingErrors: metrics.NewEvent(factory, ns, "", "publishing_errors", "p2p publishing errors"),
SequencerInconsistentL1Origin: NewEventMetrics(factory, ns, "sequencer_inconsistent_l1_origin", "events when the sequencer selects an inconsistent L1 origin"),
SequencerResets: NewEventMetrics(factory, ns, "sequencer_resets", "sequencer resets"),
SequencerInconsistentL1Origin: metrics.NewEvent(factory, ns, "", "sequencer_inconsistent_l1_origin", "events when the sequencer selects an inconsistent L1 origin"),
SequencerResets: metrics.NewEvent(factory, ns, "", "sequencer_resets", "sequencer resets"),
UnsafePayloadsBufferLen: factory.NewGauge(prometheus.GaugeOpts{
Namespace: ns,
......@@ -267,46 +259,7 @@ func NewMetrics(procName string) *Metrics {
Help: "Total estimated memory size of buffered L2 unsafe payloads",
}),
RefsNumber: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Name: "refs_number",
Help: "Gauge representing the different L1/L2 reference block numbers",
}, []string{
"layer",
"type",
}),
RefsTime: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Name: "refs_time",
Help: "Gauge representing the different L1/L2 reference block timestamps",
}, []string{
"layer",
"type",
}),
RefsHash: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Name: "refs_hash",
Help: "Gauge representing the different L1/L2 reference block hashes truncated to float values",
}, []string{
"layer",
"type",
}),
RefsSeqNr: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Name: "refs_seqnr",
Help: "Gauge representing the different L2 reference sequence numbers",
}, []string{
"type",
}),
RefsLatency: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Name: "refs_latency",
Help: "Gauge representing the different L1/L2 reference block timestamps minus current time, in seconds",
}, []string{
"layer",
"type",
}),
LatencySeen: make(map[string]common.Hash),
RefMetrics: metrics.MakeRefMetrics(ns, factory),
L1ReorgDepth: factory.NewHistogram(prometheus.HistogramOpts{
Namespace: ns,
......@@ -380,9 +333,9 @@ func NewMetrics(procName string) *Metrics {
Help: "Count of incoming dial attempts to accept, with label to filter to allowed attempts",
}, []string{"allow"}),
headChannelOpenedEvent: NewEventMetrics(factory, ns, "head_channel", "New channel at the front of the channel bank"),
channelTimedOutEvent: NewEventMetrics(factory, ns, "channel_timeout", "Channel has timed out"),
frameAddedEvent: NewEventMetrics(factory, ns, "frame_added", "New frame ingested in the channel bank"),
headChannelOpenedEvent: metrics.NewEvent(factory, ns, "", "head_channel", "New channel at the front of the channel bank"),
channelTimedOutEvent: metrics.NewEvent(factory, ns, "", "channel_timeout", "Channel has timed out"),
frameAddedEvent: metrics.NewEvent(factory, ns, "", "frame_added", "New frame ingested in the channel bank"),
ChannelInputBytes: factory.NewCounter(prometheus.CounterOpts{
Namespace: ns,
......@@ -570,53 +523,28 @@ func (m *Metrics) SetDerivationIdle(status bool) {
}
func (m *Metrics) RecordPipelineReset() {
m.PipelineResets.RecordEvent()
m.PipelineResets.Record()
}
func (m *Metrics) RecordSequencingError() {
m.SequencingErrors.RecordEvent()
m.SequencingErrors.Record()
}
func (m *Metrics) RecordPublishingError() {
m.PublishingErrors.RecordEvent()
m.PublishingErrors.Record()
}
func (m *Metrics) RecordDerivationError() {
m.DerivationErrors.RecordEvent()
m.DerivationErrors.Record()
}
func (m *Metrics) RecordReceivedUnsafePayload(payload *eth.ExecutionPayload) {
m.UnsafePayloads.RecordEvent()
m.recordRef("l2", "received_payload", uint64(payload.BlockNumber), uint64(payload.Timestamp), payload.BlockHash)
}
func (m *Metrics) recordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash) {
m.RefsNumber.WithLabelValues(layer, name).Set(float64(num))
if timestamp != 0 {
m.RefsTime.WithLabelValues(layer, name).Set(float64(timestamp))
// only meter the latency when we first see this hash for the given label name
if m.LatencySeen[name] != h {
m.LatencySeen[name] = h
m.RefsLatency.WithLabelValues(layer, name).Set(float64(timestamp) - (float64(time.Now().UnixNano()) / 1e9))
}
}
// we map the first 8 bytes to a float64, so we can graph changes of the hash to find divergences visually.
// We don't do math.Float64frombits, just a regular conversion, to keep the value within a manageable range.
m.RefsHash.WithLabelValues(layer, name).Set(float64(binary.LittleEndian.Uint64(h[:])))
}
func (m *Metrics) RecordL1Ref(name string, ref eth.L1BlockRef) {
m.recordRef("l1", name, ref.Number, ref.Time, ref.Hash)
}
func (m *Metrics) RecordL2Ref(name string, ref eth.L2BlockRef) {
m.recordRef("l2", name, ref.Number, ref.Time, ref.Hash)
m.recordRef("l1_origin", name, ref.L1Origin.Number, 0, ref.L1Origin.Hash)
m.RefsSeqNr.WithLabelValues(name).Set(float64(ref.SequenceNumber))
m.UnsafePayloads.Record()
m.RecordRef("l2", "received_payload", uint64(payload.BlockNumber), uint64(payload.Timestamp), payload.BlockHash)
}
func (m *Metrics) RecordUnsafePayloadsBuffer(length uint64, memSize uint64, next eth.BlockID) {
m.recordRef("l2", "l2_buffer_unsafe", next.Number, 0, next.Hash)
m.RecordRef("l2", "l2_buffer_unsafe", next.Number, 0, next.Hash)
m.UnsafePayloadsBufferLen.Set(float64(length))
m.UnsafePayloadsBufferMemSize.Set(float64(memSize))
}
......@@ -630,13 +558,13 @@ func (m *Metrics) RecordL1ReorgDepth(d uint64) {
}
func (m *Metrics) RecordSequencerInconsistentL1Origin(from eth.BlockID, to eth.BlockID) {
m.SequencerInconsistentL1Origin.RecordEvent()
m.recordRef("l1_origin", "inconsistent_from", from.Number, 0, from.Hash)
m.recordRef("l1_origin", "inconsistent_to", to.Number, 0, to.Hash)
m.SequencerInconsistentL1Origin.Record()
m.RecordRef("l1_origin", "inconsistent_from", from.Number, 0, from.Hash)
m.RecordRef("l1_origin", "inconsistent_to", to.Number, 0, to.Hash)
}
func (m *Metrics) RecordSequencerReset() {
m.SequencerResets.RecordEvent()
m.SequencerResets.Record()
}
func (m *Metrics) RecordGossipEvent(evType int32) {
......@@ -740,15 +668,15 @@ func (m *Metrics) RecordChannelInputBytes(inputCompressedBytes int) {
}
func (m *Metrics) RecordHeadChannelOpened() {
m.headChannelOpenedEvent.RecordEvent()
m.headChannelOpenedEvent.Record()
}
func (m *Metrics) RecordChannelTimedOut() {
m.channelTimedOutEvent.RecordEvent()
m.channelTimedOutEvent.Record()
}
func (m *Metrics) RecordFrame() {
m.frameAddedEvent.RecordEvent()
m.frameAddedEvent.Record()
}
func (m *Metrics) RecordPeerUnban() {
......@@ -821,7 +749,7 @@ func (n *noopMetricer) RecordDerivationError() {
func (n *noopMetricer) RecordReceivedUnsafePayload(payload *eth.ExecutionPayload) {
}
func (n *noopMetricer) recordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash) {
func (n *noopMetricer) RecordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash) {
}
func (n *noopMetricer) RecordL1Ref(name string, ref eth.L1BlockRef) {
......
......@@ -79,6 +79,8 @@ type Config struct {
// Active if CanyonTime != nil && L2 block timestamp >= *CanyonTime, inactive otherwise.
CanyonTime *uint64 `json:"canyon_time,omitempty"`
SpanBatchTime *uint64 `json:"span_batch_time,omitempty"`
// Note: below addresses are part of the block-derivation process,
// and required to be the same network-wide to stay in consensus.
......@@ -268,6 +270,10 @@ func (c *Config) IsCanyon(timestamp uint64) bool {
return c.CanyonTime != nil && timestamp >= *c.CanyonTime
}
func (c *Config) IsSpanBatch(timestamp uint64) bool {
return c.SpanBatchTime != nil && timestamp >= *c.SpanBatchTime
}
// Description outputs a banner describing the important parts of rollup configuration in a human-readable form.
// Optionally provide a mapping of L2 chain IDs to network names to label the L2 chain with if not unknown.
// The config should be config.Check()-ed before creating a description.
......@@ -296,6 +302,7 @@ func (c *Config) Description(l2Chains map[string]string) string {
banner += "Post-Bedrock Network Upgrades (timestamp based):\n"
banner += fmt.Sprintf(" - Regolith: %s\n", fmtForkTimeOrUnset(c.RegolithTime))
banner += fmt.Sprintf(" - Canyon: %s\n", fmtForkTimeOrUnset(c.CanyonTime))
banner += fmt.Sprintf(" - SpanBatch: %s\n", fmtForkTimeOrUnset(c.SpanBatchTime))
// Report the protocol version
banner += fmt.Sprintf("Node supports up to OP-Stack Protocol Version: %s\n", OPStackSupport)
return banner
......@@ -321,7 +328,9 @@ func (c *Config) LogDescription(log log.Logger, l2Chains map[string]string) {
"l1_network", networkL1, "l2_start_time", c.Genesis.L2Time, "l2_block_hash", c.Genesis.L2.Hash.String(),
"l2_block_number", c.Genesis.L2.Number, "l1_block_hash", c.Genesis.L1.Hash.String(),
"l1_block_number", c.Genesis.L1.Number, "regolith_time", fmtForkTimeOrUnset(c.RegolithTime),
"canyon_time", fmtForkTimeOrUnset(c.CanyonTime))
"canyon_time", fmtForkTimeOrUnset(c.CanyonTime),
"span_batch_time", fmtForkTimeOrUnset(c.SpanBatchTime),
)
}
func fmtForkTimeOrUnset(v *uint64) string {
......
......@@ -16,8 +16,8 @@ func (e *Event) Record() {
e.LastTime.SetToCurrentTime()
}
func NewEvent(factory Factory, ns string, subsystem string, name string, displayName string) Event {
return Event{
func NewEvent(factory Factory, ns string, subsystem string, name string, displayName string) *Event {
return &Event{
Total: factory.NewCounter(prometheus.CounterOpts{
Namespace: ns,
Name: fmt.Sprintf("%s_total", name),
......
......@@ -27,7 +27,7 @@ type TxMetrics struct {
currentNonce prometheus.Gauge
pendingTxs prometheus.Gauge
txPublishError *prometheus.CounterVec
publishEvent metrics.Event
publishEvent *metrics.Event
confirmEvent metrics.EventVec
rpcError prometheus.Counter
}
......
......@@ -43,6 +43,7 @@
"eip1559Elasticity": 6,
"l1GenesisBlockTimestamp": "0x64c811bf",
"l2GenesisRegolithTimeOffset": "0x0",
"l2GenesisSpanBatchTimeOffset": "0x0",
"faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 30,
"faultGameMaxDuration": 1200,
......
......@@ -254,8 +254,15 @@ the potential opponent's chess clock has run out. Because each claim is the root
truth percolates upwards towards the root claim by resolving each individual sub-game bottom-up.
In a game like the one below, we can resolve up from the deepest subgames. Here, we'd resolve `b0`
to uncountered and `a0` to countered by walking up from their deepest children, and now that all children of the
root game are resolved, we can resolve the root to countered due to `b0` remaining uncountered.
to uncountered and `a0` to countered by walking up from their deepest children, and once all children of the
root game are recursively resolved, we can resolve the root to countered due to `b0` remaining uncountered.
<!-- https://gist.github.com/clabby/e98bdd80ef3c038424f3372b70e34e08 -->
<!-- markdownlint-disable no-inline-html -->
<https://github.com/ethereum-optimism/optimism/assets/8406232/d2b708a0-539e-439d-96bd-c2f66f3a45f8>
Another example is this game, which has a slightly different structure. Here, the root claim will also
be countered due to `b0` remaining uncountered.
<!--
digraph G {
......@@ -275,7 +282,6 @@ digraph G {
key:i1:e -> key2:i1:w [color=green]
key:i2:e -> key2:i2:w [color=coral1, style=dotted]
}
subgraph cluster_0 {
color=cornflowerblue;
node [style=filled];
......@@ -284,37 +290,28 @@ digraph G {
subgraph cluster_0_0 {
label = "subgame #5";
color=purple;
a1 -> a2 [color=green];
a2 -> a1 [color=coral1, style=dotted];
subgraph cluster_0_1 {
label = "subgame #6";
color=magenta;
a2 -> a3 [color=green];
a3 -> a2 [color=coral1, style=dotted];
a2 -> a4 [color=green];
a4 -> a2 [color=coral1, style=dotted];
subgraph cluster_0_2 {
label = "subgame #7";
color=lightpink;
a3
}
subgraph cluster_0_3 {
label = "subgame #8";
color=lightpink;
a4 -> a5 [color=green];
a5 -> a4 [color=coral1, style=dotted];
subgraph cluster_0_4 {
label = "subgame #9";
color=palegreen;
a5
}
}
......@@ -322,40 +319,33 @@ digraph G {
}
label = "subgame #4";
}
subgraph cluster_1 {
node [style=filled];
label = "subgame #1";
color=cornflowerblue
b0 -> b1 [color=green];
b1 -> b0 [color=coral1, style=dotted];
subgraph cluster_1_0 {
label = "subgame #2";
color=purple;
b1 -> b2 [color=green];
b2 -> b1 [color=coral1, style=dotted];
subgraph cluster_1_1 {
label = "subgame #3";
edge [style=invis]
color=magenta;
b2
}
}
}
Root -> a0 [color=green];
Root -> b0 [color=green];
a0 -> Root [color=coral1, style=dotted];
b0 -> Root [color=coral1, style=dotted];
Root [shape=Mdiamond];
}
-->
<!-- markdownlint-disable no-inline-html -->
<p align="center">
<img src="https://github.com/ethereum-optimism/optimism/assets/8406232/9b20ba8d-0b64-47b3-9962-5533f7eb4ef7" width=60%>
......
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