diff --git a/.github/workflows-helpers/run-e2e-test-job-template.yaml b/.github/workflows-helpers/run-e2e-test-job-template.yaml index 9b4251dee..7468dae36 100644 --- a/.github/workflows-helpers/run-e2e-test-job-template.yaml +++ b/.github/workflows-helpers/run-e2e-test-job-template.yaml @@ -11,42 +11,44 @@ spec: pokt.network/purpose: e2e-tests spec: containers: - - name: e2e-tests - image: ghcr.io/pokt-network/poktrolld:${IMAGE_TAG} - command: ["/bin/sh"] - args: - - "-c" - - | - poktrolld q gateway list-gateway --node=$POCKET_NODE && \ - poktrolld q application list-application --node=$POCKET_NODE && \ - poktrolld q supplier list-supplier --node=$POCKET_NODE && \ - make acc_initialize_pubkeys && \ - go test -v ./e2e/tests/... -tags=e2e - env: - - name: POCKET_NODE - value: tcp://${NAMESPACE}-validator-poktrolld:36657 - - name: VALIDATOR_RPC_ENDPOINT - value: ${NAMESPACE}-validator-poktrolld:36657 - - name: E2E_DEBUG_OUTPUT - value: "false" # Flip to true to see the command and result of the execution - - name: POKTROLLD_HOME - value: /root/.poktroll - - name: APPGATE_SERVER_URL - value: http://${NAMESPACE}-appgate-server:80 - volumeMounts: - - mountPath: /root/.poktroll/keyring-test/ - name: keys-volume - - mountPath: /root/.poktroll/config/ - name: configs-volume - restartPolicy: Never - volumes: - - secret: - defaultMode: 420 - secretName: keys-${IMAGE_TAG} + - name: e2e-tests + image: ghcr.io/pokt-network/poktrolld:${IMAGE_TAG} + command: ["/bin/sh"] + args: + - "-c" + - | + poktrolld q gateway list-gateway --node=$POCKET_NODE && \ + poktrolld q application list-application --node=$POCKET_NODE && \ + poktrolld q supplier list-supplier --node=$POCKET_NODE && \ + make acc_initialize_pubkeys && \ + go test -v ./e2e/tests/... -tags=e2e + env: + - name: POCKET_NODE + value: tcp://${NAMESPACE}-validator-poktrolld:36657 + - name: VALIDATOR_RPC_ENDPOINT + value: ${NAMESPACE}-validator-poktrolld:36657 + - name: E2E_DEBUG_OUTPUT + value: "false" # Flip to true to see the command and result of the execution + - name: POKTROLLD_HOME + value: /root/.poktroll + - name: APPGATE_SERVER_URL + value: http://${NAMESPACE}-appgate-server:80 + - name: GATEWAY_URL + value: http://${NAMESPACE}-gateway:80 + volumeMounts: + - mountPath: /root/.poktroll/keyring-test/ name: keys-volume - - configMap: - defaultMode: 420 - name: configs-${IMAGE_TAG} + - mountPath: /root/.poktroll/config/ name: configs-volume + restartPolicy: Never + volumes: + - secret: + defaultMode: 420 + secretName: keys-${IMAGE_TAG} + name: keys-volume + - configMap: + defaultMode: 420 + name: configs-${IMAGE_TAG} + name: configs-volume serviceAccountName: default backoffLimit: 0 diff --git a/Makefile b/Makefile index 8f674a008..2cfca767c 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ POKTROLLD_HOME ?= ./localnet/poktrolld POCKET_NODE ?= tcp://127.0.0.1:36657 # The pocket node (validator in the localnet context) TESTNET_RPC ?= https://testnet-validated-validator-rpc.poktroll.com/ # TestNet RPC endpoint. Update if there's another "main" testnet. APPGATE_SERVER ?= http://localhost:42069 +GATEWAY_URL ?= http://localhost:42079 POCKET_ADDR_PREFIX = pokt CHAIN_ID = poktroll @@ -323,6 +324,10 @@ test_e2e: test_e2e_env ## Run all E2E tests test_e2e_app: go test -v ./e2e/tests/... -tags=e2e,test --features-path=stake_app.feature +.PHONY: test_e2e_supplier +test_e2e_supplier: + go test -v ./e2e/tests/... -tags=e2e,test --features-path=stake_supplier.feature + .PHONY: test_e2e_gateway test_e2e_gateway: go test -v ./e2e/tests/... -tags=e2e,test --features-path=stake_gateway.feature @@ -468,7 +473,7 @@ gateway3_stake: ## Stake gateway3 .PHONY: gateway_unstake gateway_unstake: ## Unstake an gateway (must specify the GATEWAY env var) - poktrolld --home=$(POKTROLLD_HOME) tx gateway unstake-gateway --keyring-backend test --from $(GATEWAY) --node $(POCKET_NODE) --chain-id $(CHAIN_ID) + poktrolld --home=$(POKTROLLD_HOME) tx gateway unstake-gateway -y --keyring-backend test --from $(GATEWAY) --node $(POCKET_NODE) --chain-id $(CHAIN_ID) .PHONY: gateway1_unstake gateway1_unstake: ## Unstake gateway1 @@ -508,7 +513,7 @@ app3_stake: ## Stake app3 .PHONY: app_unstake app_unstake: ## Unstake an application (must specify the APP env var) - poktrolld --home=$(POKTROLLD_HOME) tx application unstake-application --keyring-backend test --from $(APP) --node $(POCKET_NODE) --chain-id $(CHAIN_ID) + poktrolld --home=$(POKTROLLD_HOME) tx application unstake-application -y --keyring-backend test --from $(APP) --node $(POCKET_NODE) --chain-id $(CHAIN_ID) .PHONY: app1_unstake app1_unstake: ## Unstake app1 diff --git a/README.md b/README.md deleted file mode 120000 index e0feb2c93..000000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -docusaurus/docs/README.md \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..340e4a730 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +--- +sidebar_position: 1 +title: Poktroll +id: home-doc +slug: / +--- + +
+ + Pocket Network logo + +
+ +
+ + + + + + + + + + + + + +
+ +# poktroll + +**poktroll** is built using the [Cosmos SDK](https://docs.cosmos.network) and +[CometBFT](https://cometbft.com/), created with [Ignite CLI](https://ignite.com/cli) +for the Shannon upgrade of the [Pocket Network](https://pokt.network) blockchain. + +- [Learn about Pocket Network](#learn-about-pocket-network) +- [Developer Documentation](#developer-documentation) +- [Roadmap](#roadmap) +- [Quickstart](#quickstart) +- [Godoc](#godoc) +- [Have questions? Ask An PNYC](#have-questions-ask-an-pnyc) +- [License](#license) + +## Learn about Pocket Network + +User friendly documentation of the Shannon upgrade is still a WIP, but there are +a handful of (potentially outdated) resources you can reference in the meantime +to build a better understanding of Pocket Network: + +- [Pocket Network official documentation](https://docs.pokt.network) +- [[Live] Pocket Network Morse; aka v0](https://github.com/pokt-network/pocket-core) +- [[Outdated] Pocket Network Protocol](https://github.com/pokt-network/pocket-network-protocol) +- [[Deprecated]Pocket Network V1](https://github.com/pokt-network/pocket) + +## Developer Documentation + +The developer documentation is available at [dev.poktroll.com](https://dev.poktroll.com). + +## Roadmap + +You can view the Shannon Roadmap on [Github](https://github.com/orgs/pokt-network/projects/144?query=is%3Aopen+sort%3Aupdated-desc) + +## Quickstart + +The best way to get involved is by following the [quickstart instructions](<[./develop/developer_guide/quickstart.md](https://dev.poktroll.com/develop/developer_guide/quickstart)>). + +## Godoc + +The Godoc for the source code in this can be found at [pkg.go.dev/github.com/pokt-network/poktroll](https://pkg.go.dev/github.com/pokt-network/poktroll). + +## Have questions? Ask An PNYC + +You can use [PNYX](https://pnyxai.com/), an AI-powered search engine that has been +trained and indexed on the Pocket Network documentation, community calls, forums +and much more! + +--- + +## License + +This project is licensed under the MIT License; see the [LICENSE](https://github.com/pokt-network/poktroll/blob/main/LICENSE) file for details. diff --git a/docusaurus/docs/README.md b/docusaurus/docs/README.md index 73d5d724e..c3f9b42ef 100644 --- a/docusaurus/docs/README.md +++ b/docusaurus/docs/README.md @@ -29,18 +29,15 @@ slug: / # poktroll -**poktroll** is built using the [Cosmos SDK](https://docs.cosmos.network) and [CometBFT](https://cometbft.com/), created with [Ignite CLI](https://ignite.com/cli) for the Shannon upgrade of the [Pocket Network](https://pokt.network) blockchain. - -This R&D effort is the result of a research spike conducted by the Core [Pocket Network](https://pokt.network/) Protocol Team at [GROVE Inc.](https://grove.city/). We have documented our research journey [here](https://www.pokt.network/blog/pokt-network-rolling-into-the-modular-future-of-the-protocol-a-technical-deep-dive) (deep dive) and [here](https://www.pokt.network/blog/a-sovereign-rollup-and-a-modular-future) (summary). +**poktroll** is built using the [Cosmos SDK](https://docs.cosmos.network) and +[CometBFT](https://cometbft.com/), created with [Ignite CLI](https://ignite.com/cli) +for the Shannon upgrade of the [Pocket Network](https://pokt.network) blockchain. - [Learn about Pocket Network](#learn-about-pocket-network) - [Roadmap](#roadmap) -- [Getting Started](#getting-started) - - [Quickstart](#quickstart) - - [Godoc](#godoc) -- [Have questions? Ask An AI](#have-questions-ask-an-ai) - - [PNYX (Search Engine)](#pnyx-search-engine) - - [GPokT (Chatbot)](#gpokt-chatbot) +- [Quickstart](#quickstart) +- [Godoc](#godoc) +- [Have questions? Ask An PNYC](#have-questions-ask-an-pnyc) - [License](#license) ## Learn about Pocket Network @@ -50,43 +47,28 @@ a handful of (potentially outdated) resources you can reference in the meantime to build a better understanding of Pocket Network: - [Pocket Network official documentation](https://docs.pokt.network) -- [Pocket Network Morse; aka v0 (current mainnet)](https://github.com/pokt-network/pocket-core) -- [Pocket Network Protocol (outdated)](https://github.com/pokt-network/pocket-network-protocol) -- [Pocket Network V1 (deprecated)](https://github.com/pokt-network/pocket) +- [[Live] Pocket Network Morse; aka v0](https://github.com/pokt-network/pocket-core) +- [[Outdated] Pocket Network Protocol](https://github.com/pokt-network/pocket-network-protocol) +- [[Deprecated]Pocket Network V1](https://github.com/pokt-network/pocket) ## Roadmap -You can details related to our roadmap [here](./planning/roadmap/roadmap.md) and the -roadmap changelog [here](./planning/roadmap/roadmap_changelog.md). - -## Getting Started +You can view the Shannon Roadmap on [Github](https://github.com/orgs/pokt-network/projects/144?query=is%3Aopen+sort%3Aupdated-desc) -### Quickstart +## Quickstart -The best way to get involved is by following the instructions [here](./develop/developer_guide/quickstart.md). +The best way to get involved is by following the [quickstart instructions](./develop/developer_guide/quickstart.md). -### Godoc +## Godoc The Godoc for the source code in this can be found at [pkg.go.dev/github.com/pokt-network/poktroll](https://pkg.go.dev/github.com/pokt-network/poktroll). -## Have questions? Ask An AI - -The fastest and easiest way to get answers to your questions is by one of our -several AI-powered tools. - -### PNYX (Search Engine) +## Have questions? Ask An PNYC You can use [PNYX](https://pnyxai.com/), an AI-powered search engine that has been trained and indexed on the Pocket Network documentation, community calls, forums and much more! -### GPokT (Chatbot) - -You can use our chatbot, [GPokT](https://gpoktn.streamlit.app), to ask questions -about Pocket Network. Please note that it may require you to provide your own -LLM API token. If the deployed version of GPokT is down, you can deploy your own -version by following the instructions [here](https://github.com/pokt-network/gpokt). - --- ## License diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 2f5e7d68e..ea859cb41 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -24,6 +24,7 @@ import ( "github.com/pokt-network/poktroll/app" "github.com/pokt-network/poktroll/testutil/testclient" + "github.com/pokt-network/poktroll/testutil/yaml" apptypes "github.com/pokt-network/poktroll/x/application/types" prooftypes "github.com/pokt-network/poktroll/x/proof/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" @@ -219,14 +220,16 @@ func (s *suite) TheUserStakesAWithUpoktFromTheAccount(actorType string, amount i func (s *suite) TheUserStakesAWithUpoktForServiceFromTheAccount(actorType string, amount int64, serviceId, accName string) { // Create a temporary config file - configPathPattern := fmt.Sprintf("%s_stake_config_*.yaml", accName) + configPathPattern := fmt.Sprintf("%s_stake_config.yaml", accName) configFile, err := os.CreateTemp("", configPathPattern) require.NoError(s, err, "error creating config file in %q", path.Join(os.TempDir(), configPathPattern)) - configContent := fmt.Sprintf("stake_amount: %d upokt\nservice_ids:\n - %s", amount, serviceId) + // Write the config content to the file + configContent := s.getConfigFileContent(amount, actorType, serviceId) _, err = configFile.Write([]byte(configContent)) require.NoError(s, err, "error writing config file %q", configFile.Name()) + // Prepare the command arguments args := []string{ "tx", actorType, @@ -248,6 +251,31 @@ func (s *suite) TheUserStakesAWithUpoktForServiceFromTheAccount(actorType string s.pocketd.result = res } +func (s *suite) getConfigFileContent(amount int64, actorType, serviceId string) string { + var configContent string + switch actorType { + case "application": + configContent = fmt.Sprintf(` + stake_amount: %dupokt + service_ids: + - %s`, + amount, serviceId) + case "supplier": + configContent = fmt.Sprintf(` + stake_amount: %dupokt + services: + - service_id: %s + endpoints: + - publicly_exposed_url: http://relayminer:8545 + rpc_type: json_rpc`, + amount, serviceId) + default: + s.Fatalf("unknown actor type %s", actorType) + } + fmt.Println(yaml.NormalizeYAMLIndentation(configContent)) + return yaml.NormalizeYAMLIndentation(configContent) +} + func (s *suite) TheUserUnstakesAFromTheAccount(actorType string, accName string) { args := []string{ "tx", diff --git a/e2e/tests/stake_supplier.feature b/e2e/tests/stake_supplier.feature new file mode 100644 index 000000000..fc7776c64 --- /dev/null +++ b/e2e/tests/stake_supplier.feature @@ -0,0 +1,28 @@ +Feature: Stake Supplier Namespace + + Scenario: User can stake a Supplier + Given the user has the pocketd binary installed + And the "supplier" for account "supplier2" is not staked + # Stake with 1 uPOKT more than the current stake used in genesis to make + # the transaction succeed. + And the account "supplier2" has a balance greater than "1000070" uPOKT + When the user stakes a "supplier" with "1000070" uPOKT for "anvil" service from the account "supplier2" + 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 + # TODO_TECHDEBT(@Olshansk, @red-0ne): Replace these time-based waits with event listening waits + And the user should wait for "5" seconds + And the "supplier" for account "supplier2" is staked with "1000070" uPOKT + And the account balance of "supplier2" should be "1000070" uPOKT "less" than before + + Scenario: User can unstake a Supplier + Given the user has the pocketd binary installed + And the "supplier" for account "supplier2" is staked with "1000070" uPOKT + And an account exists for "supplier2" + When the user unstakes a "supplier" from the account "supplier2" + 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 "5" seconds + And the "supplier" for account "supplier2" is not staked + And the account balance of "supplier2" should be "1000070" uPOKT "more" than before \ No newline at end of file diff --git a/localnet/grafana-dashboards/cometbft.json b/localnet/grafana-dashboards/cometbft.json index f07128aca..111b5491e 100644 --- a/localnet/grafana-dashboards/cometbft.json +++ b/localnet/grafana-dashboards/cometbft.json @@ -35,6 +35,34 @@ "type": "dashboards", "url": "" }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [ + "gateway_logs" + ], + "targetBlank": false, + "title": "Gateway Logs", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [ + "supplier_logs" + ], + "targetBlank": false, + "title": "Supplier Logs", + "tooltip": "", + "type": "dashboards", + "url": "" + }, { "asDropdown": false, "icon": "external link", diff --git a/localnet/grafana-dashboards/gateway_logs.json b/localnet/grafana-dashboards/gateway_logs.json new file mode 100644 index 000000000..d71c9c3d7 --- /dev/null +++ b/localnet/grafana-dashboards/gateway_logs.json @@ -0,0 +1,118 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 30, + "links": [], + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "editorMode": "builder", + "expr": "{container=\"poktrolld-validator\"} | json | method = `StakeGateway`", + "queryType": "range", + "refId": "Gateway Staking" + } + ], + "title": "Gateway Staking", + "type": "logs" + }, + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 1, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "editorMode": "code", + "expr": "{container=\"poktrolld-validator\"} | json | method = `UnstakeGateway`", + "queryType": "range", + "refId": "Gateway Unstaking" + } + ], + "title": "Gateway Unstaking", + "type": "logs" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [ + "gateway_logs" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Protocol / Gateway Logs", + "uid": "gateway_logs", + "version": 2, + "weekStart": "" +} \ No newline at end of file diff --git a/localnet/grafana-dashboards/supplier_logs.json b/localnet/grafana-dashboards/supplier_logs.json new file mode 100644 index 000000000..609ea1b1e --- /dev/null +++ b/localnet/grafana-dashboards/supplier_logs.json @@ -0,0 +1,116 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 35, + "links": [], + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "editorMode": "code", + "expr": "{container=\"poktrolld-validator\"} | json | method = `StakeSupplier`", + "queryType": "range", + "refId": "Supplier Staking" + } + ], + "title": "Supplier Staking", + "type": "logs" + }, + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "P8E80F9AEF21F6940" + }, + "editorMode": "code", + "expr": "{container=\"poktrolld-validator\"} | json | method = `UnstakeSupplier`", + "queryType": "range", + "refId": "Supplier Unstaking" + } + ], + "title": "Supplier Unstaking", + "type": "logs" + } + ], + "schemaVersion": 39, + "tags": [ + "supplier_logs" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Protocol / Supplier Logs", + "uid": "supplier_logs", + "version": 7, + "weekStart": "" +} diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index ec39727bf..a8600264c 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -57,11 +57,11 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) (numClaimsSettled, numClaim sessionId := claim.SessionHeader.SessionId + _, isProofFound := k.proofKeeper.GetProof(ctx, sessionId, claim.SupplierAddress) // Using the probabilistic proofs approach, determine if this expiring // claim required an on-chain proof isProofRequiredForClaim := k.isProofRequiredForClaim(ctx, &claim) if isProofRequiredForClaim { - _, isProofFound := k.proofKeeper.GetProof(ctx, sessionId, claim.SupplierAddress) // If a proof is not found, the claim will expire and never be settled. if !isProofFound { // Emit an event that a claim has expired and being removed without being settled. @@ -101,9 +101,13 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) (numClaimsSettled, numClaim // The claim & proof are no longer necessary, so there's no need for them // to take up on-chain space. k.proofKeeper.RemoveClaim(ctx, sessionId, claim.SupplierAddress) - // NB: We are calling `RemoveProof` of whether or not the proof was required - // to delete it from the state. It is okay for it to fail here if it doesn't exist. - k.proofKeeper.RemoveProof(ctx, sessionId, claim.SupplierAddress) + // Whether or not the proof is required, the supplier may have submitted one + // so we need to delete it either way. If we don't have the if structure, + // a safe error will be printed, but it can be confusing to the operator + // or developer. + if isProofFound { + k.proofKeeper.RemoveProof(ctx, sessionId, claim.SupplierAddress) + } numClaimsSettled++ logger.Info(fmt.Sprintf("Successfully settled claim for session ID %q at block height %d", claim.SessionHeader.SessionId, blockHeight)) diff --git a/x/tokenomics/keeper/settle_session_accounting.go b/x/tokenomics/keeper/settle_session_accounting.go index c3e76a157..909517c49 100644 --- a/x/tokenomics/keeper/settle_session_accounting.go +++ b/x/tokenomics/keeper/settle_session_accounting.go @@ -147,8 +147,8 @@ func (k Keeper) SettleSessionAccounting( // Verify that the application has enough uPOKT to pay for the services it consumed if application.Stake.IsLT(settlementAmt) { - logger.Error(fmt.Sprintf( - "THIS SHOULD NOT HAPPEN. Application with address %s needs to be charged more than it has staked: %v > %v", + logger.Warn(fmt.Sprintf( + "THIS SHOULD NEVER HAPPEN. Application with address %s needs to be charged more than it has staked: %v > %v", applicationAddress, settlementAmtuPOKT, application.Stake, @@ -157,7 +157,9 @@ func (k Keeper) SettleSessionAccounting( // goes "into debt". Need to design a way to handle this when we implement // probabilistic proofs and add all the parameter logic. Do we touch the application balance? // Do we just let it go into debt? Do we penalize the application? Do we unstake it? Etc... - settlementAmtuPOKT = sdk.NewCoins(*application.Stake) + settlementAmt = sdk.NewCoin("upokt", math.Int(application.Stake.Amount)) + settlementAmtuPOKT = sdk.NewCoins(settlementAmt) + // TODO_BLOCKER: The application should be immediately unstaked at this point in time } // Burn uPOKT from the application module account which was held in escrow @@ -172,7 +174,7 @@ func (k Keeper) SettleSessionAccounting( // Update the application's on-chain stake newAppStake, err := (*application.Stake).SafeSub(settlementAmt) if err != nil { - return types.ErrTokenomicsApplicationNewStakeInvalid.Wrapf("application %q stake cannot be reduce to a negative amount %v", applicationAddress, newAppStake) + return types.ErrTokenomicsApplicationNewStakeInvalid.Wrapf("application %q stake cannot be reduced to a negative amount %v", applicationAddress, newAppStake) } application.Stake = &newAppStake k.applicationKeeper.SetApplication(ctx, application) diff --git a/x/tokenomics/keeper/settle_session_accounting_test.go b/x/tokenomics/keeper/settle_session_accounting_test.go index 567af0d7d..51f135b17 100644 --- a/x/tokenomics/keeper/settle_session_accounting_test.go +++ b/x/tokenomics/keeper/settle_session_accounting_test.go @@ -5,21 +5,63 @@ import ( "fmt" "testing" + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/smt" "github.com/stretchr/testify/require" testkeeper "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/sample" + apptypes "github.com/pokt-network/poktroll/x/application/types" prooftypes "github.com/pokt-network/poktroll/x/proof/types" sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" - "github.com/pokt-network/poktroll/x/tokenomics/types" + tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" ) // TODO_TEST(@bryanchriswhite, @Olshansk): Improve tokenomics tests (i.e. checking balances) // once in-memory network integration tests are supported. +func TestSettleSessionAccounting_HandleAppGoingIntoDebt(t *testing.T) { + keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t) + + // Add a new application + appStake := types.NewCoin("upokt", math.NewInt(1000000)) + app := apptypes.Application{ + Address: sample.AccAddress(), + Stake: &appStake, + } + keepers.SetApplication(ctx, app) + + // Add a new supplier + supplierStake := types.NewCoin("upokt", math.NewInt(1000000)) + supplier := sharedtypes.Supplier{ + Address: sample.AccAddress(), + Stake: &supplierStake, + } + + // The base claim whose root will be customized for testing purposes + claim := prooftypes.Claim{ + SupplierAddress: supplier.Address, + SessionHeader: &sessiontypes.SessionHeader{ + ApplicationAddress: app.Address, + Service: &sharedtypes.Service{ + Id: "svc1", + Name: "svcName1", + }, + SessionId: "session_id", + SessionStartBlockHeight: 1, + SessionEndBlockHeight: sessionkeeper.GetSessionEndBlockHeight(1), + }, + RootHash: smstRootWithSum(appStake.Amount.Uint64() + 1), // More than the app stake + } + + err := keepers.SettleSessionAccounting(ctx, &claim) + require.NoError(t, err) + // TODO_BLOCKER: Need to make sure the application is unstaked at this point in time. +} + func TestSettleSessionAccounting_ValidAccounting(t *testing.T) { t.Skip("TODO_BLOCKER(@Olshansk): Add E2E and integration tests so we validate the actual state changes of the bank & account keepers.") // Assert that `suppliertypes.ModuleName` account module balance is *unchanged* @@ -58,7 +100,7 @@ func TestSettleSessionAccounting_AppNotFound(t *testing.T) { err := keeper.SettleSessionAccounting(ctx, &claim) require.Error(t, err) - require.ErrorIs(t, err, types.ErrTokenomicsApplicationNotFound) + require.ErrorIs(t, err, tokenomicstypes.ErrTokenomicsApplicationNotFound) } func TestSettleSessionAccounting_InvalidRoot(t *testing.T) { @@ -169,7 +211,7 @@ func TestSettleSessionAccounting_InvalidClaim(t *testing.T) { desc: "Nil Claim", claim: nil, errExpected: true, - expectErr: types.ErrTokenomicsClaimNil, + expectErr: tokenomicstypes.ErrTokenomicsClaimNil, }, { desc: "Claim with nil session header", @@ -179,7 +221,7 @@ func TestSettleSessionAccounting_InvalidClaim(t *testing.T) { return &claim }(), errExpected: true, - expectErr: types.ErrTokenomicsSessionHeaderNil, + expectErr: tokenomicstypes.ErrTokenomicsSessionHeaderNil, }, { desc: "Claim with invalid session id", @@ -189,7 +231,7 @@ func TestSettleSessionAccounting_InvalidClaim(t *testing.T) { return &claim }(), errExpected: true, - expectErr: types.ErrTokenomicsSessionHeaderInvalid, + expectErr: tokenomicstypes.ErrTokenomicsSessionHeaderInvalid, }, { desc: "Claim with invalid application address", @@ -199,7 +241,7 @@ func TestSettleSessionAccounting_InvalidClaim(t *testing.T) { return &claim }(), errExpected: true, - expectErr: types.ErrTokenomicsSessionHeaderInvalid, + expectErr: tokenomicstypes.ErrTokenomicsSessionHeaderInvalid, }, { desc: "Claim with invalid supplier address", @@ -209,7 +251,7 @@ func TestSettleSessionAccounting_InvalidClaim(t *testing.T) { return &claim }(), errExpected: true, - expectErr: types.ErrTokenomicsSupplierAddressInvalid, + expectErr: tokenomicstypes.ErrTokenomicsSupplierAddressInvalid, }, } diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 01d5a75f1..f88b174d5 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -19,5 +19,5 @@ var ( ErrTokenomicsApplicationAddressInvalid = sdkerrors.Register(ModuleName, 1112, "the application address in the claim is not a valid bech32 address") ErrTokenomicsParamsInvalid = sdkerrors.Register(ModuleName, 1113, "provided params are invalid") ErrTokenomicsRootHashInvalid = sdkerrors.Register(ModuleName, 1114, "the root hash in the claim is invalid") - ErrTokenomicsApplicationNewStakeInvalid = sdkerrors.Register(ModuleName, 1115, "application stake cannot be reduce to a -ve amount") + ErrTokenomicsApplicationNewStakeInvalid = sdkerrors.Register(ModuleName, 1115, "application stake cannot be reduced to a -ve amount") )