From 545506841af9447e332e936b017f9758e06a1c6a Mon Sep 17 00:00:00 2001 From: "Dima K." Date: Thu, 22 Aug 2024 13:40:35 -0700 Subject: [PATCH 1/3] [Performance] Reduce RelayMiner memory consumption under load (#739) ## Summary ## Issue - #551 - #621 ## Type of change Select one or more: - [ ] New feature, functionality or library - [ ] Bug fix - [x] Code health or cleanup - [ ] Documentation - [ ] Other (specify) ## Testing **Documentation changes** (only if making doc changes) - [ ] `make docusaurus_start`; only needed if you make doc changes **Local Testing** (only if making code changes) - [ ] **Unit Tests**: `make go_develop_and_test` - [ ] **LocalNet E2E Tests**: `make test_e2e` - See [quickstart guide](https://dev.poktroll.com/developer_guide/quickstart) for instructions **PR Testing** (only if making code changes) - [ ] **DevNet E2E Tests**: Add the `devnet-test-e2e` label to the PR. - **THIS IS VERY EXPENSIVE**, so only do it after all the reviews are complete. - Optionally run `make trigger_ci` if you want to re-trigger tests without any code changes - If tests fail, try re-running failed tests only using the GitHub UI as shown [here](https://github.com/pokt-network/poktroll/assets/1892194/607984e9-0615-4569-9452-4c730190c1d2) ## Sanity Checklist - [ ] I have tested my changes using the available tooling - [ ] I have commented my code - [ ] I have performed a self-review of my own code; both comments & source code - [ ] I create and reference any new tickets, if applicable - [ ] I have left TODOs throughout the codebase, if applicable --------- Co-authored-by: Daniel Olshansky Co-authored-by: Bryan White --- Makefile | 6 +++ .../develop/developer_guide/quickstart.md | 2 +- .../operate/testing/load_testing_devnet.md | 4 +- go.mod | 35 ++++++------- go.sum | 41 +++++++++------ load-testing/loadtest_manifest_example.yaml | 2 +- load-testing/loadtest_manifest_localnet.yaml | 2 +- ...est_manifest_localnet_single_supplier.yaml | 51 +++++++++++++++++++ load-testing/tests/relays_stress.feature | 6 +-- .../relays_stress_single_suppier.feature | 17 +++++++ load-testing/tests/relays_stress_test.go | 4 ++ .../kubernetes/values-relayminer-common.yaml | 2 +- .../poktrolld/config/relayminer_config.yaml | 2 +- pkg/client/supplier/client_test.go | 4 +- pkg/relayer/session/sessiontree.go | 20 +++++--- .../relay_mining_difficulty_test.go | 4 +- 16 files changed, 146 insertions(+), 56 deletions(-) create mode 100644 load-testing/loadtest_manifest_localnet_single_supplier.yaml create mode 100644 load-testing/tests/relays_stress_single_suppier.feature diff --git a/Makefile b/Makefile index 4b6076abe..c8db38f6f 100644 --- a/Makefile +++ b/Makefile @@ -421,6 +421,12 @@ test_load_relays_stress_localnet: test_e2e_env warn_message_local_stress_test ## -tags=load,test -run LoadRelays --log-level=debug --timeout=30m \ --manifest ./load-testing/loadtest_manifest_localnet.yaml +.PHONY: test_load_relays_stress_localnet_single_supplier +test_load_relays_stress_localnet_single_supplier: test_e2e_env warn_message_local_stress_test ## Run the stress test for E2E relays on LocalNet using exclusively one supplier. + go test -v -count=1 ./load-testing/tests/... \ + -tags=load,test -run TestLoadRelaysSingleSupplier --log-level=debug --timeout=30m \ + --manifest ./load-testing/loadtest_manifest_localnet_single_supplier.yaml + .PHONY: test_verbose test_verbose: check_go_version ## Run all go tests verbosely go test -count=1 -v -race -tags test ./... diff --git a/docusaurus/docs/develop/developer_guide/quickstart.md b/docusaurus/docs/develop/developer_guide/quickstart.md index 13a899e29..007aa9018 100644 --- a/docusaurus/docs/develop/developer_guide/quickstart.md +++ b/docusaurus/docs/develop/developer_guide/quickstart.md @@ -433,7 +433,7 @@ The following is an example config to get you started: ```bash cat <> shannon_relayminer_config.yaml default_signing_key_names: [ "shannon_supplier" ] -smt_store_path: smt_stores +smt_store_path: $HOME/.poktroll/smt metrics: enabled: true addr: :9999 # you may need to change the metrics server port due to port conflicts. diff --git a/docusaurus/docs/operate/testing/load_testing_devnet.md b/docusaurus/docs/operate/testing/load_testing_devnet.md index faf2429a0..8e9207647 100644 --- a/docusaurus/docs/operate/testing/load_testing_devnet.md +++ b/docusaurus/docs/operate/testing/load_testing_devnet.md @@ -11,7 +11,7 @@ A guide on how to perform load testing on DevNets. - [Prerequisites](#prerequisites) - [1. Create and configure the DevNet](#1-create-and-configure-the-devnet) - [2. Stake the necessary actors](#2-stake-the-necessary-actors) - - [3. Configure the load testing manifest](#3-configure-the-load-testing-manifest) + - [3. Configure the load test manifest](#3-configure-the-load-test-manifest) - [Full example](#full-example) ## Overview @@ -90,7 +90,7 @@ service_id: "anvil" # The address of the account that will be used to fund the application accounts # so that they can stake on the network. # TODO_TECHDEBT(@bryanchriswhite, #512): Replace with faucet address. -funding_account_address: pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw # address for pnf account +funding_account_address: pokt1awtlw5sjmw2f5lgj8ekdkaqezphgz88rdk93sk # address for faucet account # In non-ephemeral chains, the gateways are identified by their addresses. gateways: diff --git a/go.mod b/go.mod index 65fdb00a4..5efd46e79 100644 --- a/go.mod +++ b/go.mod @@ -2,19 +2,18 @@ module github.com/pokt-network/poktroll go 1.22.2 -replace ( - // DEVELOPER_TIP: Uncomment to use a local copy of shannon-sdk for development purposes. - // github.com/pokt-network/shannon-sdk => ../shannon-sdk +// replace ( +// DEVELOPER_TIP: Uncomment to use a local copy of shannon-sdk for development purposes. +// github.com/pokt-network/shannon-sdk => ../shannon-sdk - // DEVELOPER_TIP: Uncomment to use a local copy of smt for development purposes. - // github.com/pokt-network/smt => ../smt +// DEVELOPER_TIP: Uncomment to use a local copy of smt for development purposes. +// github.com/pokt-network/smt => ../smt +// github.com/pokt-network/smt/kvstore/badger => ../smt/kvstore/badger +// github.com/pokt-network/smt/kvstore/pebble => ../smt/kvstore/pebble +// ) - // fix upstream GHSA-h395-qcrw-5vmq vulnerability. - github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 - - // replace broken goleveldb - github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 -) +// replace broken goleveldb +replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 require ( cosmossdk.io/api v0.7.5 @@ -57,8 +56,8 @@ require ( // repo is the first obvious idea, but has to be carefully considered, automated, and is not // a hard blocker. github.com/pokt-network/shannon-sdk v0.0.0-20240814144717-dfa95b525d46 - github.com/pokt-network/smt v0.12.0 - github.com/pokt-network/smt/kvstore/badger v0.0.0-20240109205447-868237978c0b + github.com/pokt-network/smt v0.13.0 + github.com/pokt-network/smt/kvstore/pebble v0.0.0-20240822175047-21ea8639c188 github.com/prometheus/client_golang v1.19.0 github.com/regen-network/gocuke v1.1.0 github.com/rs/zerolog v1.32.0 @@ -71,6 +70,7 @@ require ( golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/sync v0.7.0 + golang.org/x/text v0.16.0 golang.org/x/tools v0.23.0 google.golang.org/genproto/googleapis/api v0.0.0-20240709173604-40e1e62336c5 google.golang.org/grpc v1.65.0 @@ -79,8 +79,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/text v0.16.0 - require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240508200655-46a4cf4ba109.2 // indirect buf.build/gen/go/bufbuild/registry/connectrpc/go v1.16.2-20240710174705-f2077dee5ad4.1 // indirect @@ -119,9 +117,10 @@ require ( github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect - github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v1.1.0 // indirect + github.com/cockroachdb/pebble v1.1.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.9.1 // indirect @@ -145,7 +144,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/badger/v4 v4.2.1-0.20231013074411-fb1b00959581 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/distribution/reference v0.6.0 // indirect @@ -179,7 +177,6 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/cel-go v0.20.1 // indirect - github.com/google/flatbuffers v1.12.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-containerregistry v0.20.0 // indirect github.com/google/orderedcode v0.0.1 // indirect diff --git a/go.sum b/go.sum index 3f11a2b38..144e24f53 100644 --- a/go.sum +++ b/go.sum @@ -304,6 +304,8 @@ github.com/bufbuild/protovalidate-go v0.6.3 h1:wxQyzW035zM16Binbaz/nWAzS12dRIXhZ github.com/bufbuild/protovalidate-go v0.6.3/go.mod h1:J4PtwP9Z2YAGgB0+o+tTWEDtLtXvz/gfhFZD8pbzM/U= github.com/bufbuild/protoyaml-go v0.1.9 h1:anV5UtF1Mlvkkgp4NWA6U/zOnJFng8Orq4Vf3ZUQHBU= github.com/bufbuild/protoyaml-go v0.1.9/go.mod h1:KCBItkvZOK/zwGueLdH1Wx1RLyFn5rCH7YjQrdty2Wc= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -317,6 +319,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= @@ -349,12 +353,14 @@ github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065na github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= -github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= -github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -435,8 +441,6 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/badger/v4 v4.2.1-0.20231013074411-fb1b00959581 h1:yy45brf1ktmnkTCZlHynP1gRlVwZ9g19oz5D9wG81v4= -github.com/dgraph-io/badger/v4 v4.2.1-0.20231013074411-fb1b00959581/go.mod h1:T/uWAYxrXdaXw64ihI++9RMbKTCpKd/yE9+saARew7k= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= @@ -510,8 +514,9 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= -github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -544,7 +549,7 @@ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/Nu github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -559,6 +564,8 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -631,8 +638,6 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= -github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= -github.com/google/flatbuffers v1.12.1/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= @@ -834,6 +839,8 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -996,10 +1003,10 @@ github.com/pokt-network/ring-go v0.1.0 h1:hF7mDR4VVCIqqDAsrloP8azM9y1mprc99YgnTj github.com/pokt-network/ring-go v0.1.0/go.mod h1:8NHPH7H3EwrPX3XHfpyRI6bz4gApkE3+fd0XZRbMWP0= github.com/pokt-network/shannon-sdk v0.0.0-20240814144717-dfa95b525d46 h1:rkJa3LGPN+f/k2Vv9t09UWtgbpkMA0NLHRZDiGKPqo4= github.com/pokt-network/shannon-sdk v0.0.0-20240814144717-dfa95b525d46/go.mod h1:Jql/lobckajY8BVHDRkQPf6zYraompTK1et78jKVi68= -github.com/pokt-network/smt v0.12.0 h1:uqru/0ykC4LnBoMacakobNOd1iRK69PlohqjMtLmYNA= -github.com/pokt-network/smt v0.12.0/go.mod h1:S4Ho4OPkK2v2vUCHNtA49XDjqUC/OFYpBbynRVYmxvA= -github.com/pokt-network/smt/kvstore/badger v0.0.0-20240109205447-868237978c0b h1:TjfgV3vgW0zW47Br/OgUXD4M8iyR74EYanbFfN4ed8o= -github.com/pokt-network/smt/kvstore/badger v0.0.0-20240109205447-868237978c0b/go.mod h1:GbzcG5ebj8twKmBL1VzdPM4NS44okwYXBfQaVXT+6yU= +github.com/pokt-network/smt v0.13.0 h1:C2F8FlJh34aU+DVeRU/Bt8BOkFXn4QjWMK+nbT9PUj4= +github.com/pokt-network/smt v0.13.0/go.mod h1:S4Ho4OPkK2v2vUCHNtA49XDjqUC/OFYpBbynRVYmxvA= +github.com/pokt-network/smt/kvstore/pebble v0.0.0-20240822175047-21ea8639c188 h1:QK1WmFKQ/OzNVob/br55Brh+EFbWhcdq41WGC8UMihM= +github.com/pokt-network/smt/kvstore/pebble v0.0.0-20240822175047-21ea8639c188/go.mod h1:CZlY7W+7LU5hMFoTb9PmyL4wu/i41t3+gVMvDePxAmo= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -1134,6 +1141,8 @@ github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -1215,6 +1224,8 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/load-testing/loadtest_manifest_example.yaml b/load-testing/loadtest_manifest_example.yaml index 2e3612388..51c820e87 100644 --- a/load-testing/loadtest_manifest_example.yaml +++ b/load-testing/loadtest_manifest_example.yaml @@ -11,7 +11,7 @@ service_id: "anvil" # The address of the account that will be used to fund the the application accounts # so that they can stake on the network. -funding_account_address: pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw # address for pnf account +funding_account_address: pokt1awtlw5sjmw2f5lgj8ekdkaqezphgz88rdk93sk # address for faucet account # In non-ephemeral chains, the gateways are identified by their address. gateways: diff --git a/load-testing/loadtest_manifest_localnet.yaml b/load-testing/loadtest_manifest_localnet.yaml index f8216e408..5e5d87423 100644 --- a/load-testing/loadtest_manifest_localnet.yaml +++ b/load-testing/loadtest_manifest_localnet.yaml @@ -8,7 +8,7 @@ service_id: anvil # The address of the account that will be used to fund the the application, # gateway and supplier accounts so that they can stake on the network. -funding_account_address: pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw # address for pnf account +funding_account_address: pokt1awtlw5sjmw2f5lgj8ekdkaqezphgz88rdk93sk # address for faucet account # List of pre-provisioned suppliers used for load testing. # These suppliers will be progressively staked during the load test, according diff --git a/load-testing/loadtest_manifest_localnet_single_supplier.yaml b/load-testing/loadtest_manifest_localnet_single_supplier.yaml new file mode 100644 index 000000000..013aa3d9e --- /dev/null +++ b/load-testing/loadtest_manifest_localnet_single_supplier.yaml @@ -0,0 +1,51 @@ +# NB: The number of pre-provisioned **LocalNet** actors are managed in +# 'localnet_config.yaml' by the respective actors `count` property. + +is_ephemeral_chain: true # This should be `true` for LocalNet as it is an ephemeral network + +# The service ID to use for the load test. +service_id: anvil + +# The address of the account that will be used to fund the the application, +# gateway and supplier accounts so that they can stake on the network. +funding_account_address: pokt1awtlw5sjmw2f5lgj8ekdkaqezphgz88rdk93sk # address for faucet account + +# List of pre-provisioned suppliers used for load testing. +# These suppliers will be progressively staked during the load test, according +# to the test plan that is being executed. +# +# When running on **LocalNet**, the number of the suppliers defined below should match +# the `relayminers.count` in your `localnet_config.yaml`. +suppliers: + # The supplier address that is available in the load test's environment keyring, + # used to identify the supplier and sign relays and transactions with. + # It must be the address corresponding to the provided signing_key_name in the + # `relay_miner_config.yaml` file. + + # RelayMiner 1; http://localhost:10350/r/relayminer1/overview + - address: pokt19a3t4yunp0dlpfjrp7qwnzwlrzd5fzs2gjaaaj + # The advertised URL used by the supplier when it submits a stake message on-chain. + exposed_url: http://relayminer1:8545 + +# List of pre-provisioned gateways used for load testing. +# These gateways will be progressively staked and delegated to during the load test. +# +# When running on LocalNet, the number of the gateways defined below should match +# the `gateways.count` in your `localnet_config.yaml`. +gateways: + # The gateway address that is available in the load test's environment keyring, + # used to identify the gateway and sign relays and transactions with. + # It must be the address corresponding to the provided signing_key_name in the + # `appgate_server_config.yaml` file. + + # Gateway 1; http://localhost:10350/r/gateway1/overview + - address: pokt15vzxjqklzjtlz7lahe8z2dfe9nm5vxwwmscne4 + exposed_url: http://localhost:42079 # The gateway url that the user sends relays to (e.g. curl) + + # Gateway 2; http://localhost:10350/r/gateway2/overview + - address: pokt15w3fhfyc0lttv7r585e2ncpf6t2kl9uh8rsnyz + exposed_url: http://localhost:42080 + + # Gateway 3; http://localhost:10350/r/gateway3/overview + - address: pokt1zhmkkd0rh788mc9prfq0m2h88t9ge0j83gnxya + exposed_url: http://localhost:42081 diff --git a/load-testing/tests/relays_stress.feature b/load-testing/tests/relays_stress.feature index 20872b737..5aa3f63a0 100644 --- a/load-testing/tests/relays_stress.feature +++ b/load-testing/tests/relays_stress.feature @@ -10,8 +10,8 @@ Feature: Loading gateway server with relays | supplier | 1 | And more actors are staked as follows: | actor | actor inc amount | blocks per inc | max actors | - | application | 4 | 4 | 12 | - | gateway | 1 | 4 | 3 | - | supplier | 1 | 4 | 3 | + | application | 4 | 10 | 12 | + | gateway | 1 | 10 | 3 | + | supplier | 1 | 10 | 3 | When a load of concurrent relay requests are sent from the applications Then the correct pairs count of claim and proof messages should be committed on-chain \ No newline at end of file diff --git a/load-testing/tests/relays_stress_single_suppier.feature b/load-testing/tests/relays_stress_single_suppier.feature new file mode 100644 index 000000000..253b82615 --- /dev/null +++ b/load-testing/tests/relays_stress_single_suppier.feature @@ -0,0 +1,17 @@ +Feature: Loading gateway server with relays + + Scenario: Incrementing the number of relays and actors + Given localnet is running + And a rate of "1" relay requests per second is sent per application + And the following initial actors are staked: + | actor | count | + | application | 4 | + | gateway | 1 | + | supplier | 1 | + And more actors are staked as follows: + | actor | actor inc amount | blocks per inc | max actors | + | application | 4 | 10 | 12 | + | gateway | 1 | 10 | 3 | + | supplier | 1 | 10 | 1 | + When a load of concurrent relay requests are sent from the applications + Then the correct pairs count of claim and proof messages should be committed on-chain \ No newline at end of file diff --git a/load-testing/tests/relays_stress_test.go b/load-testing/tests/relays_stress_test.go index 944f81707..59f74c530 100644 --- a/load-testing/tests/relays_stress_test.go +++ b/load-testing/tests/relays_stress_test.go @@ -270,6 +270,10 @@ func TestLoadRelays(t *testing.T) { gocuke.NewRunner(t, &relaysSuite{}).Path(filepath.Join(".", "relays_stress.feature")).Run() } +func TestLoadRelaysSingleSupplier(t *testing.T) { + gocuke.NewRunner(t, &relaysSuite{}).Path(filepath.Join(".", "relays_stress_single_suppier.feature")).Run() +} + func (s *relaysSuite) LocalnetIsRunning() { s.ctx, s.cancelCtx = context.WithCancel(context.Background()) diff --git a/localnet/kubernetes/values-relayminer-common.yaml b/localnet/kubernetes/values-relayminer-common.yaml index 579e5802a..207c636b2 100644 --- a/localnet/kubernetes/values-relayminer-common.yaml +++ b/localnet/kubernetes/values-relayminer-common.yaml @@ -1,5 +1,5 @@ config: - smt_store_path: smt_stores + smt_store_path: /root/.poktroll/smt metrics: enabled: true addr: :9090 diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 236425e1e..1b9895122 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,5 +1,5 @@ signing_key_name: supplier1 -smt_store_path: smt_stores +smt_store_path: /root/.poktroll/smt metrics: enabled: true addr: :9090 diff --git a/pkg/client/supplier/client_test.go b/pkg/client/supplier/client_test.go index 09aa0dffb..3eed55b5e 100644 --- a/pkg/client/supplier/client_test.go +++ b/pkg/client/supplier/client_test.go @@ -8,7 +8,7 @@ import ( "cosmossdk.io/depinject" "github.com/golang/mock/gomock" "github.com/pokt-network/smt" - "github.com/pokt-network/smt/kvstore/badger" + "github.com/pokt-network/smt/kvstore/pebble" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/client/keyring" @@ -175,7 +175,7 @@ func TestSupplierClient_SubmitProof(t *testing.T) { }, } - kvStore, err := badger.NewKVStore("") + kvStore, err := pebble.NewKVStore("") require.NoError(t, err) // Generating an ephemeral tree & spec just so we can submit diff --git a/pkg/relayer/session/sessiontree.go b/pkg/relayer/session/sessiontree.go index 843186b0d..d7d6a9fe8 100644 --- a/pkg/relayer/session/sessiontree.go +++ b/pkg/relayer/session/sessiontree.go @@ -9,7 +9,7 @@ import ( cosmostypes "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/smt" - "github.com/pokt-network/smt/kvstore/badger" + "github.com/pokt-network/smt/kvstore/pebble" "github.com/pokt-network/poktroll/pkg/crypto/protocol" "github.com/pokt-network/poktroll/pkg/relayer" @@ -51,7 +51,7 @@ type sessionTree struct { proofBz []byte // treeStore is the KVStore used to store the SMST. - treeStore badger.BadgerKVStore + treeStore pebble.PebbleKVStore // storePath is the path to the KVStore used to store the SMST. // It is created from the storePrefix and the session.sessionId. @@ -72,14 +72,18 @@ func NewSessionTree( ) (relayer.SessionTree, error) { // Join the storePrefix and the session.sessionId and supplier's operator address to // create a unique storePath. - storePath := filepath.Join(storesDirectory, sessionHeader.SessionId, "_", supplierOperatorAddress.String()) + + // TODO_IMPROVE(#621): instead of creating a new KV store for each session, it will be more beneficial to + // use one key store. KV databases are often optimized for writing into one database. They keys can + // use supplier address and session id as prefix. The current approach might not be RAM/IO efficient. + storePath := filepath.Join(storesDirectory, supplierOperatorAddress.String(), sessionHeader.SessionId) // Make sure storePath does not exist when creating a new SessionTree if _, err := os.Stat(storePath); err != nil && !os.IsNotExist(err) { return nil, ErrSessionTreeStorePathExists.Wrapf("storePath: %q", storePath) } - treeStore, err := badger.NewKVStore(storePath) + treeStore, err := pebble.NewKVStore(storePath) if err != nil { return nil, err } @@ -157,7 +161,7 @@ func (st *sessionTree) ProveClosest(path []byte) (proof *smt.SparseMerkleClosest } // Restore the KVStore from disk since it has been closed after the claim has been generated. - st.treeStore, err = badger.NewKVStore(st.storePath) + st.treeStore, err = pebble.NewKVStore(st.storePath) if err != nil { return nil, err } @@ -240,9 +244,9 @@ func (st *sessionTree) Delete() error { st.isClaiming = false - if err := st.treeStore.ClearAll(); err != nil { - return err - } + // NB: We used to call `st.treeStore.ClearAll()` here. + // This was intentionally removed to lower the IO load. + // When the database is closed, it is deleted it from disk right away. if err := st.treeStore.Stop(); err != nil { return err diff --git a/tests/integration/tokenomics/relay_mining_difficulty_test.go b/tests/integration/tokenomics/relay_mining_difficulty_test.go index 9a6dda60e..3b3a2d876 100644 --- a/tests/integration/tokenomics/relay_mining_difficulty_test.go +++ b/tests/integration/tokenomics/relay_mining_difficulty_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/pokt-network/smt" - "github.com/pokt-network/smt/kvstore/badger" + "github.com/pokt-network/smt/kvstore/pebble" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/cmd/poktrolld/cmd" @@ -175,7 +175,7 @@ func prepareSMST( // Generating an ephemeral tree & spec just so we can submit // a proof of the right size. // TODO_TECHDEBT(#446): Centralize the configuration for the SMT spec. - kvStore, err := badger.NewKVStore("") + kvStore, err := pebble.NewKVStore("") require.NoError(t, err) // NB: A signed mined relay is a MinedRelay type with the appropriate From b5127457dca52abefff3544133cb0bb1ea2988b7 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sun, 25 Aug 2024 13:03:18 -0400 Subject: [PATCH 2/3] [Docs] Move over docs from poktroll-docker-compose-example (#757) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Make it easier to onboard users to Shannon by providing a nicer skin on the docs in [poktroll-docker-compose-example](https://github.com/pokt-network/poktroll-docker-compose-example) Also: - Improve ToC - Improve introduction - Add a results video ![Screenshot 2024-08-23 at 11 23 38 AM](https://github.com/user-attachments/assets/a73b29f1-1fb3-4e35-a41b-b9c8a9f2d450) --------- Co-authored-by: Dima K. --- .../operate/infrastructure/_category_.json | 2 +- .../docs/operate/networks/_category_.json | 4 +- .../docs/operate/quickstart/_category_.json | 8 + .../docker_compose_debian_cheatsheet.md | 304 ++++++++ .../quickstart/docker_compose_walkthrough.md | 675 ++++++++++++++++++ .../docs/operate/run_a_node/_category_.json | 2 +- .../docs/operate/testing/_category_.json | 4 +- .../docs/operate/user_guide/_category_.json | 2 +- 8 files changed, 994 insertions(+), 7 deletions(-) create mode 100644 docusaurus/docs/operate/quickstart/_category_.json create mode 100644 docusaurus/docs/operate/quickstart/docker_compose_debian_cheatsheet.md create mode 100644 docusaurus/docs/operate/quickstart/docker_compose_walkthrough.md diff --git a/docusaurus/docs/operate/infrastructure/_category_.json b/docusaurus/docs/operate/infrastructure/_category_.json index d14ee24d3..a2e8c1c70 100644 --- a/docusaurus/docs/operate/infrastructure/_category_.json +++ b/docusaurus/docs/operate/infrastructure/_category_.json @@ -1,6 +1,6 @@ { "label": "Infrastructure", - "position": 6, + "position": 5, "link": { "type": "generated-index", "description": "Infrastructure related to deploying, maintaining and testing various (Local, Dev, Test) environments." diff --git a/docusaurus/docs/operate/networks/_category_.json b/docusaurus/docs/operate/networks/_category_.json index f305b1d4e..978afd7cc 100644 --- a/docusaurus/docs/operate/networks/_category_.json +++ b/docusaurus/docs/operate/networks/_category_.json @@ -1,8 +1,8 @@ { "label": "Networks", - "position": 3, + "position": 4, "link": { "type": "generated-index", "description": "Documentation on Poktroll Networks." } -} \ No newline at end of file +} diff --git a/docusaurus/docs/operate/quickstart/_category_.json b/docusaurus/docs/operate/quickstart/_category_.json new file mode 100644 index 000000000..4a8928e1d --- /dev/null +++ b/docusaurus/docs/operate/quickstart/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Quickstart", + "position": 1, + "link": { + "type": "generated-index", + "description": "Quickstart documentation to start deploying on Shannon." + } +} diff --git a/docusaurus/docs/operate/quickstart/docker_compose_debian_cheatsheet.md b/docusaurus/docs/operate/quickstart/docker_compose_debian_cheatsheet.md new file mode 100644 index 000000000..047e7c42b --- /dev/null +++ b/docusaurus/docs/operate/quickstart/docker_compose_debian_cheatsheet.md @@ -0,0 +1,304 @@ +--- +sidebar_position: 2 +title: Docker Compose - Debian Cheatsheet +--- + +import ReactPlayer from "react-player"; + +# tl;dr Debian Cheat Sheet + +- [Results](#results) +- [Deploy your server](#deploy-your-server) +- [Install Dependencies](#install-dependencies) +- [Retrieve the source code](#retrieve-the-source-code) +- [Update your environment](#update-your-environment) +- [Start up the full node](#start-up-the-full-node) +- [Create new addresses for all your accounts and update .env](#create-new-addresses-for-all-your-accounts-and-update-env) +- [Fund your accounts](#fund-your-accounts) +- [Stake a Supplier \& Deploy a RelayMiner](#stake-a-supplier--deploy-a-relayminer) +- [Stake an Application \& Deploy an AppGate Server](#stake-an-application--deploy-an-appgate-server) +- [Send a Relay](#send-a-relay) + - [Ensure you get a response](#ensure-you-get-a-response) +- [Managing a re-genesis](#managing-a-re-genesis) + - [Full Nodes](#full-nodes) + - [Fund the same accounts](#fund-the-same-accounts) + - [Faucet is not ready and you need to fund the accounts manually](#faucet-is-not-ready-and-you-need-to-fund-the-accounts-manually) + - [Start the RelayMiner](#start-the-relayminer) + - [Start the AppGate Server](#start-the-appgate-server) + +## Results + +This is a text heavy walkthrough, but if all goes well, you should have something like the following: + + + +## Deploy your server + +1. Go to [vultr's console](https://my.vultr.com/deploy) +2. Choose `Cloud Compute - Shared CPU` +3. Choose `Debian 12 x64` +4. Select `AMD High Performance` +5. Choose the `100GB NVMe` storage w/ `4GB` memory and `2 vCPU` +6. Disable `Auto Backups` +7. Deploy + +## Install Dependencies + +See [docker's official instructions here](https://docs.docker.com/engine/install/debian/). + +Prepare the system: + +```bash +# Add Docker's official GPG key: +sudo apt-get update +sudo apt-get install ca-certificates curl +sudo install -m 0755 -d /etc/apt/keyrings +sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc +sudo chmod a+r /etc/apt/keyrings/docker.asc + +# Add the repository to Apt sources: +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +sudo apt-get update + +# Check if UFW is installed and add rules if it is +if command -v ufw > /dev/null 2>&1; then + sudo ufw allow from 172.16.0.0/12 + sudo ufw allow from 192.168.0.0/16 + echo "UFW rules added for Docker networks" +else + echo "UFW is not installed, skipping firewall configuration" +fi +``` + +And then install docker: + +```bash +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +``` + +## Retrieve the source code + +Then pull the github repo + +```bash +mkdir ~/workspace && cd ~/workspace +git clone https://github.com/pokt-network/poktroll-docker-compose-example.git +cd poktroll-docker-compose-example +``` + +## Update your environment + +```bash +cp .env.sample .env + +EXTERNAL_IP=$(curl -4 ifconfig.me/ip) +sed -i -e s/NODE_HOSTNAME=/NODE_HOSTNAME=$EXTERNAL_IP/g .env + +echo "source $(pwd)/helpers.sh" >> ~/.bashrc +echo "source $(pwd)/.env" >> ~/.bashrc +source ~/.bashrc +``` + +## Start up the full node + +```bash +docker compose up -d poktrolld poktrolld +# Optional: watch the block height sync up & logs +docker logs -f --tail 100 full_node +watch_height +``` + +## Create new addresses for all your accounts and update .env + +Supplier: + +```bash +poktrolld keys add supplier > /tmp/supplier + +mnemonic=$(tail -n 1 /tmp/supplier | tr -d '\r'); sed -i "s|SUPPLIER_MNEMONIC=\".*\"|SUPPLIER_MNEMONIC=\"$mnemonic\"|" .env + +address=$(awk '/address:/{print $3; exit}' /tmp/supplier | tr -d '\r'); sed -i "s|SUPPLIER_ADDR=\".*\"|SUPPLIER_ADDR=\"$address\"|g" .env +``` + +Application: + +```bash +poktrolld keys add application > /tmp/application + +mnemonic=$(tail -n 1 /tmp/application | tr -d '\r'); sed -i "s|APPLICATION_MNEMONIC=\".*\"|APPLICATION_MNEMONIC=\"$mnemonic\"|" .env + +address=$(awk '/address:/{print $3; exit}' /tmp/application | tr -d '\r'); sed -i "s|APPLICATION_ADDR=\".*\"|APPLICATION_ADDR=\"$address\"|g" .env +``` + +Gateway: + +```bash +poktrolld keys add gateway > /tmp/gateway + +mnemonic=$(tail -n 1 /tmp/gateway | tr -d '\r'); sed -i "s|GATEWAY_MNEMONIC=\".*\"|GATEWAY_MNEMONIC=\"$mnemonic\"|" .env + +address=$(awk '/address:/{print $3; exit}' /tmp/gateway | tr -d '\r'); sed -i "s|GATEWAY_ADDR=\".*\"|GATEWAY_ADDR=\"$address\"|g" .env +``` + +FINALLY, `source .env` to update the environment variables. + +## Fund your accounts + +Run the following: + +```bash +show_actor_addresses +``` + +For each one, fund the accounts using the [faucet](https://faucet.testnet.pokt.network/) + +Next, run this helper (it's part of `helpers.sh`) to find each of them on the explorer: + +```bash +show_explorer_urls +``` + +## Stake a Supplier & Deploy a RelayMiner + +Stake the supplier: + +```bash +sed -i -e s/YOUR_NODE_IP_OR_HOST/$NODE_HOSTNAME/g ./stake_configs/supplier_stake_config_example.yaml +sed -i -e s/YOUR_OWNER_ADDRESS/$SUPPLIER_ADDR/g ./stake_configs/supplier_stake_config_example.yaml +poktrolld tx supplier stake-supplier --config=/poktroll/stake_configs/supplier_stake_config_example.yaml --from=supplier --chain-id=poktroll --yes + +# OPTIONALLY check the supplier's status +poktrolld query supplier show-supplier $SUPPLIER_ADDR + +# Start the relay miner (please update the grove app ID if you can) +sed -i -e s/YOUR_NODE_IP_OR_HOST/$NODE_HOSTNAME/g relayminer-example/config/relayminer_config.yaml +sed -i -e "s|backend_url: \".*\"|backend_url: \"https://eth-mainnet.rpc.grove.city/v1/c7f14c60\"|g" relayminer-example/config/relayminer_config.yaml +``` + +Start the supplier + +```bash +docker compose up -d relayminer-example +# OPTIONALLY view the logs +docker logs -f --tail 100 relay_miner +``` + +## Stake an Application & Deploy an AppGate Server + +Stake the application: + +```bash +poktrolld tx application stake-application --config=/poktroll/stake_configs/application_stake_config_example.yaml --from=application --chain-id=poktroll --yes + +# OPTIONALLY check the application's status +poktrolld query application show-application $APPLICATION_ADDR +``` + +Start the appgate server: + +```bash +docker compose up -d appgate-server-example +# OPTIONALLY view the logs +docker logs -f --tail 100 appgate_server +``` + +## Send a Relay + +```bash +curl http://$NODE_HOSTNAME:85/0021 \ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' +``` + +### Ensure you get a response + +To ensure you get a response, run the request a few times. + +```bash +for i in {1..10}; do + curl http://$NODE_HOSTNAME:85/0021 \ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' \ + --max-time 1 + echo "" +done +``` + +## Managing a re-genesis + +Assuming you already had everything functioning following the steps above, this +is a quick way to reset everything (without recreating keys) after a re-genesis. + +### Full Nodes + +```bash +# Stop all containers +docker-compose down +docker rm $(docker ps -aq) -f + +# Remove existing data +rm -rf poktrolld-data/config/addrbook.json poktrolld-data/config/genesis.json poktrolld-data/data/ poktrolld-data/config/node_key.json poktrolld-data/config/priv_validator_key.json +``` + +Update `POKTROLLD_IMAGE_TAG` in `.env` based on the releases [here](https://github.com/pokt-network/poktroll/releases/tag/v0.0.6). + +```bash +# Start the full +docker compose up -d poktrolld poktrolld + +# Sanity check the logs +docker logs full_node -f --tail 100 +``` + +### Fund the same accounts + +Go to the [faucet](https://faucet.testnet.pokt.network/) and fund the same accounts: + +```bash +echo $APPLICATION_ADDR +echo $GATEWAY_ADDR +echo $SUPPLIER_ADDR +``` + +#### Faucet is not ready and you need to fund the accounts manually + +```bash +# Import the faucet using the mnemonic +poktrolld keys add --recover -i faucet +poktrolld tx bank multi-send faucet $APPLICATION_ADDR $GATEWAY_ADDR $SUPPLIER_ADDR 100000upokt --chain-id=poktroll --yes +``` + +### Start the RelayMiner + +```bash +# Stake +poktrolld tx supplier stake-supplier --config=/poktroll/stake_configs/supplier_stake_config_example.yaml --from=supplier --chain-id=poktroll --yes +# Check +poktrolld query supplier show-supplier $SUPPLIER_ADDR +# Start +docker compose up -d relayminer-example +# View +docker logs -f --tail 100 relay_miner +``` + +### Start the AppGate Server + +```bash +# Stake +poktrolld tx application stake-application --config=/poktroll/stake_configs/application_stake_config_example.yaml --from=application --chain-id=poktroll --yes +# Check +poktrolld query application show-application $APPLICATION_ADDR +# Start +docker compose up -d appgate-server-example +# View +docker logs -f --tail 100 appgate_server +``` diff --git a/docusaurus/docs/operate/quickstart/docker_compose_walkthrough.md b/docusaurus/docs/operate/quickstart/docker_compose_walkthrough.md new file mode 100644 index 000000000..31c596f3b --- /dev/null +++ b/docusaurus/docs/operate/quickstart/docker_compose_walkthrough.md @@ -0,0 +1,675 @@ +--- +sidebar_position: 1 +title: Docker Compose Walkthrough +--- + +import ReactPlayer from "react-player"; + +# Poktrolld Docker-Compose Example + +- [Introduction and Cheat Sheet](#introduction-and-cheat-sheet) +- [Key Terms in Morse and Shannon](#key-terms-in-morse-and-shannon) +- [Understanding Actors in the Shannon upgrade](#understanding-actors-in-the-shannon-upgrade) +- [Prerequisites](#prerequisites) +- [A. Deploying a Full Node](#a-deploying-a-full-node) +- [B. Creating a Supplier and Deploying a RelayMiner](#b-creating-a-supplier-and-deploying-a-relayminer) +- [C. Creating an Application and Deploying an AppGate Server](#c-creating-an-application-and-deploying-an-appgate-server) +- [D. Creating a Gateway Deploying an Gateway Server](#d-creating-a-gateway-deploying-an-gateway-server) + + + +## Introduction and Cheat Sheet + +This document uses the [poktroll-docker-compose-example](https://github.com/pokt-network/poktroll-docker-compose-example) +to help stake and deploy every actor in the Pocket Network ecosystem. + +It also provides some intuition for those already familiar with `Morse` and are +transitioning to `Shannon`. + +:::tip + +This document has a lot of details and explanations. If you're looking for a +copy-paste quickstart guide to set all of it up on a Debian server, check out +the [Debian cheat sheet](./docker_compose_debian_cheatsheet.md). + +::: + +This is a text heavy walkthrough, but if all goes well, you should have something like the following: + + + +## Key Terms in Morse and Shannon + +- `Morse` - The current version of the Pocket Network MainNet (a.k.a v0). +- `Shannon` - The upcoming version of the Pocket Network MainNet (a.k.a v1). +- `Validator` - A node that participates in the consensus process. + - In `Morse`Same in `Morse` and `Shannon`. + - In `Shannon` +- `Node` - A `Morse` actor that stakes to provide Relay services. + - In `Morse` - All `Validator` are nodes but only the top 1000 stakes `Node`s are `Validator`s + - This actor is not present in `Shannon` and decoupled into `Supplier` and a `RelayMiner`. +- `Supplier` - The on-chain actor that stakes to provide Relay services. + - In `Shannon` - This actor is responsible needs access to a Full Node (sovereign or node). +- `RelayMiner` - The off-chain service that provides Relay services on behalf of a `Supplier`. + - In `Shannon` - This actor is responsible for providing the Relay services. +- `AppGate Server` - The off-chain service that provides Relay services on behalf of an `Application` or `Gateway`. + +For more details, please refer to the [Shannon actors documentation](https://dev.poktroll.com/actors). + +## Understanding Actors in the Shannon upgrade + +For those familiar with `Morse`, Pocket Network Mainnet, the introduction of +multiple node types in the upcoming `Shannon` requires some explanation. + +In `Shannon`, the `Supplier` role is separated from the `Full node` role. + +In `Morse`, a `Validator` or a staked `Node` was responsible for both holding +a copy of the on-chain data, as well as performing relays. With `Shannon`, the +`RelayMiner` software, which runs the supplier logic, is distinct from the full-node/validator. + +Furthermore, `Shannon` introduces the `AppGate Server`, a software component that +acts on behalf of either `Applications` or `Gateways` to access services provided +by Pocket Network `Supplier`s via `RelayMiners`. + +The following diagram from the [actors](../../protocol/actors/) page captures the relationship +between on-chain records (actors) and off-chain operators (servers). + +```mermaid +--- +title: Actors +--- +flowchart TB + + subgraph on-chain + A([Application]) + G([Gateway]) + S([Supplier]) + end + + subgraph off-chain + APS[AppGate Server] + RM[Relay Miner] + end + + A -.- APS + G -.- APS + S -..- RM +``` + +## Prerequisites + +_Note: the system must be capable of exposing ports to the internet for +peer-to-peer communication._ + +### 0. Software & Tooling + +Ensure the following software is installed on your system: + +- [git](https://github.com/git-guides/install-git) +- [Docker](https://docs.docker.com/engine/install/) +- [docker-compose](https://docs.docker.com/compose/install/#installation-scenarios) + +### Clone the Repository + +```bash +git clone https://github.com/pokt-network/poktroll-docker-compose-example.git +cd poktroll-docker-compose-example +``` + +### Operational Helpers + +Run the following command, or add it to your `~/.bashrc` to have access to helpers: + +```bash +source helpers.sh +``` + +### Environment Variables + +Create and configure your `.env` file from the sample: + +```bash +cp .env.sample .env +``` + +Update `NODE_HOSTNAME` in `.env` to the IP address or hostname of your node. For example: + +```bash +sed -i -e s/NODE_HOSTNAME=/NODE_HOSTNAME=69.42.690.420/g .env +``` + +## A. Deploying a Full Node + +### Launch the Node + +_Note: You may need to replace `docker-compose` with `docker compose` if you are +running a newer version of Docker where `docker-compose` is integrated into `docker` itself._ + +Initiate the node with: + +```bash +docker-compose up -d poktrolld +``` + +Monitor node activity through logs with: + +```bash +docker-compose logs -f --tail 100 poktrolld +``` + +### Inspecting the Full Node + +If you run `docker ps`, you should see a `full_node` running which you can inspect +using the commands below. + +### CometBFT Status + +```bash +curl -s -X POST localhost:26657/status | jq +``` + +### gRPC + +To inspect the gRPC results on port 9090 you may [install grpcurl](https://github.com/fullstorydev/grpcurl?tab=readme-ov-file#installation). + +Once installed: + +```bash +grpcurl -plaintext localhost:9090 list +``` + +### Latest Block + +```bash +curl -s -X POST localhost:26657/block | jq +``` + +### Watch the height + +```bash +watch -n 1 "curl -s -X POST localhost:26657/block | jq '.result.block.header.height'" +``` + +You can compare the height relative to the [shannon testnet explorer](https://shannon.testnet.pokt.network/poktroll/block). + +### Get a way to fund your accounts + +Throughout these instructions, you will need to fund your account with tokens +at multiple points in time. + +#### 3.1 Funding using a Faucet + +When you need to fund an account, you can make use of the [Faucet](https://faucet.testnet.pokt.network/). + +#### [Requires Grove Team Support] 3.2 Funding using faucet account + +If you require a larger amount of tokens or are a core contributor, you can add the `faucet` +account to fund things yourself directly. + +```bash +poktrolld keys add --recover -i faucet +``` + +When you see the `> Enter your bipmnemonic` prompt, paste the mnemonic +provided by the Pocket team for testnet. + +When you see the `> Enter your bippassphrase. This is combined with the mnemonic to derive the seed. Most users should just hit enter to use the default, ""` +prompt, hit enter without adding a passphrase. Finish funding your account by using the command below: + +You can view the balance of the faucet address at [shannon.testnet.pokt.network/](https://shannon.testnet.pokt.network/). + +### Restarting a full node after re-genesis + +If the team has completed a re-genesis, you will need to wipe existing data +and restart your node from scratch. The following is a quick and easy way to +start from a clean slate: + +```bash + +# Stop & remove existing containers +docker-compose down +docker rm $(docker ps -aq) -f + +# Remove existing data and renew genesis +rm -rf poktrolld-data/config/addrbook.json poktrolld-data/config/genesis.json poktrolld-data/data/ + +# Re-start the node +docker-compose up -d +docker-compose logs -f --tail 100 +``` + +### Docker image updates + +The `.env` file contains `POKTROLLD_IMAGE_TAG` which can be updated based on the +images available on [ghcr](https://github.com/pokt-network/poktroll/pkgs/container/poktrolld/versions) +to update the version of the `full_node` deployed. + +## B. Creating a Supplier and Deploying a RelayMiner + +A Supplier is an on-chain record that advertises services it'll provide. + +A RelayMiner is an operator / service that provides services to offer on the Pocket Network. + +### 0. Prerequisites for a RelayMiner + +- **Full Node**: This RelayMiner deployment guide assumes the Full Node is + deployed in the same `docker-compose` stack; see section (A). +- **A poktroll account with uPOKT tokens**: Tokens can be acquired by contacting + the team or using the faucet. You are going to need a BIPmnemonic phrase for + an existing funded account before continuing below. + +### Create, configure and fund a Supplier account + +On the host where you started the full node container, run the commands below to +create your account. + +Create a new `supplier` account: + +```bash +poktrolld keys add supplier-1 +``` + +Copy the mnemonic that's printed to the screen to the `SUPPLIER_MNEMONIC` +variable in your `.env` file. + +```bash +export SUPPLIER_MNEMONIC="foo bar ..." +``` + +Save the outputted address to a variable for simplicity:: + +```bash +export SUPPLIER_ADDR="pokt1..." +``` + +Make sure to: + +```bash +source .env +``` + +Add funds to your supplier account by either going to the [faucet](https://faucet.testnet.pokt.network) +or using the `faucet` account directly if you have access to it: + +```bash +poktrolld tx bank send faucet $SUPPLIER_ADDR 10000upokt --chain-id=poktroll --yes +``` + +You can check that your address is funded correctly by running: + +```bash +poktrolld query bank balances $SUPPLIER_ADDR +``` + +If you're waiting to see if your transaction has been included in a block, you can run: + +```bash +poktrolld query tx --type=hash +``` + +### Configure and stake your Supplier + +:::tip Supplier staking config + +[dev.poktroll.com/operate/configs/supplier_staking_config](https://dev.poktroll.com/operate/configs/supplier_staking_config) +explains what supplier staking config is and how it can be used. + +::: + +Verify that the account you're planning to use for `SUPPLIER` (created above) +is available in your local Keyring: + +```bash +poktrolld keys list --list-names | grep "supplier-1" +``` + +Update the provided example supplier stake config: + +```bash +sed -i -e s/YOUR_NODE_IP_OR_HOST/$NODE_HOSTNAME/g ./stake_configs/supplier_stake_config_example.yaml +``` + +Use the configuration to stake your supplier: + +```bash +poktrolld tx supplier stake-supplier --config=/poktroll/stake_configs/supplier_stake_config_example.yaml --from=supplier-1 --chain-id=poktroll --yes +``` + +:::warning Upstaking to restake + +If you need to change any of the configurations in your staking config, you MUST +increase the stake by at least one uPOKT. This is the `stake_amount` field +in the `supplier_stake_config_example.yaml` file above. + +::: + +Verify your supplier is staked: + +```bash +poktrolld query supplier show-supplier $SUPPLIER_ADDR +``` + +### Configure and run your RelayMiner + +:::tip RelayMiner operation config + +[dev.poktroll.com/operate/configs/relayminer_config](https://dev.poktroll.com/operate/configs/relayminer_config) +explains what the RelayMiner operation config is and how it can be used. + +::: + +Update the provided example RelayMiner operation config: + +```bash +sed -i -e s/YOUR_NODE_IP_OR_HOST/$NODE_HOSTNAME/g relayminer-example/config/relayminer_config.yaml +``` + +Update the `backend_url` in `relayminer_config.yaml` with a valid `002(i.e. ETH MainNet) +service URL. We suggest using your own node, but you can get one from Grove for testing purposes. + +```bash +sed -i "s|backend_url:\".*\"|backend_url: \"https://eth-mainnet.rpc.grove.city/v1/\"|g" relayminer-example/config/relayminer_config.yaml +``` + +Start up the RelayMiner: + +```bash +docker-compose up -d relayminer-example +``` + +Check logs and confirm the node works as expected: + +```bash +docker-compose logs -f --tail 100 relayminer-example +``` + +## C. Creating an Application and Deploying an AppGate Server + +AppGate Server allows to use services provided by other operators on Pocket Network. + +### 0. Prerequisites for an AppGate Server + +- **Full Node**: This AppGate Server deployment guide assumes the Full Node is + deployed in the same docker-compose stack; see section A. +- **A poktroll account with uPOKT tokens**: Tokens can be acquired by contacting + the team. You are going to need a BIPmnemonic phrase for an existing + funded account. + +### Create, configure and fund your Application + +On the host where you started the full node container, run the commands below to +create your account. + +Create a new `application` account: + +```bash +poktrolld keys add application-1 +``` + +Copy the mnemonic that's printed to the screen to the `APPLICATION_MNEMONIC` +variable in your `.env` file. + +```bash +export APPLICATION_MNEMONIC="foo bar ..." +``` + +Save the outputted address to a variable for simplicity:: + +```bash +export APPLICATION_ADDR="pokt1..." +``` + +Make sure to: + +```bash + source .env +``` + +Add funds to your application account by either going to the [faucet](https://faucet.testnet.pokt.network) +or using the `faucet` account directly if you have access to it: + +```bash +poktrolld tx bank send faucet $APPLICATION_ADDR 10000upokt --chain-id=poktroll --yes +``` + +You can check that your address is funded correctly by running: + +```bash +poktrolld query bank balances $APPLICATION_ADDR +``` + +### Configure and stake your Application + +:::tip Application staking config + +[dev.poktroll.com/operate/configs/application_staking_config](https://dev.poktroll.com/operate/configs/application_staking_config) +explains what application staking config is and how it can be used. + +::: + +Verify that the account you're planning to use for `APPLICATION` (created above) +is available in your local Keyring: + +```bash +poktrolld keys list --list-names | grep "application-1" +``` + +Use the configuration to stake your application: + +```bash +poktrolld tx application stake-application --config=/poktroll/stake_configs/application_stake_config_example.yaml --from=application-1 --chain-id=poktroll --yes +``` + +Verify your application is staked + +```bash +poktrolld query application show-application $APPLICATION_ADDR +``` + +### Configure and run your AppGate Server + +:::tip AppGate Server operation config + +[dev.poktroll.com/operate/configs/appgate_server_config](https://dev.poktroll.com/operate/configs/appgate_server_config) +explains what the AppGate Server operation config is and how it can be used. + +::: + +appgate-server-example/config/appgate_config.yaml + +```bash +docker-compose up -d appgate-server-example +``` + +Check logs and confirm the node works as expected: + +```bash +docker-compose logs -f --tail 100 appgate-server-example +``` + +### Send a relay + +You can send requests to the newly deployed AppGate Server. If there are any +Suppliers on the network that can provide the service, the request will be +routed to them. + +The endpoint you want to send request to is: `http://your_node:appgate_server_port/service_id`. For example, this is how the request can be routed to `ethereum` +represented by `0021`: + +```bash +curl http://$NODE_HOSTNAME:85/00\ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' +``` + +You should expect a result that looks like so: + +```bash +{"jsonrpc":"2.0","id":1,"result":"0x1289571"} +``` + +## D. Creating a Gateway Deploying an Gateway Server + +Gateway Server allows to use services provided by other operators on Pocket Network. + +### 0. Prerequisites for a Gateway Server + +- **Full Node**: This Gateway Server deployment guide assumes the Full Node is + deployed in the same docker-compose stack; see section A. +- **A poktroll account with uPOKT tokens**: Tokens can be acquired by contacting + the team. You are going to need a BIPmnemonic phrase for an existing + funded account. + +### Create, configure and fund your Gateway + +On the host where you started the full node container, run the commands below to +create your account. + +Create a new `gateway` account: + +```bash +poktrolld keys add gateway-1 +``` + +Copy the mnemonic that's printed to the screen to the `GATEWAY_MNEMONIC` +variable in your `.env` file. + +```bash +export GATEWAY_MNEMONIC="foo bar ..." +``` + +Save the outputted address to a variable for simplicity:: + +```bash +export GATEWAY_ADDR="pokt1..." +``` + +Make sure to: + +```bash + source .env +``` + +Add funds to your gateway account by either going to the [faucet](https://faucet.testnet.pokt.network) +or using the `faucet` account directly if you have access to it: + +```bash +poktrolld tx bank send faucet $GATEWAY_ADDR 10000upokt --chain-id=poktroll --yes +``` + +You can check that your address is funded correctly by running: + +```bash +poktrolld query bank balances $GATEWAY_ADDR +``` + +### Configure and stake your Gateway + +:::tip Gateway staking config + +[dev.poktroll.com/operate/configs/gateway_staking_config](https://dev.poktroll.com/operate/configs/gateway_staking_config) +explains what gateway staking config is and how it can be used. + +::: + +Verify that the account you're planning to use for `GATEWAY` (created above) +is available in your local Keyring: + +```bash +poktrolld keys list --list-names | grep "gateway-1" +``` + +Use the configuration to stake your gateway: + +```bash +poktrolld tx gateway stake-gateway --config=/poktroll/stake_configs/gateway_stake_config_example.yaml --from=gateway-1 --chain-id=poktroll --yes +``` + +Verify your gateway is staked + +```bash +poktrolld query gateway show-gateway $GATEWAY_ADDR +``` + +### Configure and run your Gateway Server + +:::tip Gateway Server operation config + +[dev.poktroll.com/operate/configs/appgate_server_config](https://dev.poktroll.com/operate/configs/appgate_server_config) +explains what the Gateway Server operation config is and how it can be used. + +::: + +appgate-server-example/config/gateway_config.yaml + +```bash +docker-compose up -d gateway-example +``` + +Check logs and confirm the node works as expected: + +```bash +docker-compose logs -f --tail 100 gateway-example +``` + +### Delegate your Application to the Gateway + +poktrolld tx application delegate-to-gateway $GATEWAY_ADDR --from=application-1 --chain-id=poktroll --chain-id=poktroll --yes + +### Send a relay + +You can send requests to the newly deployed Gateway Server. If there are any +Suppliers on the network that can provide the service, the request will be +routed to them. + +The endpoint you want to send request to is: `http://your_node:gateway_server_port/service_id`. For example, this is how the request can be routed to `ethereum` +represented by `0021`: + +```bash +curl http://$NODE_HOSTNAME:84/0021?applicationAddr=$APPLICATION_ADDR \ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' +``` + +You should expect a result that looks like so: + +```bash +{"jsonrpc":"2.0","id":1,"result":"0x1289571"} +``` + +#### 5.1 Ensure you get a response + +To ensure you get a response, you may need to run the request a few times: + +```bash +for i in {1..10}; do + curl http://$NODE_HOSTNAME:85/00\ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' \ + --max-time 1 + echo "" +done +``` + +Why? + +- Suppliers may have been staked, but the RelayMiner is no longer running. +- Pocket does not currently have on-chain quality-of-service +- Pocket does not currently have supplier jailing +- You can follow along with [buildwithgrove/path](https://github.com/buildwithgrove/path) for what we'll open source. diff --git a/docusaurus/docs/operate/run_a_node/_category_.json b/docusaurus/docs/operate/run_a_node/_category_.json index d0b710dfb..479097fdc 100644 --- a/docusaurus/docs/operate/run_a_node/_category_.json +++ b/docusaurus/docs/operate/run_a_node/_category_.json @@ -1,6 +1,6 @@ { "label": "Run a Node", - "position": 2, + "position": 3, "link": { "type": "generated-index", "description": "Guides on how to deploy and operated various type of Pocket Network nodes." diff --git a/docusaurus/docs/operate/testing/_category_.json b/docusaurus/docs/operate/testing/_category_.json index dafd5b3d4..942fdc3b8 100644 --- a/docusaurus/docs/operate/testing/_category_.json +++ b/docusaurus/docs/operate/testing/_category_.json @@ -1,8 +1,8 @@ { "label": "Testing", - "position": 10, + "position": 6, "link": { "type": "generated-index", "description": "Documentation related to the type of end-to-end testing (load or other) we are doing." } -} \ No newline at end of file +} diff --git a/docusaurus/docs/operate/user_guide/_category_.json b/docusaurus/docs/operate/user_guide/_category_.json index 77b3e0c8d..4f71de3e6 100644 --- a/docusaurus/docs/operate/user_guide/_category_.json +++ b/docusaurus/docs/operate/user_guide/_category_.json @@ -1,6 +1,6 @@ { "label": "User Guide", - "position": 1, + "position": 2, "link": { "type": "generated-index", "description": "poktrolld CLI documentation" From 5042312b8d6b599bae6df631d9792c98c5929576 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 26 Aug 2024 20:20:01 +0200 Subject: [PATCH 3/3] [Application] Implement unbonding period (#735) ## Summary This PR adds an unbonding period when an `Application` submits an unstaking transaction. * Adds an unbondingHeight to the `Application` proto. * Resets the unbondingHeight when an `Application` re-stakes during that period. * Prevents unstaking when an `Application` is already in an unbonding period. * Adds an EndBlocker routine to unbond `Application`s that reached their unbonding height. * Deactivate the `Application`, denying it to get/construct `Session`s after the session corresponding to the unstake message ends. ## Issue `Application`s unstaking needs to be delayed at least until the accounting for the last `Session` is settled. This is to avoid `Application`s from prematurely unstaking and getting their funds back, before their stake is burned for the work requested. - #696 ## Type of change Select one or more: - [x] New feature, functionality or library - [ ] Bug fix - [ ] Code health or cleanup - [ ] Documentation - [ ] Other (specify) ## Testing **Documentation changes** (only if making doc changes) - [ ] `make docusaurus_start`; only needed if you make doc changes **Local Testing** (only if making code changes) - [x] **Unit Tests**: `make go_develop_and_test` - [x] **LocalNet E2E Tests**: `make test_e2e` - See [quickstart guide](https://dev.poktroll.com/developer_guide/quickstart) for instructions **PR Testing** (only if making code changes) - [ ] **DevNet E2E Tests**: Add the `devnet-test-e2e` label to the PR. - **THIS IS VERY EXPENSIVE**, so only do it after all the reviews are complete. - Optionally run `make trigger_ci` if you want to re-trigger tests without any code changes - If tests fail, try re-running failed tests only using the GitHub UI as shown [here](https://github.com/pokt-network/poktroll/assets/1892194/607984e9-0615-4569-9452-4c730190c1d2) ## Sanity Checklist - [x] I have tested my changes using the available tooling - [x] I have commented my code - [x] I have performed a self-review of my own code; both comments & source code - [ ] I create and reference any new tickets, if applicable - [ ] I have left TODOs throughout the codebase, if applicable ## Summary by CodeRabbit - **New Features** - Added the ability to track the end height of unstaking sessions for applications. - Introduced a new parameter to configure the number of unbonding sessions applications must wait after unstaking. - **Bug Fixes** - Enhanced operational checks in the unstaking process to improve reliability. - **Documentation** - Updated test scenarios for clarity regarding application unbonding and staking processes. - **Tests** - Expanded the test suite to cover new unbonding functionality and parameter updates. --- api/poktroll/application/types.pulsar.go | 118 ++++++++++--- api/poktroll/shared/params.pulsar.go | 113 +++++++++--- e2e/tests/init_test.go | 62 ++++++- e2e/tests/parse_params_test.go | 2 + e2e/tests/stake_app.feature | 7 +- e2e/tests/stake_supplier.feature | 2 +- e2e/tests/update_params.feature | 44 ++--- e2e/tests/update_params_test.go | 5 + proto/poktroll/application/types.proto | 13 +- proto/poktroll/shared/params.proto | 5 + testutil/keeper/application.go | 36 +++- .../keeper/msg_server_stake_application.go | 3 + .../keeper/msg_server_unstake_application.go | 31 ++-- .../msg_server_unstake_application_test.go | 167 +++++++++++++++--- x/application/keeper/unbond_applications.go | 67 +++++++ x/application/module/abci.go | 4 + x/application/types/application.go | 34 ++++ x/application/types/errors.go | 1 + x/application/types/types.pb.go | 101 +++++++---- x/session/keeper/session_hydrator.go | 10 ++ x/session/types/errors.go | 1 + x/shared/keeper/msg_server_update_param.go | 7 + .../keeper/msg_server_update_param_test.go | 104 +++++++++-- x/shared/types/genesis_test.go | 5 +- x/shared/types/message_update_param.go | 3 +- x/shared/types/params.go | 109 +++++++++--- x/shared/types/params.pb.go | 100 ++++++++--- x/shared/types/params_test.go | 35 ++++ x/tokenomics/types/tx.pb.go | 1 + 29 files changed, 954 insertions(+), 236 deletions(-) create mode 100644 x/application/keeper/unbond_applications.go create mode 100644 x/application/types/application.go diff --git a/api/poktroll/application/types.pulsar.go b/api/poktroll/application/types.pulsar.go index 89f1d355d..ac359e285 100644 --- a/api/poktroll/application/types.pulsar.go +++ b/api/poktroll/application/types.pulsar.go @@ -211,6 +211,7 @@ var ( fd_Application_service_configs protoreflect.FieldDescriptor fd_Application_delegatee_gateway_addresses protoreflect.FieldDescriptor fd_Application_pending_undelegations protoreflect.FieldDescriptor + fd_Application_unstake_session_end_height protoreflect.FieldDescriptor ) func init() { @@ -221,6 +222,7 @@ func init() { fd_Application_service_configs = md_Application.Fields().ByName("service_configs") fd_Application_delegatee_gateway_addresses = md_Application.Fields().ByName("delegatee_gateway_addresses") fd_Application_pending_undelegations = md_Application.Fields().ByName("pending_undelegations") + fd_Application_unstake_session_end_height = md_Application.Fields().ByName("unstake_session_end_height") } var _ protoreflect.Message = (*fastReflection_Application)(nil) @@ -318,6 +320,12 @@ func (x *fastReflection_Application) Range(f func(protoreflect.FieldDescriptor, return } } + if x.UnstakeSessionEndHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.UnstakeSessionEndHeight) + if !f(fd_Application_unstake_session_end_height, value) { + return + } + } } // Has reports whether a field is populated. @@ -343,6 +351,8 @@ func (x *fastReflection_Application) Has(fd protoreflect.FieldDescriptor) bool { return len(x.DelegateeGatewayAddresses) != 0 case "poktroll.application.Application.pending_undelegations": return len(x.PendingUndelegations) != 0 + case "poktroll.application.Application.unstake_session_end_height": + return x.UnstakeSessionEndHeight != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -369,6 +379,8 @@ func (x *fastReflection_Application) Clear(fd protoreflect.FieldDescriptor) { x.DelegateeGatewayAddresses = nil case "poktroll.application.Application.pending_undelegations": x.PendingUndelegations = nil + case "poktroll.application.Application.unstake_session_end_height": + x.UnstakeSessionEndHeight = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -409,6 +421,9 @@ func (x *fastReflection_Application) Get(descriptor protoreflect.FieldDescriptor } mapValue := &_Application_5_map{m: &x.PendingUndelegations} return protoreflect.ValueOfMap(mapValue) + case "poktroll.application.Application.unstake_session_end_height": + value := x.UnstakeSessionEndHeight + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -445,6 +460,8 @@ func (x *fastReflection_Application) Set(fd protoreflect.FieldDescriptor, value mv := value.Map() cmv := mv.(*_Application_5_map) x.PendingUndelegations = *cmv.m + case "poktroll.application.Application.unstake_session_end_height": + x.UnstakeSessionEndHeight = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -490,6 +507,8 @@ func (x *fastReflection_Application) Mutable(fd protoreflect.FieldDescriptor) pr return protoreflect.ValueOfMap(value) case "poktroll.application.Application.address": panic(fmt.Errorf("field address of message poktroll.application.Application is not mutable")) + case "poktroll.application.Application.unstake_session_end_height": + panic(fmt.Errorf("field unstake_session_end_height of message poktroll.application.Application is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -517,6 +536,8 @@ func (x *fastReflection_Application) NewField(fd protoreflect.FieldDescriptor) p case "poktroll.application.Application.pending_undelegations": m := make(map[uint64]*UndelegatingGatewayList) return protoreflect.ValueOfMap(&_Application_5_map{m: &m}) + case "poktroll.application.Application.unstake_session_end_height": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -634,6 +655,9 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { } } } + if x.UnstakeSessionEndHeight != 0 { + n += 1 + runtime.Sov(uint64(x.UnstakeSessionEndHeight)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -663,6 +687,11 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.UnstakeSessionEndHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.UnstakeSessionEndHeight)) + i-- + dAtA[i] = 0x30 + } if len(x.PendingUndelegations) > 0 { MaRsHaLmAp := func(k uint64, v *UndelegatingGatewayList) (protoiface.MarshalOutput, error) { baseI := i @@ -1055,6 +1084,25 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { } x.PendingUndelegations[mapkey] = mapvalue iNdEx = postIndex + case 6: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UnstakeSessionEndHeight", wireType) + } + x.UnstakeSessionEndHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.UnstakeSessionEndHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -1606,6 +1654,9 @@ type Application struct { // TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment // so its clear to everyone why this is necessary; https://github.com/pokt-network/poktroll/issues/476#issuecomment-2052639906. PendingUndelegations map[uint64]*UndelegatingGatewayList `protobuf:"bytes,5,rep,name=pending_undelegations,json=pendingUndelegations,proto3" json:"pending_undelegations,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // The end height of the session at which an application initiated its unstaking process. + // If the application did not unstake, this value will be 0. + UnstakeSessionEndHeight uint64 `protobuf:"varint,6,opt,name=unstake_session_end_height,json=unstakeSessionEndHeight,proto3" json:"unstake_session_end_height,omitempty"` } func (x *Application) Reset() { @@ -1663,6 +1714,13 @@ func (x *Application) GetPendingUndelegations() map[uint64]*UndelegatingGatewayL return nil } +func (x *Application) GetUnstakeSessionEndHeight() uint64 { + if x != nil { + return x.UnstakeSessionEndHeight + } + return 0 +} + // UndelegatingGatewayList is used as the Value of `pending_undelegations`. // It is required to store a repeated list of strings as a map value. type UndelegatingGatewayList struct { @@ -1713,7 +1771,7 @@ var file_poktroll_application_types_proto_rawDesc = []byte{ 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x04, 0x0a, 0x0b, 0x41, 0x70, 0x70, + 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd1, 0x04, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, @@ -1739,33 +1797,37 @@ var file_poktroll_application_types_proto_rawDesc = []byte{ 0x6e, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x76, 0x0a, 0x19, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x43, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x6e, 0x64, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x64, 0x0a, 0x17, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x47, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x11, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x1c, 0xc8, 0xde, 0x1f, 0x00, 0xd2, 0xb4, 0x2d, 0x14, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x10, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x42, 0xbe, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, - 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x42, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x25, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x50, 0x41, 0x58, 0xaa, 0x02, 0x14, - 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0xca, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x20, 0x50, 0x6f, - 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x15, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3b, 0x0a, 0x1a, 0x75, 0x6e, 0x73, 0x74, 0x61, + 0x6b, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x68, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x75, 0x6e, 0x73, + 0x74, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x48, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x1a, 0x76, 0x0a, 0x19, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, + 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x43, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x64, 0x0a, 0x17, + 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x11, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x42, 0x1c, 0xc8, 0xde, 0x1f, 0x00, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x52, 0x10, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x42, 0xbe, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x50, 0x41, 0x58, 0xaa, 0x02, 0x14, 0x50, 0x6f, 0x6b, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0xca, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x20, 0x50, 0x6f, 0x6b, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x50, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/poktroll/shared/params.pulsar.go b/api/poktroll/shared/params.pulsar.go index 0982420ec..38e93da7d 100644 --- a/api/poktroll/shared/params.pulsar.go +++ b/api/poktroll/shared/params.pulsar.go @@ -15,14 +15,15 @@ import ( ) var ( - md_Params protoreflect.MessageDescriptor - fd_Params_num_blocks_per_session protoreflect.FieldDescriptor - fd_Params_grace_period_end_offset_blocks protoreflect.FieldDescriptor - fd_Params_claim_window_open_offset_blocks protoreflect.FieldDescriptor - fd_Params_claim_window_close_offset_blocks protoreflect.FieldDescriptor - fd_Params_proof_window_open_offset_blocks protoreflect.FieldDescriptor - fd_Params_proof_window_close_offset_blocks protoreflect.FieldDescriptor - fd_Params_supplier_unbonding_period_sessions protoreflect.FieldDescriptor + md_Params protoreflect.MessageDescriptor + fd_Params_num_blocks_per_session protoreflect.FieldDescriptor + fd_Params_grace_period_end_offset_blocks protoreflect.FieldDescriptor + fd_Params_claim_window_open_offset_blocks protoreflect.FieldDescriptor + fd_Params_claim_window_close_offset_blocks protoreflect.FieldDescriptor + fd_Params_proof_window_open_offset_blocks protoreflect.FieldDescriptor + fd_Params_proof_window_close_offset_blocks protoreflect.FieldDescriptor + fd_Params_supplier_unbonding_period_sessions protoreflect.FieldDescriptor + fd_Params_application_unbonding_period_sessions protoreflect.FieldDescriptor ) func init() { @@ -35,6 +36,7 @@ func init() { fd_Params_proof_window_open_offset_blocks = md_Params.Fields().ByName("proof_window_open_offset_blocks") fd_Params_proof_window_close_offset_blocks = md_Params.Fields().ByName("proof_window_close_offset_blocks") fd_Params_supplier_unbonding_period_sessions = md_Params.Fields().ByName("supplier_unbonding_period_sessions") + fd_Params_application_unbonding_period_sessions = md_Params.Fields().ByName("application_unbonding_period_sessions") } var _ protoreflect.Message = (*fastReflection_Params)(nil) @@ -144,6 +146,12 @@ func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, proto return } } + if x.ApplicationUnbondingPeriodSessions != uint64(0) { + value := protoreflect.ValueOfUint64(x.ApplicationUnbondingPeriodSessions) + if !f(fd_Params_application_unbonding_period_sessions, value) { + return + } + } } // Has reports whether a field is populated. @@ -173,6 +181,8 @@ func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { return x.ProofWindowCloseOffsetBlocks != uint64(0) case "poktroll.shared.Params.supplier_unbonding_period_sessions": return x.SupplierUnbondingPeriodSessions != uint64(0) + case "poktroll.shared.Params.application_unbonding_period_sessions": + return x.ApplicationUnbondingPeriodSessions != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Params")) @@ -203,6 +213,8 @@ func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { x.ProofWindowCloseOffsetBlocks = uint64(0) case "poktroll.shared.Params.supplier_unbonding_period_sessions": x.SupplierUnbondingPeriodSessions = uint64(0) + case "poktroll.shared.Params.application_unbonding_period_sessions": + x.ApplicationUnbondingPeriodSessions = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Params")) @@ -240,6 +252,9 @@ func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) pro case "poktroll.shared.Params.supplier_unbonding_period_sessions": value := x.SupplierUnbondingPeriodSessions return protoreflect.ValueOfUint64(value) + case "poktroll.shared.Params.application_unbonding_period_sessions": + value := x.ApplicationUnbondingPeriodSessions + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Params")) @@ -274,6 +289,8 @@ func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value proto x.ProofWindowCloseOffsetBlocks = value.Uint() case "poktroll.shared.Params.supplier_unbonding_period_sessions": x.SupplierUnbondingPeriodSessions = value.Uint() + case "poktroll.shared.Params.application_unbonding_period_sessions": + x.ApplicationUnbondingPeriodSessions = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Params")) @@ -308,6 +325,8 @@ func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protore panic(fmt.Errorf("field proof_window_close_offset_blocks of message poktroll.shared.Params is not mutable")) case "poktroll.shared.Params.supplier_unbonding_period_sessions": panic(fmt.Errorf("field supplier_unbonding_period_sessions of message poktroll.shared.Params is not mutable")) + case "poktroll.shared.Params.application_unbonding_period_sessions": + panic(fmt.Errorf("field application_unbonding_period_sessions of message poktroll.shared.Params is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Params")) @@ -335,6 +354,8 @@ func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protor return protoreflect.ValueOfUint64(uint64(0)) case "poktroll.shared.Params.supplier_unbonding_period_sessions": return protoreflect.ValueOfUint64(uint64(0)) + case "poktroll.shared.Params.application_unbonding_period_sessions": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Params")) @@ -425,6 +446,9 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { if x.SupplierUnbondingPeriodSessions != 0 { n += 1 + runtime.Sov(uint64(x.SupplierUnbondingPeriodSessions)) } + if x.ApplicationUnbondingPeriodSessions != 0 { + n += 1 + runtime.Sov(uint64(x.ApplicationUnbondingPeriodSessions)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -454,6 +478,11 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.ApplicationUnbondingPeriodSessions != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ApplicationUnbondingPeriodSessions)) + i-- + dAtA[i] = 0x40 + } if x.SupplierUnbondingPeriodSessions != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.SupplierUnbondingPeriodSessions)) i-- @@ -671,6 +700,25 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { break } } + case 8: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ApplicationUnbondingPeriodSessions", wireType) + } + x.ApplicationUnbondingPeriodSessions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ApplicationUnbondingPeriodSessions |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -749,6 +797,11 @@ type Params struct { // On-chain business logic requires, and ensures, that the corresponding block count of the unbonding // period will exceed the end of any active claim & proof lifecycles. SupplierUnbondingPeriodSessions uint64 `protobuf:"varint,7,opt,name=supplier_unbonding_period_sessions,json=supplierUnbondingPeriodSessions,proto3" json:"supplier_unbonding_period_sessions,omitempty"` + // application_unbonding_period_sessions is the number of sessions that an application must wait after + // unstaking before their staked assets are moved to their account balance. + // On-chain business logic requires, and ensures, that the corresponding block count of the + // application unbonding period will exceed the end of its corresponding proof window close height. + ApplicationUnbondingPeriodSessions uint64 `protobuf:"varint,8,opt,name=application_unbonding_period_sessions,json=applicationUnbondingPeriodSessions,proto3" json:"application_unbonding_period_sessions,omitempty"` } func (x *Params) Reset() { @@ -820,6 +873,13 @@ func (x *Params) GetSupplierUnbondingPeriodSessions() uint64 { return 0 } +func (x *Params) GetApplicationUnbondingPeriodSessions() uint64 { + if x != nil { + return x.ApplicationUnbondingPeriodSessions + } + return 0 +} + var File_poktroll_shared_params_proto protoreflect.FileDescriptor var file_poktroll_shared_params_proto_rawDesc = []byte{ @@ -828,7 +888,7 @@ var file_poktroll_shared_params_proto_rawDesc = []byte{ 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, - 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8b, 0x06, 0x0a, 0x06, 0x50, 0x61, 0x72, + 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x89, 0x07, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x16, 0x6e, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x1a, 0xea, 0xde, 0x1f, 0x16, 0x6e, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, @@ -875,20 +935,27 @@ var file_poktroll_shared_params_proto_rawDesc = []byte{ 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x1f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x55, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x3a, 0x21, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x70, 0x6f, - 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x78, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xa1, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x70, - 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x0b, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0xa2, - 0x02, 0x03, 0x50, 0x53, 0x58, 0xaa, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0xca, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0xe2, 0x02, 0x1b, 0x50, 0x6f, 0x6b, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x10, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x3a, 0x3a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6f, 0x6e, 0x73, 0x12, 0x7c, 0x0a, 0x25, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, + 0x69, 0x6f, 0x64, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x29, 0xea, 0xde, 0x1f, 0x25, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, + 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x22, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x62, 0x6f, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x3a, 0x21, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x70, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x78, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x42, 0xa1, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x0b, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0xa2, 0x02, 0x03, + 0x50, 0x53, 0x58, 0xaa, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, + 0x68, 0x61, 0x72, 0x65, 0x64, 0xca, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0xe2, 0x02, 0x1b, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x10, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x3a, 0x3a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index f204a4ad5..2fcad22b7 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -501,7 +501,7 @@ func (s *suite) TheSupplierForAccountIsUnbonding(supplierOperatorName string) { require.True(s, supplier.IsUnbonding()) } -func (s *suite) TheUserWaitsForUnbondingPeriodToFinish(accName string) { +func (s *suite) TheUserWaitsForTheSupplierForAccountUnbondingPeriodToFinish(accName string) { _, ok := operatorAccNameToSupplierMap[accName] require.True(s, ok, "supplier %s not found", accName) @@ -509,6 +509,24 @@ func (s *suite) TheUserWaitsForUnbondingPeriodToFinish(accName string) { s.waitForBlockHeight(unbondingHeight + 1) // Add 1 to ensure the unbonding block has been committed } +func (s *suite) TheApplicationForAccountIsUnbonding(appName string) { + _, ok := accNameToAppMap[appName] + require.True(s, ok, "application %s not found", appName) + + s.waitForTxResultEvent(newEventMsgTypeMatchFn("application", "UnstakeApplication")) + + supplier := s.getApplicationInfo(appName) + require.True(s, supplier.IsUnbonding()) +} + +func (s *suite) TheUserWaitsForTheApplicationForAccountUnbondingPeriodToFinish(accName string) { + _, ok := accNameToAppMap[accName] + require.True(s, ok, "application %s not found", accName) + + unbondingHeight := s.getApplicationUnbondingHeight(accName) + s.waitForBlockHeight(unbondingHeight + 1) // Add 1 to ensure the unbonding block has been committed +} + func (s *suite) getStakedAmount(actorType, accName string) (int, bool) { s.Helper() args := []string{ @@ -724,6 +742,48 @@ func (s *suite) getSupplierUnbondingHeight(accName string) int64 { return unbondingHeight } +// getApplicationInfo returns the application information for a given application address. +func (s *suite) getApplicationInfo(appName string) *apptypes.Application { + appAddr := accNameToAddrMap[appName] + args := []string{ + "query", + "application", + "show-application", + appAddr, + "--output=json", + } + + res, err := s.pocketd.RunCommandOnHostWithRetry("", numQueryRetries, args...) + require.NoError(s, err, "error getting supplier %s", appAddr) + s.pocketd.result = res + + var resp apptypes.QueryGetApplicationResponse + responseBz := []byte(strings.TrimSpace(res.Stdout)) + s.cdc.MustUnmarshalJSON(responseBz, &resp) + return &resp.Application +} + +// getApplicationUnbondingHeight returns the height at which the application will be unbonded. +func (s *suite) getApplicationUnbondingHeight(accName string) int64 { + application := s.getApplicationInfo(accName) + + args := []string{ + "query", + "shared", + "params", + "--output=json", + } + + res, err := s.pocketd.RunCommandOnHostWithRetry("", numQueryRetries, args...) + require.NoError(s, err, "error getting shared module params") + + var resp sharedtypes.QueryParamsResponse + responseBz := []byte(strings.TrimSpace(res.Stdout)) + s.cdc.MustUnmarshalJSON(responseBz, &resp) + unbondingHeight := apptypes.GetApplicationUnbondingHeight(&resp.Params, application) + return unbondingHeight +} + // getServiceComputeUnitsPerRelay returns the compute units per relay for a given service ID func (s *suite) getServiceComputeUnitsPerRelay(serviceId string) uint64 { args := []string{ diff --git a/e2e/tests/parse_params_test.go b/e2e/tests/parse_params_test.go index 894478374..af6571fb5 100644 --- a/e2e/tests/parse_params_test.go +++ b/e2e/tests/parse_params_test.go @@ -172,6 +172,8 @@ func (s *suite) newSharedMsgUpdateParams(params paramsMap) cosmostypes.Msg { msgUpdateParams.Params.ProofWindowCloseOffsetBlocks = uint64(paramValue.value.(int64)) case sharedtypes.ParamSupplierUnbondingPeriodSessions: msgUpdateParams.Params.SupplierUnbondingPeriodSessions = uint64(paramValue.value.(int64)) + case sharedtypes.ParamApplicationUnbondingPeriodSessions: + msgUpdateParams.Params.ApplicationUnbondingPeriodSessions = uint64(paramValue.value.(int64)) default: s.Fatalf("ERROR: unexpected %q type param name %q", paramValue.typeStr, paramName) } diff --git a/e2e/tests/stake_app.feature b/e2e/tests/stake_app.feature index e0b29b03e..0ea08d7b5 100644 --- a/e2e/tests/stake_app.feature +++ b/e2e/tests/stake_app.feature @@ -1,10 +1,8 @@ Feature: Stake App Namespaces - Scenario: User can stake an Application + Scenario: User can stake an Application waiting for it to unbond Given the user has the pocketd binary installed And the user verifies the "application" for account "app2" is not staked - # Stake with 1 uPOKT more than the current stake used in genesis to make - # the transaction succeed. And the account "app2" has a balance greater than "1000070" uPOKT When the user stakes a "application" with "1000070" uPOKT for "anvil" service from the account "app2" Then the user should be able to see standard output containing "txhash:" @@ -22,6 +20,7 @@ Feature: Stake App Namespaces Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - And the user should wait for the "application" module "UnstakeApplication" message to be submitted + And the application for account "app2" is unbonding + When the user waits for the application for account "app2" unbonding period to finish And the user verifies the "application" for account "app2" is not staked And the account balance of "app2" should be "1000070" uPOKT "more" than before \ No newline at end of file diff --git a/e2e/tests/stake_supplier.feature b/e2e/tests/stake_supplier.feature index 5adedc42b..8a9aff15d 100644 --- a/e2e/tests/stake_supplier.feature +++ b/e2e/tests/stake_supplier.feature @@ -21,7 +21,7 @@ Feature: Stake Supplier Namespace And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error And the supplier for account "supplier2" is unbonding - When the user waits for "supplier2" unbonding period to finish + When the user waits for the supplier for account "supplier2" unbonding period to finish Then the user verifies the "supplier" for account "supplier2" is not staked And the account balance of "supplier2" should be "1000070" uPOKT "more" than before diff --git a/e2e/tests/update_params.feature b/e2e/tests/update_params.feature index 862d08d8f..32297eaac 100644 --- a/e2e/tests/update_params.feature +++ b/e2e/tests/update_params.feature @@ -51,14 +51,15 @@ Feature: Params Namespace And all "shared" module params are set to their default values And an authz grant from the "gov" "module" account to the "pnf" "user" account for the "/poktroll.shared.MsgUpdateParams" message exists When the "pnf" account sends an authz exec message to update all "shared" module params - | name | value | type | - | num_blocks_per_session | 5 | int64 | - | grace_period_end_offset_blocks | 2 | int64 | - | claim_window_open_offset_blocks | 2 | int64 | - | claim_window_close_offset_blocks | 3 | int64 | - | proof_window_open_offset_blocks | 1 | int64 | - | proof_window_close_offset_blocks | 5 | int64 | - | supplier_unbonding_period_sessions | 5 | int64 | + | name | value | type | + | num_blocks_per_session | 5 | int64 | + | grace_period_end_offset_blocks | 2 | int64 | + | claim_window_open_offset_blocks | 2 | int64 | + | claim_window_close_offset_blocks | 3 | int64 | + | proof_window_open_offset_blocks | 1 | int64 | + | proof_window_close_offset_blocks | 5 | int64 | + | supplier_unbonding_period_sessions | 5 | int64 | + | application_unbonding_period_sessions | 5 | int64 | Then all "shared" module params should be updated # NB: If you are reading this and any module has parameters that @@ -73,19 +74,20 @@ Feature: Params Namespace Then the "" module param "" should be updated Examples: - | module | message_type | param_name | param_value | param_type | - | tokenomics | /poktroll.tokenomics.MsgUpdateParam | compute_units_to_tokens_multiplier | 68 | int64 | - | proof | /poktroll.proof.MsgUpdateParam | min_relay_difficulty_bits | 12 | int64 | - | proof | /poktroll.proof.MsgUpdateParam | proof_request_probability | 0.1 | float | - | proof | /poktroll.proof.MsgUpdateParam | proof_requirement_threshold | 100 | int64 | - | proof | /poktroll.proof.MsgUpdateParam | proof_missing_penalty | 500 | coin | - | shared | /poktroll.shared.MsgUpdateParam | num_blocks_per_session | 5 | int64 | - | shared | /poktroll.shared.MsgUpdateParam | grace_period_end_offset_blocks | 2 | int64 | - | shared | /poktroll.shared.MsgUpdateParam | claim_window_open_offset_blocks | 2 | int64 | - | shared | /poktroll.shared.MsgUpdateParam | claim_window_close_offset_blocks | 3 | int64 | - | shared | /poktroll.shared.MsgUpdateParam | proof_window_open_offset_blocks | 1 | int64 | - | shared | /poktroll.shared.MsgUpdateParam | proof_window_close_offset_blocks | 5 | int64 | - | shared | /poktroll.shared.MsgUpdateParam | supplier_unbonding_period_sessions | 5 | int64 | + | module | message_type | param_name | param_value | param_type | + | tokenomics | /poktroll.tokenomics.MsgUpdateParam | compute_units_to_tokens_multiplier | 68 | int64 | + | proof | /poktroll.proof.MsgUpdateParam | min_relay_difficulty_bits | 12 | int64 | + | proof | /poktroll.proof.MsgUpdateParam | proof_request_probability | 0.1 | float | + | proof | /poktroll.proof.MsgUpdateParam | proof_requirement_threshold | 100 | int64 | + | proof | /poktroll.proof.MsgUpdateParam | proof_missing_penalty | 500 | coin | + | shared | /poktroll.shared.MsgUpdateParam | num_blocks_per_session | 5 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | grace_period_end_offset_blocks | 2 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | claim_window_open_offset_blocks | 2 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | claim_window_close_offset_blocks | 3 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | proof_window_open_offset_blocks | 1 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | proof_window_close_offset_blocks | 5 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | supplier_unbonding_period_sessions | 5 | int64 | + | shared | /poktroll.shared.MsgUpdateParam | application_unbonding_period_sessions | 5 | int64 | Scenario: An unauthorized user cannot update individual module params Given the user has the pocketd binary installed diff --git a/e2e/tests/update_params_test.go b/e2e/tests/update_params_test.go index b17f40bb2..ddc4762e7 100644 --- a/e2e/tests/update_params_test.go +++ b/e2e/tests/update_params_test.go @@ -436,6 +436,11 @@ func (s *suite) assertExpectedModuleParamsUpdated(moduleName string) { params.SupplierUnbondingPeriodSessions = uint64(supplierUnbondingPeriodSessions.value.(int64)) } + applicationUnbondingPeriodSessions, ok := paramsMap[sharedtypes.ParamApplicationUnbondingPeriodSessions] + if ok { + params.ApplicationUnbondingPeriodSessions = uint64(applicationUnbondingPeriodSessions.value.(int64)) + } + assertUpdatedParams(s, []byte(res.Stdout), &sharedtypes.QueryParamsResponse{ diff --git a/proto/poktroll/application/types.proto b/proto/poktroll/application/types.proto index f2fc18f0f..e55f2e303 100644 --- a/proto/poktroll/application/types.proto +++ b/proto/poktroll/application/types.proto @@ -21,13 +21,16 @@ message Application { // TODO_BETA: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. // Ensure to rename all relevant configs, comments, variables, function names, etc as well. repeated string delegatee_gateway_addresses = 4 [(cosmos_proto.scalar) = "cosmos.AddressString", (gogoproto.nullable) = false]; // The Bech32 encoded addresses for all delegatee Gateways, in a non-nullable slice - // A map from sessionEndHeights to a list of Gateways. - // The key is the height of the last block of the session during which the - // respective undelegation was committed. - // The value is a list of gateways being undelegated from. - // TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment + // A map from sessionEndHeights to a list of Gateways. + // The key is the height of the last block of the session during which the + // respective undelegation was committed. + // The value is a list of gateways being undelegated from. + // TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment // so its clear to everyone why this is necessary; https://github.com/pokt-network/poktroll/issues/476#issuecomment-2052639906. map pending_undelegations = 5 [(gogoproto.nullable) = false]; + // The end height of the session at which an application initiated its unstaking process. + // If the application did not unstake, this value will be 0. + uint64 unstake_session_end_height = 6; } // UndelegatingGatewayList is used as the Value of `pending_undelegations`. diff --git a/proto/poktroll/shared/params.proto b/proto/poktroll/shared/params.proto index 9e24b959f..1feeb2941 100644 --- a/proto/poktroll/shared/params.proto +++ b/proto/poktroll/shared/params.proto @@ -35,4 +35,9 @@ message Params { // On-chain business logic requires, and ensures, that the corresponding block count of the unbonding // period will exceed the end of any active claim & proof lifecycles. uint64 supplier_unbonding_period_sessions = 7 [(gogoproto.jsontag) = "supplier_unbonding_period_sessions"]; + // application_unbonding_period_sessions is the number of sessions that an application must wait after + // unstaking before their staked assets are moved to their account balance. + // On-chain business logic requires, and ensures, that the corresponding block count of the + // application unbonding period will exceed the end of its corresponding proof window close height. + uint64 application_unbonding_period_sessions = 8 [(gogoproto.jsontag) = "application_unbonding_period_sessions"]; } \ No newline at end of file diff --git a/testutil/keeper/application.go b/testutil/keeper/application.go index 97d578a09..312472327 100644 --- a/testutil/keeper/application.go +++ b/testutil/keeper/application.go @@ -34,7 +34,16 @@ import ( // WARNING: Using this map may cause issues if running multiple tests in parallel var stakedGatewayMap = make(map[string]struct{}) -func ApplicationKeeper(t testing.TB) (keeper.Keeper, context.Context) { +// ApplicationModuleKeepers is a struct that contains the keepers needed for testing +// the application module. +type ApplicationModuleKeepers struct { + *keeper.Keeper + types.SharedKeeper +} + +// NewApplicationModuleKeepers creates a new application keeper for testing along +// with its dependencies then returns the application module keepers and context. +func NewApplicationModuleKeepers(t testing.TB) (ApplicationModuleKeepers, context.Context) { t.Helper() storeKey := storetypes.NewKVStoreKey(types.StoreKey) @@ -81,7 +90,7 @@ func ApplicationKeeper(t testing.TB) (keeper.Keeper, context.Context) { }). AnyTimes() - k := keeper.NewKeeper( + appKeeper := keeper.NewKeeper( cdc, runtime.NewKVStoreService(storeKey), log.NewNopLogger(), @@ -95,9 +104,28 @@ func ApplicationKeeper(t testing.TB) (keeper.Keeper, context.Context) { ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) // Initialize params - require.NoError(t, k.SetParams(ctx, types.DefaultParams())) + require.NoError(t, appKeeper.SetParams(ctx, types.DefaultParams())) + + // Move block height to 1 to get a non zero session end height + sdkCtx := sdk.UnwrapSDKContext(ctx) + ctx = sdkCtx.WithBlockHeight(1) + + applicationModuleKeepers := ApplicationModuleKeepers{ + Keeper: &appKeeper, + SharedKeeper: mockSharedKeeper, + } + + return applicationModuleKeepers, ctx +} + +// ApplicationKeeper creates a new application keeper for testing and returns +// the keeper and context. +func ApplicationKeeper(t testing.TB) (keeper.Keeper, context.Context) { + t.Helper() + + applicationModuleKeepers, ctx := NewApplicationModuleKeepers(t) - return k, ctx + return *applicationModuleKeepers.Keeper, ctx } // AddGatewayToStakedGatewayMap adds the given gateway address to the staked diff --git a/x/application/keeper/msg_server_stake_application.go b/x/application/keeper/msg_server_stake_application.go index cb83ca787..a51f64d38 100644 --- a/x/application/keeper/msg_server_stake_application.go +++ b/x/application/keeper/msg_server_stake_application.go @@ -47,6 +47,9 @@ func (k msgServer) StakeApplication(ctx context.Context, msg *types.MsgStakeAppl return nil, err } logger.Info(fmt.Sprintf("Application is going to escrow an additional %+v coins", coinsToEscrow)) + + // If the application has initiated an unstake action, cancel it since it is staking again. + foundApp.UnstakeSessionEndHeight = types.ApplicationNotUnstaking } // Must always stake or upstake (> 0 delta) diff --git a/x/application/keeper/msg_server_unstake_application.go b/x/application/keeper/msg_server_unstake_application.go index 74f662d41..7fbdc9f58 100644 --- a/x/application/keeper/msg_server_unstake_application.go +++ b/x/application/keeper/msg_server_unstake_application.go @@ -8,6 +8,7 @@ import ( "github.com/pokt-network/poktroll/telemetry" "github.com/pokt-network/poktroll/x/application/types" + "github.com/pokt-network/poktroll/x/shared" ) // TODO(#489): Determine if an application needs an unbonding period after unstaking. @@ -25,8 +26,7 @@ func (k msgServer) UnstakeApplication( logger := k.Logger().With("method", "UnstakeApplication") logger.Info(fmt.Sprintf("About to unstake application with msg: %v", msg)) - // Check if the application already exists or not - var err error + // Check if the application already exists or not. foundApp, isAppFound := k.GetApplication(ctx, msg.Address) if !isAppFound { logger.Info(fmt.Sprintf("Application not found. Cannot unstake address %s", msg.Address)) @@ -34,23 +34,22 @@ func (k msgServer) UnstakeApplication( } logger.Info(fmt.Sprintf("Application found. Unstaking application for address %s", msg.Address)) - // Retrieve the address of the application - appAddress, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - logger.Error(fmt.Sprintf("could not parse address %s", msg.Address)) - return nil, err + // Check if the application has already initiated the unstaking process. + if foundApp.IsUnbonding() { + logger.Warn(fmt.Sprintf("Application %s is still unbonding from previous unstaking", msg.Address)) + return nil, types.ErrAppIsUnstaking } - // Send the coins from the application pool back to the application - err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, appAddress, []sdk.Coin{*foundApp.Stake}) - if err != nil { - logger.Error(fmt.Sprintf("could not send %v coins from %s module to %s account due to %v", foundApp.Stake, appAddress, types.ModuleName, err)) - return nil, err - } + sdkCtx := sdk.UnwrapSDKContext(ctx) + currentHeight := sdkCtx.BlockHeight() + sharedParams := k.sharedKeeper.GetParams(sdkCtx) - // Update the Application in the store - k.RemoveApplication(ctx, appAddress.String()) - logger.Info(fmt.Sprintf("Successfully removed the application: %+v", foundApp)) + // Mark the application as unstaking by recording the height at which it should + // no longer be able to request services. + // The application MAY continue to request service until the end of the current + // session. After that, the application will be considered inactive. + foundApp.UnstakeSessionEndHeight = uint64(shared.GetSessionEndHeight(&sharedParams, currentHeight)) + k.SetApplication(ctx, foundApp) isSuccessful = true return &types.MsgUnstakeApplicationResponse{}, nil diff --git a/x/application/keeper/msg_server_unstake_application_test.go b/x/application/keeper/msg_server_unstake_application_test.go index 23f3c1e0c..cc0a7ac10 100644 --- a/x/application/keeper/msg_server_unstake_application_test.go +++ b/x/application/keeper/msg_server_unstake_application_test.go @@ -15,58 +15,135 @@ import ( ) func TestMsgServer_UnstakeApplication_Success(t *testing.T) { - k, ctx := keepertest.ApplicationKeeper(t) - srv := keeper.NewMsgServerImpl(k) + applicationModuleKeepers, ctx := keepertest.NewApplicationModuleKeepers(t) + srv := keeper.NewMsgServerImpl(*applicationModuleKeepers.Keeper) + sharedParams := applicationModuleKeepers.SharedKeeper.GetParams(ctx) // Generate an address for the application - appAddr := sample.AccAddress() + unstakingAppAddr := sample.AccAddress() // Verify that the app does not exist yet - _, isAppFound := k.GetApplication(ctx, appAddr) + _, isAppFound := applicationModuleKeepers.GetApplication(ctx, unstakingAppAddr) require.False(t, isAppFound) // Prepare the application - initialStake := sdk.NewCoin("upokt", math.NewInt(100)) - stakeMsg := &types.MsgStakeApplication{ - Address: appAddr, - Stake: &initialStake, - Services: []*sharedtypes.ApplicationServiceConfig{ - { - Service: &sharedtypes.Service{Id: "svc1"}, - }, - }, - } + initialStake := int64(100) + stakeMsg := createAppStakeMsg(unstakingAppAddr, initialStake) // Stake the application _, err := srv.StakeApplication(ctx, stakeMsg) require.NoError(t, err) // Verify that the application exists - appFound, isAppFound := k.GetApplication(ctx, appAddr) + foundApp, isAppFound := applicationModuleKeepers.GetApplication(ctx, unstakingAppAddr) + require.True(t, isAppFound) + require.Equal(t, unstakingAppAddr, foundApp.Address) + require.Equal(t, initialStake, foundApp.Stake.Amount.Int64()) + require.Len(t, foundApp.ServiceConfigs, 1) + + // Create and stake another application that will not be unstaked to assert that + // only the unstaking application is removed from the applications list when the + // unbonding period is over. + nonUnstakingAppAddr := sample.AccAddress() + stakeMsg = createAppStakeMsg(nonUnstakingAppAddr, initialStake) + _, err = srv.StakeApplication(ctx, stakeMsg) + require.NoError(t, err) + + // Verify that the non-unstaking application exists + _, isAppFound = applicationModuleKeepers.GetApplication(ctx, nonUnstakingAppAddr) require.True(t, isAppFound) - require.Equal(t, appAddr, appFound.Address) - require.Equal(t, initialStake.Amount, appFound.Stake.Amount) - require.Len(t, appFound.ServiceConfigs, 1) // Unstake the application - unstakeMsg := &types.MsgUnstakeApplication{Address: appAddr} + unstakeMsg := &types.MsgUnstakeApplication{Address: unstakingAppAddr} _, err = srv.UnstakeApplication(ctx, unstakeMsg) require.NoError(t, err) - // Make sure the app can no longer be found after unstaking - _, isAppFound = k.GetApplication(ctx, appAddr) + // Make sure the application entered the unbonding period + foundApp, isAppFound = applicationModuleKeepers.GetApplication(ctx, unstakingAppAddr) + require.True(t, isAppFound) + require.True(t, foundApp.IsUnbonding()) + + // Move block height to the end of the unbonding period + unbondingHeight := types.GetApplicationUnbondingHeight(&sharedParams, &foundApp) + ctx = keepertest.SetBlockHeight(ctx, unbondingHeight) + + // Run the endblocker to unbond applications + err = applicationModuleKeepers.EndBlockerUnbondApplications(ctx) + require.NoError(t, err) + + // Make sure the unstaking application is removed from the applications list when + // the unbonding period is over. + _, isAppFound = applicationModuleKeepers.GetApplication(ctx, unstakingAppAddr) require.False(t, isAppFound) + + // Verify that the non-unstaking application still exists. + nonUnstakingApplication, isAppFound := applicationModuleKeepers.GetApplication(ctx, nonUnstakingAppAddr) + require.True(t, isAppFound) + require.False(t, nonUnstakingApplication.IsUnbonding()) +} + +func TestMsgServer_UnstakeApplication_CancelUnbondingIfRestaked(t *testing.T) { + applicationModuleKeepers, ctx := keepertest.NewApplicationModuleKeepers(t) + srv := keeper.NewMsgServerImpl(*applicationModuleKeepers.Keeper) + sharedParams := applicationModuleKeepers.SharedKeeper.GetParams(ctx) + + // Generate an address for the application + appAddr := sample.AccAddress() + + // Stake the application + initialStake := int64(100) + stakeMsg := createAppStakeMsg(appAddr, initialStake) + _, err := srv.StakeApplication(ctx, stakeMsg) + require.NoError(t, err) + + // Verify that the application exists with no unbonding height + foundApp, isAppFound := applicationModuleKeepers.GetApplication(ctx, appAddr) + require.True(t, isAppFound) + require.False(t, foundApp.IsUnbonding()) + + // Initiate the application unstaking + unstakeMsg := &types.MsgUnstakeApplication{Address: appAddr} + _, err = srv.UnstakeApplication(ctx, unstakeMsg) + require.NoError(t, err) + + // Make sure the application entered the unbonding period + foundApp, isAppFound = applicationModuleKeepers.GetApplication(ctx, appAddr) + require.True(t, isAppFound) + require.True(t, foundApp.IsUnbonding()) + + unbondingHeight := types.GetApplicationUnbondingHeight(&sharedParams, &foundApp) + + // Stake the application again + stakeMsg = createAppStakeMsg(appAddr, initialStake+1) + _, err = srv.StakeApplication(ctx, stakeMsg) + require.NoError(t, err) + + // Make sure the application is no longer in the unbonding period + foundApp, isAppFound = applicationModuleKeepers.GetApplication(ctx, appAddr) + require.True(t, isAppFound) + require.False(t, foundApp.IsUnbonding()) + + ctx = keepertest.SetBlockHeight(ctx, int64(unbondingHeight)) + + // Run the EndBlocker, the application should not be unbonding. + err = applicationModuleKeepers.EndBlockerUnbondApplications(ctx) + require.NoError(t, err) + + // Make sure the application exists with an unbonding height of 0 + foundApp, isAppFound = applicationModuleKeepers.GetApplication(ctx, appAddr) + require.True(t, isAppFound) + require.False(t, foundApp.IsUnbonding()) } func TestMsgServer_UnstakeApplication_FailIfNotStaked(t *testing.T) { - k, ctx := keepertest.ApplicationKeeper(t) - srv := keeper.NewMsgServerImpl(k) + applicationModuleKeepers, ctx := keepertest.NewApplicationModuleKeepers(t) + srv := keeper.NewMsgServerImpl(*applicationModuleKeepers.Keeper) // Generate an address for the application appAddr := sample.AccAddress() // Verify that the app does not exist yet - _, isAppFound := k.GetApplication(ctx, appAddr) + _, isAppFound := applicationModuleKeepers.GetApplication(ctx, appAddr) require.False(t, isAppFound) // Unstake the application @@ -75,6 +152,46 @@ func TestMsgServer_UnstakeApplication_FailIfNotStaked(t *testing.T) { require.Error(t, err) require.ErrorIs(t, err, types.ErrAppNotFound) - _, isAppFound = k.GetApplication(ctx, appAddr) + _, isAppFound = applicationModuleKeepers.GetApplication(ctx, appAddr) require.False(t, isAppFound) } + +func TestMsgServer_UnstakeApplication_FailIfCurrentlyUnstaking(t *testing.T) { + applicationModuleKeepers, ctx := keepertest.NewApplicationModuleKeepers(t) + srv := keeper.NewMsgServerImpl(*applicationModuleKeepers.Keeper) + + // Generate an address for the application + appAddr := sample.AccAddress() + + // Stake the application + initialStake := int64(100) + stakeMsg := createAppStakeMsg(appAddr, initialStake) + _, err := srv.StakeApplication(ctx, stakeMsg) + require.NoError(t, err) + + // Initiate the application unstaking + unstakeMsg := &types.MsgUnstakeApplication{Address: appAddr} + _, err = srv.UnstakeApplication(ctx, unstakeMsg) + require.NoError(t, err) + + sdkCtx := sdk.UnwrapSDKContext(ctx) + ctx = keepertest.SetBlockHeight(ctx, int64(sdkCtx.BlockHeight()+1)) + + // Verify that the application cannot unstake if it is already unstaking. + _, err = srv.UnstakeApplication(ctx, unstakeMsg) + require.ErrorIs(t, err, types.ErrAppIsUnstaking) +} + +func createAppStakeMsg(appAddr string, stakeAmount int64) *types.MsgStakeApplication { + initialStake := sdk.NewCoin("upokt", math.NewInt(stakeAmount)) + + return &types.MsgStakeApplication{ + Address: appAddr, + Stake: &initialStake, + Services: []*sharedtypes.ApplicationServiceConfig{ + { + Service: &sharedtypes.Service{Id: "svc1"}, + }, + }, + } +} diff --git a/x/application/keeper/unbond_applications.go b/x/application/keeper/unbond_applications.go new file mode 100644 index 000000000..38bbe2ef9 --- /dev/null +++ b/x/application/keeper/unbond_applications.go @@ -0,0 +1,67 @@ +package keeper + +import ( + "context" + "fmt" + + cosmostypes "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/poktroll/x/application/types" +) + +// EndBlockerUnbondApplications unbonds applications whose unbonding period has elapsed. +func (k Keeper) EndBlockerUnbondApplications(ctx context.Context) error { + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) + sharedParams := k.sharedKeeper.GetParams(sdkCtx) + currentHeight := sdkCtx.BlockHeight() + + // Only process unbonding applications at the end of the session. + if currentHeight != k.sharedKeeper.GetSessionEndHeight(ctx, currentHeight) { + return nil + } + + logger := k.Logger().With("method", "UnbondApplication") + + // Iterate over all applications and unbond the ones that have finished the unbonding period. + // TODO_IMPROVE: Use an index to iterate over the applications that have initiated + // the unbonding action instead of iterating over all of them. + for _, application := range k.GetAllApplications(ctx) { + // Ignore applications that have not initiated the unbonding action. + if !application.IsUnbonding() { + continue + } + + unbondingHeight := types.GetApplicationUnbondingHeight(&sharedParams, &application) + + // If the unbonding height is ahead of the current height, the application + // stays in the unbonding state. + if unbondingHeight > currentHeight { + continue + } + + // Retrieve the account address of the application. + applicationAccAddress, err := cosmostypes.AccAddressFromBech32(application.Address) + if err != nil { + logger.Error(fmt.Sprintf("could not parse address %s", application.Address)) + return err + } + + // Send the coins from the application pool back to the application + err = k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, applicationAccAddress, []sdk.Coin{*application.Stake}, + ) + if err != nil { + logger.Error(fmt.Sprintf( + "could not send %v coins from module %s to account %s due to %v", + application.Stake, applicationAccAddress, types.ModuleName, err, + )) + return err + } + + // Update the Application in the store + k.RemoveApplication(ctx, applicationAccAddress.String()) + logger.Info(fmt.Sprintf("Successfully removed the application: %+v", application)) + } + + return nil +} diff --git a/x/application/module/abci.go b/x/application/module/abci.go index ed331c3fe..3f0b16f4d 100644 --- a/x/application/module/abci.go +++ b/x/application/module/abci.go @@ -16,5 +16,9 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) error { return err } + if err := k.EndBlockerUnbondApplications(ctx); err != nil { + return err + } + return nil } diff --git a/x/application/types/application.go b/x/application/types/application.go new file mode 100644 index 000000000..b838df69a --- /dev/null +++ b/x/application/types/application.go @@ -0,0 +1,34 @@ +package types + +import sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + +// ApplicationNotUnstaking is the value of `unstake_session_end_height` if the +// application is not actively in the unbonding period. +const ApplicationNotUnstaking uint64 = 0 + +// IsUnbonding returns true if the application is actively unbonding. +// It determines if the application has submitted an unstake message, in which case +// the application has its UnstakeSessionEndHeight set. +func (s *Application) IsUnbonding() bool { + return s.UnstakeSessionEndHeight != ApplicationNotUnstaking +} + +// IsActive returns whether the application is allowed to request services at the +// given query height. +// An application that has not submitted an unstake message is always active. +// An application that has submitted an unstake message is active until the end of +// the session containing the height at which unstake message was submitted. +func (s *Application) IsActive(queryHeight int64) bool { + return !s.IsUnbonding() || uint64(queryHeight) <= s.UnstakeSessionEndHeight +} + +// GetApplicationUnbondingHeight returns the session end height at which the given +// application finishes unbonding. +func GetApplicationUnbondingHeight( + sharedParams *sharedtypes.Params, + application *Application, +) int64 { + applicationUnbondingPeriodSessions := sharedParams.ApplicationUnbondingPeriodSessions * sharedParams.NumBlocksPerSession + + return int64(application.UnstakeSessionEndHeight + applicationUnbondingPeriodSessions) +} diff --git a/x/application/types/errors.go b/x/application/types/errors.go index 981a11a3c..67754829b 100644 --- a/x/application/types/errors.go +++ b/x/application/types/errors.go @@ -18,4 +18,5 @@ var ( ErrAppMaxDelegatedGateways = sdkerrors.Register(ModuleName, 1110, "maximum number of delegated gateways reached") ErrAppInvalidMaxDelegatedGateways = sdkerrors.Register(ModuleName, 1111, "invalid MaxDelegatedGateways parameter") ErrAppNotDelegated = sdkerrors.Register(ModuleName, 1112, "application not delegated to gateway") + ErrAppIsUnstaking = sdkerrors.Register(ModuleName, 1113, "application is in unbonding period") ) diff --git a/x/application/types/types.pb.go b/x/application/types/types.pb.go index 2e9c55442..08c8cfafe 100644 --- a/x/application/types/types.pb.go +++ b/x/application/types/types.pb.go @@ -41,6 +41,9 @@ type Application struct { // TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment // so its clear to everyone why this is necessary; https://github.com/pokt-network/poktroll/issues/476#issuecomment-2052639906. PendingUndelegations map[uint64]UndelegatingGatewayList `protobuf:"bytes,5,rep,name=pending_undelegations,json=pendingUndelegations,proto3" json:"pending_undelegations" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // The end height of the session at which an application initiated its unstaking process. + // If the application did not unstake, this value will be 0. + UnstakeSessionEndHeight uint64 `protobuf:"varint,6,opt,name=unstake_session_end_height,json=unstakeSessionEndHeight,proto3" json:"unstake_session_end_height,omitempty"` } func (m *Application) Reset() { *m = Application{} } @@ -111,6 +114,13 @@ func (m *Application) GetPendingUndelegations() map[uint64]UndelegatingGatewayLi return nil } +func (m *Application) GetUnstakeSessionEndHeight() uint64 { + if m != nil { + return m.UnstakeSessionEndHeight + } + return 0 +} + // UndelegatingGatewayList is used as the Value of `pending_undelegations`. // It is required to store a repeated list of strings as a map value. type UndelegatingGatewayList struct { @@ -166,37 +176,39 @@ func init() { func init() { proto.RegisterFile("poktroll/application/types.proto", fileDescriptor_1899440439257283) } var fileDescriptor_1899440439257283 = []byte{ - // 473 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x4f, 0x8b, 0xd3, 0x40, - 0x18, 0xc6, 0x9b, 0xfe, 0x51, 0x76, 0x0a, 0xba, 0x0e, 0x15, 0xd3, 0xaa, 0x31, 0xec, 0xa9, 0x1e, - 0x3a, 0xc3, 0x56, 0x0f, 0xa2, 0xa7, 0xb6, 0x88, 0x08, 0x22, 0x92, 0xc5, 0x8b, 0x08, 0x61, 0x9a, - 0x8c, 0xb3, 0x43, 0xb3, 0x33, 0x21, 0x33, 0xcd, 0xda, 0x6f, 0xe1, 0xc1, 0x8f, 0xe2, 0x87, 0xd8, - 0xe3, 0xe2, 0xc9, 0x93, 0x48, 0xfb, 0x45, 0x24, 0x99, 0x69, 0x36, 0xd8, 0x16, 0xbc, 0x94, 0x19, - 0x9e, 0xe7, 0x79, 0xfb, 0x7b, 0xdf, 0x77, 0x02, 0xfc, 0x54, 0x2e, 0x74, 0x26, 0x93, 0x04, 0x93, - 0x34, 0x4d, 0x78, 0x44, 0x34, 0x97, 0x02, 0xeb, 0x55, 0x4a, 0x15, 0x4a, 0x33, 0xa9, 0x25, 0xec, - 0x6d, 0x1d, 0xa8, 0xe6, 0x18, 0xf4, 0x98, 0x64, 0xb2, 0x34, 0xe0, 0xe2, 0x64, 0xbc, 0x03, 0x2f, - 0x92, 0xea, 0x42, 0x2a, 0x3c, 0x27, 0x8a, 0xe2, 0xfc, 0x74, 0x4e, 0x35, 0x39, 0xc5, 0x91, 0xe4, - 0xc2, 0xea, 0x7d, 0xa3, 0x87, 0x26, 0x68, 0x2e, 0x56, 0x7a, 0x5c, 0x81, 0xa8, 0x73, 0x92, 0xd1, - 0x18, 0x2b, 0x9a, 0xe5, 0x3c, 0xa2, 0x46, 0x3e, 0xf9, 0xde, 0x06, 0xdd, 0xc9, 0xcd, 0xff, 0xc3, - 0x31, 0xb8, 0x4d, 0xe2, 0x38, 0xa3, 0x4a, 0xb9, 0x8e, 0xef, 0x0c, 0x8f, 0xa6, 0xee, 0xcf, 0x1f, - 0xa3, 0x9e, 0xad, 0x38, 0x31, 0xca, 0x99, 0xce, 0xb8, 0x60, 0xc1, 0xd6, 0x08, 0x31, 0xe8, 0x28, - 0x4d, 0x16, 0xd4, 0x6d, 0xfa, 0xce, 0xb0, 0x3b, 0xee, 0x23, 0x6b, 0x2f, 0x68, 0x91, 0xa5, 0x45, - 0x33, 0xc9, 0x45, 0x60, 0x7c, 0x30, 0x00, 0x77, 0x2d, 0x45, 0x18, 0x49, 0xf1, 0x85, 0x33, 0xe5, - 0xb6, 0xfc, 0xd6, 0xb0, 0x3b, 0x7e, 0x8a, 0xaa, 0xa1, 0x18, 0x5a, 0x54, 0x63, 0x3b, 0x33, 0x91, - 0x59, 0x99, 0x08, 0xee, 0xa8, 0xfa, 0x55, 0xc1, 0xcf, 0xe0, 0x61, 0x4c, 0x13, 0xca, 0x88, 0xa6, - 0x34, 0x2c, 0x7e, 0x2f, 0xc9, 0x2a, 0xb4, 0x84, 0x54, 0xb9, 0x6d, 0xbf, 0x35, 0x3c, 0x9a, 0x3e, - 0xba, 0xfa, 0xfd, 0xa4, 0x71, 0xb0, 0xa1, 0x7e, 0x55, 0xe0, 0x8d, 0xc9, 0x4f, 0xb6, 0x71, 0x98, - 0x83, 0xfb, 0x29, 0x15, 0x31, 0x17, 0x2c, 0x5c, 0x0a, 0x6b, 0xe3, 0x52, 0x28, 0xb7, 0x53, 0x72, - 0xbf, 0x42, 0xfb, 0x96, 0x59, 0x87, 0x47, 0x1f, 0x4c, 0xfc, 0x63, 0x3d, 0xfd, 0x5a, 0xe8, 0x6c, - 0x35, 0x6d, 0x17, 0x50, 0x41, 0x2f, 0xdd, 0x63, 0x18, 0xe4, 0xa0, 0x7f, 0x30, 0x08, 0x8f, 0x41, - 0x6b, 0x41, 0x57, 0xe5, 0x9e, 0xda, 0x41, 0x71, 0x84, 0x33, 0xd0, 0xc9, 0x49, 0xb2, 0xdc, 0x6e, - 0x62, 0xb4, 0x1f, 0xeb, 0xa6, 0x94, 0x60, 0xb6, 0xd3, 0x77, 0x5c, 0xe9, 0xc0, 0x64, 0x5f, 0x36, - 0x5f, 0x38, 0x27, 0x31, 0x78, 0x70, 0xc0, 0x05, 0xdf, 0x82, 0x7b, 0xbb, 0xe3, 0x6d, 0xfe, 0xc7, - 0x78, 0x8f, 0xd9, 0x3f, 0x53, 0x9d, 0xbe, 0xbf, 0x5a, 0x7b, 0xce, 0xf5, 0xda, 0x73, 0xfe, 0xac, - 0x3d, 0xe7, 0xdb, 0xc6, 0x6b, 0x5c, 0x6f, 0xbc, 0xc6, 0xaf, 0x8d, 0xd7, 0xf8, 0xf4, 0x9c, 0x71, - 0x7d, 0xbe, 0x9c, 0xa3, 0x48, 0x5e, 0xe0, 0xa2, 0x87, 0x91, 0xa0, 0xfa, 0x52, 0x66, 0x0b, 0x5c, - 0xbd, 0xe6, 0xaf, 0xbb, 0x1f, 0xd6, 0xfc, 0x56, 0xf9, 0xa6, 0x9f, 0xfd, 0x0d, 0x00, 0x00, 0xff, - 0xff, 0xac, 0x5c, 0x63, 0xa6, 0x7d, 0x03, 0x00, 0x00, + // 508 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x4d, 0x8b, 0x13, 0x31, + 0x1c, 0xc6, 0x3b, 0x7d, 0x59, 0xd9, 0x14, 0x74, 0x0d, 0x95, 0x9d, 0x56, 0x1d, 0x87, 0x3d, 0xd5, + 0x43, 0x13, 0xb6, 0x7a, 0x10, 0xf7, 0xd4, 0x96, 0x45, 0x05, 0x11, 0x99, 0xe2, 0x45, 0x84, 0x21, + 0x9d, 0x89, 0x69, 0x68, 0x37, 0x19, 0x26, 0xe9, 0xac, 0xfd, 0x16, 0x7e, 0x18, 0x3f, 0xc4, 0x1e, + 0x57, 0x4f, 0x9e, 0x44, 0xda, 0x2f, 0x22, 0x33, 0x49, 0xbb, 0x83, 0xdb, 0xc2, 0x5e, 0x86, 0x09, + 0xcf, 0xef, 0x49, 0x9e, 0xe4, 0xe1, 0x0f, 0xfc, 0x44, 0xce, 0x74, 0x2a, 0xe7, 0x73, 0x4c, 0x92, + 0x64, 0xce, 0x23, 0xa2, 0xb9, 0x14, 0x58, 0x2f, 0x13, 0xaa, 0x50, 0x92, 0x4a, 0x2d, 0x61, 0x6b, + 0x43, 0xa0, 0x12, 0xd1, 0x69, 0x31, 0xc9, 0x64, 0x01, 0xe0, 0xfc, 0xcf, 0xb0, 0x1d, 0x2f, 0x92, + 0xea, 0x42, 0x2a, 0x3c, 0x21, 0x8a, 0xe2, 0xec, 0x74, 0x42, 0x35, 0x39, 0xc5, 0x91, 0xe4, 0xc2, + 0xea, 0x6d, 0xa3, 0x87, 0xc6, 0x68, 0x16, 0x56, 0x7a, 0xba, 0x0d, 0xa2, 0xa6, 0x24, 0xa5, 0x31, + 0x56, 0x34, 0xcd, 0x78, 0x44, 0x8d, 0x7c, 0xf2, 0xb3, 0x0e, 0x9a, 0x83, 0x9b, 0xf3, 0x61, 0x1f, + 0xdc, 0x23, 0x71, 0x9c, 0x52, 0xa5, 0x5c, 0xc7, 0x77, 0xba, 0x87, 0x43, 0xf7, 0xd7, 0x8f, 0x5e, + 0xcb, 0xee, 0x38, 0x30, 0xca, 0x58, 0xa7, 0x5c, 0xb0, 0x60, 0x03, 0x42, 0x0c, 0x1a, 0x4a, 0x93, + 0x19, 0x75, 0xab, 0xbe, 0xd3, 0x6d, 0xf6, 0xdb, 0xc8, 0xe2, 0x79, 0x5a, 0x64, 0xd3, 0xa2, 0x91, + 0xe4, 0x22, 0x30, 0x1c, 0x0c, 0xc0, 0x03, 0x9b, 0x22, 0x8c, 0xa4, 0xf8, 0xca, 0x99, 0x72, 0x6b, + 0x7e, 0xad, 0xdb, 0xec, 0x3f, 0x47, 0xdb, 0x47, 0x31, 0x69, 0x51, 0x29, 0xdb, 0xd8, 0x58, 0x46, + 0x85, 0x23, 0xb8, 0xaf, 0xca, 0x4b, 0x05, 0xbf, 0x80, 0xc7, 0x31, 0x9d, 0x53, 0x46, 0x34, 0xa5, + 0x61, 0xfe, 0xbd, 0x24, 0xcb, 0xd0, 0x26, 0xa4, 0xca, 0xad, 0xfb, 0xb5, 0xee, 0xe1, 0xf0, 0xc9, + 0xd5, 0x9f, 0x67, 0x95, 0xbd, 0x17, 0x6a, 0x6f, 0x37, 0x78, 0x63, 0xfc, 0x83, 0x8d, 0x1d, 0x66, + 0xe0, 0x51, 0x42, 0x45, 0xcc, 0x05, 0x0b, 0x17, 0xc2, 0x62, 0x5c, 0x0a, 0xe5, 0x36, 0x8a, 0xdc, + 0x67, 0x68, 0x57, 0x99, 0xe5, 0xf0, 0xe8, 0xa3, 0xb1, 0x7f, 0x2a, 0xbb, 0xcf, 0x85, 0x4e, 0x97, + 0xc3, 0x7a, 0x1e, 0x2a, 0x68, 0x25, 0x3b, 0x00, 0x78, 0x06, 0x3a, 0x0b, 0x51, 0x3c, 0x5a, 0xa8, + 0xa8, 0x52, 0x5c, 0x8a, 0x90, 0x8a, 0x38, 0x9c, 0x52, 0xce, 0xa6, 0xda, 0x3d, 0xf0, 0x9d, 0x6e, + 0x3d, 0x38, 0xb6, 0xc4, 0xd8, 0x00, 0xe7, 0x22, 0x7e, 0x5b, 0xc8, 0x9d, 0x0c, 0xb4, 0xf7, 0x9e, + 0x0a, 0x8f, 0x40, 0x6d, 0x46, 0x97, 0x45, 0xc9, 0xf5, 0x20, 0xff, 0x85, 0x23, 0xd0, 0xc8, 0xc8, + 0x7c, 0xb1, 0xa9, 0xb1, 0xb7, 0xfb, 0x4e, 0x37, 0x5b, 0x09, 0x66, 0x9f, 0xe9, 0x3d, 0x57, 0x3a, + 0x30, 0xde, 0xd7, 0xd5, 0x57, 0xce, 0x49, 0x0c, 0x8e, 0xf7, 0x50, 0xf0, 0x1d, 0x78, 0x78, 0xbb, + 0x9b, 0xea, 0x1d, 0xba, 0x39, 0x62, 0xff, 0x55, 0x32, 0xfc, 0x70, 0xb5, 0xf2, 0x9c, 0xeb, 0x95, + 0xe7, 0xfc, 0x5d, 0x79, 0xce, 0xf7, 0xb5, 0x57, 0xb9, 0x5e, 0x7b, 0x95, 0xdf, 0x6b, 0xaf, 0xf2, + 0xf9, 0x25, 0xe3, 0x7a, 0xba, 0x98, 0xa0, 0x48, 0x5e, 0xe0, 0xfc, 0x0e, 0x3d, 0x41, 0xf5, 0xa5, + 0x4c, 0x67, 0x78, 0x3b, 0x0a, 0xdf, 0x6e, 0x4f, 0xe5, 0xe4, 0xa0, 0x18, 0x88, 0x17, 0xff, 0x02, + 0x00, 0x00, 0xff, 0xff, 0x6b, 0x46, 0x81, 0x7e, 0xba, 0x03, 0x00, 0x00, } func (m *Application) Marshal() (dAtA []byte, err error) { @@ -219,6 +231,11 @@ func (m *Application) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.UnstakeSessionEndHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.UnstakeSessionEndHeight)) + i-- + dAtA[i] = 0x30 + } if len(m.PendingUndelegations) > 0 { for k := range m.PendingUndelegations { v := m.PendingUndelegations[k] @@ -364,6 +381,9 @@ func (m *Application) Size() (n int) { n += mapEntrySize + 1 + sovTypes(uint64(mapEntrySize)) } } + if m.UnstakeSessionEndHeight != 0 { + n += 1 + sovTypes(uint64(m.UnstakeSessionEndHeight)) + } return n } @@ -666,6 +686,25 @@ func (m *Application) Unmarshal(dAtA []byte) error { } m.PendingUndelegations[mapkey] = *mapvalue iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnstakeSessionEndHeight", wireType) + } + m.UnstakeSessionEndHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnstakeSessionEndHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index e0711dd3a..52f377cc3 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -144,6 +144,16 @@ func (k Keeper) hydrateSessionApplication(ctx context.Context, sh *sessionHydrat ) } + // Do not provide sessions for applications that initiated the unstaking process + // and that are no longer active. + if !foundApp.IsActive(sh.sessionHeader.SessionEndBlockHeight) { + return types.ErrSessionAppNotActive.Wrapf( + "application %q is not active for session %s", + sh.sessionHeader.ApplicationAddress, + sh.sessionHeader.SessionId, + ) + } + for _, appServiceConfig := range foundApp.ServiceConfigs { if appServiceConfig.Service.Id == sh.sessionHeader.Service.Id { sh.session.Application = &foundApp diff --git a/x/session/types/errors.go b/x/session/types/errors.go index 6ffff939c..82b720b40 100644 --- a/x/session/types/errors.go +++ b/x/session/types/errors.go @@ -15,4 +15,5 @@ var ( ErrSessionInvalidService = sdkerrors.Register(ModuleName, 1106, "invalid service in session") ErrSessionInvalidBlockHeight = sdkerrors.Register(ModuleName, 1107, "invalid block height for session") ErrSessionInvalidSessionId = sdkerrors.Register(ModuleName, 1108, "invalid sessionId") + ErrSessionAppNotActive = sdkerrors.Register(ModuleName, 1109, "application is not active") ) diff --git a/x/shared/keeper/msg_server_update_param.go b/x/shared/keeper/msg_server_update_param.go index fd74c05b4..d83e2fc74 100644 --- a/x/shared/keeper/msg_server_update_param.go +++ b/x/shared/keeper/msg_server_update_param.go @@ -67,6 +67,13 @@ func (k msgServer) UpdateParam(ctx context.Context, msg *types.MsgUpdateParam) ( } params.SupplierUnbondingPeriodSessions = uint64(value.AsInt64) + case types.ParamApplicationUnbondingPeriodSessions: + value, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64) + if !ok { + return nil, types.ErrSharedParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) + } + + params.ApplicationUnbondingPeriodSessions = uint64(value.AsInt64) default: return nil, types.ErrSharedParamInvalid.Wrapf("unsupported param %q", msg.Name) } diff --git a/x/shared/keeper/msg_server_update_param_test.go b/x/shared/keeper/msg_server_update_param_test.go index d77ba87cd..fe93eb97c 100644 --- a/x/shared/keeper/msg_server_update_param_test.go +++ b/x/shared/keeper/msg_server_update_param_test.go @@ -50,14 +50,22 @@ func TestMsgUpdateParam_UpdateClaimWindowOpenOffsetBlocks(t *testing.T) { defaultParams := sharedtypes.DefaultParams() - // Update the SupplierUnbondingPeriodSessions such that it is greater than the - // cumulative proof window close blocks to pass UpdateParam validation. - defaultParams.SupplierUnbondingPeriodSessions = getMinSupplierUnbondingPeriodSessions( + // Calculate the minimum unbonding period sessions required by the staking actors + // to pass UpdateParam validation. + minUnbodningPeriodSessions := getMinActorUnbondingPeriodSessions( &defaultParams, defaultParams.ClaimWindowOpenOffsetBlocks, uint64(expectedClaimWindowOpenOffestBlocks), ) + // Update the SupplierUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.SupplierUnbondingPeriodSessions = minUnbodningPeriodSessions + + // Update the ApplicationUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.ApplicationUnbondingPeriodSessions = minUnbodningPeriodSessions + // Set the parameters to their default values require.NoError(t, k.SetParams(ctx, defaultParams)) @@ -87,14 +95,22 @@ func TestMsgUpdateParam_UpdateClaimWindowCloseOffsetBlocks(t *testing.T) { defaultParams := sharedtypes.DefaultParams() - // Update the SupplierUnbondingPeriodSessions such that it is greater than the - // cumulative proof window close blocks to pass UpdateParam validation. - defaultParams.SupplierUnbondingPeriodSessions = getMinSupplierUnbondingPeriodSessions( + // Calculate the minimum unbonding period sessions required by the staking actors + // to pass UpdateParam validation. + minUnbodningPeriodSessions := getMinActorUnbondingPeriodSessions( &defaultParams, - defaultParams.ClaimWindowCloseOffsetBlocks, + defaultParams.ClaimWindowOpenOffsetBlocks, uint64(expectedClaimWindowCloseOffestBlocks), ) + // Update the SupplierUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.SupplierUnbondingPeriodSessions = minUnbodningPeriodSessions + + // Update the ApplicationUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.ApplicationUnbondingPeriodSessions = minUnbodningPeriodSessions + // Set the parameters to their default values require.NoError(t, k.SetParams(ctx, defaultParams)) @@ -124,14 +140,22 @@ func TestMsgUpdateParam_UpdateProofWindowOpenOffsetBlocks(t *testing.T) { defaultParams := sharedtypes.DefaultParams() - // Update the SupplierUnbondingPeriodSessions such that it is greater than the - // cumulative proof window close blocks to pass UpdateParam validation. - defaultParams.SupplierUnbondingPeriodSessions = getMinSupplierUnbondingPeriodSessions( + // Calculate the minimum unbonding period sessions required by the staking actors + // to pass UpdateParam validation. + minUnbodningPeriodSessions := getMinActorUnbondingPeriodSessions( &defaultParams, - defaultParams.ProofWindowOpenOffsetBlocks, + defaultParams.ClaimWindowOpenOffsetBlocks, uint64(expectedProofWindowOpenOffestBlocks), ) + // Update the SupplierUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.SupplierUnbondingPeriodSessions = minUnbodningPeriodSessions + + // Update the ApplicationUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.ApplicationUnbondingPeriodSessions = minUnbodningPeriodSessions + // Set the parameters to their default values require.NoError(t, k.SetParams(ctx, defaultParams)) @@ -161,14 +185,22 @@ func TestMsgUpdateParam_UpdateProofWindowCloseOffsetBlocks(t *testing.T) { defaultParams := sharedtypes.DefaultParams() - // Update the SupplierUnbondingPeriodSessions such that it is greater than the - // cumulative proof window close blocks to pass UpdateParam validation. - defaultParams.SupplierUnbondingPeriodSessions = getMinSupplierUnbondingPeriodSessions( + // Calculate the minimum unbonding period sessions required by the staking actors + // to pass UpdateParam validation. + minUnbodningPeriodSessions := getMinActorUnbondingPeriodSessions( &defaultParams, - defaultParams.ProofWindowCloseOffsetBlocks, + defaultParams.ClaimWindowOpenOffsetBlocks, uint64(expectedProofWindowCloseOffestBlocks), ) + // Update the SupplierUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.SupplierUnbondingPeriodSessions = minUnbodningPeriodSessions + + // Update the ApplicationUnbondingPeriodSessions such that it is greater than the + // cumulative proof window close blocks to pass UpdateParam validation. + defaultParams.ApplicationUnbondingPeriodSessions = minUnbodningPeriodSessions + // Set the parameters to their default values require.NoError(t, k.SetParams(ctx, defaultParams)) @@ -261,10 +293,48 @@ func TestMsgUpdateParam_UpdateSupplierUnbondingPeriodSessions(t *testing.T) { require.ErrorIs(t, err, sharedtypes.ErrSharedParamInvalid) } -// getMinSupplierUnbondingPeriodSessions returns the supplier unbonding period +func TestMsgUpdateParam_UpdateApplicationUnbondingPeriodSessions(t *testing.T) { + var expectedApplicationUnbondingPerid int64 = 5 + + k, ctx := testkeeper.SharedKeeper(t) + msgSrv := keeper.NewMsgServerImpl(k) + + defaultParams := sharedtypes.DefaultParams() + // Set the parameters to their default values + require.NoError(t, k.SetParams(ctx, defaultParams)) + + // Ensure the default values are different from the new values we want to set + require.NotEqual(t, uint64(expectedApplicationUnbondingPerid), defaultParams.GetApplicationUnbondingPeriodSessions()) + + // Update the application unbonding period param + updateParamMsg := &sharedtypes.MsgUpdateParam{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Name: sharedtypes.ParamApplicationUnbondingPeriodSessions, + AsType: &sharedtypes.MsgUpdateParam_AsInt64{AsInt64: expectedApplicationUnbondingPerid}, + } + res, err := msgSrv.UpdateParam(ctx, updateParamMsg) + require.NoError(t, err) + + require.Equal(t, uint64(expectedApplicationUnbondingPerid), res.Params.GetApplicationUnbondingPeriodSessions()) + + // Ensure the other parameters are unchanged + testkeeper.AssertDefaultParamsEqualExceptFields(t, &defaultParams, res.Params, "ApplicationUnbondingPeriodSessions") + + // Ensure that a application unbonding period that is less than the cumulative + // proof window close blocks is not allowed. + updateParamMsg = &sharedtypes.MsgUpdateParam{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Name: sharedtypes.ParamApplicationUnbondingPeriodSessions, + AsType: &sharedtypes.MsgUpdateParam_AsInt64{AsInt64: 1}, + } + _, err = msgSrv.UpdateParam(ctx, updateParamMsg) + require.ErrorIs(t, err, sharedtypes.ErrSharedParamInvalid) +} + +// getMinActorUnbondingPeriodSessions returns the actors unbonding period // sessions such that it is greater than the cumulative proof window close blocks // to pass UpdateParam validation. -func getMinSupplierUnbondingPeriodSessions( +func getMinActorUnbondingPeriodSessions( params *sharedtypes.Params, oldParamBlocksValue uint64, newParamBlocksValue uint64, diff --git a/x/shared/types/genesis_test.go b/x/shared/types/genesis_test.go index c9988e146..fa07c23c5 100644 --- a/x/shared/types/genesis_test.go +++ b/x/shared/types/genesis_test.go @@ -24,8 +24,9 @@ func TestGenesisState_Validate(t *testing.T) { desc: "valid genesis state", genState: &types.GenesisState{ Params: types.Params{ - NumBlocksPerSession: defaultParams.NumBlocksPerSession, - SupplierUnbondingPeriodSessions: defaultParams.SupplierUnbondingPeriodSessions, + NumBlocksPerSession: defaultParams.NumBlocksPerSession, + SupplierUnbondingPeriodSessions: defaultParams.SupplierUnbondingPeriodSessions, + ApplicationUnbondingPeriodSessions: defaultParams.ApplicationUnbondingPeriodSessions, }, // this line is used by starport scaffolding # types/genesis/validField diff --git a/x/shared/types/message_update_param.go b/x/shared/types/message_update_param.go index 3a103fcf2..39334b5a8 100644 --- a/x/shared/types/message_update_param.go +++ b/x/shared/types/message_update_param.go @@ -53,7 +53,8 @@ func (msg *MsgUpdateParam) ValidateBasic() error { ParamClaimWindowCloseOffsetBlocks, ParamProofWindowOpenOffsetBlocks, ParamProofWindowCloseOffsetBlocks, - ParamSupplierUnbondingPeriodSessions: + ParamSupplierUnbondingPeriodSessions, + ParamApplicationUnbondingPeriodSessions: return msg.paramTypeIsInt64() default: return ErrSharedParamNameInvalid.Wrapf("unsupported param %q", msg.Name) diff --git a/x/shared/types/params.go b/x/shared/types/params.go index 2d359e22a..59f179763 100644 --- a/x/shared/types/params.go +++ b/x/shared/types/params.go @@ -5,31 +5,34 @@ import ( ) const ( - DefaultNumBlocksPerSession = 4 - ParamNumBlocksPerSession = "num_blocks_per_session" - DefaultGracePeriodEndOffsetBlocks = 1 - ParamGracePeriodEndOffsetBlocks = "grace_period_end_offset_blocks" - DefaultClaimWindowOpenOffsetBlocks = 2 - ParamClaimWindowOpenOffsetBlocks = "claim_window_open_offset_blocks" - DefaultClaimWindowCloseOffsetBlocks = 4 - ParamClaimWindowCloseOffsetBlocks = "claim_window_close_offset_blocks" - DefaultProofWindowOpenOffsetBlocks = 0 - ParamProofWindowOpenOffsetBlocks = "proof_window_open_offset_blocks" - DefaultProofWindowCloseOffsetBlocks = 4 - ParamProofWindowCloseOffsetBlocks = "proof_window_close_offset_blocks" - DefaultSupplierUnbondingPeriodSessions = 4 // 4 sessions - ParamSupplierUnbondingPeriodSessions = "supplier_unbonding_period_sessions" + DefaultNumBlocksPerSession = 4 + ParamNumBlocksPerSession = "num_blocks_per_session" + DefaultGracePeriodEndOffsetBlocks = 1 + ParamGracePeriodEndOffsetBlocks = "grace_period_end_offset_blocks" + DefaultClaimWindowOpenOffsetBlocks = 2 + ParamClaimWindowOpenOffsetBlocks = "claim_window_open_offset_blocks" + DefaultClaimWindowCloseOffsetBlocks = 4 + ParamClaimWindowCloseOffsetBlocks = "claim_window_close_offset_blocks" + DefaultProofWindowOpenOffsetBlocks = 0 + ParamProofWindowOpenOffsetBlocks = "proof_window_open_offset_blocks" + DefaultProofWindowCloseOffsetBlocks = 4 + ParamProofWindowCloseOffsetBlocks = "proof_window_close_offset_blocks" + DefaultSupplierUnbondingPeriodSessions = 4 // 4 sessions + ParamSupplierUnbondingPeriodSessions = "supplier_unbonding_period_sessions" + DefaultApplicationUnbondingPeriodSessions = 4 // 4 sessions + ParamApplicationUnbondingPeriodSessions = "application_unbonding_period_sessions" ) var ( - _ paramtypes.ParamSet = (*Params)(nil) - KeyNumBlocksPerSession = []byte("NumBlocksPerSession") - KeyGracePeriodEndOffsetBlocks = []byte("GracePeriodEndOffsetBlocks") - KeyClaimWindowOpenOffsetBlocks = []byte("ClaimWindowOpenOffsetBlocks") - KeyClaimWindowCloseOffsetBlocks = []byte("ClaimWindowCloseOffsetBlocks") - KeyProofWindowOpenOffsetBlocks = []byte("ProofWindowOpenOffsetBlocks") - KeyProofWindowCloseOffsetBlocks = []byte("ProofWindowCloseOffsetBlocks") - KeySupplierUnbondingPeriodSessions = []byte("SupplierUnbondingPeriodSessions") + _ paramtypes.ParamSet = (*Params)(nil) + KeyNumBlocksPerSession = []byte("NumBlocksPerSession") + KeyGracePeriodEndOffsetBlocks = []byte("GracePeriodEndOffsetBlocks") + KeyClaimWindowOpenOffsetBlocks = []byte("ClaimWindowOpenOffsetBlocks") + KeyClaimWindowCloseOffsetBlocks = []byte("ClaimWindowCloseOffsetBlocks") + KeyProofWindowOpenOffsetBlocks = []byte("ProofWindowOpenOffsetBlocks") + KeyProofWindowCloseOffsetBlocks = []byte("ProofWindowCloseOffsetBlocks") + KeySupplierUnbondingPeriodSessions = []byte("SupplierUnbondingPeriodSessions") + KeyApplicationUnbondingPeriodSessions = []byte("ApplicationUnbondingPeriodSessions") ) // ParamKeyTable the param key table for launch module @@ -40,13 +43,14 @@ func ParamKeyTable() paramtypes.KeyTable { // NewParams creates a new Params instance func NewParams() Params { return Params{ - NumBlocksPerSession: DefaultNumBlocksPerSession, - ClaimWindowOpenOffsetBlocks: DefaultClaimWindowOpenOffsetBlocks, - ClaimWindowCloseOffsetBlocks: DefaultClaimWindowCloseOffsetBlocks, - ProofWindowOpenOffsetBlocks: DefaultProofWindowOpenOffsetBlocks, - ProofWindowCloseOffsetBlocks: DefaultProofWindowCloseOffsetBlocks, - GracePeriodEndOffsetBlocks: DefaultGracePeriodEndOffsetBlocks, - SupplierUnbondingPeriodSessions: DefaultSupplierUnbondingPeriodSessions, + NumBlocksPerSession: DefaultNumBlocksPerSession, + ClaimWindowOpenOffsetBlocks: DefaultClaimWindowOpenOffsetBlocks, + ClaimWindowCloseOffsetBlocks: DefaultClaimWindowCloseOffsetBlocks, + ProofWindowOpenOffsetBlocks: DefaultProofWindowOpenOffsetBlocks, + ProofWindowCloseOffsetBlocks: DefaultProofWindowCloseOffsetBlocks, + GracePeriodEndOffsetBlocks: DefaultGracePeriodEndOffsetBlocks, + SupplierUnbondingPeriodSessions: DefaultSupplierUnbondingPeriodSessions, + ApplicationUnbondingPeriodSessions: DefaultApplicationUnbondingPeriodSessions, } } @@ -93,6 +97,11 @@ func (params *Params) ParamSetPairs() paramtypes.ParamSetPairs { ¶ms.SupplierUnbondingPeriodSessions, ValidateSupplierUnbondingPeriodSessions, ), + paramtypes.NewParamSetPair( + KeyApplicationUnbondingPeriodSessions, + ¶ms.ApplicationUnbondingPeriodSessions, + ValidateApplicationUnbondingPeriodSessions, + ), } } @@ -126,6 +135,10 @@ func (params *Params) ValidateBasic() error { return err } + if err := ValidateApplicationUnbondingPeriodSessions(params.ApplicationUnbondingPeriodSessions); err != nil { + return err + } + if err := validateGracePeriodOffsetBlocksIsLessThanNumBlocksPerSession(params); err != nil { return err } @@ -138,6 +151,10 @@ func (params *Params) ValidateBasic() error { return err } + if err := validateApplicationUnbondingPeriodIsGreaterThanCumulativeProofWindowCloseBlocks(params); err != nil { + return err + } + return nil } @@ -207,6 +224,22 @@ func ValidateSupplierUnbondingPeriodSessions(v interface{}) error { return nil } +// ValidateApplicationUnbondingPeriodSession validates the ApplicationUnbondingPeriodSessions +// governance parameter. +// NB: The argument is an interface type to satisfy the ParamSetPair function signature. +func ValidateApplicationUnbondingPeriodSessions(v interface{}) error { + applicationUnbondingPeriodSessions, err := validateIsUint64(v) + if err != nil { + return err + } + + if applicationUnbondingPeriodSessions < 1 { + return ErrSharedParamInvalid.Wrapf("invalid ApplicationUnbondingPeriodSessions: (%v)", applicationUnbondingPeriodSessions) + } + + return nil +} + // validateIsUint64 returns the casted uin64 value or an error if value is not // type assertable to uint64. func validateIsUint64(value any) (uint64, error) { @@ -266,6 +299,24 @@ func validateSupplierUnbondingPeriodIsGreaterThanCumulativeProofWindowCloseBlock return nil } +// validateApplicationUnbondingPeriodIsGreaterThanCumulativeProofWindowCloseBlocks +// ensures that a supplier cannot unbond before the pending claims are settled. +func validateApplicationUnbondingPeriodIsGreaterThanCumulativeProofWindowCloseBlocks(params *Params) error { + cumulativeProofWindowCloseBlocks := GetSessionEndToProofWindowCloseBlocks(params) + applicationUnbondingPeriodSessions := params.ApplicationUnbondingPeriodSessions * params.NumBlocksPerSession + + if applicationUnbondingPeriodSessions < cumulativeProofWindowCloseBlocks { + return ErrSharedParamInvalid.Wrapf( + "ApplicationUnbondingPeriodSessions (%v session) (%v blocks) must be greater than the cumulative ProofWindowCloseOffsetBlocks (%v)", + params.ApplicationUnbondingPeriodSessions, + applicationUnbondingPeriodSessions, + cumulativeProofWindowCloseBlocks, + ) + } + + return nil +} + // GetSessionEndToProofWindowCloseBlocks returns the total number of blocks // from the moment a session ends until the proof window closes. // NB: Using shared.GetProofWindowCloseOffsetHeight is not possible because of the diff --git a/x/shared/types/params.pb.go b/x/shared/types/params.pb.go index feac98afd..9dc1ba447 100644 --- a/x/shared/types/params.pb.go +++ b/x/shared/types/params.pb.go @@ -50,6 +50,11 @@ type Params struct { // On-chain business logic requires, and ensures, that the corresponding block count of the unbonding // period will exceed the end of any active claim & proof lifecycles. SupplierUnbondingPeriodSessions uint64 `protobuf:"varint,7,opt,name=supplier_unbonding_period_sessions,json=supplierUnbondingPeriodSessions,proto3" json:"supplier_unbonding_period_sessions"` + // application_unbonding_period_sessions is the number of sessions that an application must wait after + // unstaking before their staked assets are moved to their account balance. + // On-chain business logic requires, and ensures, that the corresponding block count of the + // application unbonding period will exceed the end of its corresponding proof window close height. + ApplicationUnbondingPeriodSessions uint64 `protobuf:"varint,8,opt,name=application_unbonding_period_sessions,json=applicationUnbondingPeriodSessions,proto3" json:"application_unbonding_period_sessions"` } func (m *Params) Reset() { *m = Params{} } @@ -134,6 +139,13 @@ func (m *Params) GetSupplierUnbondingPeriodSessions() uint64 { return 0 } +func (m *Params) GetApplicationUnbondingPeriodSessions() uint64 { + if m != nil { + return m.ApplicationUnbondingPeriodSessions + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "poktroll.shared.Params") } @@ -141,34 +153,36 @@ func init() { func init() { proto.RegisterFile("poktroll/shared/params.proto", fileDescriptor_ee6189c7aa51bbf5) } var fileDescriptor_ee6189c7aa51bbf5 = []byte{ - // 431 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcd, 0xea, 0xd3, 0x40, - 0x14, 0xc5, 0x1b, 0xad, 0x11, 0xb2, 0x11, 0xa3, 0x48, 0x48, 0x4b, 0xa6, 0x56, 0x11, 0x11, 0x6c, - 0x16, 0xee, 0x5c, 0x56, 0x5c, 0xb8, 0x6a, 0x89, 0x88, 0xe0, 0x66, 0xc8, 0xc7, 0x24, 0x1d, 0x9a, - 0xcc, 0x1d, 0x66, 0x12, 0xaa, 0xaf, 0xa0, 0x1b, 0x1f, 0xc1, 0x47, 0xf0, 0x31, 0x5c, 0x76, 0xe9, - 0x2a, 0x48, 0xbb, 0x50, 0xf2, 0x14, 0x92, 0x49, 0x63, 0xbf, 0xec, 0x3f, 0xff, 0x4d, 0x18, 0xee, - 0xf9, 0xdd, 0x7b, 0x38, 0xe4, 0x5e, 0x63, 0xc8, 0x61, 0x99, 0x0b, 0x48, 0x53, 0x57, 0x2e, 0x7c, - 0x41, 0x22, 0x97, 0xfb, 0xc2, 0xcf, 0xe4, 0x84, 0x0b, 0xc8, 0xc1, 0xbc, 0xd3, 0xaa, 0x93, 0x46, - 0xb5, 0xef, 0xfa, 0x19, 0x65, 0xe0, 0xaa, 0x6f, 0xc3, 0xd8, 0xf7, 0x13, 0x48, 0x40, 0x3d, 0xdd, - 0xfa, 0xd5, 0x54, 0xc7, 0x5f, 0x74, 0x43, 0x9f, 0xab, 0x51, 0xe6, 0xcc, 0x78, 0xc0, 0x8a, 0x0c, - 0x07, 0x29, 0x84, 0x4b, 0x89, 0x39, 0x11, 0x58, 0x12, 0x29, 0x29, 0x30, 0x4b, 0x1b, 0x69, 0x4f, - 0xfb, 0x53, 0xbb, 0x2a, 0xd1, 0x05, 0xc2, 0xbb, 0xc7, 0x8a, 0x6c, 0xaa, 0xca, 0x73, 0x22, 0xde, - 0x36, 0x45, 0x33, 0x36, 0x9c, 0x44, 0xf8, 0x21, 0xa9, 0x49, 0x0a, 0x11, 0x26, 0x2c, 0xc2, 0x10, - 0xc7, 0x92, 0xe4, 0xbb, 0x11, 0xd6, 0x0d, 0x35, 0x78, 0x5c, 0x95, 0xa8, 0x83, 0xf4, 0x6c, 0xa5, - 0xcf, 0x95, 0xfc, 0x9a, 0x45, 0x33, 0x25, 0x36, 0x8e, 0x26, 0x35, 0x50, 0x98, 0xfa, 0x34, 0xc3, - 0x2b, 0xca, 0x22, 0x58, 0x61, 0xe0, 0x84, 0x9d, 0x18, 0xdd, 0x54, 0x46, 0x8f, 0xaa, 0x12, 0x75, - 0xa1, 0xde, 0x40, 0x01, 0xef, 0x95, 0x3e, 0xe3, 0x84, 0x1d, 0x59, 0xa5, 0xc6, 0xe8, 0xa8, 0x3f, - 0x4c, 0x41, 0x92, 0x13, 0xaf, 0xbe, 0xf2, 0x7a, 0x5c, 0x95, 0xa8, 0x93, 0xf5, 0x86, 0x07, 0x66, - 0xaf, 0x6a, 0xfd, 0x34, 0x18, 0x17, 0x00, 0xf1, 0x15, 0xc1, 0x6e, 0xed, 0x83, 0x75, 0xa0, 0xde, - 0x40, 0x01, 0x97, 0x83, 0x1d, 0xf5, 0xff, 0x2f, 0x98, 0xbe, 0x0f, 0xd6, 0xc5, 0x7a, 0xc3, 0x03, - 0xb3, 0xf3, 0x60, 0xd2, 0x18, 0xcb, 0x82, 0xf3, 0x94, 0x12, 0x81, 0x0b, 0x16, 0x00, 0x8b, 0x28, - 0x4b, 0xda, 0x9f, 0xbf, 0xdb, 0x29, 0x69, 0xdd, 0x56, 0x7e, 0x4f, 0xaa, 0x12, 0x5d, 0x83, 0xf6, - 0x50, 0xcb, 0xbc, 0x6b, 0x91, 0x66, 0x5b, 0x76, 0xdb, 0x28, 0x5f, 0x3e, 0xfc, 0xf3, 0x0d, 0x69, - 0x9f, 0x7f, 0x7f, 0x7f, 0x66, 0xfd, 0xbb, 0xa5, 0x8f, 0xed, 0x35, 0x35, 0x27, 0x30, 0x7d, 0xf3, - 0x63, 0xe3, 0x68, 0xeb, 0x8d, 0xa3, 0xfd, 0xda, 0x38, 0xda, 0xd7, 0xad, 0xd3, 0x5b, 0x6f, 0x9d, - 0xde, 0xcf, 0xad, 0xd3, 0xfb, 0xe0, 0x26, 0x34, 0x5f, 0x14, 0xc1, 0x24, 0x84, 0xcc, 0xad, 0xdb, - 0x9f, 0x33, 0x92, 0xaf, 0x40, 0x2c, 0xdd, 0xf3, 0x59, 0xf9, 0x27, 0x4e, 0x64, 0xa0, 0xab, 0xfb, - 0x7a, 0xf1, 0x37, 0x00, 0x00, 0xff, 0xff, 0x24, 0xa2, 0x48, 0x2e, 0xb9, 0x03, 0x00, 0x00, + // 462 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xbf, 0x8e, 0xd3, 0x40, + 0x10, 0xc6, 0x63, 0x38, 0x72, 0xc8, 0x0d, 0xc2, 0x20, 0x14, 0xe5, 0x22, 0xef, 0x11, 0xfe, 0x08, + 0x90, 0x88, 0x0b, 0x3a, 0xca, 0x20, 0x0a, 0xaa, 0x44, 0x46, 0x08, 0x89, 0x66, 0xb5, 0xb1, 0xd7, + 0xbe, 0x55, 0xec, 0x9d, 0xd5, 0xae, 0xad, 0x80, 0xc4, 0x0b, 0x40, 0xc5, 0x23, 0xf0, 0x08, 0x3c, + 0x06, 0xe5, 0x95, 0x54, 0x16, 0x4a, 0x0a, 0x90, 0x9f, 0x02, 0x79, 0x1c, 0x73, 0x49, 0xee, 0x72, + 0xbe, 0xc6, 0x5a, 0xcd, 0xf7, 0x9b, 0xf9, 0xf4, 0xc9, 0x33, 0xf6, 0x40, 0xc1, 0x3c, 0xd3, 0x90, + 0x24, 0x9e, 0x39, 0x61, 0x9a, 0x87, 0x9e, 0x62, 0x9a, 0xa5, 0x66, 0xa4, 0x34, 0x64, 0xe0, 0xdc, + 0x6a, 0xd4, 0x51, 0xad, 0xf6, 0x6f, 0xb3, 0x54, 0x48, 0xf0, 0xf0, 0x5b, 0x33, 0xfd, 0xbb, 0x31, + 0xc4, 0x80, 0x4f, 0xaf, 0x7a, 0xd5, 0xd5, 0xe1, 0x97, 0x43, 0xbb, 0x3b, 0xc5, 0x51, 0xce, 0xc4, + 0xbe, 0x27, 0xf3, 0x94, 0xce, 0x12, 0x08, 0xe6, 0x86, 0x2a, 0xae, 0xa9, 0xe1, 0xc6, 0x08, 0x90, + 0x3d, 0xeb, 0xd8, 0x7a, 0x72, 0x30, 0xee, 0x97, 0x05, 0xd9, 0x43, 0xf8, 0x77, 0x64, 0x9e, 0x8e, + 0xb1, 0x3c, 0xe5, 0xfa, 0x6d, 0x5d, 0x74, 0x22, 0xdb, 0x8d, 0x35, 0x0b, 0x78, 0x45, 0x0a, 0x08, + 0x29, 0x97, 0x21, 0x85, 0x28, 0x32, 0x3c, 0x5b, 0x8f, 0xe8, 0x5d, 0xc3, 0xc1, 0xc3, 0xb2, 0x20, + 0x2d, 0xa4, 0xdf, 0x47, 0x7d, 0x8a, 0xf2, 0x6b, 0x19, 0x4e, 0x50, 0xac, 0x1d, 0x1d, 0x61, 0x93, + 0x20, 0x61, 0x22, 0xa5, 0x0b, 0x21, 0x43, 0x58, 0x50, 0x50, 0x5c, 0xee, 0x18, 0x5d, 0x47, 0xa3, + 0x07, 0x65, 0x41, 0xda, 0x50, 0xff, 0x08, 0x81, 0xf7, 0xa8, 0x4f, 0x14, 0x97, 0x5b, 0x56, 0x89, + 0x7d, 0xbc, 0xd5, 0x1f, 0x24, 0x60, 0xf8, 0x8e, 0xd7, 0x01, 0x7a, 0x3d, 0x2c, 0x0b, 0xd2, 0xca, + 0xfa, 0x83, 0x0d, 0xb3, 0x57, 0x95, 0xbe, 0x1b, 0x4c, 0x69, 0x80, 0xe8, 0x92, 0x60, 0x37, 0xce, + 0x82, 0xb5, 0xa0, 0xfe, 0x11, 0x02, 0xfb, 0x83, 0x6d, 0xf5, 0x5f, 0x14, 0xac, 0x7b, 0x16, 0xac, + 0x8d, 0xf5, 0x07, 0x1b, 0x66, 0xe7, 0x83, 0x19, 0x7b, 0x68, 0x72, 0xa5, 0x12, 0xc1, 0x35, 0xcd, + 0xe5, 0x0c, 0x64, 0x28, 0x64, 0xdc, 0xfc, 0xfc, 0xf5, 0x4e, 0x99, 0xde, 0x21, 0xfa, 0x3d, 0x2e, + 0x0b, 0x72, 0x05, 0xda, 0x27, 0x0d, 0xf3, 0xae, 0x41, 0xea, 0x6d, 0x59, 0x6f, 0xa3, 0x71, 0x3e, + 0xdb, 0x8f, 0x58, 0x45, 0x04, 0x2c, 0x13, 0x20, 0x2f, 0xf1, 0xbd, 0x89, 0xbe, 0x4f, 0xcb, 0x82, + 0x5c, 0xad, 0xc1, 0x1f, 0x6e, 0x60, 0x7b, 0xdc, 0x5f, 0xde, 0xff, 0xfb, 0x9d, 0x58, 0x5f, 0xff, + 0xfc, 0x78, 0xd6, 0xfb, 0x7f, 0xc9, 0x1f, 0x9b, 0x5b, 0xae, 0x0f, 0x70, 0xfc, 0xe6, 0xe7, 0xd2, + 0xb5, 0x4e, 0x97, 0xae, 0xf5, 0x7b, 0xe9, 0x5a, 0xdf, 0x56, 0x6e, 0xe7, 0x74, 0xe5, 0x76, 0x7e, + 0xad, 0xdc, 0xce, 0x07, 0x2f, 0x16, 0xd9, 0x49, 0x3e, 0x1b, 0x05, 0x90, 0x7a, 0x55, 0xfb, 0x73, + 0xc9, 0xb3, 0x05, 0xe8, 0xb9, 0x77, 0x7e, 0x56, 0xf6, 0x49, 0x71, 0x33, 0xeb, 0xe2, 0x75, 0xbf, + 0xf8, 0x17, 0x00, 0x00, 0xff, 0xff, 0x56, 0x60, 0x1b, 0xe5, 0x37, 0x04, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -211,6 +225,9 @@ func (this *Params) Equal(that interface{}) bool { if this.SupplierUnbondingPeriodSessions != that1.SupplierUnbondingPeriodSessions { return false } + if this.ApplicationUnbondingPeriodSessions != that1.ApplicationUnbondingPeriodSessions { + return false + } return true } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -233,6 +250,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ApplicationUnbondingPeriodSessions != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.ApplicationUnbondingPeriodSessions)) + i-- + dAtA[i] = 0x40 + } if m.SupplierUnbondingPeriodSessions != 0 { i = encodeVarintParams(dAtA, i, uint64(m.SupplierUnbondingPeriodSessions)) i-- @@ -309,6 +331,9 @@ func (m *Params) Size() (n int) { if m.SupplierUnbondingPeriodSessions != 0 { n += 1 + sovParams(uint64(m.SupplierUnbondingPeriodSessions)) } + if m.ApplicationUnbondingPeriodSessions != 0 { + n += 1 + sovParams(uint64(m.ApplicationUnbondingPeriodSessions)) + } return n } @@ -480,6 +505,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ApplicationUnbondingPeriodSessions", wireType) + } + m.ApplicationUnbondingPeriodSessions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ApplicationUnbondingPeriodSessions |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) diff --git a/x/shared/types/params_test.go b/x/shared/types/params_test.go index 89d0aee22..c9c47dc94 100644 --- a/x/shared/types/params_test.go +++ b/x/shared/types/params_test.go @@ -225,3 +225,38 @@ func TestParams_ValidateSupplierUnbondingPeriodSessions(t *testing.T) { }) } } + +func TestParams_ValidateApplicationUnbondingPeriodSessions(t *testing.T) { + tests := []struct { + desc string + applicationUnbondingPeriodSessions any + err error + }{ + { + desc: "invalid type", + applicationUnbondingPeriodSessions: "invalid", + err: ErrSharedParamInvalid.Wrapf("invalid parameter type: %T", "invalid"), + }, + { + desc: "valid ApplicationUnbondingPeriodSessions", + applicationUnbondingPeriodSessions: uint64(2), + }, + { + desc: "zero ApplicationUnbondingPeriodSessions", + applicationUnbondingPeriodSessions: uint64(0), + err: ErrSharedParamInvalid.Wrapf("invalid ApplicationUnbondingPeriodSessions: (%v)", uint64(0)), + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + err := ValidateApplicationUnbondingPeriodSessions(tt.applicationUnbondingPeriodSessions) + if tt.err != nil { + require.Error(t, err) + require.Contains(t, err.Error(), tt.err.Error()) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/tokenomics/types/tx.pb.go b/x/tokenomics/types/tx.pb.go index 5bc7d33e4..91f06eeff 100644 --- a/x/tokenomics/types/tx.pb.go +++ b/x/tokenomics/types/tx.pb.go @@ -133,6 +133,7 @@ type MsgUpdateParam struct { // specified in the `Params` message in `proof/params.proto.` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Types that are valid to be assigned to AsType: + // // *MsgUpdateParam_AsString // *MsgUpdateParam_AsInt64 // *MsgUpdateParam_AsBytes