Merge pull request #6 from ethereum-optimism/merge-op-ufm-2
feat: move op-ufm to this repo
This commit is contained in:
commit
0ab029a12d
@ -16,6 +16,7 @@ workflows:
|
||||
# <regex path-to-test> <parameter-to-set> <value-of-pipeline-parameter>
|
||||
mapping: |
|
||||
op-conductor-mon/.* run-build-op-conductor-mon true
|
||||
op-ufm/.* run-build-op-ufm true
|
||||
.circleci/.* run-all true
|
||||
.github/.* run-all true
|
||||
|
||||
|
@ -10,6 +10,9 @@ parameters:
|
||||
run-build-op-conductor-mon:
|
||||
type: boolean
|
||||
default: false
|
||||
run-build-op-ufm:
|
||||
type: boolean
|
||||
default: false
|
||||
run-all:
|
||||
type: boolean
|
||||
default: false
|
||||
@ -224,7 +227,11 @@ jobs:
|
||||
- run:
|
||||
name: run lint
|
||||
command: |
|
||||
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint -e "errors.As" -e "errors.Is" --timeout "3m0s" ./...
|
||||
if [ -f .golangci.yml ]; then
|
||||
golangci-lint run -c .golangci.yml -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint -e "errors.As" -e "errors.Is" --timeout "3m0s" ./...
|
||||
else
|
||||
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint -e "errors.As" -e "errors.Is" --timeout "3m0s" ./...
|
||||
fi
|
||||
working_directory: <<parameters.module>>
|
||||
|
||||
go-test:
|
||||
@ -357,3 +364,27 @@ workflows:
|
||||
- oplabs-gcr
|
||||
requires:
|
||||
- op-conductor-mon-docker-build
|
||||
op-ufm:
|
||||
when:
|
||||
or: [<< pipeline.parameters.run-build-op-ufm >>, << pipeline.parameters.run-all >>]
|
||||
jobs:
|
||||
- go-lint:
|
||||
name: op-conductor-mon-lint
|
||||
module: op-ufm
|
||||
- go-test:
|
||||
name: op-conductor-mon-tests
|
||||
module: op-ufm
|
||||
- docker-build:
|
||||
name: op-ufm-docker-build
|
||||
docker_file: op-ufm/Dockerfile
|
||||
docker_name: op-ufm
|
||||
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
|
||||
docker_context: .
|
||||
- docker-publish:
|
||||
name: op-ufm-docker-publish
|
||||
docker_name: op-ufm
|
||||
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
|
||||
context:
|
||||
- oplabs-gcr
|
||||
requires:
|
||||
- op-ufm-docker-build
|
||||
|
4
op-ufm/.gitignore
vendored
Normal file
4
op-ufm/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
bin
|
||||
tls
|
||||
|
||||
config.toml
|
10
op-ufm/.golangci.yml
Normal file
10
op-ufm/.golangci.yml
Normal file
@ -0,0 +1,10 @@
|
||||
linters-settings:
|
||||
staticcheck:
|
||||
checks: ["all"]
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: "pkg/provider/roundtrip.go"
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA4006"
|
30
op-ufm/Dockerfile
Normal file
30
op-ufm/Dockerfile
Normal file
@ -0,0 +1,30 @@
|
||||
FROM golang:1.21.1-alpine3.18 as builder
|
||||
|
||||
ARG GITCOMMIT=docker
|
||||
ARG GITDATE=docker
|
||||
ARG GITVERSION=docker
|
||||
|
||||
RUN apk add make jq git gcc musl-dev linux-headers
|
||||
|
||||
COPY ./op-ufm /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN make ufm
|
||||
|
||||
FROM alpine:3.18
|
||||
|
||||
COPY --from=builder /app/entrypoint.sh /bin/entrypoint.sh
|
||||
COPY --from=builder /app/bin/ufm /bin/ufm
|
||||
|
||||
RUN apk update && \
|
||||
chmod +x /bin/entrypoint.sh
|
||||
|
||||
RUN apk add ca-certificates jq curl bind-tools
|
||||
|
||||
VOLUME /etc/ufm
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["/bin/entrypoint.sh"]
|
||||
CMD ["/bin/ufm", "/etc/ufm/config.toml"]
|
36
op-ufm/Makefile
Normal file
36
op-ufm/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT)
|
||||
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE)
|
||||
LDFLAGSSTRING +=-X main.GitVersion=$(GITVERSION)
|
||||
LDFLAGS := -ldflags "$(LDFLAGSSTRING)"
|
||||
|
||||
ufm:
|
||||
go build -v $(LDFLAGS) -o ./bin/ufm ./cmd/ufm
|
||||
.PHONY: ufm
|
||||
|
||||
fmt:
|
||||
go mod tidy
|
||||
gofmt -w .
|
||||
.PHONY: fmt
|
||||
|
||||
test:
|
||||
go test -race -v ./...
|
||||
.PHONY: test
|
||||
|
||||
lint:
|
||||
go vet ./...
|
||||
.PHONY: lint
|
||||
|
||||
tls:
|
||||
kubectl get secrets op-ufm-client-tls -o yaml | yq '.data."tls.key"' | base64 --decode > tls/tls.key
|
||||
kubectl get secrets op-ufm-client-tls -o yaml | yq '.data."tls.crt"' | base64 --decode > tls/tls.crt
|
||||
kubectl get secrets op-ufm-client-tls -o yaml | yq '.data."ca.crt"' | base64 --decode > tls/ca.crt
|
||||
.PHONY: tls
|
||||
|
||||
mod-tidy:
|
||||
# Below GOPRIVATE line allows mod-tidy to be run immediately after
|
||||
# releasing new versions. This bypasses the Go modules proxy, which
|
||||
# can take a while to index new versions.
|
||||
#
|
||||
# See https://proxy.golang.org/ for more info.
|
||||
export GOPRIVATE="github.com/ethereum-optimism" && go mod tidy
|
||||
.PHONY: mod-tidy
|
23
op-ufm/README.md
Normal file
23
op-ufm/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# OP User Facing Monitoring
|
||||
|
||||
This project simulates a synthetic user interacting with a OP Stack chain.
|
||||
|
||||
It is intended to be used as a tool for monitoring
|
||||
the health of the network by measuring end-to-end transaction latency.
|
||||
|
||||
|
||||
## Metrics
|
||||
|
||||
* Round-trip duration time to get transaction receipt (from creation timestamp)
|
||||
|
||||
* First-seen duration time (from creation timestamp)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Run `make ufm` to build the binary. No additional dependencies are necessary.
|
||||
|
||||
Copy `example.config.toml` to `config.toml` and edit the file to configure the service.
|
||||
|
||||
Start the service with `ufm config.toml`.
|
||||
|
84
op-ufm/cmd/ufm/main.go
Normal file
84
op-ufm/cmd/ufm/main.go
Normal file
@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/exp/slog"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
oplog "github.com/ethereum-optimism/optimism/op-service/log"
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/config"
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/service"
|
||||
)
|
||||
|
||||
var (
|
||||
GitVersion = ""
|
||||
GitCommit = ""
|
||||
GitDate = ""
|
||||
)
|
||||
|
||||
func main() {
|
||||
oplog.SetGlobalLogHandler(slog.NewJSONHandler(
|
||||
os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
||||
|
||||
log.Info("initializing",
|
||||
"version", GitVersion,
|
||||
"commit", GitCommit,
|
||||
"date", GitDate)
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
log.Crit("must specify a config file on the command line")
|
||||
}
|
||||
cfg := initConfig(os.Args[1])
|
||||
|
||||
ctx := context.Background()
|
||||
svc := service.New(cfg)
|
||||
svc.Start(ctx)
|
||||
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||
recvSig := <-sig
|
||||
log.Info("caught signal, shutting down",
|
||||
"signal", recvSig)
|
||||
|
||||
svc.Shutdown()
|
||||
}
|
||||
|
||||
func initConfig(cfgFile string) *config.Config {
|
||||
cfg, err := config.New(cfgFile)
|
||||
if err != nil {
|
||||
log.Crit("error reading config file",
|
||||
"file", cfgFile,
|
||||
"err", err)
|
||||
}
|
||||
|
||||
// update log level from config
|
||||
logLevel, err := oplog.LevelFromString(cfg.LogLevel)
|
||||
if err != nil {
|
||||
logLevel = log.LevelInfo
|
||||
if cfg.LogLevel != "" {
|
||||
log.Warn("invalid server.log_level",
|
||||
"log_level", cfg.LogLevel)
|
||||
}
|
||||
}
|
||||
oplog.SetGlobalLogHandler(slog.NewJSONHandler(
|
||||
os.Stdout, &slog.HandlerOptions{Level: logLevel}))
|
||||
|
||||
// readable parsed config
|
||||
jsonCfg, _ := json.MarshalIndent(cfg, "", " ")
|
||||
fmt.Printf("%s", string(jsonCfg))
|
||||
|
||||
err = cfg.Validate()
|
||||
if err != nil {
|
||||
log.Crit("invalid config",
|
||||
"err", err)
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
6
op-ufm/entrypoint.sh
Normal file
6
op-ufm/entrypoint.sh
Normal file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Updating CA certificates."
|
||||
update-ca-certificates
|
||||
echo "Running CMD."
|
||||
exec "$@"
|
83
op-ufm/example.config.toml
Normal file
83
op-ufm/example.config.toml
Normal file
@ -0,0 +1,83 @@
|
||||
# Log level.
|
||||
# Possible values: trace | debug | info | warn | error | crit
|
||||
# Default: debug
|
||||
log_level = "debug"
|
||||
|
||||
[signer_service]
|
||||
# URL to the signer service
|
||||
url = "http://localhost:1234"
|
||||
tls_ca_cert = "tls/ca.crt"
|
||||
tls_cert = "tls/tls.crt"
|
||||
tls_key = "tls/tls.key"
|
||||
|
||||
[healthz]
|
||||
# Whether or not to enable healthz endpoint
|
||||
enabled = true
|
||||
# Host for the healthz endpoint to listen on
|
||||
host = "0.0.0.0"
|
||||
# Port for the above.
|
||||
port = "8080"
|
||||
|
||||
[metrics]
|
||||
# Whether or not to enable Prometheus metrics
|
||||
enabled = true
|
||||
# Host for the Prometheus metrics endpoint to listen on.
|
||||
host = "0.0.0.0"
|
||||
# Port for the above.
|
||||
port = "9761"
|
||||
|
||||
[wallets.default]
|
||||
# OP Stack Chain ID
|
||||
# see https://community.optimism.io/docs/useful-tools/networks/
|
||||
chain_id = 420
|
||||
# Signer method to use
|
||||
# Possible values: signer | static
|
||||
signer_method = "static"
|
||||
# Address used to send transactions
|
||||
address = "0x0000000000000000000000000000000000000000"
|
||||
# For static signer method, the private key to use
|
||||
private_key = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
# Transaction value in wei
|
||||
tx_value = 100000000000000
|
||||
|
||||
[providers.p1]
|
||||
# URL to the RPC provider
|
||||
url = "http://localhost:8551"
|
||||
# Read only providers are only used to check for transactions
|
||||
read_only = true
|
||||
# Interval to poll the provider for expected transactions
|
||||
read_interval = "10s"
|
||||
# Interval to submit new transactions to the provider
|
||||
send_interval = "30s"
|
||||
# Interval between send transaction when we get "already known" txpool err
|
||||
send_transaction_retry_interval = "100ms"
|
||||
# Max time to retry
|
||||
send_transaction_retry_timeout = "5s"
|
||||
# Interval between each send transaction to the same network
|
||||
send_transaction_cool_down = "30s"
|
||||
# Interval between receipt retrieval
|
||||
receipt_retrieval_interval = "500ms"
|
||||
# Max time to check for receipt
|
||||
receipt_retrieval_timeout = "2m"
|
||||
|
||||
[providers.p2]
|
||||
# Uncomment to disable this provider
|
||||
# disabled=true
|
||||
# URL to the RPC provider
|
||||
url = "http://localhost:8552"
|
||||
# Read only providers are only used to check for transactions
|
||||
read_only = false
|
||||
# Interval to poll the provider for expected transactions
|
||||
read_interval = "10s"
|
||||
# Interval to submit new transactions to the provider
|
||||
send_interval = "30s"
|
||||
# Interval between send transaction when we get "already known" txpool err
|
||||
send_transaction_retry_interval = "100ms"
|
||||
# Max time to retry
|
||||
send_transaction_retry_timeout = "5s"
|
||||
# Interval between each send transaction to the same network
|
||||
send_transaction_cool_down = "30s"
|
||||
# Interval between receipt retrieval
|
||||
receipt_retrieval_interval = "500ms"
|
||||
# Max time to check for receipt
|
||||
receipt_retrieval_timeout = "2m"
|
101
op-ufm/go.mod
Normal file
101
op-ufm/go.mod
Normal file
@ -0,0 +1,101 @@
|
||||
module github.com/ethereum-optimism/optimism/op-ufm
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.6
|
||||
|
||||
require (
|
||||
cloud.google.com/go/kms v1.12.1
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
github.com/ethereum-optimism/optimism v1.7.7-0.20240529212843-af0999ccc31d
|
||||
github.com/ethereum/go-ethereum v1.13.15
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/rs/cors v1.9.0
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.20.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.1.0 // indirect
|
||||
github.com/DataDog/zstd v1.5.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
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/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
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/consensys/gnark-crypto v0.12.1 // indirect
|
||||
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/deckarep/golang-set/v2 v2.1.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240522134500-19555bdbdc95 // indirect
|
||||
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
|
||||
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-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/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/s2a-go v0.1.4 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.4 // indirect
|
||||
github.com/klauspost/compress v1.17.6 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // 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/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/supranational/blst v0.3.11 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/urfave/cli/v2 v2.27.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/oauth2 v0.16.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/term v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
google.golang.org/api v0.132.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||
google.golang.org/grpc v1.56.3 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
||||
replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101315.1-rc.5
|
461
op-ufm/go.sum
Normal file
461
op-ufm/go.sum
Normal file
@ -0,0 +1,461 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk=
|
||||
cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
|
||||
cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
|
||||
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94=
|
||||
cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
|
||||
cloud.google.com/go/kms v1.12.1 h1:xZmZuwy2cwzsocmKDOPu4BL7umg8QXagQx6fKVmf45U=
|
||||
cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
|
||||
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
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/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
|
||||
github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
|
||||
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd v0.24.0 h1:gL3uHE/IaFj6fcZSu03SvqPMSx7s/dPzfpG/atRwWdo=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
||||
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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
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=
|
||||
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||
github.com/cockroachdb/pebble v0.0.0-20231018212520-f6cde3fc2fa4 h1:PuHFhOUMnD62r80dN+Ik5qco2drekgsUSVdcHsvllec=
|
||||
github.com/cockroachdb/pebble v0.0.0-20231018212520-f6cde3fc2fa4/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E=
|
||||
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
||||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
|
||||
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ=
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
|
||||
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/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=
|
||||
github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
|
||||
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ethereum-optimism/op-geth v1.101315.1-rc.5 h1:yaBvV/GfDuZOecDsGXyzsa/g8+AEBG+Bj1+NFyZRkdw=
|
||||
github.com/ethereum-optimism/op-geth v1.101315.1-rc.5/go.mod h1:8tQ6r0e1NNJbSVHzYKafQqf62gV9BzZR+SKkXRckjLM=
|
||||
github.com/ethereum-optimism/optimism v1.7.7-0.20240529212843-af0999ccc31d h1:bVre/IJ14z9JtVlEHw6q1hIhE6O8o4C8jt69TmRWrAU=
|
||||
github.com/ethereum-optimism/optimism v1.7.7-0.20240529212843-af0999ccc31d/go.mod h1:BgTeAhCkyj+v7PQPoDyvgXnjqAiwr+qcdMIeggigcC4=
|
||||
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240522134500-19555bdbdc95 h1:GjXKQg6u6WkEIcY0dvW2IKhMRY8cVjwdw+rNKhduAo8=
|
||||
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240522134500-19555bdbdc95/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0=
|
||||
github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
|
||||
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
||||
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
|
||||
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
||||
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE=
|
||||
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
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-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=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
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=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
|
||||
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubCI7dY=
|
||||
github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE=
|
||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=
|
||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
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/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.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
|
||||
github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
|
||||
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
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/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=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
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/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=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
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/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
||||
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
|
||||
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
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.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.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
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-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/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-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.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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-20220722155255-886fb9371eb4/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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.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.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc=
|
||||
google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8=
|
||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
|
||||
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/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=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
171
op-ufm/pkg/config/config.go
Normal file
171
op-ufm/pkg/config/config.go
Normal file
@ -0,0 +1,171 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
LogLevel string `toml:"log_level"`
|
||||
|
||||
Signer SignerServiceConfig `toml:"signer_service"`
|
||||
Metrics MetricsConfig `toml:"metrics"`
|
||||
Healthz HealthzConfig `toml:"healthz"`
|
||||
|
||||
Wallets map[string]*WalletConfig `toml:"wallets"`
|
||||
Providers map[string]*ProviderConfig `toml:"providers"`
|
||||
}
|
||||
|
||||
type SignerServiceConfig struct {
|
||||
URL string `toml:"url"`
|
||||
TLSCaCert string `toml:"tls_ca_cert"`
|
||||
TLSCert string `toml:"tls_cert"`
|
||||
TLSKey string `toml:"tls_key"`
|
||||
}
|
||||
|
||||
type MetricsConfig struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
Debug bool `toml:"debug"`
|
||||
Host string `toml:"host"`
|
||||
Port string `toml:"port"`
|
||||
}
|
||||
|
||||
type HealthzConfig struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
Host string `toml:"host"`
|
||||
Port string `toml:"port"`
|
||||
}
|
||||
|
||||
type WalletConfig struct {
|
||||
ChainID big.Int `toml:"chain_id"`
|
||||
|
||||
// signer | static
|
||||
SignerMethod string `toml:"signer_method"`
|
||||
Address string `toml:"address"`
|
||||
// private key is used for static signing
|
||||
PrivateKey string `toml:"private_key"`
|
||||
|
||||
// transaction parameters
|
||||
TxValue big.Int `toml:"tx_value"`
|
||||
}
|
||||
|
||||
type ProviderConfig struct {
|
||||
Network string `toml:"network"`
|
||||
URL string `toml:"url"`
|
||||
|
||||
ReadOnly bool `toml:"read_only"`
|
||||
ReadInterval TOMLDuration `toml:"read_interval"`
|
||||
|
||||
SendInterval TOMLDuration `toml:"send_interval"`
|
||||
SendTransactionRetryInterval TOMLDuration `toml:"send_transaction_retry_interval"`
|
||||
SendTransactionRetryTimeout TOMLDuration `toml:"send_transaction_retry_timeout"`
|
||||
SendTransactionCoolDown TOMLDuration `toml:"send_transaction_cool_down"`
|
||||
ReceiptRetrievalInterval TOMLDuration `toml:"receipt_retrieval_interval"`
|
||||
ReceiptRetrievalTimeout TOMLDuration `toml:"receipt_retrieval_timeout"`
|
||||
|
||||
Wallet string `toml:"wallet"`
|
||||
}
|
||||
|
||||
func New(file string) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
if _, err := toml.DecodeFile(file, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (c *Config) Validate() error {
|
||||
if c.Metrics.Enabled {
|
||||
if c.Metrics.Host == "" || c.Metrics.Port == "" {
|
||||
return errors.New("metrics is enabled but host or port are missing")
|
||||
}
|
||||
}
|
||||
if c.Healthz.Enabled {
|
||||
if c.Healthz.Host == "" || c.Healthz.Port == "" {
|
||||
return errors.New("healthz is enabled but host or port are missing")
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Wallets) == 0 {
|
||||
return errors.New("at least one wallet must be set")
|
||||
}
|
||||
|
||||
if len(c.Providers) == 0 {
|
||||
return errors.New("at least one provider must be set")
|
||||
}
|
||||
|
||||
for name, wallet := range c.Wallets {
|
||||
if wallet.ChainID.BitLen() == 0 {
|
||||
return errors.Errorf("wallet [%s] chain_id is missing", name)
|
||||
}
|
||||
if wallet.SignerMethod != "signer" && wallet.SignerMethod != "static" {
|
||||
return errors.Errorf("wallet [%s] signer_method is invalid", name)
|
||||
}
|
||||
if wallet.SignerMethod == "signer" {
|
||||
if c.Signer.URL == "" {
|
||||
return errors.New("signer url is missing")
|
||||
}
|
||||
if c.Signer.TLSCaCert == "" {
|
||||
return errors.New("signer tls_ca_cert is missing")
|
||||
}
|
||||
if c.Signer.TLSCert == "" {
|
||||
return errors.New("signer tls_cert is missing")
|
||||
}
|
||||
if c.Signer.TLSKey == "" {
|
||||
return errors.New("signer tls_key is missing")
|
||||
}
|
||||
}
|
||||
if wallet.SignerMethod == "static" {
|
||||
if wallet.PrivateKey == "" {
|
||||
return errors.Errorf("wallet [%s] private_key is missing", name)
|
||||
}
|
||||
}
|
||||
if wallet.Address == "" {
|
||||
return errors.Errorf("wallet [%s] address is missing", name)
|
||||
}
|
||||
if wallet.TxValue.BitLen() == 0 {
|
||||
return errors.Errorf("wallet [%s] tx_value is missing", name)
|
||||
}
|
||||
}
|
||||
|
||||
for name, provider := range c.Providers {
|
||||
if provider.URL == "" {
|
||||
return errors.Errorf("provider [%s] url is missing", name)
|
||||
}
|
||||
if provider.ReadInterval == 0 {
|
||||
return errors.Errorf("provider [%s] read_interval is missing", name)
|
||||
}
|
||||
if provider.SendInterval == 0 {
|
||||
return errors.Errorf("provider [%s] send_interval is missing", name)
|
||||
}
|
||||
if provider.SendTransactionRetryInterval == 0 {
|
||||
return errors.Errorf("provider [%s] send_transaction_retry_interval is missing", name)
|
||||
}
|
||||
if provider.SendTransactionRetryTimeout == 0 {
|
||||
return errors.Errorf("provider [%s] send_transaction_retry_timeout is missing", name)
|
||||
}
|
||||
if provider.SendTransactionCoolDown == 0 {
|
||||
return errors.Errorf("provider [%s] send_transaction_cool_down is missing", name)
|
||||
}
|
||||
if provider.ReceiptRetrievalInterval == 0 {
|
||||
return errors.Errorf("provider [%s] receipt_retrieval_interval is missing", name)
|
||||
}
|
||||
if provider.ReceiptRetrievalTimeout == 0 {
|
||||
return errors.Errorf("provider [%s] receipt_retrieval_timeout is missing", name)
|
||||
}
|
||||
if provider.Wallet == "" {
|
||||
return errors.Errorf("provider [%s] wallet is missing", name)
|
||||
}
|
||||
if _, ok := c.Wallets[provider.Wallet]; !ok {
|
||||
return errors.Errorf("provider [%s] has an invalid wallet [%s]", name, provider.Wallet)
|
||||
}
|
||||
}
|
||||
|
||||
if c.LogLevel == "" {
|
||||
c.LogLevel = "debug"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
15
op-ufm/pkg/config/toml_duration.go
Normal file
15
op-ufm/pkg/config/toml_duration.go
Normal file
@ -0,0 +1,15 @@
|
||||
package config
|
||||
|
||||
import "time"
|
||||
|
||||
type TOMLDuration time.Duration
|
||||
|
||||
func (t *TOMLDuration) UnmarshalText(b []byte) error {
|
||||
d, err := time.ParseDuration(string(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = TOMLDuration(d)
|
||||
return nil
|
||||
}
|
123
op-ufm/pkg/metrics/clients/eth.go
Normal file
123
op-ufm/pkg/metrics/clients/eth.go
Normal file
@ -0,0 +1,123 @@
|
||||
package clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
type InstrumentedEthClient struct {
|
||||
c *ethclient.Client
|
||||
providerName string
|
||||
}
|
||||
|
||||
func Dial(providerName string, url string) (*InstrumentedEthClient, error) {
|
||||
start := time.Now()
|
||||
c, err := ethclient.Dial(url)
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(providerName, "ethclient.Dial", err)
|
||||
return nil, err
|
||||
}
|
||||
metrics.RecordRPCLatency(providerName, "ethclient", "Dial", time.Since(start))
|
||||
return &InstrumentedEthClient{c: c, providerName: providerName}, nil
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, bool, error) {
|
||||
start := time.Now()
|
||||
tx, isPending, err := i.c.TransactionByHash(ctx, hash)
|
||||
if err != nil {
|
||||
if !i.ignorableErrors(err) {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.TransactionByHash", err)
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "TransactionByHash", time.Since(start))
|
||||
return tx, isPending, err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) PendingNonceAt(ctx context.Context, address string) (uint64, error) {
|
||||
start := time.Now()
|
||||
nonce, err := i.c.PendingNonceAt(ctx, common.HexToAddress(address))
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.PendingNonceAt", err)
|
||||
return 0, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "PendingNonceAt", time.Since(start))
|
||||
return nonce, err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||
start := time.Now()
|
||||
receipt, err := i.c.TransactionReceipt(ctx, txHash)
|
||||
if err != nil {
|
||||
if !i.ignorableErrors(err) {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.TransactionReceipt", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "TransactionReceipt", time.Since(start))
|
||||
return receipt, err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
|
||||
start := time.Now()
|
||||
err := i.c.SendTransaction(ctx, tx)
|
||||
if err != nil {
|
||||
if !i.ignorableErrors(err) {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.SendTransaction", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "SendTransaction", time.Since(start))
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
|
||||
start := time.Now()
|
||||
gas, err := i.c.EstimateGas(ctx, msg)
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.EstimateGas", err)
|
||||
return 0, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "EstimateGas", time.Since(start))
|
||||
return gas, err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
|
||||
start := time.Now()
|
||||
gasTipCap, err := i.c.SuggestGasTipCap(ctx)
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.SuggestGasTipCap", err)
|
||||
return nil, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "SuggestGasTipCap", time.Since(start))
|
||||
return gasTipCap, err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
|
||||
start := time.Now()
|
||||
header, err := i.c.HeaderByNumber(ctx, number)
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(i.providerName, "ethclient.HeaderByNumber", err)
|
||||
return nil, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "ethclient", "HeaderByNumber", time.Since(start))
|
||||
return header, err
|
||||
}
|
||||
|
||||
func (i *InstrumentedEthClient) ignorableErrors(err error) bool {
|
||||
msg := err.Error()
|
||||
// we dont use errors.Is because eth client actually uses errors.New,
|
||||
// therefore creating an incomparable instance :(
|
||||
return msg == ethereum.NotFound.Error() ||
|
||||
msg == txpool.ErrAlreadyKnown.Error() ||
|
||||
msg == core.ErrNonceTooLow.Error()
|
||||
}
|
42
op-ufm/pkg/metrics/clients/signer.go
Normal file
42
op-ufm/pkg/metrics/clients/signer.go
Normal file
@ -0,0 +1,42 @@
|
||||
package clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
signer "github.com/ethereum-optimism/optimism/op-service/signer"
|
||||
optls "github.com/ethereum-optimism/optimism/op-service/tls"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
type InstrumentedSignerClient struct {
|
||||
c *signer.SignerClient
|
||||
providerName string
|
||||
}
|
||||
|
||||
func NewSignerClient(providerName string, logger log.Logger, endpoint string, tlsConfig optls.CLIConfig) (*InstrumentedSignerClient, error) {
|
||||
start := time.Now()
|
||||
c, err := signer.NewSignerClient(logger, endpoint, tlsConfig)
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(providerName, "signer.NewSignerClient", err)
|
||||
return nil, err
|
||||
}
|
||||
metrics.RecordRPCLatency(providerName, "signer", "NewSignerClient", time.Since(start))
|
||||
return &InstrumentedSignerClient{c: c, providerName: providerName}, nil
|
||||
}
|
||||
|
||||
func (i *InstrumentedSignerClient) SignTransaction(ctx context.Context, chainId *big.Int, from *common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||
start := time.Now()
|
||||
tx, err := i.c.SignTransaction(ctx, chainId, *from, tx)
|
||||
if err != nil {
|
||||
metrics.RecordErrorDetails(i.providerName, "signer.SignTransaction", err)
|
||||
return nil, err
|
||||
}
|
||||
metrics.RecordRPCLatency(i.providerName, "signer", "SignTransaction", time.Since(start))
|
||||
return tx, err
|
||||
}
|
166
op-ufm/pkg/metrics/metrics.go
Normal file
166
op-ufm/pkg/metrics/metrics.go
Normal file
@ -0,0 +1,166 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
const (
|
||||
MetricsNamespace = "ufm"
|
||||
)
|
||||
|
||||
var (
|
||||
Debug bool
|
||||
|
||||
errorsTotal = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "errors_total",
|
||||
Help: "Count of errors",
|
||||
}, []string{
|
||||
"provider",
|
||||
"error",
|
||||
})
|
||||
|
||||
rpcLatency = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "rpc_latency",
|
||||
Help: "RPC latency per provider, client and method (ms)",
|
||||
}, []string{
|
||||
"provider",
|
||||
"client",
|
||||
"method",
|
||||
})
|
||||
|
||||
roundTripLatency = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "roundtrip_latency",
|
||||
Help: "Round trip latency per provider (ms)",
|
||||
}, []string{
|
||||
"provider",
|
||||
})
|
||||
|
||||
gasUsed = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "gas_used",
|
||||
Help: "Gas used per provider",
|
||||
}, []string{
|
||||
"provider",
|
||||
})
|
||||
|
||||
firstSeenLatency = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "first_seen_latency",
|
||||
Help: "First seen latency latency per provider (ms)",
|
||||
}, []string{
|
||||
"provider_source",
|
||||
"provider_seen",
|
||||
})
|
||||
|
||||
providerToProviderLatency = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "provider_to_provider_latency",
|
||||
Help: "Provider to provider latency (ms)",
|
||||
}, []string{
|
||||
"provider_source",
|
||||
"provider_seen",
|
||||
})
|
||||
|
||||
networkTransactionsInFlight = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: MetricsNamespace,
|
||||
Name: "transactions_inflight",
|
||||
Help: "Transactions in flight, per network",
|
||||
}, []string{
|
||||
"network",
|
||||
})
|
||||
)
|
||||
|
||||
var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z ]+`)
|
||||
|
||||
func RecordError(provider string, errorLabel string) {
|
||||
if Debug {
|
||||
log.Debug("metric inc",
|
||||
"m", "errors_total",
|
||||
"provider", provider,
|
||||
"error", errorLabel)
|
||||
}
|
||||
errorsTotal.WithLabelValues(provider, errorLabel).Inc()
|
||||
}
|
||||
|
||||
// RecordErrorDetails concats the error message to the label removing non-alpha chars
|
||||
func RecordErrorDetails(provider string, label string, err error) {
|
||||
errClean := nonAlphanumericRegex.ReplaceAllString(err.Error(), "")
|
||||
errClean = strings.ReplaceAll(errClean, " ", "_")
|
||||
errClean = strings.ReplaceAll(errClean, "__", "_")
|
||||
label = fmt.Sprintf("%s.%s", label, errClean)
|
||||
RecordError(provider, label)
|
||||
}
|
||||
|
||||
func RecordRPCLatency(provider string, client string, method string, latency time.Duration) {
|
||||
if Debug {
|
||||
log.Debug("metric set",
|
||||
"m", "rpc_latency",
|
||||
"provider", provider,
|
||||
"client", client,
|
||||
"method", method,
|
||||
"latency", latency)
|
||||
}
|
||||
rpcLatency.WithLabelValues(provider, client, method).Set(float64(latency.Milliseconds()))
|
||||
}
|
||||
|
||||
func RecordRoundTripLatency(provider string, latency time.Duration) {
|
||||
if Debug {
|
||||
log.Debug("metric set",
|
||||
"m", "roundtrip_latency",
|
||||
"provider", provider,
|
||||
"latency", latency)
|
||||
}
|
||||
roundTripLatency.WithLabelValues(provider).Set(float64(latency.Milliseconds()))
|
||||
}
|
||||
|
||||
func RecordGasUsed(provider string, val uint64) {
|
||||
if Debug {
|
||||
log.Debug("metric add",
|
||||
"m", "gas_used",
|
||||
"provider", provider,
|
||||
"val", val)
|
||||
}
|
||||
gasUsed.WithLabelValues(provider).Set(float64(val))
|
||||
}
|
||||
|
||||
func RecordFirstSeenLatency(providerSource string, providerSeen string, latency time.Duration) {
|
||||
if Debug {
|
||||
log.Debug("metric set",
|
||||
"m", "first_seen_latency",
|
||||
"provider_source", providerSource,
|
||||
"provider_seen", providerSeen,
|
||||
"latency", latency)
|
||||
}
|
||||
firstSeenLatency.WithLabelValues(providerSource, providerSeen).Set(float64(latency.Milliseconds()))
|
||||
}
|
||||
|
||||
func RecordProviderToProviderLatency(providerSource string, providerSeen string, latency time.Duration) {
|
||||
if Debug {
|
||||
log.Debug("metric set",
|
||||
"m", "provider_to_provider_latency",
|
||||
"provider_source", providerSource,
|
||||
"provider_seen", providerSeen,
|
||||
"latency", latency)
|
||||
}
|
||||
providerToProviderLatency.WithLabelValues(providerSource, providerSeen).Set(float64(latency.Milliseconds()))
|
||||
}
|
||||
|
||||
func RecordTransactionsInFlight(network string, count int) {
|
||||
if Debug {
|
||||
log.Debug("metric set",
|
||||
"m", "transactions_inflight",
|
||||
"network", network,
|
||||
"count", count)
|
||||
}
|
||||
networkTransactionsInFlight.WithLabelValues(network).Set(float64(count))
|
||||
}
|
104
op-ufm/pkg/provider/heartbeat.go
Normal file
104
op-ufm/pkg/provider/heartbeat.go
Normal file
@ -0,0 +1,104 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics/clients"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Heartbeat polls for expected in-flight transactions
|
||||
func (p *Provider) Heartbeat(ctx context.Context) {
|
||||
log.Debug("heartbeat",
|
||||
"provider", p.name,
|
||||
"count", len(p.txPool.Transactions))
|
||||
|
||||
metrics.RecordTransactionsInFlight(p.config.Network, len(p.txPool.Transactions))
|
||||
|
||||
// let's exclude transactions already seen by this provider, or originated by it
|
||||
expectedTransactions := make([]*TransactionState, 0, len(p.txPool.Transactions))
|
||||
alreadySeen := 0
|
||||
for _, st := range p.txPool.Transactions {
|
||||
if st.ProviderSource == p.name {
|
||||
continue
|
||||
}
|
||||
if _, exist := st.SeenBy[p.name]; exist {
|
||||
alreadySeen++
|
||||
continue
|
||||
}
|
||||
expectedTransactions = append(expectedTransactions, st)
|
||||
}
|
||||
|
||||
if len(expectedTransactions) == 0 {
|
||||
log.Debug("no expected txs",
|
||||
"count", len(p.txPool.Transactions),
|
||||
"provider", p.name,
|
||||
"alreadySeen", alreadySeen)
|
||||
return
|
||||
}
|
||||
|
||||
client, err := clients.Dial(p.name, p.config.URL)
|
||||
if err != nil {
|
||||
log.Error("cant dial to provider",
|
||||
"provider", p.name,
|
||||
"url", p.config.URL,
|
||||
"err", err)
|
||||
}
|
||||
|
||||
log.Debug("checking in-flight tx",
|
||||
"count", len(p.txPool.Transactions),
|
||||
"provider", p.name,
|
||||
"alreadySeen", alreadySeen)
|
||||
for _, st := range expectedTransactions {
|
||||
hash := st.Hash.Hex()
|
||||
|
||||
_, isPending, err := client.TransactionByHash(ctx, st.Hash)
|
||||
if err != nil && !errors.Is(err, ethereum.NotFound) {
|
||||
log.Error("cant check transaction",
|
||||
"provider", p.name,
|
||||
"hash", hash,
|
||||
"url", p.config.URL,
|
||||
"err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug("got transaction",
|
||||
"provider", p.name,
|
||||
"hash", hash,
|
||||
"isPending", isPending)
|
||||
|
||||
// mark transaction as seen by this provider
|
||||
st.M.Lock()
|
||||
latency := time.Since(st.SentAt)
|
||||
if st.FirstSeen.IsZero() {
|
||||
st.FirstSeen = time.Now()
|
||||
metrics.RecordFirstSeenLatency(st.ProviderSource, p.name, latency)
|
||||
log.Info("transaction first seen",
|
||||
"hash", hash,
|
||||
"firstSeenLatency", latency,
|
||||
"providerSource", st.ProviderSource,
|
||||
"providerSeen", p.name)
|
||||
}
|
||||
if _, exist := st.SeenBy[p.name]; !exist {
|
||||
st.SeenBy[p.name] = time.Now()
|
||||
metrics.RecordProviderToProviderLatency(st.ProviderSource, p.name, latency)
|
||||
}
|
||||
st.M.Unlock()
|
||||
|
||||
// check if transaction have been seen by all providers
|
||||
p.txPool.M.Lock()
|
||||
if len(st.SeenBy) == p.txPool.Expected {
|
||||
log.Debug("transaction seen by all",
|
||||
"hash", hash,
|
||||
"expected", p.txPool.Expected,
|
||||
"seenBy", len(st.SeenBy))
|
||||
delete(p.txPool.Transactions, st.Hash.Hex())
|
||||
}
|
||||
p.txPool.M.Unlock()
|
||||
}
|
||||
}
|
72
op-ufm/pkg/provider/provider.go
Normal file
72
op-ufm/pkg/provider/provider.go
Normal file
@ -0,0 +1,72 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/config"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
name string
|
||||
config *config.ProviderConfig
|
||||
signerConfig *config.SignerServiceConfig
|
||||
walletConfig *config.WalletConfig
|
||||
txPool *NetworkTransactionPool
|
||||
|
||||
cancelFunc context.CancelFunc
|
||||
}
|
||||
|
||||
func New(name string, cfg *config.ProviderConfig,
|
||||
signerConfig *config.SignerServiceConfig,
|
||||
walletConfig *config.WalletConfig,
|
||||
txPool *NetworkTransactionPool) *Provider {
|
||||
p := &Provider{
|
||||
name: name,
|
||||
config: cfg,
|
||||
signerConfig: signerConfig,
|
||||
walletConfig: walletConfig,
|
||||
txPool: txPool,
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Provider) Start(ctx context.Context) {
|
||||
providerCtx, cancelFunc := context.WithCancel(ctx)
|
||||
p.cancelFunc = cancelFunc
|
||||
|
||||
schedule(providerCtx, time.Duration(p.config.ReadInterval), p.Heartbeat)
|
||||
if !p.config.ReadOnly {
|
||||
schedule(providerCtx, time.Duration(p.config.SendInterval), p.RoundTrip)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) Shutdown() {
|
||||
if p.cancelFunc != nil {
|
||||
p.cancelFunc()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) Name() string {
|
||||
return p.name
|
||||
}
|
||||
|
||||
func (p *Provider) URL() string {
|
||||
return p.config.URL
|
||||
}
|
||||
|
||||
func schedule(ctx context.Context, interval time.Duration, handler func(ctx context.Context)) {
|
||||
go func() {
|
||||
for {
|
||||
timer := time.NewTimer(interval)
|
||||
handler(ctx)
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
case <-ctx.Done():
|
||||
timer.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
312
op-ufm/pkg/provider/roundtrip.go
Normal file
312
op-ufm/pkg/provider/roundtrip.go
Normal file
@ -0,0 +1,312 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
|
||||
iclients "github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics/clients"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-service/tls"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// RoundTrip send a new transaction to measure round trip latency
|
||||
func (p *Provider) RoundTrip(ctx context.Context) {
|
||||
log.Debug("RoundTrip",
|
||||
"provider", p.name)
|
||||
|
||||
client, err := iclients.Dial(p.name, p.config.URL)
|
||||
if err != nil {
|
||||
log.Error("cant dial to provider",
|
||||
"provider", p.name,
|
||||
"url", p.config.URL,
|
||||
"err", err)
|
||||
return
|
||||
}
|
||||
|
||||
p.txPool.ExclusiveSend.Lock()
|
||||
defer p.txPool.ExclusiveSend.Unlock()
|
||||
|
||||
// lint:ignore SA4006 txHash is set and used within tx sending loop
|
||||
txHash := common.Hash{}
|
||||
attempt := 0
|
||||
nonce := uint64(0)
|
||||
|
||||
// used for timeout
|
||||
firstAttemptAt := time.Now()
|
||||
// used for actual round trip time (disregard retry time)
|
||||
var roundTripStartedAt time.Time
|
||||
for {
|
||||
|
||||
// sleep until we get a clear to send
|
||||
for {
|
||||
coolDown := time.Duration(p.config.SendTransactionCoolDown) - time.Since(p.txPool.LastSend)
|
||||
if coolDown > 0 {
|
||||
time.Sleep(coolDown)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
from, tx, err := p.createTx(ctx, client, nonce)
|
||||
if err != nil {
|
||||
log.Error("cant create tx",
|
||||
"provider", p.name,
|
||||
"nonce", nonce,
|
||||
"err", err)
|
||||
return
|
||||
}
|
||||
nonce = tx.Nonce()
|
||||
|
||||
signedTx, err := p.sign(ctx, from, tx)
|
||||
if err != nil {
|
||||
log.Error("cant sign tx",
|
||||
"provider", p.name,
|
||||
"tx", tx,
|
||||
"err", err)
|
||||
return
|
||||
}
|
||||
txHash = signedTx.Hash()
|
||||
|
||||
roundTripStartedAt = time.Now()
|
||||
err = client.SendTransaction(ctx, signedTx)
|
||||
if err != nil {
|
||||
if err.Error() == txpool.ErrAlreadyKnown.Error() ||
|
||||
err.Error() == txpool.ErrReplaceUnderpriced.Error() ||
|
||||
err.Error() == core.ErrNonceTooLow.Error() {
|
||||
|
||||
log.Warn("cant send transaction (retryable)",
|
||||
"provider", p.name,
|
||||
"err", err,
|
||||
"nonce", nonce)
|
||||
|
||||
if time.Since(firstAttemptAt) >= time.Duration(p.config.SendTransactionRetryTimeout) {
|
||||
log.Error("send transaction timed out (known already)",
|
||||
"provider", p.name,
|
||||
"hash", txHash.Hex(),
|
||||
"nonce", nonce,
|
||||
"elapsed", time.Since(firstAttemptAt),
|
||||
"attempt", attempt)
|
||||
metrics.RecordErrorDetails(p.name, "send.timeout", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Warn("tx already known, incrementing nonce and trying again",
|
||||
"provider", p.name,
|
||||
"nonce", nonce)
|
||||
time.Sleep(time.Duration(p.config.SendTransactionRetryInterval))
|
||||
|
||||
nonce++
|
||||
attempt++
|
||||
if attempt%10 == 0 {
|
||||
log.Debug("retrying send transaction...",
|
||||
"provider", p.name,
|
||||
"attempt", attempt,
|
||||
"nonce", nonce,
|
||||
"elapsed", time.Since(firstAttemptAt))
|
||||
}
|
||||
} else {
|
||||
log.Error("cant send transaction",
|
||||
"provider", p.name,
|
||||
"nonce", nonce,
|
||||
"err", err)
|
||||
metrics.RecordErrorDetails(p.name, "ethclient.SendTransaction", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("transaction sent",
|
||||
"provider", p.name,
|
||||
"hash", txHash.Hex(),
|
||||
"nonce", nonce)
|
||||
|
||||
// add to pool
|
||||
sentAt := time.Now()
|
||||
p.txPool.M.Lock()
|
||||
p.txPool.Transactions[txHash.Hex()] = &TransactionState{
|
||||
Hash: txHash,
|
||||
ProviderSource: p.name,
|
||||
SentAt: sentAt,
|
||||
SeenBy: make(map[string]time.Time),
|
||||
}
|
||||
p.txPool.LastSend = sentAt
|
||||
p.txPool.M.Unlock()
|
||||
|
||||
var receipt *types.Receipt
|
||||
attempt = 0
|
||||
for receipt == nil {
|
||||
if time.Since(sentAt) >= time.Duration(p.config.ReceiptRetrievalTimeout) {
|
||||
log.Error("receipt retrieval timed out",
|
||||
"provider", p.name,
|
||||
"hash", txHash,
|
||||
"nonce", nonce,
|
||||
"elapsed", time.Since(sentAt))
|
||||
metrics.RecordErrorDetails(p.name, "receipt.timeout", err)
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration(p.config.ReceiptRetrievalInterval))
|
||||
if attempt%10 == 0 {
|
||||
log.Debug("checking for receipt...",
|
||||
"provider", p.name,
|
||||
"hash", txHash,
|
||||
"nonce", nonce,
|
||||
"attempt", attempt,
|
||||
"elapsed", time.Since(sentAt))
|
||||
}
|
||||
receipt, err = client.TransactionReceipt(ctx, txHash)
|
||||
if err != nil && !errors.Is(err, ethereum.NotFound) {
|
||||
log.Error("cant get receipt for transaction",
|
||||
"provider", p.name,
|
||||
"hash", txHash.Hex(),
|
||||
"nonce", nonce,
|
||||
"err", err)
|
||||
return
|
||||
}
|
||||
attempt++
|
||||
}
|
||||
|
||||
roundTripLatency := time.Since(roundTripStartedAt)
|
||||
|
||||
metrics.RecordRoundTripLatency(p.name, roundTripLatency)
|
||||
metrics.RecordGasUsed(p.name, receipt.GasUsed)
|
||||
|
||||
log.Info("got transaction receipt",
|
||||
"hash", txHash.Hex(),
|
||||
"nonce", nonce,
|
||||
"roundTripLatency", roundTripLatency,
|
||||
"provider", p.name,
|
||||
"blockNumber", receipt.BlockNumber,
|
||||
"blockHash", receipt.BlockHash,
|
||||
"gasUsed", receipt.GasUsed)
|
||||
}
|
||||
|
||||
func (p *Provider) createTx(ctx context.Context, client *iclients.InstrumentedEthClient, nonce uint64) (*common.Address, *types.Transaction, error) {
|
||||
var err error
|
||||
if nonce == 0 {
|
||||
nonce, err = client.PendingNonceAt(ctx, p.walletConfig.Address)
|
||||
if err != nil {
|
||||
log.Error("cant get nonce",
|
||||
"provider", p.name,
|
||||
"nonce", nonce,
|
||||
"err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
gasTipCap, err := client.SuggestGasTipCap(ctx)
|
||||
if err != nil {
|
||||
log.Error("cant get gas tip cap",
|
||||
"provider", p.name,
|
||||
"err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// adjust gas tip cap by 110%
|
||||
const GasTipCapAdjustmentMultiplier = 110
|
||||
const GasTipCapAdjustmentDivisor = 100
|
||||
gasTipCap = new(big.Int).Mul(gasTipCap, big.NewInt(GasTipCapAdjustmentMultiplier))
|
||||
gasTipCap = new(big.Int).Div(gasTipCap, big.NewInt(GasTipCapAdjustmentDivisor))
|
||||
|
||||
head, err := client.HeaderByNumber(ctx, nil)
|
||||
if err != nil {
|
||||
log.Error("cant get base fee from head",
|
||||
"provider", p.name,
|
||||
"err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
baseFee := head.BaseFee
|
||||
|
||||
gasFeeCap := new(big.Int).Add(
|
||||
gasTipCap,
|
||||
new(big.Int).Mul(baseFee, big.NewInt(2)))
|
||||
|
||||
addr := common.HexToAddress(p.walletConfig.Address)
|
||||
var data []byte
|
||||
dynamicTx := &types.DynamicFeeTx{
|
||||
ChainID: &p.walletConfig.ChainID,
|
||||
Nonce: nonce,
|
||||
GasFeeCap: gasFeeCap,
|
||||
GasTipCap: gasTipCap,
|
||||
To: &addr,
|
||||
Value: &p.walletConfig.TxValue,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
gas, err := client.EstimateGas(ctx, ethereum.CallMsg{
|
||||
From: addr,
|
||||
To: &addr,
|
||||
GasFeeCap: gasFeeCap,
|
||||
GasTipCap: gasTipCap,
|
||||
Data: dynamicTx.Data,
|
||||
Value: dynamicTx.Value,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("cant estimate gas",
|
||||
"provider", p.name,
|
||||
"err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
dynamicTx.Gas = gas
|
||||
tx := types.NewTx(dynamicTx)
|
||||
|
||||
log.Info("tx created",
|
||||
"provider", p.name,
|
||||
"from", addr,
|
||||
"to", dynamicTx.To,
|
||||
"nonce", dynamicTx.Nonce,
|
||||
"value", dynamicTx.Value,
|
||||
"gas", dynamicTx.Gas,
|
||||
"gasTipCap", dynamicTx.GasTipCap,
|
||||
"gasFeeCap", dynamicTx.GasFeeCap,
|
||||
)
|
||||
|
||||
return &addr, tx, nil
|
||||
}
|
||||
|
||||
func (p *Provider) sign(ctx context.Context, from *common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||
if p.walletConfig.SignerMethod == "static" {
|
||||
log.Debug("using static signer")
|
||||
privateKey, err := crypto.HexToECDSA(p.walletConfig.PrivateKey)
|
||||
if err != nil {
|
||||
log.Error("failed to parse private key", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
return types.SignTx(tx, types.LatestSignerForChainID(&p.walletConfig.ChainID), privateKey)
|
||||
} else if p.walletConfig.SignerMethod == "signer" {
|
||||
tlsConfig := tls.CLIConfig{
|
||||
TLSCaCert: p.signerConfig.TLSCaCert,
|
||||
TLSCert: p.signerConfig.TLSCert,
|
||||
TLSKey: p.signerConfig.TLSKey,
|
||||
}
|
||||
client, err := iclients.NewSignerClient(p.name, log.Root(), p.signerConfig.URL, tlsConfig)
|
||||
if err != nil || client == nil {
|
||||
log.Error("failed to create signer client", "err", err)
|
||||
}
|
||||
|
||||
if client == nil {
|
||||
return nil, errors.New("could not initialize signer client")
|
||||
}
|
||||
|
||||
signedTx, err := client.SignTransaction(ctx, &p.walletConfig.ChainID, from, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signedTx, nil
|
||||
} else {
|
||||
return nil, errors.New("invalid signer method")
|
||||
}
|
||||
}
|
40
op-ufm/pkg/provider/tx_pool.go
Normal file
40
op-ufm/pkg/provider/tx_pool.go
Normal file
@ -0,0 +1,40 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// TransactionPool is used locally to share transactions between providers under the same pool
|
||||
type TransactionPool map[string]*NetworkTransactionPool
|
||||
|
||||
// NetworkTransactionPool is used locally to share transactions between providers under the same network
|
||||
type NetworkTransactionPool struct {
|
||||
M sync.Mutex
|
||||
Transactions map[string]*TransactionState
|
||||
Expected int
|
||||
|
||||
// Last time a transaction was sent
|
||||
LastSend time.Time
|
||||
// Prevents concurrent transaction send
|
||||
ExclusiveSend sync.Mutex
|
||||
}
|
||||
|
||||
type TransactionState struct {
|
||||
// Transaction hash
|
||||
Hash common.Hash
|
||||
|
||||
// Mutex
|
||||
M sync.Mutex
|
||||
|
||||
SentAt time.Time
|
||||
ProviderSource string
|
||||
|
||||
FirstSeen time.Time
|
||||
|
||||
// Map of providers that have seen this transaction, and when
|
||||
// Once all providers have seen the transaction it is removed from the pool
|
||||
SeenBy map[string]time.Time
|
||||
}
|
42
op-ufm/pkg/service/healthz_server.go
Normal file
42
op-ufm/pkg/service/healthz_server.go
Normal file
@ -0,0 +1,42 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/cors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
type HealthzServer struct {
|
||||
ctx context.Context
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func (h *HealthzServer) Start(ctx context.Context, addr string) error {
|
||||
hdlr := mux.NewRouter()
|
||||
hdlr.HandleFunc("/healthz", h.Handle).Methods("GET")
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
})
|
||||
server := &http.Server{
|
||||
Handler: c.Handler(hdlr),
|
||||
Addr: addr,
|
||||
}
|
||||
h.server = server
|
||||
h.ctx = ctx
|
||||
return h.server.ListenAndServe()
|
||||
}
|
||||
|
||||
func (h *HealthzServer) Shutdown() error {
|
||||
return h.server.Shutdown(h.ctx)
|
||||
}
|
||||
|
||||
func (h *HealthzServer) Handle(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := w.Write([]byte("OK"))
|
||||
if err != nil {
|
||||
log.Error("error handling HealthzServer response")
|
||||
}
|
||||
}
|
27
op-ufm/pkg/service/metrics_server.go
Normal file
27
op-ufm/pkg/service/metrics_server.go
Normal file
@ -0,0 +1,27 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
type MetricsServer struct {
|
||||
ctx context.Context
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func (m *MetricsServer) Start(ctx context.Context, addr string) error {
|
||||
server := &http.Server{
|
||||
Handler: promhttp.Handler(),
|
||||
Addr: addr,
|
||||
}
|
||||
m.server = server
|
||||
m.ctx = ctx
|
||||
return m.server.ListenAndServe()
|
||||
}
|
||||
|
||||
func (m *MetricsServer) Shutdown() error {
|
||||
return m.server.Shutdown(m.ctx)
|
||||
}
|
111
op-ufm/pkg/service/service.go
Normal file
111
op-ufm/pkg/service/service.go
Normal file
@ -0,0 +1,111 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/config"
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
|
||||
"github.com/ethereum-optimism/optimism/op-ufm/pkg/provider"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
Config *config.Config
|
||||
Healthz *HealthzServer
|
||||
Metrics *MetricsServer
|
||||
Providers map[string]*provider.Provider
|
||||
}
|
||||
|
||||
func New(cfg *config.Config) *Service {
|
||||
s := &Service{
|
||||
Config: cfg,
|
||||
Healthz: &HealthzServer{},
|
||||
Metrics: &MetricsServer{},
|
||||
Providers: make(map[string]*provider.Provider, len(cfg.Providers)),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Service) Start(ctx context.Context) {
|
||||
log.Info("service starting")
|
||||
if s.Config.Healthz.Enabled {
|
||||
addr := net.JoinHostPort(s.Config.Healthz.Host, s.Config.Healthz.Port)
|
||||
log.Info("starting healthz server",
|
||||
"addr", addr)
|
||||
go func() {
|
||||
if err := s.Healthz.Start(ctx, addr); err != nil {
|
||||
log.Error("error starting healthz server",
|
||||
"err", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
metrics.Debug = s.Config.Metrics.Debug
|
||||
if s.Config.Metrics.Enabled {
|
||||
addr := net.JoinHostPort(s.Config.Metrics.Host, s.Config.Metrics.Port)
|
||||
log.Info("starting metrics server",
|
||||
"addr", addr)
|
||||
go func() {
|
||||
if err := s.Metrics.Start(ctx, addr); err != nil {
|
||||
log.Error("error starting metrics server",
|
||||
"err", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// map networks to its providers
|
||||
networks := make(map[string][]string)
|
||||
for name, providerConfig := range s.Config.Providers {
|
||||
networks[providerConfig.Network] = append(networks[providerConfig.Network], name)
|
||||
}
|
||||
|
||||
txpool := &provider.TransactionPool{}
|
||||
for name, providers := range networks {
|
||||
if len(providers) == 1 {
|
||||
log.Warn("can't measure first seen for network, please another provider",
|
||||
"network", name)
|
||||
}
|
||||
(*txpool)[name] = &provider.NetworkTransactionPool{}
|
||||
(*txpool)[name].Transactions = make(map[string]*provider.TransactionState)
|
||||
// set expected number of providers for this network
|
||||
// -1 since we don't wait for acking from the same provider
|
||||
(*txpool)[name].Expected = len(providers) - 1
|
||||
}
|
||||
|
||||
for name, providerConfig := range s.Config.Providers {
|
||||
s.Providers[name] = provider.New(name,
|
||||
providerConfig,
|
||||
&s.Config.Signer,
|
||||
s.Config.Wallets[providerConfig.Wallet],
|
||||
(*txpool)[providerConfig.Network])
|
||||
s.Providers[name].Start(ctx)
|
||||
log.Info("provider started",
|
||||
"provider", name)
|
||||
}
|
||||
|
||||
log.Info("service started")
|
||||
}
|
||||
|
||||
func (s *Service) Shutdown() {
|
||||
log.Info("service shutting down")
|
||||
if s.Config.Healthz.Enabled {
|
||||
if err := s.Healthz.Shutdown(); err != nil {
|
||||
log.Error("Error shutting down healthz server", err)
|
||||
}
|
||||
log.Info("healthz stopped")
|
||||
}
|
||||
if s.Config.Metrics.Enabled {
|
||||
if err := s.Metrics.Shutdown(); err != nil {
|
||||
log.Error("Error shutting down metrics server", err)
|
||||
}
|
||||
log.Info("metrics stopped")
|
||||
}
|
||||
for name, provider := range s.Providers {
|
||||
provider.Shutdown()
|
||||
log.Info("provider stopped",
|
||||
"provider", name)
|
||||
}
|
||||
log.Info("service stopped")
|
||||
}
|
72
op-ufm/tools/kmstool/main.go
Normal file
72
op-ufm/tools/kmstool/main.go
Normal file
@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
kms "cloud.google.com/go/kms/apiv1"
|
||||
"cloud.google.com/go/kms/apiv1/kmspb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("kmstool - usage: kmstool <key>")
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
panic("missing <key>")
|
||||
}
|
||||
|
||||
keyName := os.Args[1]
|
||||
|
||||
ctx := context.Background()
|
||||
client, err := kms.NewKeyManagementClient(ctx)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create kms client: %w", err))
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
addr, err := resolveAddr(ctx, client, keyName)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to retrieve the key: %w", err))
|
||||
}
|
||||
fmt.Printf("ethereum addr: %s", addr)
|
||||
println()
|
||||
println()
|
||||
}
|
||||
|
||||
func resolveAddr(ctx context.Context, client *kms.KeyManagementClient, keyName string) (common.Address, error) {
|
||||
resp, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{Name: keyName})
|
||||
if err != nil {
|
||||
return common.Address{}, fmt.Errorf("google kms public key %q lookup: %w", keyName, err)
|
||||
}
|
||||
keyPem := resp.Pem
|
||||
|
||||
block, _ := pem.Decode([]byte(keyPem))
|
||||
if block == nil {
|
||||
return common.Address{}, fmt.Errorf("google kms public key %q pem empty: %.130q", keyName, keyPem)
|
||||
}
|
||||
|
||||
var info struct {
|
||||
AlgID pkix.AlgorithmIdentifier
|
||||
Key asn1.BitString
|
||||
}
|
||||
_, err = asn1.Unmarshal(block.Bytes, &info)
|
||||
if err != nil {
|
||||
return common.Address{}, fmt.Errorf("google kms public key %q pem block %q: %w", keyName, block.Type, err)
|
||||
}
|
||||
|
||||
return pubKeyAddr(info.Key.Bytes), nil
|
||||
}
|
||||
|
||||
// PubKeyAddr returns the Ethereum address for the (uncompressed) key bytes.
|
||||
func pubKeyAddr(bytes []byte) common.Address {
|
||||
digest := crypto.Keccak256(bytes[1:])
|
||||
var addr common.Address
|
||||
copy(addr[:], digest[12:])
|
||||
return addr
|
||||
}
|
Loading…
Reference in New Issue
Block a user