diff --git a/.changeset/clean-crabs-wash.md b/.changeset/clean-crabs-wash.md new file mode 100644 index 0000000000000000000000000000000000000000..7391d6174c023deda14bbe4b22b30da4ddfc38b9 --- /dev/null +++ b/.changeset/clean-crabs-wash.md @@ -0,0 +1,5 @@ +--- +'@eth-optimism/integration-tests': minor +--- + +Various updates to integration tests so that they can be executed against production networks diff --git a/.changeset/many-dots-know.md b/.changeset/many-dots-know.md new file mode 100644 index 0000000000000000000000000000000000000000..7ff59d053af9ea64dbb98a9fa4e48cfc44d07970 --- /dev/null +++ b/.changeset/many-dots-know.md @@ -0,0 +1,5 @@ +--- +'@eth-optimism/l2geth': patch +--- + +Update the `RollupClient` transaction type to use `hexutil.Big` diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65bfc5216d1f7c9111ea1ec2f22bc4be6f7bf00b..1e0ebcd2e4c87f84627c0d63d0eeb25c9b1ac2f5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,6 +92,14 @@ jobs: push: true tags: ethereumoptimism/l2geth:${{ needs.release.outputs.l2geth }} + - name: Publish op_exporter + uses: docker/build-push-action@v2 + with: + context: . + file: ./ops/docker/Dockerfile.op_exporter + push: true + tags: ethereumoptimism/op_exporter:${{ needs.release.outputs.l2geth }} + - name: Publish rpc-proxy uses: docker/build-push-action@v2 with: diff --git a/.github/workflows/ts-packages.yml b/.github/workflows/ts-packages.yml index 6388e82507f7313062c1d714a694a080235f5c37..f19ec04b6bf3b2f50d3d2820d1109379e800db40 100644 --- a/.github/workflows/ts-packages.yml +++ b/.github/workflows/ts-packages.yml @@ -61,8 +61,42 @@ jobs: env: CC_SECRET: ${{ secrets.CC_SECRET }} + # A hack that allows running a job only if a specific directory changed. + # Ref: https://github.community/t/run-job-only-if-folder-changed/118292 + is-contracts-package: + name: Check files + outputs: + run_coverage: ${{ steps.check_files.outputs.run_coverage }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - run: git fetch origin $GITHUB_BASE_REF + + - name: check modified files + id: check_files + run: | + echo "=============== list modified files ===============" + git diff --name-only origin/$GITHUB_BASE_REF HEAD -- . + + echo "========== check paths of modified files ==========" + git diff --name-only origin/$GITHUB_BASE_REF HEAD -- . > files.txt + while IFS= read -r file + do + echo $file + if [[ $file != packages/contracts/* ]]; then + echo "This modified files are not in the contracts package." + echo "::set-output name=run_coverage::false" + break + else + echo "::set-output name=run_coverage::true" + fi + done < files.txt + test-coverage: name: Generate test coverage + needs: is-contracts-package + if: needs.is-contracts-package.outputs.run_coverage == 'true' runs-on: ubuntu-latest steps: diff --git a/go/op_exporter/.gitignore b/go/op_exporter/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..10cfd60097aed2aa63440468865b91f3c0bc4981 --- /dev/null +++ b/go/op_exporter/.gitignore @@ -0,0 +1,2 @@ +op_exporter +.env \ No newline at end of file diff --git a/go/op_exporter/Makefile b/go/op_exporter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..101880c07ad3fa181723576bb297db4dd4ba051b --- /dev/null +++ b/go/op_exporter/Makefile @@ -0,0 +1,21 @@ +SHELL := /bin/bash + +VERSION := `git describe --abbrev=0` +GITCOMMIT := `git rev-parse HEAD` +BUILDDATE := `date +%Y-%m-%d` +BUILDUSER := `whoami` + +LDFLAGSSTRING :=-X github.com/ethereum-optimism/optimism/go/op_exporter/version.Version=$(VERSION) +LDFLAGSSTRING +=-X github.com/ethereum-optimism/optimism/go/op_exporter/version.GitCommit=$(GITCOMMIT) +LDFLAGSSTRING +=-X github.com/ethereum-optimism/optimism/go/op_exporter/version.BuildDate=$(BUILDDATE) +LDFLAGSSTRING +=-X github.com/ethereum-optimism/optimism/go/op_exporter/version.BuildUser=$(BUILDUSER) + +LDFLAGS :=-ldflags "$(LDFLAGSSTRING)" + +.PHONY: all build + +all: build + +# Build binary +build: + CGO_ENABLED=0 go build $(LDFLAGS) \ No newline at end of file diff --git a/go/op_exporter/README.md b/go/op_exporter/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5ec4d7bfdb78b7660b3dd070e3c809954b8ec011 --- /dev/null +++ b/go/op_exporter/README.md @@ -0,0 +1,27 @@ +# op_exporter + +A prometheus exporter to collect information from an Optimistic Ethereum node and serve metrics for collection + +## Usage + +``` +make build && ./op_exporter --rpc.provider="https://kovan-sequencer.optimism.io" --label.network="kovan" +``` + +## Health endpoint `/health` + +Returns json describing the health of the sequencer based on the time since a block height update. + +``` +$ curl http://localhost:9100/health +{ "healthy": "false" } +``` + +## Metrics endpoint `/metrics` + +``` +# HELP op_gasPrice Gas price. +# TYPE op_gasPrice gauge +op_gasPrice{layer="layer1",network="kovan"} 6.9e+09 +op_gasPrice{layer="layer2",network="kovan"} 1 +``` diff --git a/go/op_exporter/collector.go b/go/op_exporter/collector.go new file mode 100644 index 0000000000000000000000000000000000000000..b74a105d12877e099e8fab961004768b4449014e --- /dev/null +++ b/go/op_exporter/collector.go @@ -0,0 +1,34 @@ +package main + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +//Define the metrics we wish to expose +var ( + gasPrice = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "op_gasPrice", + Help: "Gas price."}, + []string{"network", "layer"}, + ) + blockNumber = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "op_blocknumber", + Help: "Current block number."}, + []string{"network", "layer"}, + ) + healthySequencer = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "op_healthy_sequencer", + Help: "Is the sequencer healthy?"}, + []string{"network"}, + ) +) + +func init() { + //Register metrics with prometheus + prometheus.MustRegister(gasPrice) + prometheus.MustRegister(blockNumber) + prometheus.MustRegister(healthySequencer) +} diff --git a/go/op_exporter/go.mod b/go/op_exporter/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..8d7ace3a1e4ed62c7a6ca4f37357ba0d2a0d96cb --- /dev/null +++ b/go/op_exporter/go.mod @@ -0,0 +1,11 @@ +module github.com/ethereum-optimism/optimism/go/op_exporter + +go 1.16 + +require ( + github.com/ethereum/go-ethereum v1.10.4 + github.com/prometheus/client_golang v1.4.0 + github.com/sirupsen/logrus v1.4.2 + github.com/ybbus/jsonrpc v2.1.2+incompatible + gopkg.in/alecthomas/kingpin.v2 v2.2.6 +) diff --git a/go/op_exporter/go.sum b/go/op_exporter/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..3089f087cc5013014fdd81f3976e41ad22803546 --- /dev/null +++ b/go/op_exporter/go.sum @@ -0,0 +1,541 @@ +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.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= +github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= +github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= +github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= +github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= +github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= +github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +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/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/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/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= +github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.10.4 h1:JPZPL2MHbegfFStcaOrrggMVIcf57OQHQ0J3UhjQ+xQ= +github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +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/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +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.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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +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.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= +github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= +github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= +github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= +github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +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.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +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/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= +github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= +github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/ybbus/jsonrpc v2.1.2+incompatible h1:V4mkE9qhbDQ92/MLMIhlhMSbz8jNXdagC3xBR5NDwaQ= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/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-20200813134508-3edf25e44fcc/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-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988 h1:EjgCl+fVlIaPJSori0ikSz3uV0DOHKWOJFpv1sAAhBM= +golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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-20190206041539-40960b6deb8e/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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +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= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +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.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/go/op_exporter/main.go b/go/op_exporter/main.go new file mode 100644 index 0000000000000000000000000000000000000000..992d1605c9b74a66f4411a0d8c780f961c4edd09 --- /dev/null +++ b/go/op_exporter/main.go @@ -0,0 +1,174 @@ +package main + +import ( + "fmt" + "net/http" + "os" + "sync" + "time" + + "github.com/ethereum-optimism/optimism/go/op_exporter/version" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/prometheus/client_golang/prometheus/promhttp" + log "github.com/sirupsen/logrus" + "github.com/ybbus/jsonrpc" + "gopkg.in/alecthomas/kingpin.v2" +) + +var ( + listenAddress = kingpin.Flag( + "web.listen-address", + "Address on which to expose metrics and web interface.", + ).Default(":9100").String() + rpcProvider = kingpin.Flag( + "rpc.provider", + "Address for RPC provider.", + ).Default("http://127.0.0.1:8545").String() + networkLabel = kingpin.Flag( + "label.network", + "Label to apply to the metrics to identify the network.", + ).Default("mainnet").String() + versionFlag = kingpin.Flag( + "version", + "Display binary version.", + ).Default("False").Bool() + unhealthyTimePeriod = kingpin.Flag( + "wait.minutes", + "Number of minutes to wait for the next block before marking provider unhealthy.", + ).Default("10").Int() + //unhealthyTimePeriod = time.Minute * 10 +) + +type healthCheck struct { + mu *sync.RWMutex + height uint64 + healthy bool + updateTime time.Time +} + +func healthHandler(health *healthCheck) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + health.mu.RLock() + defer health.mu.RUnlock() + w.Write([]byte(fmt.Sprintf(`{ "healthy": "%t" }`, health.healthy))) + } +} + +func main() { + kingpin.HelpFlag.Short('h') + kingpin.Parse() + if *versionFlag { + fmt.Printf("(version=%s, gitcommit=%s)\n", version.Version, version.GitCommit) + fmt.Printf("(go=%s, user=%s, date=%s)\n", version.GoVersion, version.BuildUser, version.BuildDate) + os.Exit(0) + } + log.Infoln("exporter config", *listenAddress, *rpcProvider, *networkLabel) + log.Infoln("Starting op_exporter", version.Info()) + log.Infoln("Build context", version.BuildContext()) + + health := healthCheck{ + mu: new(sync.RWMutex), + height: 0, + healthy: false, + updateTime: time.Now(), + } + http.Handle("/metrics", promhttp.Handler()) + http.Handle("/health", healthHandler(&health)) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`<html> + <head><title>OP Exporter</title></head> + <body> + <h1>OP Exporter</h1> + <p><a href="/metrics">Metrics</a></p> + <p><a href="/health">Health</a></p> + </body> + </html>`)) + }) + go getRollupGasPrices() + go getBlockNumber(&health) + log.Infoln("Listening on", *listenAddress) + if err := http.ListenAndServe(*listenAddress, nil); err != nil { + log.Fatal(err) + } + +} + +func getBlockNumber(health *healthCheck) { + rpcClient := jsonrpc.NewClientWithOpts(*rpcProvider, &jsonrpc.RPCClientOpts{}) + var blockNumberResponse *string + for { + if err := rpcClient.CallFor(&blockNumberResponse, "eth_blockNumber"); err != nil { + health.mu.Lock() + health.healthy = false + health.mu.Unlock() + log.Warnln("Error calling eth_blockNumber, setting unhealthy", err) + } else { + log.Infoln("Got block number: ", *blockNumberResponse) + health.mu.Lock() + currentHeight, err := hexutil.DecodeUint64(*blockNumberResponse) + blockNumber.WithLabelValues( + *networkLabel, "layer2").Set(float64(currentHeight)) + if err != nil { + log.Warnln("Error decoding block height", err) + continue + } + lastHeight := health.height + // If the currentHeight is the same as the lastHeight, check that + // the unhealthyTimePeriod has passed and update health.healthy + if currentHeight == lastHeight { + currentTime := time.Now() + lastTime := health.updateTime + log.Warnln(fmt.Sprintf("Heights are the same, %v, %v", currentTime, lastTime)) + if lastTime.Add(time.Duration(*unhealthyTimePeriod) * time.Minute).Before(currentTime) { + health.healthy = false + log.Warnln("Heights are the same for the unhealthyTimePeriod, setting unhealthy") + } + } else { + log.Warnln("New block height detected, setting healthy") + health.height = currentHeight + health.updateTime = time.Now() + health.healthy = true + } + if health.healthy { + healthySequencer.WithLabelValues( + *networkLabel).Set(1) + } else { + healthySequencer.WithLabelValues( + *networkLabel).Set(0) + } + + health.mu.Unlock() + } + time.Sleep(time.Duration(30) * time.Second) + } +} + +func getRollupGasPrices() { + rpcClient := jsonrpc.NewClientWithOpts(*rpcProvider, &jsonrpc.RPCClientOpts{}) + var rollupGasPrices *GetRollupGasPrices + for { + if err := rpcClient.CallFor(&rollupGasPrices, "rollup_gasPrices"); err != nil { + log.Warnln("Error calling rollup_gasPrices", err) + } else { + l1GasPriceString := rollupGasPrices.L1GasPrice + l1GasPrice, err := hexutil.DecodeUint64(l1GasPriceString) + if err != nil { + log.Warnln("Error converting gasPrice " + l1GasPriceString) + } + gasPrice.WithLabelValues( + *networkLabel, "layer1").Set(float64(l1GasPrice)) + l2GasPriceString := rollupGasPrices.L2GasPrice + l2GasPrice, err := hexutil.DecodeUint64(l2GasPriceString) + if err != nil { + log.Warnln("Error converting gasPrice " + l2GasPriceString) + } + gasPrice.WithLabelValues( + *networkLabel, "layer2").Set(float64(l2GasPrice)) + log.Infoln("Got L1 gas string: ", l1GasPriceString) + log.Infoln("Got L1 gas prices: ", l1GasPrice) + log.Infoln("Got L2 gas string: ", l2GasPriceString) + log.Infoln("Got L2 gas prices: ", l2GasPrice) + } + time.Sleep(time.Duration(30) * time.Second) + } +} diff --git a/go/op_exporter/rpc.go b/go/op_exporter/rpc.go new file mode 100644 index 0000000000000000000000000000000000000000..f6bc9b13968a35c9e6978b410ad2b5f6e5289e1e --- /dev/null +++ b/go/op_exporter/rpc.go @@ -0,0 +1,11 @@ +package main + +// GetRollupGasPrices returns the rpc `rollup_gasPrices` status +type GetRollupGasPrices struct { + L1GasPrice string `json:"l1GasPrice"` + L2GasPrice string `json:"l2GasPrice"` +} + +type GetBlockNumber struct { + BlockNumber string `json:"result"` +} diff --git a/go/op_exporter/version/version.go b/go/op_exporter/version/version.go new file mode 100644 index 0000000000000000000000000000000000000000..d86154a93014a90b8c21507db21a706e7e2ac374 --- /dev/null +++ b/go/op_exporter/version/version.go @@ -0,0 +1,22 @@ +package version + +import ( + "fmt" + "runtime" +) + +var ( + Version string + GitCommit string + BuildUser string + BuildDate string + GoVersion = runtime.Version() +) + +func Info() string { + return fmt.Sprintf("(version=%s, gitcommit=%s)", Version, GitCommit) +} + +func BuildContext() string { + return fmt.Sprintf("(go=%s, user=%s, date=%s)", GoVersion, BuildUser, BuildDate) +} diff --git a/integration-tests/.env.example b/integration-tests/.env.example new file mode 100644 index 0000000000000000000000000000000000000000..188301c4eb088ae94cb8bac24bc49089efb7bc96 --- /dev/null +++ b/integration-tests/.env.example @@ -0,0 +1,6 @@ +# only need to fill these out if you want to test against a prod network +PRIVATE_KEY= +L1_URL= +L2_URL= +ADDRESS_MANAGER= +L2_CHAINID= diff --git a/integration-tests/README.md b/integration-tests/README.md new file mode 100644 index 0000000000000000000000000000000000000000..63ee3672896198b02c36652630a91da210969952 --- /dev/null +++ b/integration-tests/README.md @@ -0,0 +1,31 @@ +# @eth-optimism/integration-tests + +## Setup + +Follow installation + build instructions in the [primary README](../README.md). +Then, run: + +```bash +yarn build:integration +``` + +## Running tests + +### Testing a live network + +Create an `.env` file and fill it out. +Look at `.env.example` to know which variables to include. + +Once you have your environment set up, run: + +```bash +yarn test:integration:live +``` + +You can also set environment variables on the command line instead of inside `.env` if you want: + +```bash +L1_URL=whatever L2_URL=whatever yarn test:integration:live +``` + +Note that this can take an extremely long time (~1hr). diff --git a/integration-tests/hardhat.config.ts b/integration-tests/hardhat.config.ts index 50c0b7b2756e7d6761605822f8c536d79f3f5a84..c456cb75dd7699ef545a431bfa372a237fea808f 100644 --- a/integration-tests/hardhat.config.ts +++ b/integration-tests/hardhat.config.ts @@ -9,14 +9,19 @@ import 'hardhat-gas-reporter' const enableGasReport = !!process.env.ENABLE_GAS_REPORT const config: HardhatUserConfig = { - mocha: { - timeout: 20000, - }, networks: { optimism: { url: process.env.L2_URL || 'http://localhost:8545', ovm: true, }, + 'optimism-live': { + url: process.env.L2_URL || 'http://localhost:8545', + ovm: true, + timeout: 150000, + }, + }, + mocha: { + timeout: 50000, }, solidity: '0.7.6', ovm: { diff --git a/integration-tests/package.json b/integration-tests/package.json index e0298a33fe48c5f751a042c39e1462883b849314..3570eb24e124e4d23c1ae22d805d59922b5f3b22 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -13,6 +13,7 @@ "build:contracts": "hardhat compile", "build:contracts:ovm": "hardhat compile --network optimism", "test:integration": "hardhat --network optimism test", + "test:integration:live": "IS_LIVE_NETWORK=true hardhat --network optimism-live test", "test:sync": "hardhat --network optimism test sync-tests/*.spec.ts --no-compile", "clean": "rimraf cache artifacts artifacts-ovm cache-ovm" }, @@ -20,6 +21,7 @@ "@eth-optimism/contracts": "^0.4.2", "@eth-optimism/core-utils": "^0.5.0", "@eth-optimism/hardhat-ovm": "^0.2.2", + "@eth-optimism/message-relayer": "^0.1.6", "@ethersproject/providers": "^5.0.24", "@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-waffle": "^2.0.1", @@ -33,6 +35,7 @@ "chai": "^4.3.3", "chai-as-promised": "^7.1.1", "docker-compose": "^0.23.8", + "dotenv": "^10.0.0", "envalid": "^7.1.0", "babel-eslint": "^10.1.0", "eslint": "^7.27.0", diff --git a/integration-tests/test/basic-l1-l2-communication.spec.ts b/integration-tests/test/basic-l1-l2-communication.spec.ts index 96c400995e94eba0f9385ac06c8cb330df163eed..9eda61599e101035bd0bae353ec2be7a94c2c6f3 100644 --- a/integration-tests/test/basic-l1-l2-communication.spec.ts +++ b/integration-tests/test/basic-l1-l2-communication.spec.ts @@ -3,13 +3,13 @@ import { expect } from 'chai' /* Imports: External */ import { Contract, ContractFactory } from 'ethers' import { predeploys, getContractInterface } from '@eth-optimism/contracts' -import { Direction } from './shared/watcher-utils' /* Imports: Internal */ import l1SimpleStorageJson from '../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json' import l2SimpleStorageJson from '../artifacts-ovm/contracts/SimpleStorage.sol/SimpleStorage.json' import l2ReverterJson from '../artifacts-ovm/contracts/Reverter.sol/Reverter.json' -import { OptimismEnv } from './shared/env' +import { Direction } from './shared/watcher-utils' +import { OptimismEnv, useDynamicTimeoutForWithdrawals } from './shared/env' describe('Basic L1<>L2 Communication', async () => { let Factory__L1SimpleStorage: ContractFactory @@ -49,7 +49,9 @@ describe('Basic L1<>L2 Communication', async () => { }) describe('L2 => L1', () => { - it('should be able to perform a withdrawal from L2 -> L1', async () => { + it('should be able to perform a withdrawal from L2 -> L1', async function () { + await useDynamicTimeoutForWithdrawals(this, env) + const value = `0x${'77'.repeat(32)}` // Send L2 -> L1 message. @@ -58,7 +60,8 @@ describe('Basic L1<>L2 Communication', async () => { L1SimpleStorage.interface.encodeFunctionData('setValue', [value]), 5000000 ) - + await transaction.wait() + await env.relayXDomainMessages(transaction) await env.waitForXDomainTransaction(transaction, Direction.L2ToL1) expect(await L1SimpleStorage.msgSender()).to.equal( diff --git a/integration-tests/test/fee-payment.spec.ts b/integration-tests/test/fee-payment.spec.ts index de0ec93fb968a9fdb52560e63ee6674865880bfa..952c755f2676b8e5f8107bbb0df4859cb96902d3 100644 --- a/integration-tests/test/fee-payment.spec.ts +++ b/integration-tests/test/fee-payment.spec.ts @@ -3,11 +3,12 @@ import chaiAsPromised from 'chai-as-promised' chai.use(chaiAsPromised) /* Imports: External */ -import { BigNumber, Contract, utils } from 'ethers' +import { ethers, BigNumber, Contract, utils } from 'ethers' import { TxGasLimit, TxGasPrice } from '@eth-optimism/core-utils' import { predeploys, getContractInterface } from '@eth-optimism/contracts' /* Imports: Internal */ +import { IS_LIVE_NETWORK } from './shared/utils' import { OptimismEnv } from './shared/env' import { Direction } from './shared/watcher-utils' @@ -36,11 +37,11 @@ describe('Fee Payment Integration Tests', async () => { it('Should estimateGas with recoverable L2 gasLimit', async () => { const gas = await env.ovmEth.estimateGas.transfer( other, - utils.parseEther('0.5') + utils.parseEther('0.0000001') ) const tx = await env.ovmEth.populateTransaction.transfer( other, - utils.parseEther('0.5') + utils.parseEther('0.0000001') ) const executionGas = await (env.ovmEth.provider as any).send( 'eth_estimateExecutionGas', @@ -51,7 +52,7 @@ describe('Fee Payment Integration Tests', async () => { }) it('Paying a nonzero but acceptable gasPrice fee', async () => { - const amount = utils.parseEther('0.5') + const amount = utils.parseEther('0.0000001') const balanceBefore = await env.l2Wallet.getBalance() const feeVaultBalanceBefore = await env.l2Wallet.provider.getBalance( ovmSequencerFeeVault.address @@ -84,15 +85,23 @@ describe('Fee Payment Integration Tests', async () => { await expect(ovmSequencerFeeVault.withdraw()).to.be.rejected }) - it('should be able to withdraw fees back to L1 once the minimum is met', async () => { + it('should be able to withdraw fees back to L1 once the minimum is met', async function () { const l1FeeWallet = await ovmSequencerFeeVault.l1FeeWallet() const balanceBefore = await env.l1Wallet.provider.getBalance(l1FeeWallet) + const withdrawalAmount = await ovmSequencerFeeVault.MIN_WITHDRAWAL_AMOUNT() + + const l2WalletBalance = await env.l2Wallet.getBalance() + if (IS_LIVE_NETWORK && l2WalletBalance.lt(withdrawalAmount)) { + console.log( + `NOTICE: must have at least ${ethers.utils.formatEther( + withdrawalAmount + )} ETH on L2 to execute this test, skipping` + ) + this.skip() + } // Transfer the minimum required to withdraw. - await env.ovmEth.transfer( - ovmSequencerFeeVault.address, - await ovmSequencerFeeVault.MIN_WITHDRAWAL_AMOUNT() - ) + await env.ovmEth.transfer(ovmSequencerFeeVault.address, withdrawalAmount) const vaultBalance = await env.ovmEth.balanceOf( ovmSequencerFeeVault.address diff --git a/integration-tests/test/native-eth.spec.ts b/integration-tests/test/native-eth.spec.ts index beeaa068d6b6e0d25fd97496661f2b95668665bf..652861c5d8f5faa6014a08bd471d9451cc94ca98 100644 --- a/integration-tests/test/native-eth.spec.ts +++ b/integration-tests/test/native-eth.spec.ts @@ -1,7 +1,10 @@ -import { predeploys } from '@eth-optimism/contracts' - import { expect } from 'chai' + +/* Imports: External */ import { Wallet, utils, BigNumber } from 'ethers' +import { predeploys } from '@eth-optimism/contracts' + +/* Imports: Internal */ import { Direction } from './shared/watcher-utils' import { @@ -9,7 +12,7 @@ import { fundUser, PROXY_SEQUENCER_ENTRYPOINT_ADDRESS, } from './shared/utils' -import { OptimismEnv } from './shared/env' +import { OptimismEnv, useDynamicTimeoutForWithdrawals } from './shared/env' const DEFAULT_TEST_GAS_L1 = 330_000 const DEFAULT_TEST_GAS_L2 = 1_300_000 @@ -53,7 +56,7 @@ describe('Native ETH Integration Tests', async () => { describe('estimateGas', () => { it('Should estimate gas for ETH transfer', async () => { - const amount = utils.parseEther('0.5') + const amount = utils.parseEther('0.0000001') const addr = '0x' + '1234'.repeat(10) const gas = await env.ovmEth.estimateGas.transfer(addr, amount) // Expect gas to be less than or equal to the target plus 1% @@ -61,7 +64,7 @@ describe('Native ETH Integration Tests', async () => { }) it('Should estimate gas for ETH withdraw', async () => { - const amount = utils.parseEther('0.5') + const amount = utils.parseEther('0.0000001') const gas = await env.l2Bridge.estimateGas.withdraw( predeploys.OVM_ETH, amount, @@ -186,14 +189,13 @@ describe('Native ETH Integration Tests', async () => { await expect( env.l1Bridge.depositETH(DEFAULT_TEST_GAS_L2, data, { value: depositAmount, - gasLimit: 4_000_000, }) - ).to.be.revertedWith( - 'Transaction data size exceeds maximum for rollup transaction.' - ) + ).to.be.reverted }) - it('withdraw', async () => { + it('withdraw', async function () { + await useDynamicTimeoutForWithdrawals(this, env) + const withdrawAmount = BigNumber.from(3) const preBalances = await getBalances(env) expect( @@ -201,31 +203,43 @@ describe('Native ETH Integration Tests', async () => { 'Cannot run withdrawal test before any deposits...' ) + const transaction = await env.l2Bridge.withdraw( + predeploys.OVM_ETH, + withdrawAmount, + DEFAULT_TEST_GAS_L2, + '0xFFFF' + ) + await transaction.wait() + await env.relayXDomainMessages(transaction) const receipts = await env.waitForXDomainTransaction( - env.l2Bridge.withdraw( - predeploys.OVM_ETH, - withdrawAmount, - DEFAULT_TEST_GAS_L2, - '0xFFFF' - ), + transaction, Direction.L2ToL1 ) const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice) const postBalances = await getBalances(env) - expect(postBalances.l1BridgeBalance).to.deep.eq( - preBalances.l1BridgeBalance.sub(withdrawAmount) + // Approximate because there's a fee related to relaying the L2 => L1 message and it throws off the math. + expectApprox( + postBalances.l1BridgeBalance, + preBalances.l1BridgeBalance.sub(withdrawAmount), + { upperPercentDeviation: 1 } ) - expect(postBalances.l2UserBalance).to.deep.eq( - preBalances.l2UserBalance.sub(withdrawAmount.add(fee)) + expectApprox( + postBalances.l2UserBalance, + preBalances.l2UserBalance.sub(withdrawAmount.add(fee)), + { upperPercentDeviation: 1 } ) - expect(postBalances.l1UserBalance).to.deep.eq( - preBalances.l1UserBalance.add(withdrawAmount) + expectApprox( + postBalances.l1UserBalance, + preBalances.l1UserBalance.add(withdrawAmount), + { upperPercentDeviation: 1 } ) }) - it('withdrawTo', async () => { + it('withdrawTo', async function () { + await useDynamicTimeoutForWithdrawals(this, env) + const withdrawAmount = BigNumber.from(3) const preBalances = await getBalances(env) @@ -235,14 +249,17 @@ describe('Native ETH Integration Tests', async () => { 'Cannot run withdrawal test before any deposits...' ) + const transaction = await env.l2Bridge.withdrawTo( + predeploys.OVM_ETH, + l1Bob.address, + withdrawAmount, + DEFAULT_TEST_GAS_L2, + '0xFFFF' + ) + await transaction.wait() + await env.relayXDomainMessages(transaction) const receipts = await env.waitForXDomainTransaction( - env.l2Bridge.withdrawTo( - predeploys.OVM_ETH, - l1Bob.address, - withdrawAmount, - DEFAULT_TEST_GAS_L2, - '0xFFFF' - ), + transaction, Direction.L2ToL1 ) const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice) @@ -260,7 +277,9 @@ describe('Native ETH Integration Tests', async () => { ) }) - it('deposit, transfer, withdraw', async () => { + it('deposit, transfer, withdraw', async function () { + await useDynamicTimeoutForWithdrawals(this, env) + // 1. deposit const amount = utils.parseEther('1') await env.waitForXDomainTransaction( @@ -282,15 +301,18 @@ describe('Native ETH Integration Tests', async () => { // 3. do withdrawal const withdrawnAmount = utils.parseEther('0.95') + const transaction = await env.l2Bridge + .connect(other) + .withdraw( + predeploys.OVM_ETH, + withdrawnAmount, + DEFAULT_TEST_GAS_L1, + '0xFFFF' + ) + await transaction.wait() + await env.relayXDomainMessages(transaction) const receipts = await env.waitForXDomainTransaction( - env.l2Bridge - .connect(other) - .withdraw( - predeploys.OVM_ETH, - withdrawnAmount, - DEFAULT_TEST_GAS_L1, - '0xFFFF' - ), + transaction, Direction.L2ToL1 ) diff --git a/integration-tests/test/ovmcontext.spec.ts b/integration-tests/test/ovmcontext.spec.ts index f664dcc4ae63004dc0f6447ff54a57c0f66774cf..9bcd7be2206d219587f67d4e8777ac7b0ff44020 100644 --- a/integration-tests/test/ovmcontext.spec.ts +++ b/integration-tests/test/ovmcontext.spec.ts @@ -1,15 +1,14 @@ +import { expect } from 'chai' + +/* Imports: External */ import { ethers } from 'hardhat' import { injectL2Context } from '@eth-optimism/core-utils' -import { expect } from 'chai' -import { - sleep, - l2Provider, - l1Provider, - getAddressManager, -} from './shared/utils' +import { Contract, BigNumber } from 'ethers' + +/* Imports: Internal */ +import { l2Provider, l1Provider, IS_LIVE_NETWORK } from './shared/utils' import { OptimismEnv } from './shared/env' -import { getContractFactory } from '@eth-optimism/contracts' -import { Contract, ContractFactory, Wallet, BigNumber } from 'ethers' +import { Direction } from './shared/watcher-utils' /** * These tests cover the OVM execution contexts. In the OVM execution @@ -17,73 +16,51 @@ import { Contract, ContractFactory, Wallet, BigNumber } from 'ethers' * must be equal to the blocknumber/timestamp of the L1 transaction. */ describe('OVM Context: Layer 2 EVM Context', () => { - let address: string - let CanonicalTransactionChain: Contract - let OVMMulticall: Contract - let OVMContextStorage: Contract - - const L1Provider = l1Provider const L2Provider = injectL2Context(l2Provider) - + let env: OptimismEnv before(async () => { - const env = await OptimismEnv.new() - // Create providers and signers - const l1Wallet = env.l1Wallet - const l2Wallet = env.l2Wallet - const addressManager = env.addressManager + env = await OptimismEnv.new() + }) - // deploy the contract + let OVMMulticall: Contract + let OVMContextStorage: Contract + beforeEach(async () => { const OVMContextStorageFactory = await ethers.getContractFactory( 'OVMContextStorage', - l2Wallet - ) - - OVMContextStorage = await OVMContextStorageFactory.deploy() - const receipt = await OVMContextStorage.deployTransaction.wait() - address = OVMContextStorage.address - - const ctcAddress = await addressManager.getAddress( - 'OVM_CanonicalTransactionChain' + env.l2Wallet ) - const CanonicalTransactionChainFactory = getContractFactory( - 'OVM_CanonicalTransactionChain' - ) - - CanonicalTransactionChain = - CanonicalTransactionChainFactory.connect(l1Wallet).attach(ctcAddress) - const OVMMulticallFactory = await ethers.getContractFactory( 'OVMMulticall', - l2Wallet + env.l2Wallet ) + OVMContextStorage = await OVMContextStorageFactory.deploy() + await OVMContextStorage.deployTransaction.wait() OVMMulticall = await OVMMulticallFactory.deploy() await OVMMulticall.deployTransaction.wait() }) - it('Enqueue: `block.number` and `block.timestamp` have L1 values', async () => { - for (let i = 0; i < 5; i++) { - const l2Tip = await L2Provider.getBlock('latest') - const tx = await CanonicalTransactionChain.enqueue( + let numTxs = 5 + if (IS_LIVE_NETWORK) { + // Tests take way too long if we don't reduce the number of txs here. + numTxs = 1 + } + + it('enqueue: `block.number` and `block.timestamp` have L1 values', async () => { + for (let i = 0; i < numTxs; i++) { + const tx = await env.l1Messenger.sendMessage( OVMContextStorage.address, - 500_000, - '0x' + '0x', + 2_000_000 ) - - // Wait for the enqueue to be ingested - while (true) { - const tip = await L2Provider.getBlock('latest') - if (tip.number === l2Tip.number + 1) { - break - } - await sleep(500) - } + const receipt = await tx.wait() // Get the receipt - const receipt = await tx.wait() // The transaction did not revert expect(receipt.status).to.equal(1) + await env.waitForXDomainTransaction(tx, Direction.L1ToL2) + // Get the L1 block that the enqueue transaction was in so that // the timestamp can be compared against the layer two contract const block = await l1Provider.getBlock(receipt.blockNumber) @@ -96,14 +73,18 @@ describe('OVM Context: Layer 2 EVM Context', () => { const timestamp = await OVMContextStorage.timestamps(i) expect(block.timestamp).to.deep.equal(timestamp.toNumber()) } - }) + }).timeout(150000) // this specific test takes a while because it involves L1 to L2 txs it('should set correct OVM Context for `eth_call`', async () => { - const tip = await L2Provider.getBlockWithTransactions('latest') - const start = Math.max(0, tip.number - 5) - - for (let i = start; i < tip.number; i++) { - const block = await L2Provider.getBlockWithTransactions(i) + for (let i = 0; i < numTxs; i++) { + // Make an empty transaction to bump the latest block number. + const dummyTx = await env.l2Wallet.sendTransaction({ + to: `0x${'11'.repeat(20)}`, + data: '0x', + }) + await dummyTx.wait() + + const block = await L2Provider.getBlockWithTransactions('latest') const [, returnData] = await OVMMulticall.callStatic.aggregate( [ [ @@ -117,7 +98,7 @@ describe('OVM Context: Layer 2 EVM Context', () => { OVMMulticall.interface.encodeFunctionData('getCurrentBlockNumber'), ], ], - { blockTag: i } + { blockTag: block.number } ) const timestamp = BigNumber.from(returnData[0]) diff --git a/integration-tests/test/queue-ingestion.spec.ts b/integration-tests/test/queue-ingestion.spec.ts index 11dd4289677a9b6a9c7c6081dcfb5966ae8d2fae..add9c43e604d94b54848dbfa41119c29c36dca01 100644 --- a/integration-tests/test/queue-ingestion.spec.ts +++ b/integration-tests/test/queue-ingestion.spec.ts @@ -1,99 +1,65 @@ +import { expect } from 'chai' + /* Imports: Internal */ +import { providers } from 'ethers' import { injectL2Context } from '@eth-optimism/core-utils' -import { sleep } from './shared/utils' -import { OptimismEnv } from './shared/env' /* Imports: External */ -import { providers } from 'ethers' -import { expect } from 'chai' +import { OptimismEnv } from './shared/env' +import { Direction } from './shared/watcher-utils' -// This test ensures that the transactions which get `enqueue`d get -// added to the L2 blocks by the Sync Service (which queries the DTL) describe('Queue Ingestion', () => { - const RETRIES = 20 - const numTxs = 5 - let startBlock: number - let endBlock: number let env: OptimismEnv let l2Provider: providers.JsonRpcProvider - const receipts = [] - before(async () => { env = await OptimismEnv.new() l2Provider = injectL2Context(env.l2Wallet.provider as any) }) - // The transactions are enqueue'd with a `to` address of i.repeat(40) - // meaning that the `to` value is different each iteration in a deterministic - // way. They need to be inserted into the L2 chain in an ascending order. - // Keep track of the receipts so that the blockNumber can be compared - // against the `L1BlockNumber` on the tx objects. - before(async () => { - // Keep track of the L2 tip before submitting any transactions so that - // the subsequent transactions can be queried for in the next test - startBlock = (await l2Provider.getBlockNumber()) + 1 - endBlock = startBlock + numTxs - 1 - - // Enqueue some transactions by building the calldata and then sending - // the transaction to Layer 1 - for (let i = 0; i < numTxs; i++) { - const input = ['0x' + `${i}`.repeat(40), 500_000, `0x0${i}`] - const calldata = env.ctc.interface.encodeFunctionData('enqueue', input) - - const txResponse = await env.l1Wallet.sendTransaction({ - data: calldata, - to: env.ctc.address, - }) - - const receipt = await txResponse.wait() - receipts.push(receipt) - } - }) - // The batch submitter will notice that there are transactions // that are in the queue and submit them. L2 will pick up the // sequencer batch appended event and play the transactions. it('should order transactions correctly', async () => { - // Wait until each tx from the previous test has - // been executed - let i: number - for (i = 0; i < RETRIES; i++) { - const tip = await l2Provider.getBlockNumber() - if (tip >= endBlock) { - break - } - await sleep(1000) - } + const numTxs = 5 - if (i === RETRIES) { - throw new Error( - 'timed out waiting for queued transactions to be inserted' + // Enqueue some transactions by building the calldata and then sending + // the transaction to Layer 1 + const txs = [] + for (let i = 0; i < numTxs; i++) { + const tx = await env.l1Messenger.sendMessage( + `0x${`${i}`.repeat(40)}`, + `0x0${i}`, + 1_000_000 ) + await tx.wait() + txs.push(tx) } - const from = await env.l1Wallet.getAddress() - // Keep track of an index into the receipts list and - // increment it for each block fetched. - let receiptIndex = 0 - // Fetch blocks - for (i = 0; i < numTxs; i++) { - const block = await l2Provider.getBlock(startBlock + i) - const hash = block.transactions[0] - // Use as any hack because additional properties are - // added to the transaction response - const tx = await (l2Provider.getTransaction(hash) as any) + for (let i = 0; i < numTxs; i++) { + const l1Tx = txs[i] + const l1TxReceipt = await txs[i].wait() + const receipt = await env.waitForXDomainTransaction( + l1Tx, + Direction.L1ToL2 + ) + const l2Tx = (await l2Provider.getTransaction( + receipt.remoteTx.hash + )) as any + + const params = env.l2Messenger.interface.decodeFunctionData( + 'relayMessage', + l2Tx.data + ) - // The `to` addresses are defined in the previous test and - // increment sequentially. - expect(tx.to).to.be.equal('0x' + `${i}`.repeat(40)) - // The queue origin is Layer 1 - expect(tx.queueOrigin).to.be.equal('l1') - // the L1TxOrigin is equal to the Layer one from - expect(tx.l1TxOrigin).to.be.equal(from.toLowerCase()) - expect(typeof tx.l1BlockNumber).to.be.equal('number') - // Get the receipt and increment the recept index - const receipt = receipts[receiptIndex++] - expect(tx.l1BlockNumber).to.be.equal(receipt.blockNumber) + expect(params._sender.toLowerCase()).to.equal( + env.l1Wallet.address.toLowerCase() + ) + expect(params._target).to.equal('0x' + `${i}`.repeat(40)) + expect(l2Tx.queueOrigin).to.equal('l1') + expect(l2Tx.l1TxOrigin.toLowerCase()).to.equal( + env.l1Messenger.address.toLowerCase() + ) + expect(l2Tx.l1BlockNumber).to.equal(l1TxReceipt.blockNumber) } - }) + }).timeout(100_000) }) diff --git a/integration-tests/test/rpc.spec.ts b/integration-tests/test/rpc.spec.ts index b023a0b33178ca1bb5584e4ab12d9b78e32f5f41..7e0e3d8a5f26e751a3c9c321e87cf5249b9bb382 100644 --- a/integration-tests/test/rpc.spec.ts +++ b/integration-tests/test/rpc.spec.ts @@ -2,7 +2,6 @@ import { injectL2Context, TxGasLimit, TxGasPrice, - toRpcHexString, } from '@eth-optimism/core-utils' import { Wallet, BigNumber, Contract, ContractFactory } from 'ethers' import { ethers } from 'hardhat' @@ -13,6 +12,8 @@ import { DEFAULT_TRANSACTION, fundUser, expectApprox, + L2_CHAINID, + IS_LIVE_NETWORK, } from './shared/utils' import chaiAsPromised from 'chai-as-promised' import { OptimismEnv } from './shared/env' @@ -132,10 +133,9 @@ describe('Basic RPC tests', () => { gasPrice: TxGasPrice, } const fee = tx.gasPrice.mul(tx.gasLimit) - const gasLimit = 5920001 await expect(env.l2Wallet.sendTransaction(tx)).to.be.rejectedWith( - `fee too low: ${fee}, use at least tx.gasLimit = ${gasLimit} and tx.gasPrice = ${TxGasPrice.toString()}` + `fee too low: ${fee}, use at least tx.gasLimit =` ) }) @@ -317,7 +317,15 @@ describe('Basic RPC tests', () => { // canonical transaction chain. This test catches this by // querying for the latest block and then waits and then queries // the latest block again and then asserts that they are the same. - it('should return the same result when new transactions are not applied', async () => { + // + // Needs to be skipped on Prod networks because this test doesn't work when + // other people are sending transactions to the Sequencer at the same time + // as this test is running. + it('should return the same result when new transactions are not applied', async function () { + if (IS_LIVE_NETWORK) { + this.skip() + } + // Get latest block once to start. const prev = await provider.getBlockWithTransactions('latest') @@ -341,7 +349,7 @@ describe('Basic RPC tests', () => { describe('eth_chainId', () => { it('should get the correct chainid', async () => { const { chainId } = await provider.getNetwork() - expect(chainId).to.be.eq(420) + expect(chainId).to.be.eq(L2_CHAINID) }) }) diff --git a/integration-tests/test/shared/env.ts b/integration-tests/test/shared/env.ts index 9da4690cf7aaee54208e0482ddec7c4db230004d..218db66d6ba173ce2272c6721c6252f664577292 100644 --- a/integration-tests/test/shared/env.ts +++ b/integration-tests/test/shared/env.ts @@ -1,6 +1,11 @@ +/* Imports: External */ +import { Contract, utils, Wallet } from 'ethers' +import { TransactionResponse } from '@ethersproject/providers' import { getContractFactory, predeploys } from '@eth-optimism/contracts' import { Watcher } from '@eth-optimism/core-utils' -import { Contract, utils, Wallet } from 'ethers' +import { getMessagesAndProofsForL2Transaction } from '@eth-optimism/message-relayer' + +/* Imports: Internal */ import { getAddressManager, l1Provider, @@ -11,6 +16,8 @@ import { getOvmEth, getL1Bridge, getL2Bridge, + IS_LIVE_NETWORK, + sleep, } from './utils' import { initWatcher, @@ -18,7 +25,6 @@ import { Direction, waitForXDomainTransaction, } from './watcher-utils' -import { TransactionResponse } from '@ethersproject/providers' /// Helper class for instantiating a test environment with a funded account export class OptimismEnv { @@ -27,6 +33,7 @@ export class OptimismEnv { l1Bridge: Contract l1Messenger: Contract ctc: Contract + scc: Contract // L2 Contracts ovmEth: Contract @@ -53,6 +60,7 @@ export class OptimismEnv { this.l1Wallet = args.l1Wallet this.l2Wallet = args.l2Wallet this.ctc = args.ctc + this.scc = args.scc } static async new(): Promise<OptimismEnv> { @@ -85,10 +93,18 @@ export class OptimismEnv { .connect(l2Wallet) .attach(predeploys.OVM_GasPriceOracle) + const sccAddress = await addressManager.getAddress( + 'OVM_StateCommitmentChain' + ) + const scc = getContractFactory('OVM_StateCommitmentChain') + .connect(l1Wallet) + .attach(sccAddress) + return new OptimismEnv({ addressManager, l1Bridge, ctc, + scc, l1Messenger, ovmEth, gasPriceOracle, @@ -106,4 +122,94 @@ export class OptimismEnv { ): Promise<CrossDomainMessagePair> { return waitForXDomainTransaction(this.watcher, tx, direction) } + + /** + * Relays all L2 => L1 messages found in a given L2 transaction. + * + * @param tx Transaction to find messages in. + */ + async relayXDomainMessages( + tx: Promise<TransactionResponse> | TransactionResponse + ): Promise<void> { + tx = await tx + + let messagePairs = [] + while (true) { + try { + messagePairs = await getMessagesAndProofsForL2Transaction( + l1Provider, + l2Provider, + this.scc.address, + predeploys.OVM_L2CrossDomainMessenger, + tx.hash + ) + break + } catch (err) { + if (err.message.includes('unable to find state root batch for tx')) { + await sleep(5000) + } else { + throw err + } + } + } + + for (const { message, proof } of messagePairs) { + while (true) { + try { + const result = await this.l1Messenger + .connect(this.l1Wallet) + .relayMessage( + message.target, + message.sender, + message.message, + message.messageNonce, + proof + ) + await result.wait() + break + } catch (err) { + if (err.message.includes('execution failed due to an exception')) { + await sleep(5000) + } else if ( + err.message.includes('message has already been received') + ) { + break + } else { + throw err + } + } + } + } + } +} + +/** + * Sets the timeout of a test based on the challenge period of the current network. If the + * challenge period is greater than 60s (e.g., on Mainnet) then we skip this test entirely. + * + * @param testctx Function context of the test to modify (i.e. `this` when inside a test). + * @param env Optimism environment used to resolve the StateCommitmentChain. + */ +export const useDynamicTimeoutForWithdrawals = async ( + testctx: any, + env: OptimismEnv +) => { + if (!IS_LIVE_NETWORK) { + return + } + + const challengePeriod = await env.scc.FRAUD_PROOF_WINDOW() + if (challengePeriod.gt(60)) { + console.log( + `WARNING: challenge period is greater than 60s (${challengePeriod.toString()}s), skipping test` + ) + testctx.skip() + } + + // 60s for state root batch to be published + (challenge period x 4) + const timeoutMs = 60000 + challengePeriod.toNumber() * 1000 * 4 + console.log( + `NOTICE: inside a withdrawal test on a prod network, dynamically setting timeout to ${timeoutMs}ms` + ) + testctx.timeout(timeoutMs) } diff --git a/integration-tests/test/shared/utils.ts b/integration-tests/test/shared/utils.ts index 034856f729be958798a57fb39ac102f7bc51a58e..aabab62b0a9a8f1742a9c11efc80468226c0c9fc 100644 --- a/integration-tests/test/shared/utils.ts +++ b/integration-tests/test/shared/utils.ts @@ -1,13 +1,6 @@ import { expect } from 'chai' -import { Direction, waitForXDomainTransaction } from './watcher-utils' - -import { - getContractFactory, - getContractInterface, - predeploys, -} from '@eth-optimism/contracts' -import { injectL2Context, remove0x, Watcher } from '@eth-optimism/core-utils' +/* Imports: External */ import { Contract, Wallet, @@ -17,10 +10,24 @@ import { BigNumber, utils, } from 'ethers' -import { cleanEnv, str, num } from 'envalid' +import { + getContractFactory, + getContractInterface, + predeploys, +} from '@eth-optimism/contracts' +import { injectL2Context, remove0x, Watcher } from '@eth-optimism/core-utils' +import { cleanEnv, str, num, bool } from 'envalid' +import dotenv from 'dotenv' + +/* Imports: Internal */ +import { Direction, waitForXDomainTransaction } from './watcher-utils' export const GWEI = BigNumber.from(1e9) +if (process.env.IS_LIVE_NETWORK === 'true') { + dotenv.config() +} + const env = cleanEnv(process.env, { L1_URL: str({ default: 'http://localhost:9545' }), L2_URL: str({ default: 'http://localhost:8545' }), @@ -37,6 +44,8 @@ const env = cleanEnv(process.env, { ADDRESS_MANAGER: str({ default: '0x5FbDB2315678afecb367f032d93F642f64180aa3', }), + L2_CHAINID: num({ default: 420 }), + IS_LIVE_NETWORK: bool({ default: false }), }) // The hardhat instance @@ -64,6 +73,9 @@ export const PROXY_SEQUENCER_ENTRYPOINT_ADDRESS = '0x4200000000000000000000000000000000000004' export const OVM_ETH_ADDRESS = predeploys.OVM_ETH +export const L2_CHAINID = env.L2_CHAINID +export const IS_LIVE_NETWORK = env.IS_LIVE_NETWORK + export const getAddressManager = (provider: any) => { return getContractFactory('Lib_AddressManager') .connect(provider) diff --git a/l2geth/rollup/client.go b/l2geth/rollup/client.go index b885f088373679af842423441ad131867987a0ef..ad31f5649e6c2848567df7bc3771faf8f5921600 100644 --- a/l2geth/rollup/client.go +++ b/l2geth/rollup/client.go @@ -72,7 +72,7 @@ type transaction struct { BatchIndex uint64 `json:"batchIndex"` BlockNumber uint64 `json:"blockNumber"` Timestamp uint64 `json:"timestamp"` - Value hexutil.Uint64 `json:"value"` + Value *hexutil.Big `json:"value"` GasLimit uint64 `json:"gasLimit,string"` Target common.Address `json:"target"` Origin *common.Address `json:"origin"` @@ -106,7 +106,7 @@ type signature struct { // it means that the decoding failed. type decoded struct { Signature signature `json:"sig"` - Value hexutil.Uint64 `json:"value"` + Value *hexutil.Big `json:"value"` GasLimit uint64 `json:"gasLimit,string"` GasPrice uint64 `json:"gasPrice,string"` Nonce uint64 `json:"nonce,string"` @@ -343,7 +343,7 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe if res.Decoded != nil { nonce := res.Decoded.Nonce to := res.Decoded.Target - value := new(big.Int).SetUint64(uint64(res.Decoded.Value)) + value := (*big.Int)(res.Decoded.Value) // Note: there are two gas limits, one top level and // another on the raw transaction itself. Maybe maxGasLimit // for the top level? @@ -396,7 +396,7 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe gasLimit := res.GasLimit data := res.Data origin := res.Origin - value := new(big.Int).SetUint64(uint64(res.Value)) + value := (*big.Int)(res.Value) tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data) txMeta := types.NewTransactionMeta( new(big.Int).SetUint64(res.BlockNumber), diff --git a/l2geth/rollup/client_test.go b/l2geth/rollup/client_test.go index 98e832dc3744ab2bde7ac2b5e4f8a246f89c9684..125c8348f4efb94a638d7cad8f1c926ddf84b03b 100644 --- a/l2geth/rollup/client_test.go +++ b/l2geth/rollup/client_test.go @@ -1,6 +1,7 @@ package rollup import ( + "encoding/json" "errors" "fmt" "math/big" @@ -68,3 +69,40 @@ func TestRollupClientCannotConnect(t *testing.T) { t.Fatalf("Incorrect error returned: %s", err) } } +func TestDecodedJSON(t *testing.T) { + str := []byte(` + { + "index": 643116, + "batchIndex": 21083, + "blockNumber": 25954867, + "timestamp": 1625605288, + "gasLimit": "11000000", + "target": "0x4200000000000000000000000000000000000005", + "origin": null, + "data": "0xf86d0283e4e1c08343eab8941a5245ea5210c3b57b7cfdf965990e63534a7b528901a055690d9db800008081aea019f7c6719f1718475f39fb9e5a6a897c3bd5057488a014666e5ad573ec71cf0fa008836030e686f3175dd7beb8350809b47791c23a19092a8c2fab1f0b4211a466", + "queueOrigin": "sequencer", + "value": "0x1a055690d9db80000", + "queueIndex": null, + "decoded": { + "nonce": "2", + "gasPrice": "15000000", + "gasLimit": "4451000", + "value": "0x1a055690d9db80000", + "target": "0x1a5245ea5210c3b57b7cfdf965990e63534a7b52", + "data": "0x", + "sig": { + "v": 1, + "r": "0x19f7c6719f1718475f39fb9e5a6a897c3bd5057488a014666e5ad573ec71cf0f", + "s": "0x08836030e686f3175dd7beb8350809b47791c23a19092a8c2fab1f0b4211a466" + } + }, + "confirmed": true + }`) + + tx := new(transaction) + json.Unmarshal(str, tx) + cmp, _ := new(big.Int).SetString("1a055690d9db80000", 16) + if tx.Value.ToInt().Cmp(cmp) != 0 { + t.Fatal("Cannot decode") + } +} diff --git a/ops/docker/Dockerfile.integration-tests b/ops/docker/Dockerfile.integration-tests index 98401b43531307d26ed35d842fda14513c4cc00e..e0542a98b6920446ea54f826a7e10e445c85cfdb 100644 --- a/ops/docker/Dockerfile.integration-tests +++ b/ops/docker/Dockerfile.integration-tests @@ -13,6 +13,9 @@ COPY --from=builder /optimism/node_modules ./node_modules COPY --from=builder /optimism/packages/core-utils/package.json ./packages/core-utils/package.json COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dist +COPY --from=builder /optimism/packages/message-relayer/package.json ./packages/message-relayer/package.json +COPY --from=builder /optimism/packages/message-relayer/dist ./packages/message-relayer/dist + COPY --from=builder /optimism/packages/hardhat-ovm/package.json ./packages/hardhat-ovm/package.json COPY --from=builder /optimism/packages/hardhat-ovm/dist ./packages/hardhat-ovm/dist diff --git a/ops/docker/Dockerfile.op_exporter b/ops/docker/Dockerfile.op_exporter new file mode 100644 index 0000000000000000000000000000000000000000..3754319f9d1657cfe06f57e65cc7b85641c61869 --- /dev/null +++ b/ops/docker/Dockerfile.op_exporter @@ -0,0 +1,12 @@ +FROM golang:1.16 as builder + +ADD ./go/op_exporter /app/ +WORKDIR /app/ +RUN make build + +FROM alpine:latest +RUN apk --no-cache add ca-certificates +WORKDIR /root/ +COPY --from=builder /app/op_exporter /usr/local/bin/ +ENTRYPOINT ["op_exporter"] +CMD ["--help"] diff --git a/ops/docker/rpc-proxy/nginx.template.conf b/ops/docker/rpc-proxy/nginx.template.conf index 4530b5ddb84951e02caf5ef199ae8d93fbde1ee8..2c50152dffb8784b81b1fb5cf6c4ea3a53630790 100644 --- a/ops/docker/rpc-proxy/nginx.template.conf +++ b/ops/docker/rpc-proxy/nginx.template.conf @@ -11,6 +11,15 @@ events { http { include mime.types; index index.html; + # The JSONRPC POST body must fit inside this allocation for the method parsing to succeed. + # https://github.com/openresty/lua-nginx-module#ngxreqread_body + # http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size + client_body_buffer_size 128k; + # client_max_body_size should match client_body_buffer_size + # Values that exceed client_body_buffer_size will be written to a temporary file, which we don't want + # Requests above this limit will also be denied with an HTTP 413 response (entity too large) + # http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size + client_max_body_size 128k; # See Move default writable paths to a dedicated directory (#119) # https://github.com/openresty/docker-openresty/issues/119 @@ -38,7 +47,7 @@ http { metric_sequencer_requests = prometheus:counter( "nginx_eth_sequencer_requests", "Number of requests going to the sequencer", {"method", "host", "status"}) metric_replica_requests = prometheus:counter( - "nginx_eth_replica_requests", "Number of requests going to the replicas", {"host", "status"}) + "nginx_eth_replica_requests", "Number of requests going to the replicas", {"host", "status"}) metric_latency = prometheus:histogram( "nginx_http_request_duration_seconds", "HTTP request latency", {"host"}) metric_connections = prometheus:gauge( diff --git a/yarn.lock b/yarn.lock index 679dc2c888e880045f81ad0467af021a29bec548..d0d5ed0b7a43be1761d5d6235640bfaa1d0fd17a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5636,6 +5636,11 @@ dot-prop@^6.0.1: dependencies: is-obj "^2.0.0" +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + dotenv@^8.2.0: version "8.6.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b"