initial: sovereign Mukan Network fork
Some checks failed
Build SimApp / build (amd64) (push) Waiting to run
Build SimApp / build (arm64) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
Build & Push / build (push) Waiting to run
Run Gosec / Gosec (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Checks dependencies and mocks generation / Check go mod tidy (push) Waiting to run
Checks dependencies and mocks generation / Check up to date mocks (push) Waiting to run
System Tests / setup (push) Waiting to run
System Tests / test-system (push) Blocked by required conditions
System Tests / test-system-legacy (push) Blocked by required conditions
Tests / Code Coverage / split-test-files (push) Waiting to run
Tests / Code Coverage / tests (00) (push) Blocked by required conditions
Tests / Code Coverage / tests (01) (push) Blocked by required conditions
Tests / Code Coverage / tests (02) (push) Blocked by required conditions
Tests / Code Coverage / tests (03) (push) Blocked by required conditions
Tests / Code Coverage / test-integration (push) Waiting to run
Tests / Code Coverage / test-e2e (push) Waiting to run
Tests / Code Coverage / repo-analysis (push) Blocked by required conditions
Tests / Code Coverage / test-sim-nondeterminism (push) Waiting to run
Tests / Code Coverage / test-clientv2 (push) Waiting to run
Tests / Code Coverage / test-core (push) Waiting to run
Tests / Code Coverage / test-depinject (push) Waiting to run
Tests / Code Coverage / test-errors (push) Waiting to run
Tests / Code Coverage / test-math (push) Waiting to run
Tests / Code Coverage / test-schema (push) Waiting to run
Tests / Code Coverage / test-collections (push) Waiting to run
Tests / Code Coverage / test-cosmovisor (push) Waiting to run
Tests / Code Coverage / test-confix (push) Waiting to run
Tests / Code Coverage / test-store (push) Waiting to run
Tests / Code Coverage / test-log (push) Waiting to run
Tests / Code Coverage / test-x-tx (push) Waiting to run
Tests / Code Coverage / test-x-nft (push) Waiting to run
Tests / Code Coverage / test-x-circuit (push) Waiting to run
Tests / Code Coverage / test-x-feegrant (push) Waiting to run
Tests / Code Coverage / test-x-evidence (push) Waiting to run
Tests / Code Coverage / test-x-upgrade (push) Waiting to run
Tests / Code Coverage / test-tools-benchmark (push) Waiting to run
Build & Push SDK Proto Builder / build (push) Has been cancelled

This commit is contained in:
Mukan Erkin TÖRÜK 2026-05-11 03:18:24 +03:00
commit 20afb5db80
2135 changed files with 624428 additions and 0 deletions

116
.clang-format Normal file
View file

@ -0,0 +1,116 @@
---
Language: Proto
BasedOnStyle: Google
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: ".*"
Priority: 1
IncludeIsMainRegex: "(Test)?$"
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
RawStringFormats:
- Delimiters:
- pb
Language: TextProto
BasedOnStyle: Google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
---

5
.dockerignore Normal file
View file

@ -0,0 +1,5 @@
Dockerfile
Vagrantfile
build/
coverage.txt

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
client/docs/swagger-ui/* linguist-vendored

15
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,15 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# NOTE: Order is important; the last matching pattern takes the most precedence
# Cosmos SDK Codeowners
# Core team as default owners
* @cosmos/sdk-core-dev
# Components
# docs configuration
/docs/ @cosmos/sdk-core-dev

30
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View file

@ -0,0 +1,30 @@
---
name: Bug Report
about: Create a report to help us squash bugs!
title: "[Bug]: "
labels: "T:Bug"
---
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v ✰ Thanks for opening an issue! ✰
v Before smashing the submit button please review the template.
v Please also ensure that this is not a duplicate issue :)
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
<!--
IMPORTANT: Prior to opening a bug report, check if it affects one of the core modules
and if its elegible for a bug bounty on `SECURITY.md`. Bugs that are not submitted
through the appropriate channels won't receive any bounty.
-->
## Summary of Bug
<!-- Concisely describe the issue -->
## Version
<!-- git commit hash or release version -->
## Steps to Reproduce
<!-- What commands in order should someone run to reproduce your problem? -->

49
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View file

@ -0,0 +1,49 @@
name: 🐛 Bug report
description: Create a report to help us squash bugs!
title: "[Bug]: "
labels: ["T:Bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Before smashing the submit button please review the template.
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search existing issues to avoid creating duplicates.
options:
- label: I have searched the existing issues
required: true
- type: markdown
attributes:
value: |
IMPORTANT: Prior to opening a bug report, check if it affects one of the core modules
and if its eligible for a bug bounty on `SECURITY.md`. Bugs that are not submitted
through the appropriate channels won't receive any bounty.
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
value: "A bug happened!"
validations:
required: true
- type: input
attributes:
label: Cosmos SDK Version
description: If applicable, specify the version you're using
placeholder: 0.46, 0.47, main, etc.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: How to reproduce?
description: If applicable could you describe how we could reproduce the bug
placeholder: Tell us what how to reproduce the bug!
validations:
required: false

View file

@ -0,0 +1,18 @@
name: Documentation Request
description: Create an issue for missing or incorrect documentation
title: "[Documentation]: "
labels: ["T:Docs"]
body:
- type: markdown
attributes:
value: |
✰ Thanks for opening an issue! ✰
Tell us where what you would like to see get added to the documentation or if there is an error in the documentation?
- type: textarea
id: what-happened
attributes:
label: Summary
placeholder: Description of what you would like to see
validations:
required: true

31
.github/ISSUE_TEMPLATE/epics.md vendored Normal file
View file

@ -0,0 +1,31 @@
---
name: Epic
about: Create an epic/user
title: "[Epic]: "
labels: T:Epic
---
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v ✰ Thanks for opening an issue! ✰
v Before smashing the submit button please review the template.
v Word of caution: poorly thought-out proposals may be rejected
v without deliberation
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
## Summary
<!-- Short, concise description of the proposed feature/changes to the repository
What are the user needs?
How could this solution fix the user facing problem? -->
## Problem Definition
<!-- Why do we need this feature?
What problems may be addressed by introducing this feature?
What benefits does the SDK stand to gain by including this feature?
Are there any disadvantages of including this feature? -->
## Work Breakdown
<!-- Break the work into many bullet points that will later be turned into issues that can be assigned to developers to work on
This work may been to be broken up into phases of work in order to better organize when and how things get done. -->

43
.github/ISSUE_TEMPLATE/epics.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: Epic
description: Create an epic/user
title: "[Epic]: "
labels: ["T:Epic"]
body:
- type: markdown
attributes:
value: |
Thanks for opening this issue, this template is meant for long lived work scopes, if this is what you're looking for please continue
- type: textarea
id: summary
attributes:
label: Summary
description: |
What are the user needs?
How could this solution fix the user facing problem?
placeholder: Short, concise description of the proposed feature/changes to the repository
validations:
required: true
- type: textarea
id: problem
attributes:
label: Problem Definition
description: |
Why do we need this feature?
What problems may be addressed by introducing this feature?
What benefits does the SDK stand to gain by including this feature?
Are there any disadvantages of including this feature?
placeholder: Description of the issue being faced
validations:
required: true
- type: textarea
id: work
attributes:
label: Work Breakdown
description: |
Break the work into many bullet points that will later be turned into issues that can be assigned to developers to work on
This work may been to be broken up into phases of work in order to better organize when and how things get done.
placeholder: Description of the steps needed to deliver this feature
validations:
required: true

View file

@ -0,0 +1,28 @@
---
name: Feature Request
about: Create a proposal to request a feature
title: "[Feature]: "
labels: T:feature-request
---
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v ✰ Thanks for opening an issue! ✰
v Before smashing the submit button please review the template.
v Word of caution: poorly thought-out proposals may be rejected
v without deliberation
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
## Summary
<!-- Short, concise description of the proposed feature -->
## Problem Definition
<!-- Why do we need this feature?
What problems may be addressed by introducing this feature?
What benefits does the SDK stand to gain by including this feature?
Are there any disadvantages of including this feature? -->
## Proposal
<!-- Detailed description of requirements of implementation -->

View file

@ -0,0 +1,41 @@
name: Feature Request
description: Create a proposal to request a feature
title: "[Feature]: "
labels: ["T:feature-request"]
body:
- type: markdown
attributes:
value: |
✰ Thanks for opening an issue! ✰
- type: textarea
id: summary
attributes:
label: Summary
description: |
What are the user needs?
How could this solution fix the user facing problem?
placeholder: Short, concise description of the proposed feature/changes to the repository
validations:
required: true
- type: textarea
id: problem
attributes:
label: Problem Definition
description: |
If applicable please answer the below questions
Why do we need this feature?
What problems may be addressed by introducing this feature?
What benefits does the SDK stand to gain by including this feature?
Are there any disadvantages of including this feature?
placeholder: Description of the issue being faced
validations:
required: false
- type: textarea
id: proposal
attributes:
label: Proposed Feature
description: |
Description of the proposed features or changes to an existing feature to meet your needs
placeholder: Description of the proposed feature(s)
validations:
required: true

View file

@ -0,0 +1,40 @@
---
name: Module Readiness Checklist
about: Pre-flight checklist that modules must pass in order to be included in a release of the Cosmos SDK
labels: 'module-readiness-checklist'
---
## x/{MODULE_NAME} Module Readiness Checklist
This checklist is to be used for tracking the final internal audit of new Cosmos SDK modules prior to inclusion in a published release.
### Release Candidate Checklist
The following checklist should be gone through once the module has been fully implemented. This audit should be performed directly on `main`, or preferably on a `alpha` or `beta` release tag that includes the module.
The module **should not** be included in any Release Candidate tag until it has passed this checklist.
- [ ] API audit (at least 1 person) (@assignee)
- [ ] Are Msg and Query methods and types well-named and organized?
- [ ] Is everything well documented (inline godoc as well as the spec [README.md](https://github.com/cosmos/cosmos-sdk/blob/main/docs/spec/README.md) in module directory)
- [ ] State machine audit (at least 2 people) (@assignee1, @assignee2)
- [ ] Read through MsgServer code and verify correctness upon visual inspection
- [ ] Ensure all state machine code which could be confusing is properly commented
- [ ] Make sure state machine logic matches Msg method documentation
- [ ] Ensure that all state machine edge cases are covered with tests and that test coverage is sufficient (at least 90% coverage on module code)
- [ ] Assess potential threats for each method including spam attacks and ensure that threats have been addressed sufficiently. This should be done by writing up threat assessment for each method
- [ ] Assess potential risks of any new third party dependencies and decide whether a dependency audit is needed
- [ ] Completeness audit, fully implemented with tests (at least 1 person) (@assignee)
- [ ] Genesis import and export of all state
- [ ] Query services
- [ ] CLI methods
- [ ] All necessary migration scripts are present (if this is an upgrade of existing module)
### Published Release Checklist
After the above checks have been audited and the module is included in a tagged Release Candidate, the following additional checklist should be undertaken for live testing, and potentially a 3rd party audit (if deemed necessary):
- [ ] Testnet / devnet testing (2-3 people) (@assignee1, @assignee2, @assignee3)
- [ ] All Msg methods have been tested especially in light of any potential threats identified
- [ ] Genesis import and export has been tested
- [ ] Nice to have (and needed in some cases if threats could be high): Official 3rd party audit

87
.github/ISSUE_TEMPLATE/qa.md vendored Normal file
View file

@ -0,0 +1,87 @@
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v ✰ Thanks for opening an issue! ✰
v Before smashing the submit button please review the template.
v Word of caution: poorly thought-out proposals may be rejected
v without deliberation
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
## Summary
<!-- In a few short sentences summarize the release -->
## Major Changes
<!-- Describe the major changes associated to this release -->
## Gotchas
<!-- Gotchas is an area which changes could of been made that the auditors should be aware of -->
## QA Breakdown
* Audit
* [ ] Audit BaseApp
* [ ] Audit Types
* [ ] Audit x/auth
* [ ] Audit x/authz
* [ ] Audit x/bank
* [ ] Audit x/circuit
* [ ] Audit x/consensus
* [ ] Audit x/distribution
* [ ] Audit x/evidence
* [ ] Audit x/epochs
* [ ] Audit x/feegrant
* [ ] Audit x/genutil
* [ ] Audit x/gov
* [ ] Audit x/group
* [ ] Audit x/mint
* [ ] Audit x/nft
* [ ] Audit x/protocolpool
* [ ] Audit x/slashing
* [ ] Audit x/staking
* [ ] Audit x/tx
* [ ] Audit x/upgrade
* [ ] Audit client
* [ ] Audit server
* [ ] Audit store
* [ ] Audit runtime
* [ ] Audit simapp
* [ ] Release alpha
* [ ] Cosmos-SDK testnet
* [ ] Public testnet (IBC, WASM, SDK)
* [ ] Upgrade a chain with data from vX
* Release documentation
* [ ] Audit UPGRADING.md
* [ ] Update all codeblock to the appropriate version number
### Audit checklist
* please copy to a markdown to follow while you walk through the code
* 2 people should be assigned to each section
* [ ] API audit
* spec audit: check if the spec is complete.
* Are Msg and Query methods and types well-named and organized?
* Is everything well documented (inline godoc as well as package [`README.md`](https://docs.cosmos.network/main/spec/SPEC_MODULE#common-layout) in module directory)
* check the proto definition - make sure everything is in accordance to ADR-30 (at least 1 person, TODO assignee)
* Check new fields and endpoints have the `Since: cosmos-sdk X` comment
* [ ] Completeness audit, fully implemented with tests
* [ ] Genesis import and export of all state
* [ ] Query services
* [ ] CLI methods
* [ ] All necessary migration scripts are present (if this is an upgrade of existing module)
* [ ] State machine audit
* [ ] Read through MsgServer code and verify correctness upon visual inspection
* [ ] Ensure all state machine code which could be confusing is properly commented
* [ ] Make sure state machine logic matches Msg method documentation
* [ ] Ensure that all state machine edge cases are covered with tests and that test coverage is sufficient (at least 90% coverage on module code)
* [ ] Assess potential threats for each method including spam attacks and ensure that threats have been addressed sufficiently. This should be done by writing up threat assessment for each method. Specifically we should be paying attention to:
* [ ] algorithmic complexity and places this could be exploited (ex. nested `for` loops)
* [ ] charging gas complex computation (ex. `for` loops)
* [ ] storage is safe (we don't pollute the state).
* [ ] Assess potential risks of any new third party dependencies and decide whether a dependency audit is needed
* [ ] Check correctness of simulation implementation if any
* [ ] Audit Changelog against commit log, ensuring all breaking changes, bug fixes, and improvements are properly documented.
If any changes are needed, please make them against main and backport them to release/vX.X.x

38
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,38 @@
# Description
Closes: #XXXX
<!-- Add a description of the changes that this PR introduces and the files that
are the most critical to review. -->
---
## Author Checklist
*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues. Your PR will not be merged unless you satisfy
all of these items.*
I have...
* [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title, you can find examples of the prefixes below:
<!-- * `feat`: A new feature
* `fix`: A bug fix
* `docs`: Documentation only changes
* `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* `refactor`: A code change that neither fixes a bug nor adds a feature
* `perf`: A code change that improves performance
* `test`: Adding missing tests or correcting existing tests
* `build`: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* `ci`: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* `chore`: Other changes that don't modify src or test files
* `revert`: Reverts a previous commit -->
* [ ] confirmed `!` in the type prefix if API or client breaking change
* [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting))
* [ ] provided a link to the relevant issue or specification
* [ ] reviewed "Files changed" and left comments if necessary
* [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing)
* [ ] added a changelog entry to `CHANGELOG.md`
* [ ] updated the relevant documentation or specification, including comments for [documenting Go code](https://blog.golang.org/godoc)
* [ ] confirmed all CI checks have passed

11
.github/codeql/config.yml vendored Normal file
View file

@ -0,0 +1,11 @@
packs:
- crypto-com/cosmos-sdk-codeql
queries:
- uses: security-and-quality
- uses: security-experimental
- uses: security-extended
paths-ignore:
- api
- '**/*_test.go'
- '**/*.pulsar.go'
- '**/*.pb.go'

259
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,259 @@
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
time: "01:00"
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
time: "01:05"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/simapp"
schedule:
interval: daily
time: "01:10"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/tests"
schedule:
interval: weekly
day: monday
time: "01:15"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/api"
schedule:
interval: weekly
day: tuesday
time: "01:20"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/core"
schedule:
interval: weekly
day: thursday
time: "01:30"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/depinject"
schedule:
interval: weekly
day: friday
time: "01:35"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/errors"
schedule:
interval: weekly
day: monday
time: "01:40"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/math"
schedule:
interval: weekly
day: tuesday
time: "01:45"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/client/v2"
schedule:
interval: weekly
day: wednesday
time: "01:50"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/schema"
schedule:
interval: weekly
day: wednesday
time: "01:53"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/x/tx"
schedule:
interval: weekly
day: thursday
time: "01:55"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/tools/cosmovisor"
schedule:
interval: weekly
day: friday
time: "02:00"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/tools/confix"
schedule:
interval: weekly
day: tuesday
time: "02:10"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/collections"
schedule:
interval: weekly
day: friday
time: "02:20"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/x/nft"
schedule:
interval: weekly
day: monday
time: "02:25"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/x/circuit"
schedule:
interval: weekly
day: tuesday
time: "02:30"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "x/feegrant"
schedule:
interval: weekly
day: wednesday
time: "02:35"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/x/evidence"
schedule:
interval: weekly
day: thursday
time: "02:40"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/store"
schedule:
interval: weekly
day: friday
time: "02:45"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "x/upgrade"
schedule:
interval: weekly
day: monday
time: "02:50"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "log"
schedule:
interval: weekly
day: tuesday
time: "02:55"
labels:
- "A:automerge"
- dependencies
- package-ecosystem: gomod
directory: "/tools/benchmark"
schedule:
interval: weekly
day: wednesday
time: "03:25"
labels:
- "A:automerge"
- dependencies
# Dependencies should be up to date on release branch
- package-ecosystem: gomod
directory: "/"
target-branch: "release/v0.47.x"
schedule:
interval: daily
time: "03:00"
labels:
- "A:automerge"
- dependencies
- "testing-required"
allow:
- dependency-name: "github.com/cosmos/cosmos-sdk/*"
dependency-type: "all"
- dependency-name: "github.com/cosmos/*"
dependency-type: "all"
- dependency-name: "cosmossdk.io/*"
dependency-type: "all"
- dependency-name: "github.com/cometbft/*"
dependency-type: "all"
ignore:
- dependency-name: "github.com/cometbft/cometbft"
# cometbft 0.37 is not semver, but we want to only update "patch" versions for 0.37.x
update-types:
["version-update:semver-major", "version-update:semver-minor"]
- package-ecosystem: gomod
directory: "/"
target-branch: "release/v0.50.x"
schedule:
interval: daily
time: "03:00"
labels:
- "A:automerge"
- dependencies
- "testing-required"
allow:
- dependency-name: "github.com/cosmos/cosmos-sdk/*"
dependency-type: "all"
- dependency-name: "github.com/cosmos/*"
dependency-type: "all"
- dependency-name: "cosmossdk.io/*"
dependency-type: "all"
- dependency-name: "github.com/cometbft/*"
dependency-type: "all"
ignore:
- dependency-name: "github.com/cometbft/cometbft"
# cometbft 0.38 is not semver, but we want to only update "patch" versions for 0.38.x
update-types:
["version-update:semver-major", "version-update:semver-minor"]

71
.github/pr_labeler.yml vendored Normal file
View file

@ -0,0 +1,71 @@
"C:CLI":
- client/**/*
- x/*/client/**/*
"C:Confix":
- tools/confix/**/*
"C:Cosmovisor":
- tools/cosmovisor/**/*
"C:Keys":
- client/keys/**/*
"C:Simulations":
- types/simulation/**/*
- x/simulation/**/*
- x/*/simulation/**/*
- simsx/**/*
- tools/benchmark/**/*
"C:Store":
- store/**/*
"C:collections":
- collections/**/*
"C:log":
- log/*
"C:x/auth":
- x/auth/**/*
"C:x/authz":
- x/authz/**/*
"C:x/bank":
- x/bank/**/*
"C:x/circuit":
- x/circuit/**/*
"C:x/consensus":
- x/consensus/**/*
"C:x/distribution":
- x/distribution/**/*
"C:x/evidence":
- x/evidence/**/*
"C:x/feegrant":
- x/feegrant/**/*
"C:x/genutil":
- x/genutil/**/*
"C:x/gov":
- x/gov/**/*
"C:x/group":
- x/group/**/*
"C:x/mint":
- x/mint/**/*
"C:x/nft":
- x/nft/**/*
"C:x/protocolpool":
- x/protocolpool/**/*
"C:x/slashing":
- x/slashing/**/*
"C:x/staking":
- x/staking/**/*
"C:x/tx":
- x/tx/**/*
"C:x/upgrade":
- x/upgrade/**/*
"C:x/epochs":
- x/epochs/**/*
"Type: ADR":
- docs/architecture/**/*
"Type: Build":
- Makefile
- Dockerfile
- docker-compose.yml
- scripts/*
"Type: CI":
- .github/**
- buf.yaml
- .mergify.yml
- .golangci.yml

38
.github/workflows/build-docs.yml vendored Normal file
View file

@ -0,0 +1,38 @@
name: Build Docs
# This workflow runs when a PR is labeled with `docs`
# This will check if the docs build successfully by running `make build-docs`
on:
pull_request:
branches:
- main
- "release/**"
paths:
- "docs/**"
- "x/**/*.md"
- .github/workflows/deploy-docs.yml
- .github/workflows/build-docs.yml
permissions:
contents: read
jobs:
check-docs-build:
name: Check docs build
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- name: Setup Node.js 🔧
uses: actions/setup-node@v4
with:
node-version: "16.x"
# npm install npm should be removed when https://github.com/npm/cli/issues/4942 is fixed
- name: Build docs 🔧
run: |
npm install -g npm@8.5.5
make build-docs

54
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,54 @@
name: Build SimApp
on:
pull_request:
merge_group:
push:
branches:
- main
- release/**
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}-build
cancel-in-progress: true
jobs:
build:
runs-on: depot-ubuntu-22.04-4
strategy:
matrix:
go-arch: ["amd64", "arm64"] # drop 32 bit support for now (and maybe forever)
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: install aarch64-gcc
if: matrix.go-arch == 'arm64'
run: sudo apt-get install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
###################
#### Build App ####
###################
- name: Build
run: GOARCH=${{ matrix.go-arch }} make build
- name: Build with legacy app.go
run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS="legacy" make build
# TODO re-add with comet v1
#- name: Build with BLS12381
# if: matrix.go-arch == 'amd64'
# run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS="bls12381" make build
- name: Build with Secp_cgo
if: matrix.go-arch == 'amd64'
run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS="secp" make build
- name: Build with legacy app.go and Secp_cgo
if: matrix.go-arch == 'amd64'
run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS="legacy,secp" make build
###################
## Build Tooling ##
###################
- name: Build Cosmovisor
run: GOARCH=${{ matrix.go-arch }} make cosmovisor
- name: Build Confix
run: GOARCH=${{ matrix.go-arch }} make confix

View file

@ -0,0 +1,19 @@
# Checks if a changelog is missing in the PR diff
name: Changelog Reminder
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths: ["**/*.go"]
permissions:
pull-requests: write
jobs:
remind:
name: Changelog Reminder
runs-on: depot-ubuntu-22.04-4
# Skip draft PRs and PRs starting with: revert, test, chore, ci, docs, style, build, refactor
if: "!github.event.pull_request.draft && !contains(github.event.pull_request.title, 'revert') && !contains(github.event.pull_request.title, 'test') && !contains(github.event.pull_request.title, 'chore') && !contains(github.event.pull_request.title, 'ci') && !contains(github.event.pull_request.title, 'docs') && !contains(github.event.pull_request.title, 'style') && !contains(github.event.pull_request.title, 'build') && !contains(github.event.pull_request.title, 'refactor')"
steps:
- uses: actions/checkout@v4
- uses: mskelton/changelog-reminder-action@v3
with:
message: "@${{ github.actor }} your pull request is missing a changelog!"

View file

@ -0,0 +1,17 @@
name: Remove GitHub Action Old Artifacts
on:
schedule:
# Every day at 1am
- cron: "0 1 * * *"
jobs:
remove-old-artifacts:
runs-on: depot-ubuntu-22.04-4
timeout-minutes: 30
steps:
- name: Remove old artifacts
uses: c-hive/gha-remove-artifacts@v1
with:
age: "7 days"

58
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: "CodeQL"
on:
pull_request:
paths:
- "**.go"
push:
branches:
- main
- release/**
paths:
- "**.go"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Analyze
runs-on: depot-ubuntu-22.04-4
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: "go"
config-file: ./.github/codeql/config.yml
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

19
.github/workflows/consensuswarn.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: "Warn about consensus code changes"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
main:
permissions:
pull-requests: write # For reading the PR and posting comment
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: orijtech/consensuswarn@main
with:
roots: "github.com/cosmos/cosmos-sdk/baseapp.BaseApp.PrepareProposal,github.com/cosmos/cosmos-sdk/baseapp.BaseApp.ProcessProposal,github.com/cosmos/cosmos-sdk/baseapp.BaseApp.FinalizeBlock,github.com/cosmos/cosmos-sdk/baseapp.BaseApp.Commit,github.com/cosmos/cosmos-sdk/baseapp.BaseApp.VerifyVoteExtension"

View file

@ -0,0 +1,47 @@
name: Dependabot Update All Go Modules
on: pull_request
permissions:
contents: write
pull-requests: write
env:
PR_TITLE: ${{ github.event.pull_request.title }}
jobs:
update-all:
runs-on: depot-ubuntu-22.04-4
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Generate Token
uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v1
id: app-token
with:
app-id: "${{ secrets.APP_ID }}"
private-key: "${{ secrets.APP_PRIVATE_KEY }}"
- uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
token: "${{ steps.app-token.outputs.token }}"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Extract updated dependency
id: deps
run: |
# Extract the dependency name from the PR title
# Example: "build(deps): Bump github.com/cosmos/cosmos-sdk from 0.46.0 to 0.47.0"
# Extracts "github.com/cosmos/cosmos-sdk" and "0.47.0"
echo "name=$(echo "$PR_TITLE" | cut -d ' ' -f 3)" >> $GITHUB_OUTPUT
echo "version=$(echo "$PR_TITLE" | cut -d ' ' -f 7)" >> $GITHUB_OUTPUT
- name: Update all Go modules
run: |
./scripts/go-update-dep-all.sh ${{ format('{0}@v{1}', steps.deps.outputs.name, steps.deps.outputs.version) }}
./scripts/go-mod-tidy-all.sh
- name: Commit changes
uses: EndBug/add-and-commit@v9
with:
default_author: user_info
message: "${{ github.event.pull_request.title }} for all modules"

View file

@ -0,0 +1,46 @@
name: "Dependency Review"
on:
pull_request:
merge_group:
permissions:
contents: read
jobs:
dependency-review:
runs-on: depot-ubuntu-22.04-4
steps:
- name: "Checkout Repository"
uses: actions/checkout@v4
- name: "Setup Go"
uses: actions/setup-go@v5
with:
go-version: "1.24"
check-latest: true
- name: "Dependency Review"
uses: actions/dependency-review-action@v4
with:
base-ref: ${{ github.event.pull_request.base.sha || 'main' }}
head-ref: ${{ github.event.pull_request.head.sha || github.ref }}
fail-on-severity: high
- name: "Dependency audit"
run: ./scripts/dep-assert.sh
- name: "Go vulnerability check"
id: govuln
run: |
# Run the vulnerability check and capture its output (ignoring non-zero exit codes)
make vulncheck 2>&1 | tee govulncheck-output.txt || true
# Extract vulnerability identifiers from the output (e.g., GO-2025-3443)
vulnerabilities=$(grep -o 'GO-[0-9]\{4\}-[0-9]\+' govulncheck-output.txt | sort | uniq)
echo "Detected vulnerabilities: $vulnerabilities"
# Check if any vulnerability other than GO-2025-3443 exists
for vuln in $vulnerabilities; do
if [ "$vuln" != "GO-2025-3443" ]; then
echo "Found vulnerability $vuln, failing..."
exit 1
fi
done
echo "Only known vulnerability (GO-2025-3443) present. Continuing."

73
.github/workflows/docker.yml vendored Normal file
View file

@ -0,0 +1,73 @@
name: Build & Push
# Build & Push builds the simapp docker image on every push to main and
# and pushes the image to https://ghcr.io/cosmos/simapp
on:
pull_request:
paths:
- "Dockerfile"
push:
branches:
- main
tags:
- "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0.0, v20.15.10
- "v[0-9]+.[0-9]+.[0-9]+-rc.*" # Push events to matching v*, i.e. v1.0.0-rc.1, v20.15.10-rc.5
- "v[0-9]+.[0-9]+.[0-9]+-beta.*" # Push events to matching v*, i.e. v1.0.0-beta.1, v20.15.10-beta.5
workflow_dispatch:
inputs:
tags:
description: "SDK version (e.g 0.47.1)"
required: true
type: string
permissions:
contents: read
packages: write
id-token: write
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: cosmos/simapp
jobs:
build:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern={{version}},value=v${{ inputs.tags }},enable=${{ inputs.tags != '' }}
flavor: |
latest=false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log into registry ${{ env.REGISTRY }}
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Depot
uses: depot/setup-action@v1
- name: Publish to GitHub Packages
uses: depot/build-push-action@v1
with:
project: gnm1jqptpw
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}

36
.github/workflows/gosec.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: Run Gosec
on:
pull_request:
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
jobs:
Gosec:
permissions:
security-events: write
runs-on: ubuntu-latest
env:
GO111MODULE: on
steps:
- name: Checkout Source
uses: actions/checkout@v4
- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
args: "-exclude=G101,G107 -exclude-generated -no-fail -fmt sarif -out results.sarif ./..."
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

15
.github/workflows/issue_labeler.yml vendored Normal file
View file

@ -0,0 +1,15 @@
name: "Issue Labeler"
on:
issues:
types: [opened]
jobs:
triage:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: github/issue-labeler@v3.4
if: join(github.event.issue.labels) == ''
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/issue_labeler.yml
enable-versioned-regex: 0

18
.github/workflows/issues.yml vendored Normal file
View file

@ -0,0 +1,18 @@
name: Add Sprint issues to Cosmos SDK Project
on:
issues:
types:
- opened
- labeled
jobs:
add-to-project:
name: Add issue to project
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/add-to-project@v1.0.2
with:
project-url: https://github.com/orgs/cosmos/projects/26
# add all issues opened to the issue board for triage and assignment
github-token: ${{ secrets.PERSONAL_TOKEN }}

47
.github/workflows/lint-pr.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: "Lint PR"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
permissions:
contents: read
jobs:
main:
permissions:
pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs
statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR
runs-on: depot-ubuntu-22.04-4
steps:
- uses: amannn/action-semantic-pull-request@v5.5.3
id: lint_pr_title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: marocchino/sticky-pull-request-comment@v2
# When the previous steps fails, the workflow would stop. By adding this
# condition you can continue the execution with the populated error message.
if: always() && (steps.lint_pr_title.outputs.error_message != null)
with:
header: pr-title-lint-error
message: |
Hey there and thank you for opening this pull request! 👋🏼
We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted.
Details:
```
${{ steps.lint_pr_title.outputs.error_message }}
```
# Delete a previous comment when the issue has been resolved
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pr-title-lint-error
delete: true

47
.github/workflows/lint.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: Lint
on:
push:
branches:
- main
- release/**
pull_request:
merge_group:
permissions:
contents: read
jobs:
golangci:
name: golangci-lint
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.mk
Makefile
**/Makefile
.golangci.yml
- name: run linting (long)
if: env.GIT_DIFF
id: lint_long
run: |
make lint
- uses: technote-space/get-diff-action@v6.1.2
if: steps.lint_long.outcome == 'skipped'
with:
PATTERNS: |
**/*.go
*.go
- name: run linting (short)
if: steps.lint_long.outcome == 'skipped' && env.GIT_DIFF
run: |
make lint
env:
GIT_DIFF: ${{ env.GIT_DIFF }}
LINT_DIFF: 1

31
.github/workflows/md-link-checker.yml vendored Normal file
View file

@ -0,0 +1,31 @@
name: Check Markdown links
on:
pull_request:
paths:
- "docs/**"
jobs:
markdown-link-check:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- run: cd docs && sh ./pre.sh
- uses: gaurav-nelson/github-action-markdown-link-check@1.0.17
with:
folder-path: "docs"
- run: cd docs && sh ./post.sh
sims-notify-failure:
permissions:
contents: none
runs-on: depot-ubuntu-22.04-4
if: ${{ failure() }}
steps:
- name: Notify Slack on failure
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Broken Links
SLACK_ICON_EMOJI: ":skull:"
SLACK_COLOR: danger
SLACK_MESSAGE: Links are broken in docs
SLACK_FOOTER: ""

View file

@ -0,0 +1,52 @@
name: "Checks dependencies and mocks generation"
on:
merge_group:
pull_request:
push:
branches:
- main
concurrency:
group: ci-${{ github.ref }}-pr-go-mod-tidy-mocks
cancel-in-progress: true
jobs:
go-mod-tidy:
name: Check go mod tidy
runs-on: depot-ubuntu-22.04-4
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Run go mod tidy
run: ./scripts/go-mod-tidy-all.sh
- name: Check for diffs
run: |
git diff --exit-code || {
echo "Please run './scripts/go-mod-tidy-all.sh' and commit the changes";
exit 1;
}
generate-mocks:
name: Check up to date mocks
runs-on: depot-ubuntu-22.04-4
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Generate mocks
run: make mocks
- name: Check for diffs
run: |
git diff --exit-code || {
echo "Please run 'make mocks' and commit the changes";
exit 1;
}

18
.github/workflows/pr_labeler.yml vendored Normal file
View file

@ -0,0 +1,18 @@
name: "Pull Request Labeler"
on:
- pull_request_target
permissions:
contents: read
jobs:
labeler:
permissions:
contents: read # for actions/labeler to determine modified files
pull-requests: write # for actions/labeler to add labels to PRs
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/labeler@v4 # v5 is broken, ref https://github.com/actions/labeler/issues/712. Do not bump.
with:
configuration-path: .github/pr_labeler.yml
repo-token: "${{ secrets.GITHUB_TOKEN }}"

73
.github/workflows/proto-docker.yml vendored Normal file
View file

@ -0,0 +1,73 @@
name: Build & Push SDK Proto Builder
on:
push:
branches:
- main
paths:
- "contrib/devtools/Dockerfile"
workflow_dispatch:
inputs:
tags:
description: "Docker image tags"
required: true
type: string
pull_request:
paths:
- "contrib/devtools/Dockerfile"
env:
REGISTRY: ghcr.io
IMAGE_NAME: cosmos/proto-builder
# Allow one concurrent deployment
concurrency:
group: "proto-docker"
cancel-in-progress: true
jobs:
build:
runs-on: depot-ubuntu-22.04-4
permissions:
contents: read
packages: write
id-token: write
steps:
# set VERSION to new version when making changes, when merged to main the image will automatically be pushed
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# modify value when deploying a new version
tags: |
type=semver,pattern={{version}},value=${{ inputs.tags }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
if: ${{ github.event_name != 'pull_request' }}
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Depot
uses: depot/setup-action@v1
- name: Publish to GHCR
uses: depot/build-push-action@v1
with:
project: gnm1jqptpw
context: ./contrib/devtools
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

23
.github/workflows/proto-registry.yml vendored Normal file
View file

@ -0,0 +1,23 @@
# name: Buf Push
# Protobuf runs buf (https://buf.build/) push updated proto files to https://buf.build/cosmos/cosmos-sdk
# This workflow is only run when a .proto file has been changed
# on:
# push:
# tags:
# - "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10
# - "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+" # Push events to matching v*-rc*, i.e. v1.0-rc1, v20.15.10-rc2
# - "v[0-9]+.[0-9]+.[0-9]+-beta[0-9]+" # Push events to matching v*-beta*, i.e. v1.0-beta1, v20.15.10-beta2
# - "v[0-9]+.[0-9]+.[0-9]+-alpha[0-9]+" # Push events to matching v*-alpha*, i.e. v1.0-alpha1, v20.15.10-alpha2
# paths:
# - "proto/**"
# jobs:
# root:
# runs-on: depot-ubuntu-22.04-4
# name: "Push to buf.build/cosmos/cosmos-sdk"
# steps:
# - uses: actions/checkout@v4
# - uses: bufbuild/buf-setup-action@v1.50.0
# - run: buf push proto --tag ${{ github.ref_type == 'tag' && github.ref_name || github.sha }} # https://github.com/bufbuild/buf-push-action/issues/20
## TODO at each module tag to their own buf repository

31
.github/workflows/proto.yml vendored Normal file
View file

@ -0,0 +1,31 @@
name: Protobuf
# Protobuf runs buf (https://buf.build/) lint and check-breakage
# This workflow is only run when a .proto file has been changed
on:
pull_request:
paths:
- "proto/**"
permissions:
contents: read
jobs:
lint:
runs-on: depot-ubuntu-22.04-4
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: bufbuild/buf-setup-action@v1.50.0
- uses: bufbuild/buf-lint-action@v1
with:
input: "proto"
break-check:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: bufbuild/buf-setup-action@v1.50.0
- uses: bufbuild/buf-breaking-action@v1
with:
input: "proto"
against: "https://github.com/${{ github.repository }}.git#branch=${{ github.event.pull_request.base.ref }},ref=HEAD~1,subdir=proto"

39
.github/workflows/release-confix.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: Release Confix
on:
push:
tags:
- "tools/confix/v*.*.*"
permissions:
contents: read
jobs:
goreleaser:
permissions:
contents: write # for goreleaser/goreleaser-action to create a GitHub release
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
# get 'v*.*.*' part from 'confix/v*.*.*' and save to $GITHUB_ENV
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/confix/}" >> $GITHUB_ENV
# remove the possible pre-existing same tag for cosmos-sdk related tags instead of confix tags
# Because goreleaser enforces semantic versioning and will error on non compliant tags.(https://goreleaser.com/limitations/semver/)
- name: Tag without prefix locally to avoid error in goreleaser
run: |-
git tag -d ${{ env.RELEASE_VERSION }} || echo "No such a tag exists before"
git tag ${{ env.RELEASE_VERSION }} HEAD
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
# stick to version v0.179.0(https://github.com/cosmos/cosmos-sdk/issues/11125)
version: v0.179.0
args: release --rm-dist --skip-validate --release-notes ./RELEASE_NOTES.md
workdir: tools/confix
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: confix/${{ env.RELEASE_VERSION }}

View file

@ -0,0 +1,39 @@
name: Release Cosmovisor
on:
push:
tags:
- "tools/cosmovisor/v*.*.*"
permissions:
contents: read
jobs:
goreleaser:
permissions:
contents: write # for goreleaser/goreleaser-action to create a GitHub release
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
# get 'v*.*.*' part from 'cosmovisor/v*.*.*' and save to $GITHUB_ENV
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/cosmovisor/}" >> $GITHUB_ENV
# remove the possible pre-existing same tag for cosmos-sdk related tags instead of cosmovisor tags
# Because goreleaser enforces semantic versioning and will error on non compliant tags.(https://goreleaser.com/limitations/semver/)
- name: Tag without prefix locally to avoid error in goreleaser
run: |-
git tag -d ${{ env.RELEASE_VERSION }} || echo "No such a tag exists before"
git tag ${{ env.RELEASE_VERSION }} HEAD
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
# stick to version v0.179.0(https://github.com/cosmos/cosmos-sdk/issues/11125)
version: v0.179.0
args: release --rm-dist --skip-validate --release-notes ./RELEASE_NOTES.md
workdir: tools/cosmovisor
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: cosmovisor/${{ env.RELEASE_VERSION }}

39
.github/workflows/release-simd.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: Release Simd
on:
push:
tags:
- "simd/v*.*.*"
permissions:
contents: read
jobs:
goreleaser:
permissions:
contents: write # for goreleaser/goreleaser-action to create a GitHub release
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
# get 'v*.*.*' part from 'simd/v*.*.*' and save to $GITHUB_ENV
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/simd/}" >> $GITHUB_ENV
# remove the possible pre-existing same tag for cosmos-sdk related tags instead of simd tags
# Because goreleaser enforces semantic versioning and will error on non compliant tags.(https://goreleaser.com/limitations/semver/)
- name: Tag without prefix locally to avoid error in goreleaser
run: |-
git tag -d ${{ env.RELEASE_VERSION }} || echo "No such a tag exists before"
git tag ${{ env.RELEASE_VERSION }} HEAD
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
# stick to version v0.179.0(https://github.com/cosmos/cosmos-sdk/issues/11125)
version: v0.179.0
args: release --rm-dist --skip-validate
workdir: simapp
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: simd/${{ env.RELEASE_VERSION }}

51
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,51 @@
name: Release
# This workflow helps with creating releases.
# This job will only be triggered when a tag (vX.X.x) is pushed
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10
permissions:
contents: read
jobs:
release:
permissions:
contents: write # for goreleaser/goreleaser-action to create a GitHub release
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Unshallow
run: git fetch --prune --unshallow
- name: Create release
uses: goreleaser/goreleaser-action@v3
with:
args: release --clean --release-notes ./RELEASE_NOTES.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-success:
needs: release
if: ${{ success() }}
runs-on: depot-ubuntu-22.04-4
steps:
- name: Notify Slack on success
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: cosmos-tech
SLACK_USERNAME: Cosmos SDK Release Bot
SLACK_ICON: https://avatars.githubusercontent.com/t/5997665?size=64
SLACK_COLOR: good
SLACK_TITLE: "Cosmos SDK ${{ github.ref_name }} is tagged :tada:"
SLACK_MESSAGE: "@channel :point_right: https://github.com/cosmos/cosmos-sdk/releases/tag/${{ github.ref_name }}"
SLACK_FOOTER: ""
SLACK_LINK_NAMES: true
MSG_MINIMAL: true

145
.github/workflows/sims-047.yml vendored Normal file
View file

@ -0,0 +1,145 @@
name: Sims release/0.47.x
# Sims workflow runs multiple types of simulations (nondeterminism, import-export, after-import, multi-seed-short)
# This workflow will run on all Pull Requests, if a .go, .mod or .sum file have been changed
on:
schedule:
- cron: "0 0,12 * * *"
release:
types: [published]
concurrency:
group: ci-${{ github.ref }}-sims-047
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'skip-sims')"
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.47.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- run: make build
install-runsim:
permissions:
contents: none
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Install runsim
run: go install github.com/cosmos/tools/cmd/runsim@v1.0.0
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
test-sim-import-export:
runs-on: ubuntu-latest
needs: [build, install-runsim]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.47.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-import-export
run: |
make test-sim-import-export
test-sim-after-import:
runs-on: ubuntu-latest
needs: [build, install-runsim]
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.47.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-after-import
run: |
make test-sim-after-import
test-sim-multi-seed-short:
runs-on: ubuntu-latest
needs: [build, install-runsim]
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.47.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-multi-seed-short
run: |
make test-sim-multi-seed-short
sims-notify-success:
needs:
[test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export]
runs-on: ubuntu-latest
if: ${{ success() }}
steps:
- uses: actions/checkout@v4
- name: Get previous workflow status
uses: ./.github/actions/last-workflow-status
id: last_status
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Notify Slack on success
if: ${{ steps.last_status.outputs.last_status == 'failure' }}
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests release/0.47.x
SLACK_ICON_EMOJI: ":white_check_mark:"
SLACK_COLOR: good
SLACK_MESSAGE: 0.47.x Sims are passing
SLACK_FOOTER: ""
sims-notify-failure:
permissions:
contents: none
needs:
[test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export]
runs-on: ubuntu-latest
if: ${{ failure() }}
steps:
- name: Notify Slack on failure
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests release/0.47.x
SLACK_ICON_EMOJI: ":skull:"
SLACK_COLOR: danger
SLACK_MESSAGE: 0.47.x Sims are failing
SLACK_FOOTER: ""

148
.github/workflows/sims-050.yml vendored Normal file
View file

@ -0,0 +1,148 @@
name: Sims release/0.50.x
# Sims workflow runs multiple types of simulations (nondeterminism, import-export, after-import, multi-seed-short)
# This workflow will run on all Pull Requests, if a .go, .mod or .sum file have been changed
# TODO - update to 53 once we have cut release
on:
schedule:
- cron: "0 0,12 * * *"
release:
types: [published]
concurrency:
group: ci-${{ github.ref }}-sims-050
cancel-in-progress: true
jobs:
build:
runs-on: depot-ubuntu-22.04-4
if: "!contains(github.event.head_commit.message, 'skip-sims')"
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.50.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- run: make build
install-runsim:
permissions:
contents: none
runs-on: depot-ubuntu-22.04-4
needs: build
steps:
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Install runsim
run: go install github.com/cosmos/tools/cmd/runsim@v1.0.0
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
test-sim-import-export:
runs-on: depot-ubuntu-22.04-4
needs: [build, install-runsim]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.50.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-import-export
run: |
make test-sim-import-export
test-sim-after-import:
runs-on: depot-ubuntu-22.04-4
needs: [build, install-runsim]
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.50.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-after-import
run: |
make test-sim-after-import
test-sim-multi-seed-short:
runs-on: depot-ubuntu-22.04-4
needs: [build, install-runsim]
steps:
- uses: actions/checkout@v4
with:
ref: "release/v0.50.x"
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- uses: actions/cache@v4
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-multi-seed-short
run: |
make test-sim-multi-seed-short
sims-notify-success:
needs:
[test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export]
runs-on: depot-ubuntu-22.04-4
if: ${{ success() }}
steps:
- uses: actions/checkout@v4
- name: Get previous workflow status
uses: ./.github/actions/last-workflow-status
id: last_status
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Notify Slack on success
if: ${{ steps.last_status.outputs.last_status == 'failure' }}
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests release/0.50.x
SLACK_ICON_EMOJI: ":white_check_mark:"
SLACK_COLOR: good
SLACK_MESSAGE: 0.50.x Sims are passing
SLACK_FOOTER: ""
sims-notify-failure:
permissions:
contents: none
needs:
[test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export]
runs-on: depot-ubuntu-22.04-4
if: ${{ failure() }}
steps:
- name: Notify Slack on failure
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests release/0.50.x
SLACK_ICON_EMOJI: ":skull:"
SLACK_COLOR: danger
SLACK_MESSAGE: 0.50.x Sims are failing
SLACK_FOOTER: ""

88
.github/workflows/sims-nightly.yml vendored Normal file
View file

@ -0,0 +1,88 @@
name: Sims Nightly (Long)
# Release Sims workflow runs long-lived (multi-seed & large block size) simulations
# This workflow only runs mightly at 8am UTC and on releases
on:
schedule:
- cron: "0 8 * * *"
release:
types: [published]
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}-sims-nightly-long
cancel-in-progress: true
jobs:
test-sim-multi-seed-long:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: test-sim-multi-seed-long
env:
GOMEMLIMIT: 14GiB # reserve 2 GiB as buffer for GC to avoid OOM
run: |
make test-sim-multi-seed-long
test-sim-import-export:
runs-on: depot-ubuntu-22.04-4
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: test-sim-import-export
env:
GOMEMLIMIT: 14GiB # reserve 2 GiB as buffer for GC to avoid OOM
run: |
make test-sim-import-export
sims-notify-success:
needs: [test-sim-multi-seed-long, test-sim-import-export]
runs-on: depot-ubuntu-22.04-4
if: ${{ success() }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Get previous workflow status
uses: ./.github/actions/last-workflow-status
id: last_status
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Notify Slack on success
if: ${{ steps.last_status.outputs.last_status == 'failure' }}
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests
SLACK_ICON_EMOJI: ":white_check_mark:"
SLACK_COLOR: good
SLACK_MESSAGE: Sims Nightly (Long) are passing
SLACK_FOOTER: ""
sims-notify-failure:
permissions:
contents: none
needs: [test-sim-multi-seed-long]
runs-on: depot-ubuntu-22.04-4
if: ${{ failure() }}
steps:
- name: Notify Slack on failure
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests
SLACK_ICON_EMOJI: ":skull:"
SLACK_COLOR: danger
SLACK_MESSAGE: Sims Nightly (Long) are failing
SLACK_FOOTER: ""

82
.github/workflows/sims.yml vendored Normal file
View file

@ -0,0 +1,82 @@
name: Sims
# Sims workflow runs multiple types of simulations (nondeterminism, import-export, after-import, multi-seed-short)
# This workflow will run on all Pull Requests, if a .go, .mod or .sum file have been changed
on:
schedule:
- cron: "0 */2 * * *"
release:
types: [published]
concurrency:
group: ci-${{ github.ref }}-sims
cancel-in-progress: true
jobs:
build:
permissions:
contents: read # for actions/checkout to fetch code
runs-on: depot-ubuntu-22.04-16
if: "!contains(github.event.head_commit.message, 'skip-sims')"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- run: make build
test-sim-import-export:
runs-on: depot-ubuntu-22.04-16
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: test-sim-import-export
run: |
make test-sim-import-export
test-sim-after-import:
runs-on: depot-ubuntu-22.04-16
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: test-sim-after-import
run: |
make test-sim-after-import
test-sim-deterministic:
runs-on: depot-ubuntu-22.04-16
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: test-sim-nondeterminism-streaming
run: |
make test-sim-nondeterminism-streaming
test-sim-multi-seed-short:
runs-on: depot-ubuntu-22.04-16
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: test-sim-multi-seed-short
run: |
make test-sim-multi-seed-short

63
.github/workflows/systemtests.yml vendored Normal file
View file

@ -0,0 +1,63 @@
name: System Tests
on:
pull_request:
merge_group:
push:
branches:
- main
- release/v0.53.x
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}-system-tests
cancel-in-progress: true
jobs:
setup:
runs-on: depot-ubuntu-22.04-4
outputs:
git_diff: ${{ steps.git_diff.outputs.diff }}
steps:
- uses: actions/checkout@v4
with:
fetch-tags: true
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: |
./go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
test-system:
needs: setup
if: needs.setup.outputs.git_diff
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- name: Run system tests
run: |
make test-system
test-system-legacy:
needs: setup
if: needs.setup.outputs.git_diff
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- name: Run legacy system tests
run: |
COSMOS_BUILD_OPTIONS=legacy make test-system

640
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,640 @@
name: Tests / Code Coverage
on:
pull_request:
merge_group:
push:
branches:
- main
permissions:
contents: write
pull-requests: write
concurrency:
group: ci-${{ github.ref }}-tests
cancel-in-progress: true
jobs:
split-test-files:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
- name: Create a file with all core Cosmos SDK pkgs
run: go list ./... > pkgs.txt
- name: Split pkgs into 4 files
run: split -d -n l/4 pkgs.txt pkgs.txt.part.
- uses: actions/upload-artifact@v4
with:
name: "${{ github.sha }}-00"
path: ./pkgs.txt.part.00
- uses: actions/upload-artifact@v4
with:
name: "${{ github.sha }}-01"
path: ./pkgs.txt.part.01
- uses: actions/upload-artifact@v4
with:
name: "${{ github.sha }}-02"
path: ./pkgs.txt.part.02
- uses: actions/upload-artifact@v4
with:
name: "${{ github.sha }}-03"
path: ./pkgs.txt.part.03
tests:
runs-on: depot-ubuntu-22.04-4
needs: split-test-files
strategy:
fail-fast: false
matrix:
part: ["00", "01", "02", "03"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
- uses: actions/download-artifact@v4
with:
name: "${{ github.sha }}-${{ matrix.part }}"
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -race -timeout 30m -coverprofile=${{ matrix.part }}profile.out -covermode=atomic -tags='ledger test_ledger_mock'
- uses: actions/upload-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-${{ matrix.part }}-coverage"
path: ./${{ matrix.part }}profile.out
test-integration:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
- name: integration tests
if: env.GIT_DIFF
run: |
make test-integration-cov
- uses: actions/upload-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-integration-coverage"
path: ./tests/integration-profile.out
test-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.21"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
- name: e2e tests
if: env.GIT_DIFF
run: |
make test-e2e-cov
- uses: actions/upload-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-e2e-coverage"
path: ./tests/e2e-profile.out
repo-analysis:
runs-on: depot-ubuntu-22.04-4
needs: [tests, test-integration, test-e2e]
steps:
- uses: actions/checkout@v4
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-00-coverage"
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-01-coverage"
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-02-coverage"
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-03-coverage"
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-integration-coverage"
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-e2e-coverage"
continue-on-error: true
test-sim-nondeterminism:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
- name: test-sim-nondeterminism
if: env.GIT_DIFF
run: |
make test-sim-nondeterminism
###############################
#### Cosmos SDK Submodules ####
###############################
# NOTE: The following jobs are used to test the Cosmos SDK Go submodules.
# They run when there is a diff in their respective directories.
test-clientv2:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: client/v2/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
client/v2/**/*.go
client/v2/go.mod
client/v2/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd client/v2
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-core:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: core/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
core/**/*.go
core/go.mod
core/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd core
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-depinject:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
check-latest: false
cache: true
cache-dependency-path: depinject/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
depinject/**/*.go
depinject/go.mod
depinject/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd depinject
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-errors:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
check-latest: true
cache: true
cache-dependency-path: errors/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
errors/**/*.go
errors/go.mod
errors/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd errors
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-math:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
check-latest: true
cache: true
cache-dependency-path: math/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
math/**/*.go
math/go.mod
math/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd math
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-schema:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.12"
cache: true
cache-dependency-path: schema/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
schema/**/*.go
schema/go.mod
schema/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd schema
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-collections:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: collections/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
collections/**/*.go
collections/go.mod
collections/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd collections
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-cosmovisor:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: tools/cosmovisor/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
tools/cosmovisor/**/*.go
tools/cosmovisor/go.mod
tools/cosmovisor/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd tools/cosmovisor
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-confix:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: tools/confix/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
tools/confix/**/*.go
tools/confix/go.mod
tools/confix/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd tools/confix
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-store:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: store/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
store/**/*.go
store/go.mod
store/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd store
(cd streaming/abci/examples/file && go build .)
go test -ldflags "-r /usr/local/lib" -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-log:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.21"
check-latest: true
cache: true
cache-dependency-path: log/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
log/*.go
log/go.mod
log/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd log
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
#############################
### Cosmos SDK x/{module} ###
#############################
# NOTE: The following jobs are used to test the Cosmos SDK Go submodules present under x/{module}.
# They run when there is a diff in their respective directories.
test-x-tx:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: x/tx/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
x/tx/**/*.go
x/tx/go.mod
x/tx/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd x/tx
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-x-nft:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: x/nft/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
x/nft/**/*.go
x/nft/go.mod
x/nft/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd x/nft
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-x-circuit:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: x/circuit/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
x/circuit/**/*.go
x/circuit/go.mod
x/circuit/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd x/circuit
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-x-feegrant:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: x/feegrant/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
x/feegrant/**/*.go
x/feegrant/go.mod
x/feegrant/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd x/feegrant
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-x-evidence:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: x/evidence/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
x/evidence/**/*.go
x/evidence/go.mod
x/evidence/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd x/evidence
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-x-upgrade:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: x/upgrade/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
x/upgrade/**/*.go
x/upgrade/go.mod
x/upgrade/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd x/upgrade
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
test-tools-benchmark:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23.2"
check-latest: true
cache: true
cache-dependency-path: tools/benchmark/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
tools/benchmark/**/*.go
tools/benchmark/go.mod
tools/benchmark/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd tools/benchmark
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace' ./...

67
.gitignore vendored Normal file
View file

@ -0,0 +1,67 @@
# OS
.DS_Store
*.swp
*.swo
*.swl
*.swm
*.swn
*.pyc
# private files
private[.-]*
private
# Build
vendor
build
dist
tools-stamp
buf-stamp
artifacts
simapp/simd/simd
# Go
go.work
go.work.sum
# Data - ideally these don't exist
baseapp/data/*
client/lcd/keys/*
.testnets
# Testing
coverage.out
coverage.txt
*profile.out
sim_log_file
x/genutil/config
x/genutil/data
*.fail
# Vagrant
.vagrant/
*.box
*.log
vagrant
# IDE
.idea
*.iml
*.ipr
*.iws
.dir-locals.el
.vscode
.venv
# Depinject & Graphviz
dependency-graph.png
debug_container.dot
debug_container.log
# Latex
*.aux
*.out
*.synctex.gz
/x/genutil/config/priv_validator_key.json
/x/genutil/data/priv_validator_state.json

1
.gitpod.yml Normal file
View file

@ -0,0 +1 @@
image: ghcr.io/notional-labs/cosmos

144
.golangci.yml Normal file
View file

@ -0,0 +1,144 @@
version: "2"
run:
build-tags:
- e2e
- ledger
- test_ledger_mock
- sims
tests: true
allow-parallel-runners: true
linters:
default: none
enable:
- copyloopvar
- dogsled
- errcheck
- errorlint
- goconst
- gocritic
- gosec
- govet
- ineffassign
- misspell
- nakedret
- nolintlint
- revive
- staticcheck
- thelper
- unconvert
- unused
settings:
dogsled:
max-blank-identifiers: 6
gocritic:
disabled-checks:
- regexpMust
- appendAssign
- ifElseChain
gosec:
excludes:
- G101
- G107
- G404
confidence: medium
misspell:
locale: US
nolintlint:
require-explanation: true
require-specific: false
allow-unused: false
revive:
rules:
- name: redefines-builtin-id
disabled: true
staticcheck:
checks:
- all
unused:
local-variables-are-used: false
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- staticcheck
text: 'ST1003:'
- linters:
- staticcheck
text: 'ST1016:'
- linters:
- staticcheck
path: migrations
text: 'SA1019:'
- linters:
- staticcheck
text: 'SA1019: codec.NewAminoCodec is deprecated'
- linters:
- staticcheck
text: 'SA1019: legacybech32.MustMarshalPubKey'
- linters:
- staticcheck
text: 'SA1019: legacybech32.MarshalPubKey'
- linters:
- staticcheck
text: 'SA1019: legacybech32.UnmarshalPubKey'
- linters:
- staticcheck
text: 'SA1019: params.SendEnabled is deprecated'
- linters:
- gosec
text: 'G115: integer overflow conversion'
- linters:
- nolintlint
text: leading space
paths:
- server/grpc/gogoreflection/fix_registration.go
- fix_registration.go
- .*\.pb\.go$
- .*\.pb\.gw\.go$
- .*\.pulsar\.go$
- crypto/keys/secp256k1/internal/*
- types/coin_regex.go
- testutil/testdata
- x/params
- x/crisis
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 10000
max-same-issues: 10000
formatters:
enable:
- gci
- gofumpt
settings:
gci:
sections:
- standard
- default
- prefix(cosmossdk.io)
- prefix(github.com/cosmos/cosmos-sdk)
custom-order: true
gofumpt:
extra-rules: true
exclusions:
generated: lax
paths:
- server/grpc/gogoreflection/fix_registration.go
- fix_registration.go
- .*\.pb\.go$
- .*\.pb\.gw\.go$
- .*\.pulsar\.go$
- crypto/keys/secp256k1/internal/*
- types/coin_regex.go
- testutil/testdata
- x/params
- x/crisis
- third_party$
- builtin$
- examples$

27
.goreleaser.yml Normal file
View file

@ -0,0 +1,27 @@
---
project_name: cosmos-sdk
release:
github:
owner: cosmos
name: cosmos-sdk
builds:
- skip: true
archives:
- format: tar.gz
wrap_in_directory: true
format_overrides:
- goos: windows
format: zip
name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
files:
- LICENSE
- README.md
snapshot:
name_template: SNAPSHOT-{{ .Commit }}
changelog:
disable: false

12
.markdownlint.json Normal file
View file

@ -0,0 +1,12 @@
{
"default": true,
"MD004": {"style": "asterisk"},
"MD007": { "indent": 4 },
"MD013": false,
"MD024": { "siblings_only": true },
"MD025": false,
"MD033": false,
"MD034": false,
"no-hard-tabs": false,
"whitespace": false
}

2
.markdownlintignore Normal file
View file

@ -0,0 +1,2 @@
docs/node_modules
/README.md

58
.mergify.yml Normal file
View file

@ -0,0 +1,58 @@
queue_rules:
- name: default
queue_conditions:
- "#approved-reviews-by>1"
- base=main
- label=A:automerge
merge_conditions:
- "#approved-reviews-by>1"
commit_message_template: |
{{ title }} (#{{ number }})
{{ body }}
merge_method: squash
pull_request_rules:
- name: backport patches to v0.53.x branch
conditions:
- base=main
- label=backport/v0.53.x
actions:
backport:
branches:
- release/v0.53.x
- name: backport patches to v0.50.x branch
conditions:
- base=main
- label=backport/v0.50.x
actions:
backport:
branches:
- release/v0.50.x
- name: backport patches to v0.47.x branch
conditions:
- base=main
- label=backport/v0.47.x
actions:
backport:
branches:
- release/v0.47.x
- name: backport patches to v0.46.x branch
conditions:
- base=main
- label=backport/0.46.x
actions:
backport:
branches:
- release/v0.46.x
- name: backport patches to v0.45.x branch
conditions:
- base=main
- label=backport/0.45.x
actions:
backport:
branches:
- release/v0.45.x
- name: automerge to main with label automerge and branch protection passing
conditions: []
actions:
queue:

736
CHANGELOG.md Normal file
View file

@ -0,0 +1,736 @@
<!--
Guiding Principles:
Changelogs are for humans, not machines.
There should be an entry for every single version.
The same types of changes should be grouped.
Versions and sections should be linkable.
The latest version comes first.
The release date of each version is displayed.
Mention whether you follow Semantic Versioning.
Usage:
Change log entries are to be added to the Unreleased section under the
appropriate stanza (see below). Each entry is required to include a tag and
the Github issue reference in the following format:
* (<tag>) \#<issue-number> message
The tag should consist of where the change is being made ex. (x/staking), (store)
The issue numbers will later be link-ified during the release process so you do
not have to worry about including a link manually, but you can if you wish.
Types of changes (Stanzas):
"Features" for new features.
"Improvements" for changes in existing functionality.
"Deprecated" for soon-to-be removed features.
"Bug Fixes" for any bug fixes.
"Client Breaking" for breaking Protobuf, gRPC and REST routes used by end-users.
"CLI Breaking" for breaking CLI commands.
"API Breaking" for breaking exported APIs used by developers building on SDK.
"State Machine Breaking" for any changes that result in a different AppState given same genesisState and txList.
Ref: https://keepachangelog.com/en/1.0.0/
-->
# Changelog
## [v0.53.6](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.6) - 2026-02-10
### Improvements
* (deps) [#25710](https://github.com/cosmos/cosmos-sdk/pull/25710) Bump github.com/cosmos/ledger-cosmos-go from 0.16.0 to 1.0.0
* (deps) [#25820](https://github.com/cosmos/cosmos-sdk/pull/25820) Bump github.com/cometbft/cometbft from 0.80.20 to 0.38.21
### Bug Fixes
* (x/auth) [#25871](https://github.com/cosmos/cosmos-sdk/pull/25871) Limits pagination at default for values that exceed it.
* (events) [#25881](https://github.com/cosmos/cosmos-sdk/pull/25881) Add `OverrideEvents` to `EventManagerI`.
## [v0.53.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.5) - 2025-12-12
### Features
* (crypto/ledger) [#25435](https://github.com/cosmos/cosmos-sdk/pull/25435) Add SetDERConversion to reset skipDERConversion and App name for ledger.
* (gRPC) [#25565](https://github.com/cosmos/cosmos-sdk/pull/25565) Support for multi gRPC query clients serve with historical binaries to serve proper historical state.
* (blockstm) [#25600](https://github.com/cosmos/cosmos-sdk/pull/25600) Allow dynamic retrieval of the coin denomination from multi store at runtime.
* [#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Support automatic configuration of OpenTelemetry via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf) and add OpenTelemetry instrumentation of `BaseApp`.
### Improvements
* (x/mint) [#25562](https://github.com/cosmos/cosmos-sdk/pull/25562) Improve and test `x/mint` params validation.
* (server) [#25632](https://github.com/cosmos/cosmos-sdk/pull/25632) Add missing call to close the app on shutdown.
### Bug Fixes
* (cli) [#25485](https://github.com/cosmos/cosmos-sdk/pull/25485) Avoid failed to convert address field in `withdraw-validator-commission` cmd.
* (baseapp) [#25642](https://github.com/cosmos/cosmos-sdk/pull/25642) Mark pre-block events for indexing based on local configuration.
### Deprecated
* (x/nft) [#24575](https://github.com/cosmos/cosmos-sdk/pull/24575) Deprecate the `x/nft` module in the Cosmos SDK repository. This module will not be maintained to the extent that our core modules will and will be kept in a [legacy repo](https://github.com/cosmos/cosmos-legacy).
* (x/group) [#24571](https://github.com/cosmos/cosmos-sdk/pull/24571) Deprecate the `x/group` module in the Cosmos SDK repository. This module will not be maintained to the extent that our core modules will and will be kept in a [legacy repo](https://github.com/cosmos/cosmos-legacy).
* (types) [#24664](https://github.com/cosmos/cosmos-sdk/pull/24664) Deprecate the `Invariant` type in the Cosmos SDK.
* [#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Deprecate all existing methods and types in the `telemetry` package, usage of `github.com/hashicorp/go-metrics` and the `telemetry` configuration section. New instrumentation should use the official [OpenTelemetry go API](https://pkg.go.dev/go.opentelemetry.io/otel) and Cosmos SDK appllications can automatically expose OpenTelemetry metrics, traces and logs via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf).
## [v0.53.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.3) - 2025-07-25
This patch update also includes minor dependency bumps.
### Features
* (abci_utils) [#25008](https://github.com/cosmos/cosmos-sdk/pull/24861) add the ability to assign a custom signer extraction adapter in `DefaultProposalHandler`.
## [v0.53.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.3) - 2025-07-08
### Bug Fixes
* [GHSA-p22h-3m2v-cmgh](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-p22h-3m2v-cmgh) Fix x/distribution can halt when historical rewards overflow.
## [v0.53.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.2) - 2025-06-02
This patch update also includes minor dependency bumps.
### Bug Fixes
* (x/epochs) [#24770](https://github.com/cosmos/cosmos-sdk/pull/24770) Fix register of epoch hooks in `InvokeSetHooks`.
## [v0.53.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.0) - 2025-04-29
### Features
* (simsx) [#24062](https://github.com/cosmos/cosmos-sdk/pull/24062) [#24145](https://github.com/cosmos/cosmos-sdk/pull/24145) Add new simsx framework on top of simulations for better module dev experience.
* (baseapp) [#24069](https://github.com/cosmos/cosmos-sdk/pull/24069) Create CheckTxHandler to allow extending the logic of CheckTx.
* (types) [#24093](https://github.com/cosmos/cosmos-sdk/pull/24093) Added a new method, `IsGT`, for `types.Coin`. This method is used to check if a `types.Coin` is greater than another `types.Coin`.
* (client/keys) [#24071](https://github.com/cosmos/cosmos-sdk/pull/24071) Add support for importing hex key using standard input.
* (types) [#23780](https://github.com/cosmos/cosmos-sdk/pull/23780) Add a ValueCodec for the math.Uint type that can be used in collections maps.
* (perf)[#24045](https://github.com/cosmos/cosmos-sdk/pull/24045) Sims: Replace runsim command with Go stdlib testing. CLI: `Commit` default true, `Lean`, `SimulateEveryOperation`, `PrintAllInvariants`, `DBBackend` params removed
* (crypto/keyring) [#24040](https://github.com/cosmos/cosmos-sdk/pull/24040) Expose the db keyring used in the keystore.
* (types) [#23919](https://github.com/cosmos/cosmos-sdk/pull/23919) Add MustValAddressFromBech32 function.
* (all) [#23708](https://github.com/cosmos/cosmos-sdk/pull/23708) Add unordered transaction support.
* Adds a `--timeout-timestamp` flag that allows users to specify a block time at which the unordered transactions should expire from the mempool.
* (x/epochs) [#23815](https://github.com/cosmos/cosmos-sdk/pull/23815) Upstream `x/epochs` from Osmosis
* (client) [#23811](https://github.com/cosmos/cosmos-sdk/pull/23811) Add auto cli for node service.
* (genutil) [#24018](https://github.com/cosmos/cosmos-sdk/pull/24018) Allow manually setting the consensus key type in genesis
* (client) [#18557](https://github.com/cosmos/cosmos-sdk/pull/18557) Add `--qrcode` flag to `keys show` command to support displaying keys address QR code.
* (x/auth) [#24030](https://github.com/cosmos/cosmos-sdk/pull/24030) Allow usage of ed25519 keys for transaction signing.
* (baseapp) [#24163](https://github.com/cosmos/cosmos-sdk/pull/24163) Add `StreamingManager` to baseapp to extend the abci listeners.
* (x/protocolpool) [#23933](https://github.com/cosmos/cosmos-sdk/pull/23933) Add x/protocolpool module.
* x/distribution can now utilize an externally managed community pool. NOTE: this will make the message handlers for FundCommunityPool and CommunityPoolSpend error, as well as the query handler for CommunityPool.
* (client) [#18101](https://github.com/cosmos/cosmos-sdk/pull/18101) Add a `keyring-default-keyname` in `client.toml` for specifying a default key name, and skip the need to use the `--from` flag when signing transactions.
* (x/gov) [#24355](https://github.com/cosmos/cosmos-sdk/pull/24355) Allow users to set a custom CalculateVoteResultsAndVotingPower function to be used in govkeeper.Tally.
* (x/mint) [#24436](https://github.com/cosmos/cosmos-sdk/pull/24436) Allow users to set a custom minting function used in the `x/mint` begin blocker.
* The `InflationCalculationFn` argument to `mint.NewAppModule()` is now ignored and must be nil. To set a custom `InflationCalculationFn` on the default minter, use `mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(customInflationFn))`.
* (api) [#24428](https://github.com/cosmos/cosmos-sdk/pull/24428) Add block height to response headers
### Improvements
* (client) [#24561](https://github.com/cosmos/cosmos-sdk/pull/24561) TimeoutTimestamp flag has been changed to TimeoutDuration, which now sets the timeout timestamp of unordered transactions to the current time + duration passed.
* (telemetry) [#24541](https://github.com/cosmos/cosmos-sdk/pull/24541) Telemetry now includes a pre_blocker metric key. x/upgrade should migrate to this key in v0.54.0.
* (x/auth) [#24541](https://github.com/cosmos/cosmos-sdk/pull/24541) x/auth's PreBlocker now emits telemetry under the pre_blocker metric key.
* (x/bank) [#24431](https://github.com/cosmos/cosmos-sdk/pull/24431) Reduce the number of `ValidateDenom` calls in `bank.SendCoins` and `Coin`.
* The `AmountOf()` method on`sdk.Coins` no longer will `panic` if given an invalid denom and will instead return a zero value.
* (x/staking) [#24391](https://github.com/cosmos/cosmos-sdk/pull/24391) Replace panics with error results; more verbose error messages
* (x/staking) [#24354](https://github.com/cosmos/cosmos-sdk/pull/24354) Optimize validator endblock by reducing bech32 conversions, resulting in significant performance improvement
* (client/keys) [#18950](https://github.com/cosmos/cosmos-sdk/pull/18950) Improve `<appd> keys add`, `<appd> keys import` and `<appd> keys rename` by checking name validation.
* (client/keys) [#18703](https://github.com/cosmos/cosmos-sdk/pull/18703) Improve `<appd> keys add` and `<appd> keys show` by checking whether there are duplicate keys in the multisig case.
* (client/keys) [#18745](https://github.com/cosmos/cosmos-sdk/pull/18745) Improve `<appd> keys export` and `<appd> keys mnemonic` by adding --yes option to skip interactive confirmation.
* (x/bank) [#24106](https://github.com/cosmos/cosmos-sdk/pull/24106) `SendCoins` now checks for `SendRestrictions` before instead of after deducting coins using `subUnlockedCoins`.
* (crypto/ledger) [#24036](https://github.com/cosmos/cosmos-sdk/pull/24036) Improve error message when deriving paths using index > 100
* (gRPC) [#23844](https://github.com/cosmos/cosmos-sdk/pull/23844) Add debug log prints for each gRPC request.
* (gRPC) [#24073](https://github.com/cosmos/cosmos-sdk/pull/24073) Adds error handling for out-of-gas panics in grpc query handlers.
* (server) [#24072](https://github.com/cosmos/cosmos-sdk/pull/24072) Return BlockHeader by shallow copy in server Context.
* (x/bank) [#24053](https://github.com/cosmos/cosmos-sdk/pull/24053) Resolve a foot-gun by swapping send restrictions check in `InputOutputCoins` before coin deduction.
* (codec/types) [#24336](https://github.com/cosmos/cosmos-sdk/pull/24336) Most types definitions were moved to `github.com/cosmos/gogoproto/types/any` with aliases to these left in `codec/types` so that there should be no breakage to existing code. This allows protobuf generated code to optionally reference the SDK's custom `Any` type without a direct dependency on the SDK. This can be done by changing the `protoc` `M` parameter for `any.proto` to `Mgoogle/protobuf/any.proto=github.com/cosmos/gogoproto/types/any`.
### Bug Fixes
* (x/gov)[#24460](https://github.com/cosmos/cosmos-sdk/pull/24460) Do not call Remove during Walk in defaultCalculateVoteResultsAndVotingPower.
* (baseapp) [24261](https://github.com/cosmos/cosmos-sdk/pull/24261) Fix post handler error always results in code 1
* (server) [#24068](https://github.com/cosmos/cosmos-sdk/pull/24068) Allow align block header with skip check header in grpc server.
* (x/gov) [#24044](https://github.com/cosmos/cosmos-sdk/pull/24044) Fix some places in which we call Remove inside a Walk (x/gov).
* (baseapp) [#24042](https://github.com/cosmos/cosmos-sdk/pull/24042) Fixed a data race inside BaseApp.getContext, found by end-to-end (e2e) tests.
* (client/server) [#24059](https://github.com/cosmos/cosmos-sdk/pull/24059) Consistently set viper prefix in client and server. It defaults for the binary name for both client and server.
* (client/keys) [#24041](https://github.com/cosmos/cosmos-sdk/pull/24041) `keys delete` won't terminate when a key is not found, but will log the error.
* (baseapp) [#24027](https://github.com/cosmos/cosmos-sdk/pull/24027) Ensure that `BaseApp.Init` checks that the commit multistore is set to protect against nil dereferences.
* (x/group) [GHSA-47ww-ff84-4jrg](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-47ww-ff84-4jrg) Fix x/group can halt when erroring in EndBlocker
* (x/distribution) [#23934](https://github.com/cosmos/cosmos-sdk/pull/23934) Fix vulnerability in `incrementReferenceCount` in distribution.
* (baseapp) [#23879](https://github.com/cosmos/cosmos-sdk/pull/23879) Ensure finalize block response is not empty in the defer check of FinalizeBlock to avoid panic by nil pointer.
* (query) [#23883](https://github.com/cosmos/cosmos-sdk/pull/23883) Fix NPE in query pagination.
* (client) [#23860](https://github.com/cosmos/cosmos-sdk/pull/23860) Add missing `unordered` field for legacy amino signing of tx body.
* (x/bank) [#23836](https://github.com/cosmos/cosmos-sdk/pull/23836) Fix `DenomMetadata` rpc allow value with slashes.
* (query) [87d3a43](https://github.com/cosmos/cosmos-sdk/commit/87d3a432af95f4cf96aa02351ed5fcc51cca6e7b) Fix collection filtered pagination.
* (sims) [#23952](https://github.com/cosmos/cosmos-sdk/pull/23952) Use liveness matrix for validator sign status in sims
* (baseapp) [#24055](https://github.com/cosmos/cosmos-sdk/pull/24055) Align block header when query with latest height.
* (baseapp) [#24074](https://github.com/cosmos/cosmos-sdk/pull/24074) Use CometBFT's ComputeProtoSizeForTxs in defaultTxSelector.SelectTxForProposal for consistency.
* (cli) [#24090](https://github.com/cosmos/cosmos-sdk/pull/24090) Prune cmd should disable async pruning.
* (x/auth) [#19239](https://github.com/cosmos/cosmos-sdk/pull/19239) Sets from flag in multi-sign command to avoid no key name provided error.
* (x/auth) [#23741](https://github.com/cosmos/cosmos-sdk/pull/23741) Support legacy global AccountNumber for legacy compatibility.
* (baseapp) [#24526](https://github.com/cosmos/cosmos-sdk/pull/24526) Fix incorrect retention height when `commitHeight` equals `minRetainBlocks`.
* (x/protocolpool) [#24594](https://github.com/cosmos/cosmos-sdk/pull/24594) Fix NPE when initializing module via depinject.
* (x/epochs) [#24610](https://github.com/cosmos/cosmos-sdk/pull/24610) Fix semantics of `CurrentEpochStartHeight` being set before epoch has started.
## [v0.50.13](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.13) - 2025-03-12
### Bug Fixes
* [GHSA-47ww-ff84-4jrg](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-47ww-ff84-4jrg) Fix x/group can halt when erroring in EndBlocker
## [v0.50.12](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.12) - 2025-02-20
### Bug Fixes
* [GHSA-x5vx-95h7-rv4p](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-x5vx-95h7-rv4p) Fix Group module can halt chain when handling a malicious proposal.
## [v0.50.11](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.11) - 2024-12-16
### Features
* (crypto/keyring) [#21653](https://github.com/cosmos/cosmos-sdk/pull/21653) New Linux-only backend that adds Linux kernel's `keyctl` support.
### Improvements
* (server) [#21941](https://github.com/cosmos/cosmos-sdk/pull/21941) Regenerate addrbook.json for in place testnet.
### Bug Fixes
* Fix [ABS-0043/ABS-0044](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-8wcc-m6j2-qxvm) Limit recursion depth for unknown field detection and unpack any
* (server) [#22564](https://github.com/cosmos/cosmos-sdk/pull/22564) Fix fallback genesis path in server
* (x/group) [#22425](https://github.com/cosmos/cosmos-sdk/pull/22425) Proper address rendering in error
* (sims) [#21906](https://github.com/cosmos/cosmos-sdk/pull/21906) Skip sims test when running dry on validators
* (cli) [#21919](https://github.com/cosmos/cosmos-sdk/pull/21919) Query address-by-acc-num by account_id instead of id.
* (x/group) [#22229](https://github.com/cosmos/cosmos-sdk/pull/22229) Accept `1` and `try` in CLI for group proposal exec.
## [v0.50.10](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.10) - 2024-09-20
### Features
* (cli) [#20779](https://github.com/cosmos/cosmos-sdk/pull/20779) Added `module-hash-by-height` command to query and retrieve module hashes at a specified blockchain height, enhancing debugging capabilities.
* (cli) [#21372](https://github.com/cosmos/cosmos-sdk/pull/21372) Added a `bulk-add-genesis-account` genesis command to add many genesis accounts at once.
* (types/collections) [#21724](https://github.com/cosmos/cosmos-sdk/pull/21724) Added `LegacyDec` collection value.
### Improvements
* (x/bank) [#21460](https://github.com/cosmos/cosmos-sdk/pull/21460) Added `Sender` attribute in `MsgMultiSend` event.
* (genutil) [#21701](https://github.com/cosmos/cosmos-sdk/pull/21701) Improved error messages for genesis validation.
* (testutil/integration) [#21816](https://github.com/cosmos/cosmos-sdk/pull/21816) Allow to pass baseapp options in `NewIntegrationApp`.
### Bug Fixes
* (runtime) [#21769](https://github.com/cosmos/cosmos-sdk/pull/21769) Fix baseapp options ordering to avoid overwriting options set by modules.
* (x/consensus) [#21493](https://github.com/cosmos/cosmos-sdk/pull/21493) Fix regression that prevented to upgrade to > v0.50.7 without consensus version params.
* (baseapp) [#21256](https://github.com/cosmos/cosmos-sdk/pull/21256) Halt height will not commit the block indicated, meaning that if halt-height is set to 10, only blocks until 9 (included) will be committed. This is to go back to the original behavior before a change was introduced in v0.50.0.
* (baseapp) [#21444](https://github.com/cosmos/cosmos-sdk/pull/21444) Follow-up, Return PreBlocker events in FinalizeBlockResponse.
* (baseapp) [#21413](https://github.com/cosmos/cosmos-sdk/pull/21413) Fix data race in sdk mempool.
## [v0.50.9](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.9) - 2024-08-07
## Bug Fixes
* (baseapp) [#21159](https://github.com/cosmos/cosmos-sdk/pull/21159) Return PreBlocker events in FinalizeBlockResponse.
* [#20939](https://github.com/cosmos/cosmos-sdk/pull/20939) Fix collection reverse iterator to include `pagination.key` in the result.
* (client/grpc) [#20969](https://github.com/cosmos/cosmos-sdk/pull/20969) Fix `node.NewQueryServer` method not setting `cfg`.
* (testutil/integration) [#21006](https://github.com/cosmos/cosmos-sdk/pull/21006) Fix `NewIntegrationApp` method not writing default genesis to state.
* (runtime) [#21080](https://github.com/cosmos/cosmos-sdk/pull/21080) Fix `app.yaml` / `app.json` incompatibility with `depinject v1.0.0`.
## [v0.50.8](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.8) - 2024-07-15
## Features
* (client) [#20690](https://github.com/cosmos/cosmos-sdk/pull/20690) Import mnemonic from file
## Improvements
* (x/authz,x/feegrant) [#20590](https://github.com/cosmos/cosmos-sdk/pull/20590) Provide updated keeper in depinject for authz and feegrant modules.
* [#20631](https://github.com/cosmos/cosmos-sdk/pull/20631) Fix json parsing in the wait-tx command.
* (x/auth) [#20438](https://github.com/cosmos/cosmos-sdk/pull/20438) Add `--skip-signature-verification` flag to multisign command to allow nested multisigs.
## Bug Fixes
* (simulation) [#17911](https://github.com/cosmos/cosmos-sdk/pull/17911) Fix all problems with executing command `make test-sim-custom-genesis-fast` for simulation test.
* (simulation) [#18196](https://github.com/cosmos/cosmos-sdk/pull/18196) Fix the problem of `validator set is empty after InitGenesis` in simulation test.
## [v0.50.7](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.7) - 2024-06-04
### Improvements
* (debug) [#20328](https://github.com/cosmos/cosmos-sdk/pull/20328) Add consensus address for debug cmd.
* (runtime) [#20264](https://github.com/cosmos/cosmos-sdk/pull/20264) Expose grpc query router via depinject.
* (x/consensus) [#20381](https://github.com/cosmos/cosmos-sdk/pull/20381) Use Comet utility for consensus module consensus param updates.
* (client) [#20356](https://github.com/cosmos/cosmos-sdk/pull/20356) Overwrite client context when available in `SetCmdClientContext`.
### Bug Fixes
* (baseapp) [#20346](https://github.com/cosmos/cosmos-sdk/pull/20346) Correctly assign `execModeSimulate` to context for `simulateTx`.
* (baseapp) [#20144](https://github.com/cosmos/cosmos-sdk/pull/20144) Remove txs from mempool when AnteHandler fails in recheck.
* (baseapp) [#20107](https://github.com/cosmos/cosmos-sdk/pull/20107) Avoid header height overwrite block height.
* (cli) [#20020](https://github.com/cosmos/cosmos-sdk/pull/20020) Make bootstrap-state command support both new and legacy genesis format.
* (testutil/sims) [#20151](https://github.com/cosmos/cosmos-sdk/pull/20151) Set all signatures and don't overwrite the previous one in `GenSignedMockTx`.
## [v0.50.6](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.6) - 2024-04-22
### Features
* (types) [#19759](https://github.com/cosmos/cosmos-sdk/pull/19759) Align SignerExtractionAdapter in PriorityNonceMempool Remove.
* (client) [#19870](https://github.com/cosmos/cosmos-sdk/pull/19870) Add new query command `wait-tx`. Alias `event-query-tx-for` to `wait-tx` for backward compatibility.
### Improvements
* (telemetry) [#19903](https://github.com/cosmos/cosmos-sdk/pull/19903) Conditionally emit metrics based on enablement.
* **Introduction of `Now` Function**: Added a new function called `Now` to the telemetry package. It returns the current system time if telemetry is enabled, or a zero time if telemetry is not enabled.
* **Atomic Global Variable**: Implemented an atomic global variable to manage the state of telemetry's enablement. This ensures thread safety for the telemetry state.
* **Conditional Telemetry Emission**: All telemetry functions have been updated to emit metrics only when telemetry is enabled. They perform a check with `isTelemetryEnabled()` and return early if telemetry is disabled, minimizing unnecessary operations and overhead.
* (deps) [#19810](https://github.com/cosmos/cosmos-sdk/pull/19810) Upgrade prometheus version and fix API breaking change due to prometheus bump.
* (deps) [#19810](https://github.com/cosmos/cosmos-sdk/pull/19810) Bump `cosmossdk.io/store` to v1.1.0.
* (server) [#19884](https://github.com/cosmos/cosmos-sdk/pull/19884) Add start customizability to start command options.
* (x/gov) [#19853](https://github.com/cosmos/cosmos-sdk/pull/19853) Emit `depositor` in `EventTypeProposalDeposit`.
* (x/gov) [#19844](https://github.com/cosmos/cosmos-sdk/pull/19844) Emit the proposer of governance proposals.
* (baseapp) [#19616](https://github.com/cosmos/cosmos-sdk/pull/19616) Don't share gas meter in tx execution.
## Bug Fixes
* (x/authz) [#20114](https://github.com/cosmos/cosmos-sdk/pull/20114) Follow up of [GHSA-4j93-fm92-rp4m](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-4j93-fm92-rp4m) for `x/authz`.
* (crypto) [#19691](https://github.com/cosmos/cosmos-sdk/pull/19745) Fix tx sign doesn't throw an error when incorrect Ledger is used.
* (baseapp) [#19970](https://github.com/cosmos/cosmos-sdk/pull/19970) Fix default config values to use no-op mempool as default.
* (crypto) [#20027](https://github.com/cosmos/cosmos-sdk/pull/20027) secp256r1 keys now implement gogoproto's customtype interface.
* (x/bank) [#20028](https://github.com/cosmos/cosmos-sdk/pull/20028) Align query with multi denoms for send-enabled.
## [v0.50.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.5) - 2024-03-12
### Features
* (baseapp) [#19626](https://github.com/cosmos/cosmos-sdk/pull/19626) Add `DisableBlockGasMeter` option to `BaseApp`, which removes the block gas meter during transaction execution.
### Improvements
* (x/distribution) [#19707](https://github.com/cosmos/cosmos-sdk/pull/19707) Add autocli config for `DelegationTotalRewards` for CLI consistency with `q rewards` commands in previous versions.
* (x/auth) [#19651](https://github.com/cosmos/cosmos-sdk/pull/19651) Allow empty public keys in `GetSignBytesAdapter`.
### Bug Fixes
* (x/gov) [#19725](https://github.com/cosmos/cosmos-sdk/pull/19725) Fetch a failed proposal tally from proposal.FinalTallyResult in the gprc query.
* (types) [#19709](https://github.com/cosmos/cosmos-sdk/pull/19709) Fix skip staking genesis export when using `CoreAppModuleAdaptor` / `CoreAppModuleBasicAdaptor` for it.
* (x/auth) [#19549](https://github.com/cosmos/cosmos-sdk/pull/19549) Accept custom get signers when injecting `x/auth/tx`.
* (x/staking) Fix a possible bypass of delegator slashing: [GHSA-86h5-xcpx-cfqc](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-86h5-xcpx-cfqc)
* (baseapp) Fix a bug in `baseapp.ValidateVoteExtensions` helper ([GHSA-95rx-m9m5-m94v](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-95rx-m9m5-m94v)). The helper has been fixed and for avoiding API breaking changes `currentHeight` and `chainID` arguments are ignored. Those arguments are removed from the helper in v0.51+.
## [v0.50.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.4) - 2024-02-19
### Features
* (server) [#19280](https://github.com/cosmos/cosmos-sdk/pull/19280) Adds in-place testnet CLI command.
### Improvements
* (client) [#19393](https://github.com/cosmos/cosmos-sdk/pull/19393/) Add `ReadDefaultValuesFromDefaultClientConfig` to populate the default values from the default client config in client.Context without creating a app folder.
### Bug Fixes
* (x/auth/vesting) [GHSA-4j93-fm92-rp4m](#bug-fixes) Add `BlockedAddr` check in `CreatePeriodicVestingAccount`.
* (baseapp) [#19338](https://github.com/cosmos/cosmos-sdk/pull/19338) Set HeaderInfo in context when calling `setState`.
* (baseapp): [#19200](https://github.com/cosmos/cosmos-sdk/pull/19200) Ensure that sdk side ve math matches cometbft.
* [#19106](https://github.com/cosmos/cosmos-sdk/pull/19106) Allow empty public keys when setting signatures. Public keys aren't needed for every transaction.
* (baseapp) [#19198](https://github.com/cosmos/cosmos-sdk/pull/19198) Remove usage of pointers in logs in all optimistic execution goroutines.
* (baseapp) [#19177](https://github.com/cosmos/cosmos-sdk/pull/19177) Fix baseapp `DefaultProposalHandler` same-sender non-sequential sequence.
* (crypto) [#19371](https://github.com/cosmos/cosmos-sdk/pull/19371) Avoid CLI redundant log in stdout, log to stderr instead.
## [v0.50.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.3) - 2024-01-15
### Features
* (types) [#18991](https://github.com/cosmos/cosmos-sdk/pull/18991) Add SignerExtractionAdapter to PriorityNonceMempool/Config and provide Default implementation matching existing behavior.
* (gRPC) [#19043](https://github.com/cosmos/cosmos-sdk/pull/19043) Add `halt_height` to the gRPC `/cosmos/base/node/v1beta1/config` request.
### Improvements
* (x/bank) [#18956](https://github.com/cosmos/cosmos-sdk/pull/18956) Introduced a new `DenomOwnersByQuery` query method for `DenomOwners`, which accepts the denom value as a query string parameter, resolving issues with denoms containing slashes.
* (x/gov) [#18707](https://github.com/cosmos/cosmos-sdk/pull/18707) Improve genesis validation.
* (x/auth/tx) [#18772](https://github.com/cosmos/cosmos-sdk/pull/18772) Remove misleading gas wanted from tx simulation failure log.
* (client/tx) [#18852](https://github.com/cosmos/cosmos-sdk/pull/18852) Add `WithFromName` to tx factory.
* (types) [#18888](https://github.com/cosmos/cosmos-sdk/pull/18888) Speedup DecCoin.Sort() if len(coins) <= 1
* (types) [#18875](https://github.com/cosmos/cosmos-sdk/pull/18875) Speedup coins.Sort() if len(coins) <= 1
* (baseapp) [#18915](https://github.com/cosmos/cosmos-sdk/pull/18915) Add a new `ExecModeVerifyVoteExtension` exec mode and ensure it's populated in the `Context` during `VerifyVoteExtension` execution.
* (testutil) [#18930](https://github.com/cosmos/cosmos-sdk/pull/18930) Add NodeURI for clientCtx.
### Bug Fixes
* (baseapp) [#19058](https://github.com/cosmos/cosmos-sdk/pull/19058) Fix baseapp posthandler branch would fail if the `runMsgs` had returned an error.
* (baseapp) [#18609](https://github.com/cosmos/cosmos-sdk/issues/18609) Fixed accounting in the block gas meter after module's beginBlock and before DeliverTx, ensuring transaction processing always starts with the expected zeroed out block gas meter.
* (baseapp) [#18895](https://github.com/cosmos/cosmos-sdk/pull/18895) Fix de-duplicating vote extensions during validation in ValidateVoteExtensions.
## [v0.50.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.2) - 2023-12-11
### Features
* (debug) [#18219](https://github.com/cosmos/cosmos-sdk/pull/18219) Add debug commands for application codec types.
* (client/keys) [#17639](https://github.com/cosmos/cosmos-sdk/pull/17639) Allows using and saving public keys encoded as base64.
* (server) [#17094](https://github.com/cosmos/cosmos-sdk/pull/17094) Add a `shutdown-grace` flag for waiting a given time before exit.
### Improvements
* (telemetry) [#18646] (https://github.com/cosmos/cosmos-sdk/pull/18646) Enable statsd and dogstatsd telemetry sinks.
* (server) [#18478](https://github.com/cosmos/cosmos-sdk/pull/18478) Add command flag to disable colored logs.
* (x/gov) [#18025](https://github.com/cosmos/cosmos-sdk/pull/18025) Improve `<appd> q gov proposer` by querying directly a proposal instead of tx events. It is an alias of `q gov proposal` as the proposer is a field of the proposal.
* (version) [#18063](https://github.com/cosmos/cosmos-sdk/pull/18063) Allow to define extra info to be displayed in `<appd> version --long` command.
* (codec/unknownproto)[#18541](https://github.com/cosmos/cosmos-sdk/pull/18541) Remove the use of "protoc-gen-gogo/descriptor" in favour of using the official protobuf descriptorpb types inside unknownproto.
### Bug Fixes
* (x/auth) [#18564](https://github.com/cosmos/cosmos-sdk/pull/18564) Fix total fees calculation when batch signing.
* (server) [#18537](https://github.com/cosmos/cosmos-sdk/pull/18537) Fix panic when defining minimum gas config as `100stake;100uatom`. Use a `,` delimiter instead of `;`. Fixes the server config getter to use the correct delimiter.
* [#18531](https://github.com/cosmos/cosmos-sdk/pull/18531) Baseapp's `GetConsensusParams` returns an empty struct instead of panicking if no params are found.
* (client/tx) [#18472](https://github.com/cosmos/cosmos-sdk/pull/18472) Utilizes the correct Pubkey when simulating a transaction.
* (baseapp) [#18486](https://github.com/cosmos/cosmos-sdk/pull/18486) Fixed FinalizeBlock calls not being passed to ABCIListeners.
* (baseapp) [#18627](https://github.com/cosmos/cosmos-sdk/pull/18627) Post handlers are run on non successful transaction executions too.
* (baseapp) [#18654](https://github.com/cosmos/cosmos-sdk/pull/18654) Fixes an issue in which `gogoproto.Merge` does not work with gogoproto messages with custom types.
## [v0.50.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.1) - 2023-11-07
> v0.50.0 has been retracted due to a mistake in tagging the release. Please use v0.50.1 instead.
### Features
* (baseapp) [#18071](https://github.com/cosmos/cosmos-sdk/pull/18071) Add hybrid handlers to `MsgServiceRouter`.
* (server) [#18162](https://github.com/cosmos/cosmos-sdk/pull/18162) Start gRPC & API server in standalone mode.
* (baseapp & types) [#17712](https://github.com/cosmos/cosmos-sdk/pull/17712) Introduce `PreBlock`, which runs before begin blocker other modules, and allows to modify consensus parameters, and the changes are visible to the following state machine logics. Additionally it can be used for vote extensions.
* (genutil) [#17571](https://github.com/cosmos/cosmos-sdk/pull/17571) Allow creation of `AppGenesis` without a file lookup.
* (codec) [#17042](https://github.com/cosmos/cosmos-sdk/pull/17042) Add `CollValueV2` which supports encoding of protov2 messages in collections.
* (x/gov) [#16976](https://github.com/cosmos/cosmos-sdk/pull/16976) Add `failed_reason` field to `Proposal` under `x/gov` to indicate the reason for a failed proposal. Referenced from [#238](https://github.com/bnb-chain/greenfield-cosmos-sdk/pull/238) under `bnb-chain/greenfield-cosmos-sdk`.
* (baseapp) [#16898](https://github.com/cosmos/cosmos-sdk/pull/16898) Add `preFinalizeBlockHook` to allow vote extensions persistence.
* (cli) [#16887](https://github.com/cosmos/cosmos-sdk/pull/16887) Add two new CLI commands: `<appd> tx simulate` for simulating a transaction; `<appd> query block-results` for querying CometBFT RPC for block results.
* (x/bank) [#16852](https://github.com/cosmos/cosmos-sdk/pull/16852) Add `DenomMetadataByQueryString` query in bank module to support metadata query by query string.
* (baseapp) [#16581](https://github.com/cosmos/cosmos-sdk/pull/16581) Implement Optimistic Execution as an experimental feature (not enabled by default).
* (types) [#16257](https://github.com/cosmos/cosmos-sdk/pull/16257) Allow setting the base denom in the denom registry.
* (baseapp) [#16239](https://github.com/cosmos/cosmos-sdk/pull/16239) Add Gas Limits to allow node operators to resource bound queries.
* (cli) [#16209](https://github.com/cosmos/cosmos-sdk/pull/16209) Make `StartCmd` more customizable.
* (types/simulation) [#16074](https://github.com/cosmos/cosmos-sdk/pull/16074) Add generic SimulationStoreDecoder for modules using collections.
* (genutil) [#16046](https://github.com/cosmos/cosmos-sdk/pull/16046) Add "module-name" flag to genutil `add-genesis-account` to enable intializing module accounts at genesis.* [#15970](https://github.com/cosmos/cosmos-sdk/pull/15970) Enable SIGN_MODE_TEXTUAL.
* (types) [#15958](https://github.com/cosmos/cosmos-sdk/pull/15958) Add `module.NewBasicManagerFromManager` for creating a basic module manager from a module manager.
* (types/module) [#15829](https://github.com/cosmos/cosmos-sdk/pull/15829) Add new endblocker interface to handle valset updates.
* (runtime) [#15818](https://github.com/cosmos/cosmos-sdk/pull/15818) Provide logger through `depinject` instead of appBuilder.
* (types) [#15735](https://github.com/cosmos/cosmos-sdk/pull/15735) Make `ValidateBasic() error` method of `Msg` interface optional. Modules should validate messages directly in their message handlers ([RFC 001](https://docs.cosmos.network/main/rfc/rfc-001-tx-validation)).
* (x/genutil) [#15679](https://github.com/cosmos/cosmos-sdk/pull/15679) Allow applications to specify a custom genesis migration function for the `genesis migrate` command.
* (telemetry) [#15657](https://github.com/cosmos/cosmos-sdk/pull/15657) Emit more data (go version, sdk version, upgrade height) in prom metrics.
* (client) [#15597](https://github.com/cosmos/cosmos-sdk/pull/15597) Add status endpoint for clients.
* (testutil/integration) [#15556](https://github.com/cosmos/cosmos-sdk/pull/15556) Introduce `testutil/integration` package for module integration testing.
* (runtime) [#15547](https://github.com/cosmos/cosmos-sdk/pull/15547) Allow runtime to pass event core api service to modules.
* (client) [#15458](https://github.com/cosmos/cosmos-sdk/pull/15458) Add a `CmdContext` field to client.Context initialized to cobra command's context.
* (x/genutil) [#15301](https://github.com/cosmos/cosmos-sdk/pull/15031) Add application genesis. The genesis is now entirely managed by the application and passed to CometBFT at note instantiation. Functions that were taking a `cmttypes.GenesisDoc{}` now takes a `genutiltypes.AppGenesis{}`.
* (core) [#15133](https://github.com/cosmos/cosmos-sdk/pull/15133) Implement RegisterServices in the module manager.
* (x/bank) [#14894](https://github.com/cosmos/cosmos-sdk/pull/14894) Return a human readable denomination for IBC vouchers when querying bank balances. Added a `ResolveDenom` parameter to `types.QueryAllBalancesRequest` and `--resolve-denom` flag to `GetBalancesCmd()`.
* (core) [#14860](https://github.com/cosmos/cosmos-sdk/pull/14860) Add `Precommit` and `PrepareCheckState` AppModule callbacks.
* (x/gov) [#14720](https://github.com/cosmos/cosmos-sdk/pull/14720) Upstream expedited proposals from Osmosis.
* (cli) [#14659](https://github.com/cosmos/cosmos-sdk/pull/14659) Added ability to query blocks by events with queries directly passed to Tendermint, which will allow for full query operator support, e.g. `>`.
* (x/auth) [#14650](https://github.com/cosmos/cosmos-sdk/pull/14650) Add Textual SignModeHandler. Enable `SIGN_MODE_TEXTUAL` by following the [UPGRADING.md](./UPGRADING.md) instructions.
* (x/crisis) [#14588](https://github.com/cosmos/cosmos-sdk/pull/14588) Use CacheContext() in AssertInvariants().
* (mempool) [#14484](https://github.com/cosmos/cosmos-sdk/pull/14484) Add priority nonce mempool option for transaction replacement.
* (query) [#14468](https://github.com/cosmos/cosmos-sdk/pull/14468) Implement pagination for collections.
* (x/gov) [#14373](https://github.com/cosmos/cosmos-sdk/pull/14373) Add new proto field `constitution` of type `string` to gov module genesis state, which allows chain builders to lay a strong foundation by specifying purpose.
* (client) [#14342](https://github.com/cosmos/cosmos-sdk/pull/14342) Add `<app> config` command is now a sub-command, for setting, getting and migrating Cosmos SDK configuration files.
* (x/distribution) [#14322](https://github.com/cosmos/cosmos-sdk/pull/14322) Introduce a new gRPC message handler, `DepositValidatorRewardsPool`, that allows explicit funding of a validator's reward pool.
* (x/bank) [#14224](https://github.com/cosmos/cosmos-sdk/pull/14224) Allow injection of restrictions on transfers using `AppendSendRestriction` or `PrependSendRestriction`.
### Improvements
* (x/gov) [#18189](https://github.com/cosmos/cosmos-sdk/pull/18189) Limit the accepted deposit coins for a proposal to the minimum proposal deposit denoms.
* (x/staking) [#18049](https://github.com/cosmos/cosmos-sdk/pull/18049) Return early if Slash encounters zero tokens to burn.
* (x/staking) [#18035](https://github.com/cosmos/cosmos-sdk/pull/18035) Hoisted out of the redelegation loop, the non-changing validator and delegator addresses parsing.
* (keyring) [#17913](https://github.com/cosmos/cosmos-sdk/pull/17913) Add `NewAutoCLIKeyring` for creating an AutoCLI keyring from a SDK keyring.
* (x/consensus) [#18041](https://github.com/cosmos/cosmos-sdk/pull/18041) Let `ToProtoConsensusParams()` return an error.
* (x/gov) [#17780](https://github.com/cosmos/cosmos-sdk/pull/17780) Recover panics and turn them into errors when executing x/gov proposals.
* (baseapp) [#17667](https://github.com/cosmos/cosmos-sdk/pull/17667) Close databases opened by SDK in `baseApp.Close()`.
* (types/module) [#17554](https://github.com/cosmos/cosmos-sdk/pull/17554) Introduce `HasABCIGenesis` which is implemented by a module only when a validatorset update needs to be returned.
* (cli) [#17389](https://github.com/cosmos/cosmos-sdk/pull/17389) gRPC CometBFT commands have been added under `<aapd> q consensus comet`. CometBFT commands placement in the SDK has been simplified. See the exhaustive list below.
* `client/rpc.StatusCommand()` is now at `server.StatusCommand()`
* (testutil) [#17216](https://github.com/cosmos/cosmos-sdk/issues/17216) Add `DefaultContextWithKeys` to `testutil` package.
* (cli) [#17187](https://github.com/cosmos/cosmos-sdk/pull/17187) Do not use `ctx.PrintObjectLegacy` in commands anymore.
* `<appd> q gov proposer [proposal-id]` now returns a proposal id as int instead of string.
* (x/staking) [#17164](https://github.com/cosmos/cosmos-sdk/pull/17164) Add `BondedTokensAndPubKeyByConsAddr` to the keeper to enable vote extension verification.
* (x/group, x/gov) [#17109](https://github.com/cosmos/cosmos-sdk/pull/17109) Let proposal summary be 40x longer than metadata limit.
* (version) [#17096](https://github.com/cosmos/cosmos-sdk/pull/17096) Improve `getSDKVersion()` to handle module replacements.
* (types) [#16890](https://github.com/cosmos/cosmos-sdk/pull/16890) Remove `GetTxCmd() *cobra.Command` and `GetQueryCmd() *cobra.Command` from `module.AppModuleBasic` interface.
* (x/authz) [#16869](https://github.com/cosmos/cosmos-sdk/pull/16869) Improve error message when grant not found.
* (all) [#16497](https://github.com/cosmos/cosmos-sdk/pull/16497) Removed all exported vestiges of `sdk.MustSortJSON` and `sdk.SortJSON`.
* (server) [#16238](https://github.com/cosmos/cosmos-sdk/pull/16238) Don't setup p2p node keys if starting a node in GRPC only mode.
* (cli) [#16206](https://github.com/cosmos/cosmos-sdk/pull/16206) Make ABCI handshake profileable.
* (types) [#16076](https://github.com/cosmos/cosmos-sdk/pull/16076) Optimize `ChainAnteDecorators`/`ChainPostDecorators` to instantiate the functions once instead of on every invocation of the returned `AnteHandler`/`PostHandler`.
* (server) [#16071](https://github.com/cosmos/cosmos-sdk/pull/16071) When `mempool.max-txs` is set to a negative value, use a no-op mempool (effectively disable the app mempool).
* (types/query) [#16041](https://github.com/cosmos/cosmos-sdk/pull/16041) Change pagination max limit to a variable in order to be modifed by application devs.
* (simapp) [#15958](https://github.com/cosmos/cosmos-sdk/pull/15958) Refactor SimApp for removing the global basic manager.
* (all modules) [#15901](https://github.com/cosmos/cosmos-sdk/issues/15901) All core Cosmos SDK modules query commands have migrated to [AutoCLI](https://docs.cosmos.network/main/core/autocli), ensuring parity between gRPC and CLI queries.
* (x/auth) [#15867](https://github.com/cosmos/cosmos-sdk/pull/15867) Support better logging for signature verification failure.
* (store/cachekv) [#15767](https://github.com/cosmos/cosmos-sdk/pull/15767) Reduce peak RAM usage during and after `InitGenesis`.
* (x/bank) [#15764](https://github.com/cosmos/cosmos-sdk/pull/15764) Speedup x/bank `InitGenesis`.
* (x/slashing) [#15580](https://github.com/cosmos/cosmos-sdk/pull/15580) Refactor the validator's missed block signing window to be a chunked bitmap instead of a "logical" bitmap, significantly reducing the storage footprint.
* (x/gov) [#15554](https://github.com/cosmos/cosmos-sdk/pull/15554) Add proposal result log in `active_proposal` event. When a proposal passes but fails to execute, the proposal result is logged in the `active_proposal` event.
* (x/consensus) [#15553](https://github.com/cosmos/cosmos-sdk/pull/15553) Migrate consensus module to use collections.
* (server) [#15358](https://github.com/cosmos/cosmos-sdk/pull/15358) Add `server.InterceptConfigsAndCreateContext` as alternative to `server.InterceptConfigsPreRunHandler` which does not set the server context and the default SDK logger.
* (mempool) [#15328](https://github.com/cosmos/cosmos-sdk/pull/15328) Improve the `PriorityNonceMempool`:
* Support generic transaction prioritization, instead of `ctx.Priority()`
* Improve construction through the use of a single `PriorityNonceMempoolConfig` instead of option functions
* (x/authz) [#15164](https://github.com/cosmos/cosmos-sdk/pull/15164) Add `MsgCancelUnbondingDelegation` to staking authorization.
* (server) [#15041](https://github.com/cosmos/cosmos-sdk/pull/15041) Remove unnecessary sleeps from gRPC and API server initiation. The servers will start and accept requests as soon as they're ready.
* (baseapp) [#15023](https://github.com/cosmos/cosmos-sdk/pull/15023) & [#15213](https://github.com/cosmos/cosmos-sdk/pull/15213) Add `MessageRouter` interface to baseapp and pass it to authz, gov and groups instead of concrete type.
* [#15011](https://github.com/cosmos/cosmos-sdk/pull/15011) Introduce `cosmossdk.io/log` package to provide a consistent logging interface through the SDK. CometBFT logger is now replaced by `cosmossdk.io/log.Logger`.
* (x/staking) [#14864](https://github.com/cosmos/cosmos-sdk/pull/14864) `<appd> tx staking create-validator` CLI command now takes a json file as an arg instead of using required flags.
* (x/auth) [#14758](https://github.com/cosmos/cosmos-sdk/pull/14758) Allow transaction event queries to directly passed to Tendermint, which will allow for full query operator support, e.g. `>`.
* (x/evidence) [#14757](https://github.com/cosmos/cosmos-sdk/pull/14757) Evidence messages do not need to implement a `.Type()` anymore.
* (x/auth/tx) [#14751](https://github.com/cosmos/cosmos-sdk/pull/14751) Remove `.Type()` and `Route()` methods from all msgs and `legacytx.LegacyMsg` interface.
* (cli) [#14659](https://github.com/cosmos/cosmos-sdk/pull/14659) Added ability to query blocks by either height/hash `<app> q block --type=height|hash <height|hash>`.
* (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) Return undelegate amount in MsgUndelegateResponse.
* [#14529](https://github.com/cosmos/cosmos-sdk/pull/14529) Add new property `BondDenom` to `SimulationState` struct.
* (store) [#14439](https://github.com/cosmos/cosmos-sdk/pull/14439) Remove global metric gatherer from store.
* By default store has a no op metric gatherer, the application developer must set another metric gatherer or us the provided one in `store/metrics`.
* (store) [#14438](https://github.com/cosmos/cosmos-sdk/pull/14438) Pass logger from baseapp to store.
* (baseapp) [#14417](https://github.com/cosmos/cosmos-sdk/pull/14417) The store package no longer has a dependency on baseapp.
* (module) [#14415](https://github.com/cosmos/cosmos-sdk/pull/14415) Loosen assertions in SetOrderBeginBlockers() and SetOrderEndBlockers().
* (store) [#14410](https://github.com/cosmos/cosmos-sdk/pull/14410) `rootmulti.Store.loadVersion` has validation to check if all the module stores' height is correct, it will error if any module store has incorrect height.
* [#14406](https://github.com/cosmos/cosmos-sdk/issues/14406) Migrate usage of `types/store.go` to `store/types/..`.
* (context)[#14384](https://github.com/cosmos/cosmos-sdk/pull/14384) Refactor(context): Pass EventManager to the context as an interface.
* (types) [#14354](https://github.com/cosmos/cosmos-sdk/pull/14354) Improve performance on Context.KVStore and Context.TransientStore by 40%.
* (crypto/keyring) [#14151](https://github.com/cosmos/cosmos-sdk/pull/14151) Move keys presentation from `crypto/keyring` to `client/keys`
* (signing) [#14087](https://github.com/cosmos/cosmos-sdk/pull/14087) Add SignModeHandlerWithContext interface with a new `GetSignBytesWithContext` to get the sign bytes using `context.Context` as an argument to access state.
* (server) [#14062](https://github.com/cosmos/cosmos-sdk/pull/14062) Remove rosetta from server start.
* (crypto) [#3129](https://github.com/cosmos/cosmos-sdk/pull/3129) New armor and keyring key derivation uses aead and encryption uses chacha20poly.
### State Machine Breaking
* (x/gov) [#18146](https://github.com/cosmos/cosmos-sdk/pull/18146) Add denom check to reject denoms outside of those listed in `MinDeposit`. A new `MinDepositRatio` param is added (with a default value of `0.001`) and now deposits are required to be at least `MinDepositRatio*MinDeposit` to be accepted.
* (x/group,x/gov) [#16235](https://github.com/cosmos/cosmos-sdk/pull/16235) A group and gov proposal is rejected if the proposal metadata title and summary do not match the proposal title and summary.
* (baseapp) [#15930](https://github.com/cosmos/cosmos-sdk/pull/15930) change vote info provided by prepare and process proposal to the one in the block.
* (x/staking) [#15731](https://github.com/cosmos/cosmos-sdk/pull/15731) Introducing a new index to retrieve the delegations by validator efficiently.
* (x/staking) [#15701](https://github.com/cosmos/cosmos-sdk/pull/15701) The `HistoricalInfoKey` has been updated to use a binary format.
* (x/slashing) [#15580](https://github.com/cosmos/cosmos-sdk/pull/15580) The validator slashing window now stores "chunked" bitmap entries for each validator's signing window instead of a single boolean entry per signing window index.
* (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) `MsgUndelegateResponse` now includes undelegated amount. `x/staking` module's `keeper.Undelegate` now returns 3 values (completionTime,undelegateAmount,error) instead of 2.
* (x/feegrant) [#14294](https://github.com/cosmos/cosmos-sdk/pull/14294) Moved the logic of rejecting duplicate grant from `msg_server` to `keeper` method.
### API Breaking Changes
* (x/auth) [#17787](https://github.com/cosmos/cosmos-sdk/pull/17787) Remove Tip functionality.
* (types) `module.EndBlockAppModule` has been replaced by Core API `appmodule.HasEndBlocker` or `module.HasABCIEndBlock` when needing validator updates.
* (types) `module.BeginBlockAppModule` has been replaced by Core API `appmodule.HasBeginBlocker`.
* (types) [#17358](https://github.com/cosmos/cosmos-sdk/pull/17358) Remove deprecated `sdk.Handler`, use `baseapp.MsgServiceHandler` instead.
* (client) [#17197](https://github.com/cosmos/cosmos-sdk/pull/17197) `keys.Commands` does not take a home directory anymore. It is inferred from the root command.
* (x/staking) [#17157](https://github.com/cosmos/cosmos-sdk/pull/17157) `GetValidatorsByPowerIndexKey` and `ValidateBasic` for historical info takes a validator address codec in order to be able to decode/encode addresses.
* `GetOperator()` now returns the address as it is represented in state, by default this is an encoded address
* `GetConsAddr() ([]byte, error)` returns `[]byte` instead of sdk.ConsAddres.
* `FromABCIEvidence` & `GetConsensusAddress(consAc address.Codec)` now take a consensus address codec to be able to decode the incoming address.
* (x/distribution) `Delegate` & `SlashValidator` helper function added the mock staking keeper as a parameter passed to the function
* (x/staking) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `NewMsgCreateValidator`, `NewValidator`, `NewMsgCancelUnbondingDelegation`, `NewMsgUndelegate`, `NewMsgBeginRedelegate`, `NewMsgDelegate` and `NewMsgEditValidator` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`:
* `NewRedelegation` and `NewUnbondingDelegation` takes a validatorAddressCodec and a delegatorAddressCodec in order to decode the addresses.
* `NewRedelegationResponse` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`.
* `NewMsgCreateValidator.Validate()` takes an address codec in order to decode the address.
* `BuildCreateValidatorMsg` takes a ValidatorAddressCodec in order to decode addresses.
* (x/slashing) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `NewMsgUnjail` takes a string instead of `sdk.ValAddress`
* (x/genutil) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `GenAppStateFromConfig`, AddGenesisAccountCmd and `GenTxCmd` takes an addresscodec to decode addresses.
* (x/distribution) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `NewMsgDepositValidatorRewardsPool`, `NewMsgFundCommunityPool`, `NewMsgWithdrawValidatorCommission` and `NewMsgWithdrawDelegatorReward` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`.
* (x/staking) [#16959](https://github.com/cosmos/cosmos-sdk/pull/16959) Add validator and consensus address codec as staking keeper arguments.
* (x/staking) [#16958](https://github.com/cosmos/cosmos-sdk/pull/16958) DelegationI interface `GetDelegatorAddr` & `GetValidatorAddr` have been migrated to return string instead of sdk.AccAddress and sdk.ValAddress respectively. stakingtypes.NewDelegation takes a string instead of sdk.AccAddress and sdk.ValAddress.
* (testutil) [#16899](https://github.com/cosmos/cosmos-sdk/pull/16899) The *cli testutil* `QueryBalancesExec` has been removed. Use the gRPC or REST query instead.
* (x/staking) [#16795](https://github.com/cosmos/cosmos-sdk/pull/16795) `DelegationToDelegationResponse`, `DelegationsToDelegationResponses`, `RedelegationsToRedelegationResponses` are no longer exported.
* (x/auth/vesting) [#16741](https://github.com/cosmos/cosmos-sdk/pull/16741) Vesting account constructor now return an error with the result of their validate function.
* (x/auth) [#16650](https://github.com/cosmos/cosmos-sdk/pull/16650) The *cli testutil* `QueryAccountExec` has been removed. Use the gRPC or REST query instead.
* (x/auth) [#16621](https://github.com/cosmos/cosmos-sdk/pull/16621) Pass address codec to auth new keeper constructor.
* (x/auth) [#16423](https://github.com/cosmos/cosmos-sdk/pull/16423) `helpers.AddGenesisAccount` has been moved to `x/genutil` to remove the cyclic dependency between `x/auth` and `x/genutil`.
* (baseapp) [#16342](https://github.com/cosmos/cosmos-sdk/pull/16342) NewContext was renamed to NewContextLegacy. The replacement (NewContext) now does not take a header, instead you should set the header via `WithHeaderInfo` or `WithBlockHeight`. Note that `WithBlockHeight` will soon be depreacted and its recommneded to use `WithHeaderInfo`.
* (x/mint) [#16329](https://github.com/cosmos/cosmos-sdk/pull/16329) Use collections for state management:
* Removed: keeper `GetParams`, `SetParams`, `GetMinter`, `SetMinter`.
* (x/crisis) [#16328](https://github.com/cosmos/cosmos-sdk/pull/16328) Use collections for state management:
* Removed: keeper `GetConstantFee`, `SetConstantFee`
* (x/staking) [#16324](https://github.com/cosmos/cosmos-sdk/pull/16324) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`. Notable changes:
* `Validator` method now returns `types.ErrNoValidatorFound` instead of `nil` when not found.
* (x/distribution) [#16302](https://github.com/cosmos/cosmos-sdk/pull/16302) Use collections for FeePool state management.
* Removed: keeper `GetFeePool`, `SetFeePool`, `GetFeePoolCommunityCoins`
* (types) [#16272](https://github.com/cosmos/cosmos-sdk/pull/16272) `FeeGranter` in the `FeeTx` interface returns `[]byte` instead of `string`.
* (x/gov) [#16268](https://github.com/cosmos/cosmos-sdk/pull/16268) Use collections for proposal state management (part 2):
* this finalizes the gov collections migration
* Removed: types all the key related functions
* Removed: keeper `InsertActiveProposalsQueue`, `RemoveActiveProposalsQueue`, `InsertInactiveProposalsQueue`, `RemoveInactiveProposalsQueue`, `IterateInactiveProposalsQueue`, `IterateActiveProposalsQueue`, `ActiveProposalsQueueIterator`, `InactiveProposalsQueueIterator`
* (x/slashing) [#16246](https://github.com/cosmos/cosmos-sdk/issues/16246) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`. `GetValidatorSigningInfo` now returns an error instead of a `found bool`, the error can be `nil` (found), `ErrNoSigningInfoFound` (not found) and any other error.
* (module) [#16227](https://github.com/cosmos/cosmos-sdk/issues/16227) `manager.RunMigrations()` now take a `context.Context` instead of a `sdk.Context`.
* (x/crisis) [#16216](https://github.com/cosmos/cosmos-sdk/issues/16216) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error` instead of panicking.
* (x/distribution) [#16211](https://github.com/cosmos/cosmos-sdk/pull/16211) Use collections for params state management.
* (cli) [#16209](https://github.com/cosmos/cosmos-sdk/pull/16209) Add API `StartCmdWithOptions` to create customized start command.
* (x/mint) [#16179](https://github.com/cosmos/cosmos-sdk/issues/16179) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`.
* (x/gov) [#16171](https://github.com/cosmos/cosmos-sdk/pull/16171) Use collections for proposal state management (part 1):
* Removed: keeper: `GetProposal`, `UnmarshalProposal`, `MarshalProposal`, `IterateProposal`, `GetProposal`, `GetProposalFiltered`, `GetProposals`, `GetProposalID`, `SetProposalID`
* Removed: errors unused errors
* (x/gov) [#16164](https://github.com/cosmos/cosmos-sdk/pull/16164) Use collections for vote state management:
* Removed: types `VoteKey`, `VoteKeys`
* Removed: keeper `IterateVotes`, `IterateAllVotes`, `GetVotes`, `GetVote`, `SetVote`
* (sims) [#16155](https://github.com/cosmos/cosmos-sdk/pull/16155)
* `simulation.NewOperationMsg` now marshals the operation msg as proto bytes instead of legacy amino JSON bytes.
* `simulation.NewOperationMsg` is now 2-arity instead of 3-arity with the obsolete argument `codec.ProtoCodec` removed.
* The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`.
* (x/gov) [#16127](https://github.com/cosmos/cosmos-sdk/pull/16127) Use collections for deposit state management:
* The following methods are removed from the gov keeper: `GetDeposit`, `GetAllDeposits`, `IterateAllDeposits`.
* The following functions are removed from the gov types: `DepositKey`, `DepositsKey`.
* (x/gov) [#16118](https://github.com/cosmos/cosmos-sdk/pull/16118/) Use collections for constituion and params state management.
* (x/gov) [#16106](https://github.com/cosmos/cosmos-sdk/pull/16106) Remove gRPC query methods from gov keeper.
* (x/*all*) [#16052](https://github.com/cosmos/cosmos-sdk/pull/16062) `GetSignBytes` implementations on messages and global legacy amino codec definitions have been removed from all modules.
* (sims) [#16052](https://github.com/cosmos/cosmos-sdk/pull/16062) `GetOrGenerate` no longer requires a codec argument is now 4-arity instead of 5-arity.
* (types/math) [#16040](https://github.com/cosmos/cosmos-sdk/pull/16798) Remove aliases in `types/math.go` (part 2).
* (types/math) [#16040](https://github.com/cosmos/cosmos-sdk/pull/16040) Remove aliases in `types/math.go` (part 1).
* (x/auth) [#16016](https://github.com/cosmos/cosmos-sdk/pull/16016) Use collections for accounts state management:
* removed: keeper `HasAccountByID`, `AccountAddressByID`, `SetParams
* (x/genutil) [#15999](https://github.com/cosmos/cosmos-sdk/pull/15999) Genutil now takes the `GenesisTxHanlder` interface instead of deliverTx. The interface is implemented on baseapp
* (x/gov) [#15988](https://github.com/cosmos/cosmos-sdk/issues/15988) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error` (instead of panicking or returning a `found bool`). Iterators callback functions now return an error instead of a `bool`.
* (x/auth) [#15985](https://github.com/cosmos/cosmos-sdk/pull/15985) The `AccountKeeper` does not expose the `QueryServer` and `MsgServer` APIs anymore.
* (x/authz) [#15962](https://github.com/cosmos/cosmos-sdk/issues/15962) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`. The `Authorization` interface's `Accept` method now takes a `context.Context` instead of a `sdk.Context`.
* (x/distribution) [#15948](https://github.com/cosmos/cosmos-sdk/issues/15948) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey` and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`. Keeper methods also now return an `error`.
* (x/bank) [#15891](https://github.com/cosmos/cosmos-sdk/issues/15891) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey` and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`. Also `FundAccount` and `FundModuleAccount` from the `testutil` package accept a `context.Context` instead of a `sdk.Context`, and it's position was moved to the first place.
* (x/slashing) [#15875](https://github.com/cosmos/cosmos-sdk/pull/15875) `x/slashing.NewAppModule` now requires an `InterfaceRegistry` parameter.
* (x/crisis) [#15852](https://github.com/cosmos/cosmos-sdk/pull/15852) Crisis keeper now takes a instance of the address codec to be able to decode user addresses
* (x/auth) [#15822](https://github.com/cosmos/cosmos-sdk/pull/15822) The type of struct field `ante.HandlerOptions.SignModeHandler` has been changed to `x/tx/signing.HandlerMap`.
* (client) [#15822](https://github.com/cosmos/cosmos-sdk/pull/15822) The return type of the interface method `TxConfig.SignModeHandler` has been changed to `x/tx/signing.HandlerMap`.
* The signature of `VerifySignature` has been changed to accept a `x/tx/signing.HandlerMap` and other structs from `x/tx` as arguments.
* The signature of `NewTxConfigWithTextual` has been deprecated and its signature changed to accept a `SignModeOptions`.
* The signature of `NewSigVerificationDecorator` has been changed to accept a `x/tx/signing.HandlerMap`.
* (x/bank) [#15818](https://github.com/cosmos/cosmos-sdk/issues/15818) `BaseViewKeeper`'s `Logger` method now doesn't require a context. `NewBaseKeeper`, `NewBaseSendKeeper` and `NewBaseViewKeeper` now also require a `log.Logger` to be passed in.
* (x/genutil) [#15679](https://github.com/cosmos/cosmos-sdk/pull/15679) `MigrateGenesisCmd` now takes a `MigrationMap` instead of having the SDK genesis migration hardcoded.
* (client) [#15673](https://github.com/cosmos/cosmos-sdk/pull/15673) Move `client/keys.OutputFormatJSON` and `client/keys.OutputFormatText` to `client/flags` package.
* (x/*all*) [#15648](https://github.com/cosmos/cosmos-sdk/issues/15648) Make `SetParams` consistent across all modules and validate the params at the message handling instead of `SetParams` method.
* (codec) [#15600](https://github.com/cosmos/cosmos-sdk/pull/15600) [#15873](https://github.com/cosmos/cosmos-sdk/pull/15873) add support for getting signers to `codec.Codec` and `InterfaceRegistry`:
* `InterfaceRegistry` is has unexported methods and implements `protodesc.Resolver` plus the `RangeFiles` and `SigningContext` methods. All implementations of `InterfaceRegistry` by other users must now embed the official implementation.
* `Codec` has new methods `InterfaceRegistry`, `GetMsgAnySigners`, `GetMsgV1Signers`, and `GetMsgV2Signers` as well as unexported methods. All implementations of `Codec` by other users must now embed an official implementation from the `codec` package.
* `AminoCodec` is marked as deprecated and no longer implements `Codec.
* (client) [#15597](https://github.com/cosmos/cosmos-sdk/pull/15597) `RegisterNodeService` now requires a config parameter.
* (x/nft) [#15588](https://github.com/cosmos/cosmos-sdk/pull/15588) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey` and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`.
* (baseapp) [#15568](https://github.com/cosmos/cosmos-sdk/pull/15568) `SetIAVLLazyLoading` is removed from baseapp.
* (x/genutil) [#15567](https://github.com/cosmos/cosmos-sdk/pull/15567) `CollectGenTxsCmd` & `GenTxCmd` takes a address.Codec to be able to decode addresses.
* (x/bank) [#15567](https://github.com/cosmos/cosmos-sdk/pull/15567) `GenesisBalance.GetAddress` now returns a string instead of `sdk.AccAddress`
* `MsgSendExec` test helper function now takes a address.Codec
* (x/auth) [#15520](https://github.com/cosmos/cosmos-sdk/pull/15520) `NewAccountKeeper` now takes a `KVStoreService` instead of a `StoreKey` and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) `runTxMode`s were renamed to `execMode`. `ModeDeliver` as changed to `ModeFinalize` and a new `ModeVoteExtension` was added for vote extensions.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) Writing of state to the multistore was moved to `FinalizeBlock`. `Commit` still handles the committing values to disk.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) Calls to BeginBlock and EndBlock have been replaced with core api beginblock & endblock.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) BeginBlock and EndBlock are now internal to baseapp. For testing, user must call `FinalizeBlock`. BeginBlock and EndBlock calls are internal to Baseapp.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) All calls to ABCI methods now accept a pointer of the abci request and response types
* (x/consensus) [#15517](https://github.com/cosmos/cosmos-sdk/pull/15517) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`.
* (x/bank) [#15477](https://github.com/cosmos/cosmos-sdk/pull/15477) `banktypes.NewMsgMultiSend` and `keeper.InputOutputCoins` only accept one input.
* (server) [#15358](https://github.com/cosmos/cosmos-sdk/pull/15358) Remove `server.ErrorCode` that was not used anywhere.
* (x/capability) [#15344](https://github.com/cosmos/cosmos-sdk/pull/15344) Capability module was removed and is now housed in [IBC-GO](https://github.com/cosmos/ibc-go).
* (mempool) [#15328](https://github.com/cosmos/cosmos-sdk/pull/15328) The `PriorityNonceMempool` is now generic over type `C comparable` and takes a single `PriorityNonceMempoolConfig[C]` argument. See `DefaultPriorityNonceMempoolConfig` for how to construct the configuration and a `TxPriority` type.
* [#15299](https://github.com/cosmos/cosmos-sdk/pull/15299) Remove `StdTx` transaction and signing APIs. No SDK version has actually supported `StdTx` since before Stargate.
* [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284)
* (x/gov) [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) `NewKeeper` now requires `codec.Codec`.
* (x/authx) [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) `NewKeeper` now requires `codec.Codec`.
* `types/tx.Tx` no longer implements `sdk.Tx`.
* `sdk.Tx` now requires a new method `GetMsgsV2()`.
* `sdk.Msg.GetSigners` was deprecated and is no longer supported. Use the `cosmos.msg.v1.signer` protobuf annotation instead.
* `TxConfig` has a new method `SigningContext() *signing.Context`.
* `SigVerifiableTx.GetSigners()` now returns `([][]byte, error)` instead of `[]sdk.AccAddress`.
* `AccountKeeper` now has an `AddressCodec() address.Codec` method and the expected `AccountKeeper` for `x/auth/ante` expects this method.
* [#15211](https://github.com/cosmos/cosmos-sdk/pull/15211) Remove usage of `github.com/cometbft/cometbft/libs/bytes.HexBytes` in favor of `[]byte` thorough the SDK.
* (crypto) [#15070](https://github.com/cosmos/cosmos-sdk/pull/15070) `GenerateFromPassword` and `Cost` from `bcrypt.go` now take a `uint32` instead of a `int` type.
* (types) [#15067](https://github.com/cosmos/cosmos-sdk/pull/15067) Remove deprecated alias from `types/errors`. Use `cosmossdk.io/errors` instead.
* (server) [#15041](https://github.com/cosmos/cosmos-sdk/pull/15041) Refactor how gRPC and API servers are started to remove unnecessary sleeps:
* `api.Server#Start` now accepts a `context.Context`. The caller is responsible for ensuring that the context is canceled such that the API server can gracefully exit. The caller does not need to stop the server.
* To start the gRPC server you must first create the server via `NewGRPCServer`, after which you can start the gRPC server via `StartGRPCServer` which accepts a `context.Context`. The caller is responsible for ensuring that the context is canceled such that the gRPC server can gracefully exit. The caller does not need to stop the server.
* Rename `WaitForQuitSignals` to `ListenForQuitSignals`. Note, this function is no longer blocking. Thus the caller is expected to provide a `context.CancelFunc` which indicates that when a signal is caught, that any spawned processes can gracefully exit.
* Remove `ServerStartTime` constant.
* [#15011](https://github.com/cosmos/cosmos-sdk/pull/15011) All functions that were taking a CometBFT logger, now take `cosmossdk.io/log.Logger` instead.
* (simapp) [#14977](https://github.com/cosmos/cosmos-sdk/pull/14977) Move simulation helpers functions (`AppStateFn` and `AppStateRandomizedFn`) to `testutil/sims`. These takes an extra genesisState argument which is the default state of the app.
* (x/bank) [#14894](https://github.com/cosmos/cosmos-sdk/pull/14894) Allow a human readable denomination for coins when querying bank balances. Added a `ResolveDenom` parameter to `types.QueryAllBalancesRequest`.
* [#14847](https://github.com/cosmos/cosmos-sdk/pull/14847) App and ModuleManager methods `InitGenesis`, `ExportGenesis`, `BeginBlock` and `EndBlock` now also return an error.
* (x/upgrade) [#14764](https://github.com/cosmos/cosmos-sdk/pull/14764) The `x/upgrade` module is extracted to have a separate go.mod file which allows it to be a standalone module.
* (x/auth) [#14758](https://github.com/cosmos/cosmos-sdk/pull/14758) Refactor transaction searching:
* Refactor `QueryTxsByEvents` to accept a `query` of type `string` instead of `events` of type `[]string`
* Refactor CLI methods to accept `--query` flag instead of `--events`
* Pass `prove=false` to Tendermint's `TxSearch` RPC method
* (simulation) [#14751](https://github.com/cosmos/cosmos-sdk/pull/14751) Remove the `MsgType` field from `simulation.OperationInput` struct.
* (store) [#14746](https://github.com/cosmos/cosmos-sdk/pull/14746) Extract Store in its own go.mod and rename the package to `cosmossdk.io/store`.
* (x/nft) [#14725](https://github.com/cosmos/cosmos-sdk/pull/14725) Extract NFT in its own go.mod and rename the package to `cosmossdk.io/x/nft`.
* (x/gov) [#14720](https://github.com/cosmos/cosmos-sdk/pull/14720) Add an expedited field in the gov v1 proposal and `MsgNewMsgProposal`.
* (x/feegrant) [#14649](https://github.com/cosmos/cosmos-sdk/pull/14649) Extract Feegrant in its own go.mod and rename the package to `cosmossdk.io/x/feegrant`.
* (tx) [#14634](https://github.com/cosmos/cosmos-sdk/pull/14634) Move the `tx` go module to `x/tx`.
* (store/streaming)[#14603](https://github.com/cosmos/cosmos-sdk/pull/14603) `StoreDecoderRegistry` moved from store to `types/simulations` this breaks the `AppModuleSimulation` interface.
* (snapshots) [#14597](https://github.com/cosmos/cosmos-sdk/pull/14597) Move `snapshots` to `store/snapshots`, rename and bump proto package to v1.
* (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) `MsgUndelegateResponse` now includes undelegated amount. `x/staking` module's `keeper.Undelegate` now returns 3 values (completionTime,undelegateAmount,error) instead of 2.
* (crypto/keyring) [#14151](https://github.com/cosmos/cosmos-sdk/pull/14151) Move keys presentation from `crypto/keyring` to `client/keys`
* (baseapp) [#14050](https://github.com/cosmos/cosmos-sdk/pull/14050) Refactor `ABCIListener` interface to accept Go contexts.
* (x/auth) [#13850](https://github.com/cosmos/cosmos-sdk/pull/13850/) Remove `MarshalYAML` methods from module (`x/...`) types.
* (modules) [#13850](https://github.com/cosmos/cosmos-sdk/pull/13850) and [#14046](https://github.com/cosmos/cosmos-sdk/pull/14046) Remove gogoproto stringer annotations. This removes the custom `String()` methods on all types that were using the annotations.
* (x/evidence) [14724](https://github.com/cosmos/cosmos-sdk/pull/14724) Extract Evidence in its own go.mod and rename the package to `cosmossdk.io/x/evidence`.
* (crypto/keyring) [#13734](https://github.com/cosmos/cosmos-sdk/pull/13834) The keyring's `Sign` method now takes a new `signMode` argument. It is only used if the signing key is a Ledger hardware device. You can set it to 0 in all other cases.
* (snapshots) [14048](https://github.com/cosmos/cosmos-sdk/pull/14048) Move the Snapshot package to the store package. This is done in an effort group all storage related logic under one package.
* (signing) [#13701](https://github.com/cosmos/cosmos-sdk/pull/) Add `context.Context` as an argument `x/auth/signing.VerifySignature`.
* (store) [#11825](https://github.com/cosmos/cosmos-sdk/pull/11825) Make extension snapshotter interface safer to use, renamed the util function `WriteExtensionItem` to `WriteExtensionPayload`.
### Client Breaking Changes
* (x/gov) [#17910](https://github.com/cosmos/cosmos-sdk/pull/17910) Remove telemetry for counting votes and proposals. It was incorrectly counting votes. Use alternatives, such as state streaming.
* (abci) [#15845](https://github.com/cosmos/cosmos-sdk/pull/15845) Remove duplicating events in `logs`.
* (abci) [#15845](https://github.com/cosmos/cosmos-sdk/pull/15845) Add `msg_index` to all event attributes to associate events and messages.
* (x/staking) [#15701](https://github.com/cosmos/cosmos-sdk/pull/15701) `HistoricalInfoKey` now has a binary format.
* (store/streaming) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) State Streaming removed emitting of beginblock, endblock and delivertx in favour of emitting FinalizeBlock.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) BeginBlock & EndBlock events have begin or endblock in the events in order to identify which stage they are emitted from since they are returned to comet as FinalizeBlock events.
* (grpc-web) [#14652](https://github.com/cosmos/cosmos-sdk/pull/14652) Use same port for gRPC-Web and the API server.
### CLI Breaking Changes
* (all) The migration of modules to [AutoCLI](https://docs.cosmos.network/main/core/autocli) led to no changes in UX but a [small change in CLI outputs](https://github.com/cosmos/cosmos-sdk/issues/16651) where results can be nested.
* (all) Query pagination flags have been renamed with the migration to AutoCLI:
* `--reverse` -> `--page-reverse`
* `--offset` -> `--page-offset`
* `--limit` -> `--page-limit`
* `--count-total` -> `--page-count-total`
* (cli) [#17184](https://github.com/cosmos/cosmos-sdk/pull/17184) All json keys returned by the `status` command are now snake case instead of pascal case.
* (server) [#17177](https://github.com/cosmos/cosmos-sdk/pull/17177) Remove `iavl-lazy-loading` configuration.
* (x/gov) [#16987](https://github.com/cosmos/cosmos-sdk/pull/16987) In `<appd> query gov proposals` the proposal status flag have renamed from `--status` to `--proposal-status`. Additionally, that flags now uses the ENUM values: `PROPOSAL_STATUS_DEPOSIT_PERIOD`, `PROPOSAL_STATUS_VOTING_PERIOD`, `PROPOSAL_STATUS_PASSED`, `PROPOSAL_STATUS_REJECTED`, `PROPOSAL_STATUS_FAILED`.
* (x/bank) [#16899](https://github.com/cosmos/cosmos-sdk/pull/16899) With the migration to AutoCLI some bank commands have been split in two:
* Use `total-supply` (or `total`) for querying the total supply and `total-supply-of` for querying the supply of a specific denom.
* Use `denoms-metadata` for querying all denom metadata and `denom-metadata` for querying a specific denom metadata.
* (rosetta) [#16276](https://github.com/cosmos/cosmos-sdk/issues/16276) Rosetta migration to standalone repo.
* (cli) [#15826](https://github.com/cosmos/cosmos-sdk/pull/15826) Remove `<appd> q account` command. Use `<appd> q auth account` instead.
* (cli) [#15299](https://github.com/cosmos/cosmos-sdk/pull/15299) Remove `--amino` flag from `sign` and `multi-sign` commands. Amino `StdTx` has been deprecated for a while. Amino JSON signing still works as expected.
* (x/gov) [#14880](https://github.com/cosmos/cosmos-sdk/pull/14880) Remove `<app> tx gov submit-legacy-proposal cancel-software-upgrade` and `software-upgrade` commands. These commands are now in the `x/upgrade` module and using gov v1. Use `tx upgrade software-upgrade` instead.
* (x/staking) [#14864](https://github.com/cosmos/cosmos-sdk/pull/14864) `<appd> tx staking create-validator` CLI command now takes a json file as an arg instead of using required flags.
* (cli) [#14659](https://github.com/cosmos/cosmos-sdk/pull/14659) `<app> q block <height>` is removed as it just output json. The new command allows either height/hash and is `<app> q block --type=height|hash <height|hash>`.
* (grpc-web) [#14652](https://github.com/cosmos/cosmos-sdk/pull/14652) Remove `grpc-web.address` flag.
* (client) [#14342](https://github.com/cosmos/cosmos-sdk/pull/14342) `<app> config` command is now a sub-command using Confix. Use `<app> config --help` to learn more.
### Bug Fixes
* (server) [#18254](https://github.com/cosmos/cosmos-sdk/pull/18254) Don't hardcode gRPC address to localhost.
* (x/gov) [#18173](https://github.com/cosmos/cosmos-sdk/pull/18173) Gov hooks now return an error and are *blocking* when they fail. Expect for `AfterProposalFailedMinDeposit` and `AfterProposalVotingPeriodEnded` which log the error and continue.
* (x/gov) [#17873](https://github.com/cosmos/cosmos-sdk/pull/17873) Fail any inactive and active proposals that cannot be decoded.
* (x/slashing) [#18016](https://github.com/cosmos/cosmos-sdk/pull/18016) Fixed builder function for missed blocks key (`validatorMissedBlockBitArrayPrefixKey`) in slashing/migration/v4.
* (x/bank) [#18107](https://github.com/cosmos/cosmos-sdk/pull/18107) Add missing keypair of SendEnabled to restore legacy param set before migration.
* (baseapp) [#17769](https://github.com/cosmos/cosmos-sdk/pull/17769) Ensure we respect block size constraints in the `DefaultProposalHandler`'s `PrepareProposal` handler when a nil or no-op mempool is used. We provide a `TxSelector` type to assist in making transaction selection generalized. We also fix a comparison bug in tx selection when `req.maxTxBytes` is reached.
* (mempool) [#17668](https://github.com/cosmos/cosmos-sdk/pull/17668) Fix `PriorityNonceIterator.Next()` nil pointer ref for min priority at the end of iteration.
* (config) [#17649](https://github.com/cosmos/cosmos-sdk/pull/17649) Fix `mempool.max-txs` configuration is invalid in `app.config`.
* (baseapp) [#17518](https://github.com/cosmos/cosmos-sdk/pull/17518) Utilizing voting power from vote extensions (CometBFT) instead of the current bonded tokens (x/staking) to determine if a set of vote extensions are valid.
* (baseapp) [#17251](https://github.com/cosmos/cosmos-sdk/pull/17251) VerifyVoteExtensions and ExtendVote initialize their own contexts/states, allowing VerifyVoteExtensions being called without ExtendVote.
* (x/distribution) [#17236](https://github.com/cosmos/cosmos-sdk/pull/17236) Using "validateCommunityTax" in "Params.ValidateBasic", preventing panic when field "CommunityTax" is nil.
* (x/bank) [#17170](https://github.com/cosmos/cosmos-sdk/pull/17170) Avoid empty spendable error message on send coins.
* (x/group) [#17146](https://github.com/cosmos/cosmos-sdk/pull/17146) Rename x/group legacy ORM package's error codespace from "orm" to "legacy_orm", preventing collisions with ORM's error codespace "orm".
* (types/query) [#16905](https://github.com/cosmos/cosmos-sdk/pull/16905) Collections Pagination now applies proper count when filtering results.
* (x/bank) [#16841](https://github.com/cosmos/cosmos-sdk/pull/16841) Correctly process legacy `DenomAddressIndex` values.
* (x/auth/vesting) [#16733](https://github.com/cosmos/cosmos-sdk/pull/16733) Panic on overflowing and negative EndTimes when creating a PeriodicVestingAccount.
* (x/consensus) [#16713](https://github.com/cosmos/cosmos-sdk/pull/16713) Add missing ABCI param in `MsgUpdateParams`.
* (baseapp) [#16700](https://github.com/cosmos/cosmos-sdk/pull/16700) Fix consensus failure in returning no response to malformed transactions.
* [#16639](https://github.com/cosmos/cosmos-sdk/pull/16639) Make sure we don't execute blocks beyond the halt height.
* (baseapp) [#16613](https://github.com/cosmos/cosmos-sdk/pull/16613) Ensure each message in a transaction has a registered handler, otherwise `CheckTx` will fail.
* (baseapp) [#16596](https://github.com/cosmos/cosmos-sdk/pull/16596) Return error during `ExtendVote` and `VerifyVoteExtension` if the request height is earlier than `VoteExtensionsEnableHeight`.
* (baseapp) [#16259](https://github.com/cosmos/cosmos-sdk/pull/16259) Ensure the `Context` block height is correct after `InitChain` and prior to the second block.
* (x/gov) [#16231](https://github.com/cosmos/cosmos-sdk/pull/16231) Fix Rawlog JSON formatting of proposal_vote option field.* (cli) [#16138](https://github.com/cosmos/cosmos-sdk/pull/16138) Fix snapshot commands panic if snapshot don't exists.
* (x/staking) [#16043](https://github.com/cosmos/cosmos-sdk/pull/16043) Call `AfterUnbondingInitiated` hook for new unbonding entries only and fix `UnbondingDelegation` entries handling. This is a behavior change compared to Cosmos SDK v0.47.x, now the hook is called only for new unbonding entries.
* (types) [#16010](https://github.com/cosmos/cosmos-sdk/pull/16010) Let `module.CoreAppModuleBasicAdaptor` fallback to legacy genesis handling.
* (types) [#15691](https://github.com/cosmos/cosmos-sdk/pull/15691) Make `Coin.Validate()` check that `.Amount` is not nil.
* (x/crypto) [#15258](https://github.com/cosmos/cosmos-sdk/pull/15258) Write keyhash file with permissions 0600 instead of 0555.
* (x/auth) [#15059](https://github.com/cosmos/cosmos-sdk/pull/15059) `ante.CountSubKeys` returns 0 when passing a nil `Pubkey`.
* (x/capability) [#15030](https://github.com/cosmos/cosmos-sdk/pull/15030) Prevent `x/capability` from consuming `GasMeter` gas during `InitMemStore`
* (types/coin) [#14739](https://github.com/cosmos/cosmos-sdk/pull/14739) Deprecate the method `Coin.IsEqual` in favour of `Coin.Equal`. The difference between the two methods is that the first one results in a panic when denoms are not equal. This panic lead to unexpected behavior.
### Deprecated
* (types) [#16980](https://github.com/cosmos/cosmos-sdk/pull/16980) Deprecate `IntProto` and `DecProto`. Instead, `math.Int` and `math.LegacyDec` should be used respectively. Both types support `Marshal` and `Unmarshal` for binary serialization.
* (x/staking) [#14567](https://github.com/cosmos/cosmos-sdk/pull/14567) The `delegator_address` field of `MsgCreateValidator` has been deprecated.
The validator address bytes and delegator address bytes refer to the same account while creating validator (defer only in bech32 notation).
## Previous Versions
[CHANGELOG of previous versions](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md#v0470---2023-03-14).

46
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at community@interchain.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

152
CODING_GUIDELINES.md Normal file
View file

@ -0,0 +1,152 @@
# Coding Guidelines
This document is an extension to [CONTRIBUTING](./CONTRIBUTING.md) and provides more details about the coding guidelines and requirements.
## API & Design
* Code must be well structured:
* packages must have a limited responsibility (different concerns can go to different packages),
* types must be easy to compose,
* think about maintainbility and testability.
* "Depend upon abstractions, [not] concretions".
* Try to limit the number of methods you are exposing. It's easier to expose something later than to hide it.
* Take advantage of `internal` package concept.
* Follow agreed-upon design patterns and naming conventions.
* publicly-exposed functions are named logically, have forward-thinking arguments and return types.
* Avoid global variables and global configurators.
* Favor composable and extensible designs.
* Minimize code duplication.
* Limit third-party dependencies.
Performance:
* Avoid unnecessary operations or memory allocations.
Security:
* Pay proper attention to exploits involving:
* gas usage
* transaction verification and signatures
* malleability
* code must be always deterministic
* Thread safety. If some functionality is not thread-safe, or uses something that is not thread-safe, then clearly indicate the risk on each level.
## Acceptance tests
Start the design by defining Acceptance Tests. The purpose of Acceptance Testing is to
validate that the product being developed corresponds to the needs of the real users
and is ready for launch. Hence we often talk about **User Acceptance Test** (UAT).
It also gives a better understanding of the product and helps designing a right interface
and API.
UAT should be revisited at each stage of the product development:
![acceptance-tests.png](./docs/static/img/acceptance-tests.png)
### Why Acceptance Testing
* Automated acceptance tests catch serious problems that unit or component test suites could never catch.
* Automated acceptance tests deliver business value the users are expecting as they test user scenarios.
* Automated acceptance tests executed and passed on every build help improve the software delivery process.
* Testers, developers, and customers need to work closely to create suitable automated acceptance test suites.
### How to define Acceptance Test
The best way to define AT is by starting from the user stories and think about all positive and negative scenarios a user can perform.
Product Developers should collaborate with stakeholders to define AT. Functional experts and business users are both needed for defining AT.
A good pattern for defining AT is listing scenarios with [GIVEN-WHEN-THEN](https://martinfowler.com/bliki/GivenWhenThen.html) format where:
* **GIVEN**: A set of initial circumstances (e.g. bank balance)
* **WHEN**: Some event happens (e.g. customer attempts a transfer)
* **THEN**: The expected result as per the defined behavior of the system
In other words: we define a use case input, current state and the expected outcome. Example:
> Feature: User trades stocks.
> Scenario: User requests a sell before close of trading
>
> Given I have 100 shares of MSFT stock
> And I have 150 shares of APPL stock
> And the time is before close of trading
>
> When I ask to sell 20 shares of MSFT stock
>
> Then I should have 80 shares of MSFT stock
> And I should have 150 shares of APPL stock
> And a sell order for 20 shares of MSFT stock should have been executed
*Reference: [writing acceptance tests](https://openclassrooms.com/en/courses/4544611-write-agile-documentation-user-stories-acceptance-tests/4810081-writing-acceptance-tests)*.
### How and where to add acceptance tests
Acceptance tests are written in the Markdown format, using the scenario template described above, and be part of the specification (`xx_test.md` file in *spec* directory). Example: [`eco-credits/spec/06.test.md`](https://github.com/regen-network/regen-ledger/blob/7297783577e6cd102c5093365b573163680f36a1/x/ecocredit/spec/06_tests.md).
Acceptance tests should be defined during the design phase or at an early stage of development. Moreover, they should be defined before writing a module architecture - it will clarify the purpose and usage of the software.
Automated tests should cover all acceptance tests scenarios.
## Automated Tests
Make sure your code is well tested:
* Provide unit tests for every unit of your code if possible. Unit tests are expected to comprise 70%-80% of your tests.
* Describe the test scenarios you are implementing for integration tests.
* Create integration tests for queries and msgs.
* Use both test cases and property / fuzzy testing. We use the [rapid](pgregory.net/rapid) Go library for property-based and fuzzy testing.
* Do not decrease code test coverage. Explain in a PR if test coverage is decreased.
We expect tests to use `require` or `assert` rather than `t.Skip` or `t.Fail`,
unless there is a reason to do otherwise.
When testing a function under a variety of different inputs, we prefer to use
[table driven tests](https://github.com/golang/go/wiki/TableDrivenTests).
Table driven test error messages should follow the following format
`<desc>, tc #<index>, i #<index>`.
`<desc>` is an optional short description of whats failing, `tc` is the
index within the test case table that is failing, and `i` is when there
is a loop, exactly which iteration of the loop failed.
The idea is you should be able to see the
error message and figure out exactly what failed.
Here is an example check:
```go
<some table>
for tcIndex, tc := range cases {
<some code>
resp, err := doSomething()
require.NoError(err)
require.Equal(t, tc.expected, resp, "should correctly perform X")
```
## Quality Assurance
We are forming a QA team that will support the core Cosmos SDK team and collaborators by:
* Improving the Cosmos SDK QA Processes
* Improving automation in QA and testing
* Defining high-quality metrics
* Maintaining and improving testing frameworks (unit tests, integration tests, and functional tests)
* Defining test scenarios.
* Verifying user experience and defining a high quality.
* We want to have **acceptance tests**! Document and list acceptance lists that are implemented and identify acceptance tests that are still missing.
* Acceptance tests should be specified in `acceptance-tests` directory as Markdown files.
* Supporting other teams with testing frameworks, automation, and User Experience testing.
* Testing chain upgrades for every new breaking change.
* Defining automated tests that assure data integrity after an update.
Desired outcomes:
* QA team works with Development Team.
* QA is happening in parallel with Core Cosmos SDK development.
* Releases are more predictable.
* QA reports. Goal is to guide with new tasks and be one of the QA measures.
As a developer, you must help the QA team by providing instructions for User Experience (UX) and functional testing.
### QA Team to cross check Acceptance Tests
Once the AT are defined, the QA team will have an overview of the behavior a user can expect and:
* validate the user experience will be good
* validate the implementation conforms the acceptance tests
* by having a broader overview of the use cases, QA team should be able to define **test suites** and test data to efficiently automate Acceptance Tests and reuse the work.

355
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,355 @@
# Contributing
* [Teams Dev Calls](#teams-dev-calls)
* [Architecture Decision Records (ADR)](#architecture-decision-records-adr)
* [Development Procedure](#development-procedure)
* [Testing](#testing)
* [Pull Requests](#pull-requests)
* [Pull Request Templates](#pull-request-templates)
* [Requesting Reviews](#requesting-reviews)
* [Updating Documentation](#updating-documentation)
* [RFC & ADR](#RFC & ADR)
* [Dependencies](#dependencies)
* [`go.work`](#gowork)
* [`go.mod`](#gomod)
* [Protobuf](#protobuf)
* [Branching Model and Release](#branching-model-and-release)
* [PR Targeting](#pr-targeting)
* [Code Owner Membership](#code-owner-membership)
* [Concept & Feature Approval Process](#concept--feature-approval-process)
* [Strategy Discovery](#strategy-discovery)
* [Concept Approval](#concept-approval)
* [Time Bound Period](#time-bound-period)
* [Approval Committee & Decision Making](#approval-committee--decision-making)
* [Committee Members](#committee-members)
* [Committee Criteria](#committee-criteria)
* [Implementation & Release Approval](#implementation--release-approval)
Thank you for considering making contributions to the Cosmos SDK and related repositories!
Contributing to this repo can mean many things, such as participating in
discussion or proposing code changes. To ensure a smooth workflow for all
contributors, the general procedure for contributing has been established:
1. Start by browsing [new issues](https://github.com/cosmos/cosmos-sdk/issues) and [discussions](https://github.com/cosmos/cosmos-sdk/discussions). If you are looking for something interesting or if you have something in your mind, there is a chance it had been discussed.
* Looking for a good place to start contributing? How about checking out some [good first issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [bugs](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Bug%22)?
2. Determine whether a GitHub issue or discussion is more appropriate for your needs:
1. If want to propose something new that requires specification or an additional design, or you would like to change a process, start with a [new discussion](https://github.com/cosmos/cosmos-sdk/discussions/new). With discussions, we can better handle the design process using discussion threads. A discussion usually leads to one or more issues.
2. If the issue you want addressed is a specific proposal or a bug, then open a [new issue](https://github.com/cosmos/cosmos-sdk/issues/new/choose).
3. Review existing [issues](https://github.com/cosmos/cosmos-sdk/issues) to find an issue you'd like to help with.
3. Participate in thoughtful discussion on that issue.
4. If you would like to contribute:
1. Ensure that the proposal has been accepted.
2. Ensure that nobody else has already begun working on this issue. If they have,
make sure to contact them to collaborate.
3. If nobody has been assigned for the issue and you would like to work on it,
make a comment on the issue to inform the community of your intentions
to begin work.
5. To submit your work as a contribution to the repository follow standard GitHub best practices. See [pull request guideline](#pull-requests) below.
**Note:** For very small or blatantly obvious problems such as typos, you are
not required to an open issue to submit a PR, but be aware that for more complex
problems/features, if a PR is opened before an adequate design discussion has
taken place in a GitHub issue, that PR runs a high likelihood of being rejected.
## Teams Dev Calls
The Cosmos SDK has many stakeholders contributing and shaping the project. The Core SDK team is composed of Interchain GmbH and Regen Network Development developers. Any long-term contributors and additional maintainers from other projects are welcome. We use self-organizing principles to coordinate and collaborate across organizations in structured "EPIC" that focus on specific problem domains or architectural components of the Cosmos SDK.
The developers work in sprints, which are available in a [GitHub Project](https://github.com/orgs/cosmos/projects/26/views/22). The current EPICs are pinned at the top of the [issues list](https://github.com/cosmos/cosmos-sdk/issues).
The important development announcements are shared on [Discord](https://discord.com/invite/cosmosnetwork) in the `#dev-announcements` channel.
To synchronize we have few major meetings:
* Cosmos SDK Sprint Review on Monday and Thursday at 14:00 UTC (limited participation to core devs).
* Cosmos SDK Community Call on Thursday at 16:00 UTC.
If you would like to join one of the community call, then please contact us on [Discord](https://discord.com/invite/cosmosnetwork) or reach out directly to Marko (@tac0turtle).
## Architecture Decision Records (ADR)
When proposing an architecture decision for the Cosmos SDK, please start by opening an [issue](https://github.com/cosmos/cosmos-sdk/issues/new/choose) or a [discussion](https://github.com/cosmos/cosmos-sdk/discussions/new) with a summary of the proposal. Once the proposal has been discussed and there is rough alignment on a high-level approach to the design, the [ADR creation process](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/PROCESS.md) can begin. We are following this process to ensure all involved parties are in agreement before any party begins coding the proposed implementation. If you would like to see examples of how these are written, please refer to the current [ADRs](https://github.com/cosmos/cosmos-sdk/tree/main/docs/architecture).
## Development Procedure
* The latest state of development is on `main`.
* `main` must never fail `make lint test test-race`.
* No `--force` onto `main` (except when reverting a broken commit, which should seldom happen).
* Create a branch to start work:
* Fork the repo (core developers must create a branch directly in the Cosmos SDK repo),
branch from the HEAD of `main`, make some commits, and submit a PR to `main`.
* For core developers working within the `cosmos-sdk` repo, follow branch name conventions to ensure a clear
ownership of branches: `{moniker}/{issue#}-branch-name`.
* See [Branching Model](#branching-model-and-release) for more details.
* Be sure to run `make format` before every commit. The easiest way
to do this is have your editor run it for you upon saving a file (most of the editors
will do it anyway using a pre-configured setup of the programming language mode).
Additionally, be sure that your code is lint compliant by running `make lint-fix`.
A convenience git `pre-commit` hook that runs the formatters automatically
before each commit is available in the `contrib/githooks/` directory.
* Follow the [CODING GUIDELINES](CODING_GUIDELINES.md), which defines criteria for designing and coding a software.
Code is merged into main through pull request procedure.
### Testing
Tests can be executed by running `make test` at the top level of the Cosmos SDK repository.
### Pull Requests
Before submitting a pull request:
* merge the latest main `git merge origin/main`,
* run `make lint test` to ensure that all checks and tests pass.
Then:
1. If you have something to show, **start with a `Draft` PR**. It's good to have early validation of your work and we highly recommend this practice. A Draft PR also indicates to the community that the work is in progress.
Draft PRs also helps the core team provide early feedback and ensure the work is in the right direction.
2. When the code is complete, change your PR from `Draft` to `Ready for Review`.
3. Go through the actions for each checkbox present in the PR template description. The PR actions are automatically provided for each new PR.
4. Be sure to include a relevant changelog entry in the `Unreleased` section of `CHANGELOG.md` (see file for log format). The entry should be on top of all others changes in the section.
PRs must have a category prefix that is based on the type of changes being made (for example, `fix`, `feat`,
`refactor`, `docs`, and so on). The *type* must be included in the PR title as a prefix (for example,
`fix: <description>`). This convention ensures that all changes that are committed to the base branch follow the
[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
Additionally, each PR should only address a single issue.
Pull requests are merged automatically using [`A:automerge` action](https://docs.mergify.com/workflow/automerge/).
NOTE: when merging, GitHub will squash commits and rebase on top of the main.
### Pull Request Templates
There are three PR templates. The [default template](./.github/PULL_REQUEST_TEMPLATE.md) is for types `fix`, `feat`, and `refactor`. We also have a [docs template](./.github/PULL_REQUEST_TEMPLATE/docs.md) for documentation changes and an [other template](./.github/PULL_REQUEST_TEMPLATE/other.md) for changes that do not affect production code. When previewing a PR before it has been opened, you can change the template by adding one of the following parameters to the url:
* `template=docs.md`
* `template=other.md`
### Requesting Reviews
In order to accommodate the review process, the author of the PR must complete the author checklist
(from the pull request template)
to the best of their abilities before marking the PR as "Ready for Review". If you would like to
receive early feedback on the PR, open the PR as a "Draft" and leave a comment in the PR indicating
that you would like early feedback and tagging whoever you would like to receive feedback from.
Codeowners are marked automatically as the reviewers.
All PRs require at least two review approvals before they can be merged (one review might be acceptable in
the case of minor changes to [docs](./.github/PULL_REQUEST_TEMPLATE/docs.md) or [other](./.github/PULL_REQUEST_TEMPLATE/other.md) changes that do not affect production code). Each PR template has a reviewers checklist that must be completed before the PR can be merged. Each reviewer is responsible
for all checked items unless they have indicated otherwise by leaving their handle next to specific
items. In addition, use the following review explanations:
* `LGTM` without an explicit approval means that the changes look good, but you haven't thoroughly reviewed the reviewer checklist items.
* `Approval` means that you have completed some or all of the reviewer checklist items. If you only reviewed selected items, you must add your handle next to the items that you have reviewed. In addition, follow these guidelines:
* You must also think through anything which ought to be included but is not
* You must think through whether any added code could be partially combined (DRYed) with existing code
* You must think through any potential security issues or incentive-compatibility flaws introduced by the changes
* Naming must be consistent with conventions and the rest of the codebase
* Code must live in a reasonable location, considering dependency structures (for example, not importing testing modules in production code, or including example code modules in production code).
* If you approve the PR, you are responsible for any issues mentioned here and any issues that should have been addressed after thoroughly reviewing the reviewer checklist items in the pull request template.
* If you sat down with the PR submitter and did a pairing review, add this information in the `Approval` or your PR comments.
* If you are only making "surface level" reviews, submit notes as a `comment` review.
### Updating Documentation
If you open a PR on the Cosmos SDK, it is mandatory to update the relevant documentation in `/docs`.
* If your change relates to the core SDK (baseapp, store, ...), be sure to update the content in `docs/basics/`, `docs/core/` and/or `docs/building-modules/` folders.
* If your changes relate to the core of the CLI (not specifically to module's CLI/Rest), then modify the content in the `docs/run-node/` folder.
* If your changes relate to a module, then be sure to update the module's spec in `x/{moduleName}/README.md`.
When writing documentation, follow the [Documentation Writing Guidelines](./docs/DOC_WRITING_GUIDELINES.md).
### RFC & ADR
Within the Cosmos SDK we have two forms of documenting decisions, Request For Comment (RFC) & Architecture Design Record (ADR). They perform two different functions. The process for assessing if something needs an RFC is located in the respective folders:
* [RFC Process](./docs/rfc/process.md)
* [ADR Process](./docs/adr/process.md)
## Dependencies
We use [Go Modules](https://github.com/golang/go/wiki/Modules) to manage
dependency versions.
The main branch of every Cosmos repository should just build with `go get`,
which means they should be kept up-to-date with their dependencies, so we can
get away with telling people they can just `go get` our software.
Since some dependencies are not under our control, a third party may break our
build, in which case we can fall back on `go mod tidy -v`.
### `go.mod`
When extracting a package to its own go modules, some extra steps are required, for keeping our CI checks and Dev UX:
* Add a CHANGELOG.md / README.md under the new package folder
* Add the package in [`labeler.yml`](./.github/labeler.yml)
* Add weekly dependabot checks (see [dependabot.yml](./.github/dependabot.yml))
* Add tests to github workflow [test.yml](.github/workflows/test.yml) (under submodules)
* (optional) Configure a `cosmossdk.io` vanity url by submitting a PR to [cosmos/vanity](https://github.com/cosmos/vanity).
## Protobuf
We use [Protocol Buffers](https://developers.google.com/protocol-buffers) along with [gogoproto](https://github.com/cosmos/gogoproto) to generate code for use in Cosmos SDK.
For deterministic behavior around Protobuf tooling, everything is containerized using Docker. Make sure to have Docker installed on your machine, or head to [Docker's website](https://docs.docker.com/get-docker/) to install it.
For formatting code in `.proto` files, you can run `make proto-format` command.
For linting and checking breaking changes, we use [buf](https://buf.build/). You can use the commands `make proto-lint` and `make proto-check-breaking` to respectively lint your proto files and check for breaking changes.
To generate the protobuf stubs, you can run `make proto-gen`.
We also added the `make proto-all` command to run all the above commands sequentially.
In order for imports to properly compile in your IDE, you may need to manually set your protobuf path in your IDE's workspace settings/config.
For example, in vscode your `.vscode/settings.json` should look like:
```json
{
"protoc": {
"options": [
"--proto_path=${workspaceRoot}/proto",
]
}
}
```
## Branching Model and Release
User-facing repos should adhere to the trunk based development branching model: https://trunkbaseddevelopment.com. User branches should start with a user name, example: `{moniker}/{issue#}-branch-name`.
The Cosmos SDK repository is a [multi Go module](https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository) repository. It means that we have more than one Go module in a single repository.
The Cosmos SDK utilizes [semantic versioning](https://semver.org/).
### PR Targeting
Ensure that you base and target your PR on the `main` branch.
All feature additions and all bug fixes must be targeted against `main`. Exception is for bug fixes which are only related to a released version. In that case, the related bug fix PRs must target against the release branch.
If needed, we backport a commit from `main` to a release branch (excluding consensus breaking feature, API breaking and similar).
## Code Owner Membership
In the ethos of open-source projects, and out of necessity to keep the code
alive, the core contributor team will strive to permit special repo privileges
to developers who show an aptitude towards developing with this code base.
Several different kinds of privileges may be granted however most common
privileges to be granted are merge rights to either part of, or the entirety of the
code base (through the GitHub `CODEOWNERS` file). The on-boarding process for
new code owners is as follows: On a bi-monthly basis (or more frequently if
agreeable) all the existing code owners will privately convene to discuss
potential new candidates as well as the potential for existing code-owners to
exit or "pass on the torch". This private meeting is to be a held as a
phone/video meeting.
Subsequently after the meeting, and pending final approval from the ICF,
one of the existing code owners should open a PR modifying the `CODEOWNERS` file.
The other code owners should then all approve this PR to publicly display their support.
Only if unanimous consensus is reached among all the existing code-owners will
an invitation be extended to a new potential-member. Likewise, when an existing
member is suggested to be removed/or have their privileges reduced, the member
in question must agree to the decision for their removal or else no action
should be taken. If however, a code-owner is demonstrably shown to intentionally
have had acted maliciously or grossly negligent, code-owner privileges may be
stripped with no prior warning or consent from the member in question.
Other potential removal criteria:
* Missing 3 scheduled meetings results in ICF evaluating whether the member should be
removed / replaced
* Violation of Code of Conduct
Earning this privilege should be considered to be no small feat and is by no
means guaranteed by any quantifiable metric. Serving as a code owner is a symbol of great trust from
the community of this project.
## Concept & Feature Approval Process
The process for how Cosmos SDK maintainers take features and ADRs from concept to release
is broken up into three distinct stages: **Strategy Discovery**, **Concept Approval**, and
**Implementation & Release Approval**
### Strategy Discovery
* Develop long term priorities, strategy and roadmap for the Cosmos SDK
* Release committee not yet defined as there is already a roadmap that can be used for the time being
### Concept Approval
* Architecture Decision Records (ADRs) may be proposed by any contributors or maintainers of the Cosmos SDK,
and should follow the guidelines outlined in the
[ADR Creation Process](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/PROCESS.md)
* After proposal, a time bound period for Request for Comment (RFC) on ADRs commences
* ADRs are intended to be iterative, and may be merged into `main` while still in a `Proposed` status
#### Time Bound Period
* Once a PR for an ADR is opened, reviewers are expected to perform a first review within 1 week of pull request being open
* Time bound period for individual ADR Pull Requests to be merged should not exceed 2 weeks
* Total time bound period for an ADR to reach a decision (`ABANDONED | ACCEPTED | REJECTED`) should not exceed 4 weeks
If an individual Pull Request for an ADR needs more time than 2 weeks to reach resolution, it should be merged
in current state (`Draft` or `Proposed`), with its contents updated to summarize
the current state of its discussion.
If an ADR is taking longer than 4 weeks to reach a final conclusion, the **Concept Approval Committee**
should convene to rectify the situation by either:
* unanimously setting a new time bound period for this ADR
* making changes to the Concept Approval Process (as outlined here)
* making changes to the members of the Concept Approval Committee
#### Approval Committee & Decision Making
In absence of general consensus, decision making requires 1/2 vote from the two members
of the **Concept Approval Committee**.
#### Committee Members
* Core Members: **Aaron** (Regen), **Bez** (IG)
#### Committee Criteria
Members must:
* Participate in all or almost all ADR discussions, both on GitHub as well as in bi-weekly Architecture Review
meetings
* Be active contributors to the Cosmos SDK, and furthermore should be continuously making substantial contributions
to the project's codebase, review process, documentation and ADRs
* Have stake in the Cosmos SDK project, represented by:
* Being a client / user of the Comsos SDK
* "[giving back](https://www.debian.org/social_contract)" to the software
* Delegate representation in case of vacation or absence
Code owners need to maintain participation in the process, ideally as members of **Concept Approval Committee**
members, but at the very least as active participants in ADR discussions
Removal criteria:
* Missing 3 meetings results in ICF evaluating whether the member should be removed / replaced
* Violation of Code of Conduct
### Implementation & Release Approval
The following process should be adhered to both for implementation PRs corresponding to ADRs, as
well as for PRs made as part of a release process:
* Code reviewers should ensure the PR does exactly what the ADR said it should
* Code reviewers should have more senior engineering capability
* 1/2 approval is required from the **primary repo maintainers** in `CODEOWNERS`
**Note**: For any major release series denoted as a "Stable Release" (e.g. v0.42 "Stargate"), a separate release
committee is often established. Stable Releases, and their corresponding release committees are documented
separately in [Stable Release Policy](./RELEASE_PROCESS.md#stable-release-policy)*

55
Dockerfile Normal file
View file

@ -0,0 +1,55 @@
# Simple usage with a mounted data directory:
# > docker build -t simapp .
#
# Server:
# > docker run -it -p 26657:26657 -p 26656:26656 -v ~/.simapp:/root/.simapp simapp simd init test-chain
# TODO: need to set validator in genesis so start runs
# > docker run -it -p 26657:26657 -p 26656:26656 -v ~/.simapp:/root/.simapp simapp simd start
#
# Client: (Note the simapp binary always looks at ~/.simapp we can bind to different local storage)
# > docker run -it -p 26657:26657 -p 26656:26656 -v ~/.simappcli:/root/.simapp simapp simd keys add foo
# > docker run -it -p 26657:26657 -p 26656:26656 -v ~/.simappcli:/root/.simapp simapp simd keys list
#
# This image is pushed to the GHCR as https://ghcr.io/cosmos/simapp
FROM golang:1.25-alpine AS build-env
# Install minimum necessary dependencies
ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev
RUN apk add --no-cache $PACKAGES
# Set working directory for the build
WORKDIR /go/src/github.com/cosmos/cosmos-sdk
# optimization: if go.sum didn't change, docker will use cached image
COPY go.mod go.sum ./
COPY collections/go.mod collections/go.sum ./collections/
COPY store/go.mod store/go.sum ./store/
COPY log/go.mod log/go.sum ./log/
RUN go mod download
# Add source files
COPY . .
# Dockerfile Cross-Compilation Guide
# https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide
ARG TARGETOS TARGETARCH
# install simapp, remove packages
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH make build
# Use alpine:3 as a base image
FROM alpine:3
EXPOSE 26656 26657 1317 9090
# Run simd by default, omit entrypoint to ease using container with simcli
CMD ["simd"]
STOPSIGNAL SIGTERM
WORKDIR /root
# Install minimum necessary dependencies
RUN apk add --no-cache curl make bash jq sed
# Copy over binaries from the build-env
COPY --from=build-env /go/src/github.com/cosmos/cosmos-sdk/build/simd /usr/bin/simd

674
LICENSE Normal file
View file

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

536
Makefile Normal file
View file

@ -0,0 +1,536 @@
#!/usr/bin/make -f
PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation')
PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation')
# Ensure all tags are fetched
VERSION_RAW := $(shell git fetch --tags --force >/dev/null 2>&1; git describe --tags --always --match "v*")
VERSION := $(shell echo $(VERSION_RAW) | sed -E 's/^v?([0-9]+\.[0-9]+\.[0-9]+.*)/\1/')
# Fallback if the version is just a commit hash (not semver-like)
ifeq ($(findstring -,$(VERSION)),) # No "-" means it's just a hash
VERSION := 0.0.0-$(VERSION_RAW)
endif
export VERSION
export CMTVERSION := $(shell go list -m github.com/cometbft/cometbft | sed 's:.* ::')
export COMMIT := $(shell git log -1 --format='%H')
LEDGER_ENABLED ?= true
BINDIR ?= $(GOPATH)/bin
BUILDDIR ?= $(CURDIR)/build
SIMAPP = ./simapp
MOCKS_DIR = $(CURDIR)/tests/mocks
HTTPS_GIT := https://github.com/cosmos/cosmos-sdk.git
DOCKER := $(shell which docker)
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
# process build tags
build_tags = netgo
ifeq ($(LEDGER_ENABLED),true)
ifeq ($(OS),Windows_NT)
GCCEXE = $(shell where gcc.exe 2> NUL)
ifeq ($(GCCEXE),)
$(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false)
else
build_tags += ledger
endif
else
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S),OpenBSD)
$(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988))
else
GCC = $(shell command -v gcc 2> /dev/null)
ifeq ($(GCC),)
$(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false)
else
build_tags += ledger
endif
endif
endif
endif
ifeq (secp,$(findstring secp,$(COSMOS_BUILD_OPTIONS)))
build_tags += libsecp256k1_sdk
endif
ifeq (legacy,$(findstring legacy,$(COSMOS_BUILD_OPTIONS)))
build_tags += app_v1
endif
whitespace :=
whitespace += $(whitespace)
comma := ,
build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags))
# process linker flags
ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=sim \
-X github.com/cosmos/cosmos-sdk/version.AppName=simd \
-X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" \
-X github.com/cometbft/cometbft/version.TMCoreSemVer=$(CMTVERSION)
# DB backend selection
ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS)))
build_tags += gcc
endif
ifeq (badgerdb,$(findstring badgerdb,$(COSMOS_BUILD_OPTIONS)))
build_tags += badgerdb
endif
# handle rocksdb
ifeq (rocksdb,$(findstring rocksdb,$(COSMOS_BUILD_OPTIONS)))
CGO_ENABLED=1
build_tags += rocksdb
endif
# handle boltdb
ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS)))
build_tags += boltdb
endif
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
ldflags += -w -s
endif
ldflags += $(LDFLAGS)
ldflags := $(strip $(ldflags))
build_tags += $(BUILD_TAGS)
build_tags := $(strip $(build_tags))
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
# check for nostrip option
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -trimpath
endif
# Check for debug option
ifeq (debug,$(findstring debug,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -gcflags "all=-N -l"
endif
all: tools build lint test vulncheck
###############################################################################
### Build ###
###############################################################################
BUILD_TARGETS := build install
build: BUILD_ARGS=-o $(BUILDDIR)/
build-linux-amd64:
GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false $(MAKE) build
build-linux-arm64:
GOOS=linux GOARCH=arm64 LEDGER_ENABLED=false $(MAKE) build
$(BUILD_TARGETS): go.sum $(BUILDDIR)/
cd ${CURRENT_DIR}/simapp && go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./...
$(BUILDDIR)/:
mkdir -p $(BUILDDIR)/
cosmovisor:
$(MAKE) -C tools/cosmovisor cosmovisor
confix:
$(MAKE) -C tools/confix confix
hubl:
$(MAKE) -C tools/hubl hubl
.PHONY: build build-linux-amd64 build-linux-arm64 cosmovisor confix
#? mocks: Generate mock file
mocks: $(MOCKS_DIR)
@go install go.uber.org/mock/mockgen@v0.5.0
sh ./scripts/mockgen.sh
.PHONY: mocks
vulncheck: $(BUILDDIR)/
GOBIN=$(BUILDDIR) go install golang.org/x/vuln/cmd/govulncheck@latest
$(BUILDDIR)/govulncheck ./...
$(MOCKS_DIR):
mkdir -p $(MOCKS_DIR)
distclean: clean tools-clean
clean:
rm -rf \
$(BUILDDIR)/ \
artifacts/ \
tmp-swagger-gen/ \
.testnets
.PHONY: distclean clean
###############################################################################
### Tools & Dependencies ###
###############################################################################
go.sum: go.mod
echo "Ensure dependencies have not been modified ..." >&2
go mod verify
go mod tidy
###############################################################################
### Documentation ###
###############################################################################
godocs:
@echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/cosmos-sdk/types"
go install golang.org/x/tools/cmd/godoc@latest
godoc -http=:6060
build-docs:
@cd docs && DOCS_DOMAIN=docs.cosmos.network sh ./build-all.sh
.PHONY: build-docs
###############################################################################
### Tests & Simulation ###
###############################################################################
# make init-simapp initializes a single local node network
# it is useful for testing and development
# Usage: make install && make init-simapp && simd start
# Warning: make init-simapp will remove all data in simapp home directory
init-simapp:
./scripts/init-simapp.sh
test: test-unit
test-e2e:
$(MAKE) -C tests test-e2e
test-e2e-cov:
$(MAKE) -C tests test-e2e-cov
test-integration:
$(MAKE) -C tests test-integration
test-integration-cov:
$(MAKE) -C tests test-integration-cov
test-all: test-unit test-e2e test-integration test-ledger-mock test-race
TEST_PACKAGES=./...
TEST_TARGETS := test-unit test-unit-amino test-unit-proto test-ledger-mock test-race test-ledger test-race
# Test runs-specific rules. To add a new test target, just add
# a new rule, customise ARGS or TEST_PACKAGES ad libitum, and
# append the new rule to the TEST_TARGETS list.
test-unit: test_tags += cgo ledger test_ledger_mock norace
test-unit-amino: test_tags += ledger test_ledger_mock test_amino norace
test-ledger: test_tags += cgo ledger norace
test-ledger-mock: test_tags += ledger test_ledger_mock norace
test-race: test_tags += cgo ledger test_ledger_mock
test-race: ARGS=-race
test-race: TEST_PACKAGES=$(PACKAGES_NOSIMULATION)
$(TEST_TARGETS): run-tests
# check-* compiles and collects tests without running them
# note: go test -c doesn't support multiple packages yet (https://github.com/golang/go/issues/15513)
CHECK_TEST_TARGETS := check-test-unit check-test-unit-amino
check-test-unit: test_tags += cgo ledger test_ledger_mock norace
check-test-unit-amino: test_tags += ledger test_ledger_mock test_amino norace
$(CHECK_TEST_TARGETS): EXTRA_ARGS=-run=none
$(CHECK_TEST_TARGETS): run-tests
ARGS += -tags "$(test_tags)"
SUB_MODULES = $(shell find . -type f -name 'go.mod' -print0 | xargs -0 -n1 dirname | sort | grep -v './tests/systemtests')
CURRENT_DIR = $(shell pwd)
run-tests:
@(cd store/streaming/abci/examples/file && go build .)
ifneq (,$(shell which tparse 2>/dev/null))
@echo "Starting unit tests"; \
finalec=0; \
for module in $(SUB_MODULES); do \
cd ${CURRENT_DIR}/$$module; \
echo "Running unit tests for $$(grep '^module' go.mod)"; \
go test -mod=readonly -json $(ARGS) $(TEST_PACKAGES) ./... | tparse; \
ec=$$?; \
if [ "$$ec" -ne '0' ]; then finalec=$$ec; fi; \
done; \
exit $$finalec
else
@echo "Starting unit tests"; \
finalec=0; \
for module in $(SUB_MODULES); do \
cd ${CURRENT_DIR}/$$module; \
echo "Running unit tests for $$(grep '^module' go.mod)"; \
go test -mod=readonly $(ARGS) $(TEST_PACKAGES) ./... ; \
ec=$$?; \
if [ "$$ec" -ne '0' ]; then finalec=$$ec; fi; \
done; \
exit $$finalec
endif
.PHONY: run-tests test test-all $(TEST_TARGETS)
test-sim-nondeterminism:
@echo "Running non-determinism test..."
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout=30m -tags='sims' -run TestAppStateDeterminism \
-NumBlocks=100 -BlockSize=200 -Period=0
# Requires an exported plugin. See store/streaming/README.md for documentation.
#
# example:
# export COSMOS_SDK_ABCI_V1=<path-to-plugin-binary>
# make test-sim-nondeterminism-streaming
#
# Using the built-in examples:
# export COSMOS_SDK_ABCI_V1=<path-to-sdk>/store/streaming/abci/examples/file/file
# make test-sim-nondeterminism-streaming
test-sim-nondeterminism-streaming:
@echo "Running non-determinism-streaming test..."
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout=30m -tags='sims' -run TestAppStateDeterminism \
-NumBlocks=100 -BlockSize=200 -Period=0 -EnableStreaming=true
test-sim-custom-genesis-fast:
@echo "Running custom genesis simulation..."
@echo "By default, ${HOME}/.simapp/config/genesis.json will be used."
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout=30m -tags='sims' -run TestFullAppSimulation -Genesis=${HOME}/.simapp/config/genesis.json \
-NumBlocks=100 -BlockSize=200 -Seed=99 -Period=5 -SigverifyTx=false
test-sim-import-export:
@echo "Running application import/export simulation. This may take several minutes..."
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout 20m -tags='sims' -run TestAppImportExport \
-NumBlocks=50 -Period=5
test-sim-after-import:
@echo "Running application simulation-after-import. This may take several minutes..."
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout 30m -tags='sims' -run TestAppSimulationAfterImport \
-NumBlocks=50 -Period=5
test-sim-custom-genesis-multi-seed:
@echo "Running multi-seed custom genesis simulation..."
@echo "By default, ${HOME}/.simapp/config/genesis.json will be used."
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout 30m -tags='sims' -run TestFullAppSimulation -Genesis=${HOME}/.simapp/config/genesis.json \
-NumBlocks=400 -Period=5
test-sim-multi-seed-long:
@echo "Running long multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout=1h -tags='sims' -run TestFullAppSimulation \
-NumBlocks=500 -Period=50
test-sim-multi-seed-short:
@echo "Running short multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout 30m -tags='sims' -run TestFullAppSimulation \
-NumBlocks=50 -Period=10
.PHONY: \
test-sim-nondeterminism \
test-sim-nondeterminism-streaming \
test-sim-custom-genesis-fast \
test-sim-import-export \
test-sim-after-import \
test-sim-custom-genesis-multi-seed \
test-sim-multi-seed-short \
test-sim-multi-seed-long
SIM_NUM_BLOCKS ?= 500
SIM_BLOCK_SIZE ?= 200
SIM_COMMIT ?= true
#? test-sim-fuzz: Run fuzz test for simapp
test-sim-fuzz:
@echo "Running application fuzz for numBlocks=2, blockSize=20. This may take awhile!"
#ld flags are a quick fix to make it work on current osx
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -json -tags='sims' -ldflags="-extldflags=-Wl,-ld_classic" -timeout=60m -fuzztime=60m -run=^$$ -fuzz=FuzzFullAppSimulation -GenesisTime=1714720615 -NumBlocks=2 -BlockSize=20
#? test-sim-benchmark: Run benchmark test for simapp
test-sim-benchmark:
@echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -tags='sims' -run=^$$ $(.) -bench ^BenchmarkFullAppSimulation$$ \
-NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -Seed=57 -timeout 30m
# Requires an exported plugin. See store/streaming/README.md for documentation.
#
# example:
# export COSMOS_SDK_ABCI_V1=<path-to-plugin-binary>
# make test-sim-benchmark-streaming
#
# Using the built-in examples:
# export COSMOS_SDK_ABCI_V1=<path-to-sdk>/store/streaming/abci/examples/file/file
# make test-sim-benchmark-streaming
test-sim-benchmark-streaming:
@echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -run=^$$ $(.) -bench ^BenchmarkFullAppSimulation$$ \
-NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -EnableStreaming=true
test-sim-profile:
@echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -benchmem -run=^$$ $(.) -bench ^BenchmarkFullAppSimulation$$ \
-NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
# Requires an exported plugin. See store/streaming/README.md for documentation.
#
# example:
# export COSMOS_SDK_ABCI_V1=<path-to-plugin-binary>
# make test-sim-profile-streaming
#
# Using the built-in examples:
# export COSMOS_SDK_ABCI_V1=<path-to-sdk>/store/streaming/abci/examples/file/file
# make test-sim-profile-streaming
test-sim-profile-streaming:
@echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -benchmem -run=^$$ $(.) -bench ^BenchmarkFullAppSimulation$$ \
-NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out -EnableStreaming=true
.PHONY: test-sim-profile test-sim-benchmark test-sim-fuzz
benchmark:
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
.PHONY: benchmark
###############################################################################
### Linting ###
###############################################################################
golangci_version=v2.6.1
lint-install:
@echo "--> Installing golangci-lint $(golangci_version)"
@go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(golangci_version)
lint:
@echo "--> Running linter on all files"
$(MAKE) lint-install
@./scripts/go-lint-all.bash --timeout=15m
lint-fix:
@echo "--> Running linter"
$(MAKE) lint-install
@./scripts/go-lint-all.bash --fix
.PHONY: lint lint-fix
###############################################################################
### Protobuf ###
###############################################################################
protoVer=0.16.0
protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer)
protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)
proto-all: proto-format proto-lint proto-gen
proto-gen:
@echo "Generating Protobuf files"
@$(protoImage) sh ./scripts/protocgen.sh
proto-swagger-gen:
@echo "Generating Protobuf Swagger"
@$(protoImage) sh ./scripts/protoc-swagger-gen.sh
proto-format:
@$(protoImage) find ./ -name "*.proto" -exec clang-format -i {} \;
proto-lint:
@$(protoImage) buf lint --error-format=json
proto-check-breaking:
@$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main
CMT_URL = https://raw.githubusercontent.com/cometbft/cometbft/v0.38.0/proto/tendermint
CMT_CRYPTO_TYPES = proto/tendermint/crypto
CMT_ABCI_TYPES = proto/tendermint/abci
CMT_TYPES = proto/tendermint/types
CMT_VERSION = proto/tendermint/version
CMT_LIBS = proto/tendermint/libs/bits
CMT_P2P = proto/tendermint/p2p
proto-update-deps:
@echo "Updating Protobuf dependencies"
@mkdir -p $(CMT_ABCI_TYPES)
@curl -sSL $(CMT_URL)/abci/types.proto > $(CMT_ABCI_TYPES)/types.proto
@mkdir -p $(CMT_VERSION)
@curl -sSL $(CMT_URL)/version/types.proto > $(CMT_VERSION)/types.proto
@mkdir -p $(CMT_TYPES)
@curl -sSL $(CMT_URL)/types/types.proto > $(CMT_TYPES)/types.proto
@curl -sSL $(CMT_URL)/types/evidence.proto > $(CMT_TYPES)/evidence.proto
@curl -sSL $(CMT_URL)/types/params.proto > $(CMT_TYPES)/params.proto
@curl -sSL $(CMT_URL)/types/validator.proto > $(CMT_TYPES)/validator.proto
@curl -sSL $(CMT_URL)/types/block.proto > $(CMT_TYPES)/block.proto
@mkdir -p $(CMT_CRYPTO_TYPES)
@curl -sSL $(CMT_URL)/crypto/proof.proto > $(CMT_CRYPTO_TYPES)/proof.proto
@curl -sSL $(CMT_URL)/crypto/keys.proto > $(CMT_CRYPTO_TYPES)/keys.proto
@mkdir -p $(CMT_LIBS)
@curl -sSL $(CMT_URL)/libs/bits/types.proto > $(CMT_LIBS)/types.proto
@mkdir -p $(CMT_P2P)
@curl -sSL $(CMT_URL)/p2p/types.proto > $(CMT_P2P)/types.proto
$(DOCKER) run --rm -v $(CURDIR)/proto:/workspace --workdir /workspace $(protoImageName) buf mod update
.PHONY: proto-all proto-gen proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps
###############################################################################
### Localnet ###
###############################################################################
localnet-build-env:
$(MAKE) -C contrib/images simd-env
localnet-build-dlv:
$(MAKE) -C contrib/images simd-dlv
localnet-build-nodes:
$(DOCKER) run --rm -v $(CURDIR)/.testnets:/data cosmossdk/simd \
testnet init-files --validator-count 4 -o /data --starting-ip-address 192.168.10.2 --keyring-backend=test
docker compose up -d
localnet-stop:
docker compose down
# localnet-start will run a 4-node testnet locally. The nodes are
# based off the docker images in: ./contrib/images/simd-env
localnet-start: localnet-stop localnet-build-env localnet-build-nodes
# localnet-debug will run a 4-node testnet locally in debug mode
# you can read more about the debug mode here: ./contrib/images/simd-dlv/README.md
localnet-debug: localnet-stop localnet-build-dlv localnet-build-nodes
.PHONY: localnet-start localnet-stop localnet-debug localnet-build-env localnet-build-dlv localnet-build-nodes
test-system: build-v50 build
mkdir -p ./tests/systemtests/binaries/
cp $(BUILDDIR)/simd ./tests/systemtests/binaries/
mkdir -p ./tests/systemtests/binaries/v0.50
mv $(BUILDDIR)/simdv50 ./tests/systemtests/binaries/v0.50/simd
$(MAKE) -C tests/systemtests test
.PHONY: test-system
# build-v50 checks out the v0.50.x branch, builds the binary, and renames it to simdv50.
build-v50:
@echo "Starting v50 build process..."
git_status=$$(git status --porcelain) && \
has_changes=false && \
if [ -n "$$git_status" ]; then \
echo "Stashing uncommitted changes..." && \
git stash push -m "Temporary stash for v50 build" && \
has_changes=true; \
else \
echo "No changes to stash"; \
fi && \
echo "Saving current reference..." && \
CURRENT_REF=$$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse HEAD) && \
echo "Checking out release branch..." && \
git checkout release/v0.50.x && \
echo "Building v50 binary..." && \
make build && \
mv build/simd build/simdv50 && \
echo "Returning to original branch..." && \
if [ "$$CURRENT_REF" = "HEAD" ]; then \
git checkout $$(git rev-parse HEAD); \
else \
git checkout $$CURRENT_REF; \
fi && \
if [ "$$has_changes" = "true" ]; then \
echo "Reapplying stashed changes..." && \
git stash pop || echo "Warning: Could not pop stash, your changes may be in the stash list"; \
else \
echo "No changes to reapply"; \
fi
.PHONY: build-v50

33
README.md Normal file
View file

@ -0,0 +1,33 @@
<h1 align="center">
<b>Mukan SDK</b>
</h1>
<p align="center">
A highly customized, sovereign fork of the Cosmos SDK built exclusively for the <b>Mukan Network</b>.
</p>
## Overview
**Mukan SDK** is the core blockchain framework that powers the Mukan Network. It is a deliberate and permanent hard-fork of the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk), surgically modified to enforce the **Fair Birth** and **Zero Initial Supply** consensus rules of the Mukan Network.
### Key Architectural Differences from Cosmos SDK
Unlike standard Cosmos chains which require an initial Proof-of-Stake (PoS) bond to bootstrap the network, the Mukan SDK introduces a fundamental paradigm shift: **"Labor over Capital"**.
- **Zero-Supply Genesis:** Hardcoded bypass of the `IsPositive()` bonding requirements, allowing validators to join the network and produce blocks with exactly `0 UMC`.
- **Labor-Backed Consensus Power:** Modified `TokensToConsensusPower` logic ensuring that validators with `0 UMC` still possess a minimum voting power of `1`, transitioning the early network into a pure Proof-of-Work (PoW) and Proof-of-Justice (PoJ) environment.
- **Phased PoS Activation:** The traditional Proof-of-Stake mechanics are kept dormant until the initial target supply (1000 MC) is mined through the PoJ module.
## Integration
The Mukan SDK is specifically designed to be imported by the `mukan-core` daemon.
```go
replace github.com/cosmos/cosmos-sdk => git.cw.tr/mukan-network/mukan-sdk
```
## License
Mukan SDK is licensed under the **GNU General Public License v3.0 (GPLv3)**. This ensures that any network built on this framework remains open, fair, and prevents corporate monopolization of the code.
*Original Cosmos SDK components remain under their respective Apache 2.0 licenses where applicable, but the Mukan SDK fork as a whole is distributed under GPLv3.*

9
RELEASE_NOTES.md Normal file
View file

@ -0,0 +1,9 @@
# Cosmos SDK v0.53.6 Release Notes
## 🚀 Highlights
This patch release includes minor dependency bumps and functionality additions.
## 📝 Changelog
Check out the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.53.6/CHANGELOG.md) for an exhaustive list of changes or [compare changes](https://github.com/cosmos/cosmos-sdk/compare/v0.53.5...v0.53.6) from the last release.

248
RELEASE_PROCESS.md Normal file
View file

@ -0,0 +1,248 @@
# Release Process
This document outlines the process for releasing a new version of Cosmos SDK, which involves major release and patch releases as well as maintenance for the major release.
> **Note, the Cosmos SDK went directly from v0.47 to v0.50 and skipped the v0.48 and v0.49 versions.**
## Major Release Procedure
A _major release_ is an increment of the first number (eg: `v1.2``v2.0.0`) or the _point number_ (eg: `v1.1.0 → v1.2.0`, also called _point release_). Each major release opens a _stable release series_ and receives updates outlined in the [Major Release Maintenance](#major-release-maintenance)_section.
Before making a new _major_ release we do beta and release candidate releases. For example, for release 1.0.0:
```text
v1.0.0-beta1 → v1.0.0-beta2 → ... → v1.0.0-rc1 → v1.0.0-rc2 → ... → v1.0.0
```
* Release a first beta version on the `main` branch and freeze `main` from receiving any new features. After beta is released, we focus on releasing the release candidate:
* finish audits and reviews
* kick off a large round of simulation testing (e.g. 400 seeds for 2k blocks)
* perform functional tests
* add more tests
* release new beta version as the bugs are discovered and fixed.
* After the team feels that the `main` works fine we create a `release/vY` branch (going forward known a release branch), where `Y` is the version number, with the patch part substituted to `x` (eg: 0.42.x, 1.0.x). Ensure the release branch is protected so that pushes against the release branch are permitted only by the release manager or release coordinator.
* **PRs targeting this branch can be merged _only_ when exceptional circumstances arise**
* update the GitHub mergify integration by adding instructions for automatically backporting commits from `main` to the `release/vY` using the `backport/Y` label.
* In the release branch prepare a new version section in the `CHANGELOG.md`
* All links must point to their respective pull request.
* The `CHANGELOG.md` must contain only the changes of that specific released version. All other changelog entries must be deleted and linked to the `main` branch changelog ([example](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/CHANGELOG.md#previous-versions)).
* Create release notes, in `RELEASE_NOTES.md`, highlighting the new features and changes in the version. This is needed so the bot knows which entries to add to the release page on GitHub.
* Additionally verify that the `UPGRADING.md` file is up to date and contains all the necessary information for upgrading to the new version.
* Remove GitHub workflows that should not be in the release branch
* `deploy-docs.yml`: must be removed to avoid duplicate documentation deployment.
* `test.yml`: All standalone go module tests should be removed (expect `./simapp`, and `./tests` and SDK tests).
* These packages are tracked and tested directly on main.
* `build.yml`: Only the SDK and SimApp needs to be built on release branches.
* Tooling is tracked and tested directly on main.
* Create a new annotated git tag for a release candidate (eg: `git tag -a v1.1.0-rc1`) in the release branch.
* from this point we unfreeze main.
* the SDK teams collaborate and do their best to run testnets in order to validate the release.
* when bugs are found, create a PR for `main`, and backport fixes to the release branch.
* create new release candidate tags after bugs are fixed.
* After the team feels the release branch is stable and everything works, create a full release:
* update `CHANGELOG.md`.
* run `gofumpt -w -l .` to format the code.
* create a new annotated git tag (eg `git -a v1.1.0`) in the release branch.
* Create a GitHub release.
Following _semver_ philosophy, point releases after `v1.0`:
* must not break API
* can break consensus
Before `v1.0`, point release can break both point API and consensus.
## Patch Release Procedure
A _patch release_ is an increment of the patch number (eg: `v1.2.0``v1.2.1`).
**Patch release must not break API nor consensus.**
Updates to the release branch should come from `main` by backporting PRs (usually done by automatic cherry pick followed by a PRs to the release branch). The backports must be marked using `backport/Y` label in PR for main.
It is the PR author's responsibility to fix merge conflicts, update changelog entries, and
ensure CI passes. If a PR originates from an external contributor, a core team member assumes
responsibility to perform this process instead of the original author.
Lastly, it is core team's responsibility to ensure that the PR meets all the SRU criteria.
Point Release must follow the [Stable Release Policy](#stable-release-policy).
After the release branch has all commits required for the next patch release:
* Update `CHANGELOG.md` and `RELEASE_NOTES.md` (if applicable).
* Create a new annotated git tag (eg `git -a v1.1.0`) in the release branch.
* If the release is a submodule update, first go the submodule folder and name the tag prepending the path to the version:
`cd core && git -a core/v1.1.0` or `cd tools/cosmovisor && git -a tools/cosmovisor/v1.4.0`
* Create a GitHub release (if applicable).
## Major Release Maintenance
Major Release series continue to receive bug fixes (released as a Patch Release) until they reach **End Of Life**.
Major Release series is maintained in compliance with the **Stable Release Policy** as described in this document.
Only the following major release series have a stable release status:
* **0.46** is the previous major release and is supported until the release of **0.50.0**. A fairly strict **bugfix-only** rule applies to pull requests that are requested to be included into a not latest stable point-release.
* **0.47** is the last major release and is supported until the release of **0.51.0**.
The SDK team maintains the last two major releases, any other major release is considered to have reached end of life.
The SDK team will not backport any bug fixes to releases that are not supported.
Widely-used (decided at SDK team's discretion) unsupported releases are considered to be in a security maintenance mode. The SDK team will backport security fixes to these releases.
## Stable Release Policy
### Patch Releases
Once a Cosmos-SDK release has been completed and published, updates for it are released under certain circumstances
and must follow the [Patch Release Procedure](CONTRIBUTING.md#branching-model-and-release).
### Rationale
Unlike in-development `main` branch snapshots, **Cosmos SDK** releases are subject to much wider adoption,
and by a significantly different demographic of users. During development, changes in the `main` branch
affect SDK users, application developers, early adopters, and other advanced users that elect to use
unstable experimental software at their own risk.
Conversely, users of a stable release expect a high degree of stability. They build their applications on it, and the
problems they experience with it could be potentially highly disruptive to their projects.
Stable release updates are recommended to the vast majority of developers, and so it is crucial to treat them
with great caution. Hence, when updates are proposed, they must be accompanied by a strong rationale and present
a low risk of regressions, i.e. even one-line changes could cause unexpected regressions due to side effects or
poorly tested code. We never assume that any change, no matter how little or non-intrusive, is completely exempt
of regression risks.
Therefore, the requirements for stable changes are different than those that are candidates to be merged in
the `main` branch. When preparing future major releases, our aim is to design the most elegant, user-friendly and
maintainable SDK possible which often entails fundamental changes to the SDK's architecture design, rearranging and/or
renaming packages as well as reducing code duplication so that we maintain common functions and data structures in one
place rather than leaving them scattered all over the code base. However, once a release is published, the
priority is to minimize the risk caused by changes that are not strictly required to fix qualifying bugs; this tends to
be correlated with minimizing the size of such changes. As such, the same bug may need to be fixed in different
ways in stable releases and `main` branch.
### Migrations
See the SDK's policy on migrations [here](https://docs.cosmos.network/main/migrations/intro).
### What qualifies as a Stable Release Update (SRU)
* **High-impact bugs**
* Bugs that may directly cause a security vulnerability.
* _Severe regressions_ from a Cosmos-SDK's previous release. This includes all sort of issues
that may cause the core packages or the `x/` modules unusable.
* Bugs that may cause **loss of user's data**.
* Other safe cases:
* Bugs which don't fit in the aforementioned categories for which an obvious safe patch is known.
* Relatively small yet strictly non-breaking features with strong support from the community.
* Relatively small yet strictly non-breaking changes that introduce forward-compatible client
features to smoothen the migration to successive releases.
* Relatively small yet strictly non-breaking CLI improvements.
### What does not qualify as SRU
* State machine changes.
* Breaking changes in Protobuf definitions, as specified in [ADR-044](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-044-protobuf-updates-guidelines.md).
* Changes that introduces API breakages (e.g. public functions and interfaces removal/renaming).
* Client-breaking changes in gRPC and HTTP request and response types.
* CLI-breaking changes.
* Cosmetic fixes, such as formatting or linter warning fixes.
### What pull requests will be included in stable point-releases
Pull requests that fix bugs and add features that fall in the following categories do not require a **Stable Release Exception** to be granted to be included in a stable point-release:
* **Severe regressions**.
* Bugs that may cause **client applications** to be **largely unusable**.
* Bugs that may cause **state corruption or data loss**.
* Bugs that may directly or indirectly cause a **security vulnerability**.
* Non-breaking features that are strongly requested by the community.
* Non-breaking CLI improvements that are strongly requested by the community.
### What pull requests will NOT be automatically included in stable point-releases
As rule of thumb, the following changes will **NOT** be automatically accepted into stable point-releases:
* **State machine changes**.
* **Protobug-breaking changes**, as specified in [ADR-044](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-044-protobuf-updates- guidelines.md).
* **Client-breaking changes**, i.e. changes that prevent gRPC, HTTP and RPC clients to continue interacting with the node without any change.
* **API-breaking changes**, i.e. changes that prevent client applications to _build without modifications_ to the client application's source code.
* **CLI-breaking changes**, i.e. changes that require usage changes for CLI users.
In some circumstances, PRs that don't meet the aforementioned criteria might be raised and asked to be granted a _Stable Release Exception_.
### Stable Release Exception - Procedure
1. Check that the bug is either fixed or not reproducible in `main`. It is, in general, not appropriate to release bug fixes for stable releases without first testing them in `main`. Please apply the label [v0.43](https://github.com/cosmos/cosmos-sdk/milestone/26) to the issue.
2. Add a comment to the issue and ensure it contains the following information (see the bug template below):
* **[Impact]** An explanation of the bug on users and justification for backporting the fix to the stable release.
* A **[Test Case]** section containing detailed instructions on how to reproduce the bug.
* A **[Regression Potential]** section with a clear assessment on how regressions are most likely to manifest as a result of the pull request that aims to fix the bug in the target stable release.
3. **Stable Release Managers** will review and discuss the PR. Once _consensus_ surrounding the rationale has been reached and the technical review has successfully concluded, the pull request will be merged in the respective point-release target branch (e.g. `release/v0.43.x`) and the PR included in the point-release's respective milestone (e.g. `v0.43.5`).
#### Stable Release Exception - Bug template
```md
#### Impact
Brief xplanation of the effects of the bug on users and a justification for backporting the fix to the stable release.
#### Test Case
Detailed instructions on how to reproduce the bug on Stargate's most recently published point-release.
#### Regression Potential
Explanation on how regressions might manifest - even if it's unlikely.
It is assumed that stable release fixes are well-tested and they come with a low risk of regressions.
It's crucial to make the effort of thinking about what could happen in case a regression emerges.
```
### Stable Release Managers
The **Stable Release Managers** evaluate and approve or reject updates and backports to Cosmos SDK Stable Release series,
according to the [stable release policy](#stable-release-policy) and [release procedure](#major-release-procedure).
Decisions are made by consensus.
Their responsibilites include:
* Driving the Stable Release Exception process.
* Approving/rejecting proposed changes to a stable release series.
* Executing the release process of stable point-releases in compliance with the [Point Release Procedure](CONTRIBUTING.md).
Currently residing Stable Release Managers:
* @tac0turtle - Marko Baricevic
* @julienrbrt - Julien Robert
## Cosmos SDK Modules
The Cosmos SDK repository is a mono-repo where its Go modules have a different release process and cadence than the Cosmos SDK itself.
There are two types of modules:
1. Modules that import the Cosmos SDK and depend on a specific version of it.
* Modules to be imported in an app (e.g `x/` modules).
* Modules that are not imported into an app and are a standalone module (e.g. `cosmovisor`).
2. Modules that do not depend on the Cosmos SDK.
The same changelog procedure applies to all modules in the Cosmos SDK repository, and must be up-to-date with the latest changes before tagging a module version.
Note: The Cosmos SDK team is in an active process of limiting Go modules that depend on the Cosmos SDK.
### Modules that depend on the Cosmos SDK
The Cosmos SDK team should strive to release modules that depend on the Cosmos SDK at the same time or soon after a major version Cosmos SDK itself.
Those modules can be considered as part of the Cosmos SDK, but features and improvements are released at a different cadence.
* When a module is supposed to be used in an app (e.g `x/` modules), due to the dependency on the SDK, tagging a new version of a module must be done from a Cosmos SDK release branch. A compability matrix must be provided in the `README.md` of that module with the corresponding versions.
* Modules that import the SDK but do not need to be imported in an app (`e.g. cosmovisor`) must be released from the `main` branch and follow the process defined below.
### Modules that do not depend on the Cosmos SDK
Modules that do not depend on the Cosmos SDK can be released at any time from the `main` branch of the Cosmos SDK repository.
#### Branches For Go Modules
Branches that go modules are released from:
* Store v1 is released from `release/v0.50.x` branch.

270
ROADMAP.md Normal file
View file

@ -0,0 +1,270 @@
# Roadmap 2023
Welcome to the Cosmos SDK's team roadmap.
> This document is meant to help the team get feedback on the proposed work and for others to follow where we stand in our process. This will be a living document updated on a regular basis. If you'd like to participate in any workscope or would like to suggest another feature please reach out to [Marko](marko@binary.builders) or [Sam](sam@binary.builders) and we will schedule a call to discuss the feature request.
## Q1
### Storage
* [x] [Produce a spec for the new store design](https://github.com/cosmos/cosmos-sdk/issues/12986)
* Research a new design for store. This could entail writing some POC's in order to identify design patterns
* [x] Store as its own go module
* Store module should be its own go.mod without a dependency on the Cosmos SDK
* [ ] [Begin implementation of store v2](https://github.com/cosmos/cosmos-sdk/pull/15028)
* Identify the migration path from store v1 -> store v2
* [ ] Parallel execution of state
* RFC/ADR is merged into the main on the sdk
* [ ] Optimistic execution
* RFC/ADR is merged into main on the sdk
### Client UX
* [x] Release v1 of query support (auto-cli)
* A version of query support has been merged, documentation is missing
* [ ] Dynamic metadata support
* Dynamic support allows the Cosmos SDK to release a cmd line tool that could work with any chain.
* Add metadata support to latest version of Cosmos SDK and, if possible, backport to older versions
* [x] Multi-chain command **(Done)**
* Release a cmd line tool that can be pointed a grpc endpoint which then can produce cmd lines to interact with the chain
* [x] Auto-cli tx support
* Tx support for auto-cli/hubl
* This would fully remove the need for application developers to write cli commands for their modules
* [ ] [Consensus Key Rotation](https://github.com/cosmos/cosmos-sdk/issues/5231)
### Dev UX
* [x] [Release collections v0.1](https://github.com/cosmos/cosmos-sdk/issues/14300)
* Collections is a new abstraction layer similar to the ORM. In the ADR phase it received support from many in the ecosystem.
* V1 release should allow modules to be migrated to collections.
* Migrate 3 modules to use collections api
* Migrating 3 modules to use collections would help in show users how to migrate users
* [ ] [Release ORM v1](https://github.com/cosmos/cosmos-sdk/issues/11088)
* [x] [Sign mode textual](https://github.com/cosmos/cosmos-sdk/issues/11970)
* Sign mode textual has been under construction for 2 quarters now, this quarter the goal is to move towards v1 and potentially line up a audit before final release.
* [x] Core API
* [Merge ADR for Core API](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-063-core-module-api.md)
* Migrate three modules to use core api
* [x] Module Dependency
* Give three modules their own go.mods
* [ ] [Metamask signing directly into the sdk](https://github.com/cosmos/cosmos-sdk/discussions/13892)
* [ ] [ADR-033 (internal message routing)](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-033-protobuf-inter-module-comm.md)
* Merge internal message router
* Add docs on how to use the router
* [x] [ADR-54 (dependency management)](https://github.com/cosmos/cosmos-sdk/pull/11802)
* Come to consensus on module dependency graph for the future
* Begin socializing conventions
* [ ] [Remove global bech32](https://github.com/cosmos/cosmos-sdk/issues/13140)
* [x] [Auth module](https://github.com/cosmos/cosmos-sdk/issues/14900)
* Produce a spec/ADR on a proposed new auth module.
* [x] [Implement Amino Json encoder](https://github.com/cosmos/cosmos-sdk/issues/10993)
### Testing
* [x] [integration testing framework](https://github.com/cosmos/cosmos-sdk/issues/14145)
* design and merge a integration testing framework.
* The goals of the framework would that a module only needs to depend on modules that it depends on outside of testing, not all modules in the sdk like today.
### ABCI 2.0
Issue: https://github.com/cosmos/cosmos-sdk/issues/12272
* [x] [ADR ABCI 2.0](https://github.com/cosmos/cosmos-sdk/issues/14674)
* Write ADR for integration of vote extensions & finalize block
**Blocked**:
> once cometBFT has a release candidate of ABCI 2.0 (cmt 0.38)
* Integrate ABCI 2.0
### Security
* [ ] [Circuit breaker](https://github.com/cosmos/cosmos-sdk/issues/14226)
* Implement the circuit breaker module and prepare releases for Cosmos SDK versions 0.45, 0.46 and 0.47
### IAVL
* [x] [ADR 001](https://github.com/cosmos/iavl/pull/608)
* Implementation has been completed, waiting on reviewers
* [x] [Prepare the migration path](https://github.com/cosmos/iavl/issues/675)
* Migration path has not been finalized
* [ ] Test on mainnets
* If possible we would like to test the new IAVL design on mainnets to observer behavior changes.
Issue: https://github.com/cosmos/iavl/issues/548
## Q2
### Storage
* [ ] [Storage v2](https://github.com/cosmos/cosmos-sdk/issues/12986)
* Objective:
* Goal is to get 60% of the way through the rewrite of storage
* Begin testing the rewrite on mainnets if possible
* External Audit
* Progress:
* On pause till ABCI 2.0 ships
* [ ] [Optimistic Execution](https://github.com/cosmos/cosmos-sdk/issues/15365)
* Objective:
* Users should be able to pick between delayed execution and optimistic
* RFC/ADR is merged
* Implementation started.
* Progess:
* On pause till ABCI 2.0 is merged
### Client UX
* [ ] Hubl/AutoCLI
* Objective:
* Allow users to sign and submit transactions using hubl
* Add module support for autocli
* Deprecate/remove legacy cli (optional)
* Progress:
* Signing support is being refactored and is near completion
* Adapting modules to use autocli instead of manually written cli
* [ ] [Consensus Key Rotation](https://github.com/cosmos/cosmos-sdk/issues/5231)
* Objective:
* Allow users to rotate consensus keys for their validators
* Progress
* Merge pull request and updated ADR into main
* [ ] [Operator key rotation](https://github.com/cosmos/cosmos-sdk/issues/3863)
* Objective:
* Allow users to rotate operator keys for their validators
* Progress:
* secondary val index was added to support operator key rotation
* Pr is open and is being worked on
### Dev UX
* Toolkit/SDK ADR.
* Objective:
* Produce a RFC/ADR on how to make core composable
* Merge RFC/ADR into main
* Progress:
* on pause until abci 2.0 integration is completed
* Adopt core api fully in modules
* Objective:
* Remove the Cosmos SDK and Comet as a dependency from all modules
* Release v1 of modules that have their dependency graph cleaned up
* Spin out 4 more modules into their own go.mods
* Progress:
* Core api has been integrated into all modules
* KvStoreService is being added to all modules
* [ ] [Remove global bech32](https://github.com/cosmos/cosmos-sdk/issues/13140)
* Objective:
* Depreacte global bech32 setting
* Progress:
* All modules except bank use the `address.Codec`
* [ ] Make sdk.Msg only be `proto.message`
* Objectives:
* Reduce sdk.Msg to only be proto.message
* Reduce boilerplate in `msgs.go`
* Progess:
* [x] [Make ValidateBasic Optional](https://github.com/cosmos/cosmos-sdk/issues/15648)
* [ ] [Make GetSigners be optional](https://github.com/cosmos/cosmos-sdk/issues/15677)
* [ ] Remove GetsignBytes for legacy amino encoding
* [ ] [Collections](https://github.com/cosmos/cosmos-sdk/issues/14300)
* Objectives
* Migrate all modules
* Add query support
* Add schema support
* Progress:
* We have migrated three modules
### ABCI 2.0
* [ ] [ABCI 2.0](https://github.com/cosmos/cosmos-sdk/issues/12272)
* Objectives:
* Integrate comet 0.38
* QA
* Progress:
* Integration has started
### Testing
* [ ] [Integration framework](https://github.com/cosmos/cosmos-sdk/issues/14145)
* Objectives:
* Migrate all modules
* Progress:
* We have migrated 2-4 modules currently
### Modules
* [ ] [Invariant Checking](https://github.com/cosmos/cosmos-sdk/issues/15706)
* Objective:
* Design a new system for checking invairants
* Implement changes
* Audit current invariants
* Progress:
* NA
* [ ] [Accounts](https://github.com/cosmos/cosmos-sdk/issues/14900)
* Objective:
* Allow users to use account abstractions
* Implementation is completed
* External Audit is scheduled (if needed)
* Progress:
* RFC/ADR is in review
### Research
* [ ] Commitment Structure
* Objective:
* Identify different commitment structures that could be used in the sdk and how they would be plugged (highlevel)
* Progress:
* Conversations in slack have started
* [ ] Cross lang
* Objective:
* Answer, what is needed to support many languages
* Answer, what sort of encoding of passing between the cgo/ffi boundary
* Progress:
* working group is meeting bi weekly
* ADR/RFC is in review
## Q3
### Storage
* Audit & release of storage refactor
* Identify further optimizations for storage
* Goal is to identify the next bottlenecks in storage or the state machine
### Dev UX
* Complete Toolkit/SDK implementation refactor
* Goal is to release the new version of the sdk allowing for further composability
* Implement fee market abstractions
* Goal is to release an alpha version of fee market abstractions
### Modules
* Governance
* Make gov and groups composable with each other, not duplicate
* Staking
* Research a new staking design
* Begin Implementation
### Research
* Nonce Lanes
* Goal is to produce a spec and/or viability of using lanes for nonces instead of a single sequence number.
## Q4
### Research
* Stateless clients
* research how stateless clients could evolve in cosmos
This document will be updated at the end of the quarter on what was achieved and what was not. Shortly before the quarter concludes a new section will be added for the next quarter. We are working on updating the complete one year roadmap and will be posting it here as well.

79
SECURITY.md Normal file
View file

@ -0,0 +1,79 @@
# Coordinated Vulnerability Disclosure Policy
The Cosmos ecosystem believes that strong security is a blend of highly
technical security researchers who care about security and the forward
progression of the ecosystem and the attentiveness and openness of Cosmos core
contributors to help continually secure our operations.
> **IMPORTANT**: *DO NOT* open public issues on this repository for security
> vulnerabilities.
## Scope
| Scope |
|-----------------------|
| last release (tagged) |
| main branch |
The latest **release tag** of this repository is supported for security updates
as well as the **main** branch. Security vulnerabilities should be reported if
the vulnerability can be reproduced on either one of those.
## Reporting a Vulnerability
| Reporting methods |
|---------------------------------------------------------------|
| [GitHub Private Vulnerability Reporting][gh-private-advisory] |
| [HackerOne bug bounty program][h1] |
All security vulnerabilities can be reported under GitHub's [Private
vulnerability reporting][gh-private-advisory] system. This will open a private
issue for the developers. Try to fill in as much of the questions as possible.
If you are not familiar with the CVSS system for assessing vulnerabilities, just
use the Low/High/Critical severity ratings. A partially filled in report for a
critical vulnerability is still better than no report at all.
Vulnerabilities associated with the **Go, Rust or Protobuf code** of the
repository may be eligible for a [bug bounty][h1]. Please see the bug bounty
page for more details on submissions and rewards. If you think the vulnerability
is eligible for a payout, **report on HackerOne first**.
Vulnerabilities in services and their source codes (JavaScript, web page, Google
Workspace) are not in scope for the bug bounty program, but they are welcome to
be reported in GitHub.
### Guidelines
We require that all researchers:
* Abide by this policy to disclose vulnerabilities, and avoid posting
vulnerability information in public places, including GitHub, Discord,
Telegram, and Twitter.
* Make every effort to avoid privacy violations, degradation of user experience,
disruption to production systems (including but not limited to the Cosmos
Hub), and destruction of data.
* Keep any information about vulnerabilities that youve discovered confidential
between yourself and the Cosmos engineering team until the issue has been
resolved and disclosed.
* Avoid posting personally identifiable information, privately or publicly.
If you follow these guidelines when reporting an issue to us, we commit to:
* Not pursue or support any legal action related to your research on this
vulnerability
* Work with you to understand, resolve and ultimately disclose the issue in a
timely fashion
### More information
* See [TIMELINE.md] for an example timeline of a disclosure.
* See [DISCLOSURE.md] to see more into the inner workings of the disclosure
process.
* See [EXAMPLES.md] for some of the examples that we are interested in for the
bug bounty program.
[gh-private-advisory]: /../../security/advisories/new
[h1]: https://hackerone.com/cosmos
[TIMELINE.md]: https://github.com/cosmos/security/blob/main/TIMELINE.md
[DISCLOSURE.md]: https://github.com/cosmos/security/blob/main/DISCLOSURE.md
[EXAMPLES.md]: https://github.com/cosmos/security/blob/main/EXAMPLES.md

503
UPGRADE_GUIDE.md Normal file
View file

@ -0,0 +1,503 @@
# Upgrade Guide
This document provides a full guide for upgrading a Cosmos SDK chain from `v0.50.x` to `v0.53.x`.
This guide includes one **required** change and three **optional** features.
After completing this guide, applications will have:
- The `x/protocolpool` module
- The `x/epochs` module
- Unordered Transaction support
## Table of Contents
- [App Wiring Changes (REQUIRED)](#app-wiring-changes-required)
- [Adding ProtocolPool Module (OPTIONAL)](#adding-protocolpool-module-optional)
- [ProtocolPool Manual Wiring](#protocolpool-manual-wiring)
- [ProtocolPool DI Wiring](#protocolpool-di-wiring)
- [Adding Epochs Module (OPTIONAL)](#adding-epochs-module-optional)
- [Epochs Manual Wiring](#epochs-manual-wiring)
- [Epochs DI Wiring](#epochs-di-wiring)
- [Enable Unordered Transactions (OPTIONAL)](#enable-unordered-transactions-optional)
- [Upgrade Handler](#upgrade-handler)
## App Wiring Changes **REQUIRED**
The `x/auth` module now contains a `PreBlocker` that _must_ be set in the module manager's `SetOrderPreBlockers` method.
```go
app.ModuleManager.SetOrderPreBlockers(
upgradetypes.ModuleName,
authtypes.ModuleName, // NEW
)
```
## Adding ProtocolPool Module **OPTIONAL**
:::warning
Using an external community pool such as `x/protocolpool` will cause the following `x/distribution` handlers to return an error:
**QueryService**
- `CommunityPool`
**MsgService**
- `CommunityPoolSpend`
- `FundCommunityPool`
If your services depend on this functionality from `x/distribution`, please update them to use either `x/protocolpool` or your custom external community pool alternatives.
:::
### Manual Wiring
Import the following:
```go
import (
// ...
"github.com/cosmos/cosmos-sdk/x/protocolpool"
protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
protocolpooltypes "github.com/cosmos/cosmos-sdk/x/protocolpool/types"
)
```
Set the module account permissions.
```go
maccPerms = map[string][]string{
// ...
protocolpooltypes.ModuleName: nil,
protocolpooltypes.ProtocolPoolEscrowAccount: nil,
}
```
Add the protocol pool keeper to your application struct.
```go
ProtocolPoolKeeper protocolpoolkeeper.Keeper
```
Add the store key:
```go
keys := storetypes.NewKVStoreKeys(
// ...
protocolpooltypes.StoreKey,
)
```
Instantiate the keeper.
Make sure to do this before the distribution module instantiation, as you will pass the keeper there next.
```go
app.ProtocolPoolKeeper = protocolpoolkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[protocolpooltypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
```
Pass the protocolpool keeper to the distribution keeper:
```go
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[distrtypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
distrkeeper.WithExternalCommunityPool(app.ProtocolPoolKeeper), // NEW
)
```
Add the protocolpool module to the module manager:
```go
app.ModuleManager = module.NewManager(
// ...
protocolpool.NewAppModule(appCodec, app.ProtocolPoolKeeper, app.AccountKeeper, app.BankKeeper),
)
```
Add an entry for SetOrderBeginBlockers, SetOrderEndBlockers, SetOrderInitGenesis, and SetOrderExportGenesis.
```go
app.ModuleManager.SetOrderBeginBlockers(
// must come AFTER distribution.
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
)
```
```go
app.ModuleManager.SetOrderEndBlockers(
// order does not matter.
protocolpooltypes.ModuleName,
)
```
```go
app.ModuleManager.SetOrderInitGenesis(
// order does not matter.
protocolpooltypes.ModuleName,
)
```
```go
app.ModuleManager.SetOrderInitGenesis(
protocolpooltypes.ModuleName, // must be exported before bank.
banktypes.ModuleName,
)
```
### DI Wiring
Note: _as long as an external community pool keeper (here, `x/protocolpool`) is wired in DI configs, `x/distribution` will automatically use it for its external pool._
First, set up the keeper for the application.
Import the protocolpool keeper:
```go
protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
```
Add the keeper to your application struct:
```go
ProtocolPoolKeeper protocolpoolkeeper.Keeper
```
Add the keeper to the depinject system:
```go
depinject.Inject(
appConfig,
&appBuilder,
&app.appCodec,
&app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
// ... other modules
&app.ProtocolPoolKeeper, // NEW MODULE!
)
```
Next, set up configuration for the module.
Import the following:
```go
import (
protocolpoolmodulev1 "cosmossdk.io/api/cosmos/protocolpool/module/v1"
_ "github.com/cosmos/cosmos-sdk/x/protocolpool" // import for side-effects
protocolpooltypes "github.com/cosmos/cosmos-sdk/x/protocolpool/types"
)
```
The protocolpool module has module accounts that handle funds. Add them to the module account permission configuration:
```go
moduleAccPerms = []*authmodulev1.ModuleAccountPermission{
// ...
{Account: protocolpooltypes.ModuleName},
{Account: protocolpooltypes.ProtocolPoolEscrowAccount},
}
```
Next, add an entry for BeginBlockers, EndBlockers, InitGenesis, and ExportGenesis.
```go
BeginBlockers: []string{
// ...
// must be AFTER distribution.
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
},
```
```go
EndBlockers: []string{
// ...
// order for protocolpool does not matter.
protocolpooltypes.ModuleName,
},
```
```go
InitGenesis: []string{
// ... must be AFTER distribution.
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
},
```
```go
ExportGenesis: []string{
// ...
// Must be exported before x/bank.
protocolpooltypes.ModuleName,
banktypes.ModuleName,
},
```
Lastly, add an entry for protocolpool in the ModuleConfig.
```go
{
Name: protocolpooltypes.ModuleName,
Config: appconfig.WrapAny(&protocolpoolmodulev1.Module{}),
},
```
## Adding Epochs Module **OPTIONAL**
### Manual Wiring
Import the following:
```go
import (
// ...
"github.com/cosmos/cosmos-sdk/x/epochs"
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
)
```
Add the epochs keeper to your application struct:
```go
EpochsKeeper epochskeeper.Keeper
```
Add the store key:
```go
keys := storetypes.NewKVStoreKeys(
// ...
epochstypes.StoreKey,
)
```
Instantiate the keeper:
```go
app.EpochsKeeper = epochskeeper.NewKeeper(
runtime.NewKVStoreService(keys[epochstypes.StoreKey]),
appCodec,
)
```
Set up hooks for the epochs keeper:
To learn how to write hooks for the epoch keeper, see the [x/epoch README](https://github.com/cosmos/cosmos-sdk/blob/main/x/epochs/README.md)
```go
app.EpochsKeeper.SetHooks(
epochstypes.NewMultiEpochHooks(
// insert epoch hooks receivers here
app.SomeOtherModule
),
)
```
Add the epochs module to the module manager:
```go
app.ModuleManager = module.NewManager(
// ...
epochs.NewAppModule(appCodec, app.EpochsKeeper),
)
```
Add entries for SetOrderBeginBlockers and SetOrderInitGenesis:
```go
app.ModuleManager.SetOrderBeginBlockers(
// ...
epochstypes.ModuleName,
)
```
```go
app.ModuleManager.SetOrderInitGenesis(
// ...
epochstypes.ModuleName,
)
```
### DI Wiring
First, set up the keeper for the application.
Import the epochs keeper:
```go
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
```
Add the keeper to your application struct:
```go
EpochsKeeper epochskeeper.Keeper
```
Add the keeper to the depinject system:
```go
depinject.Inject(
appConfig,
&appBuilder,
&app.appCodec,
&app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
// ... other modules
&app.EpochsKeeper, // NEW MODULE!
)
```
Next, set up configuration for the module.
Import the following:
```go
import (
epochsmodulev1 "cosmossdk.io/api/cosmos/epochs/module/v1"
_ "github.com/cosmos/cosmos-sdk/x/epochs" // import for side-effects
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
)
```
Add an entry for BeginBlockers and InitGenesis:
```go
BeginBlockers: []string{
// ...
epochstypes.ModuleName,
},
```
```go
InitGenesis: []string{
// ...
epochstypes.ModuleName,
},
```
Lastly, add an entry for epochs in the ModuleConfig:
```go
{
Name: epochstypes.ModuleName,
Config: appconfig.WrapAny(&epochsmodulev1.Module{}),
},
```
## Enable Unordered Transactions **OPTIONAL**
To enable unordered transaction support on an application, the `x/auth` keeper must be supplied with the `WithUnorderedTransactions` option.
Note that unordered transactions require sequence values to be zero, and will **FAIL** if a non-zero sequence value is set.
Please ensure no sequence value is set when submitting an unordered transaction.
Services that rely on prior assumptions about sequence values should be updated to handle unordered transactions.
Services should be aware that when the transaction is unordered, the transaction sequence will always be zero.
```go
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec,
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
authtypes.ProtoBaseAccount,
maccPerms,
authcodec.NewBech32Codec(sdk.Bech32MainPrefix),
sdk.Bech32MainPrefix,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
authkeeper.WithUnorderedTransactions(true), // new option!
)
```
If using dependency injection, update the auth module config.
```go
{
Name: authtypes.ModuleName,
Config: appconfig.WrapAny(&authmodulev1.Module{
Bech32Prefix: "cosmos",
ModuleAccountPermissions: moduleAccPerms,
EnableUnorderedTransactions: true, // remove this line if you do not want unordered transactions.
}),
},
```
By default, unordered transactions use a transaction timeout duration of 10 minutes and a default gas charge of 2240 gas units.
To modify these default values, pass in the corresponding options to the new `SigVerifyOptions` field in `x/auth's` `ante.HandlerOptions`.
```go
options := ante.HandlerOptions{
SigVerifyOptions: []ante.SigVerificationDecoratorOption{
// change below as needed.
ante.WithUnorderedTxGasCost(ante.DefaultUnorderedTxGasCost),
ante.WithMaxUnorderedTxTimeoutDuration(ante.DefaultMaxTimoutDuration),
},
}
```
```go
anteDecorators := []sdk.AnteDecorator{
// ... other decorators ...
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler, options.SigVerifyOptions...), // supply new options
}
```
## Upgrade Handler
The upgrade handler only requires adding the store upgrades for the modules added above.
If your application is not adding `x/protocolpool` or `x/epochs`, you do not need to add the store upgrade.
```go
// UpgradeName defines the on-chain upgrade name for the sample SimApp upgrade
// from v050 to v053.
//
// NOTE: This upgrade defines a reference implementation of what an upgrade
// could look like when an application is migrating from Cosmos SDK version
// v0.50.x to v0.53.x.
const UpgradeName = "v050-to-v053"
func (app SimApp) RegisterUpgradeHandlers() {
app.UpgradeKeeper.SetUpgradeHandler(
UpgradeName,
func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM)
},
)
upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
if err != nil {
panic(err)
}
if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
storeUpgrades := storetypes.StoreUpgrades{
Added: []string{
epochstypes.ModuleName, // if not adding x/epochs to your chain, remove this line.
protocolpooltypes.ModuleName, // if not adding x/protocolpool to your chain, remove this line.
},
}
// configure store loader that checks if version == upgradeHeight and applies store upgrades
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
}
}
```

227
UPGRADING.md Normal file
View file

@ -0,0 +1,227 @@
# Upgrade Reference
This document provides a quick reference for the upgrades from `v0.50.x` to `v0.53.x` of Cosmos SDK.
Note, always read the **App Wiring Changes** section for more information on application wiring updates.
🚨Upgrading to v0.53.x will require a **coordinated** chain upgrade.🚨
### TLDR;
Unordered transactions, `x/protocolpool`, and `x/epoch` are the major new features added in v0.53.x.
We also added the ability to add a `CheckTx` handler and enabled ed25519 signature verification.
For a full list of changes, see the [Changelog](https://github.com/cosmos/cosmos-sdk/blob/release/v0.53.x/CHANGELOG.md).
### Unordered Transactions
The Cosmos SDK now supports unordered transactions. _This is an opt-in feature_.
Clients that use this feature may now submit their transactions in a fire-and-forget manner to chains that enabled unordered transactions.
To submit an unordered transaction, clients must set the `unordered` flag to
`true` and ensure a reasonable `timeout_timestamp` is set. The `timeout_timestamp` is
used as a TTL for the transaction and provides replay protection. Each transaction's `timeout_timestamp` must be
unique to the account; however, the difference may be as small as a nanosecond. See [ADR-070](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-070-unordered-transactions.md) for more details.
Note that unordered transactions require sequence values to be zero, and will **FAIL** if a non-zero sequence value is set.
Please ensure no sequence value is set when submitting an unordered transaction.
Services that rely on prior assumptions about sequence values should be updated to handle unordered transactions.
Services should be aware that when the transaction is unordered, the transaction sequence will always be zero.
#### Enabling Unordered Transactions
To enable unordered transactions, supply the `WithUnorderedTransactions` option to the `x/auth` keeper:
```go
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec,
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
authtypes.ProtoBaseAccount,
maccPerms,
authcodec.NewBech32Codec(sdk.Bech32MainPrefix),
sdk.Bech32MainPrefix,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
authkeeper.WithUnorderedTransactions(true), // new option!
)
```
If using dependency injection, update the auth module config.
```go
{
Name: authtypes.ModuleName,
Config: appconfig.WrapAny(&authmodulev1.Module{
Bech32Prefix: "cosmos",
ModuleAccountPermissions: moduleAccPerms,
EnableUnorderedTransactions: true, // remove this line if you do not want unordered transactions.
}),
},
```
By default, unordered transactions use a transaction timeout duration of 10 minutes and a default gas charge of 2240 gas units.
To modify these default values, pass in the corresponding options to the new `SigVerifyOptions` field in `x/auth's` `ante.HandlerOptions`.
```go
options := ante.HandlerOptions{
SigVerifyOptions: []ante.SigVerificationDecoratorOption{
// change below as needed.
ante.WithUnorderedTxGasCost(ante.DefaultUnorderedTxGasCost),
ante.WithMaxUnorderedTxTimeoutDuration(ante.DefaultMaxTimoutDuration),
},
}
```
```go
anteDecorators := []sdk.AnteDecorator{
// ... other decorators ...
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler, options.SigVerifyOptions...), // supply new options
}
```
### App Wiring Changes
In this section, we describe the required app wiring changes to run a v0.53.x Cosmos SDK application.
**These changes are directly applicable to your application wiring.**
The `x/auth` module now contains a `PreBlocker` that _must_ be set in the module manager's `SetOrderPreBlockers` method.
```go
app.ModuleManager.SetOrderPreBlockers(
upgradetypes.ModuleName,
authtypes.ModuleName, // NEW
)
```
That's it.
### New Modules
Below are some **optional** new modules you can include in your chain.
To see a full example of wiring these modules, please check out the [SimApp](https://github.com/cosmos/cosmos-sdk/blob/release/v0.53.x/simapp/app.go).
#### Epochs
Adding this module requires a `StoreUpgrade`⚠️
The new, supplemental `x/epochs` module provides Cosmos SDK modules functionality to register and execute custom logic at fixed time-intervals.
Required wiring:
- Keeper Instantiation
- StoreKey addition
- Hooks Registration
- App Module Registration
- entry in SetOrderBeginBlockers
- entry in SetGenesisModuleOrder
- entry in SetExportModuleOrder
#### ProtocolPool
:::warning
Using `protocolpool` will cause the following `x/distribution` handlers to return an error:
**QueryService**
- `CommunityPool`
**MsgService**
- `CommunityPoolSpend`
- `FundCommunityPool`
If you have services that rely on this functionality from `x/distribution`, please update them to use the `x/protocolpool` equivalents.
:::
Adding this module requires a `StoreUpgrade`⚠️
The new, supplemental `x/protocolpool` module provides extended functionality for managing and distributing block reward revenue.
Required wiring:
- Module Account Permissions
- protocolpooltypes.ModuleName (nil)
- protocolpooltypes.ProtocolPoolEscrowAccount (nil)
- Keeper Instantiation
- StoreKey addition
- Passing the keeper to the Distribution Keeper
- `distrkeeper.WithExternalCommunityPool(app.ProtocolPoolKeeper)`
- App Module Registration
- entry in SetOrderBeginBlockers
- entry in SetOrderEndBlockers
- entry in SetGenesisModuleOrder
- entry in SetExportModuleOrder **before `x/bank`**
## Custom Minting Function in `x/mint`
This release introduces the ability to configure a custom mint function in `x/mint`. The minting logic is now abstracted as a `MintFn` with a default implementation that can be overridden.
### Whats New
- **Configurable Mint Function:**
A new `MintFn` abstraction is introduced. By default, the module uses `DefaultMintFn`, but you can supply your own implementation.
- **Deprecated InflationCalculationFn Parameter:**
The `InflationCalculationFn` argument previously provided to `mint.NewAppModule()` is now ignored and must be `nil`. To customize the default minters inflation behavior, wrap your custom function with `mintkeeper.DefaultMintFn` and pass it via the `WithMintFn` option:
```go
mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(customInflationFn))
```
### How to Upgrade
1. **Using the Default Minting Function**
No action is needed if youre happy with the default behavior. Make sure your application wiring initializes the MintKeeper like this:
```go
mintKeeper := mintkeeper.NewKeeper(
appCodec,
storeService,
stakingKeeper,
accountKeeper,
bankKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
```
2. **Using a Custom Minting Function**
To use a custom minting function, define it as follows and pass it you your mintKeeper when constructing it:
```go
func myCustomMintFunc(ctx sdk.Context, k *mintkeeper.Keeper) {
// do minting...
}
// ...
mintKeeper := mintkeeper.NewKeeper(
appCodec,
storeService,
stakingKeeper,
accountKeeper,
bankKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
mintkeeper.WithMintFn(myCustomMintFunc), // Use custom minting function
)
```
### Misc Changes
#### Testnet's init-files Command
Some changes were made to `testnet`'s `init-files` command to support our new testing framework, `Systemtest`.
##### Flag Changes
- The flag for validator count was changed from `--v` to `--validator-count`(shorthand: `-v`).
##### Flag Additions
- `--staking-denom` allows changing the default stake denom, `stake`.
- `--commit-timeout` enables changing the commit timeout of the chain.
- `--single-host` enables running a multi-node network on a single host. This bumps each subsequent node's network addresses by 1. For example, node1's gRPC address will be 9090, node2's 9091, etc...

1392
baseapp/abci.go Normal file

File diff suppressed because it is too large Load diff

2537
baseapp/abci_test.go Normal file

File diff suppressed because it is too large Load diff

533
baseapp/abci_utils.go Normal file
View file

@ -0,0 +1,533 @@
package baseapp
import (
"bytes"
"context"
"fmt"
"slices"
"github.com/cockroachdb/errors"
abci "github.com/cometbft/cometbft/abci/types"
cryptoenc "github.com/cometbft/cometbft/crypto/encoding"
cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
cmttypes "github.com/cometbft/cometbft/types"
protoio "github.com/cosmos/gogoproto/io"
"github.com/cosmos/gogoproto/proto"
"cosmossdk.io/core/comet"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/mempool"
)
type (
// ValidatorStore defines the interface contract required for verifying vote
// extension signatures. Typically, this will be implemented by the x/staking
// module, which has knowledge of the CometBFT public key.
ValidatorStore interface {
GetPubKeyByConsAddr(context.Context, sdk.ConsAddress) (cmtprotocrypto.PublicKey, error)
}
// GasTx defines the contract that a transaction with a gas limit must implement.
GasTx interface {
GetGas() uint64
}
)
// ValidateVoteExtensions defines a helper function for verifying vote extension
// signatures that may be passed or manually injected into a block proposal from
// a proposer in PrepareProposal. It returns an error if any signature is invalid
// or if unexpected vote extensions and/or signatures are found or less than 2/3
// power is received.
// NOTE: From v0.50.5 `currentHeight` and `chainID` arguments are ignored for fixing an issue.
// They will be removed from the function in v0.51+.
func ValidateVoteExtensions(
ctx sdk.Context,
valStore ValidatorStore,
_ int64,
_ string,
extCommit abci.ExtendedCommitInfo,
) error {
// Get values from context
cp := ctx.ConsensusParams()
currentHeight := ctx.HeaderInfo().Height
chainID := ctx.HeaderInfo().ChainID
commitInfo := ctx.CometInfo().GetLastCommit()
// Check that both extCommit + commit are ordered in accordance with vp/address.
if err := validateExtendedCommitAgainstLastCommit(extCommit, commitInfo); err != nil {
return err
}
// Start checking vote extensions only **after** the vote extensions enable
// height, because when `currentHeight == VoteExtensionsEnableHeight`
// PrepareProposal doesn't get any vote extensions in its request.
extsEnabled := cp.Abci != nil && currentHeight > cp.Abci.VoteExtensionsEnableHeight && cp.Abci.VoteExtensionsEnableHeight != 0
marshalDelimitedFn := func(msg proto.Message) ([]byte, error) {
var buf bytes.Buffer
if err := protoio.NewDelimitedWriter(&buf).WriteMsg(msg); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var (
// Total voting power of all vote extensions.
totalVP int64
// Total voting power of all validators that submitted valid vote extensions.
sumVP int64
)
for _, vote := range extCommit.Votes {
totalVP += vote.Validator.Power
// Only check + include power if the vote is a commit vote. There must be super-majority, otherwise the
// previous block (the block the vote is for) could not have been committed.
if vote.BlockIdFlag != cmtproto.BlockIDFlagCommit {
continue
}
if !extsEnabled {
if len(vote.VoteExtension) > 0 {
return fmt.Errorf("vote extensions disabled; received non-empty vote extension at height %d", currentHeight)
}
if len(vote.ExtensionSignature) > 0 {
return fmt.Errorf("vote extensions disabled; received non-empty vote extension signature at height %d", currentHeight)
}
continue
}
if len(vote.ExtensionSignature) == 0 {
return fmt.Errorf("vote extensions enabled; received empty vote extension signature at height %d", currentHeight)
}
valConsAddr := sdk.ConsAddress(vote.Validator.Address)
pubKeyProto, err := valStore.GetPubKeyByConsAddr(ctx, valConsAddr)
if err != nil {
return fmt.Errorf("failed to get validator %X public key: %w", valConsAddr, err)
}
cmtPubKey, err := cryptoenc.PubKeyFromProto(pubKeyProto)
if err != nil {
return fmt.Errorf("failed to convert validator %X public key: %w", valConsAddr, err)
}
cve := cmtproto.CanonicalVoteExtension{
Extension: vote.VoteExtension,
Height: currentHeight - 1, // the vote extension was signed in the previous height
Round: int64(extCommit.Round),
ChainId: chainID,
}
extSignBytes, err := marshalDelimitedFn(&cve)
if err != nil {
return fmt.Errorf("failed to encode CanonicalVoteExtension: %w", err)
}
if !cmtPubKey.VerifySignature(extSignBytes, vote.ExtensionSignature) {
return fmt.Errorf("failed to verify validator %X vote extension signature", valConsAddr)
}
sumVP += vote.Validator.Power
}
// This check is probably unnecessary, but better safe than sorry.
if totalVP <= 0 {
return fmt.Errorf("total voting power must be positive, got: %d", totalVP)
}
// If the sum of the voting power has not reached (2/3 + 1) we need to error.
if requiredVP := ((totalVP * 2) / 3) + 1; sumVP < requiredVP {
return fmt.Errorf(
"insufficient cumulative voting power received to verify vote extensions; got: %d, expected: >=%d",
sumVP, requiredVP,
)
}
return nil
}
// validateExtendedCommitAgainstLastCommit validates an ExtendedCommitInfo against a LastCommit. Specifically,
// it checks that the ExtendedCommit + LastCommit (for the same height), are consistent with each other + that
// they are ordered correctly (by voting power) in accordance with
// [comet](https://github.com/cometbft/cometbft/blob/4ce0277b35f31985bbf2c25d3806a184a4510010/types/validator_set.go#L784).
func validateExtendedCommitAgainstLastCommit(ec abci.ExtendedCommitInfo, lc comet.CommitInfo) error {
// check that the rounds are the same
if ec.Round != lc.Round() {
return fmt.Errorf("extended commit round %d does not match last commit round %d", ec.Round, lc.Round())
}
// check that the # of votes are the same
if len(ec.Votes) != lc.Votes().Len() {
return fmt.Errorf("extended commit votes length %d does not match last commit votes length %d", len(ec.Votes), lc.Votes().Len())
}
// check sort order of extended commit votes
if !slices.IsSortedFunc(ec.Votes, func(vote1, vote2 abci.ExtendedVoteInfo) int {
if vote1.Validator.Power == vote2.Validator.Power {
return bytes.Compare(vote1.Validator.Address, vote2.Validator.Address) // addresses sorted in ascending order (used to break vp conflicts)
}
return -int(vote1.Validator.Power - vote2.Validator.Power) // vp sorted in descending order
}) {
return fmt.Errorf("extended commit votes are not sorted by voting power")
}
addressCache := make(map[string]struct{}, len(ec.Votes))
// check that consistency between LastCommit and ExtendedCommit
for i, vote := range ec.Votes {
// cache addresses to check for duplicates
if _, ok := addressCache[string(vote.Validator.Address)]; ok {
return fmt.Errorf("extended commit vote address %X is duplicated", vote.Validator.Address)
}
addressCache[string(vote.Validator.Address)] = struct{}{}
if !bytes.Equal(vote.Validator.Address, lc.Votes().Get(i).Validator().Address()) {
return fmt.Errorf("extended commit vote address %X does not match last commit vote address %X", vote.Validator.Address, lc.Votes().Get(i).Validator().Address())
}
if vote.Validator.Power != lc.Votes().Get(i).Validator().Power() {
return fmt.Errorf("extended commit vote power %d does not match last commit vote power %d", vote.Validator.Power, lc.Votes().Get(i).Validator().Power())
}
}
return nil
}
type (
// ProposalTxVerifier defines the interface that is implemented by BaseApp,
// that any custom ABCI PrepareProposal and ProcessProposal handler can use
// to verify a transaction.
ProposalTxVerifier interface {
PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error)
ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error)
TxDecode(txBz []byte) (sdk.Tx, error)
TxEncode(tx sdk.Tx) ([]byte, error)
}
// DefaultProposalHandler defines the default ABCI PrepareProposal and
// ProcessProposal handlers.
DefaultProposalHandler struct {
mempool mempool.Mempool
txVerifier ProposalTxVerifier
txSelector TxSelector
signerExtAdapter mempool.SignerExtractionAdapter
}
)
func NewDefaultProposalHandler(mp mempool.Mempool, txVerifier ProposalTxVerifier) *DefaultProposalHandler {
return &DefaultProposalHandler{
mempool: mp,
txVerifier: txVerifier,
txSelector: NewDefaultTxSelector(),
signerExtAdapter: mempool.NewDefaultSignerExtractionAdapter(),
}
}
// SetTxSelector sets the TxSelector function on the DefaultProposalHandler.
func (h *DefaultProposalHandler) SetTxSelector(ts TxSelector) {
h.txSelector = ts
}
// SetSignerExtractionAdapter sets the SetSignerExtractionAdapter on the DefaultProposalHandler.
func (h *DefaultProposalHandler) SetSignerExtractionAdapter(signerExtAdapter mempool.SignerExtractionAdapter) {
h.signerExtAdapter = signerExtAdapter
}
// PrepareProposalHandler returns the default implementation for processing an
// ABCI proposal. The application's mempool is enumerated and all valid
// transactions are added to the proposal. Transactions are valid if they:
//
// 1) Successfully encode to bytes.
// 2) Are valid (i.e. pass runTx, AnteHandler only).
//
// Enumeration is halted once RequestPrepareProposal.MaxBytes of transactions is
// reached or the mempool is exhausted.
//
// Note:
//
// - Step (2) is identical to the validation step performed in
// DefaultProcessProposal. It is very important that the same validation logic
// is used in both steps, and applications must ensure that this is the case in
// non-default handlers.
//
// - If no mempool is set or if the mempool is a no-op mempool, the transactions
// requested from CometBFT will simply be returned, which, by default, are in
// FIFO order.
func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
return func(ctx sdk.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) {
var maxBlockGas uint64
if b := ctx.ConsensusParams().Block; b != nil {
maxBlockGas = uint64(b.MaxGas)
}
defer h.txSelector.Clear()
// If the mempool is nil or NoOp we simply return the transactions
// requested from CometBFT, which, by default, should be in FIFO order.
//
// Note, we still need to ensure the transactions returned respect req.MaxTxBytes.
_, isNoOp := h.mempool.(mempool.NoOpMempool)
if h.mempool == nil || isNoOp {
for _, txBz := range req.Txs {
tx, err := h.txVerifier.TxDecode(txBz)
if err != nil {
return nil, err
}
stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, tx, txBz)
if stop {
break
}
}
return &abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs(ctx)}, nil
}
selectedTxsSignersSeqs := make(map[string]uint64)
var (
resError error
selectedTxsNums int
invalidTxs []sdk.Tx // invalid txs to be removed out of the loop to avoid dead lock
)
mempool.SelectBy(ctx, h.mempool, req.Txs, func(memTx sdk.Tx) bool {
unorderedTx, ok := memTx.(sdk.TxWithUnordered)
isUnordered := ok && unorderedTx.GetUnordered()
txSignersSeqs := make(map[string]uint64)
// if the tx is unordered, we don't need to check the sequence, we just add it
if !isUnordered {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}
// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue
}
// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}
}
// NOTE: Since transaction verification was already executed in CheckTx,
// which calls mempool.Insert, in theory everything in the pool should be
// valid. But some mempool implementations may insert invalid txs, so we
// check again.
txBz, err := h.txVerifier.PrepareProposalVerifyTx(memTx)
if err != nil {
invalidTxs = append(invalidTxs, memTx)
} else {
stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, memTx, txBz)
if stop {
return false
}
txsLen := len(h.txSelector.SelectedTxs(ctx))
// If the tx is unordered, we don't need to update the sender sequence.
if !isUnordered {
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
}
}
}
selectedTxsNums = txsLen
}
return true
})
if resError != nil {
return nil, resError
}
for _, tx := range invalidTxs {
err := h.mempool.Remove(tx)
if err != nil && !errors.Is(err, mempool.ErrTxNotFound) {
return nil, err
}
}
return &abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs(ctx)}, nil
}
}
// ProcessProposalHandler returns the default implementation for processing an
// ABCI proposal. Every transaction in the proposal must pass 2 conditions:
//
// 1. The transaction bytes must decode to a valid transaction.
// 2. The transaction must be valid (i.e. pass runTx, AnteHandler only)
//
// If any transaction fails to pass either condition, the proposal is rejected.
// Note that step (2) is identical to the validation step performed in
// DefaultPrepareProposal. It is very important that the same validation logic
// is used in both steps, and applications must ensure that this is the case in
// non-default handlers.
func (h *DefaultProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
// If the mempool is nil or NoOp we simply return ACCEPT,
// because PrepareProposal may have included txs that could fail verification.
_, isNoOp := h.mempool.(mempool.NoOpMempool)
if h.mempool == nil || isNoOp {
return NoOpProcessProposal()
}
return func(ctx sdk.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) {
var totalTxGas uint64
var maxBlockGas int64
if b := ctx.ConsensusParams().Block; b != nil {
maxBlockGas = b.MaxGas
}
for _, txBytes := range req.Txs {
tx, err := h.txVerifier.ProcessProposalVerifyTx(txBytes)
if err != nil {
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, nil
}
if maxBlockGas > 0 {
gasTx, ok := tx.(GasTx)
if ok {
totalTxGas += gasTx.GetGas()
}
if totalTxGas > uint64(maxBlockGas) {
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, nil
}
}
}
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
}
}
// NoOpPrepareProposal defines a no-op PrepareProposal handler. It will always
// return the transactions sent by the client's request.
func NoOpPrepareProposal() sdk.PrepareProposalHandler {
return func(_ sdk.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) {
return &abci.ResponsePrepareProposal{Txs: req.Txs}, nil
}
}
// NoOpProcessProposal defines a no-op ProcessProposal Handler. It will always
// return ACCEPT.
func NoOpProcessProposal() sdk.ProcessProposalHandler {
return func(_ sdk.Context, _ *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) {
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
}
}
// NoOpExtendVote defines a no-op ExtendVote handler. It will always return an
// empty byte slice as the vote extension.
func NoOpExtendVote() sdk.ExtendVoteHandler {
return func(_ sdk.Context, _ *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {
return &abci.ResponseExtendVote{VoteExtension: []byte{}}, nil
}
}
// NoOpVerifyVoteExtensionHandler defines a no-op VerifyVoteExtension handler. It
// will always return an ACCEPT status with no error.
func NoOpVerifyVoteExtensionHandler() sdk.VerifyVoteExtensionHandler {
return func(_ sdk.Context, _ *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error) {
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil
}
}
// TxSelector defines a helper type that assists in selecting transactions during
// mempool transaction selection in PrepareProposal. It keeps track of the total
// number of bytes and total gas of the selected transactions. It also keeps
// track of the selected transactions themselves.
type TxSelector interface {
// SelectedTxs should return a copy of the selected transactions.
SelectedTxs(ctx context.Context) [][]byte
// Clear should clear the TxSelector, nulling out all relevant fields.
Clear()
// SelectTxForProposal should attempt to select a transaction for inclusion in
// a proposal based on inclusion criteria defined by the TxSelector. It must
// return <true> if the caller should halt the transaction selection loop
// (typically over a mempool) or <false> otherwise.
SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte) bool
}
type defaultTxSelector struct {
totalTxBytes uint64
totalTxGas uint64
selectedTxs [][]byte
}
func NewDefaultTxSelector() TxSelector {
return &defaultTxSelector{}
}
func (ts *defaultTxSelector) SelectedTxs(_ context.Context) [][]byte {
txs := make([][]byte, len(ts.selectedTxs))
copy(txs, ts.selectedTxs)
return txs
}
func (ts *defaultTxSelector) Clear() {
ts.totalTxBytes = 0
ts.totalTxGas = 0
ts.selectedTxs = nil
}
func (ts *defaultTxSelector) SelectTxForProposal(_ context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte) bool {
txSize := uint64(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{txBz}))
var txGasLimit uint64
if memTx != nil {
if gasTx, ok := memTx.(GasTx); ok {
txGasLimit = gasTx.GetGas()
}
}
// only add the transaction to the proposal if we have enough capacity
if (txSize + ts.totalTxBytes) <= maxTxBytes {
// If there is a max block gas limit, add the tx only if the limit has
// not been met.
if maxBlockGas > 0 {
if (txGasLimit + ts.totalTxGas) <= maxBlockGas {
ts.totalTxGas += txGasLimit
ts.totalTxBytes += txSize
ts.selectedTxs = append(ts.selectedTxs, txBz)
}
} else {
ts.totalTxBytes += txSize
ts.selectedTxs = append(ts.selectedTxs, txBz)
}
}
// check if we've reached capacity; if so, we cannot select any more transactions
return ts.totalTxBytes >= maxTxBytes || (maxBlockGas > 0 && (ts.totalTxGas >= maxBlockGas))
}

787
baseapp/abci_utils_test.go Normal file
View file

@ -0,0 +1,787 @@
package baseapp_test
import (
"bytes"
"sort"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
cmtsecp256k1 "github.com/cometbft/cometbft/crypto/secp256k1"
cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
cmttypes "github.com/cometbft/cometbft/types"
dbm "github.com/cosmos/cosmos-db"
protoio "github.com/cosmos/gogoproto/io"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"go.uber.org/mock/gomock"
"cosmossdk.io/core/comet"
"cosmossdk.io/core/header"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/baseapp"
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
"github.com/cosmos/cosmos-sdk/baseapp/testutil/mock"
"github.com/cosmos/cosmos-sdk/client"
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/mempool"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)
const (
chainID = "chain-id"
)
type testValidator struct {
consAddr sdk.ConsAddress
tmPk cmtprotocrypto.PublicKey
privKey cmtsecp256k1.PrivKey
}
func newTestValidator() testValidator {
privkey := cmtsecp256k1.GenPrivKey()
pubkey := privkey.PubKey()
tmPk := cmtprotocrypto.PublicKey{
Sum: &cmtprotocrypto.PublicKey_Secp256K1{
Secp256K1: pubkey.Bytes(),
},
}
return testValidator{
consAddr: sdk.ConsAddress(pubkey.Address()),
tmPk: tmPk,
privKey: privkey,
}
}
func (t testValidator) toValidator(power int64) abci.Validator {
return abci.Validator{
Address: t.consAddr.Bytes(),
Power: power,
}
}
type ABCIUtilsTestSuite struct {
suite.Suite
valStore *mock.MockValidatorStore
vals [3]testValidator
ctx sdk.Context
}
func NewABCIUtilsTestSuite(t *testing.T) *ABCIUtilsTestSuite {
t.Helper()
// create 3 validators
s := &ABCIUtilsTestSuite{
vals: [3]testValidator{
newTestValidator(),
newTestValidator(),
newTestValidator(),
},
}
// create mock
ctrl := gomock.NewController(t)
valStore := mock.NewMockValidatorStore(ctrl)
s.valStore = valStore
// set up mock
s.valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), s.vals[0].consAddr.Bytes()).Return(s.vals[0].tmPk, nil).AnyTimes()
s.valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), s.vals[1].consAddr.Bytes()).Return(s.vals[1].tmPk, nil).AnyTimes()
s.valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), s.vals[2].consAddr.Bytes()).Return(s.vals[2].tmPk, nil).AnyTimes()
// create context
s.ctx = sdk.Context{}.WithConsensusParams(cmtproto.ConsensusParams{
Abci: &cmtproto.ABCIParams{
VoteExtensionsEnableHeight: 2,
},
}).WithBlockHeader(cmtproto.Header{
ChainID: chainID,
}).WithLogger(log.NewTestLogger(t))
return s
}
func TestABCIUtilsTestSuite(t *testing.T) {
suite.Run(t, NewABCIUtilsTestSuite(t))
}
// check ValidateVoteExtensions works when all nodes have CommitBlockID votes
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsHappyPath() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
extSig1, err := s.vals[1].privKey.Sign(bz)
s.Require().NoError(err)
extSig2, err := s.vals[2].privKey.Sign(bz)
s.Require().NoError(err)
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // enable vote-extensions
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
{
Validator: s.vals[0].toValidator(333),
VoteExtension: ext,
ExtensionSignature: extSig0,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
{
Validator: s.vals[1].toValidator(333),
VoteExtension: ext,
ExtensionSignature: extSig1,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
{
Validator: s.vals[2].toValidator(334),
VoteExtension: ext,
ExtensionSignature: extSig2,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
},
}
// order + convert to last commit
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// expect-pass (votes of height 2 are included in next block)
s.Require().NoError(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
// check ValidateVoteExtensions works when a single node has submitted a BlockID_Absent
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsSingleVoteAbsent() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
extSig2, err := s.vals[2].privKey.Sign(bz)
s.Require().NoError(err)
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // vote-extensions are enabled
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
{
Validator: s.vals[0].toValidator(333),
VoteExtension: ext,
ExtensionSignature: extSig0,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
// validator of power <1/3 is missing, so commit-info shld still be valid
{
Validator: s.vals[1].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagAbsent,
},
{
Validator: s.vals[2].toValidator(334),
VoteExtension: ext,
ExtensionSignature: extSig2,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
},
}
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// expect-pass (votes of height 2 are included in next block)
s.Require().NoError(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
// check ValidateVoteExtensions works with duplicate votes
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsDuplicateVotes() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
ve := abci.ExtendedVoteInfo{
Validator: s.vals[0].toValidator(333),
VoteExtension: ext,
ExtensionSignature: extSig0,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
}
ve2 := abci.ExtendedVoteInfo{
Validator: s.vals[0].toValidator(334), // use diff voting-power to dupe
VoteExtension: ext,
ExtensionSignature: extSig0,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
}
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
ve,
ve2,
},
}
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // vote-extensions are enabled
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// expect fail (duplicate votes)
s.Require().Error(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
// check ValidateVoteExtensions works when a single node has submitted a BlockID_Nil
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsSingleVoteNil() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
extSig2, err := s.vals[2].privKey.Sign(bz)
s.Require().NoError(err)
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
{
Validator: s.vals[0].toValidator(333),
VoteExtension: ext,
ExtensionSignature: extSig0,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
// validator of power <1/3 is missing, so commit-info should still be valid
{
Validator: s.vals[1].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagNil,
},
{
Validator: s.vals[2].toValidator(334),
VoteExtension: ext,
ExtensionSignature: extSig2,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
},
},
}
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // vote-extensions are enabled
// create last commit
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// expect-pass (votes of height 2 are included in next block)
s.Require().NoError(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
// check ValidateVoteExtensions works when two nodes have submitted a BlockID_Nil / BlockID_Absent
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsTwoVotesNilAbsent() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
// validator of power >2/3 is missing, so commit-info should not be valid
{
Validator: s.vals[0].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagCommit,
VoteExtension: ext,
ExtensionSignature: extSig0,
},
{
Validator: s.vals[1].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagNil,
},
{
Validator: s.vals[2].toValidator(334),
VoteExtension: ext,
BlockIdFlag: cmtproto.BlockIDFlagAbsent,
},
},
}
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // vote-extensions are enabled
// create last commit
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// expect-pass (votes of height 2 are included in next block)
s.Require().Error(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsIncorrectVotingPower() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
// validator of power >2/3 is missing, so commit-info should not be valid
{
Validator: s.vals[0].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagCommit,
VoteExtension: ext,
ExtensionSignature: extSig0,
},
{
Validator: s.vals[1].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagNil,
},
{
Validator: s.vals[2].toValidator(334),
VoteExtension: ext,
BlockIdFlag: cmtproto.BlockIDFlagAbsent,
},
},
}
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // vote-extensions are enabled
// create last commit
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// modify voting powers to differ from the last-commit
llc.Votes[0].Validator.Power = 335
llc.Votes[2].Validator.Power = 332
// expect-pass (votes of height 2 are included in next block)
s.Require().Error(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsIncorrectOrder() {
ext := []byte("vote-extension")
cve := cmtproto.CanonicalVoteExtension{
Extension: ext,
Height: 2,
Round: int64(0),
ChainId: chainID,
}
bz, err := marshalDelimitedFn(&cve)
s.Require().NoError(err)
extSig0, err := s.vals[0].privKey.Sign(bz)
s.Require().NoError(err)
llc := abci.ExtendedCommitInfo{
Round: 0,
Votes: []abci.ExtendedVoteInfo{
// validator of power >2/3 is missing, so commit-info should not be valid
{
Validator: s.vals[0].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagCommit,
VoteExtension: ext,
ExtensionSignature: extSig0,
},
{
Validator: s.vals[1].toValidator(333),
BlockIdFlag: cmtproto.BlockIDFlagNil,
},
{
Validator: s.vals[2].toValidator(334),
VoteExtension: ext,
BlockIdFlag: cmtproto.BlockIDFlagAbsent,
},
},
}
s.ctx = s.ctx.WithBlockHeight(3).WithHeaderInfo(header.Info{Height: 3, ChainID: chainID}) // vote-extensions are enabled
// create last commit
llc, info := extendedCommitToLastCommit(llc)
s.ctx = s.ctx.WithCometInfo(info)
// modify voting powers to differ from the last-commit
llc.Votes[0], llc.Votes[2] = llc.Votes[2], llc.Votes[0]
// expect-pass (votes of height 2 are included in next block)
s.Require().Error(baseapp.ValidateVoteExtensions(s.ctx, s.valStore, 0, "", llc))
}
func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_NoOpMempoolTxSelection() {
// create a codec for marshaling
cdc := codectestutil.CodecOptions{}.NewCodec()
baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry())
// create a baseapp along with a tx config for tx generation
txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes)
app := baseapp.NewBaseApp(s.T().Name(), log.NewNopLogger(), dbm.NewMemDB(), txConfig.TxDecoder())
// create a proposal handler
ph := baseapp.NewDefaultProposalHandler(mempool.NoOpMempool{}, app)
handler := ph.PrepareProposalHandler()
// build a tx
_, _, addr := testdata.KeyTestPubAddr()
builder := txConfig.NewTxBuilder()
s.Require().NoError(builder.SetMsgs(
&baseapptestutil.MsgCounter{Counter: 0, FailOnHandler: false, Signer: addr.String()},
))
builder.SetGasLimit(100)
setTxSignature(s.T(), builder, 0)
// encode the tx to be used in the proposal request
tx := builder.GetTx()
txBz, err := txConfig.TxEncoder()(tx)
s.Require().NoError(err)
s.Require().Len(txBz, 152)
txDataSize := int(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{txBz}))
s.Require().Equal(txDataSize, 155)
testCases := map[string]struct {
ctx sdk.Context
req *abci.RequestPrepareProposal
expectedTxs int
}{
"small max tx bytes": {
ctx: s.ctx,
req: &abci.RequestPrepareProposal{
Txs: [][]byte{txBz, txBz, txBz, txBz, txBz},
MaxTxBytes: 10,
},
expectedTxs: 0,
},
"small max gas": {
ctx: s.ctx.WithConsensusParams(cmtproto.ConsensusParams{
Block: &cmtproto.BlockParams{
MaxGas: 10,
},
}),
req: &abci.RequestPrepareProposal{
Txs: [][]byte{txBz, txBz, txBz, txBz, txBz},
MaxTxBytes: 465,
},
expectedTxs: 0,
},
"large max tx bytes": {
ctx: s.ctx,
req: &abci.RequestPrepareProposal{
Txs: [][]byte{txBz, txBz, txBz, txBz, txBz},
MaxTxBytes: 465,
},
expectedTxs: 3,
},
"large max tx bytes len calculation": {
ctx: s.ctx,
req: &abci.RequestPrepareProposal{
Txs: [][]byte{txBz, txBz, txBz, txBz, txBz},
MaxTxBytes: 456,
},
expectedTxs: 2,
},
"max gas and tx bytes": {
ctx: s.ctx.WithConsensusParams(cmtproto.ConsensusParams{
Block: &cmtproto.BlockParams{
MaxGas: 200,
},
}),
req: &abci.RequestPrepareProposal{
Txs: [][]byte{txBz, txBz, txBz, txBz, txBz},
MaxTxBytes: 465,
},
expectedTxs: 2,
},
}
for name, tc := range testCases {
s.Run(name, func() {
// iterate multiple times to ensure the tx selector is cleared each time
for range 6 {
resp, err := handler(tc.ctx, tc.req)
s.Require().NoError(err)
s.Require().Len(resp.Txs, tc.expectedTxs)
}
})
}
}
func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_PriorityNonceMempoolTxSelection() {
cdc := codectestutil.CodecOptions{}.NewCodec()
baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry())
txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes)
var (
secret1 = []byte("secret1")
secret2 = []byte("secret2")
secret3 = []byte("secret3")
secret4 = []byte("secret4")
secret5 = []byte("secret5")
secret6 = []byte("secret6")
)
type testTx struct {
tx sdk.Tx
priority int64
bz []byte
size int
}
testTxs := []testTx{
// test 1
{tx: buildMsg(s.T(), txConfig, []byte(`0`), [][]byte{secret1}, []uint64{1}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`12345678910`), [][]byte{secret1}, []uint64{2}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`22`), [][]byte{secret1}, []uint64{3}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`32`), [][]byte{secret2}, []uint64{1}), priority: 8},
// test 2
{tx: buildMsg(s.T(), txConfig, []byte(`4`), [][]byte{secret1, secret2}, []uint64{3, 3}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`52345678910`), [][]byte{secret1, secret3}, []uint64{4, 3}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`62`), [][]byte{secret1, secret4}, []uint64{5, 3}), priority: 8},
{tx: buildMsg(s.T(), txConfig, []byte(`72`), [][]byte{secret3, secret5}, []uint64{4, 3}), priority: 8},
{tx: buildMsg(s.T(), txConfig, []byte(`82`), [][]byte{secret2, secret6}, []uint64{4, 3}), priority: 8},
// test 3
{tx: buildMsg(s.T(), txConfig, []byte(`9`), [][]byte{secret3, secret4}, []uint64{3, 3}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`1052345678910`), [][]byte{secret1, secret2}, []uint64{4, 4}), priority: 8},
{tx: buildMsg(s.T(), txConfig, []byte(`11`), [][]byte{secret1, secret2}, []uint64{5, 5}), priority: 8},
// test 4
{tx: buildMsg(s.T(), txConfig, []byte(`1252345678910`), [][]byte{secret1}, []uint64{3}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`13`), [][]byte{secret1}, []uint64{5}), priority: 10},
{tx: buildMsg(s.T(), txConfig, []byte(`14`), [][]byte{secret1}, []uint64{6}), priority: 8},
}
for i := range testTxs {
bz, err := txConfig.TxEncoder()(testTxs[i].tx)
s.Require().NoError(err)
testTxs[i].bz = bz
testTxs[i].size = int(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{bz}))
}
s.Require().Equal(testTxs[0].size, 111)
s.Require().Equal(testTxs[1].size, 121)
s.Require().Equal(testTxs[2].size, 112)
s.Require().Equal(testTxs[3].size, 112)
s.Require().Equal(testTxs[4].size, 195)
s.Require().Equal(testTxs[5].size, 205)
s.Require().Equal(testTxs[6].size, 196)
s.Require().Equal(testTxs[7].size, 196)
s.Require().Equal(testTxs[8].size, 196)
testCases := map[string]struct {
ctx sdk.Context
txInputs []testTx
req *abci.RequestPrepareProposal
handler sdk.PrepareProposalHandler
expectedTxs []int
}{
"skip same-sender non-sequential sequence and then add others txs": {
ctx: s.ctx,
txInputs: []testTx{testTxs[0], testTxs[1], testTxs[2], testTxs[3]},
req: &abci.RequestPrepareProposal{
MaxTxBytes: 111 + 112,
},
expectedTxs: []int{0, 3},
},
"skip multi-signers msg non-sequential sequence": {
ctx: s.ctx,
txInputs: []testTx{testTxs[4], testTxs[5], testTxs[6], testTxs[7], testTxs[8]},
req: &abci.RequestPrepareProposal{
MaxTxBytes: 195 + 196,
},
expectedTxs: []int{4, 8},
},
"only the first tx is added": {
// Because tx 10 is valid, tx 11 can't be valid as they have higher sequence numbers.
ctx: s.ctx,
txInputs: []testTx{testTxs[9], testTxs[10], testTxs[11]},
req: &abci.RequestPrepareProposal{
MaxTxBytes: 195 + 196,
},
expectedTxs: []int{9},
},
"no txs added": {
// Becasuse the first tx was deemed valid but too big, the next expected valid sequence is tx[0].seq (3), so
// the rest of the txs fail because they have a seq of 4.
ctx: s.ctx,
txInputs: []testTx{testTxs[12], testTxs[13], testTxs[14]},
req: &abci.RequestPrepareProposal{
MaxTxBytes: 112,
},
expectedTxs: []int{},
},
}
for name, tc := range testCases {
s.Run(name, func() {
ctrl := gomock.NewController(s.T())
app := mock.NewMockProposalTxVerifier(ctrl)
mp := mempool.NewPriorityMempool(
mempool.PriorityNonceMempoolConfig[int64]{
TxPriority: mempool.NewDefaultTxPriority(),
MaxTx: 0,
SignerExtractor: mempool.NewDefaultSignerExtractionAdapter(),
},
)
ph := baseapp.NewDefaultProposalHandler(mp, app)
for _, v := range tc.txInputs {
app.EXPECT().PrepareProposalVerifyTx(v.tx).Return(v.bz, nil).AnyTimes()
s.NoError(mp.Insert(s.ctx.WithPriority(v.priority), v.tx))
tc.req.Txs = append(tc.req.Txs, v.bz)
}
resp, err := ph.PrepareProposalHandler()(tc.ctx, tc.req)
s.Require().NoError(err)
respTxIndexes := []int{}
for _, tx := range resp.Txs {
for i, v := range testTxs {
if bytes.Equal(tx, v.bz) {
respTxIndexes = append(respTxIndexes, i)
}
}
}
s.Require().EqualValues(tc.expectedTxs, respTxIndexes)
})
}
}
func marshalDelimitedFn(msg proto.Message) ([]byte, error) {
var buf bytes.Buffer
if err := protoio.NewDelimitedWriter(&buf).WriteMsg(msg); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func buildMsg(t *testing.T, txConfig client.TxConfig, value []byte, secrets [][]byte, nonces []uint64) sdk.Tx {
t.Helper()
builder := txConfig.NewTxBuilder()
_ = builder.SetMsgs(
&baseapptestutil.MsgKeyValue{Value: value},
)
require.Equal(t, len(secrets), len(nonces))
signatures := make([]signingtypes.SignatureV2, 0)
for index, secret := range secrets {
nonce := nonces[index]
privKey := secp256k1.GenPrivKeyFromSecret(secret)
pubKey := privKey.PubKey()
signatures = append(signatures, signingtypes.SignatureV2{
PubKey: pubKey,
Sequence: nonce,
Data: &signingtypes.SingleSignatureData{},
})
}
setTxSignatureWithSecret(t, builder, signatures...)
return builder.GetTx()
}
func setTxSignatureWithSecret(t *testing.T, builder client.TxBuilder, signatures ...signingtypes.SignatureV2) {
t.Helper()
err := builder.SetSignatures(
signatures...,
)
require.NoError(t, err)
}
func extendedCommitToLastCommit(ec abci.ExtendedCommitInfo) (abci.ExtendedCommitInfo, comet.BlockInfo) {
// sort the extended commit info
sort.Sort(extendedVoteInfos(ec.Votes))
// convert the extended commit info to last commit info
lastCommit := abci.CommitInfo{
Round: ec.Round,
Votes: make([]abci.VoteInfo, len(ec.Votes)),
}
for i, vote := range ec.Votes {
lastCommit.Votes[i] = abci.VoteInfo{
Validator: abci.Validator{
Address: vote.Validator.Address,
Power: vote.Validator.Power,
},
}
}
return ec, baseapp.NewBlockInfo(
nil,
nil,
nil,
lastCommit,
)
}
type extendedVoteInfos []abci.ExtendedVoteInfo
func (v extendedVoteInfos) Len() int {
return len(v)
}
func (v extendedVoteInfos) Less(i, j int) bool {
if v[i].Validator.Power == v[j].Validator.Power {
return bytes.Compare(v[i].Validator.Address, v[j].Validator.Address) == -1
}
return v[i].Validator.Power > v[j].Validator.Power
}
func (v extendedVoteInfos) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}

1211
baseapp/baseapp.go Normal file

File diff suppressed because it is too large Load diff

1025
baseapp/baseapp_test.go Normal file

File diff suppressed because it is too large Load diff

253
baseapp/block_gas_test.go Normal file
View file

@ -0,0 +1,253 @@
package baseapp_test
import (
"context"
"math"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
cmtjson "github.com/cometbft/cometbft/libs/json"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
store "cosmossdk.io/store/types"
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)
var blockMaxGas = uint64(simtestutil.DefaultConsensusParams.Block.MaxGas)
type BlockGasImpl struct {
panicTx bool
gasToConsume uint64
key store.StoreKey
}
func (m BlockGasImpl) Set(ctx context.Context, msg *baseapptestutil.MsgKeyValue) (*baseapptestutil.MsgCreateKeyValueResponse, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
sdkCtx.KVStore(m.key).Set(msg.Key, msg.Value)
sdkCtx.GasMeter().ConsumeGas(m.gasToConsume, "TestMsg")
if m.panicTx {
panic("panic in tx execution")
}
return &baseapptestutil.MsgCreateKeyValueResponse{}, nil
}
func TestBaseApp_BlockGas(t *testing.T) {
testcases := []struct {
name string
gasToConsume uint64 // gas to consume in the msg execution
panicTx bool // panic explicitly in tx execution
expErr bool
}{
{"less than block gas meter", 10, false, false},
{"more than block gas meter", blockMaxGas, false, true},
{"more than block gas meter", uint64(float64(blockMaxGas) * 1.2), false, true},
{"consume MaxUint64", math.MaxUint64, true, true},
{"consume MaxGasWanted", txtypes.MaxGasWanted, false, true},
{"consume block gas when panicked", 10, true, true},
}
for _, tc := range testcases {
var (
bankKeeper bankkeeper.Keeper
accountKeeper authkeeper.AccountKeeper
appBuilder *runtime.AppBuilder
txConfig client.TxConfig
cdc codec.Codec
interfaceRegistry codectypes.InterfaceRegistry
err error
)
err = depinject.Inject(
depinject.Configs(
configurator.NewAppConfig(
configurator.AuthModule(),
configurator.TxModule(),
configurator.ConsensusModule(),
configurator.BankModule(),
configurator.StakingModule(),
),
depinject.Supply(log.NewNopLogger()),
),
&bankKeeper,
&accountKeeper,
&interfaceRegistry,
&txConfig,
&cdc,
&appBuilder)
require.NoError(t, err)
bapp := appBuilder.Build(dbm.NewMemDB(), nil)
err = bapp.Load(true)
require.NoError(t, err)
t.Run(tc.name, func(t *testing.T) {
baseapptestutil.RegisterInterfaces(interfaceRegistry)
baseapptestutil.RegisterKeyValueServer(bapp.MsgServiceRouter(), BlockGasImpl{
panicTx: tc.panicTx,
gasToConsume: tc.gasToConsume,
key: bapp.UnsafeFindStoreKey(banktypes.ModuleName),
})
genState := GenesisStateWithSingleValidator(t, cdc, appBuilder)
stateBytes, err := cmtjson.MarshalIndent(genState, "", " ")
require.NoError(t, err)
_, err = bapp.InitChain(&abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: simtestutil.DefaultConsensusParams,
AppStateBytes: stateBytes,
})
require.NoError(t, err)
ctx := bapp.NewContext(false)
// tx fee
feeCoin := sdk.NewCoin("atom", sdkmath.NewInt(150))
feeAmount := sdk.NewCoins(feeCoin)
// test account and fund
priv1, _, addr1 := testdata.KeyTestPubAddr()
err = bankKeeper.MintCoins(ctx, minttypes.ModuleName, feeAmount)
require.NoError(t, err)
err = bankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr1, feeAmount)
require.NoError(t, err)
require.Equal(t, feeCoin.Amount, bankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount)
seq := accountKeeper.GetAccount(ctx, addr1).GetSequence()
require.Equal(t, uint64(0), seq)
// msg and signatures
msg := &baseapptestutil.MsgKeyValue{
Key: []byte("ok"),
Value: []byte("ok"),
Signer: addr1.String(),
}
txBuilder := txConfig.NewTxBuilder()
require.NoError(t, txBuilder.SetMsgs(msg))
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(uint64(simtestutil.DefaultConsensusParams.Block.MaxGas))
senderAccountNumber := accountKeeper.GetAccount(ctx, addr1).GetAccountNumber()
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{senderAccountNumber}, []uint64{0}
_, txBytes, err := createTestTx(txConfig, txBuilder, privs, accNums, accSeqs, ctx.ChainID())
require.NoError(t, err)
rsp, err := bapp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1, Txs: [][]byte{txBytes}})
require.NoError(t, err)
// check result
ctx = bapp.GetContextForFinalizeBlock(txBytes)
okValue := ctx.KVStore(bapp.UnsafeFindStoreKey(banktypes.ModuleName)).Get([]byte("ok"))
if tc.expErr {
if tc.panicTx {
require.Equal(t, sdkerrors.ErrPanic.ABCICode(), rsp.TxResults[0].Code)
} else {
require.Equal(t, sdkerrors.ErrOutOfGas.ABCICode(), rsp.TxResults[0].Code)
}
require.Empty(t, okValue)
} else {
require.Equal(t, uint32(0), rsp.TxResults[0].Code)
require.Equal(t, []byte("ok"), okValue)
}
// check block gas is always consumed
baseGas := uint64(57504) // baseGas is the gas consumed before tx msg
expGasConsumed := min(addUint64Saturating(tc.gasToConsume, baseGas), uint64(simtestutil.DefaultConsensusParams.Block.MaxGas))
require.Equal(t, int(expGasConsumed), int(ctx.BlockGasMeter().GasConsumed()))
// tx fee is always deducted
require.Equal(t, int64(0), bankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount.Int64())
// sender's sequence is always increased
seq = accountKeeper.GetAccount(ctx, addr1).GetSequence()
require.NoError(t, err)
require.Equal(t, uint64(1), seq)
})
}
}
func createTestTx(txConfig client.TxConfig, txBuilder client.TxBuilder, privs []cryptotypes.PrivKey, accNums, accSeqs []uint64, chainID string) (xauthsigning.Tx, []byte, error) {
defaultSignMode, err := xauthsigning.APISignModeToInternal(txConfig.SignModeHandler().DefaultMode())
if err != nil {
return nil, nil, err
}
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
var sigsV2 []signing.SignatureV2
for i, priv := range privs {
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: defaultSignMode,
Signature: nil,
},
Sequence: accSeqs[i],
}
sigsV2 = append(sigsV2, sigV2)
}
err = txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, nil, err
}
// Second round: all signer infos are set, so each signer can sign.
sigsV2 = []signing.SignatureV2{}
for i, priv := range privs {
signerData := xauthsigning.SignerData{
Address: sdk.AccAddress(priv.PubKey().Bytes()).String(),
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
PubKey: priv.PubKey(),
}
sigV2, err := tx.SignWithPrivKey(
context.TODO(), defaultSignMode, signerData,
txBuilder, priv, txConfig, accSeqs[i])
if err != nil {
return nil, nil, err
}
sigsV2 = append(sigsV2, sigV2)
}
err = txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, nil, err
}
txBytes, err := txConfig.TxEncoder()(txBuilder.GetTx())
if err != nil {
return nil, nil, err
}
return txBuilder.GetTx(), txBytes, nil
}
func addUint64Saturating(a, b uint64) uint64 {
if math.MaxUint64-a < b {
return math.MaxUint64
}
return a + b
}

8
baseapp/circuit.go Normal file
View file

@ -0,0 +1,8 @@
package baseapp
import "context"
// CircuitBreaker is an interface that defines the methods for a circuit breaker.
type CircuitBreaker interface {
IsAllowed(ctx context.Context, typeURL string) (bool, error)
}

23
baseapp/genesis.go Normal file
View file

@ -0,0 +1,23 @@
package baseapp
import (
"errors"
"github.com/cometbft/cometbft/abci/types"
"cosmossdk.io/core/genesis"
)
var _ genesis.TxHandler = (*BaseApp)(nil)
// ExecuteGenesisTx implements genesis.GenesisState from
// cosmossdk.io/core/genesis to set initial state in genesis
func (ba *BaseApp) ExecuteGenesisTx(tx []byte) error {
res := ba.deliverTx(tx)
if res.Code != types.CodeTypeOK {
return errors.New(res.Log)
}
return nil
}

159
baseapp/grpcrouter.go Normal file
View file

@ -0,0 +1,159 @@
package baseapp
import (
"context"
"fmt"
abci "github.com/cometbft/cometbft/abci/types"
gogogrpc "github.com/cosmos/gogoproto/grpc"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
"google.golang.org/protobuf/runtime/protoiface"
"github.com/cosmos/cosmos-sdk/baseapp/internal/protocompat"
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GRPCQueryRouter routes ABCI Query requests to GRPC handlers
type GRPCQueryRouter struct {
// routes maps query handlers used in ABCIQuery.
routes map[string]GRPCQueryHandler
// hybridHandlers maps the request name to the handler. It is a hybrid handler which seamlessly
// handles both gogo and protov2 messages.
hybridHandlers map[string][]func(ctx context.Context, req, resp protoiface.MessageV1) error
// binaryCodec is used to encode/decode binary protobuf messages.
binaryCodec codec.BinaryCodec
// cdc is the gRPC codec used by the router to correctly unmarshal messages.
cdc encoding.Codec
// serviceData contains the gRPC services and their handlers.
serviceData []serviceData
}
// serviceData represents a gRPC service, along with its handler.
type serviceData struct {
serviceDesc *grpc.ServiceDesc
handler any
}
var _ gogogrpc.Server = &GRPCQueryRouter{}
// NewGRPCQueryRouter creates a new GRPCQueryRouter
func NewGRPCQueryRouter() *GRPCQueryRouter {
return &GRPCQueryRouter{
routes: map[string]GRPCQueryHandler{},
hybridHandlers: map[string][]func(ctx context.Context, req, resp protoiface.MessageV1) error{},
}
}
// GRPCQueryHandler defines a function type which handles ABCI Query requests
// using gRPC
type GRPCQueryHandler = func(ctx sdk.Context, req *abci.RequestQuery) (*abci.ResponseQuery, error)
// Route returns the GRPCQueryHandler for a given query route path or nil
// if not found
func (qrt *GRPCQueryRouter) Route(path string) GRPCQueryHandler {
handler, found := qrt.routes[path]
if !found {
return nil
}
return handler
}
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
// service description, handler is an object which implements that gRPC service/
//
// This functions PANICS:
// - if a protobuf service is registered twice.
func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler any) {
// adds a top-level query handler based on the gRPC service name
for _, method := range sd.Methods {
err := qrt.registerABCIQueryHandler(sd, method, handler)
if err != nil {
panic(err)
}
err = qrt.registerHybridHandler(sd, method, handler)
if err != nil {
panic(err)
}
}
qrt.serviceData = append(qrt.serviceData, serviceData{
serviceDesc: sd,
handler: handler,
})
}
func (qrt *GRPCQueryRouter) registerABCIQueryHandler(sd *grpc.ServiceDesc, method grpc.MethodDesc, handler any) error {
fqName := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
methodHandler := method.Handler
// Check that each service is only registered once. If a service is
// registered more than once, then we should error. Since we can't
// return an error (`Server.RegisterService` interface restriction) we
// panic (at startup).
_, found := qrt.routes[fqName]
if found {
return fmt.Errorf(
"gRPC query service %s has already been registered. Please make sure to only register each service once. "+
"This usually means that there are conflicting modules registering the same gRPC query service",
fqName,
)
}
qrt.routes[fqName] = func(ctx sdk.Context, req *abci.RequestQuery) (*abci.ResponseQuery, error) {
// call the method handler from the service description with the handler object,
// a wrapped sdk.Context with proto-unmarshaled data from the ABCI request data
res, err := methodHandler(handler, ctx, func(i any) error {
return qrt.cdc.Unmarshal(req.Data, i)
}, nil)
if err != nil {
return nil, err
}
// proto marshal the result bytes
var resBytes []byte
resBytes, err = qrt.cdc.Marshal(res)
if err != nil {
return nil, err
}
// return the result bytes as the response value
return &abci.ResponseQuery{
Height: req.Height,
Value: resBytes,
}, nil
}
return nil
}
func (qrt *GRPCQueryRouter) HybridHandlerByRequestName(name string) []func(ctx context.Context, req, resp protoiface.MessageV1) error {
return qrt.hybridHandlers[name]
}
func (qrt *GRPCQueryRouter) registerHybridHandler(sd *grpc.ServiceDesc, method grpc.MethodDesc, handler any) error {
// extract message name from method descriptor
inputName, err := protocompat.RequestFullNameFromMethodDesc(sd, method)
if err != nil {
return err
}
methodHandler, err := protocompat.MakeHybridHandler(qrt.binaryCodec, sd, method, handler)
if err != nil {
return err
}
qrt.hybridHandlers[string(inputName)] = append(qrt.hybridHandlers[string(inputName)], methodHandler)
return nil
}
// SetInterfaceRegistry sets the interface registry for the router. This will
// also register the interface reflection gRPC service.
func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) {
// instantiate the codec
qrt.cdc = codec.NewProtoCodec(interfaceRegistry).GRPCCodec()
qrt.binaryCodec = codec.NewProtoCodec(interfaceRegistry)
// Once we have an interface registry, we can register the interface
// registry reflection gRPC service.
reflection.RegisterReflectionServiceServer(qrt, reflection.NewReflectionServiceServer(interfaceRegistry))
}

View file

@ -0,0 +1,64 @@
package baseapp
import (
gocontext "context"
"fmt"
abci "github.com/cometbft/cometbft/abci/types"
gogogrpc "github.com/cosmos/gogoproto/grpc"
"google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// QueryServiceTestHelper provides a helper for making grpc query service
// rpc calls in unit tests. It implements both the grpc Server and ClientConn
// interfaces needed to register a query service server and create a query
// service client.
type QueryServiceTestHelper struct {
*GRPCQueryRouter
Ctx sdk.Context
}
var (
_ gogogrpc.Server = &QueryServiceTestHelper{}
_ gogogrpc.ClientConn = &QueryServiceTestHelper{}
)
// NewQueryServerTestHelper creates a new QueryServiceTestHelper that wraps
// the provided sdk.Context
func NewQueryServerTestHelper(ctx sdk.Context, interfaceRegistry types.InterfaceRegistry) *QueryServiceTestHelper {
qrt := NewGRPCQueryRouter()
qrt.SetInterfaceRegistry(interfaceRegistry)
return &QueryServiceTestHelper{GRPCQueryRouter: qrt, Ctx: ctx}
}
// Invoke implements the grpc ClientConn.Invoke method
func (q *QueryServiceTestHelper) Invoke(_ gocontext.Context, method string, args, reply any, _ ...grpc.CallOption) error {
querier := q.Route(method)
if querier == nil {
return fmt.Errorf("handler not found for %s", method)
}
reqBz, err := q.cdc.Marshal(args)
if err != nil {
return err
}
res, err := querier(q.Ctx, &abci.RequestQuery{Data: reqBz})
if err != nil {
return err
}
err = q.cdc.Unmarshal(res.Value, reply)
if err != nil {
return err
}
return nil
}
// NewStream implements the grpc ClientConn.NewStream method
func (q *QueryServiceTestHelper) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) {
return nil, fmt.Errorf("not supported")
}

224
baseapp/grpcrouter_test.go Normal file
View file

@ -0,0 +1,224 @@
package baseapp_test
import (
"context"
"sync"
"testing"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestGRPCQueryRouter(t *testing.T) {
qr := baseapp.NewGRPCQueryRouter()
interfaceRegistry := testdata.NewTestInterfaceRegistry()
qr.SetInterfaceRegistry(interfaceRegistry)
testdata_pulsar.RegisterQueryServer(qr, testdata_pulsar.QueryImpl{})
helper := &baseapp.QueryServiceTestHelper{
GRPCQueryRouter: qr,
Ctx: sdk.Context{}.WithContext(context.Background()),
}
client := testdata.NewQueryClient(helper)
res, err := client.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
require.Nil(t, err)
require.NotNil(t, res)
require.Equal(t, "hello", res.Message)
res, err = client.Echo(context.Background(), nil)
require.Nil(t, err)
require.Empty(t, res.Message)
res2, err := client.SayHello(context.Background(), &testdata.SayHelloRequest{Name: "Foo"})
require.Nil(t, err)
require.NotNil(t, res)
require.Equal(t, "Hello Foo!", res2.Greeting)
spot := &testdata.Dog{Name: "Spot", Size_: "big"}
any, err := types.NewAnyWithValue(spot)
require.NoError(t, err)
res3, err := client.TestAny(context.Background(), &testdata.TestAnyRequest{AnyAnimal: any})
require.NoError(t, err)
require.NotNil(t, res3)
require.Equal(t, spot, res3.HasAnimal.Animal.GetCachedValue())
}
func TestGRPCRouterHybridHandlers(t *testing.T) {
assertRouterBehaviour := func(helper *baseapp.QueryServiceTestHelper) {
// test getting the handler by name
handlers := helper.HybridHandlerByRequestName("testpb.EchoRequest")
require.NotNil(t, handlers)
require.Len(t, handlers, 1)
handler := handlers[0]
// sending a protov2 message should work, and return a protov2 message
v2Resp := new(testdata_pulsar.EchoResponse)
err := handler(helper.Ctx, &testdata_pulsar.EchoRequest{Message: "hello"}, v2Resp)
require.Nil(t, err)
require.Equal(t, "hello", v2Resp.Message)
// also sending a protov1 message should work, and return a gogoproto message
gogoResp := new(testdata.EchoResponse)
err = handler(helper.Ctx, &testdata.EchoRequest{Message: "hello"}, gogoResp)
require.NoError(t, err)
require.Equal(t, "hello", gogoResp.Message)
}
t.Run("protov2 server", func(t *testing.T) {
qr := baseapp.NewGRPCQueryRouter()
interfaceRegistry := testdata.NewTestInterfaceRegistry()
qr.SetInterfaceRegistry(interfaceRegistry)
testdata_pulsar.RegisterQueryServer(qr, testdata_pulsar.QueryImpl{})
helper := &baseapp.QueryServiceTestHelper{
GRPCQueryRouter: qr,
Ctx: sdk.Context{}.WithContext(context.Background()),
}
assertRouterBehaviour(helper)
})
t.Run("gogoproto server", func(t *testing.T) {
qr := baseapp.NewGRPCQueryRouter()
interfaceRegistry := testdata.NewTestInterfaceRegistry()
qr.SetInterfaceRegistry(interfaceRegistry)
testdata.RegisterQueryServer(qr, testdata.QueryImpl{})
helper := &baseapp.QueryServiceTestHelper{
GRPCQueryRouter: qr,
Ctx: sdk.Context{}.WithContext(context.Background()),
}
assertRouterBehaviour(helper)
})
}
func TestRegisterQueryServiceTwice(t *testing.T) {
// Setup baseapp.
var appBuilder *runtime.AppBuilder
err := depinject.Inject(
depinject.Configs(
makeMinimalConfig(),
depinject.Supply(log.NewTestLogger(t)),
),
&appBuilder)
require.NoError(t, err)
db := dbm.NewMemDB()
app := appBuilder.Build(db, nil)
// First time registering service shouldn't panic.
require.NotPanics(t, func() {
testdata.RegisterQueryServer(
app.GRPCQueryRouter(),
testdata.QueryImpl{},
)
})
// Second time should panic.
require.Panics(t, func() {
testdata.RegisterQueryServer(
app.GRPCQueryRouter(),
testdata.QueryImpl{},
)
})
}
// Tests that we don't have data races per
// https://github.com/cosmos/cosmos-sdk/issues/10324
// but with the same client connection being used concurrently.
func TestQueryDataRaces_sameConnectionToSameHandler(t *testing.T) {
var mu sync.Mutex
var helper *baseapp.QueryServiceTestHelper
makeClientConn := func(qr *baseapp.GRPCQueryRouter) *baseapp.QueryServiceTestHelper {
mu.Lock()
defer mu.Unlock()
if helper == nil {
helper = &baseapp.QueryServiceTestHelper{
GRPCQueryRouter: qr,
Ctx: sdk.Context{}.WithContext(context.Background()),
}
}
return helper
}
testQueryDataRacesSameHandler(t, makeClientConn)
}
// Tests that we don't have data races per
// https://github.com/cosmos/cosmos-sdk/issues/10324
// but with unique client connections requesting from the same handler concurrently.
func TestQueryDataRaces_uniqueConnectionsToSameHandler(t *testing.T) {
// Return a new handler for every single call.
testQueryDataRacesSameHandler(t, func(qr *baseapp.GRPCQueryRouter) *baseapp.QueryServiceTestHelper {
return &baseapp.QueryServiceTestHelper{
GRPCQueryRouter: qr,
Ctx: sdk.Context{}.WithContext(context.Background()),
}
})
}
func testQueryDataRacesSameHandler(t *testing.T, makeClientConn func(*baseapp.GRPCQueryRouter) *baseapp.QueryServiceTestHelper) {
t.Helper()
t.Parallel()
qr := baseapp.NewGRPCQueryRouter()
interfaceRegistry := testdata.NewTestInterfaceRegistry()
qr.SetInterfaceRegistry(interfaceRegistry)
testdata.RegisterQueryServer(qr, testdata.QueryImpl{})
// The goal is to invoke the router concurrently and check for any data races.
// 0. Run with: go test -race
// 1. Synchronize every one of the 1,000 goroutines waiting to all query at the
// same time.
// 2. Once the greenlight is given, perform a query through the router.
var wg sync.WaitGroup
defer wg.Wait()
greenlight := make(chan bool)
n := 1000
ready := make(chan bool, n)
go func() {
for range n {
<-ready
}
close(greenlight)
}()
for range n {
wg.Add(1)
go func() {
defer wg.Done()
// Wait until we get the green light to start.
ready <- true
<-greenlight
client := testdata.NewQueryClient(makeClientConn(qr))
res, err := client.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
require.Nil(t, err)
require.NotNil(t, res)
require.Equal(t, "hello", res.Message)
res, err = client.Echo(context.Background(), nil)
require.Nil(t, err)
require.Empty(t, res.Message)
res2, err := client.SayHello(context.Background(), &testdata.SayHelloRequest{Name: "Foo"})
require.Nil(t, err)
require.NotNil(t, res)
require.Equal(t, "Hello Foo!", res2.Greeting)
spot := &testdata.Dog{Name: "Spot", Size_: "big"}
any, err := types.NewAnyWithValue(spot)
require.NoError(t, err)
res3, err := client.TestAny(context.Background(), &testdata.TestAnyRequest{AnyAnimal: any})
require.NoError(t, err)
require.NotNil(t, res3)
require.Equal(t, spot, res3.HasAnimal.Animal.GetCachedValue())
}()
}
}

128
baseapp/grpcserver.go Normal file
View file

@ -0,0 +1,128 @@
package baseapp
import (
"context"
"fmt"
"strconv"
gogogrpc "github.com/cosmos/gogoproto/grpc"
grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
)
// RegisterGRPCServer registers gRPC services directly with the gRPC server.
func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) {
app.RegisterGRPCServerWithSkipCheckHeader(server, false)
}
// RegisterGRPCServerWithSkipCheckHeader registers gRPC services with the specified gRPC server
// and bypass check header flag. During the commit phase, gRPC queries may be processed before the block header
// is fully updated, causing header checks to fail erroneously. Skipping the header check in these cases prevents
// false negatives and ensures more robust query handling. While bypassing the header check is generally preferred to avoid false
// negatives during the commit phase, there are niche scenarios where someone might want to enable it.
// For instance, if an application requires strict validation to ensure that the query context exactly
// reflects the expected block header (for consistency or security reasons), then enabling header checks
// could be beneficial. However, this strictness comes at the cost of potentially more frequent errors
// when queries occur during the commit phase.
func (app *BaseApp) RegisterGRPCServerWithSkipCheckHeader(server gogogrpc.Server, skipCheckHeader bool) {
// Define an interceptor for all gRPC queries: this interceptor will create
// a new sdk.Context, and pass it into the query handler.
interceptor := func(grpcCtx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
// If there's some metadata in the context, retrieve it.
md, ok := metadata.FromIncomingContext(grpcCtx)
if !ok {
return nil, status.Error(codes.Internal, "unable to retrieve metadata")
}
// Get height header from the request context, if present.
var height int64
if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) == 1 {
height, err = strconv.ParseInt(heightHeaders[0], 10, 64)
if err != nil {
return nil, errorsmod.Wrapf(
sdkerrors.ErrInvalidRequest,
"Baseapp.RegisterGRPCServer: invalid height header %q: %v", grpctypes.GRPCBlockHeightHeader, err)
}
if err := checkNegativeHeight(height); err != nil {
return nil, err
}
}
// Create the sdk.Context. Passing false as 2nd arg, as we can't
// actually support proofs with gRPC right now.
sdkCtx, err := app.CreateQueryContextWithCheckHeader(height, false, !skipCheckHeader)
if err != nil {
return nil, err
}
// Add relevant gRPC headers
if height == 0 {
height = sdkCtx.BlockHeight() // If height was not set in the request, set it to the latest
}
// Attach the sdk.Context into the gRPC's context.Context.
grpcCtx = context.WithValue(grpcCtx, sdk.SdkContextKey, sdkCtx)
md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(height, 10))
if err = grpc.SetHeader(grpcCtx, md); err != nil {
app.logger.Error("failed to set gRPC header", "err", err)
}
app.logger.Debug("gRPC query received", "type", fmt.Sprintf("%#v", req))
// Catch an OutOfGasPanic caused in the query handlers
defer func() {
if r := recover(); r != nil {
switch rType := r.(type) {
case storetypes.ErrorOutOfGas:
err = errorsmod.Wrapf(sdkerrors.ErrOutOfGas, "Query gas limit exceeded: %v, out of gas in location: %v", sdkCtx.GasMeter().Limit(), rType.Descriptor)
default:
panic(r)
}
}
}()
return handler(grpcCtx, req)
}
// Loop through all services and methods, add the interceptor, and register
// the service.
for _, data := range app.GRPCQueryRouter().serviceData {
desc := data.serviceDesc
newMethods := make([]grpc.MethodDesc, len(desc.Methods))
for i, method := range desc.Methods {
methodHandler := method.Handler
newMethods[i] = grpc.MethodDesc{
MethodName: method.MethodName,
Handler: func(srv any, ctx context.Context, dec func(any) error, _ grpc.UnaryServerInterceptor) (any, error) {
return methodHandler(srv, ctx, dec, grpcmiddleware.ChainUnaryServer(
grpcrecovery.UnaryServerInterceptor(),
interceptor,
))
},
}
}
newDesc := &grpc.ServiceDesc{
ServiceName: desc.ServiceName,
HandlerType: desc.HandlerType,
Methods: newMethods,
Streams: desc.Streams,
Metadata: desc.Metadata,
}
server.RegisterService(newDesc, data.handler)
}
}

211
baseapp/info.go Normal file
View file

@ -0,0 +1,211 @@
package baseapp
import (
"time"
abci "github.com/cometbft/cometbft/abci/types"
"cosmossdk.io/core/comet"
)
// NewBlockInfo returns a new BlockInfo instance
// This function should be only used in tests
func NewBlockInfo(
misbehavior []abci.Misbehavior,
validatorsHash []byte,
proposerAddress []byte,
lastCommit abci.CommitInfo,
) comet.BlockInfo {
return &cometInfo{
Misbehavior: misbehavior,
ValidatorsHash: validatorsHash,
ProposerAddress: proposerAddress,
LastCommit: lastCommit,
}
}
// CometInfo defines the properties provided by comet to the application
type cometInfo struct {
Misbehavior []abci.Misbehavior
ValidatorsHash []byte
ProposerAddress []byte
LastCommit abci.CommitInfo
}
func (r cometInfo) GetEvidence() comet.EvidenceList {
return evidenceWrapper{evidence: r.Misbehavior}
}
func (r cometInfo) GetValidatorsHash() []byte {
return r.ValidatorsHash
}
func (r cometInfo) GetProposerAddress() []byte {
return r.ProposerAddress
}
func (r cometInfo) GetLastCommit() comet.CommitInfo {
return commitInfoWrapper{r.LastCommit}
}
type evidenceWrapper struct {
evidence []abci.Misbehavior
}
func (e evidenceWrapper) Len() int {
return len(e.evidence)
}
func (e evidenceWrapper) Get(i int) comet.Evidence {
return misbehaviorWrapper{e.evidence[i]}
}
// commitInfoWrapper is a wrapper around abci.CommitInfo that implements CommitInfo interface
type commitInfoWrapper struct {
abci.CommitInfo
}
var _ comet.CommitInfo = (*commitInfoWrapper)(nil)
func (c commitInfoWrapper) Round() int32 {
return c.CommitInfo.Round
}
func (c commitInfoWrapper) Votes() comet.VoteInfos {
return abciVoteInfoWrapper{c.CommitInfo.Votes}
}
// abciVoteInfoWrapper is a wrapper around abci.VoteInfo that implements VoteInfos interface
type abciVoteInfoWrapper struct {
votes []abci.VoteInfo
}
var _ comet.VoteInfos = (*abciVoteInfoWrapper)(nil)
func (e abciVoteInfoWrapper) Len() int {
return len(e.votes)
}
func (e abciVoteInfoWrapper) Get(i int) comet.VoteInfo {
return voteInfoWrapper{e.votes[i]}
}
// voteInfoWrapper is a wrapper around abci.VoteInfo that implements VoteInfo interface
type voteInfoWrapper struct {
abci.VoteInfo
}
var _ comet.VoteInfo = (*voteInfoWrapper)(nil)
func (v voteInfoWrapper) GetBlockIDFlag() comet.BlockIDFlag {
return comet.BlockIDFlag(v.BlockIdFlag)
}
func (v voteInfoWrapper) Validator() comet.Validator {
return validatorWrapper{v.VoteInfo.Validator}
}
// validatorWrapper is a wrapper around abci.Validator that implements Validator interface
type validatorWrapper struct {
abci.Validator
}
var _ comet.Validator = (*validatorWrapper)(nil)
func (v validatorWrapper) Address() []byte {
return v.Validator.Address
}
func (v validatorWrapper) Power() int64 {
return v.Validator.Power
}
type misbehaviorWrapper struct {
abci.Misbehavior
}
func (m misbehaviorWrapper) Type() comet.MisbehaviorType {
return comet.MisbehaviorType(m.Misbehavior.Type)
}
func (m misbehaviorWrapper) Height() int64 {
return m.Misbehavior.Height
}
func (m misbehaviorWrapper) Validator() comet.Validator {
return validatorWrapper{m.Misbehavior.Validator}
}
func (m misbehaviorWrapper) Time() time.Time {
return m.Misbehavior.Time
}
func (m misbehaviorWrapper) TotalVotingPower() int64 {
return m.Misbehavior.TotalVotingPower
}
type prepareProposalInfo struct {
*abci.RequestPrepareProposal
}
var _ comet.BlockInfo = (*prepareProposalInfo)(nil)
func (r prepareProposalInfo) GetEvidence() comet.EvidenceList {
return evidenceWrapper{r.Misbehavior}
}
func (r prepareProposalInfo) GetValidatorsHash() []byte {
return r.NextValidatorsHash
}
func (r prepareProposalInfo) GetProposerAddress() []byte {
return r.ProposerAddress
}
func (r prepareProposalInfo) GetLastCommit() comet.CommitInfo {
return extendedCommitInfoWrapper{r.LocalLastCommit}
}
var _ comet.BlockInfo = (*prepareProposalInfo)(nil)
type extendedCommitInfoWrapper struct {
abci.ExtendedCommitInfo
}
var _ comet.CommitInfo = (*extendedCommitInfoWrapper)(nil)
func (e extendedCommitInfoWrapper) Round() int32 {
return e.ExtendedCommitInfo.Round
}
func (e extendedCommitInfoWrapper) Votes() comet.VoteInfos {
return extendedVoteInfoWrapperList{e.ExtendedCommitInfo.Votes}
}
type extendedVoteInfoWrapperList struct {
votes []abci.ExtendedVoteInfo
}
var _ comet.VoteInfos = (*extendedVoteInfoWrapperList)(nil)
func (e extendedVoteInfoWrapperList) Len() int {
return len(e.votes)
}
func (e extendedVoteInfoWrapperList) Get(i int) comet.VoteInfo {
return extendedVoteInfoWrapper{e.votes[i]}
}
type extendedVoteInfoWrapper struct {
abci.ExtendedVoteInfo
}
var _ comet.VoteInfo = (*extendedVoteInfoWrapper)(nil)
func (e extendedVoteInfoWrapper) GetBlockIDFlag() comet.BlockIDFlag {
return comet.BlockIDFlag(e.BlockIdFlag)
}
func (e extendedVoteInfoWrapper) Validator() comet.Validator {
return validatorWrapper{e.ExtendedVoteInfo.Validator}
}

View file

@ -0,0 +1,232 @@
package protocompat
import (
"context"
"fmt"
"reflect"
gogoproto "github.com/cosmos/gogoproto/proto"
"github.com/golang/protobuf/proto" // nolint: staticcheck // needed because gogoproto.Merge does not work consistently. See NOTE: comments.
"google.golang.org/grpc"
proto2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoiface"
"github.com/cosmos/cosmos-sdk/codec"
)
var (
gogoType = reflect.TypeOf((*gogoproto.Message)(nil)).Elem()
protov2Type = reflect.TypeOf((*proto2.Message)(nil)).Elem()
protov2MarshalOpts = proto2.MarshalOptions{Deterministic: true}
)
type Handler = func(ctx context.Context, request, response protoiface.MessageV1) error
func MakeHybridHandler(cdc codec.BinaryCodec, sd *grpc.ServiceDesc, method grpc.MethodDesc, handler any) (Handler, error) {
methodFullName := protoreflect.FullName(fmt.Sprintf("%s.%s", sd.ServiceName, method.MethodName))
desc, err := gogoproto.HybridResolver.FindDescriptorByName(methodFullName)
if err != nil {
return nil, err
}
methodDesc, ok := desc.(protoreflect.MethodDescriptor)
if !ok {
return nil, fmt.Errorf("invalid method descriptor %s", methodFullName)
}
isProtov2Handler, err := isProtov2(method)
if err != nil {
return nil, err
}
if isProtov2Handler {
return makeProtoV2HybridHandler(methodDesc, cdc, method, handler)
}
return makeGogoHybridHandler(methodDesc, cdc, method, handler)
}
// makeProtoV2HybridHandler returns a handler that can handle both gogo and protov2 messages.
func makeProtoV2HybridHandler(prefMethod protoreflect.MethodDescriptor, cdc codec.BinaryCodec, method grpc.MethodDesc, handler any) (Handler, error) {
// it's a protov2 handler, if a gogo counterparty is not found we cannot handle gogo messages.
gogoExists := gogoproto.MessageType(string(prefMethod.Output().FullName())) != nil
if !gogoExists {
return func(ctx context.Context, inReq, outResp protoiface.MessageV1) error {
protov2Request, ok := inReq.(proto2.Message)
if !ok {
return fmt.Errorf("invalid request type %T, method %s does not accept gogoproto messages", inReq, prefMethod.FullName())
}
resp, err := method.Handler(handler, ctx, func(msg any) error {
proto2.Merge(msg.(proto2.Message), protov2Request)
return nil
}, nil)
if err != nil {
return err
}
// merge on the resp
proto2.Merge(outResp.(proto2.Message), resp.(proto2.Message))
return nil
}, nil
}
return func(ctx context.Context, inReq, outResp protoiface.MessageV1) error {
// we check if the request is a protov2 message.
switch m := inReq.(type) {
case proto2.Message:
// we can just call the handler after making a copy of the message, for safety reasons.
resp, err := method.Handler(handler, ctx, func(msg any) error {
proto2.Merge(msg.(proto2.Message), m)
return nil
}, nil)
if err != nil {
return err
}
// merge on the resp
proto2.Merge(outResp.(proto2.Message), resp.(proto2.Message))
return nil
case gogoproto.Message:
// we need to marshal and unmarshal the request.
requestBytes, err := cdc.Marshal(m)
if err != nil {
return err
}
resp, err := method.Handler(handler, ctx, func(msg any) error {
// unmarshal request into the message.
return proto2.Unmarshal(requestBytes, msg.(proto2.Message))
}, nil)
if err != nil {
return err
}
// the response is a protov2 message, so we cannot just return it.
// since the request came as gogoproto, we expect the response
// to also be gogoproto.
respBytes, err := protov2MarshalOpts.Marshal(resp.(proto2.Message))
if err != nil {
return err
}
// unmarshal response into a gogo message.
return cdc.Unmarshal(respBytes, outResp.(gogoproto.Message))
default:
panic("unreachable")
}
}, nil
}
func makeGogoHybridHandler(prefMethod protoreflect.MethodDescriptor, cdc codec.BinaryCodec, method grpc.MethodDesc, handler any) (Handler, error) {
// it's a gogo handler, we check if the existing protov2 counterparty exists.
_, err := protoregistry.GlobalTypes.FindMessageByName(prefMethod.Output().FullName())
if err != nil {
// this can only be a gogo message.
return func(ctx context.Context, inReq, outResp protoiface.MessageV1) error {
_, ok := inReq.(proto2.Message)
if ok {
return fmt.Errorf("invalid request type %T, method %s does not accept protov2 messages", inReq, prefMethod.FullName())
}
resp, err := method.Handler(handler, ctx, func(msg any) error {
// merge! ref: https://github.com/cosmos/cosmos-sdk/issues/18003
// NOTE: using gogoproto.Merge will fail for some reason unknown to me, but
// using proto.Merge with gogo messages seems to work fine.
proto.Merge(msg.(gogoproto.Message), inReq)
return nil
}, nil)
if err != nil {
return err
}
// merge resp, ref: https://github.com/cosmos/cosmos-sdk/issues/18003
// NOTE: using gogoproto.Merge will fail for some reason unknown to me, but
// using proto.Merge with gogo messages seems to work fine.
proto.Merge(outResp.(gogoproto.Message), resp.(gogoproto.Message))
return nil
}, nil
}
// this is a gogo handler, and we have a protov2 counterparty.
return func(ctx context.Context, inReq, outResp protoiface.MessageV1) error {
switch m := inReq.(type) {
case proto2.Message:
// we need to marshal and unmarshal the request.
requestBytes, err := protov2MarshalOpts.Marshal(m)
if err != nil {
return err
}
resp, err := method.Handler(handler, ctx, func(msg any) error {
// unmarshal request into the message.
return cdc.Unmarshal(requestBytes, msg.(gogoproto.Message))
}, nil)
if err != nil {
return err
}
// the response is a gogo message, so we cannot just return it.
// since the request came as protov2, we expect the response
// to also be protov2.
respBytes, err := cdc.Marshal(resp.(gogoproto.Message))
if err != nil {
return err
}
// now we unmarshal back into a protov2 message.
return proto2.Unmarshal(respBytes, outResp.(proto2.Message))
case gogoproto.Message:
// we can just call the handler after making a copy of the message, for safety reasons.
resp, err := method.Handler(handler, ctx, func(msg any) error {
// ref: https://github.com/cosmos/cosmos-sdk/issues/18003
asGogoProto := msg.(gogoproto.Message)
// NOTE: using gogoproto.Merge will fail for some reason unknown to me, but
// using proto.Merge with gogo messages seems to work fine.
proto.Merge(asGogoProto, m)
return nil
}, nil)
if err != nil {
return err
}
// merge on the resp, ref: https://github.com/cosmos/cosmos-sdk/issues/18003
// NOTE: using gogoproto.Merge will fail for some reason unknown to me, but
// using proto.Merge with gogo messages seems to work fine.
proto.Merge(outResp.(gogoproto.Message), resp.(gogoproto.Message))
return nil
default:
panic("unreachable")
}
}, nil
}
// isProtov2 returns true if the given method accepts protov2 messages.
// Returns false if it does not.
// It uses the decoder function passed to the method handler to determine
// the type. Since the decoder function is passed in by the concrete implementer the expected
// message where bytes are unmarshaled to, we can use that to determine the type.
func isProtov2(md grpc.MethodDesc) (isV2Type bool, err error) {
pullRequestType := func(msg any) error {
typ := reflect.TypeOf(msg)
switch {
case typ.Implements(protov2Type):
isV2Type = true
return nil
case typ.Implements(gogoType):
isV2Type = false
return nil
default:
err = fmt.Errorf("invalid request type %T, expected protov2 or gogo message", msg)
return nil
}
}
// doNotExecute is a dummy handler that stops the request execution.
doNotExecute := func(_ context.Context, _ any, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (any, error) {
return nil, nil
}
// we are allowed to pass in a nil context and nil request, since we are not actually executing the request.
// this is made possible by the doNotExecute function which immediately returns without calling other handlers.
_, _ = md.Handler(nil, nil, pullRequestType, doNotExecute)
return isV2Type, err
}
// RequestFullNameFromMethodDesc returns the fully-qualified name of the request message of the provided service's method.
func RequestFullNameFromMethodDesc(sd *grpc.ServiceDesc, method grpc.MethodDesc) (protoreflect.FullName, error) {
methodFullName := protoreflect.FullName(fmt.Sprintf("%s.%s", sd.ServiceName, method.MethodName))
desc, err := gogoproto.HybridResolver.FindDescriptorByName(methodFullName)
if err != nil {
return "", fmt.Errorf("cannot find method descriptor %s", methodFullName)
}
methodDesc, ok := desc.(protoreflect.MethodDescriptor)
if !ok {
return "", fmt.Errorf("invalid method descriptor %s", methodFullName)
}
return methodDesc.Input().FullName(), nil
}

View file

@ -0,0 +1,221 @@
package baseapp
import (
"context"
"fmt"
gogogrpc "github.com/cosmos/gogoproto/grpc"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc"
"google.golang.org/protobuf/runtime/protoiface"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/baseapp/internal/protocompat"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// MessageRouter ADR 031 request type routing
// https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-031-msg-service.md
type MessageRouter interface {
Handler(msg sdk.Msg) MsgServiceHandler
HandlerByTypeURL(typeURL string) MsgServiceHandler
}
// MsgServiceRouter routes fully-qualified Msg service methods to their handler.
type MsgServiceRouter struct {
interfaceRegistry codectypes.InterfaceRegistry
routes map[string]MsgServiceHandler
hybridHandlers map[string]func(ctx context.Context, req, resp protoiface.MessageV1) error
circuitBreaker CircuitBreaker
}
var _ gogogrpc.Server = &MsgServiceRouter{}
// NewMsgServiceRouter creates a new MsgServiceRouter.
func NewMsgServiceRouter() *MsgServiceRouter {
return &MsgServiceRouter{
routes: map[string]MsgServiceHandler{},
hybridHandlers: map[string]func(ctx context.Context, req, resp protoiface.MessageV1) error{},
}
}
func (msr *MsgServiceRouter) SetCircuit(cb CircuitBreaker) {
msr.circuitBreaker = cb
}
// MsgServiceHandler defines a function type which handles Msg service message.
type MsgServiceHandler = func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error)
// Handler returns the MsgServiceHandler for a given msg or nil if not found.
func (msr *MsgServiceRouter) Handler(msg sdk.Msg) MsgServiceHandler {
return msr.routes[sdk.MsgTypeURL(msg)]
}
// HandlerByTypeURL returns the MsgServiceHandler for a given query route path or nil
// if not found.
func (msr *MsgServiceRouter) HandlerByTypeURL(typeURL string) MsgServiceHandler {
return msr.routes[typeURL]
}
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
// service description, handler is an object which implements that gRPC service.
//
// This function PANICs:
// - if it is called before the service `Msg`s have been registered using
// RegisterInterfaces,
// - or if a service is being registered twice.
func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler any) {
// Adds a top-level query handler based on the gRPC service name.
for _, method := range sd.Methods {
err := msr.registerMsgServiceHandler(sd, method, handler)
if err != nil {
panic(err)
}
err = msr.registerHybridHandler(sd, method, handler)
if err != nil {
panic(err)
}
}
}
func (msr *MsgServiceRouter) HybridHandlerByMsgName(msgName string) func(ctx context.Context, req, resp protoiface.MessageV1) error {
return msr.hybridHandlers[msgName]
}
func (msr *MsgServiceRouter) registerHybridHandler(sd *grpc.ServiceDesc, method grpc.MethodDesc, handler any) error {
inputName, err := protocompat.RequestFullNameFromMethodDesc(sd, method)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(msr.interfaceRegistry)
hybridHandler, err := protocompat.MakeHybridHandler(cdc, sd, method, handler)
if err != nil {
return err
}
// if circuit breaker is not nil, then we decorate the hybrid handler with the circuit breaker
if msr.circuitBreaker == nil {
msr.hybridHandlers[string(inputName)] = hybridHandler
return nil
}
// decorate the hybrid handler with the circuit breaker
circuitBreakerHybridHandler := func(ctx context.Context, req, resp protoiface.MessageV1) error {
messageName := codectypes.MsgTypeURL(req)
allowed, err := msr.circuitBreaker.IsAllowed(ctx, messageName)
if err != nil {
return err
}
if !allowed {
return fmt.Errorf("circuit breaker disallows execution of message %s", messageName)
}
return hybridHandler(ctx, req, resp)
}
msr.hybridHandlers[string(inputName)] = circuitBreakerHybridHandler
return nil
}
func (msr *MsgServiceRouter) registerMsgServiceHandler(sd *grpc.ServiceDesc, method grpc.MethodDesc, handler any) error {
fqMethod := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
methodHandler := method.Handler
var requestTypeName string
// NOTE: This is how we pull the concrete request type for each handler for registering in the InterfaceRegistry.
// This approach is maybe a bit hacky, but less hacky than reflecting on the handler object itself.
// We use a no-op interceptor to avoid actually calling into the handler itself.
_, _ = methodHandler(nil, context.Background(), func(i any) error {
msg, ok := i.(sdk.Msg)
if !ok {
// We panic here because there is no other alternative and the app cannot be initialized correctly
// this should only happen if there is a problem with code generation in which case the app won't
// work correctly anyway.
panic(fmt.Errorf("unable to register service method %s: %T does not implement sdk.Msg", fqMethod, i))
}
requestTypeName = sdk.MsgTypeURL(msg)
return nil
}, noopInterceptor)
// Check that the service Msg fully-qualified method name has already
// been registered (via RegisterInterfaces). If the user registers a
// service without registering according service Msg type, there might be
// some unexpected behavior down the road. Since we can't return an error
// (`Server.RegisterService` interface restriction) we panic (at startup).
reqType, err := msr.interfaceRegistry.Resolve(requestTypeName)
if err != nil || reqType == nil {
return fmt.Errorf(
"type_url %s has not been registered yet. "+
"Before calling RegisterService, you must register all interfaces by calling the `RegisterInterfaces` "+
"method on module.BasicManager. Each module should call `msgservice.RegisterMsgServiceDesc` inside its "+
"`RegisterInterfaces` method with the `_Msg_serviceDesc` generated by proto-gen",
requestTypeName,
)
}
// Check that each service is only registered once. If a service is
// registered more than once, then we should error. Since we can't
// return an error (`Server.RegisterService` interface restriction) we
// panic (at startup).
_, found := msr.routes[requestTypeName]
if found {
return fmt.Errorf(
"msg service %s has already been registered. Please make sure to only register each service once. "+
"This usually means that there are conflicting modules registering the same msg service",
fqMethod,
)
}
msr.routes[requestTypeName] = func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
interceptor := func(goCtx context.Context, _ any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
goCtx = context.WithValue(goCtx, sdk.SdkContextKey, ctx)
return handler(goCtx, msg)
}
if m, ok := msg.(sdk.HasValidateBasic); ok {
if err := m.ValidateBasic(); err != nil {
return nil, err
}
}
if msr.circuitBreaker != nil {
msgURL := sdk.MsgTypeURL(msg)
isAllowed, err := msr.circuitBreaker.IsAllowed(ctx, msgURL)
if err != nil {
return nil, err
}
if !isAllowed {
return nil, fmt.Errorf("circuit breaker disables execution of this message: %s", msgURL)
}
}
// Call the method handler from the service description with the handler object.
// We don't do any decoding here because the decoding was already done.
res, err := methodHandler(handler, ctx, noopDecoder, interceptor)
if err != nil {
return nil, err
}
resMsg, ok := res.(proto.Message)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting proto.Message, got %T", resMsg)
}
return sdk.WrapServiceResult(ctx, resMsg, err)
}
return nil
}
// SetInterfaceRegistry sets the interface registry for the router.
func (msr *MsgServiceRouter) SetInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) {
msr.interfaceRegistry = interfaceRegistry
}
func noopDecoder(_ any) error { return nil }
func noopInterceptor(_ context.Context, _ any, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (any, error) {
return nil, nil
}

View file

@ -0,0 +1,202 @@
package baseapp_test
import (
"context"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)
func TestRegisterMsgService(t *testing.T) {
// Setup baseapp.
var (
appBuilder *runtime.AppBuilder
registry codectypes.InterfaceRegistry
)
err := depinject.Inject(
depinject.Configs(
makeMinimalConfig(),
depinject.Supply(log.NewTestLogger(t)),
), &appBuilder, &registry)
require.NoError(t, err)
app := appBuilder.Build(dbm.NewMemDB(), nil)
require.Panics(t, func() {
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
})
// Register testdata Msg services, and rerun `RegisterMsgService`.
testdata.RegisterInterfaces(registry)
require.NotPanics(t, func() {
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
})
}
func TestRegisterMsgServiceTwice(t *testing.T) {
// Setup baseapp.
var (
appBuilder *runtime.AppBuilder
registry codectypes.InterfaceRegistry
)
err := depinject.Inject(
depinject.Configs(
makeMinimalConfig(),
depinject.Supply(log.NewTestLogger(t)),
), &appBuilder, &registry)
require.NoError(t, err)
db := dbm.NewMemDB()
app := appBuilder.Build(db, nil)
testdata.RegisterInterfaces(registry)
// First time registering service shouldn't panic.
require.NotPanics(t, func() {
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
})
// Second time should panic.
require.Panics(t, func() {
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
})
}
func TestHybridHandlerByMsgName(t *testing.T) {
// Setup baseapp and router.
var (
appBuilder *runtime.AppBuilder
registry codectypes.InterfaceRegistry
)
err := depinject.Inject(
depinject.Configs(
makeMinimalConfig(),
depinject.Supply(log.NewTestLogger(t)),
), &appBuilder, &registry)
require.NoError(t, err)
db := dbm.NewMemDB()
app := appBuilder.Build(db, nil)
testdata.RegisterInterfaces(registry)
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
handler := app.MsgServiceRouter().HybridHandlerByMsgName("testpb.MsgCreateDog")
require.NotNil(t, handler)
require.NoError(t, app.Init())
ctx := app.NewContext(true)
resp := new(testdata.MsgCreateDogResponse)
err = handler(ctx, &testdata.MsgCreateDog{
Dog: &testdata.Dog{Name: "Spot"},
Owner: "me",
}, resp)
require.NoError(t, err)
require.Equal(t, resp.Name, "Spot")
}
func TestMsgService(t *testing.T) {
priv, _, _ := testdata.KeyTestPubAddr()
var (
appBuilder *runtime.AppBuilder
cdc codec.Codec
interfaceRegistry codectypes.InterfaceRegistry
)
err := depinject.Inject(
depinject.Configs(
makeMinimalConfig(),
depinject.Supply(log.NewNopLogger()),
), &appBuilder, &cdc, &interfaceRegistry)
require.NoError(t, err)
app := appBuilder.Build(dbm.NewMemDB(), nil)
// patch in TxConfig instead of using an output from x/auth/tx
txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes)
// set the TxDecoder in the BaseApp for minimal tx simulations
app.SetTxDecoder(txConfig.TxDecoder())
defaultSignMode, err := authsigning.APISignModeToInternal(txConfig.SignModeHandler().DefaultMode())
require.NoError(t, err)
testdata.RegisterInterfaces(interfaceRegistry)
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
_, err = app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1})
require.NoError(t, err)
_, _, addr := testdata.KeyTestPubAddr()
msg := testdata.MsgCreateDog{
Dog: &testdata.Dog{Name: "Spot"},
Owner: addr.String(),
}
txBuilder := txConfig.NewTxBuilder()
txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
txBuilder.SetGasLimit(testdata.NewTestGasLimit())
err = txBuilder.SetMsgs(&msg)
require.NoError(t, err)
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: defaultSignMode,
Signature: nil,
},
Sequence: 0,
}
err = txBuilder.SetSignatures(sigV2)
require.NoError(t, err)
// Second round: all signer infos are set, so each signer can sign.
signerData := authsigning.SignerData{
ChainID: "test",
AccountNumber: 0,
Sequence: 0,
PubKey: priv.PubKey(),
}
sigV2, err = tx.SignWithPrivKey(
context.TODO(), defaultSignMode, signerData,
txBuilder, priv, txConfig, 0)
require.NoError(t, err)
err = txBuilder.SetSignatures(sigV2)
require.NoError(t, err)
// Send the tx to the app
txBytes, err := txConfig.TxEncoder()(txBuilder.GetTx())
require.NoError(t, err)
res, err := app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1, Txs: [][]byte{txBytes}})
require.NoError(t, err)
require.Equal(t, abci.CodeTypeOK, res.TxResults[0].Code, "res=%+v", res)
}

17
baseapp/noopgasmeter.go Normal file
View file

@ -0,0 +1,17 @@
package baseapp
import storetypes "cosmossdk.io/store/types"
type noopGasMeter struct{}
var _ storetypes.GasMeter = noopGasMeter{}
func (noopGasMeter) GasConsumed() storetypes.Gas { return 0 }
func (noopGasMeter) GasConsumedToLimit() storetypes.Gas { return 0 }
func (noopGasMeter) GasRemaining() storetypes.Gas { return 0 }
func (noopGasMeter) Limit() storetypes.Gas { return 0 }
func (noopGasMeter) ConsumeGas(storetypes.Gas, string) {}
func (noopGasMeter) RefundGas(storetypes.Gas, string) {}
func (noopGasMeter) IsPastLimit() bool { return false }
func (noopGasMeter) IsOutOfGas() bool { return false }
func (noopGasMeter) String() string { return "noopGasMeter" }

View file

@ -0,0 +1,160 @@
package oe
import (
"bytes"
"context"
"encoding/hex"
"math/rand"
"sync"
"time"
abci "github.com/cometbft/cometbft/abci/types"
"cosmossdk.io/log"
)
// FinalizeBlockFunc is the function that is called by the OE to finalize the
// block. It is the same as the one in the ABCI app.
type FinalizeBlockFunc func(context.Context, *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error)
// OptimisticExecution is a struct that contains the OE context. It is used to
// run the FinalizeBlock function in a goroutine, and to abort it if needed.
type OptimisticExecution struct {
finalizeBlockFunc FinalizeBlockFunc // ABCI FinalizeBlock function with a context
logger log.Logger
mtx sync.Mutex
stopCh chan struct{}
request *abci.RequestFinalizeBlock
response *abci.ResponseFinalizeBlock
err error
cancelFunc func() // cancel function for the context
initialized bool // A boolean value indicating whether the struct has been initialized
// debugging/testing options
abortRate int // number from 0 to 100 that determines the percentage of OE that should be aborted
}
// NewOptimisticExecution initializes the Optimistic Execution context but does not start it.
func NewOptimisticExecution(logger log.Logger, fn FinalizeBlockFunc, opts ...func(*OptimisticExecution)) *OptimisticExecution {
logger = logger.With(log.ModuleKey, "oe")
oe := &OptimisticExecution{logger: logger, finalizeBlockFunc: fn}
for _, opt := range opts {
opt(oe)
}
return oe
}
// WithAbortRate sets the abort rate for the OE. The abort rate is a number from
// 0 to 100 that determines the percentage of OE that should be aborted.
// This is for testing purposes only and must not be used in production.
func WithAbortRate(rate int) func(*OptimisticExecution) {
return func(oe *OptimisticExecution) {
oe.abortRate = rate
}
}
// Reset resets the OE context. Must be called whenever we want to invalidate
// the current OE.
func (oe *OptimisticExecution) Reset() {
oe.mtx.Lock()
defer oe.mtx.Unlock()
oe.request = nil
oe.response = nil
oe.err = nil
oe.initialized = false
}
func (oe *OptimisticExecution) Enabled() bool {
return oe != nil
}
// Initialized returns true if the OE was initialized, meaning that it contains
// a request and it was run or it is running.
func (oe *OptimisticExecution) Initialized() bool {
if oe == nil {
return false
}
oe.mtx.Lock()
defer oe.mtx.Unlock()
return oe.initialized
}
// Execute initializes the OE and starts it in a goroutine.
func (oe *OptimisticExecution) Execute(req *abci.RequestProcessProposal) {
oe.mtx.Lock()
defer oe.mtx.Unlock()
oe.stopCh = make(chan struct{})
oe.request = &abci.RequestFinalizeBlock{
Txs: req.Txs,
DecidedLastCommit: req.ProposedLastCommit,
Misbehavior: req.Misbehavior,
Hash: req.Hash,
Height: req.Height,
Time: req.Time,
NextValidatorsHash: req.NextValidatorsHash,
ProposerAddress: req.ProposerAddress,
}
oe.logger.Debug("OE started", "height", req.Height, "hash", hex.EncodeToString(req.Hash), "time", req.Time.String())
ctx, cancel := context.WithCancel(context.Background())
oe.cancelFunc = cancel
oe.initialized = true
go func() {
start := time.Now()
resp, err := oe.finalizeBlockFunc(ctx, oe.request)
oe.mtx.Lock()
executionTime := time.Since(start)
oe.logger.Debug("OE finished", "duration", executionTime.String(), "height", oe.request.Height, "hash", hex.EncodeToString(oe.request.Hash))
oe.response, oe.err = resp, err
close(oe.stopCh)
oe.mtx.Unlock()
}()
}
// AbortIfNeeded aborts the OE if the request hash is not the same as the one in
// the running OE. Returns true if the OE was aborted.
func (oe *OptimisticExecution) AbortIfNeeded(reqHash []byte) bool {
if oe == nil {
return false
}
oe.mtx.Lock()
defer oe.mtx.Unlock()
if !bytes.Equal(oe.request.Hash, reqHash) {
oe.logger.Error("OE aborted due to hash mismatch", "oe_hash", hex.EncodeToString(oe.request.Hash), "req_hash", hex.EncodeToString(reqHash), "oe_height", oe.request.Height, "req_height", oe.request.Height)
oe.cancelFunc()
return true
} else if oe.abortRate > 0 && rand.Intn(100) < oe.abortRate {
// this is for test purposes only, we can emulate a certain percentage of
// OE needed to be aborted.
oe.cancelFunc()
oe.logger.Error("OE aborted due to test abort rate")
return true
}
return false
}
// Abort aborts the OE unconditionally and waits for it to finish.
func (oe *OptimisticExecution) Abort() {
if oe == nil || oe.cancelFunc == nil {
return
}
oe.cancelFunc()
<-oe.stopCh
}
// WaitResult waits for the OE to finish and returns the result.
func (oe *OptimisticExecution) WaitResult() (*abci.ResponseFinalizeBlock, error) {
<-oe.stopCh
return oe.response, oe.err
}

View file

@ -0,0 +1,34 @@
package oe
import (
"context"
"errors"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/stretchr/testify/assert"
"cosmossdk.io/log"
)
func testFinalizeBlock(_ context.Context, _ *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
return nil, errors.New("test error")
}
func TestOptimisticExecution(t *testing.T) {
oe := NewOptimisticExecution(log.NewNopLogger(), testFinalizeBlock)
assert.True(t, oe.Enabled())
oe.Execute(&abci.RequestProcessProposal{
Hash: []byte("test"),
})
assert.True(t, oe.Initialized())
resp, err := oe.WaitResult()
assert.Nil(t, resp)
assert.EqualError(t, err, "test error")
assert.False(t, oe.AbortIfNeeded([]byte("test")))
assert.True(t, oe.AbortIfNeeded([]byte("wrong_hash")))
oe.Reset()
}

405
baseapp/options.go Normal file
View file

@ -0,0 +1,405 @@
package baseapp
import (
"fmt"
"io"
"math"
dbm "github.com/cosmos/cosmos-db"
"cosmossdk.io/store/metrics"
pruningtypes "cosmossdk.io/store/pruning/types"
"cosmossdk.io/store/snapshots"
snapshottypes "cosmossdk.io/store/snapshots/types"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/baseapp/oe"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/mempool"
)
// File for storing in-package BaseApp optional functions,
// for options that need access to non-exported fields of the BaseApp
// SetPruning sets a pruning option on the multistore associated with the app
func SetPruning(opts pruningtypes.PruningOptions) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.cms.SetPruning(opts) }
}
// SetMinGasPrices returns an option that sets the minimum gas prices on the app.
func SetMinGasPrices(gasPricesStr string) func(*BaseApp) {
gasPrices, err := sdk.ParseDecCoins(gasPricesStr)
if err != nil {
panic(fmt.Sprintf("invalid minimum gas prices: %v", err))
}
return func(bapp *BaseApp) { bapp.setMinGasPrices(gasPrices) }
}
// SetQueryGasLimit returns an option that sets a gas limit for queries.
func SetQueryGasLimit(queryGasLimit uint64) func(*BaseApp) {
if queryGasLimit == 0 {
queryGasLimit = math.MaxUint64
}
return func(bapp *BaseApp) { bapp.queryGasLimit = queryGasLimit }
}
// SetHaltHeight returns a BaseApp option function that sets the halt block height.
func SetHaltHeight(blockHeight uint64) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.setHaltHeight(blockHeight) }
}
// SetHaltTime returns a BaseApp option function that sets the halt block time.
func SetHaltTime(haltTime uint64) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.setHaltTime(haltTime) }
}
// SetMinRetainBlocks returns a BaseApp option function that sets the minimum
// block retention height value when determining which heights to prune during
// ABCI Commit.
func SetMinRetainBlocks(minRetainBlocks uint64) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.setMinRetainBlocks(minRetainBlocks) }
}
// SetTrace will turn on or off trace flag
func SetTrace(trace bool) func(*BaseApp) {
return func(app *BaseApp) { app.setTrace(trace) }
}
// SetIndexEvents provides a BaseApp option function that sets the events to index.
func SetIndexEvents(ie []string) func(*BaseApp) {
return func(app *BaseApp) { app.setIndexEvents(ie) }
}
// SetIAVLCacheSize provides a BaseApp option function that sets the size of IAVL cache.
func SetIAVLCacheSize(size int) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.cms.SetIAVLCacheSize(size) }
}
// SetIAVLDisableFastNode enables(false)/disables(true) fast node usage from the IAVL store.
func SetIAVLDisableFastNode(disable bool) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.cms.SetIAVLDisableFastNode(disable) }
}
// SetIAVLSyncPruning set sync/async pruning in the IAVL store. Developers should rarely use this.
// This option was added to allow the `Prune` command to force synchronous pruning, which is needed to allow the
// command to wait before returning.
func SetIAVLSyncPruning(syncPruning bool) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.cms.SetIAVLSyncPruning(syncPruning) }
}
// SetInterBlockCache provides a BaseApp option function that sets the
// inter-block cache.
func SetInterBlockCache(cache storetypes.MultiStorePersistentCache) func(*BaseApp) {
return func(app *BaseApp) { app.setInterBlockCache(cache) }
}
// SetSnapshot sets the snapshot store.
func SetSnapshot(snapshotStore *snapshots.Store, opts snapshottypes.SnapshotOptions) func(*BaseApp) {
return func(app *BaseApp) { app.SetSnapshot(snapshotStore, opts) }
}
// SetMempool sets the mempool on BaseApp.
func SetMempool(mempool mempool.Mempool) func(*BaseApp) {
return func(app *BaseApp) { app.SetMempool(mempool) }
}
// SetChainID sets the chain ID in BaseApp.
func SetChainID(chainID string) func(*BaseApp) {
return func(app *BaseApp) { app.chainID = chainID }
}
// SetStoreLoader allows customization of the rootMultiStore initialization.
func SetStoreLoader(loader StoreLoader) func(*BaseApp) {
return func(app *BaseApp) { app.SetStoreLoader(loader) }
}
// SetOptimisticExecution enables optimistic execution.
func SetOptimisticExecution(opts ...func(*oe.OptimisticExecution)) func(*BaseApp) {
return func(app *BaseApp) {
app.optimisticExec = oe.NewOptimisticExecution(app.logger, app.internalFinalizeBlock, opts...)
}
}
// DisableBlockGasMeter disables the block gas meter.
func DisableBlockGasMeter() func(*BaseApp) {
return func(app *BaseApp) { app.SetDisableBlockGasMeter(true) }
}
func (app *BaseApp) SetName(name string) {
if app.sealed {
panic("SetName() on sealed BaseApp")
}
app.name = name
}
// SetParamStore sets a parameter store on the BaseApp.
func (app *BaseApp) SetParamStore(ps ParamStore) {
if app.sealed {
panic("SetParamStore() on sealed BaseApp")
}
app.paramStore = ps
}
// SetVersion sets the application's version string.
func (app *BaseApp) SetVersion(v string) {
if app.sealed {
panic("SetVersion() on sealed BaseApp")
}
app.version = v
}
// SetProtocolVersion sets the application's protocol version
func (app *BaseApp) SetProtocolVersion(v uint64) {
app.appVersion = v
}
func (app *BaseApp) SetDB(db dbm.DB) {
if app.sealed {
panic("SetDB() on sealed BaseApp")
}
app.db = db
}
func (app *BaseApp) SetCMS(cms storetypes.CommitMultiStore) {
if app.sealed {
panic("SetCMS() on sealed BaseApp")
}
app.cms = cms
}
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
if app.sealed {
panic("SetInitChainer() on sealed BaseApp")
}
app.initChainer = initChainer
}
func (app *BaseApp) PreBlocker() sdk.PreBlocker {
return app.preBlocker
}
func (app *BaseApp) SetPreBlocker(preBlocker sdk.PreBlocker) {
if app.sealed {
panic("SetPreBlocker() on sealed BaseApp")
}
app.preBlocker = preBlocker
}
func (app *BaseApp) SetBeginBlocker(beginBlocker sdk.BeginBlocker) {
if app.sealed {
panic("SetBeginBlocker() on sealed BaseApp")
}
app.beginBlocker = beginBlocker
}
func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) {
if app.sealed {
panic("SetEndBlocker() on sealed BaseApp")
}
app.endBlocker = endBlocker
}
func (app *BaseApp) SetPrepareCheckStater(prepareCheckStater sdk.PrepareCheckStater) {
if app.sealed {
panic("SetPrepareCheckStater() on sealed BaseApp")
}
app.prepareCheckStater = prepareCheckStater
}
func (app *BaseApp) SetPrecommiter(precommiter sdk.Precommiter) {
if app.sealed {
panic("SetPrecommiter() on sealed BaseApp")
}
app.precommiter = precommiter
}
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
if app.sealed {
panic("SetAnteHandler() on sealed BaseApp")
}
app.anteHandler = ah
}
func (app *BaseApp) SetPostHandler(ph sdk.PostHandler) {
if app.sealed {
panic("SetPostHandler() on sealed BaseApp")
}
app.postHandler = ph
}
func (app *BaseApp) SetAddrPeerFilter(pf sdk.PeerFilter) {
if app.sealed {
panic("SetAddrPeerFilter() on sealed BaseApp")
}
app.addrPeerFilter = pf
}
func (app *BaseApp) SetIDPeerFilter(pf sdk.PeerFilter) {
if app.sealed {
panic("SetIDPeerFilter() on sealed BaseApp")
}
app.idPeerFilter = pf
}
func (app *BaseApp) SetFauxMerkleMode() {
if app.sealed {
panic("SetFauxMerkleMode() on sealed BaseApp")
}
app.fauxMerkleMode = true
}
// SetNotSigverify during simulation testing, transaction signature verification needs to be ignored.
func (app *BaseApp) SetNotSigverifyTx() {
app.sigverifyTx = false
}
// SetCommitMultiStoreTracer sets the store tracer on the BaseApp's underlying
// CommitMultiStore.
func (app *BaseApp) SetCommitMultiStoreTracer(w io.Writer) {
app.cms.SetTracer(w)
}
// SetStoreLoader allows us to customize the rootMultiStore initialization.
func (app *BaseApp) SetStoreLoader(loader StoreLoader) {
if app.sealed {
panic("SetStoreLoader() on sealed BaseApp")
}
app.storeLoader = loader
}
// SetSnapshot sets the snapshot store and options.
func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts snapshottypes.SnapshotOptions) {
if app.sealed {
panic("SetSnapshot() on sealed BaseApp")
}
if snapshotStore == nil {
app.snapshotManager = nil
return
}
app.cms.SetSnapshotInterval(opts.Interval)
app.snapshotManager = snapshots.NewManager(snapshotStore, opts, app.cms, nil, app.logger)
}
// SetInterfaceRegistry sets the InterfaceRegistry.
func (app *BaseApp) SetInterfaceRegistry(registry types.InterfaceRegistry) {
app.interfaceRegistry = registry
app.grpcQueryRouter.SetInterfaceRegistry(registry)
app.msgServiceRouter.SetInterfaceRegistry(registry)
app.cdc = codec.NewProtoCodec(registry)
}
// SetTxDecoder sets the TxDecoder if it wasn't provided in the BaseApp constructor.
func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) {
app.txDecoder = txDecoder
}
// SetTxEncoder sets the TxEncoder if it wasn't provided in the BaseApp constructor.
func (app *BaseApp) SetTxEncoder(txEncoder sdk.TxEncoder) {
app.txEncoder = txEncoder
}
// SetQueryMultiStore set a alternative MultiStore implementation to support grpc query service.
//
// Ref: https://github.com/cosmos/cosmos-sdk/issues/13317
func (app *BaseApp) SetQueryMultiStore(ms storetypes.MultiStore) {
app.qms = ms
}
// SetMempool sets the mempool for the BaseApp and is required for the app to start up.
func (app *BaseApp) SetMempool(mempool mempool.Mempool) {
if app.sealed {
panic("SetMempool() on sealed BaseApp")
}
app.mempool = mempool
}
// SetProcessProposal sets the process proposal function for the BaseApp.
func (app *BaseApp) SetProcessProposal(handler sdk.ProcessProposalHandler) {
if app.sealed {
panic("SetProcessProposal() on sealed BaseApp")
}
app.processProposal = handler
}
// SetPrepareProposal sets the prepare proposal function for the BaseApp.
func (app *BaseApp) SetPrepareProposal(handler sdk.PrepareProposalHandler) {
if app.sealed {
panic("SetPrepareProposal() on sealed BaseApp")
}
app.prepareProposal = handler
}
// SetCheckTx sets the checkTx function for the BaseApp.
func (app *BaseApp) SetCheckTxHandler(handler sdk.CheckTxHandler) {
if app.sealed {
panic("SetCheckTxHandler() on sealed BaseApp")
}
app.checkTxHandler = handler
}
func (app *BaseApp) SetExtendVoteHandler(handler sdk.ExtendVoteHandler) {
if app.sealed {
panic("SetExtendVoteHandler() on sealed BaseApp")
}
app.extendVote = handler
}
func (app *BaseApp) SetVerifyVoteExtensionHandler(handler sdk.VerifyVoteExtensionHandler) {
if app.sealed {
panic("SetVerifyVoteExtensionHandler() on sealed BaseApp")
}
app.verifyVoteExt = handler
}
// SetStoreMetrics sets the prepare proposal function for the BaseApp.
func (app *BaseApp) SetStoreMetrics(gatherer metrics.StoreMetrics) {
if app.sealed {
panic("SetStoreMetrics() on sealed BaseApp")
}
app.cms.SetMetrics(gatherer)
}
// SetStreamingManager sets the streaming manager for the BaseApp.
func (app *BaseApp) SetStreamingManager(manager storetypes.StreamingManager) {
app.streamingManager = manager
}
// SetDisableBlockGasMeter sets the disableBlockGasMeter flag for the BaseApp.
func (app *BaseApp) SetDisableBlockGasMeter(disableBlockGasMeter bool) {
app.disableBlockGasMeter = disableBlockGasMeter
}
// SetMsgServiceRouter sets the MsgServiceRouter of a BaseApp.
func (app *BaseApp) SetMsgServiceRouter(msgServiceRouter *MsgServiceRouter) {
app.msgServiceRouter = msgServiceRouter
}
// SetGRPCQueryRouter sets the GRPCQueryRouter of the BaseApp.
func (app *BaseApp) SetGRPCQueryRouter(grpcQueryRouter *GRPCQueryRouter) {
app.grpcQueryRouter = grpcQueryRouter
}

15
baseapp/params.go Normal file
View file

@ -0,0 +1,15 @@
package baseapp
import (
"context"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
)
// ParamStore defines the interface the parameter store used by the BaseApp must
// fulfill.
type ParamStore interface {
Get(ctx context.Context) (cmtproto.ConsensusParams, error)
Has(ctx context.Context) (bool, error)
Set(ctx context.Context, cp cmtproto.ConsensusParams) error
}

150
baseapp/params_legacy.go Normal file
View file

@ -0,0 +1,150 @@
/*
Deprecated.
Legacy types are defined below to aid in the migration of CometBFT consensus
parameters from use of the now deprecated x/params modules to a new dedicated
x/consensus module.
Application developers should ensure that they implement their upgrade handler
correctly such that app.ConsensusParamsKeeper.Set() is called with the values
returned by GetConsensusParams().
Example:
baseAppLegacySS := app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable())
app.UpgradeKeeper.SetUpgradeHandler(
UpgradeName,
func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
if cp := baseapp.GetConsensusParams(ctx, baseAppLegacySS); cp != nil {
app.ConsensusParamsKeeper.Set(ctx, cp)
} else {
ctx.Logger().Info("warning: consensus parameters are undefined; skipping migration", "upgrade", UpgradeName)
}
return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM)
},
)
Developers can also bypass the use of the legacy Params subspace and set the
values to app.ConsensusParamsKeeper.Set() explicitly.
Note, for new chains this is not necessary as CometBFT's consensus parameters
will automatically be set for you in InitChain.
*/
package baseapp
import (
"errors"
"fmt"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const Paramspace = "baseapp"
var (
ParamStoreKeyBlockParams = []byte("BlockParams")
ParamStoreKeyEvidenceParams = []byte("EvidenceParams")
ParamStoreKeyValidatorParams = []byte("ValidatorParams")
)
type LegacyParamStore interface {
Get(ctx sdk.Context, key []byte, ptr any)
Has(ctx sdk.Context, key []byte) bool
}
func ValidateBlockParams(i any) error {
v, ok := i.(cmtproto.BlockParams)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v.MaxBytes <= 0 {
return fmt.Errorf("block maximum bytes must be positive: %d", v.MaxBytes)
}
if v.MaxGas < -1 {
return fmt.Errorf("block maximum gas must be greater than or equal to -1: %d", v.MaxGas)
}
return nil
}
func ValidateEvidenceParams(i any) error {
v, ok := i.(cmtproto.EvidenceParams)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v.MaxAgeNumBlocks <= 0 {
return fmt.Errorf("evidence maximum age in blocks must be positive: %d", v.MaxAgeNumBlocks)
}
if v.MaxAgeDuration <= 0 {
return fmt.Errorf("evidence maximum age time duration must be positive: %v", v.MaxAgeDuration)
}
if v.MaxBytes < 0 {
return fmt.Errorf("maximum evidence bytes must be non-negative: %v", v.MaxBytes)
}
return nil
}
func ValidateValidatorParams(i any) error {
v, ok := i.(cmtproto.ValidatorParams)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if len(v.PubKeyTypes) == 0 {
return errors.New("validator allowed pubkey types must not be empty")
}
return nil
}
func GetConsensusParams(ctx sdk.Context, paramStore LegacyParamStore) *cmtproto.ConsensusParams {
if paramStore == nil {
return nil
}
cp := new(cmtproto.ConsensusParams)
if paramStore.Has(ctx, ParamStoreKeyBlockParams) {
var bp cmtproto.BlockParams
paramStore.Get(ctx, ParamStoreKeyBlockParams, &bp)
cp.Block = &bp
}
if paramStore.Has(ctx, ParamStoreKeyEvidenceParams) {
var ep cmtproto.EvidenceParams
paramStore.Get(ctx, ParamStoreKeyEvidenceParams, &ep)
cp.Evidence = &ep
}
if paramStore.Has(ctx, ParamStoreKeyValidatorParams) {
var vp cmtproto.ValidatorParams
paramStore.Get(ctx, ParamStoreKeyValidatorParams, &vp)
cp.Validator = &vp
}
return cp
}
func MigrateParams(ctx sdk.Context, lps LegacyParamStore, ps ParamStore) error {
if cp := GetConsensusParams(ctx, lps); cp != nil {
if err := ps.Set(ctx, *cp); err != nil {
return err
}
} else {
ctx.Logger().Info("warning: consensus parameters are undefined; skipping migration")
}
return nil
}

80
baseapp/recovery.go Normal file
View file

@ -0,0 +1,80 @@
package baseapp
import (
"fmt"
"runtime/debug"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// RecoveryHandler handles recovery() object.
// Return a non-nil error if recoveryObj was processed.
// Return nil if recoveryObj was not processed.
type RecoveryHandler func(recoveryObj any) error
// recoveryMiddleware is wrapper for RecoveryHandler to create chained recovery handling.
// returns (recoveryMiddleware, nil) if recoveryObj was not processed and should be passed to the next middleware in chain.
// returns (nil, error) if recoveryObj was processed and middleware chain processing should be stopped.
type recoveryMiddleware func(recoveryObj any) (recoveryMiddleware, error)
// processRecovery processes recoveryMiddleware chain for recovery() object.
// Chain processing stops on non-nil error or when chain is processed.
func processRecovery(recoveryObj any, middleware recoveryMiddleware) error {
if middleware == nil {
return nil
}
next, err := middleware(recoveryObj)
if err != nil {
return err
}
return processRecovery(recoveryObj, next)
}
// newRecoveryMiddleware creates a RecoveryHandler middleware.
func newRecoveryMiddleware(handler RecoveryHandler, next recoveryMiddleware) recoveryMiddleware {
return func(recoveryObj any) (recoveryMiddleware, error) {
if err := handler(recoveryObj); err != nil {
return nil, err
}
return next, nil
}
}
// newOutOfGasRecoveryMiddleware creates a standard OutOfGas recovery middleware for app.runTx method.
func newOutOfGasRecoveryMiddleware(gasWanted uint64, ctx sdk.Context, next recoveryMiddleware) recoveryMiddleware {
handler := func(recoveryObj any) error {
err, ok := recoveryObj.(storetypes.ErrorOutOfGas)
if !ok {
return nil
}
return errorsmod.Wrap(
sdkerrors.ErrOutOfGas, fmt.Sprintf(
"out of gas in location: %v; gasWanted: %d, gasUsed: %d",
err.Descriptor, gasWanted, ctx.GasMeter().GasConsumed(),
),
)
}
return newRecoveryMiddleware(handler, next)
}
// newDefaultRecoveryMiddleware creates a default (last in chain) recovery middleware for app.runTx method.
func newDefaultRecoveryMiddleware() recoveryMiddleware {
handler := func(recoveryObj any) error {
return errorsmod.Wrap(
sdkerrors.ErrPanic, fmt.Sprintf(
"recovered: %v\nstack:\n%v", recoveryObj, string(debug.Stack()),
),
)
}
return newRecoveryMiddleware(handler, nil)
}

64
baseapp/recovery_test.go Normal file
View file

@ -0,0 +1,64 @@
package baseapp
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
// Test that recovery chain produces expected error at specific middleware layer
func TestRecoveryChain(t *testing.T) {
createError := func(id int) error {
return fmt.Errorf("error from id: %d", id)
}
createHandler := func(id int, handle bool) RecoveryHandler {
return func(_ any) error {
if handle {
return createError(id)
}
return nil
}
}
// check recovery chain [1] -> 2 -> 3
{
mw := newRecoveryMiddleware(createHandler(3, false), nil)
mw = newRecoveryMiddleware(createHandler(2, false), mw)
mw = newRecoveryMiddleware(createHandler(1, true), mw)
receivedErr := processRecovery(nil, mw)
require.Equal(t, createError(1), receivedErr)
}
// check recovery chain 1 -> [2] -> 3
{
mw := newRecoveryMiddleware(createHandler(3, false), nil)
mw = newRecoveryMiddleware(createHandler(2, true), mw)
mw = newRecoveryMiddleware(createHandler(1, false), mw)
receivedErr := processRecovery(nil, mw)
require.Equal(t, createError(2), receivedErr)
}
// check recovery chain 1 -> 2 -> [3]
{
mw := newRecoveryMiddleware(createHandler(3, true), nil)
mw = newRecoveryMiddleware(createHandler(2, false), mw)
mw = newRecoveryMiddleware(createHandler(1, false), mw)
receivedErr := processRecovery(nil, mw)
require.Equal(t, createError(3), receivedErr)
}
// check recovery chain 1 -> 2 -> 3
{
mw := newRecoveryMiddleware(createHandler(3, false), nil)
mw = newRecoveryMiddleware(createHandler(2, false), mw)
mw = newRecoveryMiddleware(createHandler(1, false), mw)
receivedErr := processRecovery(nil, mw)
require.Nil(t, receivedErr)
}
}

View file

@ -0,0 +1,41 @@
package baseapp
import (
"testing"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
"cosmossdk.io/log"
"cosmossdk.io/store"
storemetrics "cosmossdk.io/store/metrics"
)
// Ensures that error checks are performed before sealing the app.
// Please see https://github.com/cosmos/cosmos-sdk/issues/18726
func TestNilCmsCheckBeforeSeal(t *testing.T) {
app := new(BaseApp)
// 1. Invoking app.Init with a nil cms MUST not seal the app
// and should return an error firstly, which can later be reversed.
for range 10 { // N times, the app shouldn't be sealed.
err := app.Init()
require.Error(t, err)
require.Contains(t, err.Error(), "commit multi-store must not be nil")
require.False(t, app.IsSealed(), "the app MUST not be sealed")
}
// 2. Now that we've figured out and gotten back an error, let's rectify the problem.
// and we should be able to set the commit multistore then reinvoke app.Init successfully!
db := dbm.NewMemDB()
logger := log.NewTestLogger(t)
app.cms = store.NewCommitMultiStore(db, logger, storemetrics.NewNoOpMetrics())
err := app.Init()
require.Nil(t, err, "app.Init MUST now succeed")
require.True(t, app.IsSealed(), "the app must now be sealed")
// 3. Now we should expect a panic because the app is sealed.
require.Panics(t, func() {
_ = app.Init()
})
}

346
baseapp/snapshot_test.go Normal file
View file

@ -0,0 +1,346 @@
package baseapp_test
import (
"context"
"fmt"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/stretchr/testify/require"
pruningtypes "cosmossdk.io/store/pruning/types"
snapshottypes "cosmossdk.io/store/snapshots/types"
)
func TestABCI_ListSnapshots(t *testing.T) {
ssCfg := SnapshotsConfig{
blocks: 5,
blockTxs: 4,
snapshotInterval: 2,
snapshotKeepRecent: 2,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
}
suite := NewBaseAppSuiteWithSnapshots(t, ssCfg)
resp, err := suite.baseApp.ListSnapshots(&abci.RequestListSnapshots{})
require.NoError(t, err)
for _, s := range resp.Snapshots {
require.NotEmpty(t, s.Hash)
require.NotEmpty(t, s.Metadata)
s.Hash = nil
s.Metadata = nil
}
require.Equal(t, &abci.ResponseListSnapshots{Snapshots: []*abci.Snapshot{
{Height: 4, Format: snapshottypes.CurrentFormat, Chunks: 2},
{Height: 2, Format: snapshottypes.CurrentFormat, Chunks: 1},
}}, resp)
}
func TestABCI_SnapshotWithPruning(t *testing.T) {
testCases := map[string]struct {
ssCfg SnapshotsConfig
expectedSnapshots []*abci.Snapshot
}{
"prune nothing with snapshot": {
ssCfg: SnapshotsConfig{
blocks: 20,
blockTxs: 2,
snapshotInterval: 5,
snapshotKeepRecent: 1,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
},
expectedSnapshots: []*abci.Snapshot{
{Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5},
},
},
"prune everything with snapshot": {
ssCfg: SnapshotsConfig{
blocks: 20,
blockTxs: 2,
snapshotInterval: 5,
snapshotKeepRecent: 1,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningEverything),
},
expectedSnapshots: []*abci.Snapshot{
{Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5},
},
},
"default pruning with snapshot": {
ssCfg: SnapshotsConfig{
blocks: 20,
blockTxs: 2,
snapshotInterval: 5,
snapshotKeepRecent: 1,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningDefault),
},
expectedSnapshots: []*abci.Snapshot{
{Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5},
},
},
"custom": {
ssCfg: SnapshotsConfig{
blocks: 25,
blockTxs: 2,
snapshotInterval: 5,
snapshotKeepRecent: 2,
pruningOpts: pruningtypes.NewCustomPruningOptions(12, 12),
},
expectedSnapshots: []*abci.Snapshot{
{Height: 25, Format: snapshottypes.CurrentFormat, Chunks: 6},
{Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5},
},
},
"no snapshots": {
ssCfg: SnapshotsConfig{
blocks: 10,
blockTxs: 2,
snapshotInterval: 0, // 0 implies disable snapshots
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
},
expectedSnapshots: []*abci.Snapshot{},
},
"keep all snapshots": {
ssCfg: SnapshotsConfig{
blocks: 10,
blockTxs: 2,
snapshotInterval: 3,
snapshotKeepRecent: 0, // 0 implies keep all snapshots
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
},
expectedSnapshots: []*abci.Snapshot{
{Height: 9, Format: snapshottypes.CurrentFormat, Chunks: 2},
{Height: 6, Format: snapshottypes.CurrentFormat, Chunks: 2},
{Height: 3, Format: snapshottypes.CurrentFormat, Chunks: 1},
},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
suite := NewBaseAppSuiteWithSnapshots(t, tc.ssCfg)
resp, err := suite.baseApp.ListSnapshots(&abci.RequestListSnapshots{})
require.NoError(t, err)
for _, s := range resp.Snapshots {
require.NotEmpty(t, s.Hash)
require.NotEmpty(t, s.Metadata)
s.Hash = nil
s.Metadata = nil
}
require.Equal(t, &abci.ResponseListSnapshots{Snapshots: tc.expectedSnapshots}, resp)
// Validate that heights were pruned correctly by querying the state at the last height that should be present relative to latest
// and the first height that should be pruned.
//
// Exceptions:
// * Prune nothing: should be able to query all heights (we only test first and latest)
// * Prune default: should be able to query all heights (we only test first and latest)
// * The reason for default behaving this way is that we only commit 20 heights but default has 100_000 keep-recent
var lastExistingHeight int64
if tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningNothing || tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningDefault {
lastExistingHeight = 1
} else {
// Integer division rounds down so by multiplying back we get the last height at which we pruned
lastExistingHeight = int64((tc.ssCfg.blocks/tc.ssCfg.pruningOpts.Interval)*tc.ssCfg.pruningOpts.Interval - tc.ssCfg.pruningOpts.KeepRecent)
}
// Query 1
res, err := suite.baseApp.Query(context.TODO(), &abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight})
require.NoError(t, err)
require.NotNil(t, res, "height: %d", lastExistingHeight)
require.NotNil(t, res.Value, "height: %d", lastExistingHeight)
// Query 2
res, err = suite.baseApp.Query(context.TODO(), &abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight - 1})
require.NoError(t, err)
require.NotNil(t, res, "height: %d", lastExistingHeight-1)
if tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningNothing || tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningDefault {
// With prune nothing or default, we query height 0 which translates to the latest height.
require.NotNil(t, res.Value, "height: %d", lastExistingHeight-1)
}
})
}
}
func TestABCI_LoadSnapshotChunk(t *testing.T) {
ssCfg := SnapshotsConfig{
blocks: 2,
blockTxs: 5,
snapshotInterval: 2,
snapshotKeepRecent: snapshottypes.CurrentFormat,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
}
suite := NewBaseAppSuiteWithSnapshots(t, ssCfg)
testCases := map[string]struct {
height uint64
format uint32
chunk uint32
expectEmpty bool
}{
"Existing snapshot": {2, snapshottypes.CurrentFormat, 1, false},
"Missing height": {100, snapshottypes.CurrentFormat, 1, true},
"Missing format": {2, snapshottypes.CurrentFormat + 1, 1, true},
"Missing chunk": {2, snapshottypes.CurrentFormat, 9, true},
"Zero height": {0, snapshottypes.CurrentFormat, 1, true},
"Zero format": {2, 0, 1, true},
"Zero chunk": {2, snapshottypes.CurrentFormat, 0, false},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
resp, _ := suite.baseApp.LoadSnapshotChunk(&abci.RequestLoadSnapshotChunk{
Height: tc.height,
Format: tc.format,
Chunk: tc.chunk,
})
if tc.expectEmpty {
require.Equal(t, &abci.ResponseLoadSnapshotChunk{}, resp)
return
}
require.NotEmpty(t, resp.Chunk)
})
}
}
func TestABCI_OfferSnapshot_Errors(t *testing.T) {
ssCfg := SnapshotsConfig{
blocks: 0,
blockTxs: 0,
snapshotInterval: 2,
snapshotKeepRecent: 2,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
}
suite := NewBaseAppSuiteWithSnapshots(t, ssCfg)
m := snapshottypes.Metadata{ChunkHashes: [][]byte{{1}, {2}, {3}}}
metadata, err := m.Marshal()
require.NoError(t, err)
hash := []byte{1, 2, 3}
testCases := map[string]struct {
snapshot *abci.Snapshot
result abci.ResponseOfferSnapshot_Result
}{
"nil snapshot": {nil, abci.ResponseOfferSnapshot_REJECT},
"invalid format": {&abci.Snapshot{
Height: 1, Format: 9, Chunks: 3, Hash: hash, Metadata: metadata,
}, abci.ResponseOfferSnapshot_REJECT_FORMAT},
"incorrect chunk count": {&abci.Snapshot{
Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 2, Hash: hash, Metadata: metadata,
}, abci.ResponseOfferSnapshot_REJECT},
"no chunks": {&abci.Snapshot{
Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 0, Hash: hash, Metadata: metadata,
}, abci.ResponseOfferSnapshot_REJECT},
"invalid metadata serialization": {&abci.Snapshot{
Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 0, Hash: hash, Metadata: []byte{3, 1, 4},
}, abci.ResponseOfferSnapshot_REJECT},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
resp, err := suite.baseApp.OfferSnapshot(&abci.RequestOfferSnapshot{Snapshot: tc.snapshot})
require.NoError(t, err)
require.Equal(t, tc.result, resp.Result)
})
}
// Offering a snapshot after one has been accepted should error
resp, err := suite.baseApp.OfferSnapshot(&abci.RequestOfferSnapshot{Snapshot: &abci.Snapshot{
Height: 1,
Format: snapshottypes.CurrentFormat,
Chunks: 3,
Hash: []byte{1, 2, 3},
Metadata: metadata,
}})
require.NoError(t, err)
require.Equal(t, &abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}, resp)
resp, err = suite.baseApp.OfferSnapshot(&abci.RequestOfferSnapshot{Snapshot: &abci.Snapshot{
Height: 2,
Format: snapshottypes.CurrentFormat,
Chunks: 3,
Hash: []byte{1, 2, 3},
Metadata: metadata,
}})
require.NoError(t, err)
require.Equal(t, &abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}, resp)
}
func TestABCI_ApplySnapshotChunk(t *testing.T) {
srcCfg := SnapshotsConfig{
blocks: 4,
blockTxs: 10,
snapshotInterval: 2,
snapshotKeepRecent: 2,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
}
srcSuite := NewBaseAppSuiteWithSnapshots(t, srcCfg)
targetCfg := SnapshotsConfig{
blocks: 0,
blockTxs: 0,
snapshotInterval: 2,
snapshotKeepRecent: 2,
pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing),
}
targetSuite := NewBaseAppSuiteWithSnapshots(t, targetCfg)
// fetch latest snapshot to restore
respList, err := srcSuite.baseApp.ListSnapshots(&abci.RequestListSnapshots{})
require.NoError(t, err)
require.NotEmpty(t, respList.Snapshots)
snapshot := respList.Snapshots[0]
// make sure the snapshot has at least 3 chunks
require.GreaterOrEqual(t, snapshot.Chunks, uint32(3), "Not enough snapshot chunks")
// begin a snapshot restoration in the target
respOffer, err := targetSuite.baseApp.OfferSnapshot(&abci.RequestOfferSnapshot{Snapshot: snapshot})
require.NoError(t, err)
require.Equal(t, &abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}, respOffer)
// We should be able to pass an invalid chunk and get a verify failure, before
// reapplying it.
respApply, err := targetSuite.baseApp.ApplySnapshotChunk(&abci.RequestApplySnapshotChunk{
Index: 0,
Chunk: []byte{9},
Sender: "sender",
})
require.NoError(t, err)
require.Equal(t, &abci.ResponseApplySnapshotChunk{
Result: abci.ResponseApplySnapshotChunk_RETRY,
RefetchChunks: []uint32{0},
RejectSenders: []string{"sender"},
}, respApply)
// fetch each chunk from the source and apply it to the target
for index := uint32(0); index < snapshot.Chunks; index++ {
respChunk, err := srcSuite.baseApp.LoadSnapshotChunk(&abci.RequestLoadSnapshotChunk{
Height: snapshot.Height,
Format: snapshot.Format,
Chunk: index,
})
require.NoError(t, err)
require.NotNil(t, respChunk.Chunk)
respApply, err := targetSuite.baseApp.ApplySnapshotChunk(&abci.RequestApplySnapshotChunk{
Index: index,
Chunk: respChunk.Chunk,
})
require.NoError(t, err)
require.Equal(t, &abci.ResponseApplySnapshotChunk{
Result: abci.ResponseApplySnapshotChunk_ACCEPT,
}, respApply)
}
// the target should now have the same hash as the source
require.Equal(t, srcSuite.baseApp.LastCommitID(), targetSuite.baseApp.LastCommitID())
}

36
baseapp/state.go Normal file
View file

@ -0,0 +1,36 @@
package baseapp
import (
"sync"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
type state struct {
ms storetypes.CacheMultiStore
mtx sync.RWMutex
ctx sdk.Context
}
// CacheMultiStore calls and returns a CacheMultiStore on the state's underling
// CacheMultiStore.
func (st *state) CacheMultiStore() storetypes.CacheMultiStore {
return st.ms.CacheMultiStore()
}
// SetContext updates the state's context to the context provided.
func (st *state) SetContext(ctx sdk.Context) {
st.mtx.Lock()
defer st.mtx.Unlock()
st.ctx = ctx
}
// Context returns the Context of the state.
func (st *state) Context() sdk.Context {
st.mtx.RLock()
defer st.mtx.RUnlock()
return st.ctx
}

108
baseapp/streaming.go Normal file
View file

@ -0,0 +1,108 @@
package baseapp
import (
"fmt"
"slices"
"sort"
"strings"
"github.com/spf13/cast"
"cosmossdk.io/store/streaming"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client/flags"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
)
const (
StreamingTomlKey = "streaming"
StreamingABCITomlKey = "abci"
StreamingABCIPluginTomlKey = "plugin"
StreamingABCIKeysTomlKey = "keys"
StreamingABCIStopNodeOnErrTomlKey = "stop-node-on-err"
)
// RegisterStreamingServices registers streaming services with the BaseApp.
func (app *BaseApp) RegisterStreamingServices(appOpts servertypes.AppOptions, keys map[string]*storetypes.KVStoreKey) error {
// register streaming services
streamingCfg := cast.ToStringMap(appOpts.Get(StreamingTomlKey))
for service := range streamingCfg {
pluginKey := fmt.Sprintf("%s.%s.%s", StreamingTomlKey, service, StreamingABCIPluginTomlKey)
pluginName := strings.TrimSpace(cast.ToString(appOpts.Get(pluginKey)))
if len(pluginName) > 0 {
logLevel := cast.ToString(appOpts.Get(flags.FlagLogLevel))
plugin, err := streaming.NewStreamingPlugin(pluginName, logLevel)
if err != nil {
return fmt.Errorf("failed to load streaming plugin: %w", err)
}
if err := app.registerStreamingPlugin(appOpts, keys, plugin); err != nil {
return fmt.Errorf("failed to register streaming plugin %w", err)
}
}
}
return nil
}
// registerStreamingPlugin registers streaming plugins with the BaseApp.
func (app *BaseApp) registerStreamingPlugin(
appOpts servertypes.AppOptions,
keys map[string]*storetypes.KVStoreKey,
streamingPlugin any,
) error {
v, ok := streamingPlugin.(storetypes.ABCIListener)
if !ok {
return fmt.Errorf("unexpected plugin type %T", v)
}
app.registerABCIListenerPlugin(appOpts, keys, v)
return nil
}
// registerABCIListenerPlugin registers plugins that implement the ABCIListener interface.
func (app *BaseApp) registerABCIListenerPlugin(
appOpts servertypes.AppOptions,
keys map[string]*storetypes.KVStoreKey,
abciListener storetypes.ABCIListener,
) {
stopNodeOnErrKey := fmt.Sprintf("%s.%s.%s", StreamingTomlKey, StreamingABCITomlKey, StreamingABCIStopNodeOnErrTomlKey)
stopNodeOnErr := cast.ToBool(appOpts.Get(stopNodeOnErrKey))
keysKey := fmt.Sprintf("%s.%s.%s", StreamingTomlKey, StreamingABCITomlKey, StreamingABCIKeysTomlKey)
exposeKeysStr := cast.ToStringSlice(appOpts.Get(keysKey))
exposedKeys := exposeStoreKeysSorted(exposeKeysStr, keys)
app.cms.AddListeners(exposedKeys)
app.SetStreamingManager(
storetypes.StreamingManager{
ABCIListeners: []storetypes.ABCIListener{abciListener},
StopNodeOnErr: stopNodeOnErr,
},
)
}
func exposeAll(list []string) bool {
return slices.Contains(list, "*")
}
func exposeStoreKeysSorted(keysStr []string, keys map[string]*storetypes.KVStoreKey) []storetypes.StoreKey {
var exposeStoreKeys []storetypes.StoreKey
if exposeAll(keysStr) {
exposeStoreKeys = make([]storetypes.StoreKey, 0, len(keys))
for key := range keys {
exposeStoreKeys = append(exposeStoreKeys, keys[key])
}
} else {
exposeStoreKeys = make([]storetypes.StoreKey, 0, len(keysStr))
for _, keyStr := range keysStr {
if storeKey, ok := keys[keyStr]; ok {
exposeStoreKeys = append(exposeStoreKeys, storeKey)
}
}
}
// sort storeKeys for deterministic output
sort.SliceStable(exposeStoreKeys, func(i, j int) bool {
return exposeStoreKeys[i].Name() < exposeStoreKeys[j].Name()
})
return exposeStoreKeys
}

151
baseapp/streaming_test.go Normal file
View file

@ -0,0 +1,151 @@
package baseapp_test
import (
"context"
"fmt"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/stretchr/testify/require"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/baseapp"
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
)
var _ storetypes.ABCIListener = (*MockABCIListener)(nil)
type MockABCIListener struct {
name string
ChangeSet []*storetypes.StoreKVPair
}
func NewMockABCIListener(name string) MockABCIListener {
return MockABCIListener{
name: name,
ChangeSet: make([]*storetypes.StoreKVPair, 0),
}
}
func (m MockABCIListener) ListenFinalizeBlock(_ context.Context, _ abci.RequestFinalizeBlock, _ abci.ResponseFinalizeBlock) error {
return nil
}
func (m *MockABCIListener) ListenCommit(_ context.Context, _ abci.ResponseCommit, cs []*storetypes.StoreKVPair) error {
m.ChangeSet = cs
return nil
}
var distKey1 = storetypes.NewKVStoreKey("distKey1")
func TestABCI_MultiListener_StateChanges(t *testing.T) {
anteKey := []byte("ante-key")
anteOpt := func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) }
distOpt := func(bapp *baseapp.BaseApp) { bapp.MountStores(distKey1) }
mockListener1 := NewMockABCIListener("lis_1")
mockListener2 := NewMockABCIListener("lis_2")
streamingManager := storetypes.StreamingManager{ABCIListeners: []storetypes.ABCIListener{&mockListener1, &mockListener2}}
streamingManagerOpt := func(bapp *baseapp.BaseApp) { bapp.SetStreamingManager(streamingManager) }
addListenerOpt := func(bapp *baseapp.BaseApp) { bapp.CommitMultiStore().AddListeners([]storetypes.StoreKey{distKey1}) }
suite := NewBaseAppSuite(t, anteOpt, distOpt, streamingManagerOpt, addListenerOpt)
_, err := suite.baseApp.InitChain(
&abci.RequestInitChain{
ConsensusParams: &tmproto.ConsensusParams{},
},
)
require.NoError(t, err)
deliverKey := []byte("deliver-key")
baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, deliverKey})
nBlocks := 3
txPerHeight := 5
for blockN := range nBlocks {
txs := [][]byte{}
var expectedChangeSet []*storetypes.StoreKVPair
// create final block context state
_, err := suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: int64(blockN) + 1, Txs: txs})
require.NoError(t, err)
for i := range txPerHeight {
counter := int64(blockN*txPerHeight + i)
tx := newTxCounter(t, suite.txConfig, counter, counter)
txBytes, err := suite.txConfig.TxEncoder()(tx)
require.NoError(t, err)
sKey := fmt.Appendf(nil, "distKey%d", i)
sVal := fmt.Appendf(nil, "distVal%d", i)
store := getFinalizeBlockStateCtx(suite.baseApp).KVStore(distKey1)
store.Set(sKey, sVal)
expectedChangeSet = append(expectedChangeSet, &storetypes.StoreKVPair{
StoreKey: distKey1.Name(),
Delete: false,
Key: sKey,
Value: sVal,
})
txs = append(txs, txBytes)
}
res, err := suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: int64(blockN) + 1, Txs: txs})
require.NoError(t, err)
for _, tx := range res.TxResults {
events := tx.GetEvents()
require.Len(t, events, 3, "should contain ante handler, message type and counter events respectively")
// require.Equal(t, sdk.MarkEventsToIndex(counterEvent("ante_handler", counter).ToABCIEvents(), map[string]struct{}{})[0], events[0], "ante handler event")
// require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0], events[2], "msg handler update counter event")
}
_, err = suite.baseApp.Commit()
require.NoError(t, err)
require.Equal(t, expectedChangeSet, mockListener1.ChangeSet, "should contain the same changeSet")
require.Equal(t, expectedChangeSet, mockListener2.ChangeSet, "should contain the same changeSet")
}
}
func Test_Ctx_with_StreamingManager(t *testing.T) {
mockListener1 := NewMockABCIListener("lis_1")
mockListener2 := NewMockABCIListener("lis_2")
listeners := []storetypes.ABCIListener{&mockListener1, &mockListener2}
streamingManager := storetypes.StreamingManager{ABCIListeners: listeners, StopNodeOnErr: true}
streamingManagerOpt := func(bapp *baseapp.BaseApp) { bapp.SetStreamingManager(streamingManager) }
addListenerOpt := func(bapp *baseapp.BaseApp) { bapp.CommitMultiStore().AddListeners([]storetypes.StoreKey{distKey1}) }
suite := NewBaseAppSuite(t, streamingManagerOpt, addListenerOpt)
_, err := suite.baseApp.InitChain(&abci.RequestInitChain{
ConsensusParams: &tmproto.ConsensusParams{},
})
require.NoError(t, err)
ctx := getFinalizeBlockStateCtx(suite.baseApp)
sm := ctx.StreamingManager()
require.NotNil(t, sm, fmt.Sprintf("nil StreamingManager: %v", sm))
require.Equal(t, listeners, sm.ABCIListeners, fmt.Sprintf("should contain same listeners: %v", listeners))
require.Equal(t, true, sm.StopNodeOnErr, "should contain StopNodeOnErr = true")
nBlocks := 2
for blockN := range nBlocks {
_, err := suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: int64(blockN) + 1})
require.NoError(t, err)
ctx := getFinalizeBlockStateCtx(suite.baseApp)
sm := ctx.StreamingManager()
require.NotNil(t, sm, fmt.Sprintf("nil StreamingManager: %v", sm))
require.Equal(t, listeners, sm.ABCIListeners, fmt.Sprintf("should contain same listeners: %v", listeners))
require.Equal(t, true, sm.StopNodeOnErr, "should contain StopNodeOnErr = true")
_, err = suite.baseApp.Commit()
require.NoError(t, err)
}
}

85
baseapp/test_helpers.go Normal file
View file

@ -0,0 +1,85 @@
package baseapp
import (
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// SimCheck defines a CheckTx helper function that used in tests and simulations.
func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) {
// runTx expects tx bytes as argument, so we encode the tx argument into
// bytes. Note that runTx will actually decode those bytes again. But since
// this helper is only used in tests/simulation, it's fine.
bz, err := txEncoder(tx)
if err != nil {
return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
gasInfo, result, _, err := app.runTx(execModeCheck, bz, tx)
return gasInfo, result, err
}
// Simulate executes a tx in simulate mode to get result and gas info.
func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) {
gasInfo, result, _, err := app.runTx(execModeSimulate, txBytes, nil)
return gasInfo, result, err
}
func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) {
// See comment for Check().
bz, err := txEncoder(tx)
if err != nil {
return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
gasInfo, result, _, err := app.runTx(execModeFinalize, bz, tx)
return gasInfo, result, err
}
func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) {
// See comment for Check().
bz, err := txEncoder(tx)
if err != nil {
return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
gasInfo, result, _, err := app.runTx(execModeFinalize, bz, tx)
return gasInfo, result, err
}
// SimWriteState is an entrypoint for simulations only. They are not executed during the normal ABCI finalize
// block step but later. Therefor an extra call to the root multi-store (app.cms) is required to write the changes.
func (app *BaseApp) SimWriteState() {
app.finalizeBlockState.ms.Write()
}
// NewContextLegacy returns a new sdk.Context with the provided header
func (app *BaseApp) NewContextLegacy(isCheckTx bool, header cmtproto.Header) sdk.Context {
if isCheckTx {
return sdk.NewContext(app.checkState.ms, header, true, app.logger).
WithMinGasPrices(app.minGasPrices)
}
return sdk.NewContext(app.finalizeBlockState.ms, header, false, app.logger)
}
// NewContext returns a new sdk.Context with a empty header
func (app *BaseApp) NewContext(isCheckTx bool) sdk.Context {
return app.NewContextLegacy(isCheckTx, cmtproto.Header{})
}
func (app *BaseApp) NewUncachedContext(isCheckTx bool, header cmtproto.Header) sdk.Context {
return sdk.NewContext(app.cms, header, isCheckTx, app.logger)
}
func (app *BaseApp) GetContextForFinalizeBlock(txBytes []byte) sdk.Context {
return app.getContextForTx(execModeFinalize, txBytes)
}
func (app *BaseApp) GetContextForCheckTx(txBytes []byte) sdk.Context {
return app.getContextForTx(execModeCheck, txBytes)
}

View file

@ -0,0 +1,5 @@
version: v1
plugins:
- name: gocosmos
out: ../..
opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types

Some files were not shown because too many files have changed in this diff Show more