diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..12b7a27 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,108 @@ +name: Release cw-relayer and contracts + +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - "secret-v[0-9]+\\.[0-9]+\\.[0-9]+" # Official release version tags e.g. v2.0.5 + - "secret-v[0-9]+\\.[0-9]+\\.[0-9]+-rc[0-9]+" # Release candidate tags e.g. v1.0.3-rc4 + - "secret-v[0-9]+\\.[0-9]+\\.[0-9]+-alpha[0-9]+" # Alpha release testing tags e.g. v0.0.3-alpha1 + +permissions: + contents: write + id-token: write + +jobs: + contract: + runs-on: ubuntu-latest + steps: + - name: Set env + run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/*}" >> $GITHUB_ENV + + - uses: actions/checkout@v3 + - name: Install latest stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + ref: ${{ env.BRANCH_NAME }} + + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/*}" >> $GITHUB_ENV + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Generate Cargo.lock + run: | + cargo fetch --verbose --manifest-path ./cosmwasm/Cargo.toml + - name: Build/Release Artifacts + if: startsWith(github.ref, 'refs/tags/') + run: | + docker run --rm -v "$(pwd)/cosmwasm":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/workspace-optimizer:0.12.7 + tar -zcvf cosmwasm-artifacts-${{ env.RELEASE_VERSION }}.tar.gz cosmwasm/artifacts + - name: Release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + files: | + cosmwasm-artifacts-${{ env.RELEASE_VERSION }}.tar.gz + + goreleaser: + strategy: + matrix: + os: [ubuntu-latest, ubuntu-20.04] + runs-on: ${{matrix.os}} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-go@v4 + with: + go-version: 1.19 + cache: true + cache-dependency-path: cw-relayer/go.sum + + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/*}" >> $GITHUB_ENV + + - name: Check GLIBC version + if: startsWith(matrix.os, 'ubuntu-') + run: | + echo "GLIBC_VERSION=$(ldd --version | grep ldd | awk '{print $NF}')" >> $GITHUB_ENV + + # Ref: https://goreleaser.com/limitations/semver + - name: Tag without prefix locally to avoid error in goreleaser + run: |- + git tag -d ${{ env.RELEASE_VERSION }} || echo "No such a tag exists before" + git tag ${{ env.RELEASE_VERSION }} HEAD + + - name: Build + uses: goreleaser/goreleaser-action@v4 + if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'Enable:ReleaseBuild') + with: + version: latest + args: build --rm-dist --skip-validate # skip validate skips initial sanity checks in order to be able to fully run + env: + GORELEASER_CURRENT_TAG: ${{ env.RELEASE_VERSION }} + GLIBC_VERSION: ${{ env.GLIBC_VERSION }} + + - name: release + if: startsWith(github.ref, 'refs/tags/') + uses: goreleaser/goreleaser-action@v4 + with: + # Note, we have to pin to v0.179.0 due to newer releases enforcing + # correct semantic versioning even when '--skip-validate' is provided. + # + # Ref: https://github.com/goreleaser/goreleaser/pull/2503 + version: v0.179.0 + args: release --rm-dist --skip-validate + workdir: cw-relayer + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GORELEASER_CURRENT_TAG: ${{ env.RELEASE_VERSION }} + GLIBC_VERSION: ${{ env.GLIBC_VERSION }} + BRANCH_NAME: ${{ env.BRANCH_NAME }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 50add57..6a9604b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -cosmwasm/* +cosmwasm/artifacts +cosmwasm/target cw-relayer/build \ No newline at end of file diff --git a/Makefile b/Makefile index a9310ad..9b2510f 100644 --- a/Makefile +++ b/Makefile @@ -35,4 +35,7 @@ test-unit-contract: compile-contract: cosmwasm/scripts/build_artifacts.sh -.PHONY: test-e2e \ No newline at end of file +compile-contract-arm: + cosmwasm/scripts/build_artifacts_arm.sh + +.PHONY: test-e2e compile-contract-arm compile-contract \ No newline at end of file diff --git a/cosmwasm/Cargo.lock b/cosmwasm/Cargo.lock index d764bd0..f1a3379 100644 --- a/cosmwasm/Cargo.lock +++ b/cosmwasm/Cargo.lock @@ -761,7 +761,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "std-reference" -version = "0.1.0" +version = "0.0.2" dependencies = [ "base64", "cosmwasm-schema", diff --git a/cosmwasm/contracts/price-feed/Cargo.toml b/cosmwasm/contracts/price-feed/Cargo.toml index 5688ffe..8371b0f 100644 --- a/cosmwasm/contracts/price-feed/Cargo.toml +++ b/cosmwasm/contracts/price-feed/Cargo.toml @@ -2,7 +2,7 @@ authors = ["ojonetwork"] edition = "2021" name = "std-reference" -version = "0.1.0" +version = "0.0.2" exclude = [ "contract.wasm", diff --git a/cosmwasm/scripts/build_artifacts_arm.sh b/cosmwasm/scripts/build_artifacts_arm.sh new file mode 100644 index 0000000..a1a0f1e --- /dev/null +++ b/cosmwasm/scripts/build_artifacts_arm.sh @@ -0,0 +1,4 @@ +docker run --rm -v "$(pwd)/cosmwasm":/code \ +--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ +--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ +cosmwasm/workspace-optimizer-arm64:0.12.7 \ No newline at end of file diff --git a/cw-relayer/.goreleaser.yml b/cw-relayer/.goreleaser.yml new file mode 100644 index 0000000..384f704 --- /dev/null +++ b/cw-relayer/.goreleaser.yml @@ -0,0 +1,50 @@ +project_name: secret-cw-relayer + +env: + - CGO_ENABLED=1 + +before: + hooks: + - go mod download + +builds: + - main: ./ + id: "secret-cw-relayer" + binary: secret-cw-relayer + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + ldflags: + - -s -w -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X github.com/ojo-network/contracts/cmd.Version={{ replace .Version "cw-relayer/" "cw-relayer-" }} -X github.com/ojo-network/contracts/cmd.Commit={{ .Commit }} + goos: + - linux + goarch: + - amd64 + +archives: + - id: bin + format: binary + name_template: "{{ .Binary }}-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}-glibc-{{.Env.GLIBC_VERSION}}" + + - id: tarball + format: tar.gz + wrap_in_directory: true + format_overrides: + - goos: windows + format: zip + name_template: '{{ .Binary }}-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}-glibc-{{.Env.GLIBC_VERSION}}' + files: + - README.md + +release: + disable: false + +snapshot: + name_template: SNAPSHOT-{{ .Commit }} + +checksum: + name_template: 'SHA256SUMS-{{ replace .Version "version/" "cw-relayer-version-" }}-glibc-{{.Env.GLIBC_VERSION}}.txt' + algorithm: sha256 + +changelog: + skip: false \ No newline at end of file diff --git a/cw-relayer/cmd/cw-relayer.go b/cw-relayer/cmd/cw-relayer.go index 706aee1..148460e 100644 --- a/cw-relayer/cmd/cw-relayer.go +++ b/cw-relayer/cmd/cw-relayer.go @@ -178,14 +178,19 @@ func cwRelayerCmdHandler(cmd *cobra.Command, args []string) error { cfg.MedianRequestID, cfg.DeviationRequestID, cfg.MedianDuration, + cfg.DeviationDuration, + cfg.SkipNumEvents, + cfg.IgnoreMedianErrors, relayer.AutoRestartConfig{AutoRestart: cfg.Restart.AutoID, Denom: cfg.Restart.Denom, SkipError: cfg.Restart.SkipError}, tick.Tick, ) - g.Go(func() error { - // start the process that queries the prices on Ojo & submits them on Wasmd - return startPriceRelayer(ctx, logger, newRelayer) - }) + g.Go( + func() error { + // start the process that queries the prices on Ojo & submits them on Wasmd + return startPriceRelayer(ctx, logger, newRelayer) + }, + ) // Block main process until all spawned goroutines have gracefully exited and // signal has been captured in the main process or if an error occurs. diff --git a/cw-relayer/config.toml b/cw-relayer/config.toml index e7e7d91..326695c 100644 --- a/cw-relayer/config.toml +++ b/cw-relayer/config.toml @@ -25,6 +25,8 @@ median_request_id = 1 request_id = 1 deviation_request_id = 1 median_duration = 1 +deviation_duration = 1 +ignore_median_errors= false gas_prices = "0.15uscrt" diff --git a/cw-relayer/config/config.go b/cw-relayer/config/config.go index bdc6e87..23c99e7 100644 --- a/cw-relayer/config/config.go +++ b/cw-relayer/config/config.go @@ -47,9 +47,16 @@ type ( DeviationRequestID uint64 `mapstructure:"deviation_request_id"` // force relay prices and reset epoch time in contracts if err in broadcasting tx - MissedThreshold int64 `mapstructure:"missed_threshold"` - ResolveDuration string `mapstructure:"resolve_duration"` - MedianDuration int64 `mapstructure:"median_duration"` + MissedThreshold int64 `mapstructure:"missed_threshold"` + ResolveDuration string `mapstructure:"resolve_duration"` + MedianDuration int64 `mapstructure:"median_duration"` + DeviationDuration int64 `mapstructure:"deviation_duration"` + + // skip price update events + SkipNumEvents int64 `mapstructure:"skip_num_events"` + + // if true, would ignore any errors when querying median or deviations + IgnoreMedianErrors bool `mapstructure:"ignore_median_errors"` GasPrices string `mapstructure:"gas_prices" validate:"required"` GasLimit uint64 `mapstructure:"gas_limit" validate:"required"` diff --git a/cw-relayer/go.mod b/cw-relayer/go.mod index 1168c7b..95ace1d 100644 --- a/cw-relayer/go.mod +++ b/cw-relayer/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/cosmos/cosmos-sdk v0.46.12 - github.com/go-playground/validator/v10 v10.11.1 + github.com/go-playground/validator/v10 v10.4.1 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.3 github.com/golangci/golangci-lint v1.52.2 @@ -91,8 +91,8 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.1.0 // indirect @@ -152,7 +152,7 @@ require ( github.com/kyoh86/exportloopref v0.1.11 // indirect github.com/ldez/gomoddirectives v0.2.3 // indirect github.com/ldez/tagliatelle v0.4.0 // indirect - github.com/leodido/go-urn v1.2.1 // indirect + github.com/leodido/go-urn v1.2.0 // indirect github.com/leonklingele/grouper v1.1.1 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect diff --git a/cw-relayer/go.sum b/cw-relayer/go.sum index c041b11..75a966b 100644 --- a/cw-relayer/go.sum +++ b/cw-relayer/go.sum @@ -176,7 +176,6 @@ github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daixiang0/gci v0.10.1 h1:eheNA3ljF6SxnPD/vE4lCBusVHmV3Rs3dkKvFrJ7MR0= @@ -257,12 +256,12 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= @@ -494,13 +493,10 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 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/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g= @@ -511,8 +507,8 @@ github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUc github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.4.0 h1:sylp7d9kh6AdXN2DpVGHBRb5guTVAgOxqNGhbqc4b1c= github.com/ldez/tagliatelle v0.4.0/go.mod h1:mNtTfrHy2haaBAw+VT7IBV6VXBThS7TCreYWbBcJ87I= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= @@ -613,7 +609,6 @@ github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvI github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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= @@ -670,8 +665,6 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -845,7 +838,6 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= @@ -936,7 +928,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1029,7 +1020,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1264,7 +1254,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= diff --git a/cw-relayer/relayer/client/chain_subscribe.go b/cw-relayer/relayer/client/chain_subscribe.go index 28916cc..b0da3e7 100644 --- a/cw-relayer/relayer/client/chain_subscribe.go +++ b/cw-relayer/relayer/client/chain_subscribe.go @@ -38,7 +38,7 @@ func NewBlockHeightSubscription( ) (*EventSubscribe, error) { newEvent := &EventSubscribe{ logger: logger.With().Str("event", tickEventType).Logger(), - Tick: make(chan struct{}), + Tick: make(chan struct{}, 100), timeout: timeout, maxTickTimeout: maxTickTimeout, rpcAddress: rpcAddress, diff --git a/cw-relayer/relayer/relayer.go b/cw-relayer/relayer/relayer.go index c718920..d5f8328 100644 --- a/cw-relayer/relayer/relayer.go +++ b/cw-relayer/relayer/relayer.go @@ -25,7 +25,10 @@ import ( var ( // RateFactor is used to convert ojo prices to contract-compatible values. - RateFactor = types.NewDec(10).Power(9) + RateFactor = types.NewDec(10).Power(9) + noRates = fmt.Errorf("no rates found") + noMedians = fmt.Errorf("median deviations empty") + noDeviations = fmt.Errorf("deviation deviations empty") ) // Relayer defines a structure that queries prices from ojo and publishes prices to wasm contract. @@ -51,13 +54,17 @@ type Relayer struct { queryTimeout time.Duration // if missedCounter >= missedThreshold, force relay prices (bypasses timing restrictions) - missedCounter int64 - missedThreshold int64 - timeoutHeight int64 - medianDuration int64 - maxQueryRetries int64 - queryRetries int64 - index int + missedCounter int64 + missedThreshold int64 + timeoutHeight int64 + medianDuration int64 + deviationDuration int64 + maxQueryRetries int64 + queryRetries int64 + skipNumEvents int64 + index int + + ignoreMedianErrors bool iopubkey []byte @@ -87,6 +94,9 @@ func New( medianRequestID uint64, deviationRequestID uint64, medianDuration int64, + deviationDuration int64, + skipNumEvents int64, + ignoreMedianErrors bool, config AutoRestartConfig, event chan struct{}, ) *Relayer { @@ -107,7 +117,10 @@ func New( closer: psync.NewCloser(), codeHash: codeHash, medianDuration: medianDuration, + deviationDuration: deviationDuration, + ignoreMedianErrors: ignoreMedianErrors, resolveDuration: resolveDuration, + skipNumEvents: skipNumEvents, requestID: requestID, medianRequestID: medianRequestID, deviationRequestID: deviationRequestID, @@ -151,12 +164,22 @@ func (r *Relayer) Start(ctx context.Context) error { Uint64("deviation request id", r.deviationRequestID).Msg("relayer state startup successful") } + epoch := int64(-1) + skipEvents := r.skipNumEvents > 0 + r.skipNumEvents++ for { select { case <-ctx.Done(): r.closer.Close() + return nil case <-r.event: + epoch++ + if skipEvents && epoch%r.skipNumEvents != 0 { + r.logger.Debug().Int64("epoch", epoch).Msg("skipping events") + continue + } + r.logger.Debug().Msg("relayer tick") startTime := time.Now() if err := r.tick(ctx); err != nil { @@ -190,7 +213,14 @@ func (r *Relayer) restart(ctx context.Context) error { return err } - responses, err := r.relayerClient.BroadcastContractQuery(ctx, r.iopubkey, r.codeHash, r.contractAddress, r.queryTimeout, queryMsgs...) + responses, err := r.relayerClient.BroadcastContractQuery( + ctx, + r.iopubkey, + r.codeHash, + r.contractAddress, + r.queryTimeout, + queryMsgs..., + ) if err != nil { return err } @@ -224,10 +254,10 @@ func (r *Relayer) restart(ctx context.Context) error { return nil } -func (r *Relayer) setDenomPrices(ctx context.Context, postMedian bool) error { +func (r *Relayer) setDenomPrices(ctx context.Context, postMedian, postDeviation bool) error { if r.queryRetries > r.maxQueryRetries { r.queryRetries = 0 - return fmt.Errorf("retry threshold exceeded") + return noRates } grpcConn, err := grpc.Dial( @@ -240,7 +270,7 @@ func (r *Relayer) setDenomPrices(ctx context.Context, postMedian bool) error { // retry or switch rpc if err != nil { r.increment() - return r.setDenomPrices(ctx, postMedian) + return r.setDenomPrices(ctx, postMedian, postDeviation) } defer grpcConn.Close() @@ -256,7 +286,7 @@ func (r *Relayer) setDenomPrices(ctx context.Context, postMedian bool) error { if err != nil || queryResponse.ExchangeRates.Empty() { r.logger.Debug().Msg("error querying exchange rates") r.increment() - return r.setDenomPrices(ctx, postMedian) + return r.setDenomPrices(ctx, postMedian, postDeviation) } r.exchangeRates = queryResponse.ExchangeRates @@ -264,50 +294,56 @@ func (r *Relayer) setDenomPrices(ctx context.Context, postMedian bool) error { var mu sync.Mutex g, _ := errgroup.WithContext(ctx) - g.Go(func() error { - deviationsQueryResponse, err := queryClient.MedianDeviations(ctx, &oracletypes.QueryMedianDeviations{}) - if err != nil { - return err - } - - if len(deviationsQueryResponse.MedianDeviations) == 0 { - return fmt.Errorf("median deviations empty") - } - - deviations := make([]types.DecCoin, len(deviationsQueryResponse.MedianDeviations)) - for i, priceStamp := range deviationsQueryResponse.MedianDeviations { - deviations[i] = *priceStamp.ExchangeRate - } - - mu.Lock() - r.historicalDeviations = deviations - mu.Unlock() - - return nil - }) + if postDeviation { + g.Go( + func() error { + deviationsQueryResponse, err := queryClient.MedianDeviations(ctx, &oracletypes.QueryMedianDeviations{}) + if err != nil { + return err + } + + if len(deviationsQueryResponse.MedianDeviations) == 0 { + return noDeviations + } + + deviations := make([]types.DecCoin, len(deviationsQueryResponse.MedianDeviations)) + for i, priceStamp := range deviationsQueryResponse.MedianDeviations { + deviations[i] = *priceStamp.ExchangeRate + } + + mu.Lock() + r.historicalDeviations = deviations + mu.Unlock() + + return nil + }, + ) + } if postMedian { - g.Go(func() error { - medianQueryResponse, err := queryClient.Medians(ctx, &oracletypes.QueryMedians{}) - if err != nil { - return err - } - - if len(medianQueryResponse.Medians) == 0 { - return fmt.Errorf("median rates empty") - } - - medians := make([]types.DecCoin, len(medianQueryResponse.Medians)) - for i, priceStamp := range medianQueryResponse.Medians { - medians[i] = *priceStamp.ExchangeRate - } - - mu.Lock() - r.historicalMedians = medians - mu.Unlock() - - return nil - }) + g.Go( + func() error { + medianQueryResponse, err := queryClient.Medians(ctx, &oracletypes.QueryMedians{}) + if err != nil { + return err + } + + if len(medianQueryResponse.Medians) == 0 { + return noMedians + } + + medians := make([]types.DecCoin, len(medianQueryResponse.Medians)) + for i, priceStamp := range medianQueryResponse.Medians { + medians[i] = *priceStamp.ExchangeRate + } + + mu.Lock() + r.historicalMedians = medians + mu.Unlock() + + return nil + }, + ) } return g.Wait() @@ -339,9 +375,27 @@ func (r *Relayer) tick(ctx context.Context) error { postMedian = r.requestID%uint64(r.medianDuration) == 0 } - if err := r.setDenomPrices(ctx, postMedian); err != nil { + var postDeviation bool + if r.deviationDuration > 0 { + postDeviation = r.requestID%uint64(r.deviationDuration) == 0 + } + + err = r.setDenomPrices(ctx, postMedian, postDeviation) + switch err { + case nil: + break + case noMedians, noDeviations: + if !r.ignoreMedianErrors { + return err + } + + // as median and deviation are not properly set, do not push prices to contract + postMedian = false + postDeviation = false + default: return err } + nextBlockHeight := blockHeight + 1 forceRelay := r.missedCounter >= r.missedThreshold @@ -353,22 +407,50 @@ func (r *Relayer) tick(ctx context.Context) error { return err } - deviationMsg, err := generateContractRelayMsg(forceRelay, RelayHistoricalDeviation, r.deviationRequestID, nextBlockTime, r.historicalDeviations) - if err != nil { - return err - } + dataMsgs := [][]byte{rateMsg} + + logs := r.logger.Info() + logs.Str("contract address", r.contractAddress). + Str("relayer address", r.relayerClient.RelayerAddrString). + Str("block timestamp", blockTimestamp.String()). + Bool("median posted", postMedian). + Bool("deviation posted", postDeviation). + Uint64("request id", r.requestID) + + if postDeviation { + resolveTime := time.Duration(r.resolveDuration.Nanoseconds() * r.deviationDuration) + nextDeviationBlockTime := blockTimestamp.Add(resolveTime).Unix() + deviationMsg, err := generateContractRelayMsg( + forceRelay, + RelayHistoricalDeviation, + r.deviationRequestID, + nextDeviationBlockTime, + r.historicalDeviations, + ) + if err != nil { + return err + } - dataMsgs := [][]byte{rateMsg, deviationMsg} + dataMsgs = append(dataMsgs, deviationMsg) + logs.Uint64("deviation request id", r.deviationRequestID) + } if postMedian { resolveTime := time.Duration(r.resolveDuration.Nanoseconds() * r.medianDuration) nextMedianBlockTime := blockTimestamp.Add(resolveTime).Unix() - medianMsg, err := generateContractRelayMsg(forceRelay, RelayHistoricalMedian, r.medianRequestID, nextMedianBlockTime, r.historicalMedians) + medianMsg, err := generateContractRelayMsg( + forceRelay, + RelayHistoricalMedian, + r.medianRequestID, + nextMedianBlockTime, + r.historicalMedians, + ) if err != nil { return err } dataMsgs = append(dataMsgs, medianMsg) + logs.Uint64("median request id", r.medianRequestID) } clientCtx, wasmCtx, err := r.relayerClient.CreateClientAndScrtWasmCtx() @@ -393,20 +475,7 @@ func (r *Relayer) tick(ctx context.Context) error { executeMsgs[i] = &executeMsg } - logs := r.logger.Info() - logs.Str("contract address", r.contractAddress). - Str("relayer address", r.relayerClient.RelayerAddrString). - Str("block timestamp", blockTimestamp.String()). - Bool("median posted", postMedian). - Uint64("request id", r.requestID). - Uint64("deviation request id", r.deviationRequestID) - - if postMedian { - logs.Uint64("median request id", r.medianRequestID) - } - logs.Msg("broadcasting execute to contract") - if err := r.relayerClient.BroadcastTx(*clientCtx, nextBlockHeight, r.timeoutHeight, executeMsgs...); err != nil { r.missedCounter += 1 return err @@ -419,10 +488,13 @@ func (r *Relayer) tick(ctx context.Context) error { // increment request id to be stored in contracts r.requestID += 1 - r.deviationRequestID += 1 if postMedian { r.medianRequestID += 1 } + if postDeviation { + r.deviationRequestID += 1 + } + return nil }