From e5d592cedad79a5efaf606071f4b5ee52ded6e07 Mon Sep 17 00:00:00 2001 From: ethnical Date: Mon, 20 May 2024 23:42:46 +0200 Subject: [PATCH 01/34] feat: global_events listen on the logs of each blocks. --- op-monitorism/cmd/monitorism/cli.go | 23 +++ op-monitorism/global_events/cli.go | 56 +++++++ op-monitorism/global_events/monitor.go | 223 +++++++++++++++++++++++++ 3 files changed, 302 insertions(+) create mode 100644 op-monitorism/global_events/cli.go create mode 100644 op-monitorism/global_events/monitor.go diff --git a/op-monitorism/cmd/monitorism/cli.go b/op-monitorism/cmd/monitorism/cli.go index d8c98e3..5c07a44 100644 --- a/op-monitorism/cmd/monitorism/cli.go +++ b/op-monitorism/cmd/monitorism/cli.go @@ -7,6 +7,7 @@ import ( monitorism "github.com/ethereum-optimism/monitorism/op-monitorism" "github.com/ethereum-optimism/monitorism/op-monitorism/balances" "github.com/ethereum-optimism/monitorism/op-monitorism/fault" + "github.com/ethereum-optimism/monitorism/op-monitorism/global_events" "github.com/ethereum-optimism/monitorism/op-monitorism/multisig" "github.com/ethereum-optimism/monitorism/op-monitorism/withdrawals" @@ -60,6 +61,13 @@ func newCli(GitCommit string, GitDate string) *cli.App { Flags: append(balances.CLIFlags("BALANCE_MON"), defaultFlags...), Action: cliapp.LifecycleCmd(BalanceMain), }, + { + Name: "global_events", + Usage: "Monitors global events with YAML configuration", + Description: "Monitors global events with YAML configuration", + Flags: append(global_events.CLIFlags("global_events if you see this variable then changed into the code."), defaultFlags...), + Action: cliapp.LifecycleCmd(global_eventsMain), + }, { Name: "version", Usage: "Show version", @@ -73,6 +81,21 @@ func newCli(GitCommit string, GitDate string) *cli.App { } } +func global_eventsMain(ctx *cli.Context, closeApp context.CancelCauseFunc) (cliapp.Lifecycle, error) { + log := oplog.NewLogger(oplog.AppOut(ctx), oplog.ReadCLIConfig(ctx)) + cfg, err := global_events.ReadCLIFlags(ctx) + if err != nil { + return nil, fmt.Errorf("failed to parse global_events config from flags: %w", err) + } + + metricsRegistry := opmetrics.NewRegistry() + monitor, err := global_events.NewMonitor(ctx.Context, log, opmetrics.With(metricsRegistry), cfg) + if err != nil { + return nil, fmt.Errorf("failed to create global_events monitor: %w", err) + } + + return monitorism.NewCliApp(ctx, log, metricsRegistry, monitor) +} func MultisigMain(ctx *cli.Context, closeApp context.CancelCauseFunc) (cliapp.Lifecycle, error) { log := oplog.NewLogger(oplog.AppOut(ctx), oplog.ReadCLIConfig(ctx)) cfg, err := multisig.ReadCLIFlags(ctx) diff --git a/op-monitorism/global_events/cli.go b/op-monitorism/global_events/cli.go new file mode 100644 index 0000000..b8aa088 --- /dev/null +++ b/op-monitorism/global_events/cli.go @@ -0,0 +1,56 @@ +package global_events + +import ( + // "fmt" + + opservice "github.com/ethereum-optimism/optimism/op-service" + + "github.com/ethereum/go-ethereum/common" + + "github.com/urfave/cli/v2" +) + +const ( + L1NodeURLFlagName = "l1.node.url" + + NicknameFlagName = "nickname" + OptimismPortalAddressFlagName = "optimismportal.address" + SafeAddressFlagName = "safe.address" + OnePassVaultFlagName = "op.vault" +) + +type CLIConfig struct { + L1NodeURL string + Nickname string + OptimismPortalAddress common.Address + + // Optional + SafeAddress *common.Address + OnePassVault *string +} + +func ReadCLIFlags(ctx *cli.Context) (CLIConfig, error) { + cfg := CLIConfig{ + L1NodeURL: ctx.String(L1NodeURLFlagName), + Nickname: ctx.String(NicknameFlagName), + } + + return cfg, nil +} + +func CLIFlags(envVar string) []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: L1NodeURLFlagName, + Usage: "Node URL of L1 peer", + Value: "http://127.0.0.1:8545", + EnvVars: opservice.PrefixEnvVar(envVar, "L1_NODE_URL"), + }, + &cli.StringFlag{ + Name: NicknameFlagName, + Usage: "Nickname of chain being monitored", + EnvVars: opservice.PrefixEnvVar(envVar, "NICKNAME"), //need to change the name to BLOCKCHAIN_NAME + Required: true, + }, + } +} diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go new file mode 100644 index 0000000..728ee25 --- /dev/null +++ b/op-monitorism/global_events/monitor.go @@ -0,0 +1,223 @@ +package global_events + +import ( + "context" + // "encoding/json" + "fmt" + // "math/big" + // "os" + // "os/exec" + // "strconv" + // "strings" + + "github.com/ethereum-optimism/optimism/op-bindings/bindings" + "github.com/ethereum-optimism/optimism/op-service/metrics" + "github.com/ethereum/go-ethereum" + // "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + // "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + + "github.com/prometheus/client_golang/prometheus" +) + +const ( + MetricsNamespace = "multisig_mon" + SafeNonceABI = "nonce()" + + OPTokenEnvName = "OP_SERVICE_ACCOUNT_TOKEN" + + // Item names follow a `ready-.json` format + PresignedNonceTitlePrefix = "ready-" + PresignedNonceTitleSuffix = ".json" +) + +var ( + SafeNonceSelector = crypto.Keccak256([]byte(SafeNonceABI))[:4] +) + +type Monitor struct { + log log.Logger + + l1Client *ethclient.Client + + optimismPortalAddress common.Address + optimismPortal *bindings.OptimismPortalCaller + nickname string + + onePassToken string + onePassVault *string + safeAddress *common.Address + + // metrics + safeNonce *prometheus.GaugeVec + latestPresignedPauseNonce *prometheus.GaugeVec + pausedState *prometheus.GaugeVec + unexpectedRpcErrors *prometheus.CounterVec +} + +func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { + l1Client, err := ethclient.Dial(cfg.L1NodeURL) + if err != nil { + return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) + } + + if cfg.SafeAddress == nil { + log.Warn("safe integration is not configured") + } + + return &Monitor{ + log: log, + l1Client: l1Client, + + optimismPortalAddress: cfg.OptimismPortalAddress, + nickname: cfg.Nickname, + + safeAddress: cfg.SafeAddress, + onePassVault: cfg.OnePassVault, + + safeNonce: m.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: MetricsNamespace, + Name: "safeNonce", + Help: "Safe Nonce", + }, []string{"address", "nickname"}), + latestPresignedPauseNonce: m.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: MetricsNamespace, + Name: "latestPresignedPauseNonce", + Help: "Latest pre-signed pause nonce", + }, []string{"address", "nickname"}), + pausedState: m.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: MetricsNamespace, + Name: "pausedState", + Help: "OptimismPortal paused state", + }, []string{"address", "nickname"}), + unexpectedRpcErrors: m.NewCounterVec(prometheus.CounterOpts{ + Namespace: MetricsNamespace, + Name: "unexpectedRpcErrors", + Help: "number of unexpcted rpc errors", + }, []string{"section", "name"}), + }, nil +} + +func (m *Monitor) Run(ctx context.Context) { + m.checkEvents(ctx) + // m.checkSafeNonce(ctx) + // m.checkPresignedNonce(ctx) +} +func (m *Monitor) checkEvents(ctx context.Context) { + header, err := m.l1Client.HeaderByNumber(context.Background(), nil) + if err != nil { + log.Crit("Failed to retrieve latest block header: %v", err) + } + latestBlockNumber := header.Number + + query := ethereum.FilterQuery{ + FromBlock: latestBlockNumber, + ToBlock: latestBlockNumber, + Addresses: []common.Address{ + // List of addresses to filter the logs by; remove or modify as needed + }, + } + + logs, err := m.l1Client.FilterLogs(context.Background(), query) + if err != nil { + m.log.Crit("Failed to retrieve logs: %v", err) + } + + fmt.Println("--------------------------START OF BLOCK--------------------------------------") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Println("Block Number: ", latestBlockNumber) + fmt.Println("Number of logs: ", len(logs)) + fmt.Println("BlockHash:", header.Hash().Hex()) + // for _, vLog := range logs { + // fmt.Println("\n%s\n", vLog) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + // } + + fmt.Println("--------------------------END OF BLOCK--------------------------------------") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + // paused, err := m.optimismPortal.Paused(&bind.CallOpts{Context: ctx}) + // if err != nil { + // m.log.Error("failed to query OptimismPortal paused status", "err", err) + // m.unexpectedRpcErrors.WithLabelValues("optimismportal", "paused").Inc() + // return + // } + + // pausedMetric := 0 + // if paused { + // pausedMetric = 1 + // } + // + // m.pausedState.WithLabelValues(m.optimismPortalAddress.String(), m.nickname).Set(float64(pausedMetric)) + // m.log.Info("OptimismPortal status", "address", m.optimismPortalAddress.String(), "paused", paused) + m.log.Info("Checking events") +} + +// func (m *Monitor) checkSafeNonce(ctx context.Context) { +// if m.safeAddress == nil { +// m.log.Warn("safe address is not configured, skipping...") +// return +// } +// +// nonceBytes := hexutil.Bytes{} +// nonceTx := map[string]interface{}{"to": *m.safeAddress, "data": hexutil.Encode(SafeNonceSelector)} +// if err := m.l1Client.Client().CallContext(ctx, &nonceBytes, "eth_call", nonceTx, "latest"); err != nil { +// m.log.Error("failed to query safe nonce", "err", err) +// m.unexpectedRpcErrors.WithLabelValues("safe", "nonce()").Inc() +// return +// } +// +// nonce := new(big.Int).SetBytes(nonceBytes).Uint64() +// m.safeNonce.WithLabelValues(m.safeAddress.String(), m.nickname).Set(float64(nonce)) +// m.log.Info("Safe Nonce", "address", m.safeAddress.String(), "nonce", nonce) +// } + +// func (m *Monitor) checkPresignedNonce(ctx context.Context) { +// if m.onePassVault == nil { +// m.log.Warn("one pass integration is not configured, skipping...") +// return +// } +// +// cmd := exec.CommandContext(ctx, "op", "item", "list", "--format=json", fmt.Sprintf("--vault=%s", *m.onePassVault)) +// +// output, err := cmd.Output() +// if err != nil { +// m.log.Error("failed to run op cli") +// m.unexpectedRpcErrors.WithLabelValues("1pass", "exec").Inc() +// return +// } +// +// vaultItems := []struct{ Title string }{} +// if err := json.Unmarshal(output, &vaultItems); err != nil { +// m.log.Error("failed to unmarshal op cli stdout", "err", err) +// m.unexpectedRpcErrors.WithLabelValues("1pass", "stdout").Inc() +// return +// } +// +// latestPresignedNonce := int64(-1) +// for _, item := range vaultItems { +// if strings.HasPrefix(item.Title, PresignedNonceTitlePrefix) && strings.HasSuffix(item.Title, PresignedNonceTitleSuffix) { +// nonceStr := item.Title[len(PresignedNonceTitlePrefix) : len(item.Title)-len(PresignedNonceTitleSuffix)] +// nonce, err := strconv.ParseInt(nonceStr, 10, 64) +// if err != nil { +// m.log.Error("failed to parse nonce from item title", "title", item.Title) +// m.unexpectedRpcErrors.WithLabelValues("1pass", "title").Inc() +// return +// } +// if nonce > latestPresignedNonce { +// latestPresignedNonce = nonce +// } +// } +// } +// +// m.latestPresignedPauseNonce.WithLabelValues(m.safeAddress.String(), m.nickname).Set(float64(latestPresignedNonce)) +// if latestPresignedNonce == -1 { +// m.log.Error("no presigned nonce found") +// return +// } +// +// m.log.Info("Latest Presigned Nonce", "nonce", latestPresignedNonce) +// } +func (m *Monitor) Close(_ context.Context) error { + m.l1Client.Close() + return nil +} From 606a42295d7034fe43bbdd8bf1213a9e599ae7de Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 12:27:40 +0200 Subject: [PATCH 02/34] feat: Yaml template + logs fitering --- .../cmd/monitorism/SystemConfigUpdate.yaml | 11 ++ op-monitorism/cmd/monitorism/alerts.yaml | 13 ++ op-monitorism/global_events/cli.go | 25 ++-- op-monitorism/global_events/monitor.go | 117 ++++++++++++------ op-monitorism/global_events/monitor_test.go | 62 ++++++++++ op-monitorism/global_events/types.go | 78 ++++++++++++ 6 files changed, 259 insertions(+), 47 deletions(-) create mode 100644 op-monitorism/cmd/monitorism/SystemConfigUpdate.yaml create mode 100644 op-monitorism/cmd/monitorism/alerts.yaml create mode 100644 op-monitorism/global_events/monitor_test.go create mode 100644 op-monitorism/global_events/types.go diff --git a/op-monitorism/cmd/monitorism/SystemConfigUpdate.yaml b/op-monitorism/cmd/monitorism/SystemConfigUpdate.yaml new file mode 100644 index 0000000..32b6ced --- /dev/null +++ b/op-monitorism/cmd/monitorism/SystemConfigUpdate.yaml @@ -0,0 +1,11 @@ +# This watches the L1 SystemConfig for OP Mainnet for config updates. +version: 1.0 +name: SystemConfig Config Updates +priority: P2 +addresses: + - eth/op/SystemConfig +events: + - signature: ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data) + # Notice that the above signature is not normalized. The normalized version is: + # ConfigUpdate(uint256,uint8,bytes) + # But for UX diff --git a/op-monitorism/cmd/monitorism/alerts.yaml b/op-monitorism/cmd/monitorism/alerts.yaml new file mode 100644 index 0000000..93429dd --- /dev/null +++ b/op-monitorism/cmd/monitorism/alerts.yaml @@ -0,0 +1,13 @@ +# This watches all contacts for OP, Mode, and Base mainnets for two logs. +# These logs are emitted by Safes, so this effectively watches for all +# transactions from any Safe on these chains. +version: 1.0 +name: Safe Watcher +priority: P0 +addresses: + - eth/op + - eth/mode + - eth/base +events: + - signature: ExecutionFailure(bytes32,uint256) + - signature: ExecutionSuccess(bytes32,uint256) diff --git a/op-monitorism/global_events/cli.go b/op-monitorism/global_events/cli.go index b8aa088..97c777b 100644 --- a/op-monitorism/global_events/cli.go +++ b/op-monitorism/global_events/cli.go @@ -5,34 +5,29 @@ import ( opservice "github.com/ethereum-optimism/optimism/op-service" - "github.com/ethereum/go-ethereum/common" + // "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v2" ) const ( L1NodeURLFlagName = "l1.node.url" - - NicknameFlagName = "nickname" - OptimismPortalAddressFlagName = "optimismportal.address" - SafeAddressFlagName = "safe.address" - OnePassVaultFlagName = "op.vault" + NicknameFlagName = "nickname" + PathYamlFlagName = "pathYaml" ) type CLIConfig struct { - L1NodeURL string - Nickname string - OptimismPortalAddress common.Address - + L1NodeURL string + Nickname string + pathYaml string // Optional - SafeAddress *common.Address - OnePassVault *string } func ReadCLIFlags(ctx *cli.Context) (CLIConfig, error) { cfg := CLIConfig{ L1NodeURL: ctx.String(L1NodeURLFlagName), Nickname: ctx.String(NicknameFlagName), + pathYaml: ctx.String(PathYamlFlagName), } return cfg, nil @@ -52,5 +47,11 @@ func CLIFlags(envVar string) []cli.Flag { EnvVars: opservice.PrefixEnvVar(envVar, "NICKNAME"), //need to change the name to BLOCKCHAIN_NAME Required: true, }, + &cli.StringFlag{ + Name: PathYamlFlagName, + Usage: "Path to the yaml file containing the events to monitor", + EnvVars: opservice.PrefixEnvVar(envVar, "PATH_YAML"), //need to change the name to BLOCKCHAIN_NAME + Required: true, + }, } } diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 728ee25..7b60c77 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -9,10 +9,11 @@ import ( // "os/exec" // "strconv" // "strings" - - "github.com/ethereum-optimism/optimism/op-bindings/bindings" + // "github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum/go-ethereum" + "regexp" + "strings" // "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" // "github.com/ethereum/go-ethereum/common/hexutil" @@ -24,32 +25,25 @@ import ( ) const ( - MetricsNamespace = "multisig_mon" - SafeNonceABI = "nonce()" + MetricsNamespace = "global_events_mon" - OPTokenEnvName = "OP_SERVICE_ACCOUNT_TOKEN" + // OPTokenEnvName = "OP_SERVICE_ACCOUNT_TOKEN" // Item names follow a `ready-.json` format - PresignedNonceTitlePrefix = "ready-" - PresignedNonceTitleSuffix = ".json" -) - -var ( - SafeNonceSelector = crypto.Keccak256([]byte(SafeNonceABI))[:4] + // PresignedNonceTitlePrefix = "ready-" + // PresignedNonceTitleSuffix = ".json" ) type Monitor struct { log log.Logger - l1Client *ethclient.Client + l1Client *ethclient.Client + MonitoringAddresses []MonitoringAddress - optimismPortalAddress common.Address - optimismPortal *bindings.OptimismPortalCaller - nickname string + nickname string - onePassToken string - onePassVault *string - safeAddress *common.Address + filename string //filename of the yaml rules + yamlconfig Configuration // metrics safeNonce *prometheus.GaugeVec @@ -63,21 +57,24 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) } + fmt.Printf("--------------------------------------- global_events_mon (Infos) -----------------------------\n") + fmt.Printf("PathYaml: %v\n", cfg.pathYaml) + fmt.Printf("Nickname: %v\n", cfg.Nickname) + fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) + yamlconfig := ReadYamlFile(cfg.pathYaml) - if cfg.SafeAddress == nil { - log.Warn("safe integration is not configured") - } + MonitoringAddresses := fromConfigurationToAddress(yamlconfig) + DisplayMonitorAddresses(MonitoringAddresses) + fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") + // fmt.Printf("YAML Config: %v\n", yamlconfig) return &Monitor{ - log: log, - l1Client: l1Client, - - optimismPortalAddress: cfg.OptimismPortalAddress, - nickname: cfg.Nickname, - - safeAddress: cfg.SafeAddress, - onePassVault: cfg.OnePassVault, + log: log, + l1Client: l1Client, + MonitoringAddresses: MonitoringAddresses, + nickname: cfg.Nickname, + yamlconfig: yamlconfig, safeNonce: m.NewGaugeVec(prometheus.GaugeOpts{ Namespace: MetricsNamespace, Name: "safeNonce", @@ -100,9 +97,54 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC }, []string{"section", "name"}), }, nil } +func formatSignature(signature string) string { + // Regex to extract function name and parameters + r := regexp.MustCompile(`(\w+)\s*\(([^)]*)\)`) + matches := r.FindStringSubmatch(signature) + + if len(matches) != 3 { + return "" + } + + // Function name + funcName := matches[1] + // Parameters, split by commas + params := matches[2] + // Clean parameters to keep only types + cleanParams := make([]string, 0) + for _, param := range strings.Split(params, ",") { + parts := strings.Fields(param) + if len(parts) > 0 { + cleanParams = append(cleanParams, parts[0]) + } + } + + // Return formatted function signature + return fmt.Sprintf("%s(%s)", funcName, strings.Join(cleanParams, ",")) +} + +// Format And Hash the signature to create the topic. +// Formatting allows use to use "transfer(address owner, uint256 amount)" instead of "transfer(address,uint256 +// So with the name parameters + +func FormatAndHash(signature string) []byte { // this will return the topic not the 4bytes so longer. + formattedSignature := formatSignature(signature) + if formattedSignature == "" { + panic("Invalid signature") + } + hash := crypto.Keccak256([]byte(formattedSignature)) + return hash +} func (m *Monitor) Run(ctx context.Context) { - m.checkEvents(ctx) + // m.checkEvents(ctx) + input := "balanceOf(address owner)" + formattedSignature := formatSignature(input) + if formattedSignature == "" { + panic("Invalid signature") + } + hash := crypto.Keccak256([]byte(formattedSignature)) + fmt.Printf("Function Selector: 0x%x\n", hash[:4]) // m.checkSafeNonce(ctx) // m.checkPresignedNonce(ctx) } @@ -126,15 +168,20 @@ func (m *Monitor) checkEvents(ctx context.Context) { m.log.Crit("Failed to retrieve logs: %v", err) } - fmt.Println("--------------------------START OF BLOCK--------------------------------------") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("-------------------------- START OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` fmt.Println("Block Number: ", latestBlockNumber) fmt.Println("Number of logs: ", len(logs)) fmt.Println("BlockHash:", header.Hash().Hex()) - // for _, vLog := range logs { - // fmt.Println("\n%s\n", vLog) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - // } + for _, vLog := range logs { + // if vlog.Topics == topics_toml { + // // alerting + 1 + // } + fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("TxHash: %s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + } - fmt.Println("--------------------------END OF BLOCK--------------------------------------") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("-------------------------- END OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` // paused, err := m.optimismPortal.Paused(&bind.CallOpts{Context: ctx}) // if err != nil { // m.log.Error("failed to query OptimismPortal paused status", "err", err) diff --git a/op-monitorism/global_events/monitor_test.go b/op-monitorism/global_events/monitor_test.go new file mode 100644 index 0000000..7ed37c3 --- /dev/null +++ b/op-monitorism/global_events/monitor_test.go @@ -0,0 +1,62 @@ +package global_events + +import ( + // "strings" + "testing" +) + +func TestFormatSignature(t *testing.T) { + tests := []struct { + name string + input string + expectedOutput string + }{ + { + name: "Basic Function", + input: "balanceOf(address owner)", + expectedOutput: "balanceOf(address)", + }, + { + name: "Function With Multiple Params", + input: "transfer(address to, uint256 amount)", + expectedOutput: "transfer(address,uint256)", + }, + { + name: "Function With No Params", + input: "pause()", + expectedOutput: "pause()", + }, + { + name: "Function With Extra Spaces", + input: " approve ( address spender , uint256 value ) ", + expectedOutput: "approve(address,uint256)", + }, + { + name: "Invalid Input", + input: "invalidInput", + expectedOutput: "", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + output := formatSignature(test.input) + if output != test.expectedOutput { + t.Errorf("Failed %s: expected %q but got %q", test.name, test.expectedOutput, output) + } + t.Logf("Success %s: from %q got %q", test.name, test.input, output) + + }) + } +} + +// func TestFunctionSelector(t *testing.T) { +// expectedSelector := "70a08231" // known selector for "balanceOf(address)" +// formattedSignature := "balanceOf(address)" +// hash := crypto.Keccak256([]byte(formattedSignature)) +// selector := strings.ToLower(fmt.Sprintf("%x", hash[:4])) +// +// if selector != expectedSelector { +// t.Errorf("Selector calculation failed: expected %s but got %s", expectedSelector, selector) +// } +// } diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go new file mode 100644 index 0000000..93e3fd9 --- /dev/null +++ b/op-monitorism/global_events/types.go @@ -0,0 +1,78 @@ +package global_events + +import ( + "fmt" + "gopkg.in/yaml.v3" + "os" +) + +type EventTopic struct { + Index int `yaml:"index"` + Values []string `yaml:"values"` +} + +type Event struct { + _4bytes string // That is the 4 bytes of the event signature, will be generated from the Event.Signature function just below this. + Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" + // Topics []EventTopic `yaml:"topics,omitempty"` +} + +type Configuration struct { + Version string `yaml:"version"` + Name string `yaml:"name"` + Priority string `yaml:"priority"` + Addresses []string `yaml:"addresses"` + Events []Event `yaml:"events"` +} + +type MonitoringAddress struct { + Address string `yaml:"addresses"` + Events []Event `yaml:"events"` +} + +func ReadYamlFile(filename string) Configuration { + var config Configuration + data, err := os.ReadFile(filename) + if err != nil { + fmt.Println("Error reading YAML file:", err) + panic("Error reading YAML") + } + err = yaml.Unmarshal(data, &config) + if err != nil { + fmt.Println("Error reading YAML file:", err) + panic("Error reading YAML") + + } + return config +} + +// fromConfigurationToAddress take the configuration yaml and create the `monitoringAddresses` array +// that will contains all the addresses that will monitore. +func fromConfigurationToAddress(config Configuration) []MonitoringAddress { + var monitoringAddresses []MonitoringAddress + for _, address := range config.Addresses { + event_with_4bytes := make([]Event, len(config.Events)) + for _, event := range config.Events { + event._4bytes = string(FormatAndHash(event.Signature)) + event_with_4bytes = append(event_with_4bytes, event) + } + monitoringAddresses = append(monitoringAddresses, MonitoringAddress{Address: address, Events: event_with_4bytes}) + } + return monitoringAddresses +} +func DisplayMonitorAddresses(monitoringAddresses []MonitoringAddress) { + println("Monitoring addresses") + fmt.Printf("Number of addresses: %d\n", len(monitoringAddresses)) //need to put also the number of events + fmt.Printf("Number of events: %d\n", len(monitoringAddresses[0].Events)) + for _, address := range monitoringAddresses { + fmt.Println("Address:", address.Address) + for _, event := range address.Events { + fmt.Println("Event:", event.Signature, "4bytes:", event._4bytes) + } + } +} + +// if _, err := toml.DecodeFile("config.toml", &config); err != nil { +// fmt.Println("Error loading TOML data:", err) +// os.Exit(1) +// } From 44cd9caf31513e8529687f4a17e9b04d796d9728 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 14:04:49 +0200 Subject: [PATCH 03/34] chore: add current block infos + ChainId to ensure we are on the correct chain --- op-monitorism/global_events/monitor.go | 22 ++++++++++++++++++++++ op-monitorism/global_events/types.go | 9 ++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 7b60c77..10cd361 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -52,12 +52,34 @@ type Monitor struct { unexpectedRpcErrors *prometheus.CounterVec } +func ChainIDToName(chainID int64) string { + switch chainID { + case 1: + return "Ethereum [Mainnet]" + case 11155111: + return "Sepolia [Testnet]" + } + return "The ChainID is Not defined into the chaindIDToName function, this is probably a custom chain." +} + func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { l1Client, err := ethclient.Dial(cfg.L1NodeURL) if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) } fmt.Printf("--------------------------------------- global_events_mon (Infos) -----------------------------\n") + // fmt.Printf("chainID:", ChainIDToName(l1Client.ChainID()) + ChainID, err := l1Client.ChainID(context.Background()) + if err != nil { + log.Crit("Failed to retrieve chain ID: %v", err) + } + header, err := l1Client.HeaderByNumber(context.Background(), nil) + if err != nil { + log.Crit("Failed to fetch the latest block header: %v", err) + } + + fmt.Printf("latestBlockNumber: %s\n", header.Number) + fmt.Printf("chainId: %+v\n", ChainIDToName(ChainID.Int64())) fmt.Printf("PathYaml: %v\n", cfg.pathYaml) fmt.Printf("Nickname: %v\n", cfg.Nickname) fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 93e3fd9..ac79cc9 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -51,10 +51,11 @@ func ReadYamlFile(filename string) Configuration { func fromConfigurationToAddress(config Configuration) []MonitoringAddress { var monitoringAddresses []MonitoringAddress for _, address := range config.Addresses { - event_with_4bytes := make([]Event, len(config.Events)) + var event_with_4bytes []Event for _, event := range config.Events { event._4bytes = string(FormatAndHash(event.Signature)) event_with_4bytes = append(event_with_4bytes, event) + } monitoringAddresses = append(monitoringAddresses, MonitoringAddress{Address: address, Events: event_with_4bytes}) } @@ -65,10 +66,12 @@ func DisplayMonitorAddresses(monitoringAddresses []MonitoringAddress) { fmt.Printf("Number of addresses: %d\n", len(monitoringAddresses)) //need to put also the number of events fmt.Printf("Number of events: %d\n", len(monitoringAddresses[0].Events)) for _, address := range monitoringAddresses { - fmt.Println("Address:", address.Address) + fmt.Println("===============================\nAddress:", address.Address) for _, event := range address.Events { - fmt.Println("Event:", event.Signature, "4bytes:", event._4bytes) + fmt.Printf("Event: %s, Topic[0]: %x\n", event.Signature, event._4bytes) } + + fmt.Println("===============================") } } From c27a107bed4a07b11d2a3ad8646904c83b3f48a5 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 15:18:58 +0200 Subject: [PATCH 04/34] chore: move the rules into a dedicated folders --- op-monitorism/cmd/{monitorism => rules}/SystemConfigUpdate.yaml | 0 op-monitorism/cmd/{monitorism => rules}/alerts.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename op-monitorism/cmd/{monitorism => rules}/SystemConfigUpdate.yaml (100%) rename op-monitorism/cmd/{monitorism => rules}/alerts.yaml (100%) diff --git a/op-monitorism/cmd/monitorism/SystemConfigUpdate.yaml b/op-monitorism/cmd/rules/SystemConfigUpdate.yaml similarity index 100% rename from op-monitorism/cmd/monitorism/SystemConfigUpdate.yaml rename to op-monitorism/cmd/rules/SystemConfigUpdate.yaml diff --git a/op-monitorism/cmd/monitorism/alerts.yaml b/op-monitorism/cmd/rules/alerts.yaml similarity index 100% rename from op-monitorism/cmd/monitorism/alerts.yaml rename to op-monitorism/cmd/rules/alerts.yaml From 9c1c1a52340bb575f8aab4e50f9819f18fa96118 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 15:19:39 +0200 Subject: [PATCH 05/34] chore: rename the param --- op-monitorism/global_events/cli.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/op-monitorism/global_events/cli.go b/op-monitorism/global_events/cli.go index 97c777b..a4b439a 100644 --- a/op-monitorism/global_events/cli.go +++ b/op-monitorism/global_events/cli.go @@ -10,24 +10,25 @@ import ( "github.com/urfave/cli/v2" ) +// args in CLI have to be standardized and clean. const ( - L1NodeURLFlagName = "l1.node.url" - NicknameFlagName = "nickname" - PathYamlFlagName = "pathYaml" + L1NodeURLFlagName = "l1.node.url" + NicknameFlagName = "nickname" + PathYamlRulesFlagName = "PathYamlRules" ) type CLIConfig struct { - L1NodeURL string - Nickname string - pathYaml string + L1NodeURL string + Nickname string + PathYamlRules string // Optional } func ReadCLIFlags(ctx *cli.Context) (CLIConfig, error) { cfg := CLIConfig{ - L1NodeURL: ctx.String(L1NodeURLFlagName), - Nickname: ctx.String(NicknameFlagName), - pathYaml: ctx.String(PathYamlFlagName), + L1NodeURL: ctx.String(L1NodeURLFlagName), + Nickname: ctx.String(NicknameFlagName), + PathYamlRules: ctx.String(PathYamlRulesFlagName), } return cfg, nil @@ -48,7 +49,7 @@ func CLIFlags(envVar string) []cli.Flag { Required: true, }, &cli.StringFlag{ - Name: PathYamlFlagName, + Name: PathYamlRulesFlagName, Usage: "Path to the yaml file containing the events to monitor", EnvVars: opservice.PrefixEnvVar(envVar, "PATH_YAML"), //need to change the name to BLOCKCHAIN_NAME Required: true, From b0f020cb2b3d9a7e5e89400d0ba448c7407788db Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 15:20:17 +0200 Subject: [PATCH 06/34] feat: add logging and infos to ensure no mistake when running --- op-monitorism/global_events/monitor.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 10cd361..6507bd6 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -2,6 +2,7 @@ package global_events import ( "context" + // "os" // "encoding/json" "fmt" // "math/big" @@ -10,10 +11,12 @@ import ( // "strconv" // "strings" // "github.com/ethereum-optimism/optimism/op-bindings/bindings" - "github.com/ethereum-optimism/optimism/op-service/metrics" - "github.com/ethereum/go-ethereum" "regexp" "strings" + + "github.com/ethereum-optimism/optimism/op-service/metrics" + "github.com/ethereum/go-ethereum" + // "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" // "github.com/ethereum/go-ethereum/common/hexutil" @@ -59,7 +62,7 @@ func ChainIDToName(chainID int64) string { case 11155111: return "Sepolia [Testnet]" } - return "The ChainID is Not defined into the chaindIDToName function, this is probably a custom chain." + return "The ChainID is Not defined into the chaindIDToName function, this is probably a custom chain otherwise something is going wrong!" } func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { @@ -77,15 +80,16 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC if err != nil { log.Crit("Failed to fetch the latest block header: %v", err) } - + // display the infos at the start to ensure everything is correct. fmt.Printf("latestBlockNumber: %s\n", header.Number) fmt.Printf("chainId: %+v\n", ChainIDToName(ChainID.Int64())) - fmt.Printf("PathYaml: %v\n", cfg.pathYaml) + fmt.Printf("PathYaml: %v\n", cfg.PathYamlRules) fmt.Printf("Nickname: %v\n", cfg.Nickname) fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) - yamlconfig := ReadYamlFile(cfg.pathYaml) + MonitoringAddresses := ReadAllYamlRules(cfg.PathYamlRules) + // yamlconfig := ReadYamlFile(cfg.PathYamlRules) - MonitoringAddresses := fromConfigurationToAddress(yamlconfig) + // MonitoringAddresses := fromConfigurationToAddress(yamlconfig) DisplayMonitorAddresses(MonitoringAddresses) fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") @@ -95,8 +99,8 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC l1Client: l1Client, MonitoringAddresses: MonitoringAddresses, - nickname: cfg.Nickname, - yamlconfig: yamlconfig, + nickname: cfg.Nickname, + // yamlconfig: yamlconfig, safeNonce: m.NewGaugeVec(prometheus.GaugeOpts{ Namespace: MetricsNamespace, Name: "safeNonce", From c12d2a299916a70a17e8ed267649cdf9990d903b Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 15:20:48 +0200 Subject: [PATCH 07/34] feat: add the possibilities or reading of the rules at once. --- op-monitorism/global_events/types.go | 43 ++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index ac79cc9..5559398 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -4,6 +4,7 @@ import ( "fmt" "gopkg.in/yaml.v3" "os" + "path/filepath" ) type EventTopic struct { @@ -61,18 +62,50 @@ func fromConfigurationToAddress(config Configuration) []MonitoringAddress { } return monitoringAddresses } + +// Read all the files in the `rules` directory at the given path from the command line `--PathYamlRules` that are YAML files. +func ReadAllYamlRules(PathYamlRules string) []MonitoringAddress { + var monitoringAddresses []MonitoringAddress + + entries, err := os.ReadDir(PathYamlRules) //Only read yaml files + if err != nil { + fmt.Println("Error reading directory:", err) + panic("Error reading directory") + } + var yamlFiles []os.DirEntry + // Filter entries for files ending with ".yaml" or ".yml" + for _, entry := range entries { + if entry.IsDir() { + continue // Skip directories + } + + // Check if the file ends with ".yaml" or ".yml" + if filepath.Ext(entry.Name()) == ".yaml" || filepath.Ext(entry.Name()) == ".yml" { + yamlFiles = append(yamlFiles, entry) + } + } + + for _, file := range yamlFiles { + path_rule := PathYamlRules + "/" + file.Name() + fmt.Printf("Reading a rule named: %s\n", path_rule) + yamlconfig := ReadYamlFile(path_rule) + monitoringAddresses = append(monitoringAddresses, fromConfigurationToAddress(yamlconfig)...) + + } + + return monitoringAddresses +} func DisplayMonitorAddresses(monitoringAddresses []MonitoringAddress) { - println("Monitoring addresses") - fmt.Printf("Number of addresses: %d\n", len(monitoringAddresses)) //need to put also the number of events - fmt.Printf("Number of events: %d\n", len(monitoringAddresses[0].Events)) + println("============== Monitoring addresses =================") for _, address := range monitoringAddresses { - fmt.Println("===============================\nAddress:", address.Address) + fmt.Println("Address:", address.Address) for _, event := range address.Events { fmt.Printf("Event: %s, Topic[0]: %x\n", event.Signature, event._4bytes) } - fmt.Println("===============================") } + fmt.Println("===============================") + } // if _, err := toml.DecodeFile("config.toml", &config); err != nil { From 24efca4707763b54e9dfabe9512013bc4634a9e5 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 19:07:15 +0200 Subject: [PATCH 08/34] feat: add a new general structure that hold the addresses and events. --- op-monitorism/global_events/monitor.go | 40 ++++++++++++----------- op-monitorism/global_events/types.go | 44 +++++++++++++++++++++----- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 6507bd6..c742c08 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -40,8 +40,8 @@ const ( type Monitor struct { log log.Logger - l1Client *ethclient.Client - MonitoringAddresses []MonitoringAddress + l1Client *ethclient.Client + TabMonitoringAddresses TabMonitoringAddress nickname string @@ -62,7 +62,7 @@ func ChainIDToName(chainID int64) string { case 11155111: return "Sepolia [Testnet]" } - return "The ChainID is Not defined into the chaindIDToName function, this is probably a custom chain otherwise something is going wrong!" + return "The `ChainID` is Not defined into the `chaindIDToName` function, this is probably a custom chain otherwise something is going wrong!" } func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { @@ -70,7 +70,7 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) } - fmt.Printf("--------------------------------------- global_events_mon (Infos) -----------------------------\n") + fmt.Printf("--------------------------------------- Global_events_mon (Infos) -----------------------------\n") // fmt.Printf("chainID:", ChainIDToName(l1Client.ChainID()) ChainID, err := l1Client.ChainID(context.Background()) if err != nil { @@ -86,18 +86,20 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC fmt.Printf("PathYaml: %v\n", cfg.PathYamlRules) fmt.Printf("Nickname: %v\n", cfg.Nickname) fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) - MonitoringAddresses := ReadAllYamlRules(cfg.PathYamlRules) + TabMonitoringAddresses := ReadAllYamlRules(cfg.PathYamlRules) // yamlconfig := ReadYamlFile(cfg.PathYamlRules) + fmt.Printf("Number of Addresses monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetUniqueMonitoredAddresses())) + fmt.Printf("Number of Events monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetMonitoredEvents())) // MonitoringAddresses := fromConfigurationToAddress(yamlconfig) - DisplayMonitorAddresses(MonitoringAddresses) + // DisplayMonitorAddresses(MonitoringAddresses) fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") // fmt.Printf("YAML Config: %v\n", yamlconfig) return &Monitor{ - log: log, - l1Client: l1Client, - MonitoringAddresses: MonitoringAddresses, + log: log, + l1Client: l1Client, + TabMonitoringAddresses: TabMonitoringAddresses, nickname: cfg.Nickname, // yamlconfig: yamlconfig, @@ -163,16 +165,16 @@ func FormatAndHash(signature string) []byte { // this will return the topic not } func (m *Monitor) Run(ctx context.Context) { - // m.checkEvents(ctx) - input := "balanceOf(address owner)" - formattedSignature := formatSignature(input) - if formattedSignature == "" { - panic("Invalid signature") - } - hash := crypto.Keccak256([]byte(formattedSignature)) - fmt.Printf("Function Selector: 0x%x\n", hash[:4]) - // m.checkSafeNonce(ctx) - // m.checkPresignedNonce(ctx) + m.checkEvents(ctx) + // input := "balanceOf(address owner)" + // formattedSignature := formatSignature(input) + // if formattedSignature == "" { + // panic("Invalid signature") + // } + // hash := crypto.Keccak256([]byte(formattedSignature)) + // fmt.Printf("Function Selector: 0x%x\n", hash[:4]) + // // m.checkSafeNonce(ctx) + // // m.checkPresignedNonce(ctx) } func (m *Monitor) checkEvents(ctx context.Context) { header, err := m.l1Client.HeaderByNumber(context.Background(), nil) diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 5559398..3adabb1 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -5,6 +5,7 @@ import ( "gopkg.in/yaml.v3" "os" "path/filepath" + "slices" ) type EventTopic struct { @@ -31,6 +32,39 @@ type MonitoringAddress struct { Events []Event `yaml:"events"` } +type TabMonitoringAddress struct { + MonitoringAddress []MonitoringAddress +} + +// Return all the addresses currently monitored +func (T TabMonitoringAddress) GetMonitoredAddresses() []string { + var addresses []string + for _, T := range T.MonitoringAddress { + addresses = append(addresses, T.Address) + } + + return addresses +} + +// Return all the events currently monitored +func (T TabMonitoringAddress) GetMonitoredEvents() []Event { + var Events []Event + for _, T := range T.MonitoringAddress { + for _, event := range T.Events { + Events = append(Events, event) + } + } + + return Events +} + +// return all the UNIQUE addresses currently GetMonitoredEvents +func (T TabMonitoringAddress) GetUniqueMonitoredAddresses() []string { + temporary := T.GetMonitoredAddresses() + slices.Sort(temporary) + return slices.Compact(temporary) +} + func ReadYamlFile(filename string) Configuration { var config Configuration data, err := os.ReadFile(filename) @@ -64,7 +98,7 @@ func fromConfigurationToAddress(config Configuration) []MonitoringAddress { } // Read all the files in the `rules` directory at the given path from the command line `--PathYamlRules` that are YAML files. -func ReadAllYamlRules(PathYamlRules string) []MonitoringAddress { +func ReadAllYamlRules(PathYamlRules string) TabMonitoringAddress { var monitoringAddresses []MonitoringAddress entries, err := os.ReadDir(PathYamlRules) //Only read yaml files @@ -93,7 +127,7 @@ func ReadAllYamlRules(PathYamlRules string) []MonitoringAddress { } - return monitoringAddresses + return TabMonitoringAddress{MonitoringAddress: monitoringAddresses} } func DisplayMonitorAddresses(monitoringAddresses []MonitoringAddress) { println("============== Monitoring addresses =================") @@ -102,13 +136,7 @@ func DisplayMonitorAddresses(monitoringAddresses []MonitoringAddress) { for _, event := range address.Events { fmt.Printf("Event: %s, Topic[0]: %x\n", event.Signature, event._4bytes) } - } fmt.Println("===============================") } - -// if _, err := toml.DecodeFile("config.toml", &config); err != nil { -// fmt.Println("Error loading TOML data:", err) -// os.Exit(1) -// } From 27e34ca8559a4774899d973fb7836ef751fe0228 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 21:47:02 +0200 Subject: [PATCH 09/34] feat: add the feature to monitore the empty addresses (all the addresses) + add the fact we don't suport the `sep:` inside the yaml files. --- op-monitorism/cmd/rules/{alerts.yaml => SafeExecution.yaml} | 5 +---- op-monitorism/cmd/rules/SystemConfigUpdate.yaml | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) rename op-monitorism/cmd/rules/{alerts.yaml => SafeExecution.yaml} (72%) diff --git a/op-monitorism/cmd/rules/alerts.yaml b/op-monitorism/cmd/rules/SafeExecution.yaml similarity index 72% rename from op-monitorism/cmd/rules/alerts.yaml rename to op-monitorism/cmd/rules/SafeExecution.yaml index 93429dd..904da1a 100644 --- a/op-monitorism/cmd/rules/alerts.yaml +++ b/op-monitorism/cmd/rules/SafeExecution.yaml @@ -4,10 +4,7 @@ version: 1.0 name: Safe Watcher priority: P0 -addresses: - - eth/op - - eth/mode - - eth/base +addresses: # /!\ We are not supporting EIP 3770 yet, if the address is not starting by `0x`, this will panic by safety measure. events: - signature: ExecutionFailure(bytes32,uint256) - signature: ExecutionSuccess(bytes32,uint256) diff --git a/op-monitorism/cmd/rules/SystemConfigUpdate.yaml b/op-monitorism/cmd/rules/SystemConfigUpdate.yaml index 32b6ced..a9d3fcd 100644 --- a/op-monitorism/cmd/rules/SystemConfigUpdate.yaml +++ b/op-monitorism/cmd/rules/SystemConfigUpdate.yaml @@ -1,9 +1,9 @@ # This watches the L1 SystemConfig for OP Mainnet for config updates. +# - eth/op/SystemConfig version: 1.0 name: SystemConfig Config Updates priority: P2 -addresses: - - eth/op/SystemConfig +addresses: # /!\ We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. events: - signature: ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data) # Notice that the above signature is not normalized. The normalized version is: From a261b4ab8e8d62607ad3464d4f6f7c6611d6da3d Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 21:48:05 +0200 Subject: [PATCH 10/34] feat: Insert the `common.Address` type --- op-monitorism/global_events/types.go | 49 ++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 3adabb1..b34cecf 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -2,10 +2,12 @@ package global_events import ( "fmt" + "github.com/ethereum/go-ethereum/common" + "golang.org/x/exp/maps" "gopkg.in/yaml.v3" "os" "path/filepath" - "slices" + // "slices" ) type EventTopic struct { @@ -20,16 +22,16 @@ type Event struct { } type Configuration struct { - Version string `yaml:"version"` - Name string `yaml:"name"` - Priority string `yaml:"priority"` - Addresses []string `yaml:"addresses"` - Events []Event `yaml:"events"` + Version string `yaml:"version"` + Name string `yaml:"name"` + Priority string `yaml:"priority"` + Addresses []common.Address `yaml:"addresses"` //TODO: add the superchain registry with the format `/l1/l2/optimismPortal` + Events []Event `yaml:"events"` } type MonitoringAddress struct { - Address string `yaml:"addresses"` - Events []Event `yaml:"events"` + Address common.Address `yaml:"addresses"` + Events []Event `yaml:"events"` } type TabMonitoringAddress struct { @@ -37,8 +39,8 @@ type TabMonitoringAddress struct { } // Return all the addresses currently monitored -func (T TabMonitoringAddress) GetMonitoredAddresses() []string { - var addresses []string +func (T TabMonitoringAddress) GetMonitoredAddresses() []common.Address { + var addresses []common.Address for _, T := range T.MonitoringAddress { addresses = append(addresses, T.Address) } @@ -59,10 +61,15 @@ func (T TabMonitoringAddress) GetMonitoredEvents() []Event { } // return all the UNIQUE addresses currently GetMonitoredEvents -func (T TabMonitoringAddress) GetUniqueMonitoredAddresses() []string { - temporary := T.GetMonitoredAddresses() - slices.Sort(temporary) - return slices.Compact(temporary) +func (T TabMonitoringAddress) GetUniqueMonitoredAddresses() []common.Address { + hashmap := make(map[common.Address]bool) + for _, address := range T.GetMonitoredAddresses() { + if address != common.HexToAddress("0x0") { // If the address is set to 0x0, it means we are monitoring all the addresses, so we need to remove it from the tab here. + hashmap[address] = true + } + + } + return maps.Keys(hashmap) } func ReadYamlFile(filename string) Configuration { @@ -85,6 +92,19 @@ func ReadYamlFile(filename string) Configuration { // that will contains all the addresses that will monitore. func fromConfigurationToAddress(config Configuration) []MonitoringAddress { var monitoringAddresses []MonitoringAddress + if len(config.Addresses) == 0 && len(config.Events) > 0 { + fmt.Println("No addresses to monitor, but some events are defined (this means we are monitoring all the addresses), probably for debugging purposes.") + var event_with_4bytes []Event + for _, event := range config.Events { + event._4bytes = string(FormatAndHash(event.Signature)) + event_with_4bytes = append(event_with_4bytes, event) + + } + monitoringAddresses = append(monitoringAddresses, MonitoringAddress{Address: common.Address{}, Events: event_with_4bytes}) + + return []MonitoringAddress{MonitoringAddress{Address: common.Address{}, Events: event_with_4bytes}} + } + for _, address := range config.Addresses { var event_with_4bytes []Event for _, event := range config.Events { @@ -94,6 +114,7 @@ func fromConfigurationToAddress(config Configuration) []MonitoringAddress { } monitoringAddresses = append(monitoringAddresses, MonitoringAddress{Address: address, Events: event_with_4bytes}) } + return monitoringAddresses } From 851b96cea192d7a0ab062c477fc6303c216ef401 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 21:49:10 +0200 Subject: [PATCH 11/34] feat: Monitore all the events when the addresses are empty. --- op-monitorism/global_events/monitor.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index c742c08..84399f0 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -3,6 +3,7 @@ package global_events import ( "context" // "os" + // "os" // "encoding/json" "fmt" // "math/big" @@ -18,7 +19,7 @@ import ( "github.com/ethereum/go-ethereum" // "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" + // "github.com/ethereum/go-ethereum/common" // "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" @@ -93,7 +94,7 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC // MonitoringAddresses := fromConfigurationToAddress(yamlconfig) // DisplayMonitorAddresses(MonitoringAddresses) - + // Should I make a sleep of 10 seconds to ensure we can read this information before the prod? fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") // fmt.Printf("YAML Config: %v\n", yamlconfig) return &Monitor{ @@ -182,15 +183,13 @@ func (m *Monitor) checkEvents(ctx context.Context) { log.Crit("Failed to retrieve latest block header: %v", err) } latestBlockNumber := header.Number - + fmt.Printf("Get the list of the addresses we are going to monitore\n", m.TabMonitoringAddresses.GetUniqueMonitoredAddresses()) query := ethereum.FilterQuery{ FromBlock: latestBlockNumber, ToBlock: latestBlockNumber, - Addresses: []common.Address{ - // List of addresses to filter the logs by; remove or modify as needed - }, + Addresses: m.TabMonitoringAddresses.GetUniqueMonitoredAddresses(), //if empty means that all addresses are monitored! } - + // os.Exit(0) logs, err := m.l1Client.FilterLogs(context.Background(), query) if err != nil { m.log.Crit("Failed to retrieve logs: %v", err) @@ -204,6 +203,7 @@ func (m *Monitor) checkEvents(ctx context.Context) { // if vlog.Topics == topics_toml { // // alerting + 1 // } + // if vLog.Topics == m.TabMonitoringAddresses.GetMonitoredEvents() fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` fmt.Printf("TxHash: %s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` From 25cc44ed26d2b7171806f7ccaba7814126ccaca2 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 21 May 2024 23:46:39 +0200 Subject: [PATCH 12/34] feat: add the `common.hash()` to have a more robust check. --- op-monitorism/global_events/monitor.go | 29 +++++++++++++++++++------- op-monitorism/global_events/types.go | 10 ++++----- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 84399f0..5f543aa 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -21,6 +21,7 @@ import ( // "github.com/ethereum/go-ethereum/accounts/abi/bind" // "github.com/ethereum/go-ethereum/common" // "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" @@ -156,13 +157,14 @@ func formatSignature(signature string) string { // Formatting allows use to use "transfer(address owner, uint256 amount)" instead of "transfer(address,uint256 // So with the name parameters -func FormatAndHash(signature string) []byte { // this will return the topic not the 4bytes so longer. +func FormatAndHash(signature string) common.Hash { // this will return the topic not the 4bytes so longer. formattedSignature := formatSignature(signature) if formattedSignature == "" { panic("Invalid signature") } hash := crypto.Keccak256([]byte(formattedSignature)) - return hash + return common.BytesToHash(hash) + } func (m *Monitor) Run(ctx context.Context) { @@ -183,7 +185,7 @@ func (m *Monitor) checkEvents(ctx context.Context) { log.Crit("Failed to retrieve latest block header: %v", err) } latestBlockNumber := header.Number - fmt.Printf("Get the list of the addresses we are going to monitore\n", m.TabMonitoringAddresses.GetUniqueMonitoredAddresses()) + // fmt.Printf("Get the list of the addresses we are going to monitore\n", m.TabMonitoringAdHexToHashHashetUniqueMonitoredAddresses()) query := ethereum.FilterQuery{ FromBlock: latestBlockNumber, ToBlock: latestBlockNumber, @@ -199,14 +201,17 @@ func (m *Monitor) checkEvents(ctx context.Context) { fmt.Println("Block Number: ", latestBlockNumber) fmt.Println("Number of logs: ", len(logs)) fmt.Println("BlockHash:", header.Hash().Hex()) + for _, vLog := range logs { // if vlog.Topics == topics_toml { // // alerting + 1 // } - // if vLog.Topics == m.TabMonitoringAddresses.GetMonitoredEvents() - fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Printf("TxHash: %s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + if IsTopicInMonitoredEvents(vLog.Topics, m.TabMonitoringAddresses.GetMonitoredEvents()) { + fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("TxHash: %s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + } + } fmt.Printf("-------------------------- END OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` @@ -226,6 +231,16 @@ func (m *Monitor) checkEvents(ctx context.Context) { // m.log.Info("OptimismPortal status", "address", m.optimismPortalAddress.String(), "paused", paused) m.log.Info("Checking events") } +func IsTopicInMonitoredEvents(topics []common.Hash, monitoredEvents []Event) bool { + for _, monitoredEvent := range monitoredEvents { + fmt.Printf("Monitored Event: %v\n", monitoredEvent._4bytes) + fmt.Printf("Topics: %v\n", topics[0]) + if monitoredEvent._4bytes == topics[0] { + return true + } + } + return false +} // func (m *Monitor) checkSafeNonce(ctx context.Context) { // if m.safeAddress == nil { diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index b34cecf..30cd382 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -16,9 +16,9 @@ type EventTopic struct { } type Event struct { - _4bytes string // That is the 4 bytes of the event signature, will be generated from the Event.Signature function just below this. - Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" - // Topics []EventTopic `yaml:"topics,omitempty"` + _4bytes common.Hash // That is the 4 bytes of the event signature, will be generated from the Event.Signature function just below this. + Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" + Topics []EventTopic `yaml:"topics,omitempty"` } type Configuration struct { @@ -96,7 +96,7 @@ func fromConfigurationToAddress(config Configuration) []MonitoringAddress { fmt.Println("No addresses to monitor, but some events are defined (this means we are monitoring all the addresses), probably for debugging purposes.") var event_with_4bytes []Event for _, event := range config.Events { - event._4bytes = string(FormatAndHash(event.Signature)) + event._4bytes = FormatAndHash(event.Signature) event_with_4bytes = append(event_with_4bytes, event) } @@ -108,7 +108,7 @@ func fromConfigurationToAddress(config Configuration) []MonitoringAddress { for _, address := range config.Addresses { var event_with_4bytes []Event for _, event := range config.Events { - event._4bytes = string(FormatAndHash(event.Signature)) + event._4bytes = FormatAndHash(event.Signature) event_with_4bytes = append(event_with_4bytes, event) } From 392b7bc96c3629dd0d21e61103c772f3fc0367a7 Mon Sep 17 00:00:00 2001 From: ethnical Date: Wed, 22 May 2024 14:45:58 +0200 Subject: [PATCH 13/34] chore: add the `globalconfig.yml` this is file is NOT NECESSARY but just to share with the team if necessary. --- op-monitorism/cmd/monitorism/globalconfig.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 op-monitorism/cmd/monitorism/globalconfig.yaml diff --git a/op-monitorism/cmd/monitorism/globalconfig.yaml b/op-monitorism/cmd/monitorism/globalconfig.yaml new file mode 100644 index 0000000..5cf1c9e --- /dev/null +++ b/op-monitorism/cmd/monitorism/globalconfig.yaml @@ -0,0 +1,17 @@ +configuration: + - version: "1.0" + name: Safe Watcher + priority: P0 + addresses: [] + events: + - keccak256_signature: 0x23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d23 + signature: ExecutionFailure(bytes32,uint256) + - keccak256_signature: 0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e + signature: ExecutionSuccess(bytes32,uint256) + - version: "1.0" + name: SystemConfig Config Updates + priority: P2 + addresses: [] + events: + - keccak256_signature: 0x82f8cc4439cd78202f3081cd05a23d895e011595628770738fc5ba8ecba469ed + signature: ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data) From 6c6d2ec675b8e50f40518a83f66a72e8ae340dbb Mon Sep 17 00:00:00 2001 From: ethnical Date: Wed, 22 May 2024 14:46:55 +0200 Subject: [PATCH 14/34] feat: add the types tests --- op-monitorism/global_events/types_test.go | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 op-monitorism/global_events/types_test.go diff --git a/op-monitorism/global_events/types_test.go b/op-monitorism/global_events/types_test.go new file mode 100644 index 0000000..78c69a7 --- /dev/null +++ b/op-monitorism/global_events/types_test.go @@ -0,0 +1,35 @@ +package global_events + +import ( + "gopkg.in/yaml.v3" + "testing" +) + +func TestYamlToConfiguration(t *testing.T) { + data := ` +configuration: + - version: "1.0" + name: "Safe Watcher" + priority: "P0" + addresses: "We are not supporting EIP 3770 yet, if the address is not starting by '0x', this will panic by safety measure." + events: + - signature: "ExecutionFailure(bytes32,uint256)" + - signature: "ExecutionSuccess(bytes32,uint256)" + - version: "1.0" + name: "Safe Watcher" + priority: "P0" + addresses: "We are not supporting EIP 3770 yet, if the address is not starting by '0x', this will panic by safety measure." + events: + - signature: "ExecutionFailure(bytes32,uint256)" + - signature: "ExecutionSuccess(bytes32,uint256)" +` + + var config GlobalConfiguration + err := yaml.Unmarshal([]byte(data), &config) + if err != nil { + t.Errorf("error: %v", err) + } + + // Print the config to see if it's correct + t.Logf("%+v\n", config) +} From f813c162a54e27fe7e37e9f5a5c047d5dc93005b Mon Sep 17 00:00:00 2001 From: ethnical Date: Wed, 22 May 2024 14:47:34 +0200 Subject: [PATCH 15/34] feat: changes the current struct to a better `GlobalConfiguration`. --- op-monitorism/global_events/monitor.go | 88 +++++++++--------- op-monitorism/global_events/types.go | 121 +++++++++++++++++-------- 2 files changed, 131 insertions(+), 78 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 5f543aa..1c12c6a 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -3,6 +3,7 @@ package global_events import ( "context" // "os" + // "time" // "os" // "encoding/json" "fmt" @@ -18,9 +19,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum/go-ethereum" - // "github.com/ethereum/go-ethereum/accounts/abi/bind" - // "github.com/ethereum/go-ethereum/common" - // "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" @@ -42,8 +40,8 @@ const ( type Monitor struct { log log.Logger - l1Client *ethclient.Client - TabMonitoringAddresses TabMonitoringAddress + l1Client *ethclient.Client + globalconfig GlobalConfiguration nickname string @@ -88,20 +86,23 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC fmt.Printf("PathYaml: %v\n", cfg.PathYamlRules) fmt.Printf("Nickname: %v\n", cfg.Nickname) fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) - TabMonitoringAddresses := ReadAllYamlRules(cfg.PathYamlRules) - // yamlconfig := ReadYamlFile(cfg.PathYamlRules) - fmt.Printf("Number of Addresses monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetUniqueMonitoredAddresses())) - fmt.Printf("Number of Events monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetMonitoredEvents())) - - // MonitoringAddresses := fromConfigurationToAddress(yamlconfig) - // DisplayMonitorAddresses(MonitoringAddresses) - // Should I make a sleep of 10 seconds to ensure we can read this information before the prod? + globalConfig := ReadAllYamlRules(cfg.PathYamlRules) + fmt.Printf("GlobalConfig: %#v\n", globalConfig.Configuration) + // // yamlconfig := ReadYamlFile(cfg.PathYamlRules) + // fmt.Printf("Number of Addresses monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetUniqueMonitoredAddresses())) + // fmt.Printf("Number of Events monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetMonitoredEvents())) + // + // // MonitoringAddresses := fromConfigurationToAddress(yamlconfig) + globalConfig.DisplayMonitorAddresses() + // // Should I make a sleep of 10 seconds to ensure we can read this information before the prod? fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") + // + // time.Sleep(10 * time.Second) // sleep for 10 seconds usefull to read the information before the prod. // fmt.Printf("YAML Config: %v\n", yamlconfig) return &Monitor{ - log: log, - l1Client: l1Client, - TabMonitoringAddresses: TabMonitoringAddresses, + log: log, + l1Client: l1Client, + globalconfig: globalConfig, nickname: cfg.Nickname, // yamlconfig: yamlconfig, @@ -182,39 +183,41 @@ func (m *Monitor) Run(ctx context.Context) { func (m *Monitor) checkEvents(ctx context.Context) { header, err := m.l1Client.HeaderByNumber(context.Background(), nil) if err != nil { - log.Crit("Failed to retrieve latest block header: %v", err) + m.log.Warn("Failed to retrieve latest block header: %v", err) //TODO:need to wait 12 and retry here! } latestBlockNumber := header.Number // fmt.Printf("Get the list of the addresses we are going to monitore\n", m.TabMonitoringAdHexToHashHashetUniqueMonitoredAddresses()) query := ethereum.FilterQuery{ FromBlock: latestBlockNumber, ToBlock: latestBlockNumber, - Addresses: m.TabMonitoringAddresses.GetUniqueMonitoredAddresses(), //if empty means that all addresses are monitored! + // Addresses: []common.Address{}, //if empty means that all addresses are monitored should be this value for optimisation and avoiding to take every logs every time -> m.globalconfig.GetUniqueMonitoredAddresses } // os.Exit(0) logs, err := m.l1Client.FilterLogs(context.Background(), query) - if err != nil { - m.log.Crit("Failed to retrieve logs: %v", err) + if err != nil { //TODO:need to wait 12 and retry here! + m.log.Warn("Failed to retrieve logs: %v", err) } - fmt.Printf("-------------------------- START OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Println("Block Number: ", latestBlockNumber) - fmt.Println("Number of logs: ", len(logs)) - fmt.Println("BlockHash:", header.Hash().Hex()) + // fmt.Printf("-------------------------- START OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + // fmt.Println("Block Number: ", latestBlockNumber) + // fmt.Println("Number of logs: ", len(logs)) + // fmt.Println("BlockHash:", header.Hash().Hex()) for _, vLog := range logs { - // if vlog.Topics == topics_toml { - // // alerting + 1 - // } - if IsTopicInMonitoredEvents(vLog.Topics, m.TabMonitoringAddresses.GetMonitoredEvents()) { - fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Printf("TxHash: %s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + if len(vLog.Topics) > 0 { //Ensure no anonymous event is here. + if len(m.globalconfig.SearchIfATopicIsInsideAnAlert(vLog.Topics[0]).Events) > 0 { + // function that return all the values from the config + // returndatafromconfig(vlog.topics, v.logAddress) + fmt.Printf("-------------------------- Event Detected ------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("TxHash: h%s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + fmt.Printf("The current config that matched this function: %v\n", m.globalconfig.SearchIfATopicIsInsideAnAlert(vLog.Topics[0])) + fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + } } } - fmt.Printf("-------------------------- END OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + // fmt.Printf("-------------------------- END OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` // paused, err := m.optimismPortal.Paused(&bind.CallOpts{Context: ctx}) // if err != nil { // m.log.Error("failed to query OptimismPortal paused status", "err", err) @@ -231,16 +234,17 @@ func (m *Monitor) checkEvents(ctx context.Context) { // m.log.Info("OptimismPortal status", "address", m.optimismPortalAddress.String(), "paused", paused) m.log.Info("Checking events") } -func IsTopicInMonitoredEvents(topics []common.Hash, monitoredEvents []Event) bool { - for _, monitoredEvent := range monitoredEvents { - fmt.Printf("Monitored Event: %v\n", monitoredEvent._4bytes) - fmt.Printf("Topics: %v\n", topics[0]) - if monitoredEvent._4bytes == topics[0] { - return true - } - } - return false -} + +// func IsTopicInMonitoredEvents(topics []common.Hash, monitoredEvents []Event) bool { +// for _, monitoredEvent := range monitoredEvents { +// // fmt.Printf("Monitored Event: %v\n", monitoredEvent._4bytes) +// // fmt.Printf("Topics: %v\n", topics[0]) +// if monitoredEvent._4bytes == topics[0] { +// return true +// } +// } +// return false +// } // func (m *Monitor) checkSafeNonce(ctx context.Context) { // if m.safeAddress == nil { diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 30cd382..01aed11 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -1,12 +1,14 @@ package global_events import ( + // "bytes" "fmt" + "os" + "path/filepath" + "github.com/ethereum/go-ethereum/common" "golang.org/x/exp/maps" "gopkg.in/yaml.v3" - "os" - "path/filepath" // "slices" ) @@ -16,9 +18,9 @@ type EventTopic struct { } type Event struct { - _4bytes common.Hash // That is the 4 bytes of the event signature, will be generated from the Event.Signature function just below this. - Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" - Topics []EventTopic `yaml:"topics,omitempty"` + Keccak256_Signature common.Hash // `Topic[0]` That is the 4 bytes of the event signature, will be generated from the Event.Signature function just below this. + Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" + Topics []EventTopic `yaml:"topics,omitempty"` } type Configuration struct { @@ -29,15 +31,49 @@ type Configuration struct { Events []Event `yaml:"events"` } +type GlobalConfiguration struct { + Configuration []Configuration `yaml:"configuration"` +} + +// monitore one address for multiples events type MonitoringAddress struct { Address common.Address `yaml:"addresses"` Events []Event `yaml:"events"` } +// tab of monitoring addresses allows us to have multiples addresses with multiples events cf above. type TabMonitoringAddress struct { MonitoringAddress []MonitoringAddress } +// This will return at the FIRST occurence of the address in the configuration. +// This can be an issue if there is multiples times the same alerts in multiples yaml rules. +// TODO: mark this one into the docs. +func (G GlobalConfiguration) ReturnEventsMonitoredForAnAddress(target_address common.Address) []Event { + for _, config := range G.Configuration { + for _, address := range config.Addresses { + if address == target_address { + return config.Events + } + } + } + return []Event{} // no events monitored for this address + +} +func (G GlobalConfiguration) SearchIfATopicIsInsideAnAlert(topic common.Hash) Configuration { + for _, config := range G.Configuration { + for _, event := range config.Events { + // fmt.Printf("Comparing %x with %x\n", topic, event.Keccak256_Signature) + if topic == event.Keccak256_Signature { + return config + } + + } + } + return Configuration{} + +} + // Return all the addresses currently monitored func (T TabMonitoringAddress) GetMonitoredAddresses() []common.Address { var addresses []common.Address @@ -88,39 +124,37 @@ func ReadYamlFile(filename string) Configuration { return config } -// fromConfigurationToAddress take the configuration yaml and create the `monitoringAddresses` array -// that will contains all the addresses that will monitore. -func fromConfigurationToAddress(config Configuration) []MonitoringAddress { - var monitoringAddresses []MonitoringAddress +// fromConfigurationToAddress take the configuration yaml and resolve the signature stringed like Transfer(address // that will contains all the addresses that will monitore. +func StringFunctionToHex(config Configuration) Configuration { + var FinalConfig Configuration + if len(config.Addresses) == 0 && len(config.Events) > 0 { fmt.Println("No addresses to monitor, but some events are defined (this means we are monitoring all the addresses), probably for debugging purposes.") - var event_with_4bytes []Event - for _, event := range config.Events { - event._4bytes = FormatAndHash(event.Signature) - event_with_4bytes = append(event_with_4bytes, event) - + keccak256_topic_0 := config.Events + for i, event := range config.Events { + keccak256_topic_0[i].Keccak256_Signature = FormatAndHash(event.Signature) + fmt.Printf("Keccak256_Signature: %x\n", keccak256_topic_0[i].Keccak256_Signature) } - monitoringAddresses = append(monitoringAddresses, MonitoringAddress{Address: common.Address{}, Events: event_with_4bytes}) + FinalConfig = Configuration{Version: config.Version, Name: config.Name, Priority: config.Priority, Addresses: []common.Address{}, Events: keccak256_topic_0} - return []MonitoringAddress{MonitoringAddress{Address: common.Address{}, Events: event_with_4bytes}} + return FinalConfig } - - for _, address := range config.Addresses { - var event_with_4bytes []Event - for _, event := range config.Events { - event._4bytes = FormatAndHash(event.Signature) - event_with_4bytes = append(event_with_4bytes, event) + // If there is addresses to monitor, we will resolve the signature of the events. + for _, address := range config.Addresses { //resolve the hex signature from a topic + keccak256_topic_0 := config.Events + for i, event := range config.Events { + keccak256_topic_0[i].Keccak256_Signature = FormatAndHash(event.Signature) } - monitoringAddresses = append(monitoringAddresses, MonitoringAddress{Address: address, Events: event_with_4bytes}) + FinalConfig = Configuration{Version: config.Version, Name: config.Name, Priority: config.Priority, Addresses: []common.Address{address}, Events: keccak256_topic_0} } - return monitoringAddresses + return FinalConfig } // Read all the files in the `rules` directory at the given path from the command line `--PathYamlRules` that are YAML files. -func ReadAllYamlRules(PathYamlRules string) TabMonitoringAddress { - var monitoringAddresses []MonitoringAddress +func ReadAllYamlRules(PathYamlRules string) GlobalConfiguration { + var GlobalConfig GlobalConfiguration entries, err := os.ReadDir(PathYamlRules) //Only read yaml files if err != nil { @@ -143,21 +177,36 @@ func ReadAllYamlRules(PathYamlRules string) TabMonitoringAddress { for _, file := range yamlFiles { path_rule := PathYamlRules + "/" + file.Name() fmt.Printf("Reading a rule named: %s\n", path_rule) - yamlconfig := ReadYamlFile(path_rule) - monitoringAddresses = append(monitoringAddresses, fromConfigurationToAddress(yamlconfig)...) + yamlconfig := ReadYamlFile(path_rule) // Read the yaml file + yamlconfig = StringFunctionToHex(yamlconfig) // Modify the yaml config to have the common.hash of the event signature. + GlobalConfig.Configuration = append(GlobalConfig.Configuration, yamlconfig) + // monitoringAddresses = append(monitoringAddresses, fromConfigurationToAddress(yamlconfig)...) } - return TabMonitoringAddress{MonitoringAddress: monitoringAddresses} + yaml_marshalled, err := yaml.Marshal(GlobalConfig) + err = os.WriteFile("globalconfig.yaml", yaml_marshalled, 0644) + if err != nil { + fmt.Println("Error writing the globalconfig YAML file on the disk:", err) + panic("Error writing the globalconfig YAML file on the disk") + } + return GlobalConfig } -func DisplayMonitorAddresses(monitoringAddresses []MonitoringAddress) { + +func (G GlobalConfiguration) DisplayMonitorAddresses() { println("============== Monitoring addresses =================") - for _, address := range monitoringAddresses { - fmt.Println("Address:", address.Address) - for _, event := range address.Events { - fmt.Printf("Event: %s, Topic[0]: %x\n", event.Signature, event._4bytes) + for _, config := range G.Configuration { + fmt.Printf("Name: %s\n", config.Name) + if len(config.Addresses) == 0 && len(config.Events) > 0 { + fmt.Println("No addresses to monitor, but some events are defined (this means we are monitoring all the addresses), probably for debugging purposes.") + for _, events := range config.Events { + fmt.Printf("Events: %v\n", events) + } + } else { + for _, address := range config.Addresses { + fmt.Println("Address:", address) + fmt.Printf("Events: %v\n", G.ReturnEventsMonitoredForAnAddress(address)) + } } } - fmt.Println("===============================") - } From 8977046d4936b80161dd588077e8f81e529b3975 Mon Sep 17 00:00:00 2001 From: ethnical Date: Wed, 22 May 2024 17:27:12 +0200 Subject: [PATCH 16/34] feat: adds metrics + clean the codes --- op-monitorism/global_events/monitor.go | 196 ++++--------------------- op-monitorism/global_events/types.go | 73 ++------- 2 files changed, 46 insertions(+), 223 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 1c12c6a..9857af6 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -2,17 +2,7 @@ package global_events import ( "context" - // "os" - // "time" - // "os" - // "encoding/json" "fmt" - // "math/big" - // "os" - // "os/exec" - // "strconv" - // "strings" - // "github.com/ethereum-optimism/optimism/op-bindings/bindings" "regexp" "strings" @@ -29,32 +19,27 @@ import ( const ( MetricsNamespace = "global_events_mon" - - // OPTokenEnvName = "OP_SERVICE_ACCOUNT_TOKEN" - - // Item names follow a `ready-.json` format - // PresignedNonceTitlePrefix = "ready-" - // PresignedNonceTitleSuffix = ".json" ) +// Monitor is the main struct of the monitor. type Monitor struct { log log.Logger l1Client *ethclient.Client globalconfig GlobalConfiguration - + // nickname is the nickname of the monitor (we need to change the name this is not an ideal one here). nickname string filename string //filename of the yaml rules yamlconfig Configuration - // metrics - safeNonce *prometheus.GaugeVec - latestPresignedPauseNonce *prometheus.GaugeVec - pausedState *prometheus.GaugeVec - unexpectedRpcErrors *prometheus.CounterVec + // Prometheus metrics + eventEmitted *prometheus.GaugeVec + unexpectedRpcErrors *prometheus.CounterVec } +// ChainIDToName() allows to convert the chainID to a human readable name. +// For now only ethereum + Sepolia are supported. func ChainIDToName(chainID int64) string { switch chainID { case 1: @@ -65,6 +50,7 @@ func ChainIDToName(chainID int64) string { return "The `ChainID` is Not defined into the `chaindIDToName` function, this is probably a custom chain otherwise something is going wrong!" } +// NewMonitor creates a new Monitor instance. func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { l1Client, err := ethclient.Dial(cfg.L1NodeURL) if err != nil { @@ -88,39 +74,20 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) globalConfig := ReadAllYamlRules(cfg.PathYamlRules) fmt.Printf("GlobalConfig: %#v\n", globalConfig.Configuration) - // // yamlconfig := ReadYamlFile(cfg.PathYamlRules) - // fmt.Printf("Number of Addresses monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetUniqueMonitoredAddresses())) - // fmt.Printf("Number of Events monitored (for now don't take in consideration the duplicates): %v\n", len(TabMonitoringAddresses.GetMonitoredEvents())) - // - // // MonitoringAddresses := fromConfigurationToAddress(yamlconfig) globalConfig.DisplayMonitorAddresses() - // // Should I make a sleep of 10 seconds to ensure we can read this information before the prod? fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") - // // time.Sleep(10 * time.Second) // sleep for 10 seconds usefull to read the information before the prod. - // fmt.Printf("YAML Config: %v\n", yamlconfig) return &Monitor{ log: log, l1Client: l1Client, globalconfig: globalConfig, nickname: cfg.Nickname, - // yamlconfig: yamlconfig, - safeNonce: m.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: MetricsNamespace, - Name: "safeNonce", - Help: "Safe Nonce", - }, []string{"address", "nickname"}), - latestPresignedPauseNonce: m.NewGaugeVec(prometheus.GaugeOpts{ + eventEmitted: m.NewGaugeVec(prometheus.GaugeOpts{ Namespace: MetricsNamespace, - Name: "latestPresignedPauseNonce", - Help: "Latest pre-signed pause nonce", - }, []string{"address", "nickname"}), - pausedState: m.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: MetricsNamespace, - Name: "pausedState", - Help: "OptimismPortal paused state", - }, []string{"address", "nickname"}), + Name: "eventEmitted", + Help: "Event monitored emitted an log", + }, []string{"nickname", "alertname", "address", "functionName"}), unexpectedRpcErrors: m.NewCounterVec(prometheus.CounterOpts{ Namespace: MetricsNamespace, Name: "unexpectedRpcErrors", @@ -128,6 +95,9 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC }, []string{"section", "name"}), }, nil } + +// formatSignature allows to format the signature of a function to be able to hash it. +// e.g: "transfer(address owner, uint256 amount)" -> "transfer(address,uint256)" func formatSignature(signature string) string { // Regex to extract function name and parameters r := regexp.MustCompile(`(\w+)\s*\(([^)]*)\)`) @@ -154,11 +124,9 @@ func formatSignature(signature string) string { return fmt.Sprintf("%s(%s)", funcName, strings.Join(cleanParams, ",")) } -// Format And Hash the signature to create the topic. -// Formatting allows use to use "transfer(address owner, uint256 amount)" instead of "transfer(address,uint256 -// So with the name parameters - -func FormatAndHash(signature string) common.Hash { // this will return the topic not the 4bytes so longer. +// FormatAndHash allow to Format the signature (e.g: "transfer(address,uint256)") to create the keccak256 hash associated with it. +// Formatting allows use to use "transfer(address owner, uint256 amount)" instead of "transfer(address,uint256)" +func FormatAndHash(signature string) common.Hash { formattedSignature := formatSignature(signature) if formattedSignature == "" { panic("Invalid signature") @@ -170,147 +138,43 @@ func FormatAndHash(signature string) common.Hash { // this will return the topic func (m *Monitor) Run(ctx context.Context) { m.checkEvents(ctx) - // input := "balanceOf(address owner)" - // formattedSignature := formatSignature(input) - // if formattedSignature == "" { - // panic("Invalid signature") - // } - // hash := crypto.Keccak256([]byte(formattedSignature)) - // fmt.Printf("Function Selector: 0x%x\n", hash[:4]) - // // m.checkSafeNonce(ctx) - // // m.checkPresignedNonce(ctx) } -func (m *Monitor) checkEvents(ctx context.Context) { +func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs crit are not causing panic in runtime! header, err := m.l1Client.HeaderByNumber(context.Background(), nil) if err != nil { m.log.Warn("Failed to retrieve latest block header: %v", err) //TODO:need to wait 12 and retry here! } + latestBlockNumber := header.Number - // fmt.Printf("Get the list of the addresses we are going to monitore\n", m.TabMonitoringAdHexToHashHashetUniqueMonitoredAddresses()) query := ethereum.FilterQuery{ FromBlock: latestBlockNumber, ToBlock: latestBlockNumber, // Addresses: []common.Address{}, //if empty means that all addresses are monitored should be this value for optimisation and avoiding to take every logs every time -> m.globalconfig.GetUniqueMonitoredAddresses } - // os.Exit(0) + logs, err := m.l1Client.FilterLogs(context.Background(), query) if err != nil { //TODO:need to wait 12 and retry here! m.log.Warn("Failed to retrieve logs: %v", err) } - // fmt.Printf("-------------------------- START OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - // fmt.Println("Block Number: ", latestBlockNumber) - // fmt.Println("Number of logs: ", len(logs)) - // fmt.Println("BlockHash:", header.Hash().Hex()) - for _, vLog := range logs { if len(vLog.Topics) > 0 { //Ensure no anonymous event is here. - if len(m.globalconfig.SearchIfATopicIsInsideAnAlert(vLog.Topics[0]).Events) > 0 { - // function that return all the values from the config - // returndatafromconfig(vlog.topics, v.logAddress) - fmt.Printf("-------------------------- Event Detected ------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Printf("TxHash: h%s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - fmt.Printf("The current config that matched this function: %v\n", m.globalconfig.SearchIfATopicIsInsideAnAlert(vLog.Topics[0])) - fmt.Printf("----------------------------------------------------------------\n") // Prints the log data; consider using `vLog.Topics` or `vLog.Data` + if len(m.globalconfig.SearchIfATopicIsInsideAnAlert(vLog.Topics[0]).Events) > 0 { // We matched an alert! + config := m.globalconfig.SearchIfATopicIsInsideAnAlert(vLog.Topics[0]) + fmt.Printf("-------------------------- Event Detected ------------------------\n") + fmt.Printf("TxHash: h%s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) + fmt.Printf("The current config that matched this function: %v\n", config) + fmt.Printf("----------------------------------------------------------------\n") + m.eventEmitted.WithLabelValues(m.nickname, vLog.Address.String(), config.Name, config.Events[0].Signature).Set(float64(1)) + } } } + m.log.Info("Checking events...", "CurrentBlock", latestBlockNumber) - // fmt.Printf("-------------------------- END OF BLOCK (%s)--------------------------------------", latestBlockNumber) // Prints the log data; consider using `vLog.Topics` or `vLog.Data` - // paused, err := m.optimismPortal.Paused(&bind.CallOpts{Context: ctx}) - // if err != nil { - // m.log.Error("failed to query OptimismPortal paused status", "err", err) - // m.unexpectedRpcErrors.WithLabelValues("optimismportal", "paused").Inc() - // return - // } - - // pausedMetric := 0 - // if paused { - // pausedMetric = 1 - // } - // - // m.pausedState.WithLabelValues(m.optimismPortalAddress.String(), m.nickname).Set(float64(pausedMetric)) - // m.log.Info("OptimismPortal status", "address", m.optimismPortalAddress.String(), "paused", paused) - m.log.Info("Checking events") } -// func IsTopicInMonitoredEvents(topics []common.Hash, monitoredEvents []Event) bool { -// for _, monitoredEvent := range monitoredEvents { -// // fmt.Printf("Monitored Event: %v\n", monitoredEvent._4bytes) -// // fmt.Printf("Topics: %v\n", topics[0]) -// if monitoredEvent._4bytes == topics[0] { -// return true -// } -// } -// return false -// } - -// func (m *Monitor) checkSafeNonce(ctx context.Context) { -// if m.safeAddress == nil { -// m.log.Warn("safe address is not configured, skipping...") -// return -// } -// -// nonceBytes := hexutil.Bytes{} -// nonceTx := map[string]interface{}{"to": *m.safeAddress, "data": hexutil.Encode(SafeNonceSelector)} -// if err := m.l1Client.Client().CallContext(ctx, &nonceBytes, "eth_call", nonceTx, "latest"); err != nil { -// m.log.Error("failed to query safe nonce", "err", err) -// m.unexpectedRpcErrors.WithLabelValues("safe", "nonce()").Inc() -// return -// } -// -// nonce := new(big.Int).SetBytes(nonceBytes).Uint64() -// m.safeNonce.WithLabelValues(m.safeAddress.String(), m.nickname).Set(float64(nonce)) -// m.log.Info("Safe Nonce", "address", m.safeAddress.String(), "nonce", nonce) -// } - -// func (m *Monitor) checkPresignedNonce(ctx context.Context) { -// if m.onePassVault == nil { -// m.log.Warn("one pass integration is not configured, skipping...") -// return -// } -// -// cmd := exec.CommandContext(ctx, "op", "item", "list", "--format=json", fmt.Sprintf("--vault=%s", *m.onePassVault)) -// -// output, err := cmd.Output() -// if err != nil { -// m.log.Error("failed to run op cli") -// m.unexpectedRpcErrors.WithLabelValues("1pass", "exec").Inc() -// return -// } -// -// vaultItems := []struct{ Title string }{} -// if err := json.Unmarshal(output, &vaultItems); err != nil { -// m.log.Error("failed to unmarshal op cli stdout", "err", err) -// m.unexpectedRpcErrors.WithLabelValues("1pass", "stdout").Inc() -// return -// } -// -// latestPresignedNonce := int64(-1) -// for _, item := range vaultItems { -// if strings.HasPrefix(item.Title, PresignedNonceTitlePrefix) && strings.HasSuffix(item.Title, PresignedNonceTitleSuffix) { -// nonceStr := item.Title[len(PresignedNonceTitlePrefix) : len(item.Title)-len(PresignedNonceTitleSuffix)] -// nonce, err := strconv.ParseInt(nonceStr, 10, 64) -// if err != nil { -// m.log.Error("failed to parse nonce from item title", "title", item.Title) -// m.unexpectedRpcErrors.WithLabelValues("1pass", "title").Inc() -// return -// } -// if nonce > latestPresignedNonce { -// latestPresignedNonce = nonce -// } -// } -// } -// -// m.latestPresignedPauseNonce.WithLabelValues(m.safeAddress.String(), m.nickname).Set(float64(latestPresignedNonce)) -// if latestPresignedNonce == -1 { -// m.log.Error("no presigned nonce found") -// return -// } -// -// m.log.Info("Latest Presigned Nonce", "nonce", latestPresignedNonce) -// } func (m *Monitor) Close(_ context.Context) error { m.l1Client.Close() return nil diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 01aed11..2903d3c 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -1,28 +1,28 @@ package global_events import ( - // "bytes" "fmt" "os" "path/filepath" "github.com/ethereum/go-ethereum/common" - "golang.org/x/exp/maps" "gopkg.in/yaml.v3" - // "slices" ) +// EventTopic is the struct that will contain the index of the topic and the values that will be monitored (not used currently). type EventTopic struct { Index int `yaml:"index"` Values []string `yaml:"values"` } +// Event is the struct that will contain the signature of the event and the topics that will be monitored. type Event struct { - Keccak256_Signature common.Hash // `Topic[0]` That is the 4 bytes of the event signature, will be generated from the Event.Signature function just below this. - Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" - Topics []EventTopic `yaml:"topics,omitempty"` + Keccak256_Signature common.Hash // the value is the `Topic[0]`. This is generated from the `Event.Signature` field (eg. 0x23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d23 --> ExecutionFailure(bytes32,uint256) + Signature string `yaml:"signature"` // That is the name of the function like "Transfer(address,address,uint256)" + Topics []EventTopic `yaml:"topics,omitempty"` // The topics that will be monitored not used yet. } +// Configuration is the struct that will contain the configuration coming from the yaml files under the `rules` directory. type Configuration struct { Version string `yaml:"version"` Name string `yaml:"name"` @@ -31,24 +31,13 @@ type Configuration struct { Events []Event `yaml:"events"` } +// GlobalConfiguration is the struct that will contain all the configuration of the monitoring. type GlobalConfiguration struct { Configuration []Configuration `yaml:"configuration"` } -// monitore one address for multiples events -type MonitoringAddress struct { - Address common.Address `yaml:"addresses"` - Events []Event `yaml:"events"` -} - -// tab of monitoring addresses allows us to have multiples addresses with multiples events cf above. -type TabMonitoringAddress struct { - MonitoringAddress []MonitoringAddress -} - -// This will return at the FIRST occurence of the address in the configuration. -// This can be an issue if there is multiples times the same alerts in multiples yaml rules. -// TODO: mark this one into the docs. +// ReturnEventsMonitoredForAnAddress will return the list of events monitored for a given address /!\ This will return the first occurence of the address in the configuration. +// We assume currently there is no duplicates into the rules. func (G GlobalConfiguration) ReturnEventsMonitoredForAnAddress(target_address common.Address) []Event { for _, config := range G.Configuration { for _, address := range config.Addresses { @@ -60,12 +49,14 @@ func (G GlobalConfiguration) ReturnEventsMonitoredForAnAddress(target_address co return []Event{} // no events monitored for this address } + +// SearchIfATopicIsInsideAnAlert Search if a topic is inside a rules, if this the case will return a `Configuration`. /!\ This is worth noting that the returned only contains the event that matched the topic in `topic` in parameter. func (G GlobalConfiguration) SearchIfATopicIsInsideAnAlert(topic common.Hash) Configuration { for _, config := range G.Configuration { for _, event := range config.Events { // fmt.Printf("Comparing %x with %x\n", topic, event.Keccak256_Signature) if topic == event.Keccak256_Signature { - return config + return Configuration{Version: config.Version, Name: config.Name, Priority: config.Priority, Addresses: config.Addresses, Events: []Event{event}} } } @@ -74,40 +65,7 @@ func (G GlobalConfiguration) SearchIfATopicIsInsideAnAlert(topic common.Hash) Co } -// Return all the addresses currently monitored -func (T TabMonitoringAddress) GetMonitoredAddresses() []common.Address { - var addresses []common.Address - for _, T := range T.MonitoringAddress { - addresses = append(addresses, T.Address) - } - - return addresses -} - -// Return all the events currently monitored -func (T TabMonitoringAddress) GetMonitoredEvents() []Event { - var Events []Event - for _, T := range T.MonitoringAddress { - for _, event := range T.Events { - Events = append(Events, event) - } - } - - return Events -} - -// return all the UNIQUE addresses currently GetMonitoredEvents -func (T TabMonitoringAddress) GetUniqueMonitoredAddresses() []common.Address { - hashmap := make(map[common.Address]bool) - for _, address := range T.GetMonitoredAddresses() { - if address != common.HexToAddress("0x0") { // If the address is set to 0x0, it means we are monitoring all the addresses, so we need to remove it from the tab here. - hashmap[address] = true - } - - } - return maps.Keys(hashmap) -} - +// ReadYamlFile read a yaml file and return a Configuration struct. func ReadYamlFile(filename string) Configuration { var config Configuration data, err := os.ReadFile(filename) @@ -124,7 +82,7 @@ func ReadYamlFile(filename string) Configuration { return config } -// fromConfigurationToAddress take the configuration yaml and resolve the signature stringed like Transfer(address // that will contains all the addresses that will monitore. +// StringFunctionToHex take the configuration yaml and resolve the signature stringed like "Transfer(address)" // that will contains all the addresses that will monitore. func StringFunctionToHex(config Configuration) Configuration { var FinalConfig Configuration @@ -152,7 +110,7 @@ func StringFunctionToHex(config Configuration) Configuration { return FinalConfig } -// Read all the files in the `rules` directory at the given path from the command line `--PathYamlRules` that are YAML files. +// ReadAllYamlRules Read all the files in the `rules` directory at the given path from the command line `--PathYamlRules` that are YAML files. func ReadAllYamlRules(PathYamlRules string) GlobalConfiguration { var GlobalConfig GlobalConfiguration @@ -193,6 +151,7 @@ func ReadAllYamlRules(PathYamlRules string) GlobalConfiguration { return GlobalConfig } +// DisplayMonitorAddresses() will display the addresses that are monitored and the events that are monitored for each address. func (G GlobalConfiguration) DisplayMonitorAddresses() { println("============== Monitoring addresses =================") for _, config := range G.Configuration { From 67ed2fe1f998eb4d28da2c35f8e466e2a54195d4 Mon Sep 17 00:00:00 2001 From: ethnical Date: Wed, 22 May 2024 17:33:51 +0200 Subject: [PATCH 17/34] readme: add a short readme during the creation --- op-monitorism/global_events/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 op-monitorism/global_events/README.md diff --git a/op-monitorism/global_events/README.md b/op-monitorism/global_events/README.md new file mode 100644 index 0000000..27fd164 --- /dev/null +++ b/op-monitorism/global_events/README.md @@ -0,0 +1,19 @@ +## Global Events monitoring +This monitoring modules for the yaml rules added with the format ⚠️ This readme will be move into the global readme in the future. +```yaml +# This watches all contacts for OP, Mode, and Base mainnets for two logs. +# These logs are emitted by Safes, so this effectively watches for all +# transactions from any Safe on these chains. + +version: 1.X +name: My Super Explicit Alert Name. +priority: P0 +addresses: 0x000000000000000000000000000000000000CAFE +events: + - signature: FunctionYouWantToMonitore(bytes32,uint256) + - signature: FunctionYouWantToMonitore(bytes32,uint256) +``` +To run it: +```bash +go run . global_events --nickname MySuperNickName --l1.node.url https://localhost:8545 --PathYamlRules ../rules --loop.interval.msec 12000 +``` From d6521775fcb63d4c945a314cb9531265938d3886 Mon Sep 17 00:00:00 2001 From: ethnical Date: Wed, 22 May 2024 18:04:53 +0200 Subject: [PATCH 18/34] chore: update the test --- op-monitorism/global_events/monitor_test.go | 2 - op-monitorism/global_events/types_test.go | 47 +++++++++++++++++---- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/op-monitorism/global_events/monitor_test.go b/op-monitorism/global_events/monitor_test.go index 7ed37c3..e8bd08d 100644 --- a/op-monitorism/global_events/monitor_test.go +++ b/op-monitorism/global_events/monitor_test.go @@ -44,8 +44,6 @@ func TestFormatSignature(t *testing.T) { if output != test.expectedOutput { t.Errorf("Failed %s: expected %q but got %q", test.name, test.expectedOutput, output) } - t.Logf("Success %s: from %q got %q", test.name, test.input, output) - }) } } diff --git a/op-monitorism/global_events/types_test.go b/op-monitorism/global_events/types_test.go index 78c69a7..a21374a 100644 --- a/op-monitorism/global_events/types_test.go +++ b/op-monitorism/global_events/types_test.go @@ -1,35 +1,64 @@ package global_events import ( + "github.com/ethereum/go-ethereum/common" "gopkg.in/yaml.v3" "testing" ) -func TestYamlToConfiguration(t *testing.T) { - data := ` +const data = ` configuration: - version: "1.0" - name: "Safe Watcher" + name: "BuildLand" priority: "P0" - addresses: "We are not supporting EIP 3770 yet, if the address is not starting by '0x', this will panic by safety measure." + addresses: + - 0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5 events: - signature: "ExecutionFailure(bytes32,uint256)" - signature: "ExecutionSuccess(bytes32,uint256)" - version: "1.0" - name: "Safe Watcher" - priority: "P0" - addresses: "We are not supporting EIP 3770 yet, if the address is not starting by '0x', this will panic by safety measure." + name: "NightLand" + priority: "P2" + addresses: # We are not supporting EIP 3770 yet, if the address is not starting by '0x', this will panic by safety measure." events: - signature: "ExecutionFailure(bytes32,uint256)" - signature: "ExecutionSuccess(bytes32,uint256)" ` +// func (G GlobalConfiguration) ReturnEventsMonitoredForAnAddress(target_address common.Address) []Event { +// for _, config := range G.Configuration { +// for _, address := range config.Addresses { +// if address == target_address { +// return config.Events +// } +// } +// } +// return []Event{} // no events monitored for this address +// +// Print the config to see if it's correct +func TestReturnEventsMonitoredForAnAddress(t *testing.T) { var config GlobalConfiguration err := yaml.Unmarshal([]byte(data), &config) if err != nil { t.Errorf("error: %v", err) } + config.ReturnEventsMonitoredForAnAddress(common.HexToAddress("0x41")) +} - // Print the config to see if it's correct - t.Logf("%+v\n", config) +func TestDisplayMonitorAddresses(t *testing.T) { + var config GlobalConfiguration + err := yaml.Unmarshal([]byte(data), &config) + if err != nil { + t.Errorf("error: %v", err) + } + config.DisplayMonitorAddresses() +} + +func TestYamlToConfiguration(t *testing.T) { + + var config GlobalConfiguration + err := yaml.Unmarshal([]byte(data), &config) + if err != nil { + t.Errorf("error: %v", err) + } } From ab5f2ee0f233242a8bf339a907853308a1ba2d6f Mon Sep 17 00:00:00 2001 From: Ethnical Date: Wed, 22 May 2024 18:25:17 +0200 Subject: [PATCH 19/34] Rename README.md to README.md --- op-monitorism/global_events/{README.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename op-monitorism/global_events/{README.md => README.md} (100%) diff --git a/op-monitorism/global_events/README.md b/op-monitorism/global_events/README.md similarity index 100% rename from op-monitorism/global_events/README.md rename to op-monitorism/global_events/README.md From a0ca940c561f875aec225439b509651e5a260cc9 Mon Sep 17 00:00:00 2001 From: ethnical Date: Fri, 24 May 2024 17:32:41 +0200 Subject: [PATCH 20/34] chore: fix bugs + added the comments for the events 1 signer --- op-monitorism/global_events/monitor.go | 44 +++++++++++++++++++++----- op-monitorism/global_events/types.go | 6 ++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 9857af6..6f29a03 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + "github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum/go-ethereum" @@ -13,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - "github.com/prometheus/client_golang/prometheus" + "time" ) const ( @@ -28,7 +29,10 @@ type Monitor struct { l1Client *ethclient.Client globalconfig GlobalConfiguration // nickname is the nickname of the monitor (we need to change the name this is not an ideal one here). - nickname string + nickname string + safeAddress *bindings.OptimismPortalCaller + + LiveAddress *common.Address filename string //filename of the yaml rules yamlconfig Configuration @@ -76,7 +80,7 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC fmt.Printf("GlobalConfig: %#v\n", globalConfig.Configuration) globalConfig.DisplayMonitorAddresses() fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") - // time.Sleep(10 * time.Second) // sleep for 10 seconds usefull to read the information before the prod. + time.Sleep(10 * time.Second) // sleep for 10 seconds usefull to read the information before the prod. return &Monitor{ log: log, l1Client: l1Client, @@ -87,7 +91,7 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC Namespace: MetricsNamespace, Name: "eventEmitted", Help: "Event monitored emitted an log", - }, []string{"nickname", "alertname", "address", "functionName"}), + }, []string{"nickname", "rulename", "priority", "functionName", "address"}), unexpectedRpcErrors: m.NewCounterVec(prometheus.CounterOpts{ Namespace: MetricsNamespace, Name: "unexpectedRpcErrors", @@ -102,11 +106,9 @@ func formatSignature(signature string) string { // Regex to extract function name and parameters r := regexp.MustCompile(`(\w+)\s*\(([^)]*)\)`) matches := r.FindStringSubmatch(signature) - if len(matches) != 3 { return "" } - // Function name funcName := matches[1] // Parameters, split by commas @@ -119,7 +121,6 @@ func formatSignature(signature string) string { cleanParams = append(cleanParams, parts[0]) } } - // Return formatted function signature return fmt.Sprintf("%s(%s)", funcName, strings.Join(cleanParams, ",")) } @@ -139,6 +140,33 @@ func FormatAndHash(signature string) common.Hash { func (m *Monitor) Run(ctx context.Context) { m.checkEvents(ctx) } + +func (m *Monitor) SignerCanBeRemove(ctx context.Context) { //TODO: Ensure the logs crit are not causing panic in runtime! + // if m.safeAddress == nil { + // m.log.Warn("safe address is not configured, skipping...") + // return + // } + // + // nonceBytes := hexutil.Bytes{} + // nonceTx := map[string]interface{}{"to": *m.safeAddress, "data": hexutil.Encode(SafeNonceSelector)} + // if err := m.l1Client.Client().CallContext(ctx, &nonceBytes, "eth_call", nonceTx, "latest"); err != nil { + // m.log.Error("failed to query safe nonce", "err", err) + // m.unexpectedRpcErrors.WithLabelValues("safe", "nonce()").Inc() + // return + // } + // + // nonce := new(big.Int).SetBytes(nonceBytes).Uint64() + // m.safeNonce.WithLabelValues(m.safeAddress.String(), m.nickname).Set(float64(nonce)) + // m.log.Info("Safe Nonce", "address", m.safeAddress.String(), "nonce", nonce) + // } + // + // m.pausedState.WithLabelValues(m.optimismPortalAddress.String(), m.nickname).Set(float64(pausedMetric)) + // m.log.Info("OptimismPortal status", "address", m.optimismPortalAddress.String(), "paused", paused) + // m.log.Info("Checking if the signer can be SignerCanBeRemove..") + +} + +// checkEvents function to check the events. If an events is emitted onchain and match the rules defined in the yaml file, then we will display the event. func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs crit are not causing panic in runtime! header, err := m.l1Client.HeaderByNumber(context.Background(), nil) if err != nil { @@ -165,7 +193,7 @@ func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs cri fmt.Printf("TxHash: h%s\nAddress:%s\nTopics: %s\n", vLog.TxHash, vLog.Address, vLog.Topics) fmt.Printf("The current config that matched this function: %v\n", config) fmt.Printf("----------------------------------------------------------------\n") - m.eventEmitted.WithLabelValues(m.nickname, vLog.Address.String(), config.Name, config.Events[0].Signature).Set(float64(1)) + m.eventEmitted.WithLabelValues(m.nickname, config.Name, config.Priority, config.Events[0].Signature, vLog.Address.String()).Set(float64(1)) } } diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 2903d3c..946e418 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -157,14 +157,16 @@ func (G GlobalConfiguration) DisplayMonitorAddresses() { for _, config := range G.Configuration { fmt.Printf("Name: %s\n", config.Name) if len(config.Addresses) == 0 && len(config.Events) > 0 { - fmt.Println("No addresses to monitor, but some events are defined (this means we are monitoring all the addresses), probably for debugging purposes.") + fmt.Println("Address:[], No address are defined but some events are defined (this means we are monitoring all the addresses), probably for debugging purposes.") for _, events := range config.Events { fmt.Printf("Events: %v\n", events) } } else { for _, address := range config.Addresses { fmt.Println("Address:", address) - fmt.Printf("Events: %v\n", G.ReturnEventsMonitoredForAnAddress(address)) + for _, events := range G.ReturnEventsMonitoredForAnAddress(address) { + fmt.Printf("Events: %v\n", events) + } } } } From 4fd4456b28db1f9ff73726ec8e2270a6e94a2abf Mon Sep 17 00:00:00 2001 From: ethnical Date: Fri, 24 May 2024 18:14:11 +0200 Subject: [PATCH 21/34] feat: small git clone to fetch from github embeeded into the binary --- op-monitorism/global_events/monitor.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 6f29a03..ca48e01 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -14,6 +14,9 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" + git "github.com/go-git/go-git/v5" + + "github.com/go-git/go-git/v5/plumbing" "github.com/prometheus/client_golang/prometheus" "time" ) @@ -54,8 +57,23 @@ func ChainIDToName(chainID int64) string { return "The `ChainID` is Not defined into the `chaindIDToName` function, this is probably a custom chain otherwise something is going wrong!" } +func cloneRepo(repoURL string, path string) error { //for debug purpose will be store to /tmp/Monitorism/rules_l1 + _, err := git.PlainClone(path, false, &git.CloneOptions{ + URL: repoURL, + ReferenceName: plumbing.NewBranchReferenceName("main"), // Replace 'main' with your branch if different + SingleBranch: true, + Depth: 1, // Use a shallow clone to speed up the process + }) + if err != nil { + + fmt.Printf("Error while cloning the repo: %v", err) + } + return err +} + // NewMonitor creates a new Monitor instance. func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { + cloneRepo("https://github.com/ethereum-optimism/monitorism.git", "/tmp/Monitorism/") //rules are located l1Client, err := ethclient.Dial(cfg.L1NodeURL) if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) @@ -139,6 +157,7 @@ func FormatAndHash(signature string) common.Hash { func (m *Monitor) Run(ctx context.Context) { m.checkEvents(ctx) + // m.SignerCanBeRemove } func (m *Monitor) SignerCanBeRemove(ctx context.Context) { //TODO: Ensure the logs crit are not causing panic in runtime! From 09daa19db53d7ff94e4cecb19b2f78448930fcb0 Mon Sep 17 00:00:00 2001 From: ethnical Date: Fri, 24 May 2024 18:37:27 +0200 Subject: [PATCH 22/34] chore: fix the name of the env --- op-monitorism/cmd/monitorism/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op-monitorism/cmd/monitorism/cli.go b/op-monitorism/cmd/monitorism/cli.go index 5c07a44..5ddc09a 100644 --- a/op-monitorism/cmd/monitorism/cli.go +++ b/op-monitorism/cmd/monitorism/cli.go @@ -65,7 +65,7 @@ func newCli(GitCommit string, GitDate string) *cli.App { Name: "global_events", Usage: "Monitors global events with YAML configuration", Description: "Monitors global events with YAML configuration", - Flags: append(global_events.CLIFlags("global_events if you see this variable then changed into the code."), defaultFlags...), + Flags: append(global_events.CLIFlags("GLOBAL_EVENT_MON"), defaultFlags...), Action: cliapp.LifecycleCmd(global_eventsMain), }, { From fe3eef4a3ff157504e42e70453b02e8dd0e546dd Mon Sep 17 00:00:00 2001 From: ethnical Date: Sat, 25 May 2024 11:47:06 +0200 Subject: [PATCH 23/34] bump: version git --- op-monitorism/go.mod | 20 +++++++++-- op-monitorism/go.sum | 82 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/op-monitorism/go.mod b/op-monitorism/go.mod index 8abf764..46dad4f 100644 --- a/op-monitorism/go.mod +++ b/op-monitorism/go.mod @@ -7,17 +7,21 @@ replace github.com/ethereum/go-ethereum v1.13.11 => github.com/ethereum-optimism require ( github.com/ethereum-optimism/optimism v1.7.3 github.com/ethereum/go-ethereum v1.13.11 + github.com/go-git/go-git/v5 v5.12.0 github.com/prometheus/client_golang v1.19.0 github.com/urfave/cli/v2 v2.27.1 + gopkg.in/yaml.v3 v3.0.1 ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect @@ -27,6 +31,7 @@ require ( github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/cockroachdb/errors v1.11.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20231018212520-f6cde3fc2fa4 // indirect @@ -37,8 +42,10 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240318114348-52d3dbd1605d // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fatih/structs v1.1.0 // indirect @@ -46,9 +53,12 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 // indirect github.com/google/uuid v1.6.0 // indirect @@ -59,6 +69,7 @@ require ( github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect github.com/iris-contrib/schema v0.0.6 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kataras/blocks v0.0.7 // indirect @@ -67,6 +78,7 @@ require ( github.com/kataras/pio v0.0.12 // indirect github.com/kataras/sitemap v0.0.6 // indirect github.com/kataras/tunnel v0.0.4 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -91,16 +103,19 @@ require ( github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rivo/uniseg v0.4.3 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.0 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/supranational/blst v0.3.11 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect @@ -111,6 +126,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yosssi/ace v0.0.5 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect @@ -126,7 +142,7 @@ require ( golang.org/x/tools v0.16.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect lukechampine.com/blake3 v1.2.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/op-monitorism/go.sum b/op-monitorism/go.sum index bce5eab..2bf838b 100644 --- a/op-monitorism/go.sum +++ b/op-monitorism/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= @@ -10,8 +12,11 @@ github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= @@ -23,6 +28,10 @@ github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKS github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -36,6 +45,7 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPx github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -44,6 +54,9 @@ github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgk github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= @@ -67,6 +80,8 @@ github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJ github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -78,6 +93,10 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etly github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/ethereum-optimism/op-geth v1.101311.0-rc.1 h1:3JE5FyGXNQCnXUuiK3I6ZD3zbB2DBIcEMsXCpjrXUwM= github.com/ethereum-optimism/op-geth v1.101311.0-rc.1/go.mod h1:K23yb9efVf9DdUOv/vl/Ux57Tng00rLaFqWYlFF45CA= github.com/ethereum-optimism/optimism v1.7.3 h1:kAwQcXcOnSqpcHDe8ZKUgbMSZn4p6khzM5E6QfqC/yQ= @@ -104,8 +123,18 @@ github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2Gihuqh github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -116,6 +145,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -182,6 +213,8 @@ github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -198,12 +231,15 @@ github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA= github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -287,6 +323,8 @@ github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -304,8 +342,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -314,13 +352,16 @@ github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQ github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -331,6 +372,7 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -362,6 +404,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -381,6 +425,7 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -390,6 +435,10 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= @@ -397,6 +446,8 @@ golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUU golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -406,10 +457,16 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -417,6 +474,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -432,6 +491,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -439,8 +499,11 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -449,12 +512,18 @@ golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -465,6 +534,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -483,6 +554,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -493,6 +565,8 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From c757978ba3f25461723845befa5bad7555d62e03 Mon Sep 17 00:00:00 2001 From: ethnical Date: Sat, 25 May 2024 12:09:29 +0200 Subject: [PATCH 24/34] readme fix the `-` --- op-monitorism/global_events/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/op-monitorism/global_events/README.md b/op-monitorism/global_events/README.md index 27fd164..eab744e 100644 --- a/op-monitorism/global_events/README.md +++ b/op-monitorism/global_events/README.md @@ -1,5 +1,7 @@ ## Global Events monitoring + This monitoring modules for the yaml rules added with the format ⚠️ This readme will be move into the global readme in the future. + ```yaml # This watches all contacts for OP, Mode, and Base mainnets for two logs. # These logs are emitted by Safes, so this effectively watches for all @@ -8,12 +10,15 @@ This monitoring modules for the yaml rules added with the format ⚠️ This rea version: 1.X name: My Super Explicit Alert Name. priority: P0 -addresses: 0x000000000000000000000000000000000000CAFE +addresses: + - 0x000000000000000000000000000000000000CAFE events: - signature: FunctionYouWantToMonitore(bytes32,uint256) - signature: FunctionYouWantToMonitore(bytes32,uint256) ``` -To run it: + +To run it: + ```bash go run . global_events --nickname MySuperNickName --l1.node.url https://localhost:8545 --PathYamlRules ../rules --loop.interval.msec 12000 ``` From 4bd2bb3c91b6da943c69dd6d7f90a4f34cd1e0fc Mon Sep 17 00:00:00 2001 From: ethnical Date: Sat, 25 May 2024 13:32:28 +0200 Subject: [PATCH 25/34] chore: errors handling + rpc message error logs. --- op-monitorism/global_events/monitor.go | 18 +++++++++++++----- op-monitorism/global_events/types.go | 16 +++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index ca48e01..90e8508 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -86,7 +86,7 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC } header, err := l1Client.HeaderByNumber(context.Background(), nil) if err != nil { - log.Crit("Failed to fetch the latest block header: %v", err) + log.Crit("Failed to fetch the latest block header", "error", err) } // display the infos at the start to ensure everything is correct. fmt.Printf("latestBlockNumber: %s\n", header.Number) @@ -94,7 +94,11 @@ func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIC fmt.Printf("PathYaml: %v\n", cfg.PathYamlRules) fmt.Printf("Nickname: %v\n", cfg.Nickname) fmt.Printf("L1NodeURL: %v\n", cfg.L1NodeURL) - globalConfig := ReadAllYamlRules(cfg.PathYamlRules) + globalConfig, err := ReadAllYamlRules(cfg.PathYamlRules) + if err != nil { + log.Crit("Failed to read the yaml rules", "error", err.Error()) + } + // create a globalconfig empty fmt.Printf("GlobalConfig: %#v\n", globalConfig.Configuration) globalConfig.DisplayMonitorAddresses() fmt.Printf("--------------------------------------- End of Infos -----------------------------\n") @@ -189,7 +193,9 @@ func (m *Monitor) SignerCanBeRemove(ctx context.Context) { //TODO: Ensure the lo func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs crit are not causing panic in runtime! header, err := m.l1Client.HeaderByNumber(context.Background(), nil) if err != nil { - m.log.Warn("Failed to retrieve latest block header: %v", err) //TODO:need to wait 12 and retry here! + m.unexpectedRpcErrors.WithLabelValues("L1", "HeaderByNumber").Inc() + m.log.Warn("Failed to retrieve latest block header", "error", err.Error()) //TODO:need to wait 12 and retry here! + return } latestBlockNumber := header.Number @@ -201,7 +207,9 @@ func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs cri logs, err := m.l1Client.FilterLogs(context.Background(), query) if err != nil { //TODO:need to wait 12 and retry here! - m.log.Warn("Failed to retrieve logs: %v", err) + m.unexpectedRpcErrors.WithLabelValues("L1", "FilterLogs").Inc() + m.log.Warn("Failed to retrieve logs:", "error", err.Error()) + return } for _, vLog := range logs { @@ -218,7 +226,7 @@ func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs cri } } - m.log.Info("Checking events...", "CurrentBlock", latestBlockNumber) + m.log.Info("Checking events..", "CurrentBlock", latestBlockNumber) } diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 946e418..96454eb 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -1,12 +1,12 @@ package global_events import ( + "errors" "fmt" - "os" - "path/filepath" - "github.com/ethereum/go-ethereum/common" "gopkg.in/yaml.v3" + "os" + "path/filepath" ) // EventTopic is the struct that will contain the index of the topic and the values that will be monitored (not used currently). @@ -111,7 +111,7 @@ func StringFunctionToHex(config Configuration) Configuration { } // ReadAllYamlRules Read all the files in the `rules` directory at the given path from the command line `--PathYamlRules` that are YAML files. -func ReadAllYamlRules(PathYamlRules string) GlobalConfiguration { +func ReadAllYamlRules(PathYamlRules string) (GlobalConfiguration, error) { var GlobalConfig GlobalConfiguration entries, err := os.ReadDir(PathYamlRules) //Only read yaml files @@ -131,7 +131,9 @@ func ReadAllYamlRules(PathYamlRules string) GlobalConfiguration { yamlFiles = append(yamlFiles, entry) } } - + if len(yamlFiles) == 0 { + return GlobalConfiguration{}, errors.New("No YAML files found in the directory") + } for _, file := range yamlFiles { path_rule := PathYamlRules + "/" + file.Name() fmt.Printf("Reading a rule named: %s\n", path_rule) @@ -148,10 +150,10 @@ func ReadAllYamlRules(PathYamlRules string) GlobalConfiguration { fmt.Println("Error writing the globalconfig YAML file on the disk:", err) panic("Error writing the globalconfig YAML file on the disk") } - return GlobalConfig + return GlobalConfig, nil } -// DisplayMonitorAddresses() will display the addresses that are monitored and the events that are monitored for each address. +// DisplayMonitorAddresses will display the addresses that are monitored and the events that are monitored for each address. func (G GlobalConfiguration) DisplayMonitorAddresses() { println("============== Monitoring addresses =================") for _, config := range G.Configuration { From 60a16e6e58b777020e86908ae2cae0b5b74a8c5d Mon Sep 17 00:00:00 2001 From: ethnical Date: Sat, 25 May 2024 14:09:38 +0200 Subject: [PATCH 26/34] chore: fix comments + add the rules --- op-monitorism/global_events/monitor.go | 6 ++++-- .../rules/rules_mainnet_L1/LivenessFallback.yaml | 7 +++++++ .../rules/rules_mainnet_L1/LivenessRemoveAdded.yaml | 9 +++++++++ .../rules/rules_mainnet_L1/ModuleAndGuard.yaml | 9 +++++++++ .../rules/rules_mainnet_L1/OptimismPortalProxy.yaml | 8 ++++++++ .../rules/rules_mainnet_L1/SystemChainConfig.yaml | 8 ++++++++ .../rules/rules_mainnet_L1/TemplateYaml.yaml | 11 +++++++++++ .../rules/rules_sepolia_L1/LivenessFallback.yaml | 7 +++++++ .../rules/rules_sepolia_L1/LivenessRemoveAdded.yaml | 9 +++++++++ .../rules/rules_sepolia_L1/ModuleAndGuard.yaml | 9 +++++++++ .../rules/rules_sepolia_L1/OptimismPortalProxy.yaml | 8 ++++++++ .../rules/rules_sepolia_L1/SystemChainConfig.yaml | 8 ++++++++ .../rules/rules_sepolia_L1/TemplateYaml.yaml | 11 +++++++++++ op-monitorism/global_events/types.go | 4 ++-- 14 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 op-monitorism/global_events/rules/rules_mainnet_L1/LivenessFallback.yaml create mode 100644 op-monitorism/global_events/rules/rules_mainnet_L1/LivenessRemoveAdded.yaml create mode 100644 op-monitorism/global_events/rules/rules_mainnet_L1/ModuleAndGuard.yaml create mode 100644 op-monitorism/global_events/rules/rules_mainnet_L1/OptimismPortalProxy.yaml create mode 100644 op-monitorism/global_events/rules/rules_mainnet_L1/SystemChainConfig.yaml create mode 100644 op-monitorism/global_events/rules/rules_mainnet_L1/TemplateYaml.yaml create mode 100644 op-monitorism/global_events/rules/rules_sepolia_L1/LivenessFallback.yaml create mode 100644 op-monitorism/global_events/rules/rules_sepolia_L1/LivenessRemoveAdded.yaml create mode 100644 op-monitorism/global_events/rules/rules_sepolia_L1/ModuleAndGuard.yaml create mode 100644 op-monitorism/global_events/rules/rules_sepolia_L1/OptimismPortalProxy.yaml create mode 100644 op-monitorism/global_events/rules/rules_sepolia_L1/SystemChainConfig.yaml create mode 100644 op-monitorism/global_events/rules/rules_sepolia_L1/TemplateYaml.yaml diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 90e8508..21d2c47 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -66,14 +66,14 @@ func cloneRepo(repoURL string, path string) error { //for debug purpose will be }) if err != nil { - fmt.Printf("Error while cloning the repo: %v", err) + fmt.Printf("Error while cloning the repo: %v\n", err) } return err } // NewMonitor creates a new Monitor instance. func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { - cloneRepo("https://github.com/ethereum-optimism/monitorism.git", "/tmp/Monitorism/") //rules are located + cloneRepo("https://github.com/ethereum-optimism/monitorism.git", "/tmp/Monitorism/") //This copy the repo to /tmp/Monitorism/ we need to have the rules inside the repo and this will download them. l1Client, err := ethclient.Dial(cfg.L1NodeURL) if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) @@ -159,6 +159,7 @@ func FormatAndHash(signature string) common.Hash { } +// Run the monitor functions declared as a monitor method. func (m *Monitor) Run(ctx context.Context) { m.checkEvents(ctx) // m.SignerCanBeRemove @@ -230,6 +231,7 @@ func (m *Monitor) checkEvents(ctx context.Context) { //TODO: Ensure the logs cri } +// Close closes the monitor. func (m *Monitor) Close(_ context.Context) error { m.l1Client.Close() return nil diff --git a/op-monitorism/global_events/rules/rules_mainnet_L1/LivenessFallback.yaml b/op-monitorism/global_events/rules/rules_mainnet_L1/LivenessFallback.yaml new file mode 100644 index 0000000..75c8a03 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_mainnet_L1/LivenessFallback.yaml @@ -0,0 +1,7 @@ +version: 1.0 +name: Liveness Fallback Owner (Safe SC) L1 +priority: P2 +addresses: + - 0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 +events: + - signature: OwnershipTransferredToFallback() diff --git a/op-monitorism/global_events/rules/rules_mainnet_L1/LivenessRemoveAdded.yaml b/op-monitorism/global_events/rules/rules_mainnet_L1/LivenessRemoveAdded.yaml new file mode 100644 index 0000000..8cb07db --- /dev/null +++ b/op-monitorism/global_events/rules/rules_mainnet_L1/LivenessRemoveAdded.yaml @@ -0,0 +1,9 @@ +version: 1.0 +name: Liveness Signer Action (Safe SC) L1 +priority: P2 +addresses: + - 0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 +events: + - signature: AddedOwner(address owner) + - signature: RemovedOwner(address owner) + - signature: ChangedThreshold(uint256 threshold) diff --git a/op-monitorism/global_events/rules/rules_mainnet_L1/ModuleAndGuard.yaml b/op-monitorism/global_events/rules/rules_mainnet_L1/ModuleAndGuard.yaml new file mode 100644 index 0000000..b538e36 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_mainnet_L1/ModuleAndGuard.yaml @@ -0,0 +1,9 @@ +version: 1.0 +name: Guard/Module Removed or Replaced (Safe SC) L1 +priority: P2 +addresses: + - 0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 +events: + - signature: EnabledModule(address module) + - signature: DisabledModule(address module) + - signature: ChangedGuard(address guard) diff --git a/op-monitorism/global_events/rules/rules_mainnet_L1/OptimismPortalProxy.yaml b/op-monitorism/global_events/rules/rules_mainnet_L1/OptimismPortalProxy.yaml new file mode 100644 index 0000000..4851642 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_mainnet_L1/OptimismPortalProxy.yaml @@ -0,0 +1,8 @@ +version: 1.0 +name: OptimismPortalProxy (after Proof) L1 +priority: P5 +addresses: + - 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed # /!\ We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. +events: + - signature: DisputeGameBlacklisted(IDisputeGame indexed disputeGame) + - signature: RespectedGameTypeSet(GameType indexed newGameType, Timestamp indexed updatedAt) diff --git a/op-monitorism/global_events/rules/rules_mainnet_L1/SystemChainConfig.yaml b/op-monitorism/global_events/rules/rules_mainnet_L1/SystemChainConfig.yaml new file mode 100644 index 0000000..d17b28b --- /dev/null +++ b/op-monitorism/global_events/rules/rules_mainnet_L1/SystemChainConfig.yaml @@ -0,0 +1,8 @@ +version: 1.0 +name: SuperChainConfig Pause and Unpause L1 +priority: P2 +addresses: + - 0x95703e0982140D16f8ebA6d158FccEde42f04a4C # /!\ We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. +events: + - signature: Paused(String) + - signature: Unpaused() diff --git a/op-monitorism/global_events/rules/rules_mainnet_L1/TemplateYaml.yaml b/op-monitorism/global_events/rules/rules_mainnet_L1/TemplateYaml.yaml new file mode 100644 index 0000000..7a834e7 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_mainnet_L1/TemplateYaml.yaml @@ -0,0 +1,11 @@ +# This is a TEMPLATE file please copy this one +# This watches all contacts for OP, Mode, and Base mainnets for two logs. +version: 1.0 +name: Template SafeExecution Events (Success/Failure) L1 # Please put the L1 or L2 at the end of the name. +priority: P5 # This is a test, so it is a P5 +#If addresses is empty like below it will watch all addresses otherwise you can address specific addresses. +addresses: + # - 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed # /!\ SPECIFIC ADDRESS -> We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. +events: + - signature: ExecutionFailure(bytes32,uint256) # List of the events to watch for the addresses. + - signature: ExecutionSuccess(bytes32,uint256) # List of the events to watch for the addresses. diff --git a/op-monitorism/global_events/rules/rules_sepolia_L1/LivenessFallback.yaml b/op-monitorism/global_events/rules/rules_sepolia_L1/LivenessFallback.yaml new file mode 100644 index 0000000..fe6f5ca --- /dev/null +++ b/op-monitorism/global_events/rules/rules_sepolia_L1/LivenessFallback.yaml @@ -0,0 +1,7 @@ +version: 1.0 +name: Liveness Fallback Owner (Safe SC) L1 +priority: P2 +addresses: + - 0xCB7b18DBA09fc0525554727Df1b8Ee9c90b9870c #Need to recheck for this actual addresses. +events: + - signature: OwnershipTransferredToFallback() diff --git a/op-monitorism/global_events/rules/rules_sepolia_L1/LivenessRemoveAdded.yaml b/op-monitorism/global_events/rules/rules_sepolia_L1/LivenessRemoveAdded.yaml new file mode 100644 index 0000000..e2da6fc --- /dev/null +++ b/op-monitorism/global_events/rules/rules_sepolia_L1/LivenessRemoveAdded.yaml @@ -0,0 +1,9 @@ +version: 1.0 +name: Liveness Signer Action (Safe SC) L1 +priority: P2 +addresses: + - 0xCB7b18DBA09fc0525554727Df1b8Ee9c90b9870c #Need to recheck for this actual addresses. +events: + - signature: AddedOwner(address owner) + - signature: RemovedOwner(address owner) + - signature: ChangedThreshold(uint256 threshold) diff --git a/op-monitorism/global_events/rules/rules_sepolia_L1/ModuleAndGuard.yaml b/op-monitorism/global_events/rules/rules_sepolia_L1/ModuleAndGuard.yaml new file mode 100644 index 0000000..1b8a4f9 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_sepolia_L1/ModuleAndGuard.yaml @@ -0,0 +1,9 @@ +version: 1.0 +name: Liveness Enabled/DisabledModule (Safe SC) L1 +priority: P2 +addresses: + - 0xCB7b18DBA09fc0525554727Df1b8Ee9c90b9870c +events: + - signature: EnabledModule(address module) + - signature: DisabledModule(address module) + - signature: ChangedGuard(address guard) diff --git a/op-monitorism/global_events/rules/rules_sepolia_L1/OptimismPortalProxy.yaml b/op-monitorism/global_events/rules/rules_sepolia_L1/OptimismPortalProxy.yaml new file mode 100644 index 0000000..f9df968 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_sepolia_L1/OptimismPortalProxy.yaml @@ -0,0 +1,8 @@ +version: 1.0 +name: OptimismPortalProxy (after Proof) L1 +priority: P5 +addresses: + - 0x16Fc5058F25648194471939df75CF27A2fdC48BC # /!\ We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. +events: + - signature: DisputeGameBlacklisted(IDisputeGame indexed disputeGame) + - signature: RespectedGameTypeSet(GameType indexed newGameType, Timestamp indexed updatedAt) diff --git a/op-monitorism/global_events/rules/rules_sepolia_L1/SystemChainConfig.yaml b/op-monitorism/global_events/rules/rules_sepolia_L1/SystemChainConfig.yaml new file mode 100644 index 0000000..1165cc9 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_sepolia_L1/SystemChainConfig.yaml @@ -0,0 +1,8 @@ +version: 1.0 +name: SuperChainConfig Pause and Unpause L1 +priority: P2 +addresses: + - 0xC2Be75506d5724086DEB7245bd260Cc9753911Be # /!\ We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. +events: + - signature: Paused(String) + - signature: Unpaused() diff --git a/op-monitorism/global_events/rules/rules_sepolia_L1/TemplateYaml.yaml b/op-monitorism/global_events/rules/rules_sepolia_L1/TemplateYaml.yaml new file mode 100644 index 0000000..7a834e7 --- /dev/null +++ b/op-monitorism/global_events/rules/rules_sepolia_L1/TemplateYaml.yaml @@ -0,0 +1,11 @@ +# This is a TEMPLATE file please copy this one +# This watches all contacts for OP, Mode, and Base mainnets for two logs. +version: 1.0 +name: Template SafeExecution Events (Success/Failure) L1 # Please put the L1 or L2 at the end of the name. +priority: P5 # This is a test, so it is a P5 +#If addresses is empty like below it will watch all addresses otherwise you can address specific addresses. +addresses: + # - 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed # /!\ SPECIFIC ADDRESS -> We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. +events: + - signature: ExecutionFailure(bytes32,uint256) # List of the events to watch for the addresses. + - signature: ExecutionSuccess(bytes32,uint256) # List of the events to watch for the addresses. diff --git a/op-monitorism/global_events/types.go b/op-monitorism/global_events/types.go index 96454eb..72716c8 100644 --- a/op-monitorism/global_events/types.go +++ b/op-monitorism/global_events/types.go @@ -82,7 +82,7 @@ func ReadYamlFile(filename string) Configuration { return config } -// StringFunctionToHex take the configuration yaml and resolve the signature stringed like "Transfer(address)" // that will contains all the addresses that will monitore. +// StringFunctionToHex take the configuration yaml and resolve a solidity event like "Transfer(address)" to the keccak256 hash of the event signature and UPDATE the configuration with the keccak256 hash. func StringFunctionToHex(config Configuration) Configuration { var FinalConfig Configuration @@ -145,7 +145,7 @@ func ReadAllYamlRules(PathYamlRules string) (GlobalConfiguration, error) { } yaml_marshalled, err := yaml.Marshal(GlobalConfig) - err = os.WriteFile("globalconfig.yaml", yaml_marshalled, 0644) + err = os.WriteFile("/tmp/globalconfig.yaml", yaml_marshalled, 0644) // Storing the configuration if we need to debug and knows what is monitored in the future. if err != nil { fmt.Println("Error writing the globalconfig YAML file on the disk:", err) panic("Error writing the globalconfig YAML file on the disk") From fe4d93729c21fb1b42adb5f5e6c6c5460d28936d Mon Sep 17 00:00:00 2001 From: Ethnical Date: Sat, 25 May 2024 14:14:09 +0200 Subject: [PATCH 27/34] Update README.md --- op-monitorism/global_events/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/op-monitorism/global_events/README.md b/op-monitorism/global_events/README.md index eab744e..3ed538b 100644 --- a/op-monitorism/global_events/README.md +++ b/op-monitorism/global_events/README.md @@ -2,19 +2,19 @@ This monitoring modules for the yaml rules added with the format ⚠️ This readme will be move into the global readme in the future. +The rules are located here: `op-monitorism/global_events/rules/` then we have multiples folders depending the networks you want to monitore (`mainnet` or `sepolia`) for now. ```yaml +# This is a TEMPLATE file please copy this one # This watches all contacts for OP, Mode, and Base mainnets for two logs. -# These logs are emitted by Safes, so this effectively watches for all -# transactions from any Safe on these chains. - -version: 1.X -name: My Super Explicit Alert Name. -priority: P0 +version: 1.0 +name: Template SafeExecution Events (Success/Failure) L1 # Please put the L1 or L2 at the end of the name. +priority: P5 # This is a test, so it is a P5 +#If addresses is empty like below it will watch all addresses otherwise you can address specific addresses. addresses: - - 0x000000000000000000000000000000000000CAFE + # - 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed # Specific Addresses /!\ We are not supporting EIP 3770 yet, if the address is not starting by 0x, this will panic by safety measure. events: - - signature: FunctionYouWantToMonitore(bytes32,uint256) - - signature: FunctionYouWantToMonitore(bytes32,uint256) + - signature: ExecutionFailure(bytes32,uint256) # List of the events to watch for the addresses. + - signature: ExecutionSuccess(bytes32,uint256) # List of the events to watch for the addresses. ``` To run it: From e8740fe9dab73162bd6cb726578e5eb512afb6ab Mon Sep 17 00:00:00 2001 From: Ethnical Date: Sat, 25 May 2024 14:26:32 +0200 Subject: [PATCH 28/34] Update README.md --- op-monitorism/global_events/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/op-monitorism/global_events/README.md b/op-monitorism/global_events/README.md index 3ed538b..550fb0b 100644 --- a/op-monitorism/global_events/README.md +++ b/op-monitorism/global_events/README.md @@ -20,5 +20,7 @@ events: To run it: ```bash -go run . global_events --nickname MySuperNickName --l1.node.url https://localhost:8545 --PathYamlRules ../rules --loop.interval.msec 12000 + +go run ../cmd/monitorism global_events --nickname MySuperNickName --l1.node.url https://localhost:8545 --PathYamlRules /tmp/Monitorism/op-monitorism/global_events/rules/rules_mainnet_L1 --loop.interval.msec 12000 + ``` From d7e4d62efd6f8d907b3f136fbf118b0aee234ad6 Mon Sep 17 00:00:00 2001 From: Ethnical Date: Mon, 27 May 2024 18:20:59 +0200 Subject: [PATCH 29/34] Update README.md --- op-monitorism/global_events/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/op-monitorism/global_events/README.md b/op-monitorism/global_events/README.md index 550fb0b..a1851ea 100644 --- a/op-monitorism/global_events/README.md +++ b/op-monitorism/global_events/README.md @@ -2,6 +2,32 @@ This monitoring modules for the yaml rules added with the format ⚠️ This readme will be move into the global readme in the future. +CLI and Docs: +```bash +NAME: + Monitorism global_events - Monitors global events with YAML configuration + +USAGE: + Monitorism global_events [command options] [arguments...] + +DESCRIPTION: + Monitors global events with YAML configuration + +OPTIONS: + --l1.node.url value Node URL of L1 peer (default: "http://127.0.0.1:8545") [$GLOBAL_EVENT_MON_L1_NODE_URL] + --nickname value Nickname of chain being monitored [$GLOBAL_EVENT_MON_NICKNAME] + --PathYamlRules value Path to the yaml file containing the events to monitor [$GLOBAL_EVENT_MON_PATH_YAML] + --log.level value The lowest log level that will be output (default: INFO) [$MONITORISM_LOG_LEVEL] + --log.format value Format the log output. Supported formats: 'text', 'terminal', 'logfmt', 'json', 'json-pretty', (default: text) [$MONITORISM_LOG_FORMAT] + --log.color Color the log output if in terminal mode (default: false) [$MONITORISM_LOG_COLOR] + --metrics.enabled Enable the metrics server (default: false) [$MONITORISM_METRICS_ENABLED] + --metrics.addr value Metrics listening address (default: "0.0.0.0") [$MONITORISM_METRICS_ADDR] + --metrics.port value Metrics listening port (default: 7300) [$MONITORISM_METRICS_PORT] + --loop.interval.msec value Loop interval of the monitor in milliseconds (default: 60000) [$MONITORISM_LOOP_INTERVAL_MSEC] + --help, -h show help + +``` + The rules are located here: `op-monitorism/global_events/rules/` then we have multiples folders depending the networks you want to monitore (`mainnet` or `sepolia`) for now. ```yaml # This is a TEMPLATE file please copy this one From fbeab19565cfe65a3d6e02b0fb2afc0f17140bc7 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 28 May 2024 14:50:17 +0200 Subject: [PATCH 30/34] chore: remove the useless comments + comment the `cloneRepo()` if needed in the future. --- op-monitorism/global_events/monitor.go | 36 +++++++++------------ op-monitorism/global_events/monitor_test.go | 12 ------- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 21d2c47..523a42e 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -3,21 +3,18 @@ package global_events import ( "context" "fmt" - "regexp" - "strings" - "github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" git "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" "github.com/prometheus/client_golang/prometheus" + "regexp" + "strings" "time" ) @@ -57,29 +54,28 @@ func ChainIDToName(chainID int64) string { return "The `ChainID` is Not defined into the `chaindIDToName` function, this is probably a custom chain otherwise something is going wrong!" } -func cloneRepo(repoURL string, path string) error { //for debug purpose will be store to /tmp/Monitorism/rules_l1 - _, err := git.PlainClone(path, false, &git.CloneOptions{ - URL: repoURL, - ReferenceName: plumbing.NewBranchReferenceName("main"), // Replace 'main' with your branch if different - SingleBranch: true, - Depth: 1, // Use a shallow clone to speed up the process - }) - if err != nil { - - fmt.Printf("Error while cloning the repo: %v\n", err) - } - return err -} +// func cloneRepo(repoURL string, path string) error { //for debug purpose will be store to /tmp/Monitorism/rules_l1 +// _, err := git.PlainClone(path, false, &git.CloneOptions{ +// URL: repoURL, +// ReferenceName: plumbing.NewBranchReferenceName("ethni/globalevents"), // Replace 'main' with your branch if different +// SingleBranch: true, +// Depth: 1, // Use a shallow clone to speed up the process +// }) +// if err != nil { +// +// fmt.Printf("Error while cloning the repo: %v\n", err) +// } +// return err +// } // NewMonitor creates a new Monitor instance. func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { - cloneRepo("https://github.com/ethereum-optimism/monitorism.git", "/tmp/Monitorism/") //This copy the repo to /tmp/Monitorism/ we need to have the rules inside the repo and this will download them. + // cloneRepo("https://github.com/ethereum-optimism/monitorism.git", "/tmp/Monitorism/") //This copy the repo to /tmp/Monitorism/ we need to have the rules inside the repo and this will download them. l1Client, err := ethclient.Dial(cfg.L1NodeURL) if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err) } fmt.Printf("--------------------------------------- Global_events_mon (Infos) -----------------------------\n") - // fmt.Printf("chainID:", ChainIDToName(l1Client.ChainID()) ChainID, err := l1Client.ChainID(context.Background()) if err != nil { log.Crit("Failed to retrieve chain ID: %v", err) diff --git a/op-monitorism/global_events/monitor_test.go b/op-monitorism/global_events/monitor_test.go index e8bd08d..8cadf07 100644 --- a/op-monitorism/global_events/monitor_test.go +++ b/op-monitorism/global_events/monitor_test.go @@ -1,7 +1,6 @@ package global_events import ( - // "strings" "testing" ) @@ -47,14 +46,3 @@ func TestFormatSignature(t *testing.T) { }) } } - -// func TestFunctionSelector(t *testing.T) { -// expectedSelector := "70a08231" // known selector for "balanceOf(address)" -// formattedSignature := "balanceOf(address)" -// hash := crypto.Keccak256([]byte(formattedSignature)) -// selector := strings.ToLower(fmt.Sprintf("%x", hash[:4])) -// -// if selector != expectedSelector { -// t.Errorf("Selector calculation failed: expected %s but got %s", expectedSelector, selector) -// } -// } From 67756ad2b599f17fd5a4871e02f44a028615b641 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 28 May 2024 14:54:41 +0200 Subject: [PATCH 31/34] chore: remove the `SignerCanBeRemove()` --- op-monitorism/global_events/monitor.go | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 523a42e..e726238 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -158,32 +158,6 @@ func FormatAndHash(signature string) common.Hash { // Run the monitor functions declared as a monitor method. func (m *Monitor) Run(ctx context.Context) { m.checkEvents(ctx) - // m.SignerCanBeRemove -} - -func (m *Monitor) SignerCanBeRemove(ctx context.Context) { //TODO: Ensure the logs crit are not causing panic in runtime! - // if m.safeAddress == nil { - // m.log.Warn("safe address is not configured, skipping...") - // return - // } - // - // nonceBytes := hexutil.Bytes{} - // nonceTx := map[string]interface{}{"to": *m.safeAddress, "data": hexutil.Encode(SafeNonceSelector)} - // if err := m.l1Client.Client().CallContext(ctx, &nonceBytes, "eth_call", nonceTx, "latest"); err != nil { - // m.log.Error("failed to query safe nonce", "err", err) - // m.unexpectedRpcErrors.WithLabelValues("safe", "nonce()").Inc() - // return - // } - // - // nonce := new(big.Int).SetBytes(nonceBytes).Uint64() - // m.safeNonce.WithLabelValues(m.safeAddress.String(), m.nickname).Set(float64(nonce)) - // m.log.Info("Safe Nonce", "address", m.safeAddress.String(), "nonce", nonce) - // } - // - // m.pausedState.WithLabelValues(m.optimismPortalAddress.String(), m.nickname).Set(float64(pausedMetric)) - // m.log.Info("OptimismPortal status", "address", m.optimismPortalAddress.String(), "paused", paused) - // m.log.Info("Checking if the signer can be SignerCanBeRemove..") - } // checkEvents function to check the events. If an events is emitted onchain and match the rules defined in the yaml file, then we will display the event. From f9fa27c675369be55e78314c4890bb11866bcc28 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 28 May 2024 14:56:14 +0200 Subject: [PATCH 32/34] chore: comment the dependencies for `cloneRepo()` if we need to use it the future. --- op-monitorism/global_events/monitor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index e726238..1676d71 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -10,8 +10,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - git "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" "github.com/prometheus/client_golang/prometheus" "regexp" "strings" @@ -54,6 +52,8 @@ func ChainIDToName(chainID int64) string { return "The `ChainID` is Not defined into the `chaindIDToName` function, this is probably a custom chain otherwise something is going wrong!" } +// git "github.com/go-git/go-git/v5" +// "github.com/go-git/go-git/v5/plumbing" // func cloneRepo(repoURL string, path string) error { //for debug purpose will be store to /tmp/Monitorism/rules_l1 // _, err := git.PlainClone(path, false, &git.CloneOptions{ // URL: repoURL, From 261c416e5f56caf46989fff1c8fa534490514bad Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 28 May 2024 16:23:49 +0200 Subject: [PATCH 33/34] chore: remove not necessary function. --- op-monitorism/global_events/types_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/op-monitorism/global_events/types_test.go b/op-monitorism/global_events/types_test.go index a21374a..0d9b526 100644 --- a/op-monitorism/global_events/types_test.go +++ b/op-monitorism/global_events/types_test.go @@ -25,16 +25,6 @@ configuration: - signature: "ExecutionSuccess(bytes32,uint256)" ` -// func (G GlobalConfiguration) ReturnEventsMonitoredForAnAddress(target_address common.Address) []Event { -// for _, config := range G.Configuration { -// for _, address := range config.Addresses { -// if address == target_address { -// return config.Events -// } -// } -// } -// return []Event{} // no events monitored for this address -// // Print the config to see if it's correct func TestReturnEventsMonitoredForAnAddress(t *testing.T) { var config GlobalConfiguration From 16ec7d213875d0048aee6dd0c8ad47988eda5453 Mon Sep 17 00:00:00 2001 From: ethnical Date: Tue, 28 May 2024 17:42:45 +0200 Subject: [PATCH 34/34] chore: remove the `CloneRepo()` function. --- op-monitorism/global_events/monitor.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/op-monitorism/global_events/monitor.go b/op-monitorism/global_events/monitor.go index 1676d71..7397155 100644 --- a/op-monitorism/global_events/monitor.go +++ b/op-monitorism/global_events/monitor.go @@ -52,25 +52,8 @@ func ChainIDToName(chainID int64) string { return "The `ChainID` is Not defined into the `chaindIDToName` function, this is probably a custom chain otherwise something is going wrong!" } -// git "github.com/go-git/go-git/v5" -// "github.com/go-git/go-git/v5/plumbing" -// func cloneRepo(repoURL string, path string) error { //for debug purpose will be store to /tmp/Monitorism/rules_l1 -// _, err := git.PlainClone(path, false, &git.CloneOptions{ -// URL: repoURL, -// ReferenceName: plumbing.NewBranchReferenceName("ethni/globalevents"), // Replace 'main' with your branch if different -// SingleBranch: true, -// Depth: 1, // Use a shallow clone to speed up the process -// }) -// if err != nil { -// -// fmt.Printf("Error while cloning the repo: %v\n", err) -// } -// return err -// } - // NewMonitor creates a new Monitor instance. func NewMonitor(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLIConfig) (*Monitor, error) { - // cloneRepo("https://github.com/ethereum-optimism/monitorism.git", "/tmp/Monitorism/") //This copy the repo to /tmp/Monitorism/ we need to have the rules inside the repo and this will download them. l1Client, err := ethclient.Dial(cfg.L1NodeURL) if err != nil { return nil, fmt.Errorf("failed to dial l1 rpc: %w", err)