diff --git a/simulators/eth2/engine/Dockerfile b/simulators/eth2/engine/Dockerfile new file mode 100644 index 0000000000..c7cdb3e13f --- /dev/null +++ b/simulators/eth2/engine/Dockerfile @@ -0,0 +1,11 @@ +FROM golang:1-alpine AS builder +RUN apk --no-cache add gcc musl-dev linux-headers cmake make clang build-base clang-static clang-dev +ADD . /source +WORKDIR /source +RUN go build -o ./sim . + +# Build the runner container. +FROM alpine:latest +ADD . / +COPY --from=builder /source/sim / +ENTRYPOINT ["./sim"] diff --git a/simulators/eth2/engine/README.md b/simulators/eth2/engine/README.md new file mode 100644 index 0000000000..d9e05565c4 --- /dev/null +++ b/simulators/eth2/engine/README.md @@ -0,0 +1,97 @@ +# Eth2 in Hive + +This is *experimental*. + +## Configuration + +Chain configuration is provided via environment vars, for the clients to build configs in their format of preference. +The configuration (incl. formatting of values) matches the [Eth2 config spec](https://github.com/ethereum/consensus-specs/tree/dev/configs)). + +**Each configuration var is prefixed with `HIVE_ETH2_CONFIG_`**. + +And configuration variable is runtime-configurable, i.e. client docker images can adopt the Hive config without rebuild. + +The `PRESET_BASE` config var refers to the chosen set of compile-time configuration. +By default this is set to `mainnet`, and clients support `minimal` for testing purposes. +Other presets (compile-time configuration) may be introduced over time if required for advanced testing. + +## Container preparation + +Note `{}` is used for variable substitution, not part of content. + +### Validator Client + +#### Files + +Keystore files, encrypted. The `pubkey` is lowercase, hex with 0x prefix, of validator signing key. +Lower crypto parameters may be used to speed up tests. +See [eip-2335](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2335.md) for the keystore format. +``` +/hive/input/keystores/{pubkey}/keystore.json +``` + +Secret for the matching keystore. The `pubkey` is lowercase, hex with 0x prefix, of validator signing key. +Secret files have mode `0600`. The secret file is raw and bytes can be loaded directly. +No special characters are used for ease with text processing. +``` +/hive/input/secrets/{pubkey} +``` + +#### Env vars + +Every standard eth2-config var prefixed with `HIVE_ETH2_CONFIG_`, and additionally: + +```yaml +# HTTP API address, or can be assumed to be GRPC if using Prysm. +HIVE_ETH2_BN_API_IP: "{ip}" +HIVE_ETH2_BN_API_PORT: "{port}" + +HIVE_ETH2_BN_VENDOR: "{vendor}" # lowercase name of BN type. E.g. "prysm" + +HIVE_ETH2_GRAFFITI: "" # graffiti to put in blocks. Disabled if empty. + +HIVE_ETH2_VC_API_PORT: +``` + +### Beacon Node + +#### Files + +An Eth2 genesis state, encoded with SSZ. Not present when genesis is being tested (requires `HIVE_ETH2_ETH1_RPC_ADDRS`) +``` +/hive/input/genesis.ssz +``` + +#### Env vars + +Every standard eth2-config var prefixed with `HIVE_ETH2_CONFIG_`, and additionally: + +```yaml +HIVE_ETH2_DEPOSIT_DEPLOY_BLOCK_NUMBER: 0 # decimal number + +HIVE_ETH2_BOOTNODE_ENRS: "" # comma separated list of ENRs + +# IP address, required to set ENR correct from the start. +# If left empty, the node should attempt to discover its own IP with discv5. +HIVE_ETH2_P2P_IP_ADDRESS: "" +HIVE_ETH2_P2P_TCP_PORT: 9000 # Port to bind libp2p to, put into ENR +HIVE_ETH2_P2P_UDP_PORT: 9000 # Port to bind discv5 to, put into ENR + +HIVE_ETH2_P2P_TARGET_PEERS: 10 # Target number of peers + +# Some clients have a hard limit on slots that can be skipped without block. +HIVE_ETH2_MAX_SKIP_SLOTS: 1000 + +# Comma separated list of Eth1 nodes to communicate with. +# Clients should strip off everything after first comma if they do not load-balancing between them. +# If it is left empty, the beacon node should use a "dummy eth1" mode, where it fills Eth1 votes with mock data. +HIVE_ETH2_ETH1_RPC_ADDRS: "" + +# Port to expose standard HTTP API on +HIVE_ETH2_BN_API_PORT: 4000 +# Port to expose GRPC version of API on (Prysm has both) +HIVE_ETH2_BN_GRPC_PORT: 4001 + +# If not, metrics should be exposed on the given port +HIVE_ETH2_METRICS_PORT: 8080 +``` diff --git a/simulators/eth2/engine/go.mod b/simulators/eth2/engine/go.mod new file mode 100644 index 0000000000..8bba0efbdd --- /dev/null +++ b/simulators/eth2/engine/go.mod @@ -0,0 +1,67 @@ +module github.com/ethereum/hive/simulators/eth2/engine + +go 1.17 + +require ( + github.com/ethereum/go-ethereum v1.10.17 + github.com/ethereum/hive v0.0.0-20220202142700-64e211a795ba + github.com/google/uuid v1.3.0 + github.com/herumi/bls-eth-go-binary v0.0.0-20210902234237-7763804ee078 + github.com/pkg/errors v0.9.1 + github.com/protolambda/eth2api v0.0.0-20220123235524-49a703ed9d94 + github.com/protolambda/go-keystorev4 v0.0.0-20210914214957-cf12d9c28a52 + github.com/protolambda/zrnt v0.25.0 + github.com/protolambda/ztyp v0.2.1 + github.com/rauljordan/engine-proxy v0.0.0-20220511134016-2e057ad9d277 + github.com/tyler-smith/go-bip39 v1.1.0 + github.com/wealdtech/go-eth2-util v1.6.5 +) + +require ( + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/VictoriaMetrics/fastcache v1.6.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/deckarep/golang-set v1.8.0 // indirect + github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5 // indirect + github.com/go-kit/kit v0.9.0 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/holiman/uint256 v1.2.0 + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/onsi/gomega v1.10.3 // indirect + github.com/prometheus/tsdb v0.10.0 // indirect + github.com/protolambda/bls12-381-util v0.0.0-20210812140640-b03868185758 + github.com/shirou/gopsutil v3.21.8+incompatible // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/tklauser/go-sysconf v0.3.9 // indirect + golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect + golang.org/x/text v0.3.7 // indirect + gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) + +require ( + github.com/btcsuite/btcd/btcec/v2 v2.1.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/golang-jwt/jwt/v4 v4.3.0 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect + github.com/julienschmidt/httprouter v1.3.0 // indirect + github.com/kilic/bls12-381 v0.1.0 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/tklauser/numcpus v0.3.0 // indirect + github.com/urfave/cli/v2 v2.5.1 // indirect + github.com/wealdtech/go-bytesutil v1.1.1 // indirect + github.com/wealdtech/go-eth2-types/v2 v2.5.6 // indirect + golang.org/x/crypto v0.0.0-20211202192323-5770296d904e // indirect + gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect +) diff --git a/simulators/eth2/engine/go.sum b/simulators/eth2/engine/go.sum new file mode 100644 index 0000000000..4bcb357b7e --- /dev/null +++ b/simulators/eth2/engine/go.sum @@ -0,0 +1,688 @@ +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-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= +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/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +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/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= +github.com/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/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.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= +github.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs= +github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +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/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/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/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= +github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= +github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +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.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +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.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8= +github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= +github.com/ethereum/hive v0.0.0-20220202142700-64e211a795ba h1:J/zALdNL6F+ymZqpZdrUxQ8DUVAQScscQG8lwWxXv3E= +github.com/ethereum/hive v0.0.0-20220202142700-64e211a795ba/go.mod h1:xptEyWnRW33B208ZrXXvkDpnP/BCvsigi/vir2TxruM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/ferranbt/fastssz v0.0.0-20210526181520-7df50c8568f8/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM= +github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5 h1:6dVcS0LktRSyEEgldFY4N9J17WjUoiJStttH+RZj0Wo= +github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= +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 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +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 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= +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 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= +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-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sourcemap/sourcemap v2.1.3+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/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +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-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= +github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +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/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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +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.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.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/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/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +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 h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/herumi/bls-eth-go-binary v0.0.0-20210902234237-7763804ee078 h1:7V5qCWTKJ0T/9KjYo2dBFaIDEb2dvy3onu9nqOIIFDc= +github.com/herumi/bls-eth-go-binary v0.0.0-20210902234237-7763804ee078/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= +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.3-0.20220313090229-ca81a64b4204 h1:+EYBkW+dbi3F/atB+LSQZSWh7+HNrV3A/N0y6DSoy9k= +github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +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/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +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/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +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 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +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/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +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.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= +github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= +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/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/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +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/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +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/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +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/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +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-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +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 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +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 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +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_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/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/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/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= +github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= +github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w= +github.com/protolambda/bls12-381-util v0.0.0-20210812140640-b03868185758 h1:Y+nKcW05nyE1vh/lqislMgU0ZMk7Pq/hEDk72mSybTQ= +github.com/protolambda/bls12-381-util v0.0.0-20210812140640-b03868185758/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= +github.com/protolambda/eth2api v0.0.0-20220123235524-49a703ed9d94 h1:Bk93Xw5kP9mXRcxfbE2xFYxF+9pXS3qUJ+wVdOlK6/U= +github.com/protolambda/eth2api v0.0.0-20220123235524-49a703ed9d94/go.mod h1:qU7hKXIGcpnIEz+I4NmJ7sJEJRL5z36rzBfJA7gtpMs= +github.com/protolambda/go-keystorev4 v0.0.0-20210914214957-cf12d9c28a52 h1:5znmcOBjXNx2ox6KXpBRAoIuDOCw7ZV+2Xb6yZ7M0K0= +github.com/protolambda/go-keystorev4 v0.0.0-20210914214957-cf12d9c28a52/go.mod h1:Xda3KO8+DMyWaTr+LwUUpVRTB5SdFzoKu0ivXNI6p1s= +github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M= +github.com/protolambda/zrnt v0.25.0 h1:r/cmve62cBfgYM9OR+cv6aMzIO+XAvSSXriMbka3OTc= +github.com/protolambda/zrnt v0.25.0/go.mod h1:lTbFlr58RAlNRQNkaHyQmXYzaRgsdQXdmgNWalfIyEs= +github.com/protolambda/ztyp v0.2.1 h1:+rfw75/Zh8EopNlG652TGDXlLgJflj6XWxJ9yCVpJws= +github.com/protolambda/ztyp v0.2.1/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= +github.com/rauljordan/engine-proxy v0.0.0-20220505020248-4d72a091d291 h1:jZt1X6I8x95FmP3UGLVtotZnRBaq2QDr0OyAQ+RilP4= +github.com/rauljordan/engine-proxy v0.0.0-20220505020248-4d72a091d291/go.mod h1:Fu64H2/DkuM4VAt220/6Oa3sk98mRVVh8NdF1LQ90l0= +github.com/rauljordan/engine-proxy v0.0.0-20220510133143-bd0a867f46c6 h1:YID7XiMgg7iYyJHt9mOoSn38zDckcMp3pkfStWiFZbU= +github.com/rauljordan/engine-proxy v0.0.0-20220510133143-bd0a867f46c6/go.mod h1:9OVXfWYnIV+wj1/SqfdREmE5mzN/OANAgdOJRtFtvpo= +github.com/rauljordan/engine-proxy v0.0.0-20220511134016-2e057ad9d277 h1:DIenUSk9rv/jl69L5PrevX/l/fNxSusiVWhsGW2FYXQ= +github.com/rauljordan/engine-proxy v0.0.0-20220511134016-2e057ad9d277/go.mod h1:9OVXfWYnIV+wj1/SqfdREmE5mzN/OANAgdOJRtFtvpo= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= +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 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/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/shirou/gopsutil v3.21.8+incompatible h1:sh0foI8tMRlCidUJR+KzqWYWxrkuuPIGiO6Vp+KXdCU= +github.com/shirou/gopsutil v3.21.8+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.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +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 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= +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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +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/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.5.1 h1:YKwdkyA0xTBzOaP2G0DVxBnCheHGP+Y9VbKAs4K1Ess= +github.com/urfave/cli/v2 v2.5.1/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/wealdtech/go-bytesutil v1.1.1 h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc= +github.com/wealdtech/go-bytesutil v1.1.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s= +github.com/wealdtech/go-eth2-types/v2 v2.5.6 h1:Lf68vvyJbCMX8g9WysEqQBEOUn+44IUI7w3uoQtG6NQ= +github.com/wealdtech/go-eth2-types/v2 v2.5.6/go.mod h1:SX7+QxnhXGxeW8tESzJ/BSIXvoflBHUi21chqRsZ9wE= +github.com/wealdtech/go-eth2-util v1.6.5 h1:FAdcuwYagSkdDEUvYc3h/lHDvS6/lYGQLrFX11/AoNA= +github.com/wealdtech/go-eth2-util v1.6.5/go.mod h1:L0OLqIfgfYSPQAzGm1E9T3AwzCWfXu0woLGzm6vwlp4= +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/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-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-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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-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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +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-20190222072716-a9d3bda3a223/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-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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/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-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/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-20210124154548-22da62e12c0c/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +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/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +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/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +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/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +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/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20200109203555-b30bc20e4fd1 h1:iiHuQZCNgYPmFQxd3BBN/Nc5+dAwzZuq5y40s20oQw0= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= +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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= +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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/simulators/eth2/engine/helper.go b/simulators/eth2/engine/helper.go new file mode 100644 index 0000000000..29f15d136a --- /dev/null +++ b/simulators/eth2/engine/helper.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "math/big" + + "github.com/ethereum/hive/hivesim" + "github.com/ethereum/hive/simulators/eth2/engine/setup" + blsu "github.com/protolambda/bls12-381-util" +) + +type ConsensusType int + +const ( + Ethash ConsensusType = iota + Clique +) + +type testSpec struct { + Name string + About string + Run func(*hivesim.T, *testEnv, node) +} + +type testEnv struct { + Clients *ClientDefinitionsByRole + Keys []*setup.KeyDetails + Secrets *[]blsu.SecretKey +} + +type node struct { + ExecutionClient string + ConsensusClient string +} + +func (n *node) String() string { + return fmt.Sprintf("%s-%s", n.ConsensusClient, n.ExecutionClient) +} + +type config struct { + AltairForkEpoch uint64 + MergeForkEpoch uint64 + ValidatorCount uint64 + KeyTranches uint64 + SlotTime uint64 + TerminalTotalDifficulty *big.Int + + // Node configurations to launch. Each node as a proportional share of + // validators. + Nodes []node + Eth1Consensus ConsensusType +} + +func (c *config) activeFork() string { + if c.MergeForkEpoch == 0 { + return "merge" + } else if c.AltairForkEpoch == 0 { + return "altair" + } else { + return "phase0" + } +} + +func shorten(s string) string { + start := s[0:6] + end := s[62:] + return fmt.Sprintf("%s..%s", start, end) +} diff --git a/simulators/eth2/engine/main.go b/simulators/eth2/engine/main.go new file mode 100644 index 0000000000..e74ded7f99 --- /dev/null +++ b/simulators/eth2/engine/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + + "github.com/ethereum/hive/hivesim" + "github.com/ethereum/hive/simulators/eth2/engine/setup" +) + +var tests = []testSpec{ + //{Name: "transition-testnet", Run: TransitionTestnet}, + {Name: "test-rpc-error", Run: TestRPCError}, +} + +func main() { + var suite = hivesim.Suite{ + Name: "cl-test", + Description: `Run different eth2 testnets.`, + } + suite.Add(hivesim.TestSpec{ + Name: "cl-tests", + Description: "Collection of different eth2 testnet compositions and assertions.", + Run: func(t *hivesim.T) { + clientTypes, err := t.Sim.ClientTypes() + if err != nil { + t.Fatal(err) + } + c := ClientsByRole(clientTypes) + if len(c.Eth1) != 1 { + t.Fatalf("choose 1 eth1 client type") + } + if len(c.Beacon) != 1 { + t.Fatalf("choose 1 beacon client type") + } + if len(c.Validator) != 1 { + t.Fatalf("choose 1 validator client type") + } + runAllTests(t, c) + }, + }) + hivesim.MustRunSuite(hivesim.New(), suite) +} + +func runAllTests(t *hivesim.T, c *ClientDefinitionsByRole) { + mnemonic := "couple kiwi radio river setup fortune hunt grief buddy forward perfect empty slim wear bounce drift execute nation tobacco dutch chapter festival ice fog" + + // Generate validator keys to use for all tests. + keySrc := &setup.MnemonicsKeySource{ + From: 0, + To: 64, + Validator: mnemonic, + Withdrawal: mnemonic, + } + keys, err := keySrc.Keys() + if err != nil { + t.Fatal(err) + } + secrets, err := setup.SecretKeys(keys) + if err != nil { + t.Fatal(err) + } + for _, node := range c.Combinations() { + for _, test := range tests { + test := test + t.Run(hivesim.TestSpec{ + Name: fmt.Sprintf("%s-%s", test.Name, node), + Description: test.About, + Run: func(t *hivesim.T) { + env := &testEnv{c, keys, secrets} + test.Run(t, env, node) + }, + }) + } + } +} diff --git a/simulators/eth2/engine/nodes.go b/simulators/eth2/engine/nodes.go new file mode 100644 index 0000000000..2d31ab89d1 --- /dev/null +++ b/simulators/eth2/engine/nodes.go @@ -0,0 +1,94 @@ +package main + +import ( + "context" + "errors" + "fmt" + "net/http" + "time" + + "github.com/ethereum/hive/hivesim" + "github.com/ethereum/hive/simulators/eth2/engine/setup" + "github.com/protolambda/eth2api" + "github.com/protolambda/eth2api/client/nodeapi" +) + +const ( + PortUserRPC = 8545 + PortEngineRPC = 8551 + PortBeaconTCP = 9000 + PortBeaconUDP = 9000 + PortBeaconAPI = 4000 + PortBeaconGRPC = 4001 + PortMetrics = 8080 + PortValidatorAPI = 5000 +) + +// TODO: we assume the clients were configured with default ports. +// Would be cleaner to run a script in the client to get the address without assumptions + +type Eth1Node struct { + *hivesim.Client +} + +func (en *Eth1Node) UserRPCAddress() (string, error) { + return fmt.Sprintf("http://%v:%d", en.IP, PortUserRPC), nil +} + +func (en *Eth1Node) EngineRPCAddress() (string, error) { + // TODO what will the default port be? + return fmt.Sprintf("http://%v:%d", en.IP, PortEngineRPC), nil +} + +func (en *Eth1Node) MustGetEnode() string { + addr, err := en.EnodeURL() + if err != nil { + panic(err) + } + return addr +} + +type BeaconNode struct { + *hivesim.Client + API *eth2api.Eth2HttpClient +} + +func NewBeaconNode(cl *hivesim.Client) *BeaconNode { + return &BeaconNode{ + Client: cl, + API: ð2api.Eth2HttpClient{ + Addr: fmt.Sprintf("http://%s:%d", cl.IP, PortBeaconAPI), + Cli: &http.Client{}, + Codec: eth2api.JSONCodec{}, + }, + } +} + +func (bn *BeaconNode) ENR() (string, error) { + ctx, _ := context.WithTimeout(context.Background(), time.Second*10) + var out eth2api.NetworkIdentity + if err := nodeapi.Identity(ctx, bn.API, &out); err != nil { + return "", err + } + fmt.Printf("p2p addrs: %v\n", out.P2PAddresses) + fmt.Printf("peer id: %s\n", out.PeerID) + return out.ENR, nil +} + +func (bn *BeaconNode) EnodeURL() (string, error) { + return "", errors.New("beacon node does not have an discv4 Enode URL, use ENR or multi-address instead") +} + +type ValidatorClient struct { + *hivesim.Client + keys []*setup.KeyDetails +} + +func (v *ValidatorClient) ContainsKey(pk [48]byte) bool { + for _, k := range v.keys { + if k.ValidatorPubkey == pk { + return true + } + } + return false +} diff --git a/simulators/eth2/engine/prepared_testnet.go b/simulators/eth2/engine/prepared_testnet.go new file mode 100644 index 0000000000..c48deaa271 --- /dev/null +++ b/simulators/eth2/engine/prepared_testnet.go @@ -0,0 +1,260 @@ +package main + +import ( + "encoding/hex" + "fmt" + "net" + "os" + "strings" + "time" + + "github.com/holiman/uint256" + blsu "github.com/protolambda/bls12-381-util" + "github.com/protolambda/ztyp/view" + + "github.com/ethereum/hive/hivesim" + "github.com/ethereum/hive/simulators/eth2/engine/setup" + "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/configs" +) + +var depositAddress common.Eth1Address + +func init() { + _ = depositAddress.UnmarshalText([]byte("0x4242424242424242424242424242424242424242")) +} + +// PreparedTestnet has all the options for starting nodes, ready to build the network. +type PreparedTestnet struct { + // Consensus chain configuration + spec *common.Spec + + // Execution chain configuration and genesis info + eth1Genesis *setup.Eth1Genesis + // Consensus genesis state + eth2Genesis common.BeaconState + // Secret keys of validators, to fabricate extra signed test messages with during testnet/ + // E.g. to test a slashable offence that would not otherwise happen. + keys *[]blsu.SecretKey + + // Configuration to apply to every node of the given type + executionOpts hivesim.StartOption + validatorOpts hivesim.StartOption + beaconOpts hivesim.StartOption + + // A tranche is a group of validator keys to run on 1 node + keyTranches [][]*setup.KeyDetails +} + +// Build all artifacts require to start a testnet. +func prepareTestnet(t *hivesim.T, env *testEnv, config *config) *PreparedTestnet { + eth1GenesisTime := common.Timestamp(time.Now().Unix()) + eth2GenesisTime := eth1GenesisTime + 30 + + // Generate genesis for execution clients + eth1Genesis := setup.BuildEth1Genesis(config.TerminalTotalDifficulty, uint64(eth1GenesisTime), config.Eth1Consensus == Clique) + eth1ConfigOpt := eth1Genesis.ToParams(depositAddress) + eth1Bundle, err := setup.Eth1Bundle(eth1Genesis.Genesis) + if err != nil { + t.Fatal(err) + } + execNodeOpts := hivesim.Params{"HIVE_LOGLEVEL": os.Getenv("HIVE_LOGLEVEL")} + jwtSecret := hivesim.Params{"HIVE_JWTSECRET": "true"} + executionOpts := hivesim.Bundle(eth1ConfigOpt, eth1Bundle, execNodeOpts, jwtSecret) + + // Generate beacon spec + // + // TODO: specify build-target based on preset, to run clients in mainnet or minimal mode. + // copy the default mainnet config, and make some minimal modifications for testnet usage + specCpy := *configs.Mainnet + spec := &specCpy + spec.Config.DEPOSIT_CONTRACT_ADDRESS = depositAddress + spec.Config.DEPOSIT_CHAIN_ID = eth1Genesis.Genesis.Config.ChainID.Uint64() + spec.Config.DEPOSIT_NETWORK_ID = eth1Genesis.NetworkID + spec.Config.ETH1_FOLLOW_DISTANCE = 1 + + spec.Config.ALTAIR_FORK_EPOCH = common.Epoch(config.AltairForkEpoch) + spec.Config.BELLATRIX_FORK_EPOCH = common.Epoch(config.MergeForkEpoch) + spec.Config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT = config.ValidatorCount + spec.Config.SECONDS_PER_SLOT = common.Timestamp(config.SlotTime) + tdd, _ := uint256.FromBig(config.TerminalTotalDifficulty) + spec.Config.TERMINAL_TOTAL_DIFFICULTY = view.Uint256View(*tdd) + + // Generate keys opts for validators + keyTranches := setup.KeyTranches(env.Keys, uint64(len(config.Nodes))) + + consensusConfigOpts, err := setup.ConsensusConfigsBundle(spec, eth1Genesis.Genesis, config.ValidatorCount) + if err != nil { + t.Fatal(err) + } + + // prepare genesis beacon state, with all the validators in it. + state, err := setup.BuildBeaconState(spec, eth1Genesis.Genesis, eth2GenesisTime, env.Keys) + if err != nil { + t.Fatal(err) + } + + // Write info so that the genesis state can be generated by the client + stateOpt, err := setup.StateBundle(state) + if err != nil { + t.Fatal(err) + } + + // Define additional start options for beacon chain + commonOpts := hivesim.Params{ + "HIVE_ETH2_BN_API_PORT": fmt.Sprintf("%d", PortBeaconAPI), + "HIVE_ETH2_BN_GRPC_PORT": fmt.Sprintf("%d", PortBeaconGRPC), + "HIVE_ETH2_METRICS_PORT": fmt.Sprintf("%d", PortMetrics), + "HIVE_ETH2_CONFIG_DEPOSIT_CONTRACT_ADDRESS": depositAddress.String(), + } + beaconOpts := hivesim.Bundle( + commonOpts, + hivesim.Params{ + "HIVE_CHECK_LIVE_PORT": fmt.Sprintf("%d", PortBeaconAPI), + "HIVE_ETH2_MERGE_ENABLED": "1", + "HIVE_ETH2_ETH1_GENESIS_TIME": fmt.Sprintf("%d", eth1Genesis.Genesis.Timestamp), + "HIVE_ETH2_GENESIS_FORK": config.activeFork(), + }, + stateOpt, + consensusConfigOpts, + ) + + validatorOpts := hivesim.Bundle( + commonOpts, + hivesim.Params{ + "HIVE_CHECK_LIVE_PORT": "0", + }, + consensusConfigOpts, + ) + + return &PreparedTestnet{ + spec: spec, + eth1Genesis: eth1Genesis, + eth2Genesis: state, + keys: env.Secrets, + executionOpts: executionOpts, + beaconOpts: beaconOpts, + validatorOpts: validatorOpts, + keyTranches: keyTranches, + } +} + +func (p *PreparedTestnet) createTestnet(t *hivesim.T) *Testnet { + genesisTime, _ := p.eth2Genesis.GenesisTime() + genesisValidatorsRoot, _ := p.eth2Genesis.GenesisValidatorsRoot() + return &Testnet{ + t: t, + genesisTime: genesisTime, + genesisValidatorsRoot: genesisValidatorsRoot, + spec: p.spec, + eth1Genesis: p.eth1Genesis, + } +} + +func (p *PreparedTestnet) startEth1Node(testnet *Testnet, eth1Def *hivesim.ClientDefinition, consensus ConsensusType) { + testnet.t.Logf("Starting eth1 node: %s (%s)", eth1Def.Name, eth1Def.Version) + + opts := []hivesim.StartOption{p.executionOpts} + if len(testnet.eth1) == 0 { + // we only make the first eth1 node a miner + if consensus == Ethash { + opts = append(opts, hivesim.Params{"HIVE_MINER": "1212121212121212121212121212121212121212"}) + } else if consensus == Clique { + opts = append(opts, hivesim.Params{ + "HIVE_CLIQUE_PRIVATEKEY": "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c", + "HIVE_MINER": "658bdf435d810c91414ec09147daa6db62406379", + }) + } + } else { + bootnode, err := testnet.eth1[0].EnodeURL() + if err != nil { + testnet.t.Fatalf("failed to get eth1 bootnode URL: %v", err) + } + + // Make the client connect to the first eth1 node, as a bootnode for the eth1 net + opts = append(opts, hivesim.Params{"HIVE_BOOTNODE": bootnode}) + } + en := &Eth1Node{testnet.t.StartClient(eth1Def.Name, opts...)} + dest, _ := en.EngineRPCAddress() + testnet.eth1 = append(testnet.eth1, en) + simIP, err := testnet.t.Sim.ContainerNetworkIP(testnet.t.SuiteID, "bridge", "simulation") + if err != nil { + panic(err) + } + secret, err := hex.DecodeString("7365637265747365637265747365637265747365637265747365637265747365") + if err != nil { + panic(err) + } + testnet.proxies = append(testnet.proxies, NewProxy(net.ParseIP(simIP), PortEngineRPC+len(testnet.eth1), dest, secret)) +} + +func (p *PreparedTestnet) startBeaconNode(testnet *Testnet, beaconDef *hivesim.ClientDefinition, eth1Endpoints []int) { + testnet.t.Logf("Starting beacon node: %s (%s)", beaconDef.Name, beaconDef.Version) + + opts := []hivesim.StartOption{p.beaconOpts} + // Hook up beacon node to (maybe multiple) eth1 nodes + for _, index := range eth1Endpoints { + if index < 0 || index >= len(testnet.eth1) { + testnet.t.Fatalf("only have %d eth1 nodes, cannot find index %d for BN", len(testnet.eth1), index) + } + } + + var addrs []string + var engineAddrs []string + for _, index := range eth1Endpoints { + eth1Node := testnet.proxies[index] + userRPC, err := eth1Node.UserRPCAddress() + if err != nil { + testnet.t.Fatalf("eth1 node used for beacon without available RPC: %v", err) + } + addrs = append(addrs, userRPC) + engineRPC, err := eth1Node.EngineRPCAddress() + if err != nil { + testnet.t.Fatalf("eth1 node used for beacon without available RPC: %v", err) + } + engineAddrs = append(engineAddrs, engineRPC) + } + opts = append(opts, hivesim.Params{ + "HIVE_ETH2_ETH1_RPC_ADDRS": strings.Join(addrs, ","), + "HIVE_ETH2_ETH1_ENGINE_RPC_ADDRS": strings.Join(engineAddrs, ","), + }) + + if len(testnet.beacons) > 0 { + bootnodeENR, err := testnet.beacons[0].ENR() + if err != nil { + testnet.t.Fatalf("failed to get ENR as bootnode for beacon node: %v", err) + } + opts = append(opts, hivesim.Params{"HIVE_ETH2_BOOTNODE_ENRS": bootnodeENR}) + } + + // TODO + //if p.configName != "mainnet" && hasBuildTarget(beaconDef, p.configName) { + // opts = append(opts, hivesim.WithBuildTarget(p.configName)) + //} + bn := NewBeaconNode(testnet.t.StartClient(beaconDef.Name, opts...)) + testnet.beacons = append(testnet.beacons, bn) +} + +func (p *PreparedTestnet) startValidatorClient(testnet *Testnet, validatorDef *hivesim.ClientDefinition, bnIndex int, keyIndex int) { + testnet.t.Logf("Starting validator client: %s (%s)", validatorDef.Name, validatorDef.Version) + + if bnIndex >= len(testnet.beacons) { + testnet.t.Fatalf("only have %d beacon nodes, cannot find index %d for VC", len(testnet.beacons), bnIndex) + } + bn := testnet.beacons[bnIndex] + // Hook up validator to beacon node + bnAPIOpt := hivesim.Params{ + "HIVE_ETH2_BN_API_IP": bn.IP.String(), + } + if keyIndex >= len(p.keyTranches) { + testnet.t.Fatalf("only have %d key tranches, cannot find index %d for VC", len(p.keyTranches), keyIndex) + } + keysOpt := setup.KeysBundle(p.keyTranches[keyIndex]) + opts := []hivesim.StartOption{p.validatorOpts, keysOpt, bnAPIOpt} + // TODO + //if p.configName != "mainnet" && hasBuildTarget(validatorDef, p.configName) { + // opts = append(opts, hivesim.WithBuildTarget(p.configName)) + //} + vc := &ValidatorClient{testnet.t.StartClient(validatorDef.Name, opts...), p.keyTranches[keyIndex]} + testnet.validators = append(testnet.validators, vc) +} diff --git a/simulators/eth2/engine/proxies.go b/simulators/eth2/engine/proxies.go new file mode 100644 index 0000000000..730681d8e0 --- /dev/null +++ b/simulators/eth2/engine/proxies.go @@ -0,0 +1,77 @@ +package main + +import ( + "context" + "fmt" + "net" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + "github.com/rauljordan/engine-proxy/proxy" +) + +type Proxy struct { + IP net.IP + port int + proxy *proxy.Proxy + JWTSecret string + config *proxy.SpoofingConfig + + rpc *rpc.Client + mu sync.Mutex +} + +func NewProxy(hostIP net.IP, port int, destination string, jwtSecret []byte) *Proxy { + host := "0.0.0.0" + config := proxy.SpoofingConfig{} + options := []proxy.Option{ + proxy.WithHost(host), + proxy.WithPort(port), + proxy.WithDestinationAddress(destination), + proxy.WithSpoofingConfig(&config), + proxy.WithJWTSecret(jwtSecret), + } + proxy, err := proxy.New(options...) + if err != nil { + panic(err) + } + go func() { + if err := proxy.Start(context.Background()); err != nil { + panic(err) + } + }() + time.Sleep(100 * time.Millisecond) + log.Info("Starting new proxy", "host", host, "port", port) + return &Proxy{IP: hostIP, port: port, proxy: proxy, config: &config} +} + +func (p *Proxy) UserRPCAddress() (string, error) { + return fmt.Sprintf("http://%v:%d", p.IP, p.port), nil +} + +func (p *Proxy) EngineRPCAddress() (string, error) { + return fmt.Sprintf("http://%v:%d", p.IP, p.port), nil +} + +func (p *Proxy) AddRequest(spoof *proxy.Spoof) { + log.Info("Adding spoof request", "method", spoof.Method) + p.config.Requests = append(p.config.Requests, spoof) + p.proxy.UpdateSpoofingConfig(p.config) +} + +func (p *Proxy) AddResponse(spoof *proxy.Spoof) { + log.Info("Adding spoof response", "method", spoof.Method) + p.config.Responses = append(p.config.Responses, spoof) + p.proxy.UpdateSpoofingConfig(p.config) +} + +func (p *Proxy) RPC() *rpc.Client { + p.mu.Lock() + defer p.mu.Unlock() + if p.rpc == nil { + p.rpc, _ = rpc.DialHTTP(fmt.Sprintf("http://%v:%d", p.IP, p.port)) + } + return p.rpc +} diff --git a/simulators/eth2/engine/roles.go b/simulators/eth2/engine/roles.go new file mode 100644 index 0000000000..0aac41645f --- /dev/null +++ b/simulators/eth2/engine/roles.go @@ -0,0 +1,57 @@ +package main + +import "github.com/ethereum/hive/hivesim" + +type ClientDefinitionsByRole struct { + Beacon []*hivesim.ClientDefinition `json:"beacon"` + Validator []*hivesim.ClientDefinition `json:"validator"` + Eth1 []*hivesim.ClientDefinition `json:"eth1"` + Other []*hivesim.ClientDefinition `json:"Other"` +} + +func ClientsByRole(available []*hivesim.ClientDefinition) *ClientDefinitionsByRole { + var out ClientDefinitionsByRole + for _, client := range available { + if client.HasRole("beacon") { + out.Beacon = append(out.Beacon, client) + } + if client.HasRole("validator") { + out.Validator = append(out.Validator, client) + } + if client.HasRole("eth1") { + out.Eth1 = append(out.Eth1, client) + } + } + return &out +} + +func (c *ClientDefinitionsByRole) ClientByNameAndRole(name, role string) *hivesim.ClientDefinition { + switch role { + case "beacon": + return byName(c.Beacon, name) + case "validator": + return byName(c.Validator, name) + case "eth1": + return byName(c.Eth1, name) + } + return nil +} + +func byName(clients []*hivesim.ClientDefinition, name string) *hivesim.ClientDefinition { + for _, client := range clients { + if client.Name == name { + return client + } + } + return nil +} + +func (c *ClientDefinitionsByRole) Combinations() []node { + var nodes []node + for _, beacon := range c.Beacon { + for _, eth1 := range c.Eth1 { + nodes = append(nodes, node{eth1.Name, beacon.Name[:len(beacon.Name)-3]}) + } + } + return nodes +} diff --git a/simulators/eth2/engine/running_testnet.go b/simulators/eth2/engine/running_testnet.go new file mode 100644 index 0000000000..23e58d1477 --- /dev/null +++ b/simulators/eth2/engine/running_testnet.go @@ -0,0 +1,387 @@ +package main + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/hive/hivesim" + "github.com/ethereum/hive/simulators/eth2/engine/setup" + "github.com/protolambda/eth2api" + "github.com/protolambda/eth2api/client/beaconapi" + "github.com/protolambda/eth2api/client/debugapi" + "github.com/protolambda/zrnt/eth2/beacon/altair" + "github.com/protolambda/zrnt/eth2/beacon/bellatrix" + "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/beacon/phase0" + "github.com/protolambda/zrnt/eth2/util/math" +) + +var MAX_PARTICIPATION_SCORE = 7 + +type Testnet struct { + t *hivesim.T + + genesisTime common.Timestamp + genesisValidatorsRoot common.Root + + // Consensus chain configuration + spec *common.Spec + // Execution chain configuration and genesis info + eth1Genesis *setup.Eth1Genesis + + beacons []*BeaconNode + validators []*ValidatorClient + eth1 []*Eth1Node + proxies []*Proxy +} + +func startTestnet(t *hivesim.T, env *testEnv, config *config) *Testnet { + prep := prepareTestnet(t, env, config) + testnet := prep.createTestnet(t) + + genesisTime := testnet.GenesisTime() + countdown := genesisTime.Sub(time.Now()) + t.Logf("Created new testnet, genesis at %s (%s from now)", genesisTime, countdown) + + // for each key partition, we start a validator client with its own beacon node and eth1 node + for i, node := range config.Nodes { + prep.startEth1Node(testnet, env.Clients.ClientByNameAndRole(node.ExecutionClient, "eth1"), config.Eth1Consensus) + prep.startBeaconNode(testnet, env.Clients.ClientByNameAndRole(fmt.Sprintf("%s-bn", node.ConsensusClient), "beacon"), []int{i}) + prep.startValidatorClient(testnet, env.Clients.ClientByNameAndRole(fmt.Sprintf("%s-vc", node.ConsensusClient), "validator"), i, i) + } + + return testnet +} + +func (t *Testnet) GenesisTime() time.Time { + return time.Unix(int64(t.genesisTime), 0) +} + +func (t *Testnet) ValidatorClientIndex(pk [48]byte) (int, error) { + for i, v := range t.validators { + if v.ContainsKey(pk) { + return i, nil + } + } + return 0, fmt.Errorf("key not found in any validator client") +} + +// WaitForFinality blocks until a beacon client reaches finality. +func (t *Testnet) WaitForFinality(ctx context.Context) (common.Checkpoint, error) { + genesis := t.GenesisTime() + slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second + timer := time.NewTicker(slotDuration) + done := make(chan common.Checkpoint, len(t.beacons)) + + for { + select { + case <-ctx.Done(): + return common.Checkpoint{}, fmt.Errorf("context called") + case finalized := <-done: + return finalized, nil + case tim := <-timer.C: + // start polling after first slot of genesis + if tim.Before(genesis.Add(slotDuration)) { + t.t.Logf("Time till genesis: %s", genesis.Sub(tim)) + continue + } + + // new slot, log and check status of all beacon nodes + type res struct { + idx int + msg string + err error + } + var ( + wg sync.WaitGroup + ch = make(chan res, len(t.beacons)) + ) + for i, b := range t.beacons { + wg.Add(1) + go func(ctx context.Context, i int, b *BeaconNode, ch chan res) { + defer wg.Done() + ctx, cancel := context.WithTimeout(ctx, time.Second*5) + defer cancel() + + var ( + slot common.Slot + head string + justified string + finalized string + execution string + health float64 + ) + + var headInfo eth2api.BeaconBlockHeaderAndInfo + if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil { + ch <- res{err: fmt.Errorf("beacon %d: failed to poll head: %v", i, err)} + return + } else if !exists { + ch <- res{err: fmt.Errorf("beacon %d: no head block", i)} + return + } + + var checkpoints eth2api.FinalityCheckpoints + if exists, err := beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdRoot(headInfo.Header.Message.StateRoot), &checkpoints); err != nil { + ch <- res{err: fmt.Errorf("beacon %d: failed to poll finality checkpoint: %v", i, err)} + return + } else if !exists { + ch <- res{err: fmt.Errorf("beacon %d: Expected state for head block", i)} + return + } + + var versionedBlock eth2api.VersionedSignedBeaconBlock + if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(headInfo.Root), &versionedBlock); err != nil { + ch <- res{err: fmt.Errorf("beacon %d: failed to retrieve block: %v", i, err)} + return + } else if !exists { + ch <- res{err: fmt.Errorf("beacon %d: block not found", i)} + return + } + switch versionedBlock.Version { + case "phase0": + execution = "0x0000..0000" + case "altair": + execution = "0x0000..0000" + case "bellatrix": + block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock) + execution = shorten(block.Message.Body.ExecutionPayload.BlockHash.String()) + } + + slot = headInfo.Header.Message.Slot + head = shorten(headInfo.Root.String()) + justified = shorten(checkpoints.CurrentJustified.String()) + finalized = shorten(checkpoints.Finalized.String()) + health, err := getHealth(ctx, b.API, t.spec, slot) + if err != nil { + ch <- res{err: fmt.Errorf("beacon %d: %s", i, err)} + } + + ch <- res{i, fmt.Sprintf("beacon %d: slot=%d, head=%s, health=%.2f, exec_payload=%s, justified=%s, finalized=%s", i, slot, head, health, execution, justified, finalized), nil} + + ep := t.spec.SlotToEpoch(slot) + if ep > 4 && ep > checkpoints.Finalized.Epoch+2 { + ch <- res{err: fmt.Errorf("failed to finalize, head slot %d (epoch %d) is more than 2 ahead of finality checkpoint %d", slot, ep, checkpoints.Finalized.Epoch)} + } + + if (checkpoints.Finalized != common.Checkpoint{}) { + done <- checkpoints.Finalized + } + }(ctx, i, b, ch) + } + wg.Wait() + close(ch) + + // print out logs in ascending idx order + sorted := make([]string, len(t.beacons)) + for out := range ch { + if out.err != nil { + return common.Checkpoint{}, out.err + } + sorted[out.idx] = out.msg + } + for _, msg := range sorted { + t.t.Logf(msg) + } + } + } +} + +// VerifyParticipation ensures that the participation of the finialized epoch +// of a given checkpoint is above the expected threshold. +func (t *Testnet) VerifyParticipation(ctx context.Context, checkpoint common.Checkpoint, expected float64) error { + slot, _ := t.spec.EpochStartSlot(checkpoint.Epoch + 1) + if t.spec.BELLATRIX_FORK_EPOCH <= checkpoint.Epoch { + // slot-1 to target last slot in finalized epoch + slot = slot - 1 + } + for i, b := range t.beacons { + health, err := getHealth(ctx, b.API, t.spec, slot) + if err != nil { + return err + } + if health < expected { + return fmt.Errorf("beacon %d: participation not healthy (got: %.2f, expected: %.2f)", i, health, expected) + } + t.t.Logf("beacon %d: epoch=%d participation=%.2f", i, checkpoint.Epoch, health) + } + return nil +} + +// VerifyExecutionPayloadIsCanonical retrieves the execution payload from the +// finalized block and verifies that is in the execution client's canonical +// chain. +func (t *Testnet) VerifyExecutionPayloadIsCanonical(ctx context.Context, checkpoint common.Checkpoint) error { + var versionedBlock eth2api.VersionedSignedBeaconBlock + if exists, err := beaconapi.BlockV2(ctx, t.beacons[0].API, eth2api.BlockIdRoot(checkpoint.Root), &versionedBlock); err != nil { + return fmt.Errorf("beacon %d: failed to retrieve block: %v", 0, err) + } else if !exists { + return fmt.Errorf("beacon %d: block not found", 0) + } + if versionedBlock.Version != "bellatrix" { + return nil + } + payload := versionedBlock.Data.(*bellatrix.SignedBeaconBlock).Message.Body.ExecutionPayload + + for i, proxy := range t.proxies { + client := ethclient.NewClient(proxy.RPC()) + block, err := client.BlockByNumber(ctx, big.NewInt(int64(payload.BlockNumber))) + if err != nil { + return fmt.Errorf("eth1 %d: %s", 0, err) + } + if block.Hash() != [32]byte(payload.BlockHash) { + return fmt.Errorf("eth1 %d: blocks don't match (got=%s, expected=%s)", i, shorten(block.Hash().String()), shorten(payload.BlockHash.String())) + } + } + return nil +} + +// VerifyProposers checks that all validator clients have proposed a block on +// the finalized beacon chain that includes an execution payload. +func (t *Testnet) VerifyProposers(ctx context.Context, checkpoint common.Checkpoint) error { + proposers := make([]bool, len(t.beacons)) + for slot := 0; slot < int(t.spec.SLOTS_PER_EPOCH)*int(checkpoint.Epoch); slot += 1 { + var versionedBlock eth2api.VersionedSignedBeaconBlock + if exists, err := beaconapi.BlockV2(ctx, t.beacons[0].API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil { + return fmt.Errorf("beacon %d: failed to retrieve block: %v", 0, err) + } else if !exists { + return fmt.Errorf("beacon %d: block not found", 0) + } + var proposerIndex common.ValidatorIndex + switch versionedBlock.Version { + case "phase0": + block := versionedBlock.Data.(*phase0.SignedBeaconBlock) + proposerIndex = block.Message.ProposerIndex + case "altair": + block := versionedBlock.Data.(*altair.SignedBeaconBlock) + proposerIndex = block.Message.ProposerIndex + case "bellatrix": + block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock) + proposerIndex = block.Message.ProposerIndex + } + + var validator eth2api.ValidatorResponse + if exists, err := beaconapi.StateValidator(ctx, t.beacons[0].API, eth2api.StateIdSlot(slot), eth2api.ValidatorIdIndex(proposerIndex), &validator); err != nil { + return fmt.Errorf("beacon %d: failed to retrieve validator: %v", 0, err) + } else if !exists { + return fmt.Errorf("beacon %d: validator not found", 0) + } + idx, err := t.ValidatorClientIndex([48]byte(validator.Validator.Pubkey)) + if err != nil { + return fmt.Errorf("pub key not found on any validator client") + } + proposers[idx] = true + } + for i, proposed := range proposers { + if !proposed { + return fmt.Errorf("beacon %d: did not propose a block", i) + } + } + return nil +} + +func (t *Testnet) VerifyELHeads(ctx context.Context) error { + client := ethclient.NewClient(t.eth1[0].RPC()) + head, err := client.HeaderByNumber(ctx, nil) + if err != nil { + return err + } + + t.t.Logf("Verifying EL heads at %v", head.Hash()) + for i, node := range t.eth1 { + client := ethclient.NewClient(node.RPC()) + head2, err := client.HeaderByNumber(ctx, nil) + if err != nil { + return err + } + if head.Hash() != head2.Hash() { + return fmt.Errorf("different heads: %v: %v %v: %v", 0, head, i, head2) + } + } + return nil +} + +func getHealth(ctx context.Context, api *eth2api.Eth2HttpClient, spec *common.Spec, slot common.Slot) (float64, error) { + var ( + health float64 + stateInfo eth2api.VersionedBeaconState + ) + if exists, err := debugapi.BeaconStateV2(ctx, api, eth2api.StateIdSlot(slot), &stateInfo); err != nil { + return 0, fmt.Errorf("failed to retrieve state: %v", err) + } else if !exists { + return 0, fmt.Errorf("block not found") + } + switch stateInfo.Version { + case "phase0": + state := stateInfo.Data.(*phase0.BeaconState) + epoch := spec.SlotToEpoch(slot) + validatorIds := make([]eth2api.ValidatorId, 0, len(state.Validators)) + for id, validator := range state.Validators { + if epoch >= validator.ActivationEligibilityEpoch && epoch < validator.ExitEpoch && !validator.Slashed { + validatorIds = append(validatorIds, eth2api.ValidatorIdIndex(id)) + } + } + var ( + beforeEpoch = 0 + afterEpoch = spec.SlotToEpoch(slot) + balancesBefore []eth2api.ValidatorBalanceResponse + balancesAfter []eth2api.ValidatorBalanceResponse + ) + + // If it's genesis, keep before also set to 0. + if afterEpoch != 0 { + beforeEpoch = int(spec.SlotToEpoch(slot)) - 1 + } + if exists, err := beaconapi.StateValidatorBalances(ctx, api, eth2api.StateIdSlot(beforeEpoch*int(spec.SLOTS_PER_EPOCH)), validatorIds, &balancesBefore); err != nil { + return 0, fmt.Errorf("failed to retrieve validator balances: %v", err) + } else if !exists { + return 0, fmt.Errorf("validator balances not found") + } + if exists, err := beaconapi.StateValidatorBalances(ctx, api, eth2api.StateIdSlot(int(afterEpoch)*int(spec.SLOTS_PER_EPOCH)), validatorIds, &balancesAfter); err != nil { + return 0, fmt.Errorf("failed to retrieve validator balances: %v", err) + } else if !exists { + return 0, fmt.Errorf("validator balances not found") + } + health = legacyCalcHealth(spec, balancesBefore, balancesAfter) + case "altair": + state := stateInfo.Data.(*altair.BeaconState) + health = calcHealth(state.CurrentEpochParticipation) + case "bellatrix": + state := stateInfo.Data.(*bellatrix.BeaconState) + health = calcHealth(state.CurrentEpochParticipation) + } + return health, nil +} + +func calcHealth(p altair.ParticipationRegistry) float64 { + sum := 0 + for _, p := range p { + sum += int(p) + } + avg := float64(sum) / float64(len(p)) + return avg / float64(MAX_PARTICIPATION_SCORE) +} + +// legacyCalcHealth calculates the health of the network based on balances at +// the beginning of an epoch versus the balances at the end. +// +// NOTE: this isn't strictly the most correct way of doing things, but it is +// quite accurate and doesn't require implementing the attestation processing +// logic here. +func legacyCalcHealth(spec *common.Spec, before, after []eth2api.ValidatorBalanceResponse) float64 { + sum_before := big.NewInt(0) + sum_after := big.NewInt(0) + for i := range before { + sum_before.Add(sum_before, big.NewInt(int64(before[i].Balance))) + sum_after.Add(sum_after, big.NewInt(int64(after[i].Balance))) + } + count := big.NewInt(int64(len(before))) + avg_before := big.NewInt(0).Div(sum_before, count).Uint64() + avg_after := sum_after.Div(sum_after, count).Uint64() + reward := avg_before * spec.BASE_REWARD_FACTOR / math.IntegerSquareRootPrysm(sum_before.Uint64()) / spec.HYSTERESIS_QUOTIENT + return float64(avg_after-avg_before) / float64(reward*common.BASE_REWARDS_PER_EPOCH) +} diff --git a/simulators/eth2/engine/scenarios.go b/simulators/eth2/engine/scenarios.go new file mode 100644 index 0000000000..7b7900152f --- /dev/null +++ b/simulators/eth2/engine/scenarios.go @@ -0,0 +1,97 @@ +package main + +import ( + "context" + "math/big" + "time" + + "github.com/ethereum/hive/hivesim" + "github.com/rauljordan/engine-proxy/proxy" +) + +var ( + VALIDATOR_COUNT uint64 = 64 + SLOT_TIME uint64 = 3 + TERMINAL_TOTAL_DIFFICULTY = big.NewInt(100) +) + +func TransitionTestnet(t *hivesim.T, env *testEnv, n node) { + config := config{ + AltairForkEpoch: 0, + MergeForkEpoch: 0, + ValidatorCount: VALIDATOR_COUNT, + SlotTime: SLOT_TIME, + TerminalTotalDifficulty: TERMINAL_TOTAL_DIFFICULTY, + Nodes: []node{ + n, + n, + }, + Eth1Consensus: Clique, + } + + testnet := startTestnet(t, env, &config) + + ctx := context.Background() + finalized, err := testnet.WaitForFinality(ctx) + if err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyParticipation(ctx, finalized, 0.95); err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyExecutionPayloadIsCanonical(ctx, finalized); err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyProposers(ctx, finalized); err != nil { + t.Fatalf("%v", err) + } +} + +func TestRPCError(t *hivesim.T, env *testEnv, n node) { + config := config{ + AltairForkEpoch: 0, + MergeForkEpoch: 0, + ValidatorCount: VALIDATOR_COUNT, + SlotTime: SLOT_TIME, + TerminalTotalDifficulty: TERMINAL_TOTAL_DIFFICULTY, + Nodes: []node{ + n, + n, + }, + Eth1Consensus: Clique, + } + + testnet := startTestnet(t, env, &config) + + ctx := context.Background() + finalized, err := testnet.WaitForFinality(ctx) + if err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyParticipation(ctx, finalized, 0.95); err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyExecutionPayloadIsCanonical(ctx, finalized); err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyProposers(ctx, finalized); err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyELHeads(ctx); err != nil { + t.Fatalf("%v", err) + } + fields := make(map[string]interface{}) + fields["headBlockHash"] = "weird error" + spoof := &proxy.Spoof{ + Method: "engine_forkchoiceUpdatedV1", + Fields: fields, + } + testnet.proxies[0].AddRequest(spoof) + time.Sleep(24 * time.Second) + if err := testnet.VerifyParticipation(ctx, finalized, 0.95); err != nil { + t.Fatalf("%v", err) + } + if err := testnet.VerifyELHeads(ctx); err == nil { + t.Fatalf("Expected different heads after spoof %v", err) + } +} diff --git a/simulators/eth2/engine/setup/eth1config.go b/simulators/eth2/engine/setup/eth1config.go new file mode 100644 index 0000000000..c9c4eec6ab --- /dev/null +++ b/simulators/eth2/engine/setup/eth1config.go @@ -0,0 +1,137 @@ +package setup + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/hive/hivesim" +) + +// The runtime deposit contract code, along with the storage that would otherwise have been initialized +// in the deployment constructor call. +// The storage tracks the default zero-hash of each binary tree layer, to shape the initial stack of an empty tree. +var embeddedDepositContract = ` +{ + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } +} +` + +type Eth1Genesis struct { + Genesis *core.Genesis + DepositAddress common.Address + NetworkID uint64 +} + +func BuildEth1Genesis(ttd *big.Int, genesisTime uint64, clique bool) *Eth1Genesis { + depositContractAddr := common.HexToAddress("0x4242424242424242424242424242424242424242") + var depositContractAcc core.GenesisAccount + if err := json.Unmarshal([]byte(embeddedDepositContract), &depositContractAcc); err != nil { + panic(err) + } + genesis := Eth1Genesis{ + Genesis: &core.Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP150Hash: common.Hash{}, + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeForkBlock: big.NewInt(0), + TerminalTotalDifficulty: ttd, + Clique: nil, + }, + Nonce: 0, + Timestamp: genesisTime, + ExtraData: nil, + GasLimit: 30_000_000, + Difficulty: big.NewInt(0), + Mixhash: common.Hash{}, + Coinbase: common.Address{}, + Alloc: core.GenesisAlloc{ + depositContractAddr: depositContractAcc, + }, + }, + DepositAddress: depositContractAddr, + NetworkID: 1, + } + if clique { + genesis.Genesis.Config.Clique = ¶ms.CliqueConfig{Period: 2, Epoch: 0} + genesis.Genesis.ExtraData = common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + } + return &genesis +} + +func (conf *Eth1Genesis) ToParams(depositAddress [20]byte) hivesim.Params { + params := hivesim.Params{ + "HIVE_DEPOSIT_CONTRACT_ADDRESS": common.Address(depositAddress).String(), + "HIVE_NETWORK_ID": fmt.Sprintf("%d", conf.NetworkID), + "HIVE_CHAIN_ID": conf.Genesis.Config.ChainID.String(), + "HIVE_FORK_HOMESTEAD": conf.Genesis.Config.HomesteadBlock.String(), + //"HIVE_FORK_DAO_BLOCK": conf.Genesis.Config.DAOForkBlock.String(), // nil error, not used anyway + "HIVE_FORK_TANGERINE": conf.Genesis.Config.EIP150Block.String(), + "HIVE_FORK_SPURIOUS": conf.Genesis.Config.EIP155Block.String(), // also eip558 + "HIVE_FORK_BYZANTIUM": conf.Genesis.Config.ByzantiumBlock.String(), + "HIVE_FORK_CONSTANTINOPLE": conf.Genesis.Config.ConstantinopleBlock.String(), + "HIVE_FORK_PETERSBURG": conf.Genesis.Config.PetersburgBlock.String(), + "HIVE_FORK_ISTANBUL": conf.Genesis.Config.IstanbulBlock.String(), + "HIVE_FORK_MUIRGLACIER": conf.Genesis.Config.MuirGlacierBlock.String(), + "HIVE_FORK_BERLIN": conf.Genesis.Config.BerlinBlock.String(), + "HIVE_FORK_LONDON": conf.Genesis.Config.LondonBlock.String(), + "HIVE_FORK_ARROWGLACIER": conf.Genesis.Config.ArrowGlacierBlock.String(), + "HIVE_MERGE_BLOCK_ID": conf.Genesis.Config.MergeForkBlock.String(), + "HIVE_TERMINAL_TOTAL_DIFFICULTY": conf.Genesis.Config.TerminalTotalDifficulty.String(), + } + if conf.Genesis.Config.Clique != nil { + params["HIVE_CLIQUE_PERIOD"] = fmt.Sprint(conf.Genesis.Config.Clique.Period) + } + return params +} diff --git a/simulators/eth2/engine/setup/files.go b/simulators/eth2/engine/setup/files.go new file mode 100644 index 0000000000..871217ba9e --- /dev/null +++ b/simulators/eth2/engine/setup/files.go @@ -0,0 +1,79 @@ +package setup + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/hive/hivesim" + "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/ztyp/codec" + "gopkg.in/yaml.v2" +) + +func bytesSource(data []byte) func() (io.ReadCloser, error) { + return func() (io.ReadCloser, error) { + return ioutil.NopCloser(bytes.NewReader(data)), nil + } +} + +func Eth1Bundle(genesis *core.Genesis) (hivesim.StartOption, error) { + out, err := json.Marshal(genesis) + if err != nil { + return nil, fmt.Errorf("failed to serialize genesis state: %v", err) + } + return hivesim.WithDynamicFile("genesis.json", bytesSource(out)), nil +} + +func StateBundle(state common.BeaconState) (hivesim.StartOption, error) { + var stateBytes bytes.Buffer + if err := state.Serialize(codec.NewEncodingWriter(&stateBytes)); err != nil { + return nil, fmt.Errorf("failed to serialize genesis state: %v", err) + } + return hivesim.WithDynamicFile("/hive/input/genesis.ssz", bytesSource(stateBytes.Bytes())), nil +} + +func ConsensusConfigsBundle(spec *common.Spec, genesis *core.Genesis, valCount uint64) (hivesim.StartOption, error) { + config, err := yaml.Marshal(spec.Config) + if err != nil { + return nil, err + } + phase0Preset, err := yaml.Marshal(spec.Phase0Preset) + if err != nil { + return nil, err + } + altairPreset, err := yaml.Marshal(spec.AltairPreset) + if err != nil { + return nil, err + } + bellatrixPreset, err := yaml.Marshal(spec.BellatrixPreset) + if err != nil { + return nil, err + } + db := rawdb.NewMemoryDatabase() + genesisHash := genesis.ToBlock(db).Hash() + return hivesim.Bundle( + hivesim.WithDynamicFile("/hive/input/config.yaml", bytesSource(config)), + hivesim.WithDynamicFile("/hive/input/preset_phase0.yaml", bytesSource(phase0Preset)), + hivesim.WithDynamicFile("/hive/input/preset_altair.yaml", bytesSource(altairPreset)), + hivesim.WithDynamicFile("/hive/input/preset_bellatrix.yaml", bytesSource(bellatrixPreset)), + hivesim.Params{ + "HIVE_ETH2_ETH1_GENESIS_HASH": genesisHash.String(), + }, + ), nil +} + +func KeysBundle(keys []*KeyDetails) hivesim.StartOption { + opts := make([]hivesim.StartOption, 0, len(keys)*2) + for _, k := range keys { + p := fmt.Sprintf("/hive/input/keystores/0x%x/keystore.json", k.ValidatorPubkey[:]) + opts = append(opts, hivesim.WithDynamicFile(p, bytesSource(k.ValidatorKeystoreJSON))) + p = fmt.Sprintf("/hive/input/secrets/0x%x", k.ValidatorPubkey[:]) + opts = append(opts, hivesim.WithDynamicFile(p, bytesSource([]byte(k.ValidatorKeystorePass)))) + } + return hivesim.Bundle(opts...) +} diff --git a/simulators/eth2/engine/setup/genesis.go b/simulators/eth2/engine/setup/genesis.go new file mode 100644 index 0000000000..edcb742d6c --- /dev/null +++ b/simulators/eth2/engine/setup/genesis.go @@ -0,0 +1,225 @@ +package setup + +import ( + "crypto/sha256" + "fmt" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/holiman/uint256" + "github.com/protolambda/zrnt/eth2/beacon/altair" + "github.com/protolambda/zrnt/eth2/beacon/bellatrix" + "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/beacon/phase0" + "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/ztyp/tree" + "github.com/protolambda/ztyp/view" +) + +func genesisPayloadHeader(eth1GenesisBlock *types.Block, spec *common.Spec) (*common.ExecutionPayloadHeader, error) { + extra := eth1GenesisBlock.Extra() + if len(extra) > common.MAX_EXTRA_DATA_BYTES { + return nil, fmt.Errorf("extra data is %d bytes, max is %d", len(extra), common.MAX_EXTRA_DATA_BYTES) + } + if len(eth1GenesisBlock.Transactions()) != 0 { + return nil, fmt.Errorf("expected no transactions in genesis execution payload") + } + + baseFee, overflow := uint256.FromBig(eth1GenesisBlock.BaseFee()) + if overflow { + return nil, fmt.Errorf("basefee larger than 2^256-1") + } + + return &common.ExecutionPayloadHeader{ + ParentHash: common.Root(eth1GenesisBlock.ParentHash()), + FeeRecipient: common.Eth1Address(eth1GenesisBlock.Coinbase()), + StateRoot: common.Bytes32(eth1GenesisBlock.Root()), + ReceiptRoot: common.Bytes32(eth1GenesisBlock.ReceiptHash()), + LogsBloom: common.LogsBloom(eth1GenesisBlock.Bloom()), + Random: common.Bytes32{}, + BlockNumber: view.Uint64View(eth1GenesisBlock.NumberU64()), + GasLimit: view.Uint64View(eth1GenesisBlock.GasLimit()), + GasUsed: view.Uint64View(eth1GenesisBlock.GasUsed()), + Timestamp: common.Timestamp(eth1GenesisBlock.Time()), + ExtraData: extra, + BaseFeePerGas: view.Uint256View(*baseFee), + BlockHash: common.Root(eth1GenesisBlock.Hash()), + // empty transactions root + TransactionsRoot: common.PayloadTransactionsType(spec).DefaultNode().MerkleRoot(tree.GetHashFn()), + }, nil +} + +func createValidators(spec *common.Spec, keys []*KeyDetails) []phase0.KickstartValidatorData { + validators := make([]phase0.KickstartValidatorData, 0, len(keys)) + hasher := sha256.New() + withdrawalCred := func(k common.BLSPubkey) (out common.Root) { + hasher.Reset() + hasher.Write(k[:]) + dat := hasher.Sum(nil) + copy(out[:], dat) + out[0] = common.BLS_WITHDRAWAL_PREFIX + return + } + for _, key := range keys { + validators = append(validators, phase0.KickstartValidatorData{ + Pubkey: key.ValidatorPubkey, + WithdrawalCredentials: withdrawalCred(key.WithdrawalPubkey), + Balance: spec.MAX_EFFECTIVE_BALANCE, + }) + } + return validators +} + +// BuildBeaconState creates a beacon state, with either ExecutionFromGenesis or NoExecutionFromGenesis, the given timestamp, and validators derived from the given keys. +// The deposit contract will be recognized as an empty tree, ready for new deposits, thus skipping any transactions for pre-mined validators. +// +// TODO: instead of providing a eth1 genesis, provide an eth1 chain, so we can simulate a merge genesis state that embeds an existing eth1 chain. +func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisTime common.Timestamp, keys []*KeyDetails) (common.BeaconState, error) { + if uint64(len(keys)) < spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT { + return nil, fmt.Errorf("WARNING: not enough validator keys for genesis. Got %d, but need at least %d.\n", + len(keys), spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT) + } + + eth1Db := rawdb.NewMemoryDatabase() + eth1GenesisBlock := eth1Genesis.ToBlock(eth1Db) + eth1BlockHash := common.Root(eth1GenesisBlock.Hash()) + + validators := createValidators(spec, keys) + + hFn := tree.GetHashFn() + + var state common.BeaconState + var forkVersion common.Version + var emptyBodyRoot common.Root + if spec.BELLATRIX_FORK_EPOCH == 0 { + state = bellatrix.NewBeaconStateView(spec) + forkVersion = spec.BELLATRIX_FORK_VERSION + emptyBodyRoot = bellatrix.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn) + } else if spec.ALTAIR_FORK_EPOCH == 0 { + state = bellatrix.NewBeaconStateView(spec) + forkVersion = spec.ALTAIR_FORK_VERSION + emptyBodyRoot = altair.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn) + } else { + state = phase0.NewBeaconStateView(spec) + forkVersion = spec.GENESIS_FORK_VERSION + emptyBodyRoot = phase0.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn) + } + + if err := state.SetGenesisTime(eth2GenesisTime); err != nil { + return nil, err + } + + if err := state.SetFork(common.Fork{ + PreviousVersion: forkVersion, // duplicate, since there is nothing before genesis. + CurrentVersion: forkVersion, + Epoch: common.GENESIS_EPOCH, + }); err != nil { + return nil, err + } + // Empty deposit-tree + eth1Dat := common.Eth1Data{ + DepositRoot: phase0.NewDepositRootsView().HashTreeRoot(tree.GetHashFn()), + DepositCount: 0, + BlockHash: eth1BlockHash, + } + if err := state.SetEth1Data(eth1Dat); err != nil { + return nil, err + } + // sanity check: Leave the deposit index to 0. No deposits happened. + if i, err := state.Eth1DepositIndex(); err != nil { + return nil, err + } else if i != 0 { + return nil, fmt.Errorf("expected 0 deposit index in state, got %d", i) + } + if err := state.SetLatestBlockHeader(&common.BeaconBlockHeader{BodyRoot: emptyBodyRoot}); err != nil { + return nil, err + } + // Seed RANDAO with Eth1 entropy + if err := state.SeedRandao(spec, eth1BlockHash); err != nil { + return nil, err + } + + for _, v := range validators { + if err := state.AddValidator(spec, v.Pubkey, v.WithdrawalCredentials, v.Balance); err != nil { + return nil, err + } + } + vals, err := state.Validators() + if err != nil { + return nil, err + } + // Process activations + for i := 0; i < len(validators); i++ { + val, err := vals.Validator(common.ValidatorIndex(i)) + if err != nil { + return nil, err + } + vEff, err := val.EffectiveBalance() + if err != nil { + return nil, err + } + if vEff == spec.MAX_EFFECTIVE_BALANCE { + if err := val.SetActivationEligibilityEpoch(common.GENESIS_EPOCH); err != nil { + return nil, err + } + if err := val.SetActivationEpoch(common.GENESIS_EPOCH); err != nil { + return nil, err + } + } + } + if err := state.SetGenesisValidatorsRoot(vals.HashTreeRoot(tree.GetHashFn())); err != nil { + return nil, err + } + if st, ok := state.(common.SyncCommitteeBeaconState); ok { + indicesBounded, err := common.LoadBoundedIndices(vals) + if err != nil { + return nil, err + } + active := common.ActiveIndices(indicesBounded, common.GENESIS_EPOCH) + indices, err := common.ComputeSyncCommitteeIndices(spec, state, common.GENESIS_EPOCH, active) + if err != nil { + return nil, fmt.Errorf("failed to compute sync committee indices: %v", err) + } + pubs, err := common.NewPubkeyCache(vals) + if err != nil { + return nil, err + } + // Note: A duplicate committee is assigned for the current and next committee at genesis + syncCommittee, err := common.IndicesToSyncCommittee(indices, pubs) + if err != nil { + return nil, err + } + syncCommitteeView, err := syncCommittee.View(spec) + if err != nil { + return nil, err + } + if err := st.SetCurrentSyncCommittee(syncCommitteeView); err != nil { + return nil, err + } + if err := st.SetNextSyncCommittee(syncCommitteeView); err != nil { + return nil, err + } + } + + if st, ok := state.(*bellatrix.BeaconStateView); ok { + // did we hit the TTD at genesis block? + tdd := uint256.Int(spec.TERMINAL_TOTAL_DIFFICULTY) + embedExecAtGenesis := tdd.ToBig().Cmp(eth1Genesis.Difficulty) < 0 + + var execPayloadHeader *common.ExecutionPayloadHeader + if embedExecAtGenesis { + execPayloadHeader, err = genesisPayloadHeader(eth1GenesisBlock, spec) + } else { + // we didn't build any on the eth1 chain though, + // so we just put the genesis hash here (it could be any block from eth1 chain before TTD that is not ahead of eth2) + execPayloadHeader = new(common.ExecutionPayloadHeader) + } + + if err := st.SetLatestExecutionPayloadHeader(execPayloadHeader); err != nil { + return nil, err + } + } + + return state, nil +} diff --git a/simulators/eth2/engine/setup/validator_keys.go b/simulators/eth2/engine/setup/validator_keys.go new file mode 100644 index 0000000000..f6d54844bf --- /dev/null +++ b/simulators/eth2/engine/setup/validator_keys.go @@ -0,0 +1,200 @@ +package setup + +import ( + "crypto/rand" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + + blsu "github.com/protolambda/bls12-381-util" + + "github.com/google/uuid" + hbls "github.com/herumi/bls-eth-go-binary/bls" + "github.com/pkg/errors" + "github.com/protolambda/go-keystorev4" + "github.com/tyler-smith/go-bip39" + util "github.com/wealdtech/go-eth2-util" +) + +// TODO: replace wealdtech util with more minimal key derivation lib, can then also remove herumi BLS +func init() { + if err := hbls.Init(hbls.BLS12_381); err != nil { + panic(err) + } + if err := hbls.SetETHmode(hbls.EthModeLatest); err != nil { + panic(err) + } +} + +type KeyDetails struct { + // ValidatorKeystoreJSON encodes an EIP-2335 keystore, serialized in JSON + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2335.md + ValidatorKeystoreJSON []byte + // ValidatorKeystorePass holds the secret used for ValidatorKeystoreJSON + ValidatorKeystorePass string + // ValidatorSecretKey is the serialized secret key for validator duties + ValidatorSecretKey [32]byte + // ValidatorSecretKey is the serialized pubkey derived from ValidatorSecretKey + ValidatorPubkey [48]byte + // WithdrawalSecretKey is the serialized secret key for withdrawing stake + WithdrawalSecretKey [32]byte + // WithdrawalPubkey is the serialized pubkey derived from WithdrawalSecretKey + WithdrawalPubkey [48]byte +} + +// MnemonicsKeySource creates a range of BLS validator and withdrawal keys. +// "m/12381/3600/%d/0/0" path for validator keys +// "m/12381/3600/%d/0" path for withdrawal keys +type MnemonicsKeySource struct { + // From account range start, inclusive + From uint64 `yaml:"from"` + // To account range end, exclusive + To uint64 `yaml:"to"` + // Validator mnemonic + Validator string `yaml:"validator"` + // Withdrawal mnemonic + Withdrawal string `yaml:"withdrawal"` + + // cache loaded validator details + cache []*KeyDetails `yaml:"-"` +} + +func mnemonicToSeed(mnemonic string) (seed []byte, err error) { + mnemonic = strings.TrimSpace(mnemonic) + if !bip39.IsMnemonicValid(mnemonic) { + return nil, errors.New("mnemonic is not valid") + } + return bip39.NewSeed(mnemonic, ""), nil +} + +func weakKeystore(secret []byte, pub []byte, passphrase []byte) (*keystorev4.Keystore, error) { + var salt [32]byte + if _, err := rand.Read(salt[:]); err != nil { + return nil, err + } + kdfParams := &keystorev4.PBKDF2Params{ + Dklen: 32, + C: 2, // INSECURE but much faster, this is an ephemeral testnet + Prf: "hmac-sha256", + Salt: salt[:], + } + cipherParams, err := keystorev4.NewAES128CTRParams() + if err != nil { + return nil, fmt.Errorf("failed to create AES128CTR params: %w", err) + } + crypto, err := keystorev4.Encrypt(secret, passphrase, kdfParams, keystorev4.Sha256ChecksumParams, cipherParams) + if err != nil { + return nil, fmt.Errorf("failed to encrypt secret: %w", err) + } + id, err := uuid.NewUUID() + if err != nil { + return nil, fmt.Errorf("failed to generate UUID: %w", err) + } + return &keystorev4.Keystore{ + Crypto: *crypto, + Description: "", + Pubkey: pub, + Path: "", + UUID: id, + Version: 4, + }, nil +} + +// Same crypto, but not secure, for testing only! +// Just generate weak keystores, so encryption and decryption doesn't take as long during testing. +func marshalWeakKeystoreJSON(priv []byte, pub []byte, normedPass []byte) ([]byte, error) { + store, err := weakKeystore(priv, pub, normedPass) + if err != nil { + return nil, fmt.Errorf("failed to encrypt keystore: %v", err) + } + return json.MarshalIndent(store, "", " ") +} + +func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) { + if k.cache != nil { + return k.cache, nil + } + valSeed, err := mnemonicToSeed(k.Validator) + if err != nil { + return nil, fmt.Errorf("bad validator seed: %w", err) + } + withdrSeed, err := mnemonicToSeed(k.Withdrawal) + if err != nil { + return nil, fmt.Errorf("bad validator seed: %w", err) + } + if k.From > k.To { + return nil, fmt.Errorf("invalid key range: from %d > to %d", k.From, k.To) + } + out := make([]*KeyDetails, 0, k.To-k.From) + for i := k.From; i < k.To; i++ { + path := fmt.Sprintf("m/12381/3600/%d/0/0", i) + valPrivateKey, err := util.PrivateKeyFromSeedAndPath(valSeed, path) + if err != nil { + return nil, errors.Wrapf(err, "failed to create validator private key for path %q", path) + } + path = fmt.Sprintf("m/12381/3600/%d/0", i) + withdrPrivateKey, err := util.PrivateKeyFromSeedAndPath(withdrSeed, path) + if err != nil { + return nil, errors.Wrapf(err, "failed to create withdrawal private key for path %q", path) + } + var passRandomness [32]byte + _, err = rand.Read(passRandomness[:]) + if err != nil { + return nil, fmt.Errorf("failed to generate keystore password: %w", err) + } + priv := valPrivateKey.Marshal() + if len(priv) != 32 { + return nil, fmt.Errorf("expected priv key of 32 bytes, got: %x", priv) // testing, we can log privs. + } + pub := valPrivateKey.PublicKey().Marshal() + if len(pub) != 48 { + return nil, fmt.Errorf("expected pub key of 48 bytes, got: %x", pub) // testing, we can log privs. + } + wPriv := withdrPrivateKey.Marshal() + if len(priv) != 32 { + return nil, fmt.Errorf("expected priv key of 32 bytes, got: %x", priv) // testing, we can log privs. + } + wPub := withdrPrivateKey.PublicKey().Marshal() + if len(pub) != 48 { + return nil, fmt.Errorf("expected pub key of 48 bytes, got: %x", pub) // testing, we can log privs. + } + // We don't have fancy password norming, just use a base64 pass instead. + passphrase := base64.URLEncoding.EncodeToString(passRandomness[:]) + jsonData, err := marshalWeakKeystoreJSON(priv, pub, []byte(passphrase)) + k := &KeyDetails{ + ValidatorKeystoreJSON: jsonData, + ValidatorKeystorePass: passphrase, + } + copy(k.ValidatorPubkey[:], pub) + copy(k.ValidatorSecretKey[:], priv) + copy(k.WithdrawalPubkey[:], wPub) + copy(k.WithdrawalSecretKey[:], wPriv) + + out = append(out, k) + } + k.cache = out + return out, nil +} + +func SecretKeys(keys []*KeyDetails) (*[]blsu.SecretKey, error) { + secrets := make([]blsu.SecretKey, len(keys)) + for i := 0; i < len(keys); i++ { + if err := secrets[i].Deserialize(&keys[i].ValidatorSecretKey); err != nil { + return nil, fmt.Errorf("validator %d has invalid key: %v", i, err) + } + } + return &secrets, nil +} + +func KeyTranches(keys []*KeyDetails, keyTranches uint64) [][]*KeyDetails { + tranches := make([][]*KeyDetails, 0, keyTranches) + valCount := uint64(len(keys)) + for i := uint64(0); i < keyTranches; i++ { + // Give each validator client an equal subset of the genesis validator keys + startIndex := valCount * i / keyTranches + endIndex := valCount * (i + 1) / keyTranches + tranches = append(tranches, keys[startIndex:endIndex]) + } + return tranches +}