Commit f2e5a7a5 authored by Sam Stokes's avatar Sam Stokes Committed by GitHub

Add check-fjord script to smoke test live chains (#10578)

* Add check-fjord script to smoke test live chains

* Fix checkRIP7212 invalid signature test

* check-fjord: several fixes

* fix callopts

* check-fjord: fix bindings import

* check-fjord: fix errors & naming

* lint

* fix commands

* Remove unused configuration flags

* Add e2e test for check-fjord script

* Add test to verify unactivated fjord is properly detected

* Refactor check-fjord script and e2e test for cleaner separation

* Add tests to ensure all fjord checks error if fork is unactivated

* Update op-e2e/check_scripts_test.go

---------
Co-authored-by: default avatarSebastian Stammler <seb@oplabs.co>
parent bcdf96ab
...@@ -844,7 +844,7 @@ func checkL1Fees(ctx context.Context, env *actionEnv) error { ...@@ -844,7 +844,7 @@ func checkL1Fees(ctx context.Context, env *actionEnv) error {
return fmt.Errorf("expected %d L1 gas, but only spent %d", expectedCalldataGas, receipt.L1GasUsed) return fmt.Errorf("expected %d L1 gas, but only spent %d", expectedCalldataGas, receipt.L1GasUsed)
} }
if big.NewInt(0).Cmp(receipt.L1Fee) >= 0 { if big.NewInt(0).Cmp(receipt.L1Fee) >= 0 {
return fmt.Errorf("calculated to low L1 fee: %d", receipt.L1Fee) return fmt.Errorf("calculated too low L1 fee: %d", receipt.L1Fee)
} }
env.log.Info("L1 fees test: success") env.log.Info("L1 fees test: success")
return nil return nil
......
This diff is collapsed.
package main
import (
"context"
"errors"
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-chain-ops/cmd/check-fjord/checks"
op_service "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/opio"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/urfave/cli/v2"
)
var (
prefix = "CHECK_FJORD"
EndpointL2 = &cli.StringFlag{
Name: "l2",
Usage: "L2 execution RPC endpoint",
EnvVars: op_service.PrefixEnvVar(prefix, "L2"),
Value: "http://localhost:9545",
}
AccountKey = &cli.StringFlag{
Name: "account",
Usage: "Private key (hex-formatted string) of test account to perform test txs with",
EnvVars: op_service.PrefixEnvVar(prefix, "ACCOUNT"),
}
)
type CheckAction func(ctx context.Context, env *checks.CheckFjordConfig) error
func makeFlags() []cli.Flag {
flags := []cli.Flag{
EndpointL2,
AccountKey,
}
return append(flags, oplog.CLIFlags(prefix)...)
}
func makeCommand(name string, fn CheckAction) *cli.Command {
return &cli.Command{
Name: name,
Action: makeCommandAction(fn),
Flags: cliapp.ProtectFlags(makeFlags()),
}
}
func makeCommandAction(fn CheckAction) func(c *cli.Context) error {
return func(c *cli.Context) error {
logCfg := oplog.ReadCLIConfig(c)
logger := oplog.NewLogger(c.App.Writer, logCfg)
c.Context = opio.CancelOnInterrupt(c.Context)
l2Cl, err := ethclient.DialContext(c.Context, c.String(EndpointL2.Name))
if err != nil {
return fmt.Errorf("failed to dial L2 RPC: %w", err)
}
key, err := crypto.HexToECDSA(c.String(AccountKey.Name))
if err != nil {
return fmt.Errorf("failed to parse test private key: %w", err)
}
if err := fn(c.Context, &checks.CheckFjordConfig{
Log: logger,
L2: l2Cl,
Key: key,
Addr: crypto.PubkeyToAddress(key.PublicKey),
}); err != nil {
return fmt.Errorf("command error: %w", err)
}
return nil
}
}
func main() {
app := cli.NewApp()
app.Name = "check-fjord"
app.Usage = "Check Fjord upgrade results."
app.Description = "Check Fjord upgrade results."
app.Action = func(c *cli.Context) error {
return errors.New("see sub-commands")
}
app.Writer = os.Stdout
app.ErrWriter = os.Stderr
app.Commands = []*cli.Command{
makeCommand("all", checks.CheckAll),
makeCommand("rip-7212", checks.CheckRIP7212),
{
Name: "fast-lz",
Subcommands: []*cli.Command{
makeCommand("gas-price-oracle", checks.CheckGasPriceOracle),
makeCommand("tx-empty", checks.CheckTxEmpty),
makeCommand("tx-all-zero", checks.CheckTxAllZero),
makeCommand("tx-all-42", checks.CheckTxAll42),
makeCommand("tx-random", checks.CheckTxRandom),
makeCommand("all", checks.CheckAllFastLz),
},
Flags: makeFlags(),
Action: makeCommandAction(checks.CheckAllFastLz),
},
}
err := app.Run(os.Args)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Application failed: %v\n", err)
os.Exit(1)
}
}
package op_e2e
import (
"context"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
fjordChecks "github.com/ethereum-optimism/optimism/op-chain-ops/cmd/check-fjord/checks"
"github.com/ethereum-optimism/optimism/op-service/testlog"
)
// TestCheckFjordScript ensures the op-chain-ops/cmd/check-fjord script runs successfully
// against a test chain with the fjord hardfork activated/unactivated
func TestCheckFjordScript(t *testing.T) {
log := testlog.Logger(t, log.LevelInfo)
cfg := DefaultSystemConfig(t)
genesisActivation := hexutil.Uint64(0)
cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisCanyonTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisDeltaTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisActivation
tests := []struct {
name string
fjordActivation *hexutil.Uint64
expectErr bool
}{
{
name: "fjord_activated",
fjordActivation: &genesisActivation,
expectErr: false,
},
{
name: "fjord_unactivated",
fjordActivation: nil,
expectErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
InitParallel(t)
cfg.DeployConfig.L2GenesisFjordTimeOffset = tt.fjordActivation
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
defer sys.Close()
checkFjordConfig := &fjordChecks.CheckFjordConfig{
Log: log,
L2: sys.Clients["sequencer"],
Key: sys.Cfg.Secrets.Alice,
Addr: sys.Cfg.Secrets.Addresses().Alice,
}
if tt.expectErr {
err = fjordChecks.CheckRIP7212(context.Background(), checkFjordConfig)
require.Error(t, err, "expected error for CheckRIP7212")
err = fjordChecks.CheckGasPriceOracle(context.Background(), checkFjordConfig)
require.Error(t, err, "expected error for CheckGasPriceOracle")
err = fjordChecks.CheckTxEmpty(context.Background(), checkFjordConfig)
require.Error(t, err, "expected error for CheckTxEmpty")
err = fjordChecks.CheckTxAllZero(context.Background(), checkFjordConfig)
require.Error(t, err, "expected error for CheckTxAllZero")
err = fjordChecks.CheckTxAll42(context.Background(), checkFjordConfig)
require.Error(t, err, "expected error for CheckTxAll42")
err = fjordChecks.CheckTxRandom(context.Background(), checkFjordConfig)
require.Error(t, err, "expected error for CheckTxRandom")
} else {
err = fjordChecks.CheckAll(context.Background(), checkFjordConfig)
require.NoError(t, err, "should not error on CheckAll")
}
})
}
}
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