Commit 48a146d7 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into inphi/fdg-rez

parents 7fefff6e 8d8b6703
...@@ -2,10 +2,13 @@ ...@@ -2,10 +2,13 @@
package database package database
import ( import (
"context"
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/indexer/config" "github.com/ethereum-optimism/optimism/indexer/config"
_ "github.com/ethereum-optimism/optimism/indexer/database/serializers" _ "github.com/ethereum-optimism/optimism/indexer/database/serializers"
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/pkg/errors"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
"gorm.io/gorm" "gorm.io/gorm"
...@@ -31,6 +34,8 @@ type DB struct { ...@@ -31,6 +34,8 @@ type DB struct {
} }
func NewDB(dbConfig config.DBConfig) (*DB, error) { func NewDB(dbConfig config.DBConfig) (*DB, error) {
retryStrategy := &retry.ExponentialStrategy{Min: 1000, Max: 20_000, MaxJitter: 250}
dsn := fmt.Sprintf("host=%s port=%d dbname=%s sslmode=disable", dbConfig.Host, dbConfig.Port, dbConfig.Name) dsn := fmt.Sprintf("host=%s port=%d dbname=%s sslmode=disable", dbConfig.Host, dbConfig.Port, dbConfig.Name)
if dbConfig.User != "" { if dbConfig.User != "" {
dsn += fmt.Sprintf(" user=%s", dbConfig.User) dsn += fmt.Sprintf(" user=%s", dbConfig.User)
...@@ -38,17 +43,24 @@ func NewDB(dbConfig config.DBConfig) (*DB, error) { ...@@ -38,17 +43,24 @@ func NewDB(dbConfig config.DBConfig) (*DB, error) {
if dbConfig.Password != "" { if dbConfig.Password != "" {
dsn += fmt.Sprintf(" password=%s", dbConfig.Password) dsn += fmt.Sprintf(" password=%s", dbConfig.Password)
} }
gorm, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
gormConfig := gorm.Config{
// The indexer will explicitly manage the transactions // The indexer will explicitly manage the transactions
SkipDefaultTransaction: true, SkipDefaultTransaction: true,
Logger: logger.Default.LogMode(logger.Silent),
}
gorm, err := retry.Do[*gorm.DB](context.Background(), 10, retryStrategy, func() (*gorm.DB, error) {
gorm, err := gorm.Open(postgres.Open(dsn), &gormConfig)
// We may choose to create an adapter such that the if err != nil {
// logger emits to the geth logger when on DEBUG mode return nil, errors.Wrap(err, "failed to connect to database")
Logger: logger.Default.LogMode(logger.Silent), }
return gorm, nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to connect to database after multiple retries")
} }
db := &DB{ db := &DB{
......
...@@ -38,5 +38,6 @@ ...@@ -38,5 +38,6 @@
"SchemaRegistry", "SchemaRegistry",
"ProtocolVersions", "ProtocolVersions",
"Safe", "Safe",
"SafeProxyFactory" "SafeProxyFactory",
"DelayedVetoable"
] ]
This diff is collapsed.
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"encoding/json"
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const DelayedVetoableStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"src/L1/DelayedVetoable.sol:DelayedVetoable\",\"label\":\"_delay\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint256\"},{\"astId\":1001,\"contract\":\"src/L1/DelayedVetoable.sol:DelayedVetoable\",\"label\":\"_queuedAt\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_bytes32,t_uint256)\"}],\"types\":{\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var DelayedVetoableStorageLayout = new(solc.StorageLayout)
var DelayedVetoableDeployedBin = "0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063b912de5d11610050578063b912de5d14610111578063d4b8399214610124578063d8bff4401461012c57610072565b806354fd4d501461007c5780635c39fcc1146100ce5780636a42b8f8146100fb575b61007a610134565b005b6100b86040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516100c591906106a7565b60405180910390f35b6100d66104fb565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c5565b610103610532565b6040519081526020016100c5565b61010361011f36600461071a565b610540565b6100d6610567565b6100d6610593565b361580156101425750600054155b15610298573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015906101c357503373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614155b1561023d576040517f295a81c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660048201523360248201526044015b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000060008190556040519081527febf28bfb587e28dfffd9173cf71c32ba5d3f0544a0117b5539c9b274a5bba2a89060200160405180910390a1565b600080366040516102aa929190610733565b60405190819003902090503373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480156103065750600081815260016020526040902054155b1561036c5760005460000361031e5761031e816105bf565b6000818152600160205260408082204290555182917f87a332a414acbc7da074543639ce7ae02ff1ea72e88379da9f261b080beb5a139161036191903690610743565b60405180910390a250565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480156103be575060008181526001602052604090205415155b15610406576000818152600160205260408082208290555182917fbede6852c1d97d93ff557f676de76670cd0dec861e7fe8beb13aa0ba2b0ab0409161036191903690610743565b600081815260016020526040812054900361048b576040517f295a81c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166004820152336024820152604401610234565b60008054828252600160205260409091205442916104a891610790565b10156104e0576040517f43dc986d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600160205260408120556104f8816105bf565b50565b60003361052757507f000000000000000000000000000000000000000000000000000000000000000090565b61052f610134565b90565b600033610527575060005490565b60003361055a575060009081526001602052604090205490565b610562610134565b919050565b60003361052757507f000000000000000000000000000000000000000000000000000000000000000090565b60003361052757507f000000000000000000000000000000000000000000000000000000000000000090565b807f4c109d85bcd0bb5c735b4be850953d652afe4cd9aa2e0b1426a65a4dcb2e12296000366040516105f2929190610743565b60405180910390a26000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16600036604051610645929190610733565b6000604051808303816000865af19150503d8060008114610682576040519150601f19603f3d011682016040523d82523d6000602084013e610687565b606091505b50909250905081151560010361069f57805160208201f35b805160208201fd5b600060208083528351808285015260005b818110156106d4578581018301518582016040015282016106b8565b818111156106e6576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561072c57600080fd5b5035919050565b8183823760009101908152919050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b600082198211156107ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50019056fea164736f6c634300080f000a"
func init() {
if err := json.Unmarshal([]byte(DelayedVetoableStorageLayoutJSON), DelayedVetoableStorageLayout); err != nil {
panic(err)
}
layouts["DelayedVetoable"] = DelayedVetoableStorageLayout
deployedBytecodes["DelayedVetoable"] = DelayedVetoableDeployedBin
}
This diff is collapsed.
This diff is collapsed.
...@@ -24,6 +24,7 @@ var ( ...@@ -24,6 +24,7 @@ var (
cannonPreState = "./pre.json" cannonPreState = "./pre.json"
datadir = "./test_data" datadir = "./test_data"
cannonL2 = "http://example.com:9545" cannonL2 = "http://example.com:9545"
rollupRpc = "http://example.com:8555"
alphabetTrace = "abcdefghijz" alphabetTrace = "abcdefghijz"
agreeWithProposedOutput = "true" agreeWithProposedOutput = "true"
) )
...@@ -249,6 +250,25 @@ func TestDataDir(t *testing.T) { ...@@ -249,6 +250,25 @@ func TestDataDir(t *testing.T) {
}) })
} }
func TestRollupRpc(t *testing.T) {
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--rollup-rpc"))
})
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeCannon, "--rollup-rpc"))
})
t.Run("RequiredForOutputCannonTrace", func(t *testing.T) {
verifyArgsInvalid(t, "flag rollup-rpc is required", addRequiredArgsExcept(config.TraceTypeOutputCannon, "--rollup-rpc"))
})
t.Run("Valid", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeOutputCannon))
require.Equal(t, rollupRpc, cfg.RollupRpc)
})
}
func TestCannonL2(t *testing.T) { func TestCannonL2(t *testing.T) {
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--cannon-l2")) configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--cannon-l2"))
...@@ -429,6 +449,9 @@ func requiredArgs(traceType config.TraceType) map[string]string { ...@@ -429,6 +449,9 @@ func requiredArgs(traceType config.TraceType) map[string]string {
args["--cannon-prestate"] = cannonPreState args["--cannon-prestate"] = cannonPreState
args["--cannon-l2"] = cannonL2 args["--cannon-l2"] = cannonL2
} }
if traceType == config.TraceTypeOutputCannon {
args["--rollup-rpc"] = rollupRpc
}
return args return args
} }
......
...@@ -32,6 +32,7 @@ var ( ...@@ -32,6 +32,7 @@ var (
ErrCannonNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path") ErrCannonNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path")
ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path")
ErrCannonNetworkUnknown = errors.New("unknown cannon network") ErrCannonNetworkUnknown = errors.New("unknown cannon network")
ErrMissingRollupRpc = errors.New("missing rollup rpc url")
) )
type TraceType string type TraceType string
...@@ -107,6 +108,9 @@ type Config struct { ...@@ -107,6 +108,9 @@ type Config struct {
// Specific to the alphabet trace provider // Specific to the alphabet trace provider
AlphabetTrace string // String for the AlphabetTraceProvider AlphabetTrace string // String for the AlphabetTraceProvider
// Specific to the output cannon trace type
RollupRpc string
// Specific to the cannon trace provider // Specific to the cannon trace provider
CannonBin string // Path to the cannon executable to run when generating trace data CannonBin string // Path to the cannon executable to run when generating trace data
CannonServer string // Path to the op-program executable that provides the pre-image oracle server CannonServer string // Path to the op-program executable that provides the pre-image oracle server
...@@ -168,6 +172,11 @@ func (c Config) Check() error { ...@@ -168,6 +172,11 @@ func (c Config) Check() error {
if c.MaxConcurrency == 0 { if c.MaxConcurrency == 0 {
return ErrMaxConcurrencyZero return ErrMaxConcurrencyZero
} }
if c.TraceType == TraceTypeOutputCannon {
if c.RollupRpc == "" {
return ErrMissingRollupRpc
}
}
if c.TraceType == TraceTypeCannon || c.TraceType == TraceTypeOutputCannon { if c.TraceType == TraceTypeCannon || c.TraceType == TraceTypeOutputCannon {
if c.CannonBin == "" { if c.CannonBin == "" {
return ErrMissingCannonBin return ErrMissingCannonBin
......
...@@ -20,6 +20,7 @@ var ( ...@@ -20,6 +20,7 @@ var (
validCannonAbsolutPreState = "pre.json" validCannonAbsolutPreState = "pre.json"
validDatadir = "/tmp/data" validDatadir = "/tmp/data"
validCannonL2 = "http://localhost:9545" validCannonL2 = "http://localhost:9545"
validRollupRpc = "http://localhost:8555"
agreeWithProposedOutput = true agreeWithProposedOutput = true
) )
...@@ -35,6 +36,9 @@ func validConfig(traceType TraceType) Config { ...@@ -35,6 +36,9 @@ func validConfig(traceType TraceType) Config {
cfg.CannonL2 = validCannonL2 cfg.CannonL2 = validCannonL2
cfg.CannonNetwork = validCannonNetwork cfg.CannonNetwork = validCannonNetwork
} }
if traceType == TraceTypeOutputCannon {
cfg.RollupRpc = validRollupRpc
}
return cfg return cfg
} }
...@@ -125,6 +129,12 @@ func TestHttpPollInterval(t *testing.T) { ...@@ -125,6 +129,12 @@ func TestHttpPollInterval(t *testing.T) {
}) })
} }
func TestRollupRpcRequired(t *testing.T) {
config := validConfig(TraceTypeOutputCannon)
config.RollupRpc = ""
require.ErrorIs(t, config.Check(), ErrMissingRollupRpc)
}
func TestCannonL2Required(t *testing.T) { func TestCannonL2Required(t *testing.T) {
config := validConfig(TraceTypeCannon) config := validConfig(TraceTypeCannon)
config.CannonL2 = "" config.CannonL2 = ""
......
...@@ -76,14 +76,22 @@ var ( ...@@ -76,14 +76,22 @@ var (
EnvVars: prefixEnvVars("HTTP_POLL_INTERVAL"), EnvVars: prefixEnvVars("HTTP_POLL_INTERVAL"),
Value: config.DefaultPollInterval, Value: config.DefaultPollInterval,
} }
RollupRpcFlag = &cli.StringFlag{
Name: "rollup-rpc",
Usage: "HTTP provider URL for the rollup node",
EnvVars: prefixEnvVars("ROLLUP_RPC"),
}
AlphabetFlag = &cli.StringFlag{ AlphabetFlag = &cli.StringFlag{
Name: "alphabet", Name: "alphabet",
Usage: "Correct Alphabet Trace (alphabet trace type only)", Usage: "Correct Alphabet Trace (alphabet trace type only)",
EnvVars: prefixEnvVars("ALPHABET"), EnvVars: prefixEnvVars("ALPHABET"),
} }
CannonNetworkFlag = &cli.StringFlag{ CannonNetworkFlag = &cli.StringFlag{
Name: "cannon-network", Name: "cannon-network",
Usage: fmt.Sprintf("Predefined network selection. Available networks: %s (cannon trace type only)", strings.Join(chaincfg.AvailableNetworks(), ", ")), Usage: fmt.Sprintf(
"Predefined network selection. Available networks: %s (cannon trace type only)",
strings.Join(chaincfg.AvailableNetworks(), ", "),
),
EnvVars: prefixEnvVars("CANNON_NETWORK"), EnvVars: prefixEnvVars("CANNON_NETWORK"),
} }
CannonRollupConfigFlag = &cli.StringFlag{ CannonRollupConfigFlag = &cli.StringFlag{
...@@ -149,6 +157,7 @@ var requiredFlags = []cli.Flag{ ...@@ -149,6 +157,7 @@ var requiredFlags = []cli.Flag{
var optionalFlags = []cli.Flag{ var optionalFlags = []cli.Flag{
MaxConcurrencyFlag, MaxConcurrencyFlag,
HTTPPollInterval, HTTPPollInterval,
RollupRpcFlag,
AlphabetFlag, AlphabetFlag,
GameAllowlistFlag, GameAllowlistFlag,
CannonNetworkFlag, CannonNetworkFlag,
...@@ -221,6 +230,9 @@ func CheckRequired(ctx *cli.Context) error { ...@@ -221,6 +230,9 @@ func CheckRequired(ctx *cli.Context) error {
if err := CheckCannonFlags(ctx); err != nil { if err := CheckCannonFlags(ctx); err != nil {
return err return err
} }
if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
}
default: default:
return fmt.Errorf("invalid trace type. must be one of %v", config.TraceTypes) return fmt.Errorf("invalid trace type. must be one of %v", config.TraceTypes)
} }
...@@ -266,6 +278,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) { ...@@ -266,6 +278,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
GameWindow: ctx.Duration(GameWindowFlag.Name), GameWindow: ctx.Duration(GameWindowFlag.Name),
MaxConcurrency: maxConcurrency, MaxConcurrency: maxConcurrency,
PollInterval: ctx.Duration(HTTPPollInterval.Name), PollInterval: ctx.Duration(HTTPPollInterval.Name),
RollupRpc: ctx.String(RollupRpcFlag.Name),
AlphabetTrace: ctx.String(AlphabetFlag.Name), AlphabetTrace: ctx.String(AlphabetFlag.Name),
CannonNetwork: ctx.String(CannonNetworkFlag.Name), CannonNetwork: ctx.String(CannonNetworkFlag.Name),
CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name), CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name),
......
...@@ -64,6 +64,9 @@ type Config struct { ...@@ -64,6 +64,9 @@ type Config struct {
// ServerMode indicates that the program should run in pre-image server mode and wait for requests. // ServerMode indicates that the program should run in pre-image server mode and wait for requests.
// No client program is run. // No client program is run.
ServerMode bool ServerMode bool
// IsCustomChainConfig indicates that the program uses a custom chain configuration
IsCustomChainConfig bool
} }
func (c *Config) Check() error { func (c *Config) Check() error {
...@@ -117,15 +120,18 @@ func NewConfig( ...@@ -117,15 +120,18 @@ func NewConfig(
l2Claim common.Hash, l2Claim common.Hash,
l2ClaimBlockNum uint64, l2ClaimBlockNum uint64,
) *Config { ) *Config {
_, err := params.LoadOPStackChainConfig(l2Genesis.ChainID.Uint64())
isCustomConfig := err != nil
return &Config{ return &Config{
Rollup: rollupCfg, Rollup: rollupCfg,
L2ChainConfig: l2Genesis, L2ChainConfig: l2Genesis,
L1Head: l1Head, L1Head: l1Head,
L2Head: l2Head, L2Head: l2Head,
L2OutputRoot: l2OutputRoot, L2OutputRoot: l2OutputRoot,
L2Claim: l2Claim, L2Claim: l2Claim,
L2ClaimBlockNumber: l2ClaimBlockNum, L2ClaimBlockNumber: l2ClaimBlockNum,
L1RPCKind: sources.RPCKindBasic, L1RPCKind: sources.RPCKindBasic,
IsCustomChainConfig: isCustomConfig,
} }
} }
...@@ -156,6 +162,7 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) { ...@@ -156,6 +162,7 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) {
} }
l2GenesisPath := ctx.String(flags.L2GenesisPath.Name) l2GenesisPath := ctx.String(flags.L2GenesisPath.Name)
var l2ChainConfig *params.ChainConfig var l2ChainConfig *params.ChainConfig
var isCustomConfig bool
if l2GenesisPath == "" { if l2GenesisPath == "" {
networkName := ctx.String(flags.Network.Name) networkName := ctx.String(flags.Network.Name)
ch := chaincfg.ChainByName(networkName) ch := chaincfg.ChainByName(networkName)
...@@ -169,25 +176,27 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) { ...@@ -169,25 +176,27 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) {
l2ChainConfig = cfg l2ChainConfig = cfg
} else { } else {
l2ChainConfig, err = loadChainConfigFromGenesis(l2GenesisPath) l2ChainConfig, err = loadChainConfigFromGenesis(l2GenesisPath)
isCustomConfig = true
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid genesis: %w", err) return nil, fmt.Errorf("invalid genesis: %w", err)
} }
return &Config{ return &Config{
Rollup: rollupCfg, Rollup: rollupCfg,
DataDir: ctx.String(flags.DataDir.Name), DataDir: ctx.String(flags.DataDir.Name),
L2URL: ctx.String(flags.L2NodeAddr.Name), L2URL: ctx.String(flags.L2NodeAddr.Name),
L2ChainConfig: l2ChainConfig, L2ChainConfig: l2ChainConfig,
L2Head: l2Head, L2Head: l2Head,
L2OutputRoot: l2OutputRoot, L2OutputRoot: l2OutputRoot,
L2Claim: l2Claim, L2Claim: l2Claim,
L2ClaimBlockNumber: l2ClaimBlockNum, L2ClaimBlockNumber: l2ClaimBlockNum,
L1Head: l1Head, L1Head: l1Head,
L1URL: ctx.String(flags.L1NodeAddr.Name), L1URL: ctx.String(flags.L1NodeAddr.Name),
L1TrustRPC: ctx.Bool(flags.L1TrustRPC.Name), L1TrustRPC: ctx.Bool(flags.L1TrustRPC.Name),
L1RPCKind: sources.RPCProviderKind(ctx.String(flags.L1RPCProviderKind.Name)), L1RPCKind: sources.RPCProviderKind(ctx.String(flags.L1RPCProviderKind.Name)),
ExecCmd: ctx.String(flags.Exec.Name), ExecCmd: ctx.String(flags.Exec.Name),
ServerMode: ctx.Bool(flags.Server.Name), ServerMode: ctx.Bool(flags.Server.Name),
IsCustomChainConfig: isCustomConfig,
}, nil }, nil
} }
......
package config package config
import ( import (
"math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-program/chainconfig"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -12,7 +14,7 @@ import ( ...@@ -12,7 +14,7 @@ import (
var ( var (
validRollupConfig = chaincfg.Goerli validRollupConfig = chaincfg.Goerli
validL2Genesis = params.GoerliChainConfig validL2Genesis = chainconfig.OPGoerliChainConfig
validL1Head = common.Hash{0xaa} validL1Head = common.Hash{0xaa}
validL2Head = common.Hash{0xbb} validL2Head = common.Hash{0xbb}
validL2Claim = common.Hash{0xcc} validL2Claim = common.Hash{0xcc}
...@@ -158,6 +160,19 @@ func TestRejectExecAndServerMode(t *testing.T) { ...@@ -158,6 +160,19 @@ func TestRejectExecAndServerMode(t *testing.T) {
require.ErrorIs(t, err, ErrNoExecInServerMode) require.ErrorIs(t, err, ErrNoExecInServerMode)
} }
func TestIsCustomChainConfig(t *testing.T) {
t.Run("nonCustom", func(t *testing.T) {
cfg := validConfig()
require.Equal(t, cfg.IsCustomChainConfig, false)
})
t.Run("custom", func(t *testing.T) {
customChainConfig := &params.ChainConfig{ChainID: big.NewInt(0x1212121212)}
cfg := NewConfig(validRollupConfig, customChainConfig, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum)
require.Equal(t, cfg.IsCustomChainConfig, true)
})
}
func validConfig() *Config { func validConfig() *Config {
cfg := NewConfig(validRollupConfig, validL2Genesis, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum) cfg := NewConfig(validRollupConfig, validL2Genesis, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum)
cfg.DataDir = "/tmp/configTest" cfg.DataDir = "/tmp/configTest"
......
...@@ -38,7 +38,15 @@ func (s *LocalPreimageSource) Get(key common.Hash) ([]byte, error) { ...@@ -38,7 +38,15 @@ func (s *LocalPreimageSource) Get(key common.Hash) ([]byte, error) {
case l2ClaimBlockNumberKey: case l2ClaimBlockNumberKey:
return binary.BigEndian.AppendUint64(nil, s.config.L2ClaimBlockNumber), nil return binary.BigEndian.AppendUint64(nil, s.config.L2ClaimBlockNumber), nil
case l2ChainIDKey: case l2ChainIDKey:
return binary.BigEndian.AppendUint64(nil, client.CustomChainIDIndicator), nil // The CustomChainIDIndicator informs the client to rely on the L2ChainConfigKey to
// read the chain config. Otherwise, it'll attempt to read a non-existent hardcoded chain config
var chainID uint64
if s.config.IsCustomChainConfig {
chainID = client.CustomChainIDIndicator
} else {
chainID = s.config.L2ChainConfig.ChainID.Uint64()
}
return binary.BigEndian.AppendUint64(nil, chainID), nil
case l2ChainConfigKey: case l2ChainConfigKey:
return json.Marshal(s.config.L2ChainConfig) return json.Marshal(s.config.L2ChainConfig)
case rollupKey: case rollupKey:
......
...@@ -7,7 +7,6 @@ import ( ...@@ -7,7 +7,6 @@ import (
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
preimage "github.com/ethereum-optimism/optimism/op-preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client"
"github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
...@@ -33,7 +32,7 @@ func TestLocalPreimageSource(t *testing.T) { ...@@ -33,7 +32,7 @@ func TestLocalPreimageSource(t *testing.T) {
{"L2OutputRoot", l2OutputRootKey, cfg.L2OutputRoot.Bytes()}, {"L2OutputRoot", l2OutputRootKey, cfg.L2OutputRoot.Bytes()},
{"L2Claim", l2ClaimKey, cfg.L2Claim.Bytes()}, {"L2Claim", l2ClaimKey, cfg.L2Claim.Bytes()},
{"L2ClaimBlockNumber", l2ClaimBlockNumberKey, binary.BigEndian.AppendUint64(nil, cfg.L2ClaimBlockNumber)}, {"L2ClaimBlockNumber", l2ClaimBlockNumberKey, binary.BigEndian.AppendUint64(nil, cfg.L2ClaimBlockNumber)},
{"L2ChainID", l2ChainIDKey, binary.BigEndian.AppendUint64(nil, client.CustomChainIDIndicator)}, {"L2ChainID", l2ChainIDKey, binary.BigEndian.AppendUint64(nil, cfg.L2ChainConfig.ChainID.Uint64())},
{"Rollup", rollupKey, asJson(t, cfg.Rollup)}, {"Rollup", rollupKey, asJson(t, cfg.Rollup)},
{"ChainConfig", l2ChainConfigKey, asJson(t, cfg.L2ChainConfig)}, {"ChainConfig", l2ChainConfigKey, asJson(t, cfg.L2ChainConfig)},
{"Unknown", preimage.LocalIndexKey(1000).PreimageKey(), nil}, {"Unknown", preimage.LocalIndexKey(1000).PreimageKey(), nil},
......
...@@ -46,6 +46,9 @@ CrossDomainOwnable3_Test:test_transferOwnership_zeroAddress_reverts() (gas: 1208 ...@@ -46,6 +46,9 @@ CrossDomainOwnable3_Test:test_transferOwnership_zeroAddress_reverts() (gas: 1208
CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 81417) CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 81417)
CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10597) CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10597)
CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883) CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883)
DelayedVetoable_Getters_Test:test_getters() (gas: 21342)
DelayedVetoable_Getters_TestFail:test_getters_notZeroAddress_reverts() (gas: 26649)
DelayedVetoable_HandleCall_TestFail:test_handleCall_unauthorizedInitiation_reverts() (gas: 20234)
DeleteOutput:test_script_succeeds() (gas: 3100) DeleteOutput:test_script_succeeds() (gas: 3100)
DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582) DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582)
DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395) DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395)
......
{ {
"src/EAS/EAS.sol": "0x1acb25751a1206eb859cc5fcf934da2f84cfb907b8e8951d86fc4e43c53a7303", "src/EAS/EAS.sol": "0x1acb25751a1206eb859cc5fcf934da2f84cfb907b8e8951d86fc4e43c53a7303",
"src/EAS/SchemaRegistry.sol": "0x305f3afed2e337cd70aac70fc202e6503b947b0a31e0d4e18c49486eeb635bb5", "src/EAS/SchemaRegistry.sol": "0x305f3afed2e337cd70aac70fc202e6503b947b0a31e0d4e18c49486eeb635bb5",
"src/L1/DelayedVetoable.sol": "0x276c6276292095e6aa37a70008cf4e0d1cbcc020dbc9107459bbc72ab5ed744f",
"src/L1/L1CrossDomainMessenger.sol": "0x14f5991022705b8bd3bf931e138a528cc9c9e90d0f1ec398efd5079224d61b3b", "src/L1/L1CrossDomainMessenger.sol": "0x14f5991022705b8bd3bf931e138a528cc9c9e90d0f1ec398efd5079224d61b3b",
"src/L1/L1ERC721Bridge.sol": "0x3e0e3d2f4c151e41585850f06e6452cdda86348debfe6ff16e364a839266450b", "src/L1/L1ERC721Bridge.sol": "0x3e0e3d2f4c151e41585850f06e6452cdda86348debfe6ff16e364a839266450b",
"src/L1/L1StandardBridge.sol": "0x12e227c6054660a83b92d823a7447db96a7d476b7a94e0f1807772d400329880", "src/L1/L1StandardBridge.sol": "0x12e227c6054660a83b92d823a7447db96a7d476b7a94e0f1807772d400329880",
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { ISemver } from "src/universal/ISemver.sol";
/// @title DelayedVetoable
/// @notice This contract enables a delay before a call is forwarded to a target contract, and during the delay period
/// the call can be vetoed by the authorized vetoer.
/// This contract does not support value transfers, only data is forwarded.
/// Additionally, this contract cannot be used to forward calls with data beginning with the function selector
/// of the queuedAt(bytes32) function. This is because of input validation checks which solidity performs at
/// runtime on functions which take an argument.
contract DelayedVetoable is ISemver {
/// @notice Error for when the delay has already been set.
error AlreadyDelayed();
/// @notice Error for when attempting to forward too early.
error ForwardingEarly();
/// @notice Error for the target is not set.
error TargetUnitialized();
/// @notice Error for unauthorized calls.
error Unauthorized(address expected, address actual);
/// @notice An event that is emitted when the delay is activated.
/// @param delay The delay that was activated.
event DelayActivated(uint256 delay);
/// @notice An event that is emitted when a call is initiated.
/// @param callHash The hash of the call data.
/// @param data The data of the initiated call.
event Initiated(bytes32 indexed callHash, bytes data);
/// @notice An event that is emitted each time a call is forwarded.
/// @param callHash The hash of the call data.
/// @param data The data forwarded to the target.
event Forwarded(bytes32 indexed callHash, bytes data);
/// @notice An event that is emitted each time a call is vetoed.
/// @param callHash The hash of the call data.
/// @param data The data forwarded to the target.
event Vetoed(bytes32 indexed callHash, bytes data);
/// @notice The address that all calls are forwarded to after the delay.
address internal immutable TARGET;
/// @notice The address that can veto a call.
address internal immutable VETOER;
/// @notice The address that can initiate a call.
address internal immutable INITIATOR;
/// @notice The delay which will be set after the initial system deployment is completed.
uint256 internal immutable OPERATING_DELAY;
/// @notice The current amount of time to wait before forwarding a call.
uint256 internal _delay;
/// @notice The time that a call was initiated.
mapping(bytes32 => uint256) internal _queuedAt;
/// @notice A modifier that reverts if not called by the vetoer or by address(0) to allow
/// eth_call to interact with this proxy without needing to use low-level storage
/// inspection. We assume that nobody is able to trigger calls from address(0) during
/// normal EVM execution.
modifier readOrHandle() {
if (msg.sender == address(0)) {
_;
} else {
// This WILL halt the call frame on completion.
_handleCall();
}
}
/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
/// @notice Sets the target admin during contract deployment.
/// @param vetoer_ Address of the vetoer.
/// @param initiator_ Address of the initiator.
/// @param target_ Address of the target.
/// @param operatingDelay_ Time to delay when the system is operational.
constructor(address vetoer_, address initiator_, address target_, uint256 operatingDelay_) {
// Note that the _delay value is not set here. Having an initial delay of 0 is helpful
// during the deployment of a new system.
VETOER = vetoer_;
INITIATOR = initiator_;
TARGET = target_;
OPERATING_DELAY = operatingDelay_;
}
/// @notice Gets the initiator
/// @return initiator_ Initiator address.
function initiator() external virtual readOrHandle returns (address initiator_) {
initiator_ = INITIATOR;
}
//// @notice Queries the vetoer address.
/// @return vetoer_ Vetoer address.
function vetoer() external virtual readOrHandle returns (address vetoer_) {
vetoer_ = VETOER;
}
//// @notice Queries the target address.
/// @return target_ Target address.
function target() external readOrHandle returns (address target_) {
target_ = TARGET;
}
/// @notice Gets the delay
/// @return delay_ Delay address.
function delay() external readOrHandle returns (uint256 delay_) {
delay_ = _delay;
}
/// @notice Gets entries in the _queuedAt mapping.
/// @param callHash The hash of the call data.
/// @return queuedAt_ The time the callHash was recorded.
function queuedAt(bytes32 callHash) external readOrHandle returns (uint256 queuedAt_) {
queuedAt_ = _queuedAt[callHash];
}
/// @notice Used for all calls that pass data to the contract.
fallback() external {
_handleCall();
}
/// @notice Receives all calls other than those made by the vetoer.
/// This enables transparent initiation and forwarding of calls to the target and avoids
/// the need for additional layers of abi encoding.
function _handleCall() internal {
// The initiator and vetoer activate the delay by passing in null data.
if (msg.data.length == 0 && _delay == 0) {
if (msg.sender != INITIATOR && msg.sender != VETOER) {
revert Unauthorized(INITIATOR, msg.sender);
}
_delay = OPERATING_DELAY;
emit DelayActivated(_delay);
return;
}
bytes32 callHash = keccak256(msg.data);
// Case 1: The initiator is calling the contract to initiate a call.
if (msg.sender == INITIATOR && _queuedAt[callHash] == 0) {
if (_delay == 0) {
// This forward function will halt the call frame on completion.
_forwardAndHalt(callHash);
}
_queuedAt[callHash] = block.timestamp;
emit Initiated(callHash, msg.data);
return;
}
// Case 2: The vetoer is calling the contract to veto a call.
// Note: The vetoer retains the ability to veto even after the delay has passed. This makes censoring the vetoer
// more costly, as there is no time limit after which their transaction can be included.
if (msg.sender == VETOER && _queuedAt[callHash] != 0) {
delete _queuedAt[callHash];
emit Vetoed(callHash, msg.data);
return;
}
// Case 3: The call is from an unpermissioned actor. We'll forward the call if the delay has
// passed.
if (_queuedAt[callHash] == 0) {
// The call has not been initiated, so we'll treat this is an unauthorized initiation attempt.
revert Unauthorized(INITIATOR, msg.sender);
}
if (_queuedAt[callHash] + _delay < block.timestamp) {
// Not enough time has passed, so we'll revert.
revert ForwardingEarly();
}
// Delete the call to prevent replays
delete _queuedAt[callHash];
_forwardAndHalt(callHash);
}
/// @notice Forwards the call to the target and halts the call frame.
function _forwardAndHalt(bytes32 callHash) internal {
// Forward the call
emit Forwarded(callHash, msg.data);
(bool success, bytes memory returndata) = TARGET.call(msg.data);
if (success == true) {
assembly {
return(add(returndata, 0x20), mload(returndata))
}
} else {
assembly {
revert(add(returndata, 0x20), mload(returndata))
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { CommonTest } from "./CommonTest.t.sol";
import { DelayedVetoable } from "src/L1/DelayedVetoable.sol";
contract DelayedVetoable_Init is CommonTest {
error Unauthorized(address expected, address actual);
error ForwardingEarly();
event Initiated(bytes32 indexed callHash, bytes data);
event Forwarded(bytes32 indexed callHash, bytes data);
event Vetoed(bytes32 indexed callHash, bytes data);
address target = address(0xabba);
address initiator = alice;
address vetoer = bob;
uint256 operatingDelay = 14 days;
DelayedVetoable delayedVetoable;
function setUp() public override {
super.setUp();
delayedVetoable = new DelayedVetoable({
initiator_: alice,
vetoer_: bob,
target_: address(target),
operatingDelay_: operatingDelay
});
// Most tests will use the operating delay, so we call as the initiator with null data
// to set the delay. For tests that need to use the initial zero delay, we'll modify the
// value in storage.
vm.prank(initiator);
(bool success,) = address(delayedVetoable).call(hex"");
}
/// @dev This function is used to prevent initiating the delay unintentionally..
/// @param data The data to be used in the call.
function assumeNonzeroData(bytes memory data) internal pure {
vm.assume(data.length > 0);
}
}
contract DelayedVetoable_Getters_Test is DelayedVetoable_Init {
/// @dev The getters return the expected values when called by the zero address.
function test_getters() external {
vm.startPrank(address(0));
assertEq(delayedVetoable.initiator(), initiator);
assertEq(delayedVetoable.vetoer(), vetoer);
assertEq(delayedVetoable.target(), target);
assertEq(delayedVetoable.delay(), operatingDelay);
}
}
contract DelayedVetoable_Getters_TestFail is DelayedVetoable_Init {
/// @dev Check that getter calls from unauthorized entities will revert.
function test_getters_notZeroAddress_reverts() external {
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this)));
delayedVetoable.initiator();
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this)));
delayedVetoable.vetoer();
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this)));
delayedVetoable.target();
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this)));
delayedVetoable.delay();
}
}
contract DelayedVetoable_HandleCall_Test is DelayedVetoable_Init {
/// @dev A call can be initiated by the initiator.
function testFuzz_handleCall_initiation_succeeds(bytes memory data) external {
assumeNonzeroData(data);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit Initiated(keccak256(data), data);
vm.prank(initiator);
(bool success,) = address(delayedVetoable).call(data);
assertTrue(success);
}
/// @dev The delay is inititially set to zero and the call is immediately forwarded.
function testFuzz_handleCall_initialForwardingImmediately_succeeds(
bytes calldata inData,
bytes calldata outData
)
external
{
assumeNonzeroData(inData);
if (inData.length >= 4) {
vm.assume(bytes4(inData[0:4]) != bytes4(keccak256("queuedAt(bytes32)")));
}
// Reset the delay to zero
vm.store(address(delayedVetoable), bytes32(uint256(0)), bytes32(uint256(0)));
vm.mockCall(target, inData, outData);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
vm.expectCall({ callee: target, data: inData });
emit Forwarded(keccak256(inData), inData);
vm.prank(initiator);
(bool success, bytes memory returnData) = address(delayedVetoable).call(inData);
assertTrue(success);
assertEq(returnData, outData);
}
/// @dev The delay can be activated by the vetoer or initiator, and are not forwarded until the delay has passed
/// once activated.
function testFuzz_handleCall_forwardingWithDelay_succeeds(bytes memory data) external {
assumeNonzeroData(data);
vm.prank(initiator);
(bool success,) = address(delayedVetoable).call(data);
// Check that the call is in the _queuedAt mapping
bytes32 callHash = keccak256(data);
vm.prank(address(0));
assertEq(delayedVetoable.queuedAt(callHash), block.timestamp);
vm.warp(block.timestamp + operatingDelay);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit Forwarded(keccak256(data), data);
vm.expectCall({ callee: target, data: data });
(success,) = address(delayedVetoable).call(data);
assertTrue(success);
}
}
contract DelayedVetoable_HandleCall_TestFail is DelayedVetoable_Init {
/// @dev The delay is inititially set to zero and the call is immediately forwarded.
function test_handleCall_unauthorizedInitiation_reverts() external {
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this)));
(bool success,) = address(delayedVetoable).call(NON_ZERO_DATA);
}
/// @dev The call cannot be forewarded until the delay has passed.
function testFuzz_handleCall_forwardingTooSoon_reverts(bytes memory data) external {
vm.prank(initiator);
(bool success,) = address(delayedVetoable).call(data);
vm.expectRevert(abi.encodeWithSelector(ForwardingEarly.selector));
(success,) = address(delayedVetoable).call(data);
}
/// @dev The call cannot be forwarded a second time.
function testFuzz_handleCall_forwardingTwice_reverts(bytes memory data) external {
assumeNonzeroData(data);
// Initiate the call
vm.prank(initiator);
(bool success,) = address(delayedVetoable).call(data);
vm.warp(block.timestamp + operatingDelay);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit Forwarded(keccak256(data), data);
// Forward the call
vm.expectCall({ callee: target, data: data });
(success,) = address(delayedVetoable).call(data);
assertTrue(success);
// Attempt to foward the same call again.
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this)));
(success,) = address(delayedVetoable).call(data);
assertTrue(success);
}
/// @dev If the target reverts, it is bubbled up.
function testFuzz_handleCall_forwardingTargetReverts_reverts(bytes memory inData, bytes memory outData) external {
assumeNonzeroData(inData);
// Initiate the call
vm.prank(initiator);
(bool success,) = address(delayedVetoable).call(inData);
vm.warp(block.timestamp + operatingDelay);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit Forwarded(keccak256(inData), inData);
vm.mockCallRevert(target, inData, outData);
// Forward the call
vm.expectRevert(outData);
(bool success2,) = address(delayedVetoable).call(inData);
}
/// @dev A test documenting the single instance in which the contract is not 'transparent' to the initiator.
function testFuzz_handleCall_queuedAtClash_reverts(bytes memory outData) external {
// This will get us calldata with the same function selector as the queuedAt function, but
// with the incorrect input data length.
bytes memory inData = abi.encodePacked(keccak256("queuedAt(bytes32)"));
// Reset the delay to zero
vm.store(address(delayedVetoable), bytes32(uint256(0)), bytes32(uint256(0)));
vm.prank(initiator);
vm.expectRevert(outData);
(bool success,) = address(delayedVetoable).call(inData);
}
}
...@@ -35,7 +35,7 @@ importers: ...@@ -35,7 +35,7 @@ importers:
version: 10.0.1 version: 10.0.1
'@types/node': '@types/node':
specifier: ^20.5.3 specifier: ^20.5.3
version: 20.6.1 version: 20.6.2
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: ^6.7.0 specifier: ^6.7.0
version: 6.7.0(@typescript-eslint/parser@6.7.0)(eslint@8.49.0)(typescript@5.1.6) version: 6.7.0(@typescript-eslint/parser@6.7.0)(eslint@8.49.0)(typescript@5.1.6)
...@@ -92,7 +92,7 @@ importers: ...@@ -92,7 +92,7 @@ importers:
version: 14.0.1 version: 14.0.1
markdownlint: markdownlint:
specifier: ^0.31.0 specifier: ^0.31.0
version: 0.31.0 version: 0.31.1
markdownlint-cli2: markdownlint-cli2:
specifier: 0.4.0 specifier: 0.4.0
version: 0.4.0 version: 0.4.0
...@@ -342,7 +342,7 @@ importers: ...@@ -342,7 +342,7 @@ importers:
version: 5.1.6 version: 5.1.6
vite: vite:
specifier: ^4.4.6 specifier: ^4.4.6
version: 4.4.6(@types/node@20.6.1) version: 4.4.6(@types/node@20.6.2)
vitest: vitest:
specifier: ^0.34.2 specifier: ^0.34.2
version: 0.34.2(jsdom@22.1.0) version: 0.34.2(jsdom@22.1.0)
...@@ -436,7 +436,7 @@ importers: ...@@ -436,7 +436,7 @@ importers:
version: 1.3.1(typescript@5.1.6) version: 1.3.1(typescript@5.1.6)
vite: vite:
specifier: ^4.4.6 specifier: ^4.4.6
version: 4.4.6(@types/node@20.6.1) version: 4.4.6(@types/node@20.6.2)
vitest: vitest:
specifier: ^0.34.2 specifier: ^0.34.2
version: 0.34.2(jsdom@22.1.0) version: 0.34.2(jsdom@22.1.0)
...@@ -567,7 +567,7 @@ importers: ...@@ -567,7 +567,7 @@ importers:
version: 1.6.0(typescript@5.1.6)(zod@3.22.0) version: 1.6.0(typescript@5.1.6)(zod@3.22.0)
vite: vite:
specifier: ^4.4.9 specifier: ^4.4.9
version: 4.4.9(@types/node@20.6.1) version: 4.4.9(@types/node@20.6.2)
vitest: vitest:
specifier: ^0.34.1 specifier: ^0.34.1
version: 0.34.1 version: 0.34.1
...@@ -3783,7 +3783,7 @@ packages: ...@@ -3783,7 +3783,7 @@ packages:
resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
dependencies: dependencies:
'@types/minimatch': 5.1.2 '@types/minimatch': 5.1.2
'@types/node': 20.6.1 '@types/node': 20.6.2
dev: true dev: true
/@types/is-ci@3.0.0: /@types/is-ci@3.0.0:
...@@ -3852,7 +3852,7 @@ packages: ...@@ -3852,7 +3852,7 @@ packages:
/@types/morgan@1.9.4: /@types/morgan@1.9.4:
resolution: {integrity: sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==} resolution: {integrity: sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==}
dependencies: dependencies:
'@types/node': 20.6.1 '@types/node': 20.6.2
dev: true dev: true
/@types/ms@0.7.31: /@types/ms@0.7.31:
...@@ -3876,10 +3876,6 @@ packages: ...@@ -3876,10 +3876,6 @@ packages:
resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==} resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==}
dev: true dev: true
/@types/node@20.6.1:
resolution: {integrity: sha512-4LcJvuXQlv4lTHnxwyHQZ3uR9Zw2j7m1C9DfuwoTFQQP4Pmu04O6IfLYgMmHoOCt0nosItLLZAH+sOrRE0Bo8g==}
dev: true
/@types/node@20.6.2: /@types/node@20.6.2:
resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==} resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==}
...@@ -10707,8 +10703,8 @@ packages: ...@@ -10707,8 +10703,8 @@ packages:
markdown-it: 12.3.2 markdown-it: 12.3.2
dev: true dev: true
/markdownlint@0.31.0: /markdownlint@0.31.1:
resolution: {integrity: sha512-e+jZGRGZrz1s0T4wiPDFtyQafq7sKgdbf2sdL46gRT8zLEvDDihQmGeSCV6VXp9BsfkuZ0dPTAg9hf4j6NFgjg==} resolution: {integrity: sha512-CKMR2hgcIBrYlIUccDCOvi966PZ0kJExDrUi1R+oF9PvqQmCrTqjOsgIvf2403OmJ+CWomuzDoylr6KbuMyvHA==}
engines: {node: '>=16'} engines: {node: '>=16'}
dependencies: dependencies:
markdown-it: 13.0.1 markdown-it: 13.0.1
...@@ -14649,7 +14645,7 @@ packages: ...@@ -14649,7 +14645,7 @@ packages:
- zod - zod
dev: true dev: true
/vite-node@0.34.1(@types/node@20.6.1): /vite-node@0.34.1(@types/node@20.6.2):
resolution: {integrity: sha512-odAZAL9xFMuAg8aWd7nSPT+hU8u2r9gU3LRm9QKjxBEF2rRdWpMuqkrkjvyVQEdNFiBctqr2Gg4uJYizm5Le6w==} resolution: {integrity: sha512-odAZAL9xFMuAg8aWd7nSPT+hU8u2r9gU3LRm9QKjxBEF2rRdWpMuqkrkjvyVQEdNFiBctqr2Gg4uJYizm5Le6w==}
engines: {node: '>=v14.18.0'} engines: {node: '>=v14.18.0'}
hasBin: true hasBin: true
...@@ -14659,7 +14655,7 @@ packages: ...@@ -14659,7 +14655,7 @@ packages:
mlly: 1.4.0 mlly: 1.4.0
pathe: 1.1.1 pathe: 1.1.1
picocolors: 1.0.0 picocolors: 1.0.0
vite: 4.4.9(@types/node@20.6.1) vite: 4.4.9(@types/node@20.6.2)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
...@@ -14671,7 +14667,7 @@ packages: ...@@ -14671,7 +14667,7 @@ packages:
- terser - terser
dev: true dev: true
/vite-node@0.34.2(@types/node@20.6.1): /vite-node@0.34.2(@types/node@20.6.2):
resolution: {integrity: sha512-JtW249Zm3FB+F7pQfH56uWSdlltCo1IOkZW5oHBzeQo0iX4jtC7o1t9aILMGd9kVekXBP2lfJBEQt9rBh07ebA==} resolution: {integrity: sha512-JtW249Zm3FB+F7pQfH56uWSdlltCo1IOkZW5oHBzeQo0iX4jtC7o1t9aILMGd9kVekXBP2lfJBEQt9rBh07ebA==}
engines: {node: '>=v14.18.0'} engines: {node: '>=v14.18.0'}
hasBin: true hasBin: true
...@@ -14681,7 +14677,7 @@ packages: ...@@ -14681,7 +14677,7 @@ packages:
mlly: 1.4.0 mlly: 1.4.0
pathe: 1.1.1 pathe: 1.1.1
picocolors: 1.0.0 picocolors: 1.0.0
vite: 4.4.9(@types/node@20.6.1) vite: 4.4.9(@types/node@20.6.2)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
...@@ -14715,7 +14711,7 @@ packages: ...@@ -14715,7 +14711,7 @@ packages:
- terser - terser
dev: true dev: true
/vite@4.4.6(@types/node@20.6.1): /vite@4.4.6(@types/node@20.6.2):
resolution: {integrity: sha512-EY6Mm8vJ++S3D4tNAckaZfw3JwG3wa794Vt70M6cNJ6NxT87yhq7EC8Rcap3ahyHdo8AhCmV9PTk+vG1HiYn1A==} resolution: {integrity: sha512-EY6Mm8vJ++S3D4tNAckaZfw3JwG3wa794Vt70M6cNJ6NxT87yhq7EC8Rcap3ahyHdo8AhCmV9PTk+vG1HiYn1A==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true hasBin: true
...@@ -14743,7 +14739,7 @@ packages: ...@@ -14743,7 +14739,7 @@ packages:
terser: terser:
optional: true optional: true
dependencies: dependencies:
'@types/node': 20.6.1 '@types/node': 20.6.2
esbuild: 0.18.15 esbuild: 0.18.15
postcss: 8.4.27 postcss: 8.4.27
rollup: 3.26.3 rollup: 3.26.3
...@@ -14751,42 +14747,6 @@ packages: ...@@ -14751,42 +14747,6 @@ packages:
fsevents: 2.3.2 fsevents: 2.3.2
dev: true dev: true
/vite@4.4.9(@types/node@20.6.1):
resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
'@types/node': '>= 14'
less: '*'
lightningcss: ^1.21.0
sass: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
dependencies:
'@types/node': 20.6.1
esbuild: 0.18.15
postcss: 8.4.27
rollup: 3.28.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/vite@4.4.9(@types/node@20.6.2): /vite@4.4.9(@types/node@20.6.2):
resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
...@@ -14856,7 +14816,7 @@ packages: ...@@ -14856,7 +14816,7 @@ packages:
dependencies: dependencies:
'@types/chai': 4.3.6 '@types/chai': 4.3.6
'@types/chai-subset': 1.3.3 '@types/chai-subset': 1.3.3
'@types/node': 20.6.1 '@types/node': 20.6.2
'@vitest/expect': 0.34.1 '@vitest/expect': 0.34.1
'@vitest/runner': 0.34.1 '@vitest/runner': 0.34.1
'@vitest/snapshot': 0.34.1 '@vitest/snapshot': 0.34.1
...@@ -14875,8 +14835,8 @@ packages: ...@@ -14875,8 +14835,8 @@ packages:
strip-literal: 1.0.1 strip-literal: 1.0.1
tinybench: 2.5.0 tinybench: 2.5.0
tinypool: 0.7.0 tinypool: 0.7.0
vite: 4.4.9(@types/node@20.6.1) vite: 4.4.9(@types/node@20.6.2)
vite-node: 0.34.1(@types/node@20.6.1) vite-node: 0.34.1(@types/node@20.6.2)
why-is-node-running: 2.2.2 why-is-node-running: 2.2.2
transitivePeerDependencies: transitivePeerDependencies:
- less - less
...@@ -14921,7 +14881,7 @@ packages: ...@@ -14921,7 +14881,7 @@ packages:
dependencies: dependencies:
'@types/chai': 4.3.6 '@types/chai': 4.3.6
'@types/chai-subset': 1.3.3 '@types/chai-subset': 1.3.3
'@types/node': 20.6.1 '@types/node': 20.6.2
'@vitest/expect': 0.34.2 '@vitest/expect': 0.34.2
'@vitest/runner': 0.34.2 '@vitest/runner': 0.34.2
'@vitest/snapshot': 0.34.2 '@vitest/snapshot': 0.34.2
...@@ -14941,8 +14901,8 @@ packages: ...@@ -14941,8 +14901,8 @@ packages:
strip-literal: 1.0.1 strip-literal: 1.0.1
tinybench: 2.5.0 tinybench: 2.5.0
tinypool: 0.7.0 tinypool: 0.7.0
vite: 4.4.9(@types/node@20.6.1) vite: 4.4.9(@types/node@20.6.2)
vite-node: 0.34.2(@types/node@20.6.1) vite-node: 0.34.2(@types/node@20.6.2)
why-is-node-running: 2.2.2 why-is-node-running: 2.2.2
transitivePeerDependencies: transitivePeerDependencies:
- less - less
......
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