diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml new file mode 100644 index 0000000000..18959e503a --- /dev/null +++ b/.github/workflows/sims.yml @@ -0,0 +1,284 @@ +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: + pull_request: + push: + branches: + - master + +jobs: + cleanup-runs: + runs-on: ubuntu-latest + if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + build: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'skip-sims')" + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - run: make build + + install-runsim: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - name: Install runsim + run: export GO111MODULE="on" && go get github.com/cosmos/tools/cmd/runsim@v1.0.0 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + + # experimental simulations + sim-nondeterminism-experimental: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + PATTERNS: | + **/**.go + go.mod + go.sum + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-nondeterminism-experimental + run: | + make sim-regen-nondeterminism + if: env.GIT_DIFF + + sim-import-export-experimental: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + SUFFIX_FILTER: | + **/**.go + go.mod + go.sum + SET_ENV_NAME_INSERTIONS: 1 + SET_ENV_NAME_LINES: 1 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-import-export-experimental + run: | + make sim-regen-import-export + if: env.GIT_DIFF + + sim-after-import-experimental: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + SUFFIX_FILTER: | + **/**.go + go.mod + go.sum + SET_ENV_NAME_INSERTIONS: 1 + SET_ENV_NAME_LINES: 1 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-after-import-experimental + run: | + make sim-regen-after-import + if: env.GIT_DIFF + + sim-fullapp-experimental: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + SUFFIX_FILTER: | + **/**.go + go.mod + go.sum + SET_ENV_NAME_INSERTIONS: 1 + SET_ENV_NAME_LINES: 1 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-fullapp-experimental + run: | + make sim-regen-fast + if: env.GIT_DIFF + + + # stable simulation jobs + sim-nondeterminism-stable: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + PATTERNS: | + **/**.go + go.mod + go.sum + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-nondeterminism-stable + run: | + make sim-regen-nondeterminism + if: env.GIT_DIFF + + sim-import-export-stable: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + SUFFIX_FILTER: | + **/**.go + go.mod + go.sum + SET_ENV_NAME_INSERTIONS: 1 + SET_ENV_NAME_LINES: 1 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-import-export-stable + run: | + make sim-regen-import-export + if: env.GIT_DIFF + + sim-after-import-stable: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + SUFFIX_FILTER: | + **/**.go + go.mod + go.sum + SET_ENV_NAME_INSERTIONS: 1 + SET_ENV_NAME_LINES: 1 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-after-import-stable + run: | + make sim-regen-after-import + if: env.GIT_DIFF + + sim-fullapp-stable: + runs-on: ubuntu-latest + needs: [build, install-runsim] + env: + EXPERIMENTAL: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2.1.3 + with: + go-version: 1.15 + - name: Display go version + run: go version + - uses: technote-space/get-diff-action@v4 + with: + SUFFIX_FILTER: | + **/**.go + go.mod + go.sum + SET_ENV_NAME_INSERTIONS: 1 + SET_ENV_NAME_LINES: 1 + - uses: actions/cache@v2.1.3 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + if: env.GIT_DIFF + - name: sim-fullapp-stable + run: | + make sim-regen-fast + if: env.GIT_DIFF diff --git a/app/app.go b/app/app.go index b7c3f5fccd..f32e2f4a23 100644 --- a/app/app.go +++ b/app/app.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -89,6 +90,8 @@ const ( appName = "regen" ) +var _ simapp.App = &RegenApp{} + var ( // DefaultNodeHome default home directories for regen DefaultNodeHome = os.ExpandEnv("$HOME/.regen") diff --git a/app/experimental_appconfig.go b/app/experimental_appconfig.go index 72988651b3..e76b5fd626 100644 --- a/app/experimental_appconfig.go +++ b/app/experimental_appconfig.go @@ -78,8 +78,8 @@ func setCustomModules(app *RegenApp, interfaceRegistry types.InterfaceRegistry) /* New Module Wiring START */ newModuleManager := server.NewManager(app.BaseApp, codec.NewProtoCodec(interfaceRegistry)) - // BEGIN HACK: this is a total, ugly hack until x/auth supports ADR 033 or we have a suitable alternative - groupModule := group.Module{AccountKeeper: app.AccountKeeper} + // BEGIN HACK: this is a total, ugly hack until x/auth & x/bank supports ADR 033 or we have a suitable alternative + groupModule := group.Module{AccountKeeper: app.AccountKeeper, BankKeeper: app.BankKeeper} // use a separate newModules from the global NewModules here because we need to pass state into the group module newModules := []moduletypes.Module{ ecocredit.Module{}, @@ -97,8 +97,8 @@ func setCustomModules(app *RegenApp, interfaceRegistry types.InterfaceRegistry) panic(err) } - return newModuleManager /* New Module Wiring END */ + return newModuleManager } func (app *RegenApp) registerUpgradeHandlers() { @@ -122,6 +122,11 @@ func setCustomOrderInitGenesis() []string { func (app *RegenApp) setCustomSimulationManager() []module.AppModuleSimulation { return []module.AppModuleSimulation{ wasm.NewAppModule(&app.wasmKeeper, app.StakingKeeper), + group.Module{ + Registry: app.interfaceRegistry, + BankKeeper: app.BankKeeper, + AccountKeeper: app.AccountKeeper, + }, } } diff --git a/app/sim_test.go b/app/sim_test.go index 1c62c93640..5d8572709c 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -7,6 +7,8 @@ import ( "os" "testing" + "github.com/cosmos/cosmos-sdk/simapp" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" @@ -14,11 +16,9 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/simapp/helpers" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" @@ -90,7 +90,7 @@ func simulateFromSeed(t *testing.T, app *RegenApp, config simtypes.Config) (bool t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.AppCodec(), app.SimulationManager()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 - simapp.SimulationOperations(app, app.AppCodec(), config), + SimulationOperations(app, app.AppCodec(), config), app.ModuleAccountAddrs(), config, app.AppCodec(), @@ -244,7 +244,7 @@ func TestAppSimulationAfterImport(t *testing.T) { newApp.BaseApp, simapp.AppStateFn(app.AppCodec(), app.SimulationManager()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 - simapp.SimulationOperations(newApp, newApp.AppCodec(), config), + SimulationOperations(newApp, newApp.AppCodec(), config), app.ModuleAccountAddrs(), config, app.appCodec, diff --git a/app/utils.go b/app/utils.go new file mode 100644 index 0000000000..0c237d1416 --- /dev/null +++ b/app/utils.go @@ -0,0 +1,35 @@ +package app + +import ( + "encoding/json" + "io/ioutil" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/simulation" +) + +// SimulationOperations retrieves the simulation params from the provided file path +// and returns all the modules weighted operations +func SimulationOperations(app *RegenApp, cdc codec.JSONMarshaler, config simulation.Config) []simulation.WeightedOperation { + simState := module.SimulationState{ + AppParams: make(simulation.AppParams), + Cdc: cdc, + } + + if config.ParamsFile != "" { + bz, err := ioutil.ReadFile(config.ParamsFile) + if err != nil { + panic(err) + } + + err = json.Unmarshal(bz, &simState.AppParams) + if err != nil { + panic(err) + } + } + + simState.ParamChanges = app.SimulationManager().GenerateParamChanges(config.Seed) + simState.Contents = app.SimulationManager().GetProposalContents(simState) + return app.smm.WeightedOperations(simState, app.sm.Modules) +} diff --git a/docs/modules/data/protobuf.md b/docs/modules/data/protobuf.md index 91dd136005..b3b35aba83 100644 --- a/docs/modules/data/protobuf.md +++ b/docs/modules/data/protobuf.md @@ -16,15 +16,21 @@ - [GraphMerkleTree](#regen.data.v1alpha2.GraphMerkleTree) - [MediaType](#regen.data.v1alpha2.MediaType) +- [regen/data/v1alpha2/tx.proto](#regen/data/v1alpha2/tx.proto) + - [MsgAnchorDataRequest](#regen.data.v1alpha2.MsgAnchorDataRequest) + - [MsgAnchorDataResponse](#regen.data.v1alpha2.MsgAnchorDataResponse) + - [MsgSignDataRequest](#regen.data.v1alpha2.MsgSignDataRequest) + - [MsgSignDataResponse](#regen.data.v1alpha2.MsgSignDataResponse) + - [MsgStoreRawDataRequest](#regen.data.v1alpha2.MsgStoreRawDataRequest) + - [MsgStoreRawDataResponse](#regen.data.v1alpha2.MsgStoreRawDataResponse) + + - [Msg](#regen.data.v1alpha2.Msg) + - [regen/data/v1alpha2/events.proto](#regen/data/v1alpha2/events.proto) - [EventAnchorData](#regen.data.v1alpha2.EventAnchorData) - [EventSignData](#regen.data.v1alpha2.EventSignData) - [EventStoreRawData](#regen.data.v1alpha2.EventStoreRawData) -- [regen/data/v1alpha2/genesis.proto](#regen/data/v1alpha2/genesis.proto) - - [GenesisContentEntry](#regen.data.v1alpha2.GenesisContentEntry) - - [GenesisState](#regen.data.v1alpha2.GenesisState) - - [regen/data/v1alpha2/query.proto](#regen/data/v1alpha2/query.proto) - [ContentEntry](#regen.data.v1alpha2.ContentEntry) - [QueryByHashRequest](#regen.data.v1alpha2.QueryByHashRequest) @@ -34,15 +40,9 @@ - [Query](#regen.data.v1alpha2.Query) -- [regen/data/v1alpha2/tx.proto](#regen/data/v1alpha2/tx.proto) - - [MsgAnchorDataRequest](#regen.data.v1alpha2.MsgAnchorDataRequest) - - [MsgAnchorDataResponse](#regen.data.v1alpha2.MsgAnchorDataResponse) - - [MsgSignDataRequest](#regen.data.v1alpha2.MsgSignDataRequest) - - [MsgSignDataResponse](#regen.data.v1alpha2.MsgSignDataResponse) - - [MsgStoreRawDataRequest](#regen.data.v1alpha2.MsgStoreRawDataRequest) - - [MsgStoreRawDataResponse](#regen.data.v1alpha2.MsgStoreRawDataResponse) - - - [Msg](#regen.data.v1alpha2.Msg) +- [regen/data/v1alpha2/genesis.proto](#regen/data/v1alpha2/genesis.proto) + - [GenesisContentEntry](#regen.data.v1alpha2.GenesisContentEntry) + - [GenesisState](#regen.data.v1alpha2.GenesisState) - [Scalar Value Types](#scalar-value-types) @@ -209,53 +209,91 @@ MediaType defines MIME media types to be used with a ContentHash.Raw hash. - +
-## regen/data/v1alpha2/events.proto +## regen/data/v1alpha2/tx.proto - + -### EventAnchorData -EventAnchorData is an event emitted when data is anchored on-chain. +### MsgAnchorDataRequest +MsgAnchorDataRequest is the Msg/AnchorData request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| iri | [string](#string) | | iri is the data IRI | +| sender | [string](#string) | | sender is the address of the sender of the transaction. The sender in StoreData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing services. | +| hash | [ContentHash](#regen.data.v1alpha2.ContentHash) | | hash is the hash-based identifier for the anchored content. | - + -### EventSignData -EventSignData is an event emitted when data is signed on-chain. +### MsgAnchorDataResponse +MsgAnchorDataRequest is the Msg/AnchorData response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| iri | [string](#string) | | iri is the data IRI | -| signers | [string](#string) | repeated | signers are the addresses of the accounts which have signed the data. | +| timestamp | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | timestamp is the timestamp of the block at which the data was anchored. | - + -### EventStoreRawData -EventStoreRawData is an event emitted when data is stored on-chain. +### MsgSignDataRequest +MsgSignDataRequest is the Msg/SignData request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| iri | [string](#string) | | iri is the data IRI | +| signers | [string](#string) | repeated | signers are the addresses of the accounts signing the data. By making a SignData request, the signers are attesting to the veracity of the data referenced by the cid. The precise meaning of this may vary depending on the underlying data. | +| hash | [ContentHash.Graph](#regen.data.v1alpha2.ContentHash.Graph) | | hash is the hash-based identifier for the anchored content. Only RDF graph data can be signed as its data model is intended to specifically convey semantic meaning. | + + + + + + + + +### MsgSignDataResponse +MsgSignDataResponse is the Msg/SignData response type. + + + + + + + + +### MsgStoreRawDataRequest +MsgStoreRawDataRequest is the Msg/StoreRawData request type. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| sender | [string](#string) | | sender is the address of the sender of the transaction. The sender in StoreData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing services. | +| content_hash | [ContentHash.Raw](#regen.data.v1alpha2.ContentHash.Raw) | | content_hash is the hash-based identifier for the anchored content. | +| content | [bytes](#bytes) | | content is the content of the raw data corresponding to the provided content hash. | + + + + + + + + +### MsgStoreRawDataResponse +MsgStoreRawDataRequest is the Msg/StoreRawData response type. @@ -267,44 +305,81 @@ EventStoreRawData is an event emitted when data is stored on-chain. + + + +### Msg +Msg is the regen.data.v1alpha1 Msg service + +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +| AnchorData | [MsgAnchorDataRequest](#regen.data.v1alpha2.MsgAnchorDataRequest) | [MsgAnchorDataResponse](#regen.data.v1alpha2.MsgAnchorDataResponse) | AnchorData "anchors" a piece of data to the blockchain based on its secure hash, effectively providing a tamper resistant timestamp. + +The sender in AnchorData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing timestamp services. SignData should be used to create a digital signature attesting to the veracity of some piece of data. | +| SignData | [MsgSignDataRequest](#regen.data.v1alpha2.MsgSignDataRequest) | [MsgSignDataResponse](#regen.data.v1alpha2.MsgSignDataResponse) | SignData allows for signing of an arbitrary piece of data on the blockchain. By "signing" data the signers are making a statement about the veracity of the data itself. It is like signing a legal document, meaning that I agree to all conditions and to the best of my knowledge everything is true. When anchoring data, the sender is not attesting to the veracity of the data, they are simply communicating that it exists. + +On-chain signatures have the following benefits: - on-chain identities can be managed using different cryptographic keys that change over time through key rotation practices - an on-chain identity may represent an organization and through delegation individual members may sign on behalf of the group - the blockchain transaction envelope provides built-in replay protection and timestamping + +SignData implicitly calls AnchorData if the data was not already anchored. + +SignData can be called multiple times for the same content hash with different signers and those signers will be appended to the list of signers. | +| StoreRawData | [MsgStoreRawDataRequest](#regen.data.v1alpha2.MsgStoreRawDataRequest) | [MsgStoreRawDataResponse](#regen.data.v1alpha2.MsgStoreRawDataResponse) | StoreRawData stores a piece of raw data corresponding to an ContentHash.Raw on the blockchain. + +StoreRawData implicitly calls AnchorData if the data was not already anchored. + +The sender in StoreRawData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing storage services. SignData should be used to create a digital signature attesting to the veracity of some piece of data. | + - + -## regen/data/v1alpha2/genesis.proto +## regen/data/v1alpha2/events.proto - + -### GenesisContentEntry -GenesisContentEntry is a genesis content entry +### EventAnchorData +EventAnchorData is an event emitted when data is anchored on-chain. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| hash | [ContentHash](#regen.data.v1alpha2.ContentHash) | | hash is the ContentHash | -| timestamp | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | timestamp is the anchor Timestamp | -| signers | [SignerEntry](#regen.data.v1alpha2.SignerEntry) | repeated | signers are the signers, if any | -| content | [Content](#regen.data.v1alpha2.Content) | | content is the actual content if stored on-chain | +| iri | [string](#string) | | iri is the data IRI | - + -### GenesisState -GenesisState is the genesis state +### EventSignData +EventSignData is an event emitted when data is signed on-chain. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| entries | [GenesisContentEntry](#regen.data.v1alpha2.GenesisContentEntry) | repeated | entries are the content entries | +| iri | [string](#string) | | iri is the data IRI | +| signers | [string](#string) | repeated | signers are the addresses of the accounts which have signed the data. | + + + + + + + + +### EventStoreRawData +EventStoreRawData is an event emitted when data is stored on-chain. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| iri | [string](#string) | | iri is the data IRI | @@ -428,91 +503,40 @@ Query is the regen.data.v1alpha1 Query service - + -## regen/data/v1alpha2/tx.proto - - - - - -### MsgAnchorDataRequest -MsgAnchorDataRequest is the Msg/AnchorData request type. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| sender | [string](#string) | | sender is the address of the sender of the transaction. The sender in StoreData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing services. | -| hash | [ContentHash](#regen.data.v1alpha2.ContentHash) | | hash is the hash-based identifier for the anchored content. | - - - - - - - - -### MsgAnchorDataResponse -MsgAnchorDataRequest is the Msg/AnchorData response type. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| timestamp | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | timestamp is the timestamp of the block at which the data was anchored. | - - - +## regen/data/v1alpha2/genesis.proto - + -### MsgSignDataRequest -MsgSignDataRequest is the Msg/SignData request type. +### GenesisContentEntry +GenesisContentEntry is a genesis content entry | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| signers | [string](#string) | repeated | signers are the addresses of the accounts signing the data. By making a SignData request, the signers are attesting to the veracity of the data referenced by the cid. The precise meaning of this may vary depending on the underlying data. | -| hash | [ContentHash.Graph](#regen.data.v1alpha2.ContentHash.Graph) | | hash is the hash-based identifier for the anchored content. Only RDF graph data can be signed as its data model is intended to specifically convey semantic meaning. | - - - - - - - - -### MsgSignDataResponse -MsgSignDataResponse is the Msg/SignData response type. +| hash | [ContentHash](#regen.data.v1alpha2.ContentHash) | | hash is the ContentHash | +| timestamp | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | timestamp is the anchor Timestamp | +| signers | [SignerEntry](#regen.data.v1alpha2.SignerEntry) | repeated | signers are the signers, if any | +| content | [Content](#regen.data.v1alpha2.Content) | | content is the actual content if stored on-chain | - + -### MsgStoreRawDataRequest -MsgStoreRawDataRequest is the Msg/StoreRawData request type. +### GenesisState +GenesisState is the genesis state | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| sender | [string](#string) | | sender is the address of the sender of the transaction. The sender in StoreData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing services. | -| content_hash | [ContentHash.Raw](#regen.data.v1alpha2.ContentHash.Raw) | | content_hash is the hash-based identifier for the anchored content. | -| content | [bytes](#bytes) | | content is the content of the raw data corresponding to the provided content hash. | - - - - - - - - -### MsgStoreRawDataResponse -MsgStoreRawDataRequest is the Msg/StoreRawData response type. +| entries | [GenesisContentEntry](#regen.data.v1alpha2.GenesisContentEntry) | repeated | entries are the content entries | @@ -524,30 +548,6 @@ MsgStoreRawDataRequest is the Msg/StoreRawData response type. - - - -### Msg -Msg is the regen.data.v1alpha1 Msg service - -| Method Name | Request Type | Response Type | Description | -| ----------- | ------------ | ------------- | ------------| -| AnchorData | [MsgAnchorDataRequest](#regen.data.v1alpha2.MsgAnchorDataRequest) | [MsgAnchorDataResponse](#regen.data.v1alpha2.MsgAnchorDataResponse) | AnchorData "anchors" a piece of data to the blockchain based on its secure hash, effectively providing a tamper resistant timestamp. - -The sender in AnchorData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing timestamp services. SignData should be used to create a digital signature attesting to the veracity of some piece of data. | -| SignData | [MsgSignDataRequest](#regen.data.v1alpha2.MsgSignDataRequest) | [MsgSignDataResponse](#regen.data.v1alpha2.MsgSignDataResponse) | SignData allows for signing of an arbitrary piece of data on the blockchain. By "signing" data the signers are making a statement about the veracity of the data itself. It is like signing a legal document, meaning that I agree to all conditions and to the best of my knowledge everything is true. When anchoring data, the sender is not attesting to the veracity of the data, they are simply communicating that it exists. - -On-chain signatures have the following benefits: - on-chain identities can be managed using different cryptographic keys that change over time through key rotation practices - an on-chain identity may represent an organization and through delegation individual members may sign on behalf of the group - the blockchain transaction envelope provides built-in replay protection and timestamping - -SignData implicitly calls AnchorData if the data was not already anchored. - -SignData can be called multiple times for the same content hash with different signers and those signers will be appended to the list of signers. | -| StoreRawData | [MsgStoreRawDataRequest](#regen.data.v1alpha2.MsgStoreRawDataRequest) | [MsgStoreRawDataResponse](#regen.data.v1alpha2.MsgStoreRawDataResponse) | StoreRawData stores a piece of raw data corresponding to an ContentHash.Raw on the blockchain. - -StoreRawData implicitly calls AnchorData if the data was not already anchored. - -The sender in StoreRawData is not attesting to the veracity of the underlying data. They can simply be a intermediary providing storage services. SignData should be used to create a digital signature attesting to the veracity of some piece of data. | - diff --git a/docs/modules/ecocredit/protobuf.md b/docs/modules/ecocredit/protobuf.md index 0966213a45..4091cde7a7 100644 --- a/docs/modules/ecocredit/protobuf.md +++ b/docs/modules/ecocredit/protobuf.md @@ -4,30 +4,10 @@ ## Table of Contents -- [regen/ecocredit/v1alpha1/events.proto](#regen/ecocredit/v1alpha1/events.proto) - - [EventCreateBatch](#regen.ecocredit.v1alpha1.EventCreateBatch) - - [EventCreateClass](#regen.ecocredit.v1alpha1.EventCreateClass) - - [EventReceive](#regen.ecocredit.v1alpha1.EventReceive) - - [EventRetire](#regen.ecocredit.v1alpha1.EventRetire) - - [regen/ecocredit/v1alpha1/types.proto](#regen/ecocredit/v1alpha1/types.proto) - [BatchInfo](#regen.ecocredit.v1alpha1.BatchInfo) - [ClassInfo](#regen.ecocredit.v1alpha1.ClassInfo) -- [regen/ecocredit/v1alpha1/query.proto](#regen/ecocredit/v1alpha1/query.proto) - - [QueryBalanceRequest](#regen.ecocredit.v1alpha1.QueryBalanceRequest) - - [QueryBalanceResponse](#regen.ecocredit.v1alpha1.QueryBalanceResponse) - - [QueryBatchInfoRequest](#regen.ecocredit.v1alpha1.QueryBatchInfoRequest) - - [QueryBatchInfoResponse](#regen.ecocredit.v1alpha1.QueryBatchInfoResponse) - - [QueryClassInfoRequest](#regen.ecocredit.v1alpha1.QueryClassInfoRequest) - - [QueryClassInfoResponse](#regen.ecocredit.v1alpha1.QueryClassInfoResponse) - - [QueryPrecisionRequest](#regen.ecocredit.v1alpha1.QueryPrecisionRequest) - - [QueryPrecisionResponse](#regen.ecocredit.v1alpha1.QueryPrecisionResponse) - - [QuerySupplyRequest](#regen.ecocredit.v1alpha1.QuerySupplyRequest) - - [QuerySupplyResponse](#regen.ecocredit.v1alpha1.QuerySupplyResponse) - - - [Query](#regen.ecocredit.v1alpha1.Query) - - [regen/ecocredit/v1alpha1/tx.proto](#regen/ecocredit/v1alpha1/tx.proto) - [MsgCreateBatchRequest](#regen.ecocredit.v1alpha1.MsgCreateBatchRequest) - [MsgCreateBatchRequest.BatchIssuance](#regen.ecocredit.v1alpha1.MsgCreateBatchRequest.BatchIssuance) @@ -45,532 +25,552 @@ - [Msg](#regen.ecocredit.v1alpha1.Msg) +- [regen/ecocredit/v1alpha1/events.proto](#regen/ecocredit/v1alpha1/events.proto) + - [EventCreateBatch](#regen.ecocredit.v1alpha1.EventCreateBatch) + - [EventCreateClass](#regen.ecocredit.v1alpha1.EventCreateClass) + - [EventReceive](#regen.ecocredit.v1alpha1.EventReceive) + - [EventRetire](#regen.ecocredit.v1alpha1.EventRetire) + +- [regen/ecocredit/v1alpha1/query.proto](#regen/ecocredit/v1alpha1/query.proto) + - [QueryBalanceRequest](#regen.ecocredit.v1alpha1.QueryBalanceRequest) + - [QueryBalanceResponse](#regen.ecocredit.v1alpha1.QueryBalanceResponse) + - [QueryBatchInfoRequest](#regen.ecocredit.v1alpha1.QueryBatchInfoRequest) + - [QueryBatchInfoResponse](#regen.ecocredit.v1alpha1.QueryBatchInfoResponse) + - [QueryClassInfoRequest](#regen.ecocredit.v1alpha1.QueryClassInfoRequest) + - [QueryClassInfoResponse](#regen.ecocredit.v1alpha1.QueryClassInfoResponse) + - [QueryPrecisionRequest](#regen.ecocredit.v1alpha1.QueryPrecisionRequest) + - [QueryPrecisionResponse](#regen.ecocredit.v1alpha1.QueryPrecisionResponse) + - [QuerySupplyRequest](#regen.ecocredit.v1alpha1.QuerySupplyRequest) + - [QuerySupplyResponse](#regen.ecocredit.v1alpha1.QuerySupplyResponse) + + - [Query](#regen.ecocredit.v1alpha1.Query) + - [Scalar Value Types](#scalar-value-types) - + -## regen/ecocredit/v1alpha1/events.proto +## regen/ecocredit/v1alpha1/types.proto - + -### EventCreateBatch -EventCreateBatch is an event emitted when a credit batch is created. +### BatchInfo +BatchInfo represents the high-level on-chain information for a credit batch. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | class_id | [string](#string) | | class_id is the unique ID of credit class. | | batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | -| issuer | [string](#string) | | issuer is the account address of the issuer of the credit batch. | -| total_units | [string](#string) | | total_units is the total number of units in the credit batch. | +| issuer | [string](#string) | | issuer is the issuer of the credit batch. | +| total_units | [string](#string) | | total_units is the total number of units in the credit batch and is immutable. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit batch. | - + -### EventCreateClass -EventCreateClass is an event emitted when a credit class is created. +### ClassInfo +ClassInfo represents the high-level on-chain information for a credit class. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | class_id | [string](#string) | | class_id is the unique ID of credit class. | | designer | [string](#string) | | designer is the designer of the credit class. | +| issuers | [string](#string) | repeated | issuers are the approved issuers of the credit class. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit class. | + - + -### EventReceive -EventReceive is an event emitted when credits are received either upon -creation of a new batch or upon transfer. Each batch_denom created or -transferred will result in a separate EventReceive for easy indexing. + + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| sender | [string](#string) | | sender is the sender of the credits in the case that this event is the result of a transfer. It will not be set when credits are received at initial issuance. | -| recipient | [string](#string) | | recipient is the recipient of the credits | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | -| units | [string](#string) | | units is the decimal number of both tradable and retired credits received. | + + +## regen/ecocredit/v1alpha1/tx.proto - + -### EventRetire -EventRetire is an event emitted when credits are retired. An separate event -is emitted for each batch_denom in the case where credits from multiple -batches have been retired at once for easy indexing. +### MsgCreateBatchRequest +MsgCreateBatchRequest is the Msg/CreateBatch request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| retirer | [string](#string) | | retirer is the account which has done the "retiring". This will be the account receiving credits in the case that credits were retired upon issuance using Msg/CreateBatch or retired upon transfer using Msg/Send. | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | -| units | [string](#string) | | units is the decimal number of credits that have been retired. | +| issuer | [string](#string) | | issuer is the address of the batch issuer. | +| class_id | [string](#string) | | class_id is the unique ID of the class. | +| issuance | [MsgCreateBatchRequest.BatchIssuance](#regen.ecocredit.v1alpha1.MsgCreateBatchRequest.BatchIssuance) | repeated | issuance are the credits issued in the batch. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit batch. | - - + - +### MsgCreateBatchRequest.BatchIssuance +BatchIssuance represents the issuance of some credits in a batch to a +single recipient. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| recipient | [string](#string) | | recipient is the account of the recipient. | +| tradable_units | [string](#string) | | tradable_units are the units of credits in this issuance that can be traded by this recipient. Decimal values are acceptable. | +| retired_units | [string](#string) | | retired_units are the units of credits in this issuance that are effectively retired by the issuer on receipt. Decimal values are acceptable. | - - -## regen/ecocredit/v1alpha1/types.proto - + -### BatchInfo -BatchInfo represents the high-level on-chain information for a credit batch. +### MsgCreateBatchResponse +MsgCreateBatchResponse is the Msg/CreateBatch response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| class_id | [string](#string) | | class_id is the unique ID of credit class. | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | -| issuer | [string](#string) | | issuer is the issuer of the credit batch. | -| total_units | [string](#string) | | total_units is the total number of units in the credit batch and is immutable. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit batch. | +| batch_denom | [string](#string) | | batch_denom is the unique denomination ID of the newly created batch. | - + -### ClassInfo -ClassInfo represents the high-level on-chain information for a credit class. +### MsgCreateClassRequest +MsgCreateClassRequest is the Msg/CreateClass request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| class_id | [string](#string) | | class_id is the unique ID of credit class. | -| designer | [string](#string) | | designer is the designer of the credit class. | -| issuers | [string](#string) | repeated | issuers are the approved issuers of the credit class. | +| designer | [string](#string) | | designer is the address of the account which designed the credit class. The designer has special permissions to change the list of issuers and perform other administrative operations. | +| issuers | [string](#string) | repeated | issuers are the account addresses of the approved issuers. | | metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit class. | - - + - +### MsgCreateClassResponse +MsgCreateClassResponse is the Msg/CreateClass response type. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| class_id | [string](#string) | | class_id is the unique ID of the newly created credit class. | - - -## regen/ecocredit/v1alpha1/query.proto - + -### QueryBalanceRequest -QueryBalanceRequest is the Query/Balance request type. +### MsgRetireRequest +MsgRetireRequest is the Msg/Retire request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| account | [string](#string) | | account is the address of the account whose balance is being queried. | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch balance to query. | +| holder | [string](#string) | | holder is the credit holder address. | +| credits | [MsgRetireRequest.RetireUnits](#regen.ecocredit.v1alpha1.MsgRetireRequest.RetireUnits) | repeated | credits are the credits being retired. | - + -### QueryBalanceResponse -QueryBalanceResponse is the Query/Balance response type. +### MsgRetireRequest.RetireUnits +RetireUnits are the units of the batch being retired. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| tradable_units | [string](#string) | | tradable_units is the decimal number of tradable units. | -| retired_units | [string](#string) | | retired_units is the decimal number of retired units. | - - +| batch_denom | [string](#string) | | batch_denom is the unique ID of the credit batch. | +| units | [string](#string) | | retired_units are the units of credits being retired. Decimal values are acceptable within the precision returned by Query/Precision. | - -### QueryBatchInfoRequest -QueryBatchInfoRequest is the Query/BatchInfo request type. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch to query. | +### MsgRetireResponse +MsgRetireRequest is the Msg/Retire response type. - + -### QueryBatchInfoResponse -QueryBatchInfoResponse is the Query/BatchInfo response type. +### MsgSendRequest +MsgSendRequest is the Msg/Send request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| info | [BatchInfo](#regen.ecocredit.v1alpha1.BatchInfo) | | info is the BatchInfo for the credit batch. | +| sender | [string](#string) | | sender is the address of the account sending credits. | +| recipient | [string](#string) | | sender is the address of the account receiving credits. | +| credits | [MsgSendRequest.SendUnits](#regen.ecocredit.v1alpha1.MsgSendRequest.SendUnits) | repeated | credits are the credits being sent. | - + -### QueryClassInfoRequest -QueryClassInfoRequest is the Query/ClassInfo request type. +### MsgSendRequest.SendUnits +SendUnits are the tradable and retired units of a credit batch to send. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| class_id | [string](#string) | | class_id is the unique ID of credit class to query. | - - +| batch_denom | [string](#string) | | batch_denom is the unique ID of the credit batch. | +| tradable_units | [string](#string) | | tradable_units are the units of credits in this issuance that can be traded by this recipient. Decimal values are acceptable within the precision returned by Query/Precision. | +| retired_units | [string](#string) | | retired_units are the units of credits in this issuance that are effectively retired by the issuer on receipt. Decimal values are acceptable within the precision returned by Query/Precision. | - -### QueryClassInfoResponse -QueryClassInfoResponse is the Query/ClassInfo request type. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| info | [ClassInfo](#regen.ecocredit.v1alpha1.ClassInfo) | | info is the ClassInfo for the credit class. | +### MsgSendResponse +MsgSendResponse is the Msg/Send response type. - + -### QueryPrecisionRequest -QueryPrecisionRequest is the Query/Precision request type. +### MsgSetPrecisionRequest +MsgRetireRequest is the Msg/SetPrecision request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch to query. | - - +| issuer | [string](#string) | | issuer is the address of the batch issuer. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of the credit batch. | +| max_decimal_places | [uint32](#uint32) | | max_decimal_places is the new maximum number of decimal places that can be used to represent some quantity of credit units. It is an experimental feature to concretely explore an idea proposed in https://github.com/cosmos/cosmos-sdk/issues/7113. | - -### QueryPrecisionResponse -QueryPrecisionResponse is the Query/Precision response type. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| max_decimal_places | [uint32](#uint32) | | max_decimal_places is the maximum number of decimal places that can be used to represent some quantity of credit units. It is an experimental feature to concretely explore an idea proposed in https://github.com/cosmos/cosmos-sdk/issues/7113. | +### MsgSetPrecisionResponse +MsgRetireRequest is the Msg/SetPrecision response type. + - + -### QuerySupplyRequest -QuerySupplyRequest is the Query/Supply request type. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch to query. | + +### Msg +Msg is the regen.ecocredit.v1alpha1 Msg service. +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +| CreateClass | [MsgCreateClassRequest](#regen.ecocredit.v1alpha1.MsgCreateClassRequest) | [MsgCreateClassResponse](#regen.ecocredit.v1alpha1.MsgCreateClassResponse) | CreateClass creates a new credit class with an approved list of issuers and optional metadata. | +| CreateBatch | [MsgCreateBatchRequest](#regen.ecocredit.v1alpha1.MsgCreateBatchRequest) | [MsgCreateBatchResponse](#regen.ecocredit.v1alpha1.MsgCreateBatchResponse) | CreateBatch creates a new batch of credits for an existing credit class. This will create a new batch denom with a fixed supply. Issued credits can be distributed to recipients in either tradable or retired form. | +| Send | [MsgSendRequest](#regen.ecocredit.v1alpha1.MsgSendRequest) | [MsgSendResponse](#regen.ecocredit.v1alpha1.MsgSendResponse) | Send sends tradeable credits from one account to another account. Sent credits can either be tradable or retired on receipt. | +| Retire | [MsgRetireRequest](#regen.ecocredit.v1alpha1.MsgRetireRequest) | [MsgRetireResponse](#regen.ecocredit.v1alpha1.MsgRetireResponse) | Retire retires a specified number of credits in the holder's account. | +| SetPrecision | [MsgSetPrecisionRequest](#regen.ecocredit.v1alpha1.MsgSetPrecisionRequest) | [MsgSetPrecisionResponse](#regen.ecocredit.v1alpha1.MsgSetPrecisionResponse) | SetPrecision allows an issuer to increase the decimal precision of a credit batch. It is an experimental feature to concretely explore an idea proposed in https://github.com/cosmos/cosmos-sdk/issues/7113. The number of decimal places allowed for a credit batch is determined by the original number of decimal places used with calling CreatBatch. SetPrecision allows the number of allowed decimal places to be increased, effectively making the supply more granular without actually changing any balances. It allows asset issuers to be able to issue an asset without needing to think about how many subdivisions are needed upfront. While it may not be relevant for credits which likely have a fairly stable market value, I wanted to experiment a bit and this serves as a proof of concept for a broader bank redesign where say for instance a coin like the ATOM or XRN could be issued in its own units rather than micro or nano-units. Instead an operation like SetPrecision would allow trading in micro, nano or pico in the future based on market demand. Arbitrary, unbounded precision is not desirable because this can lead to spam attacks (like sending 0.000000000000000000000000000001 coins). This is effectively fixed precision so under the hood it is still basically an integer, but the fixed precision can be increased so its more adaptable long term than just an integer. | + - + + -### QuerySupplyResponse -QuerySupplyResponse is the Query/Supply response type. +## regen/ecocredit/v1alpha1/events.proto -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| tradable_supply | [string](#string) | | tradable_units is the decimal number of tradable units in the batch supply. | -| retired_supply | [string](#string) | | retired_supply is the decimal number of retired units in the batch supply. | + +### EventCreateBatch +EventCreateBatch is an event emitted when a credit batch is created. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| class_id | [string](#string) | | class_id is the unique ID of credit class. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | +| issuer | [string](#string) | | issuer is the account address of the issuer of the credit batch. | +| total_units | [string](#string) | | total_units is the total number of units in the credit batch. | - - - - -### Query -Msg is the regen.ecocredit.v1alpha1 Query service. + -| Method Name | Request Type | Response Type | Description | -| ----------- | ------------ | ------------- | ------------| -| ClassInfo | [QueryClassInfoRequest](#regen.ecocredit.v1alpha1.QueryClassInfoRequest) | [QueryClassInfoResponse](#regen.ecocredit.v1alpha1.QueryClassInfoResponse) | ClassInfo queries for information on a credit class. | -| BatchInfo | [QueryBatchInfoRequest](#regen.ecocredit.v1alpha1.QueryBatchInfoRequest) | [QueryBatchInfoResponse](#regen.ecocredit.v1alpha1.QueryBatchInfoResponse) | BatchInfo queries for information on a credit batch. | -| Balance | [QueryBalanceRequest](#regen.ecocredit.v1alpha1.QueryBalanceRequest) | [QueryBalanceResponse](#regen.ecocredit.v1alpha1.QueryBalanceResponse) | Balance queries the balance (both tradable and retired) of a given credit batch for a given account. | -| Supply | [QuerySupplyRequest](#regen.ecocredit.v1alpha1.QuerySupplyRequest) | [QuerySupplyResponse](#regen.ecocredit.v1alpha1.QuerySupplyResponse) | Supply queries the tradable and retired supply of a credit batch. | -| Precision | [QueryPrecisionRequest](#regen.ecocredit.v1alpha1.QueryPrecisionRequest) | [QueryPrecisionResponse](#regen.ecocredit.v1alpha1.QueryPrecisionResponse) | Precision queries the number of decimal places that can be used to represent credit batch units. See Tx/SetPrecision for more details. | +### EventCreateClass +EventCreateClass is an event emitted when a credit class is created. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| class_id | [string](#string) | | class_id is the unique ID of credit class. | +| designer | [string](#string) | | designer is the designer of the credit class. | - - -## regen/ecocredit/v1alpha1/tx.proto - + -### MsgCreateBatchRequest -MsgCreateBatchRequest is the Msg/CreateBatch request type. +### EventReceive +EventReceive is an event emitted when credits are received either upon +creation of a new batch or upon transfer. Each batch_denom created or +transferred will result in a separate EventReceive for easy indexing. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| issuer | [string](#string) | | issuer is the address of the batch issuer. | -| class_id | [string](#string) | | class_id is the unique ID of the class. | -| issuance | [MsgCreateBatchRequest.BatchIssuance](#regen.ecocredit.v1alpha1.MsgCreateBatchRequest.BatchIssuance) | repeated | issuance are the credits issued in the batch. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit batch. | +| sender | [string](#string) | | sender is the sender of the credits in the case that this event is the result of a transfer. It will not be set when credits are received at initial issuance. | +| recipient | [string](#string) | | recipient is the recipient of the credits | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | +| units | [string](#string) | | units is the decimal number of both tradable and retired credits received. | - + -### MsgCreateBatchRequest.BatchIssuance -BatchIssuance represents the issuance of some credits in a batch to a -single recipient. +### EventRetire +EventRetire is an event emitted when credits are retired. An separate event +is emitted for each batch_denom in the case where credits from multiple +batches have been retired at once for easy indexing. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| recipient | [string](#string) | | recipient is the account of the recipient. | -| tradable_units | [string](#string) | | tradable_units are the units of credits in this issuance that can be traded by this recipient. Decimal values are acceptable. | -| retired_units | [string](#string) | | retired_units are the units of credits in this issuance that are effectively retired by the issuer on receipt. Decimal values are acceptable. | +| retirer | [string](#string) | | retirer is the account which has done the "retiring". This will be the account receiving credits in the case that credits were retired upon issuance using Msg/CreateBatch or retired upon transfer using Msg/Send. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch. | +| units | [string](#string) | | units is the decimal number of credits that have been retired. | + - + -### MsgCreateBatchResponse -MsgCreateBatchResponse is the Msg/CreateBatch response type. + + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| batch_denom | [string](#string) | | batch_denom is the unique denomination ID of the newly created batch. | + + +## regen/ecocredit/v1alpha1/query.proto - + -### MsgCreateClassRequest -MsgCreateClassRequest is the Msg/CreateClass request type. +### QueryBalanceRequest +QueryBalanceRequest is the Query/Balance request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| designer | [string](#string) | | designer is the address of the account which designed the credit class. The designer has special permissions to change the list of issuers and perform other administrative operations. | -| issuers | [string](#string) | repeated | issuers are the account addresses of the approved issuers. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the credit class. | +| account | [string](#string) | | account is the address of the account whose balance is being queried. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch balance to query. | - + -### MsgCreateClassResponse -MsgCreateClassResponse is the Msg/CreateClass response type. +### QueryBalanceResponse +QueryBalanceResponse is the Query/Balance response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| class_id | [string](#string) | | class_id is the unique ID of the newly created credit class. | +| tradable_units | [string](#string) | | tradable_units is the decimal number of tradable units. | +| retired_units | [string](#string) | | retired_units is the decimal number of retired units. | - + -### MsgRetireRequest -MsgRetireRequest is the Msg/Retire request type. +### QueryBatchInfoRequest +QueryBatchInfoRequest is the Query/BatchInfo request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| holder | [string](#string) | | holder is the credit holder address. | -| credits | [MsgRetireRequest.RetireUnits](#regen.ecocredit.v1alpha1.MsgRetireRequest.RetireUnits) | repeated | credits are the credits being retired. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch to query. | - + -### MsgRetireRequest.RetireUnits -RetireUnits are the units of the batch being retired. +### QueryBatchInfoResponse +QueryBatchInfoResponse is the Query/BatchInfo response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| batch_denom | [string](#string) | | batch_denom is the unique ID of the credit batch. | -| units | [string](#string) | | retired_units are the units of credits being retired. Decimal values are acceptable within the precision returned by Query/Precision. | +| info | [BatchInfo](#regen.ecocredit.v1alpha1.BatchInfo) | | info is the BatchInfo for the credit batch. | - + -### MsgRetireResponse -MsgRetireRequest is the Msg/Retire response type. +### QueryClassInfoRequest +QueryClassInfoRequest is the Query/ClassInfo request type. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| class_id | [string](#string) | | class_id is the unique ID of credit class to query. | - + -### MsgSendRequest -MsgSendRequest is the Msg/Send request type. +### QueryClassInfoResponse +QueryClassInfoResponse is the Query/ClassInfo request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| sender | [string](#string) | | sender is the address of the account sending credits. | -| recipient | [string](#string) | | sender is the address of the account receiving credits. | -| credits | [MsgSendRequest.SendUnits](#regen.ecocredit.v1alpha1.MsgSendRequest.SendUnits) | repeated | credits are the credits being sent. | +| info | [ClassInfo](#regen.ecocredit.v1alpha1.ClassInfo) | | info is the ClassInfo for the credit class. | - + -### MsgSendRequest.SendUnits -SendUnits are the tradable and retired units of a credit batch to send. +### QueryPrecisionRequest +QueryPrecisionRequest is the Query/Precision request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| batch_denom | [string](#string) | | batch_denom is the unique ID of the credit batch. | -| tradable_units | [string](#string) | | tradable_units are the units of credits in this issuance that can be traded by this recipient. Decimal values are acceptable within the precision returned by Query/Precision. | -| retired_units | [string](#string) | | retired_units are the units of credits in this issuance that are effectively retired by the issuer on receipt. Decimal values are acceptable within the precision returned by Query/Precision. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch to query. | - + -### MsgSendResponse -MsgSendResponse is the Msg/Send response type. +### QueryPrecisionResponse +QueryPrecisionResponse is the Query/Precision response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| max_decimal_places | [uint32](#uint32) | | max_decimal_places is the maximum number of decimal places that can be used to represent some quantity of credit units. It is an experimental feature to concretely explore an idea proposed in https://github.com/cosmos/cosmos-sdk/issues/7113. | - -### MsgSetPrecisionRequest -MsgRetireRequest is the Msg/SetPrecision request type. + + + +### QuerySupplyRequest +QuerySupplyRequest is the Query/Supply request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| issuer | [string](#string) | | issuer is the address of the batch issuer. | -| batch_denom | [string](#string) | | batch_denom is the unique ID of the credit batch. | -| max_decimal_places | [uint32](#uint32) | | max_decimal_places is the new maximum number of decimal places that can be used to represent some quantity of credit units. It is an experimental feature to concretely explore an idea proposed in https://github.com/cosmos/cosmos-sdk/issues/7113. | +| batch_denom | [string](#string) | | batch_denom is the unique ID of credit batch to query. | - + + +### QuerySupplyResponse +QuerySupplyResponse is the Query/Supply response type. -### MsgSetPrecisionResponse -MsgRetireRequest is the Msg/SetPrecision response type. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| tradable_supply | [string](#string) | | tradable_units is the decimal number of tradable units in the batch supply. | +| retired_supply | [string](#string) | | retired_supply is the decimal number of retired units in the batch supply. | @@ -583,18 +583,18 @@ MsgRetireRequest is the Msg/SetPrecision response type. - + -### Msg -Msg is the regen.ecocredit.v1alpha1 Msg service. +### Query +Msg is the regen.ecocredit.v1alpha1 Query service. | Method Name | Request Type | Response Type | Description | | ----------- | ------------ | ------------- | ------------| -| CreateClass | [MsgCreateClassRequest](#regen.ecocredit.v1alpha1.MsgCreateClassRequest) | [MsgCreateClassResponse](#regen.ecocredit.v1alpha1.MsgCreateClassResponse) | CreateClass creates a new credit class with an approved list of issuers and optional metadata. | -| CreateBatch | [MsgCreateBatchRequest](#regen.ecocredit.v1alpha1.MsgCreateBatchRequest) | [MsgCreateBatchResponse](#regen.ecocredit.v1alpha1.MsgCreateBatchResponse) | CreateBatch creates a new batch of credits for an existing credit class. This will create a new batch denom with a fixed supply. Issued credits can be distributed to recipients in either tradable or retired form. | -| Send | [MsgSendRequest](#regen.ecocredit.v1alpha1.MsgSendRequest) | [MsgSendResponse](#regen.ecocredit.v1alpha1.MsgSendResponse) | Send sends tradeable credits from one account to another account. Sent credits can either be tradable or retired on receipt. | -| Retire | [MsgRetireRequest](#regen.ecocredit.v1alpha1.MsgRetireRequest) | [MsgRetireResponse](#regen.ecocredit.v1alpha1.MsgRetireResponse) | Retire retires a specified number of credits in the holder's account. | -| SetPrecision | [MsgSetPrecisionRequest](#regen.ecocredit.v1alpha1.MsgSetPrecisionRequest) | [MsgSetPrecisionResponse](#regen.ecocredit.v1alpha1.MsgSetPrecisionResponse) | SetPrecision allows an issuer to increase the decimal precision of a credit batch. It is an experimental feature to concretely explore an idea proposed in https://github.com/cosmos/cosmos-sdk/issues/7113. The number of decimal places allowed for a credit batch is determined by the original number of decimal places used with calling CreatBatch. SetPrecision allows the number of allowed decimal places to be increased, effectively making the supply more granular without actually changing any balances. It allows asset issuers to be able to issue an asset without needing to think about how many subdivisions are needed upfront. While it may not be relevant for credits which likely have a fairly stable market value, I wanted to experiment a bit and this serves as a proof of concept for a broader bank redesign where say for instance a coin like the ATOM or XRN could be issued in its own units rather than micro or nano-units. Instead an operation like SetPrecision would allow trading in micro, nano or pico in the future based on market demand. Arbitrary, unbounded precision is not desirable because this can lead to spam attacks (like sending 0.000000000000000000000000000001 coins). This is effectively fixed precision so under the hood it is still basically an integer, but the fixed precision can be increased so its more adaptable long term than just an integer. | +| ClassInfo | [QueryClassInfoRequest](#regen.ecocredit.v1alpha1.QueryClassInfoRequest) | [QueryClassInfoResponse](#regen.ecocredit.v1alpha1.QueryClassInfoResponse) | ClassInfo queries for information on a credit class. | +| BatchInfo | [QueryBatchInfoRequest](#regen.ecocredit.v1alpha1.QueryBatchInfoRequest) | [QueryBatchInfoResponse](#regen.ecocredit.v1alpha1.QueryBatchInfoResponse) | BatchInfo queries for information on a credit batch. | +| Balance | [QueryBalanceRequest](#regen.ecocredit.v1alpha1.QueryBalanceRequest) | [QueryBalanceResponse](#regen.ecocredit.v1alpha1.QueryBalanceResponse) | Balance queries the balance (both tradable and retired) of a given credit batch for a given account. | +| Supply | [QuerySupplyRequest](#regen.ecocredit.v1alpha1.QuerySupplyRequest) | [QuerySupplyResponse](#regen.ecocredit.v1alpha1.QuerySupplyResponse) | Supply queries the tradable and retired supply of a credit batch. | +| Precision | [QueryPrecisionRequest](#regen.ecocredit.v1alpha1.QueryPrecisionRequest) | [QueryPrecisionResponse](#regen.ecocredit.v1alpha1.QueryPrecisionResponse) | Precision queries the number of decimal places that can be used to represent credit batch units. See Tx/SetPrecision for more details. | diff --git a/docs/modules/group/protobuf.md b/docs/modules/group/protobuf.md index 134a37da49..4603db7c8f 100644 --- a/docs/modules/group/protobuf.md +++ b/docs/modules/group/protobuf.md @@ -4,15 +4,6 @@ ## Table of Contents -- [regen/group/v1alpha1/events.proto](#regen/group/v1alpha1/events.proto) - - [EventCreateGroup](#regen.group.v1alpha1.EventCreateGroup) - - [EventCreateGroupAccount](#regen.group.v1alpha1.EventCreateGroupAccount) - - [EventCreateProposal](#regen.group.v1alpha1.EventCreateProposal) - - [EventExec](#regen.group.v1alpha1.EventExec) - - [EventUpdateGroup](#regen.group.v1alpha1.EventUpdateGroup) - - [EventUpdateGroupAccount](#regen.group.v1alpha1.EventUpdateGroupAccount) - - [EventVote](#regen.group.v1alpha1.EventVote) - - [regen/group/v1alpha1/types.proto](#regen/group/v1alpha1/types.proto) - [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) - [GroupInfo](#regen.group.v1alpha1.GroupInfo) @@ -29,8 +20,40 @@ - [Proposal.Result](#regen.group.v1alpha1.Proposal.Result) - [Proposal.Status](#regen.group.v1alpha1.Proposal.Status) -- [regen/group/v1alpha1/genesis.proto](#regen/group/v1alpha1/genesis.proto) - - [GenesisState](#regen.group.v1alpha1.GenesisState) +- [regen/group/v1alpha1/tx.proto](#regen/group/v1alpha1/tx.proto) + - [MsgCreateGroupAccountRequest](#regen.group.v1alpha1.MsgCreateGroupAccountRequest) + - [MsgCreateGroupAccountResponse](#regen.group.v1alpha1.MsgCreateGroupAccountResponse) + - [MsgCreateGroupRequest](#regen.group.v1alpha1.MsgCreateGroupRequest) + - [MsgCreateGroupResponse](#regen.group.v1alpha1.MsgCreateGroupResponse) + - [MsgCreateProposalRequest](#regen.group.v1alpha1.MsgCreateProposalRequest) + - [MsgCreateProposalResponse](#regen.group.v1alpha1.MsgCreateProposalResponse) + - [MsgExecRequest](#regen.group.v1alpha1.MsgExecRequest) + - [MsgExecResponse](#regen.group.v1alpha1.MsgExecResponse) + - [MsgUpdateGroupAccountAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminRequest) + - [MsgUpdateGroupAccountAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminResponse) + - [MsgUpdateGroupAccountDecisionPolicyRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyRequest) + - [MsgUpdateGroupAccountDecisionPolicyResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyResponse) + - [MsgUpdateGroupAccountMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataRequest) + - [MsgUpdateGroupAccountMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataResponse) + - [MsgUpdateGroupAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAdminRequest) + - [MsgUpdateGroupAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAdminResponse) + - [MsgUpdateGroupMembersRequest](#regen.group.v1alpha1.MsgUpdateGroupMembersRequest) + - [MsgUpdateGroupMembersResponse](#regen.group.v1alpha1.MsgUpdateGroupMembersResponse) + - [MsgUpdateGroupMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupMetadataRequest) + - [MsgUpdateGroupMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupMetadataResponse) + - [MsgVoteRequest](#regen.group.v1alpha1.MsgVoteRequest) + - [MsgVoteResponse](#regen.group.v1alpha1.MsgVoteResponse) + + - [Msg](#regen.group.v1alpha1.Msg) + +- [regen/group/v1alpha1/events.proto](#regen/group/v1alpha1/events.proto) + - [EventCreateGroup](#regen.group.v1alpha1.EventCreateGroup) + - [EventCreateGroupAccount](#regen.group.v1alpha1.EventCreateGroupAccount) + - [EventCreateProposal](#regen.group.v1alpha1.EventCreateProposal) + - [EventExec](#regen.group.v1alpha1.EventExec) + - [EventUpdateGroup](#regen.group.v1alpha1.EventUpdateGroup) + - [EventUpdateGroupAccount](#regen.group.v1alpha1.EventUpdateGroupAccount) + - [EventVote](#regen.group.v1alpha1.EventVote) - [regen/group/v1alpha1/query.proto](#regen/group/v1alpha1/query.proto) - [QueryGroupAccountInfoRequest](#regen.group.v1alpha1.QueryGroupAccountInfoRequest) @@ -58,157 +81,13 @@ - [Query](#regen.group.v1alpha1.Query) -- [regen/group/v1alpha1/tx.proto](#regen/group/v1alpha1/tx.proto) - - [MsgCreateGroupAccountRequest](#regen.group.v1alpha1.MsgCreateGroupAccountRequest) - - [MsgCreateGroupAccountResponse](#regen.group.v1alpha1.MsgCreateGroupAccountResponse) - - [MsgCreateGroupRequest](#regen.group.v1alpha1.MsgCreateGroupRequest) - - [MsgCreateGroupResponse](#regen.group.v1alpha1.MsgCreateGroupResponse) - - [MsgCreateProposalRequest](#regen.group.v1alpha1.MsgCreateProposalRequest) - - [MsgCreateProposalResponse](#regen.group.v1alpha1.MsgCreateProposalResponse) - - [MsgExecRequest](#regen.group.v1alpha1.MsgExecRequest) - - [MsgExecResponse](#regen.group.v1alpha1.MsgExecResponse) - - [MsgUpdateGroupAccountAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminRequest) - - [MsgUpdateGroupAccountAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminResponse) - - [MsgUpdateGroupAccountDecisionPolicyRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyRequest) - - [MsgUpdateGroupAccountDecisionPolicyResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyResponse) - - [MsgUpdateGroupAccountMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataRequest) - - [MsgUpdateGroupAccountMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataResponse) - - [MsgUpdateGroupAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAdminRequest) - - [MsgUpdateGroupAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAdminResponse) - - [MsgUpdateGroupMembersRequest](#regen.group.v1alpha1.MsgUpdateGroupMembersRequest) - - [MsgUpdateGroupMembersResponse](#regen.group.v1alpha1.MsgUpdateGroupMembersResponse) - - [MsgUpdateGroupMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupMetadataRequest) - - [MsgUpdateGroupMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupMetadataResponse) - - [MsgVoteRequest](#regen.group.v1alpha1.MsgVoteRequest) - - [MsgVoteResponse](#regen.group.v1alpha1.MsgVoteResponse) - - - [Msg](#regen.group.v1alpha1.Msg) +- [regen/group/v1alpha1/genesis.proto](#regen/group/v1alpha1/genesis.proto) + - [GenesisState](#regen.group.v1alpha1.GenesisState) - [Scalar Value Types](#scalar-value-types) - - - -## regen/group/v1alpha1/events.proto - - - - - -### EventCreateGroup -EventCreateGroup is an event emitted when a group is created. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | - - - - - - - - -### EventCreateGroupAccount -EventCreateGroupAccount is an event emitted when a group account is created. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| address | [string](#string) | | address is the address of the group account. | - - - - - - - - -### EventCreateProposal -EventCreateProposal is an event emitted when a proposal is created. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of the proposal. | - - - - - - - - -### EventExec -EventExec is an event emitted when a proposal is executed. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of the proposal. | - - - - - - - - -### EventUpdateGroup -EventUpdateGroup is an event emitted when a group is updated. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | - - - - - - - - -### EventUpdateGroupAccount -EventUpdateGroupAccount is an event emitted when a group account is updated. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| address | [string](#string) | | address is the address of the group account. | - - - - - - - - -### EventVote -EventVote is an event emitted when a voter votes on a proposal. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of the proposal. | - - - - - - - - - - - - - - - @@ -453,740 +332,881 @@ Status defines proposal statuses. - + -## regen/group/v1alpha1/genesis.proto +## regen/group/v1alpha1/tx.proto - + -### GenesisState -GenesisState defines the group module's genesis state. +### MsgCreateGroupAccountRequest +MsgCreateGroupAccountRequest is the Msg/CreateGroupAccount request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| group_seq | [uint64](#uint64) | | group_seq is the group table orm.Sequence, it is used to get the next group ID. | -| groups | [GroupInfo](#regen.group.v1alpha1.GroupInfo) | repeated | groups is the list of groups info. | -| group_members | [GroupMember](#regen.group.v1alpha1.GroupMember) | repeated | group_members is the list of groups members. | -| group_account_seq | [uint64](#uint64) | | group_account_seq is the group account table orm.Sequence, it is used to generate the next group account address. | -| group_accounts | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | repeated | group_accounts is the list of group accounts info. | -| proposal_seq | [uint64](#uint64) | | proposal_seq is the proposal table orm.Sequence, it is used to get the next proposal ID. | -| proposals | [Proposal](#regen.group.v1alpha1.Proposal) | repeated | proposals is the list of proposals. | -| votes | [Vote](#regen.group.v1alpha1.Vote) | repeated | votes is the list of votes. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the group account. | +| decision_policy | [google.protobuf.Any](#google.protobuf.Any) | | decision_policy specifies the group account's decision policy. | - - + - +### MsgCreateGroupAccountResponse +MsgCreateGroupAccountResponse is the Msg/CreateGroupAccount response type. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| address | [string](#string) | | address is the account address of the newly created group account. | - - -## regen/group/v1alpha1/query.proto - + -### QueryGroupAccountInfoRequest -QueryGroupAccountInfoRequest is the Query/GroupAccountInfo request type. +### MsgCreateGroupRequest +MsgCreateGroupRequest is the Msg/CreateGroup request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| address | [string](#string) | | address is the account address of the group account. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| members | [Member](#regen.group.v1alpha1.Member) | repeated | members defines the group members. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the group. | - + -### QueryGroupAccountInfoResponse -QueryGroupAccountInfoResponse is the Query/GroupAccountInfo response type. +### MsgCreateGroupResponse +MsgCreateGroupResponse is the Msg/CreateGroup response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| info | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | | info is the GroupAccountInfo for the group account. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the newly created group. | - + -### QueryGroupAccountsByAdminRequest -QueryGroupAccountsByAdminRequest is the Query/GroupAccountsByAdmin request type. +### MsgCreateProposalRequest +MsgCreateProposalRequest is the Msg/CreateProposal request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the admin address of the group account. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - - +| address | [string](#string) | | address is the group account address. | +| proposers | [string](#string) | repeated | proposers are the account addresses of the proposers. Proposers signatures will be counted as yes votes. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the proposal. | +| msgs | [google.protobuf.Any](#google.protobuf.Any) | repeated | msgs is a list of Msgs that will be executed if the proposal passes. | - -### QueryGroupAccountsByAdminResponse -QueryGroupAccountsByAdminResponse is the Query/GroupAccountsByAdmin response type. + + + +### MsgCreateProposalResponse +MsgCreateProposalResponse is the Msg/CreateProposal response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| group_accounts | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | repeated | group_accounts are the group accounts info with provided admin. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| proposal_id | [uint64](#uint64) | | proposal is the unique ID of the proposal. | - + -### QueryGroupAccountsByGroupRequest -QueryGroupAccountsByGroupRequest is the Query/GroupAccountsByGroup request type. +### MsgExecRequest +MsgExecRequest is the Msg/Exec request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group account's group. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| proposal_id | [uint64](#uint64) | | proposal is the unique ID of the proposal. | +| signer | [string](#string) | | signer is the account address used to execute the proposal. | - + + +### MsgExecResponse +MsgExecResponse is the Msg/Exec request type. + + -### QueryGroupAccountsByGroupResponse -QueryGroupAccountsByGroupResponse is the Query/GroupAccountsByGroup response type. + + + + + +### MsgUpdateGroupAccountAdminRequest +MsgUpdateGroupAccountAdminRequest is the Msg/UpdateGroupAccountAdmin request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| group_accounts | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | repeated | group_accounts are the group accounts info associated with the provided group. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| address | [string](#string) | | address is the group account address. | +| new_admin | [string](#string) | | new_admin is the new group account admin. | - + + +### MsgUpdateGroupAccountAdminResponse +MsgUpdateGroupAccountAdminResponse is the Msg/UpdateGroupAccountAdmin response type. + -### QueryGroupInfoRequest -QueryGroupInfoRequest is the Query/GroupInfo request type. + + + + + + +### MsgUpdateGroupAccountDecisionPolicyRequest +MsgUpdateGroupAccountDecisionPolicyRequest is the Msg/UpdateGroupAccountDecisionPolicy request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| address | [string](#string) | | address is the group account address. | +| decision_policy | [google.protobuf.Any](#google.protobuf.Any) | | decision_policy is the updated group account decision policy. | - + -### QueryGroupInfoResponse -QueryGroupInfoResponse is the Query/GroupInfo response type. +### MsgUpdateGroupAccountDecisionPolicyResponse +MsgUpdateGroupAccountDecisionPolicyResponse is the Msg/UpdateGroupAccountDecisionPolicy response type. + + + + + + + + +### MsgUpdateGroupAccountMetadataRequest +MsgUpdateGroupAccountMetadataRequest is the Msg/UpdateGroupAccountMetadata request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| info | [GroupInfo](#regen.group.v1alpha1.GroupInfo) | | info is the GroupInfo for the group. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| address | [string](#string) | | address is the group account address. | +| metadata | [bytes](#bytes) | | metadata is the updated group account metadata. | - + -### QueryGroupMembersRequest -QueryGroupMembersRequest is the Query/GroupMembersRequest request type. +### MsgUpdateGroupAccountMetadataResponse +MsgUpdateGroupAccountMetadataResponse is the Msg/UpdateGroupAccountMetadata response type. + + + + + + + + +### MsgUpdateGroupAdminRequest +MsgUpdateGroupAdminRequest is the Msg/UpdateGroupAdmin request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | +| admin | [string](#string) | | admin is the current account address of the group admin. | | group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| new_admin | [string](#string) | | new_admin is the group new admin account address. | - + + +### MsgUpdateGroupAdminResponse +MsgUpdateGroupAdminResponse is the Msg/UpdateGroupAdmin response type. + -### QueryGroupMembersResponse -QueryGroupMembersResponse is the Query/GroupMembersResponse response type. + + + + + + +### MsgUpdateGroupMembersRequest +MsgUpdateGroupMembersRequest is the Msg/UpdateGroupMembers request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| members | [GroupMember](#regen.group.v1alpha1.GroupMember) | repeated | members are the members of the group with given group_id. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | +| member_updates | [Member](#regen.group.v1alpha1.Member) | repeated | member_updates is the list of members to update, set weight to 0 to remove a member. | - + + +### MsgUpdateGroupMembersResponse +MsgUpdateGroupMembersResponse is the Msg/UpdateGroupMembers response type. + + -### QueryGroupsByAdminRequest -QueryGroupsByAdminRequest is the Query/GroupsByAdminRequest request type. + + + + + +### MsgUpdateGroupMetadataRequest +MsgUpdateGroupMetadataRequest is the Msg/UpdateGroupMetadata request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of a group's admin. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| admin | [string](#string) | | admin is the account address of the group admin. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | +| metadata | [bytes](#bytes) | | metadata is the updated group's metadata. | - + + +### MsgUpdateGroupMetadataResponse +MsgUpdateGroupMetadataResponse is the Msg/UpdateGroupMetadata response type. + + + -### QueryGroupsByAdminResponse -QueryGroupsByAdminResponse is the Query/GroupsByAdminResponse response type. + + + + +### MsgVoteRequest +MsgVoteRequest is the Msg/Vote request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| groups | [GroupInfo](#regen.group.v1alpha1.GroupInfo) | repeated | groups are the groups info with the provided admin. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| proposal_id | [uint64](#uint64) | | proposal is the unique ID of the proposal. | +| voter | [string](#string) | | voter is the voter account address. | +| choice | [Choice](#regen.group.v1alpha1.Choice) | | choice is the voter's choice on the proposal. | +| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the vote. | - + + +### MsgVoteResponse +MsgVoteResponse is the Msg/Vote response type. -### QueryProposalRequest -QueryProposalRequest is the Query/Proposal request type. -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of a proposal. | + + + - + -### QueryProposalResponse -QueryProposalResponse is the Query/Proposal response type. +### Msg +Msg is the regen.group.v1alpha1 Msg service. +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +| CreateGroup | [MsgCreateGroupRequest](#regen.group.v1alpha1.MsgCreateGroupRequest) | [MsgCreateGroupResponse](#regen.group.v1alpha1.MsgCreateGroupResponse) | CreateGroup creates a new group with an admin account address, a list of members and some optional metadata. | +| UpdateGroupMembers | [MsgUpdateGroupMembersRequest](#regen.group.v1alpha1.MsgUpdateGroupMembersRequest) | [MsgUpdateGroupMembersResponse](#regen.group.v1alpha1.MsgUpdateGroupMembersResponse) | UpdateGroupMembers updates the group members with given group id and admin address. | +| UpdateGroupAdmin | [MsgUpdateGroupAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAdminRequest) | [MsgUpdateGroupAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAdminResponse) | UpdateGroupAdmin updates the group admin with given group id and previous admin address. | +| UpdateGroupMetadata | [MsgUpdateGroupMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupMetadataRequest) | [MsgUpdateGroupMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupMetadataResponse) | UpdateGroupMetadata updates the group metadata with given group id and admin address. | +| CreateGroupAccount | [MsgCreateGroupAccountRequest](#regen.group.v1alpha1.MsgCreateGroupAccountRequest) | [MsgCreateGroupAccountResponse](#regen.group.v1alpha1.MsgCreateGroupAccountResponse) | CreateGroupAccount creates a new group account using given DecisionPolicy. | +| UpdateGroupAccountAdmin | [MsgUpdateGroupAccountAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminRequest) | [MsgUpdateGroupAccountAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminResponse) | UpdateGroupAccountAdmin updates a group account admin. | +| UpdateGroupAccountDecisionPolicy | [MsgUpdateGroupAccountDecisionPolicyRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyRequest) | [MsgUpdateGroupAccountDecisionPolicyResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyResponse) | UpdateGroupAccountDecisionPolicy allows a group account decision policy to be updated. | +| UpdateGroupAccountMetadata | [MsgUpdateGroupAccountMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataRequest) | [MsgUpdateGroupAccountMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataResponse) | UpdateGroupAccountMetadata updates a group account metadata. | +| CreateProposal | [MsgCreateProposalRequest](#regen.group.v1alpha1.MsgCreateProposalRequest) | [MsgCreateProposalResponse](#regen.group.v1alpha1.MsgCreateProposalResponse) | CreateProposal submits a new proposal. | +| Vote | [MsgVoteRequest](#regen.group.v1alpha1.MsgVoteRequest) | [MsgVoteResponse](#regen.group.v1alpha1.MsgVoteResponse) | Vote allows a voter to vote on a proposal. | +| Exec | [MsgExecRequest](#regen.group.v1alpha1.MsgExecRequest) | [MsgExecResponse](#regen.group.v1alpha1.MsgExecResponse) | Exec executes a proposal. | -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| proposal | [Proposal](#regen.group.v1alpha1.Proposal) | | proposal is the proposal info. | + + + +## regen/group/v1alpha1/events.proto - -### QueryProposalsByGroupAccountRequest -QueryProposalsByGroupAccountRequest is the Query/ProposalByGroupAccount request type. + + +### EventCreateGroup +EventCreateGroup is an event emitted when a group is created. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| address | [string](#string) | | address is the group account address related to proposals. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | - + -### QueryProposalsByGroupAccountResponse -QueryProposalsByGroupAccountResponse is the Query/ProposalByGroupAccount response type. +### EventCreateGroupAccount +EventCreateGroupAccount is an event emitted when a group account is created. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| proposals | [Proposal](#regen.group.v1alpha1.Proposal) | repeated | proposals are the proposals with given group account. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| address | [string](#string) | | address is the address of the group account. | - + -### QueryVoteByProposalVoterRequest -QueryVoteByProposalVoterResponse is the Query/VoteByProposalVoter request type. +### EventCreateProposal +EventCreateProposal is an event emitted when a proposal is created. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of a proposal. | -| voter | [string](#string) | | voter is a proposal voter account address. | +| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of the proposal. | - + -### QueryVoteByProposalVoterResponse -QueryVoteByProposalVoterResponse is the Query/VoteByProposalVoter response type. +### EventExec +EventExec is an event emitted when a proposal is executed. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| vote | [Vote](#regen.group.v1alpha1.Vote) | | vote is the vote with given proposal_id and voter. | +| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of the proposal. | - + -### QueryVotesByProposalRequest -QueryVotesByProposalResponse is the Query/VotesByProposal request type. +### EventUpdateGroup +EventUpdateGroup is an event emitted when a group is updated. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of a proposal. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | - + -### QueryVotesByProposalResponse -QueryVotesByProposalResponse is the Query/VotesByProposal response type. +### EventUpdateGroupAccount +EventUpdateGroupAccount is an event emitted when a group account is updated. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| votes | [Vote](#regen.group.v1alpha1.Vote) | repeated | votes are the list of votes for given proposal_id. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| address | [string](#string) | | address is the address of the group account. | - + -### QueryVotesByVoterRequest -QueryVotesByVoterResponse is the Query/VotesByVoter request type. +### EventVote +EventVote is an event emitted when a voter votes on a proposal. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| voter | [string](#string) | | voter is a proposal voter account address. | -| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of the proposal. | + + + + + + + - -### QueryVotesByVoterResponse -QueryVotesByVoterResponse is the Query/VotesByVoter response type. + + + + +## regen/group/v1alpha1/query.proto + + + + + +### QueryGroupAccountInfoRequest +QueryGroupAccountInfoRequest is the Query/GroupAccountInfo request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| votes | [Vote](#regen.group.v1alpha1.Vote) | repeated | votes are the list of votes by given voter. | -| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| address | [string](#string) | | address is the account address of the group account. | - - + - +### QueryGroupAccountInfoResponse +QueryGroupAccountInfoResponse is the Query/GroupAccountInfo response type. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| info | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | | info is the GroupAccountInfo for the group account. | -### Query -Query is the regen.group.v1alpha1 Query service. -| Method Name | Request Type | Response Type | Description | -| ----------- | ------------ | ------------- | ------------| -| GroupInfo | [QueryGroupInfoRequest](#regen.group.v1alpha1.QueryGroupInfoRequest) | [QueryGroupInfoResponse](#regen.group.v1alpha1.QueryGroupInfoResponse) | GroupInfo queries group info based on group id. | -| GroupAccountInfo | [QueryGroupAccountInfoRequest](#regen.group.v1alpha1.QueryGroupAccountInfoRequest) | [QueryGroupAccountInfoResponse](#regen.group.v1alpha1.QueryGroupAccountInfoResponse) | GroupAccountInfo queries group account info based on group account address. | -| GroupMembers | [QueryGroupMembersRequest](#regen.group.v1alpha1.QueryGroupMembersRequest) | [QueryGroupMembersResponse](#regen.group.v1alpha1.QueryGroupMembersResponse) | GroupMembers queries members of a group | -| GroupsByAdmin | [QueryGroupsByAdminRequest](#regen.group.v1alpha1.QueryGroupsByAdminRequest) | [QueryGroupsByAdminResponse](#regen.group.v1alpha1.QueryGroupsByAdminResponse) | GroupsByAdmin queries groups by admin address. | -| GroupAccountsByGroup | [QueryGroupAccountsByGroupRequest](#regen.group.v1alpha1.QueryGroupAccountsByGroupRequest) | [QueryGroupAccountsByGroupResponse](#regen.group.v1alpha1.QueryGroupAccountsByGroupResponse) | GroupAccountsByGroup queries group accounts by group id. | -| GroupAccountsByAdmin | [QueryGroupAccountsByAdminRequest](#regen.group.v1alpha1.QueryGroupAccountsByAdminRequest) | [QueryGroupAccountsByAdminResponse](#regen.group.v1alpha1.QueryGroupAccountsByAdminResponse) | GroupsByAdmin queries group accounts by admin address. | -| Proposal | [QueryProposalRequest](#regen.group.v1alpha1.QueryProposalRequest) | [QueryProposalResponse](#regen.group.v1alpha1.QueryProposalResponse) | Proposal queries a proposal based on proposal id. | -| ProposalsByGroupAccount | [QueryProposalsByGroupAccountRequest](#regen.group.v1alpha1.QueryProposalsByGroupAccountRequest) | [QueryProposalsByGroupAccountResponse](#regen.group.v1alpha1.QueryProposalsByGroupAccountResponse) | ProposalsByGroupAccount queries proposals based on group account address. | -| VoteByProposalVoter | [QueryVoteByProposalVoterRequest](#regen.group.v1alpha1.QueryVoteByProposalVoterRequest) | [QueryVoteByProposalVoterResponse](#regen.group.v1alpha1.QueryVoteByProposalVoterResponse) | VoteByProposalVoter queries a vote by proposal id and voter. | -| VotesByProposal | [QueryVotesByProposalRequest](#regen.group.v1alpha1.QueryVotesByProposalRequest) | [QueryVotesByProposalResponse](#regen.group.v1alpha1.QueryVotesByProposalResponse) | VotesByProposal queries a vote by proposal. | -| VotesByVoter | [QueryVotesByVoterRequest](#regen.group.v1alpha1.QueryVotesByVoterRequest) | [QueryVotesByVoterResponse](#regen.group.v1alpha1.QueryVotesByVoterResponse) | VotesByVoter queries a vote by voter. | - - - + -## regen/group/v1alpha1/tx.proto +### QueryGroupAccountsByAdminRequest +QueryGroupAccountsByAdminRequest is the Query/GroupAccountsByAdmin request type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| admin | [string](#string) | | admin is the admin address of the group account. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | + - -### MsgCreateGroupAccountRequest -MsgCreateGroupAccountRequest is the Msg/CreateGroupAccount request type. + + + + + +### QueryGroupAccountsByAdminResponse +QueryGroupAccountsByAdminResponse is the Query/GroupAccountsByAdmin response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the group account. | -| decision_policy | [google.protobuf.Any](#google.protobuf.Any) | | decision_policy specifies the group account's decision policy. | +| group_accounts | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | repeated | group_accounts are the group accounts info with provided admin. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + -### MsgCreateGroupAccountResponse -MsgCreateGroupAccountResponse is the Msg/CreateGroupAccount response type. +### QueryGroupAccountsByGroupRequest +QueryGroupAccountsByGroupRequest is the Query/GroupAccountsByGroup request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| address | [string](#string) | | address is the account address of the newly created group account. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group account's group. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - + -### MsgCreateGroupRequest -MsgCreateGroupRequest is the Msg/CreateGroup request type. +### QueryGroupAccountsByGroupResponse +QueryGroupAccountsByGroupResponse is the Query/GroupAccountsByGroup response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| members | [Member](#regen.group.v1alpha1.Member) | repeated | members defines the group members. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the group. | +| group_accounts | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | repeated | group_accounts are the group accounts info associated with the provided group. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + -### MsgCreateGroupResponse -MsgCreateGroupResponse is the Msg/CreateGroup response type. +### QueryGroupInfoRequest +QueryGroupInfoRequest is the Query/GroupInfo request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the newly created group. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | - + -### MsgCreateProposalRequest -MsgCreateProposalRequest is the Msg/CreateProposal request type. +### QueryGroupInfoResponse +QueryGroupInfoResponse is the Query/GroupInfo response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| address | [string](#string) | | address is the group account address. | -| proposers | [string](#string) | repeated | proposers are the account addresses of the proposers. Proposers signatures will be counted as yes votes. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the proposal. | -| msgs | [google.protobuf.Any](#google.protobuf.Any) | repeated | msgs is a list of Msgs that will be executed if the proposal passes. | +| info | [GroupInfo](#regen.group.v1alpha1.GroupInfo) | | info is the GroupInfo for the group. | - + -### MsgCreateProposalResponse -MsgCreateProposalResponse is the Msg/CreateProposal response type. +### QueryGroupMembersRequest +QueryGroupMembersRequest is the Query/GroupMembersRequest request type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal is the unique ID of the proposal. | +| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - + -### MsgExecRequest -MsgExecRequest is the Msg/Exec request type. +### QueryGroupMembersResponse +QueryGroupMembersResponse is the Query/GroupMembersResponse response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal is the unique ID of the proposal. | -| signer | [string](#string) | | signer is the account address used to execute the proposal. | +| members | [GroupMember](#regen.group.v1alpha1.GroupMember) | repeated | members are the members of the group with given group_id. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + + +### QueryGroupsByAdminRequest +QueryGroupsByAdminRequest is the Query/GroupsByAdminRequest request type. -### MsgExecResponse -MsgExecResponse is the Msg/Exec request type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| admin | [string](#string) | | admin is the account address of a group's admin. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - -### MsgUpdateGroupAccountAdminRequest -MsgUpdateGroupAccountAdminRequest is the Msg/UpdateGroupAccountAdmin request type. + + +### QueryGroupsByAdminResponse +QueryGroupsByAdminResponse is the Query/GroupsByAdminResponse response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| address | [string](#string) | | address is the group account address. | -| new_admin | [string](#string) | | new_admin is the new group account admin. | +| groups | [GroupInfo](#regen.group.v1alpha1.GroupInfo) | repeated | groups are the groups info with the provided admin. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + -### MsgUpdateGroupAccountAdminResponse -MsgUpdateGroupAccountAdminResponse is the Msg/UpdateGroupAccountAdmin response type. +### QueryProposalRequest +QueryProposalRequest is the Query/Proposal request type. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of a proposal. | - + -### MsgUpdateGroupAccountDecisionPolicyRequest -MsgUpdateGroupAccountDecisionPolicyRequest is the Msg/UpdateGroupAccountDecisionPolicy request type. +### QueryProposalResponse +QueryProposalResponse is the Query/Proposal response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| address | [string](#string) | | address is the group account address. | -| decision_policy | [google.protobuf.Any](#google.protobuf.Any) | | decision_policy is the updated group account decision policy. | +| proposal | [Proposal](#regen.group.v1alpha1.Proposal) | | proposal is the proposal info. | - + -### MsgUpdateGroupAccountDecisionPolicyResponse -MsgUpdateGroupAccountDecisionPolicyResponse is the Msg/UpdateGroupAccountDecisionPolicy response type. +### QueryProposalsByGroupAccountRequest +QueryProposalsByGroupAccountRequest is the Query/ProposalByGroupAccount request type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| address | [string](#string) | | address is the group account address related to proposals. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - -### MsgUpdateGroupAccountMetadataRequest -MsgUpdateGroupAccountMetadataRequest is the Msg/UpdateGroupAccountMetadata request type. + + + +### QueryProposalsByGroupAccountResponse +QueryProposalsByGroupAccountResponse is the Query/ProposalByGroupAccount response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| address | [string](#string) | | address is the group account address. | -| metadata | [bytes](#bytes) | | metadata is the updated group account metadata. | +| proposals | [Proposal](#regen.group.v1alpha1.Proposal) | repeated | proposals are the proposals with given group account. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + -### MsgUpdateGroupAccountMetadataResponse -MsgUpdateGroupAccountMetadataResponse is the Msg/UpdateGroupAccountMetadata response type. +### QueryVoteByProposalVoterRequest +QueryVoteByProposalVoterResponse is the Query/VoteByProposalVoter request type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of a proposal. | +| voter | [string](#string) | | voter is a proposal voter account address. | - -### MsgUpdateGroupAdminRequest -MsgUpdateGroupAdminRequest is the Msg/UpdateGroupAdmin request type. + + + +### QueryVoteByProposalVoterResponse +QueryVoteByProposalVoterResponse is the Query/VoteByProposalVoter response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the current account address of the group admin. | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | -| new_admin | [string](#string) | | new_admin is the group new admin account address. | +| vote | [Vote](#regen.group.v1alpha1.Vote) | | vote is the vote with given proposal_id and voter. | - + -### MsgUpdateGroupAdminResponse -MsgUpdateGroupAdminResponse is the Msg/UpdateGroupAdmin response type. +### QueryVotesByProposalRequest +QueryVotesByProposalResponse is the Query/VotesByProposal request type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| proposal_id | [uint64](#uint64) | | proposal_id is the unique ID of a proposal. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - -### MsgUpdateGroupMembersRequest -MsgUpdateGroupMembersRequest is the Msg/UpdateGroupMembers request type. + + + +### QueryVotesByProposalResponse +QueryVotesByProposalResponse is the Query/VotesByProposal response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | -| member_updates | [Member](#regen.group.v1alpha1.Member) | repeated | member_updates is the list of members to update, set weight to 0 to remove a member. | +| votes | [Vote](#regen.group.v1alpha1.Vote) | repeated | votes are the list of votes for given proposal_id. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + + +### QueryVotesByVoterRequest +QueryVotesByVoterResponse is the Query/VotesByVoter request type. -### MsgUpdateGroupMembersResponse -MsgUpdateGroupMembersResponse is the Msg/UpdateGroupMembers response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| voter | [string](#string) | | voter is a proposal voter account address. | +| pagination | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - -### MsgUpdateGroupMetadataRequest -MsgUpdateGroupMetadataRequest is the Msg/UpdateGroupMetadata request type. + + +### QueryVotesByVoterResponse +QueryVotesByVoterResponse is the Query/VotesByVoter response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| admin | [string](#string) | | admin is the account address of the group admin. | -| group_id | [uint64](#uint64) | | group_id is the unique ID of the group. | -| metadata | [bytes](#bytes) | | metadata is the updated group's metadata. | - +| votes | [Vote](#regen.group.v1alpha1.Vote) | repeated | votes are the list of votes by given voter. | +| pagination | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | - + -### MsgUpdateGroupMetadataResponse -MsgUpdateGroupMetadataResponse is the Msg/UpdateGroupMetadata response type. + + + +### Query +Query is the regen.group.v1alpha1 Query service. +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +| GroupInfo | [QueryGroupInfoRequest](#regen.group.v1alpha1.QueryGroupInfoRequest) | [QueryGroupInfoResponse](#regen.group.v1alpha1.QueryGroupInfoResponse) | GroupInfo queries group info based on group id. | +| GroupAccountInfo | [QueryGroupAccountInfoRequest](#regen.group.v1alpha1.QueryGroupAccountInfoRequest) | [QueryGroupAccountInfoResponse](#regen.group.v1alpha1.QueryGroupAccountInfoResponse) | GroupAccountInfo queries group account info based on group account address. | +| GroupMembers | [QueryGroupMembersRequest](#regen.group.v1alpha1.QueryGroupMembersRequest) | [QueryGroupMembersResponse](#regen.group.v1alpha1.QueryGroupMembersResponse) | GroupMembers queries members of a group | +| GroupsByAdmin | [QueryGroupsByAdminRequest](#regen.group.v1alpha1.QueryGroupsByAdminRequest) | [QueryGroupsByAdminResponse](#regen.group.v1alpha1.QueryGroupsByAdminResponse) | GroupsByAdmin queries groups by admin address. | +| GroupAccountsByGroup | [QueryGroupAccountsByGroupRequest](#regen.group.v1alpha1.QueryGroupAccountsByGroupRequest) | [QueryGroupAccountsByGroupResponse](#regen.group.v1alpha1.QueryGroupAccountsByGroupResponse) | GroupAccountsByGroup queries group accounts by group id. | +| GroupAccountsByAdmin | [QueryGroupAccountsByAdminRequest](#regen.group.v1alpha1.QueryGroupAccountsByAdminRequest) | [QueryGroupAccountsByAdminResponse](#regen.group.v1alpha1.QueryGroupAccountsByAdminResponse) | GroupsByAdmin queries group accounts by admin address. | +| Proposal | [QueryProposalRequest](#regen.group.v1alpha1.QueryProposalRequest) | [QueryProposalResponse](#regen.group.v1alpha1.QueryProposalResponse) | Proposal queries a proposal based on proposal id. | +| ProposalsByGroupAccount | [QueryProposalsByGroupAccountRequest](#regen.group.v1alpha1.QueryProposalsByGroupAccountRequest) | [QueryProposalsByGroupAccountResponse](#regen.group.v1alpha1.QueryProposalsByGroupAccountResponse) | ProposalsByGroupAccount queries proposals based on group account address. | +| VoteByProposalVoter | [QueryVoteByProposalVoterRequest](#regen.group.v1alpha1.QueryVoteByProposalVoterRequest) | [QueryVoteByProposalVoterResponse](#regen.group.v1alpha1.QueryVoteByProposalVoterResponse) | VoteByProposalVoter queries a vote by proposal id and voter. | +| VotesByProposal | [QueryVotesByProposalRequest](#regen.group.v1alpha1.QueryVotesByProposalRequest) | [QueryVotesByProposalResponse](#regen.group.v1alpha1.QueryVotesByProposalResponse) | VotesByProposal queries a vote by proposal. | +| VotesByVoter | [QueryVotesByVoterRequest](#regen.group.v1alpha1.QueryVotesByVoterRequest) | [QueryVotesByVoterResponse](#regen.group.v1alpha1.QueryVotesByVoterResponse) | VotesByVoter queries a vote by voter. | - + -### MsgVoteRequest -MsgVoteRequest is the Msg/Vote request type. -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| proposal_id | [uint64](#uint64) | | proposal is the unique ID of the proposal. | -| voter | [string](#string) | | voter is the voter account address. | -| choice | [Choice](#regen.group.v1alpha1.Choice) | | choice is the voter's choice on the proposal. | -| metadata | [bytes](#bytes) | | metadata is any arbitrary metadata to attached to the vote. | + + +## regen/group/v1alpha1/genesis.proto + +### GenesisState +GenesisState defines the group module's genesis state. - -### MsgVoteResponse -MsgVoteResponse is the Msg/Vote response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| group_seq | [uint64](#uint64) | | group_seq is the group table orm.Sequence, it is used to get the next group ID. | +| groups | [GroupInfo](#regen.group.v1alpha1.GroupInfo) | repeated | groups is the list of groups info. | +| group_members | [GroupMember](#regen.group.v1alpha1.GroupMember) | repeated | group_members is the list of groups members. | +| group_account_seq | [uint64](#uint64) | | group_account_seq is the group account table orm.Sequence, it is used to generate the next group account address. | +| group_accounts | [GroupAccountInfo](#regen.group.v1alpha1.GroupAccountInfo) | repeated | group_accounts is the list of group accounts info. | +| proposal_seq | [uint64](#uint64) | | proposal_seq is the proposal table orm.Sequence, it is used to get the next proposal ID. | +| proposals | [Proposal](#regen.group.v1alpha1.Proposal) | repeated | proposals is the list of proposals. | +| votes | [Vote](#regen.group.v1alpha1.Vote) | repeated | votes is the list of votes. | @@ -1198,26 +1218,6 @@ MsgVoteResponse is the Msg/Vote response type. - - - -### Msg -Msg is the regen.group.v1alpha1 Msg service. - -| Method Name | Request Type | Response Type | Description | -| ----------- | ------------ | ------------- | ------------| -| CreateGroup | [MsgCreateGroupRequest](#regen.group.v1alpha1.MsgCreateGroupRequest) | [MsgCreateGroupResponse](#regen.group.v1alpha1.MsgCreateGroupResponse) | CreateGroup creates a new group with an admin account address, a list of members and some optional metadata. | -| UpdateGroupMembers | [MsgUpdateGroupMembersRequest](#regen.group.v1alpha1.MsgUpdateGroupMembersRequest) | [MsgUpdateGroupMembersResponse](#regen.group.v1alpha1.MsgUpdateGroupMembersResponse) | UpdateGroupMembers updates the group members with given group id and admin address. | -| UpdateGroupAdmin | [MsgUpdateGroupAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAdminRequest) | [MsgUpdateGroupAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAdminResponse) | UpdateGroupAdmin updates the group admin with given group id and previous admin address. | -| UpdateGroupMetadata | [MsgUpdateGroupMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupMetadataRequest) | [MsgUpdateGroupMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupMetadataResponse) | UpdateGroupMetadata updates the group metadata with given group id and admin address. | -| CreateGroupAccount | [MsgCreateGroupAccountRequest](#regen.group.v1alpha1.MsgCreateGroupAccountRequest) | [MsgCreateGroupAccountResponse](#regen.group.v1alpha1.MsgCreateGroupAccountResponse) | CreateGroupAccount creates a new group account using given DecisionPolicy. | -| UpdateGroupAccountAdmin | [MsgUpdateGroupAccountAdminRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminRequest) | [MsgUpdateGroupAccountAdminResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountAdminResponse) | UpdateGroupAccountAdmin updates a group account admin. | -| UpdateGroupAccountDecisionPolicy | [MsgUpdateGroupAccountDecisionPolicyRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyRequest) | [MsgUpdateGroupAccountDecisionPolicyResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountDecisionPolicyResponse) | UpdateGroupAccountDecisionPolicy allows a group account decision policy to be updated. | -| UpdateGroupAccountMetadata | [MsgUpdateGroupAccountMetadataRequest](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataRequest) | [MsgUpdateGroupAccountMetadataResponse](#regen.group.v1alpha1.MsgUpdateGroupAccountMetadataResponse) | UpdateGroupAccountMetadata updates a group account metadata. | -| CreateProposal | [MsgCreateProposalRequest](#regen.group.v1alpha1.MsgCreateProposalRequest) | [MsgCreateProposalResponse](#regen.group.v1alpha1.MsgCreateProposalResponse) | CreateProposal submits a new proposal. | -| Vote | [MsgVoteRequest](#regen.group.v1alpha1.MsgVoteRequest) | [MsgVoteResponse](#regen.group.v1alpha1.MsgVoteResponse) | Vote allows a voter to vote on a proposal. | -| Exec | [MsgExecRequest](#regen.group.v1alpha1.MsgExecRequest) | [MsgExecResponse](#regen.group.v1alpha1.MsgExecResponse) | Exec executes a proposal. | - diff --git a/sims.mk b/sims.mk index 678cea9f00..69b53c80c4 100644 --- a/sims.mk +++ b/sims.mk @@ -3,43 +3,33 @@ ######################################## ### Simulations +simulation_tags="" + +ifeq ($(EXPERIMENTAL),true) + simulation_tags += experimental +endif + sim-regen-nondeterminism: @echo "Running nondeterminism test..." @go test -mod=readonly $(APP_DIR) -run TestAppStateDeterminism -Enabled=true \ - -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h - + -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h -tags="$(simulation_tags)" sim-regen-custom-genesis-fast: @echo "Running custom genesis simulation..." @echo "By default, ${HOME}/.regen/config/genesis.json will be used." @go test -mod=readonly $(APP_DIR) -run TestFullAppSimulation -Genesis=${HOME}/.regen/config/genesis.json \ - -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h + -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h -tags="$(simulation_tags)" sim-regen-fast: @echo "Running quick Regen simulation. This may take several minutes..." - @go test -mod=readonly $(APP_DIR) -run TestFullAppSimulation -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h + @go test -mod=readonly $(APP_DIR) -run TestFullAppSimulation -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h -tags="$(simulation_tags)" sim-regen-import-export: runsim @echo "Running Regen import/export simulation. This may take several minutes..." - $(GOPATH)/bin/runsim -Jobs=4 -SimAppPkg=$(APP_DIR) -ExitOnFail 25 5 TestImportExport + $(GOPATH)/bin/runsim -Jobs=4 -ExitOnFail 25 5 TestImportExport -sim-regen-simulation-after-import: runsim +sim-regen-after-import: runsim @echo "Running application simulation-after-import. This may take several minutes..." - $(GOPATH)/bin/runsim -Jobs=4 -SimAppPkg=$(APP_DIR) -ExitOnFail 50 5 TestAppSimulationAfterImport - -sim-regen-custom-genesis-multi-seed: runsim - @echo "Running multi-seed custom genesis simulation..." - @echo "By default, ${HOME}/.regen/config/genesis.json will be used." - $(GOPATH)/bin/runsim -Genesis=${HOME}/.regen/config/genesis.json -SimAppPkg=$(APP_DIR) -ExitOnFail 400 5 TestFullAppSimulation - -sim-regen-multi-seed: runsim - @echo "Running multi-seed application simulation. This may take awhile!" - $(GOPATH)/bin/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation - -sim-benchmark-invariants: - @echo "Running simulation invariant benchmarks..." - @go test -mod=readonly $(APP_DIR) -benchmem -bench=BenchmarkInvariants -run=^$ \ - -Enabled=true -NumBlocks=1000 -BlockSize=200 \ - -Commit=true -Seed=57 -v -timeout 24h + $(GOPATH)/bin/runsim -Jobs=4 -ExitOnFail 50 5 TestAppSimulationAfterImport SIM_NUM_BLOCKS ?= 500 SIM_BLOCK_SIZE ?= 200 @@ -55,7 +45,21 @@ sim-regen-profile: @go test -mod=readonly -benchmem -run=^$$ $(APP_DIR) -bench ^BenchmarkFullAppSimulation$$ \ -Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out +sim-regen-custom-genesis-multi-seed: runsim + @echo "Running multi-seed custom genesis simulation..." + @echo "By default, ${HOME}/.regen/config/genesis.json will be used." + $(GOPATH)/bin/runsim -Genesis=${HOME}/.regen/config/genesis.json -SimAppPkg=$(APP_DIR) -ExitOnFail 400 5 TestFullAppSimulation + +sim-regen-multi-seed: runsim + @echo "Running multi-seed application simulation. This may take awhile!" + $(GOPATH)/bin/runsim -Jobs=4 -SimAppPkg=$(APP_DIR) -ExitOnFail 500 50 TestFullAppSimulation + +sim-benchmark-invariants: + @echo "Running simulation invariant benchmarks..." + @go test -mod=readonly $(APP_DIR) -benchmem -bench=BenchmarkInvariants -run=^$ \ + -Enabled=true -NumBlocks=1000 -BlockSize=200 \ + -Commit=true -Seed=57 -v -timeout 24h -tags="$(simulation_tags)" .PHONY: runsim sim-regen-nondeterminism sim-regen-custom-genesis-fast sim-regen-fast sim-regen-import-export \ - sim-regen-simulation-after-import sim-regen-custom-genesis-multi-seed sim-regen-multi-seed \ - sim-benchmark-invariants sim-regen-benchmark sim-regen-profile + sim-regen-after-import sim-regen-benchmark sim-regen-profile sim-benchmark-invariants sim-regen-multi-seed \ + sim-regen-custom-genesis-multi-seed diff --git a/types/module/server/manager.go b/types/module/server/manager.go index d01dab3e47..7890e3f428 100644 --- a/types/module/server/manager.go +++ b/types/module/server/manager.go @@ -8,6 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" + sdkmodule "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/simulation" + sdk "github.com/cosmos/cosmos-sdk/types" gogogrpc "github.com/gogo/protobuf/grpc" abci "github.com/tendermint/tendermint/abci/types" @@ -18,14 +21,15 @@ import ( // Manager is the server module manager type Manager struct { - baseApp *baseapp.BaseApp - cdc *codec.ProtoCodec - keys map[string]ModuleKey - router *router - requiredServices map[reflect.Type]bool - initGenesisHandlers map[string]module.InitGenesisHandler - exportGenesisHandlers map[string]module.ExportGenesisHandler - registerInvariantsHandler map[string]RegisterInvariantsHandler + baseApp *baseapp.BaseApp + cdc *codec.ProtoCodec + keys map[string]ModuleKey + router *router + requiredServices map[reflect.Type]bool + initGenesisHandlers map[string]module.InitGenesisHandler + exportGenesisHandlers map[string]module.ExportGenesisHandler + registerInvariantsHandler map[string]RegisterInvariantsHandler + weightedOperationsHandlers map[string]WeightedOperationsHandler } // RegisterInvariants registers all module routes and module querier routes @@ -51,9 +55,14 @@ func NewManager(baseApp *baseapp.BaseApp, cdc *codec.ProtoCodec) *Manager { providedServices: map[reflect.Type]bool{}, antiReentryMap: map[string]bool{}, }, + weightedOperationsHandlers: map[string]WeightedOperationsHandler{}, } } +func (mm *Manager) GetWeightedOperationsHandlers() map[string]WeightedOperationsHandler { + return mm.weightedOperationsHandlers +} + // RegisterModules registers modules with the Manager and registers their services. func (mm *Manager) RegisterModules(modules []module.Module) error { // First we register all interface types. This is done for all modules first before registering @@ -120,6 +129,10 @@ func (mm *Manager) RegisterModules(modules []module.Module) error { mm.initGenesisHandlers[name] = cfg.initGenesisHandler mm.exportGenesisHandlers[name] = cfg.exportGenesisHandler + if cfg.weightedOperationHandler != nil { + mm.weightedOperationsHandlers[name] = cfg.weightedOperationHandler + } + // If mod implements LegacyRouteModule, register module route. // This is currently used for the group module as part of #218. routeMod, ok := mod.(LegacyRouteModule) @@ -138,6 +151,22 @@ func (mm *Manager) RegisterModules(modules []module.Module) error { return nil } +// WeightedOperations returns all the modules' weighted operations of an application +func (mm *Manager) WeightedOperations(state sdkmodule.SimulationState, modules []sdkmodule.AppModuleSimulation) []simulation.WeightedOperation { + wOps := make([]simulation.WeightedOperation, 0, len(modules)+len(mm.weightedOperationsHandlers)) + // adding non ADR-33 modules weighted operations + for _, m := range modules { + wOps = append(wOps, m.WeightedOperations(state)...) + } + + // adding ADR-33 modules weighted operations + for _, weightedOperationHandler := range mm.weightedOperationsHandlers { + wOps = append(wOps, weightedOperationHandler(state)...) + } + + return wOps +} + // AuthorizationMiddleware is a function that allows for more complex authorization than the default authorization scheme, // such as delegated permissions. It will be called only if the default authorization fails. type AuthorizationMiddleware func(ctx sdk.Context, methodName string, req sdk.MsgRequest, signer sdk.AccAddress) bool @@ -234,11 +263,16 @@ type configurator struct { router sdk.Router initGenesisHandler module.InitGenesisHandler exportGenesisHandler module.ExportGenesisHandler + weightedOperationHandler WeightedOperationsHandler registerInvariantsHandler RegisterInvariantsHandler } var _ Configurator = &configurator{} +func (c *configurator) RegisterWeightedOperationsHandler(operationsHandler WeightedOperationsHandler) { + c.weightedOperationHandler = operationsHandler +} + func (c *configurator) MsgServer() gogogrpc.Server { return c.msgServer } @@ -273,3 +307,5 @@ func (c *configurator) Router() sdk.Router { func (c *configurator) RequireServer(serverInterface interface{}) { c.requiredServices[reflect.TypeOf(serverInterface)] = true } + +type WeightedOperationsHandler func(simstate sdkmodule.SimulationState) []simulation.WeightedOperation diff --git a/types/module/server/module.go b/types/module/server/module.go index ba2762c4f2..cc77553dda 100644 --- a/types/module/server/module.go +++ b/types/module/server/module.go @@ -27,6 +27,8 @@ type Configurator interface { // Router() is temporarily added here to use in the group module. // TODO: remove once #225 addressed Router() sdk.Router + + RegisterWeightedOperationsHandler(WeightedOperationsHandler) } // LegacyRouteModule is the module type that a module must implement diff --git a/x/group/exported/expected_keepers.go b/x/group/exported/expected_keepers.go new file mode 100644 index 0000000000..1c908ba3cd --- /dev/null +++ b/x/group/exported/expected_keepers.go @@ -0,0 +1,22 @@ +package exported + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +type AccountKeeper interface { + // Return a new account with the next account number. Does not save the new account to the store. + NewAccount(sdk.Context, authtypes.AccountI) authtypes.AccountI + + // Retrieve an account from the store. + GetAccount(sdk.Context, sdk.AccAddress) authtypes.AccountI + + // Set an account in the store. + SetAccount(sdk.Context, authtypes.AccountI) +} + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} diff --git a/x/group/module/module.go b/x/group/module/module.go index df7ab72532..665d76400e 100644 --- a/x/group/module/module.go +++ b/x/group/module/module.go @@ -3,28 +3,38 @@ package module import ( "encoding/json" "fmt" + "math/rand" + "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" - climodule "github.com/regen-network/regen-ledger/types/module/client/cli" - servermodule "github.com/regen-network/regen-ledger/types/module/server" - "github.com/regen-network/regen-ledger/x/group" - "github.com/regen-network/regen-ledger/x/group/client" - "github.com/regen-network/regen-ledger/x/group/server" + "github.com/spf13/cobra" sdkclient "github.com/cosmos/cosmos-sdk/client" "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/module" - "github.com/gorilla/mux" - "github.com/spf13/cobra" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + climodule "github.com/regen-network/regen-ledger/types/module/client/cli" + "github.com/regen-network/regen-ledger/x/group" + "github.com/regen-network/regen-ledger/x/group/client" + + "github.com/regen-network/regen-ledger/x/group/exported" + "github.com/regen-network/regen-ledger/x/group/server" + "github.com/regen-network/regen-ledger/x/group/simulation" + + servermodule "github.com/regen-network/regen-ledger/types/module/server" ) type Module struct { - AccountKeeper server.AccountKeeper + Registry types.InterfaceRegistry + BankKeeper exported.BankKeeper + AccountKeeper exported.AccountKeeper } var _ module.AppModuleBasic = Module{} +var _ module.AppModuleSimulation = Module{} var _ servermodule.Module = Module{} var _ climodule.Module = Module{} var _ servermodule.LegacyRouteModule = Module{} @@ -39,7 +49,7 @@ func (a Module) RegisterInterfaces(registry types.InterfaceRegistry) { } func (a Module) RegisterServices(configurator servermodule.Configurator) { - server.RegisterServices(configurator, a.AccountKeeper) + server.RegisterServices(configurator, a.AccountKeeper, a.BankKeeper) } func (a Module) DefaultGenesis(marshaler codec.JSONMarshaler) json.RawMessage { @@ -71,5 +81,34 @@ func (a Module) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { } func (a Module) Route(configurator servermodule.Configurator) sdk.Route { - return sdk.NewRoute(group.RouterKey, server.NewHandler(configurator, a.AccountKeeper)) + return sdk.NewRoute(group.RouterKey, server.NewHandler(configurator, a.AccountKeeper, a.BankKeeper)) +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenesisState of the group module. +func (Module) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns all the group content functions used to +// simulate proposals. +func (Module) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized group param changes for the simulator. +func (Module) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { + return nil +} + +// RegisterStoreDecoder registers a decoder for group module's types +func (Module) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { +} + +// WeightedOperations returns all the group module operations with their respective weights. +// NOTE: This is no longer needed for the modules which uses ADR-33, group module `WeightedOperations` +// registered in the `x/group/server` package. +func (Module) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return nil } diff --git a/x/group/server/expected_keepers.go b/x/group/server/expected_keepers.go deleted file mode 100644 index 83c583b6e9..0000000000 --- a/x/group/server/expected_keepers.go +++ /dev/null @@ -1,17 +0,0 @@ -package server - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -type AccountKeeper interface { - // Return a new account with the next account number. Does not save the new account to the store. - NewAccount(sdk.Context, types.AccountI) types.AccountI - - // Retrieve an account from the store. - GetAccount(sdk.Context, sdk.AccAddress) types.AccountI - - // Set an account in the store. - SetAccount(sdk.Context, types.AccountI) -} diff --git a/x/group/server/handler.go b/x/group/server/handler.go index a63f46dfad..9d45a4d390 100644 --- a/x/group/server/handler.go +++ b/x/group/server/handler.go @@ -6,12 +6,13 @@ import ( "github.com/regen-network/regen-ledger/types" servermodule "github.com/regen-network/regen-ledger/types/module/server" "github.com/regen-network/regen-ledger/x/group" + "github.com/regen-network/regen-ledger/x/group/exported" ) // NewHandler creates an sdk.Handler for all the group type messages. // This is needed for supporting amino-json signing. -func NewHandler(configurator servermodule.Configurator, accountKeeper AccountKeeper) sdk.Handler { - impl := newServer(configurator.ModuleKey(), configurator.Router(), accountKeeper, configurator.Marshaler()) +func NewHandler(configurator servermodule.Configurator, accountKeeper exported.AccountKeeper, bankKeeper exported.BankKeeper) sdk.Handler { + impl := newServer(configurator.ModuleKey(), configurator.Router(), accountKeeper, bankKeeper, configurator.Marshaler()) return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) diff --git a/x/group/server/invariants.go b/x/group/server/invariants.go index 53c3019f64..cf3f9062f0 100644 --- a/x/group/server/invariants.go +++ b/x/group/server/invariants.go @@ -130,9 +130,8 @@ func groupTotalWeightInvariant(ctx sdk.Context, groupTable orm.Table, groupMembe } defer groupIt.Close() - membersWeight := apd.New(0, 0) - for { + membersWeight := apd.New(0, 0) _, err := groupIt.LoadNext(&groupInfo) if orm.ErrIteratorDone.Is(err) { break @@ -161,6 +160,7 @@ func groupTotalWeightInvariant(ctx sdk.Context, groupTable orm.Table, groupMembe if err != nil { return msg, broken, err } + if groupWeight.Cmp(membersWeight) != 0 { broken = true msg += "group's TotalWeight must be equal to the sum of its members' weights\n" diff --git a/x/group/server/operations.go b/x/group/server/operations.go new file mode 100644 index 0000000000..00880a1893 --- /dev/null +++ b/x/group/server/operations.go @@ -0,0 +1,18 @@ +package server + +import ( + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/regen-network/regen-ledger/x/group" + "github.com/regen-network/regen-ledger/x/group/simulation" +) + +// WeightedOperations returns all the group module operations with their respective weights. +func (s serverImpl) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + + queryClient := group.NewQueryClient(s.key) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + s.accKeeper, s.bankKeeper, queryClient, + ) +} diff --git a/x/group/server/server.go b/x/group/server/server.go index 6f032a52bf..16cfa7f637 100644 --- a/x/group/server/server.go +++ b/x/group/server/server.go @@ -7,6 +7,7 @@ import ( "github.com/regen-network/regen-ledger/orm" servermodule "github.com/regen-network/regen-ledger/types/module/server" "github.com/regen-network/regen-ledger/x/group" + "github.com/regen-network/regen-ledger/x/group/exported" ) const ( @@ -42,7 +43,8 @@ type serverImpl struct { key servermodule.RootModuleKey router sdk.Router - accKeeper AccountKeeper + accKeeper exported.AccountKeeper + bankKeeper exported.BankKeeper // Group Table groupSeq orm.Sequence @@ -71,8 +73,8 @@ type serverImpl struct { voteByVoterIndex orm.Index } -func newServer(storeKey servermodule.RootModuleKey, router sdk.Router, accKeeper AccountKeeper, cdc codec.Marshaler) serverImpl { - s := serverImpl{key: storeKey, router: router, accKeeper: accKeeper} +func newServer(storeKey servermodule.RootModuleKey, router sdk.Router, accKeeper exported.AccountKeeper, bankKeeper exported.BankKeeper, cdc codec.Marshaler) serverImpl { + s := serverImpl{key: storeKey, router: router, accKeeper: accKeeper, bankKeeper: bankKeeper} // Group Table groupTableBuilder := orm.NewTableBuilder(GroupTablePrefix, storeKey, &group.GroupInfo{}, orm.FixLengthIndexKeys(orm.EncodedSeqLength), cdc) @@ -160,10 +162,11 @@ func newServer(storeKey servermodule.RootModuleKey, router sdk.Router, accKeeper return s } -func RegisterServices(configurator servermodule.Configurator, accountKeeper AccountKeeper) { - impl := newServer(configurator.ModuleKey(), configurator.Router(), accountKeeper, configurator.Marshaler()) +func RegisterServices(configurator servermodule.Configurator, accountKeeper exported.AccountKeeper, bankKeeper exported.BankKeeper) { + impl := newServer(configurator.ModuleKey(), configurator.Router(), accountKeeper, bankKeeper, configurator.Marshaler()) group.RegisterMsgServer(configurator.MsgServer(), impl) group.RegisterQueryServer(configurator.QueryServer(), impl) configurator.RegisterInvariantsHandler(impl.RegisterInvariants) configurator.RegisterGenesisHandlers(impl.InitGenesis, impl.ExportGenesis) + configurator.RegisterWeightedOperationsHandler(impl.WeightedOperations) } diff --git a/x/group/simulation/genesis.go b/x/group/simulation/genesis.go new file mode 100644 index 0000000000..a749b9807d --- /dev/null +++ b/x/group/simulation/genesis.go @@ -0,0 +1,196 @@ +package simulation + +import ( + "math/rand" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + gogotypes "github.com/gogo/protobuf/types" + + "github.com/regen-network/regen-ledger/x/group" +) + +const ( + GroupInfo = "group-info" + GroupMembers = "group-members" + GroupAccountInfo = "group-accout-info" + GroupProposals = "group-proposals" + GroupVote = "group-vote" +) + +func getGroups(r *rand.Rand, accounts []simtypes.Account) []*group.GroupInfo { + groups := make([]*group.GroupInfo, 3) + for i := 0; i < 3; i++ { + acc, _ := simtypes.RandomAcc(r, accounts) + groups[i] = &group.GroupInfo{ + GroupId: uint64(i + 1), + Admin: acc.Address.String(), + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + Version: 1, + TotalWeight: "10", + } + } + return groups +} + +func getGroupMembers(r *rand.Rand, accounts []simtypes.Account) []*group.GroupMember { + groupMembers := make([]*group.GroupMember, 3) + for i := 0; i < 3; i++ { + acc, _ := simtypes.RandomAcc(r, accounts) + groupMembers[i] = &group.GroupMember{ + GroupId: uint64(i + 1), + Member: &group.Member{ + Address: acc.Address.String(), + Weight: "10", + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + }, + } + } + return groupMembers +} + +func getGroupAccounts(r *rand.Rand, simState *module.SimulationState) []*group.GroupAccountInfo { + groupMembers := make([]*group.GroupAccountInfo, 3) + for i := 0; i < 3; i++ { + acc, _ := simtypes.RandomAcc(r, simState.Accounts) + any, err := codectypes.NewAnyWithValue(group.NewThresholdDecisionPolicy("10", gogotypes.Duration{Seconds: 1})) + if err != nil { + panic(err) + } + groupMembers[i] = &group.GroupAccountInfo{ + GroupId: uint64(i + 1), + Admin: acc.Address.String(), + Address: acc.Address.String(), + Version: 1, + DecisionPolicy: any, + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + } + } + return groupMembers +} + +func getProposals(r *rand.Rand, simState *module.SimulationState) []*group.Proposal { + proposals := make([]*group.Proposal, 3) + proposers := []string{simState.Accounts[0].Address.String(), simState.Accounts[1].Address.String()} + for i := 0; i < 3; i++ { + from, _ := simtypes.RandomAcc(r, simState.Accounts) + to, _ := simtypes.RandomAcc(r, simState.Accounts) + fromAddr := from.Address.String() + + proposal := &group.Proposal{ + ProposalId: uint64(i + 1), + Proposers: proposers, + Address: fromAddr, + GroupVersion: uint64(i + 1), + GroupAccountVersion: uint64(i + 1), + Status: group.ProposalStatusSubmitted, + Result: group.ProposalResultAccepted, + VoteState: group.Tally{ + YesCount: "1", + NoCount: "1", + AbstainCount: "1", + VetoCount: "0", + }, + ExecutorResult: group.ProposalExecutorResultNotRun, + Metadata: []byte(simtypes.RandStringOfLength(r, 50)), + SubmittedAt: gogotypes.Timestamp{Seconds: 1}, + Timeout: gogotypes.Timestamp{Seconds: 1000}, + } + err := proposal.SetMsgs([]sdk.Msg{&banktypes.MsgSend{ + FromAddress: fromAddr, + ToAddress: to.Address.String(), + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + }}) + if err != nil { + panic(err) + } + + proposals[i] = proposal + } + + return proposals +} + +func getVotes(r *rand.Rand, simState *module.SimulationState) []*group.Vote { + votes := make([]*group.Vote, 3) + + for i := 0; i < 3; i++ { + votes[i] = &group.Vote{ + ProposalId: uint64(i + 1), + Voter: simState.Accounts[i].Address.String(), + Choice: getVoteChoice(i), + Metadata: []byte(simtypes.RandStringOfLength(r, 50)), + SubmittedAt: gogotypes.Timestamp{Seconds: 10}, + } + } + + return votes +} + +func getVoteChoice(index int) group.Choice { + switch index { + case 0: + return group.Choice_CHOICE_YES + case 1: + return group.Choice_CHOICE_NO + case 2: + return group.Choice_CHOICE_ABSTAIN + default: + return group.Choice_CHOICE_VETO + } +} + +// RandomizedGenState generates a random GenesisState for the group module. +func RandomizedGenState(simState *module.SimulationState) { + + // groups + var groups []*group.GroupInfo + simState.AppParams.GetOrGenerate( + simState.Cdc, GroupInfo, &groups, simState.Rand, + func(r *rand.Rand) { groups = getGroups(r, simState.Accounts) }, + ) + + // group members + var members []*group.GroupMember + simState.AppParams.GetOrGenerate( + simState.Cdc, GroupMembers, &members, simState.Rand, + func(r *rand.Rand) { members = getGroupMembers(r, simState.Accounts) }, + ) + + // group accounts + var groupAccounts []*group.GroupAccountInfo + simState.AppParams.GetOrGenerate( + simState.Cdc, GroupAccountInfo, &groupAccounts, simState.Rand, + func(r *rand.Rand) { groupAccounts = getGroupAccounts(r, simState) }, + ) + + // proposals + var proposals []*group.Proposal + simState.AppParams.GetOrGenerate( + simState.Cdc, GroupProposals, &proposals, simState.Rand, + func(r *rand.Rand) { proposals = getProposals(r, simState) }, + ) + + // votes + var votes []*group.Vote + simState.AppParams.GetOrGenerate( + simState.Cdc, GroupVote, &votes, simState.Rand, + func(r *rand.Rand) { votes = getVotes(r, simState) }, + ) + + groupGenesis := group.GenesisState{ + GroupSeq: 3, + Groups: groups, + GroupMembers: members, + GroupAccountSeq: 3, + GroupAccounts: groupAccounts, + ProposalSeq: 3, + Proposals: proposals, + Votes: votes, + } + + simState.GenState[group.ModuleName] = simState.Cdc.MustMarshalJSON(&groupGenesis) +} diff --git a/x/group/simulation/operations.go b/x/group/simulation/operations.go new file mode 100644 index 0000000000..1254952c84 --- /dev/null +++ b/x/group/simulation/operations.go @@ -0,0 +1,918 @@ +package simulation + +import ( + "fmt" + "math/rand" + "strings" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp/helpers" + "github.com/cosmos/cosmos-sdk/x/simulation" + + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + gogotypes "github.com/gogo/protobuf/types" + regentypes "github.com/regen-network/regen-ledger/types" + "github.com/regen-network/regen-ledger/x/group" + "github.com/regen-network/regen-ledger/x/group/exported" +) + +// Simulation operation weights constants +const ( + OpMsgCreateGroupRequest = "op_weight_msg_create_group" + OpMsgUpdateGroupAdminRequest = "op_weight_msg_update_group_admin" + OpMsgUpdateGroupMetadata = "op_wieght_msg_update_group_metadata" + OpMsgUpdateGroupMembers = "op_weight_msg_update_group_members" + OpMsgCreateGroupAccountRequest = "op_weight_msg_create_group_account" + OpMsgUpdateGroupAccountAdmin = "op_weight_msg_update_group_account_admin" + OpMsgUpdateGroupAccountDecisionPolicy = "op_weight_msg_update_group_account_decision_policy" + OpMsgUpdateGroupAccountMetaData = "op_weight_msg_update_group_account_metadata" + OpMsgCreateProposal = "op_weight_msg_create_proposal" + OpMsgVote = "op_weight_msg_vote" + OpMsgExec = "ops_weight_msg_exec" +) + +// If update group or group account txn's executed, `SimulateMsgVote` & `SimulateMsgExec` txn's returns `noOp`. +// That's why we have less weight for update group & group-account txn's. +const ( + WeightCreateGroup = 100 + WeightCreateGroupAccount = 100 + WeightCreateProposal = 90 + WeightMsgVote = 90 + WeightMsgExec = 90 + WeightUpdateGroupMetadata = 5 + WeightUpdateGroupAdmin = 5 + WeightUpdateGroupMembers = 5 + WeightUpdateGroupAccountAdmin = 5 + WeightUpdateGroupAccountDecisionPolicy = 5 + WeightUpdateGroupAccountComment = 5 + GroupMemberWeight = 40 +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak exported.AccountKeeper, + bk exported.BankKeeper, qryClient group.QueryClient) simulation.WeightedOperations { + var ( + weightMsgCreateGroup int + weightMsgUpdateGroupAdmin int + weightMsgUpdateGroupMetadata int + weightMsgUpdateGroupMembers int + weightMsgCreateGroupAccount int + weightMsgUpdateGroupAccountAdmin int + weightMsgUpdateGroupAccountDecisionPolicy int + weightMsgUpdateGroupAccountComment int + weightMsgCreateProposal int + weightMsgVote int + weightMsgExec int + ) + + appParams.GetOrGenerate(cdc, OpMsgCreateGroupRequest, &weightMsgCreateGroup, nil, + func(_ *rand.Rand) { + weightMsgCreateGroup = WeightCreateGroup + }, + ) + appParams.GetOrGenerate(cdc, OpMsgCreateGroupAccountRequest, &weightMsgCreateGroupAccount, nil, + func(_ *rand.Rand) { + weightMsgCreateGroupAccount = WeightCreateGroupAccount + }, + ) + appParams.GetOrGenerate(cdc, OpMsgCreateProposal, &weightMsgCreateProposal, nil, + func(_ *rand.Rand) { + weightMsgCreateProposal = WeightCreateProposal + }, + ) + appParams.GetOrGenerate(cdc, OpMsgVote, &weightMsgVote, nil, + func(_ *rand.Rand) { + weightMsgVote = WeightMsgVote + }, + ) + appParams.GetOrGenerate(cdc, OpMsgExec, &weightMsgExec, nil, + func(_ *rand.Rand) { + weightMsgExec = WeightMsgExec + }, + ) + appParams.GetOrGenerate(cdc, OpMsgUpdateGroupMetadata, &weightMsgUpdateGroupMetadata, nil, + func(_ *rand.Rand) { + weightMsgUpdateGroupMetadata = WeightUpdateGroupMetadata + }, + ) + appParams.GetOrGenerate(cdc, OpMsgUpdateGroupAdminRequest, &weightMsgUpdateGroupAdmin, nil, + func(_ *rand.Rand) { + weightMsgUpdateGroupAdmin = WeightUpdateGroupAdmin + }, + ) + appParams.GetOrGenerate(cdc, OpMsgUpdateGroupMembers, &weightMsgUpdateGroupMembers, nil, + func(_ *rand.Rand) { + weightMsgUpdateGroupMembers = WeightUpdateGroupMembers + }, + ) + appParams.GetOrGenerate(cdc, OpMsgUpdateGroupAccountAdmin, &weightMsgUpdateGroupAccountAdmin, nil, + func(_ *rand.Rand) { + weightMsgUpdateGroupAccountAdmin = WeightUpdateGroupAccountAdmin + }, + ) + appParams.GetOrGenerate(cdc, OpMsgUpdateGroupAccountDecisionPolicy, &weightMsgUpdateGroupAccountDecisionPolicy, nil, + func(_ *rand.Rand) { + weightMsgUpdateGroupAccountDecisionPolicy = WeightUpdateGroupAccountDecisionPolicy + }, + ) + appParams.GetOrGenerate(cdc, OpMsgUpdateGroupAccountMetaData, &weightMsgUpdateGroupAccountComment, nil, + func(_ *rand.Rand) { + weightMsgUpdateGroupAccountComment = WeightUpdateGroupAccountComment + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgCreateGroup, + SimulateMsgCreateGroup(ak, bk), + ), + simulation.NewWeightedOperation( + weightMsgCreateGroupAccount, + SimulateMsgCreateGroupAccount(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgCreateProposal, + SimulateMsgCreateProposal(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgVote, + SimulateMsgVote(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgExec, + SimulateMsgExec(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgUpdateGroupMetadata, + SimulateMsgUpdateGroupMetadata(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgUpdateGroupAdmin, + SimulateMsgUpdateGroupAdmin(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgUpdateGroupMembers, + SimulateMsgUpdateGroupMembers(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgUpdateGroupAccountAdmin, + SimulateMsgUpdateGroupAccountAdmin(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgUpdateGroupAccountDecisionPolicy, + SimulateMsgUpdateGroupAccountDecisionPolicy(ak, bk, qryClient), + ), + simulation.NewWeightedOperation( + weightMsgUpdateGroupAccountComment, + SimulateMsgUpdateGroupAccountMetadata(ak, bk, qryClient), + ), + } +} + +// SimulateMsgCreateGroup generates a MsgCreateGroupRequest with random values +func SimulateMsgCreateGroup(ak exported.AccountKeeper, bk exported.BankKeeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc, _ := simtypes.RandomAcc(r, accounts) + account := ak.GetAccount(ctx, acc.Address) + accAddr := acc.Address.String() + + spendableCoins := bk.SpendableCoins(ctx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroup, "fee error"), nil, err + } + + members := []group.Member{ + { + Address: accAddr, + Weight: fmt.Sprintf("%d", GroupMemberWeight), + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + }, + } + + msg := &group.MsgCreateGroupRequest{Admin: accAddr, Members: members, Metadata: []byte(simtypes.RandStringOfLength(r, 10))} + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroup, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, ""), nil, err + } +} + +// SimulateMsgCreateGroupAccount generates a NewMsgCreateGroupAccountRequest with random values +func SimulateMsgCreateGroupAccount(ak exported.AccountKeeper, bk exported.BankKeeper, qryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc := accounts[0] + account := ak.GetAccount(ctx, acc.Address) + + spendableCoins := bk.SpendableCoins(ctx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, "fee error"), nil, err + } + + groupAdmin, groupID, op, err := getGroupDetails(ctx, qryClient, acc) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + addr, err := sdk.AccAddressFromBech32(groupAdmin) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, "fail to decode acc address"), nil, err + } + + msg, err := group.NewMsgCreateGroupAccountRequest( + addr, + groupID, + []byte(simtypes.RandStringOfLength(r, 10)), + &group.ThresholdDecisionPolicy{ + Threshold: "20", + Timeout: gogotypes.Duration{Seconds: int64(30 * 24 * 60 * 60)}, + }, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, err.Error()), nil, err + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + return simtypes.NewOperationMsg(msg, true, ""), nil, err + } +} + +func getGroupDetails(sdkCtx sdk.Context, qryClient group.QueryClient, acc simtypes.Account) (groupAdmin string, groupID uint64, op simtypes.OperationMsg, err error) { + ctx := regentypes.Context{Context: sdkCtx} + + groups, err := qryClient.GroupsByAdmin(ctx, &group.QueryGroupsByAdminRequest{Admin: acc.Address.String()}) + if err != nil { + return "", 0, simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, "fail to query groups"), err + } + + if len(groups.Groups) == 0 { + return "", 0, simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, ""), nil + } + + groupAdmin = groups.Groups[0].Admin + groupID = groups.Groups[0].GroupId + + return groupAdmin, groupID, simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateGroupAccount, ""), nil +} + +// SimulateMsgCreateProposal generates a NewMsgCreateProposalRequest with random values +func SimulateMsgCreateProposal(ak exported.AccountKeeper, bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc := accounts[0] + account := ak.GetAccount(sdkCtx, acc.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateProposal, "fee error"), nil, err + } + + ctx := regentypes.Context{Context: sdkCtx} + groupAdmin, _, op, err := getGroupDetails(sdkCtx, queryClient, acc) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateProposal, opMsg), nil, err + } + + msg := group.MsgCreateProposalRequest{ + Address: groupAccounts[0].Address, + Proposers: []string{acc.Address.String()}, + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgCreateProposal, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgUpdateGroupAdmin generates a MsgUpdateGroupAccountAdminRequest with random values +func SimulateMsgUpdateGroupAdmin(ak exported.AccountKeeper, bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + acc2 := accounts[1] + + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAdmin, "fee error"), nil, err + } + + ctx := regentypes.Context{Context: sdkCtx} + + groupAdmin, groupID, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAdmin, opMsg), nil, err + } + + msg := group.MsgUpdateGroupAdminRequest{ + GroupId: groupID, + Admin: groupAccounts[0].Admin, + NewAdmin: acc2.Address.String(), + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAdmin, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgUpdateGroupMetadata generates a MsgUpdateGroupMetadataRequest with random values +func SimulateMsgUpdateGroupMetadata(ak exported.AccountKeeper, bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc := accounts[0] + account := ak.GetAccount(sdkCtx, acc.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupComment, "fee error"), nil, err + } + + groupAdmin, groupID, op, err := getGroupDetails(sdkCtx, queryClient, acc) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + msg := group.MsgUpdateGroupMetadataRequest{ + GroupId: groupID, + Admin: groupAdmin, + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupComment, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgUpdateGroupMembers generates a MsgUpdateGroupMembersRequest with random values +func SimulateMsgUpdateGroupMembers(ak exported.AccountKeeper, + bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + acc2 := accounts[1] + acc3 := accounts[2] + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupMembers, "fee error"), nil, err + } + + ctx := regentypes.Context{Context: sdkCtx} + groupAdmin, groupID, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupMembers, opMsg), nil, err + } + + members := []group.Member{ + { + Address: acc2.Address.String(), + Weight: fmt.Sprintf("%d", GroupMemberWeight), + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + }, + { + Address: acc3.Address.String(), + Weight: fmt.Sprintf("%d", GroupMemberWeight), + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + }, + } + + msg := group.MsgUpdateGroupMembersRequest{ + GroupId: groupID, + Admin: groupAdmin, + MemberUpdates: members, + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupMembers, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgUpdateGroupAccountAdmin generates a MsgUpdateGroupAccountAdminRequest with random values +func SimulateMsgUpdateGroupAccountAdmin(ak exported.AccountKeeper, bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + acc2 := accounts[1] + + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountAdmin, "fee error"), nil, err + } + + ctx := regentypes.Context{Context: sdkCtx} + + groupAdmin, _, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountAdmin, opMsg), nil, err + } + + msg := group.MsgUpdateGroupAccountAdminRequest{ + Admin: groupAccounts[0].Admin, + Address: groupAccounts[0].Address, + NewAdmin: acc2.Address.String(), + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountAdmin, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgUpdateGroupAccountDecisionPolicy generates a NewMsgUpdateGroupAccountDecisionPolicyRequest with random values +func SimulateMsgUpdateGroupAccountDecisionPolicy(ak exported.AccountKeeper, + bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountDecisionPolicy, "fee error"), nil, err + } + + ctx := regentypes.Context{Context: sdkCtx} + groupAdmin, _, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountDecisionPolicy, opMsg), nil, err + } + + adminBech32, err := sdk.AccAddressFromBech32(groupAccounts[0].Admin) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountDecisionPolicy, fmt.Sprintf("fail to decide bech32 address: %s", err.Error())), nil, nil + } + + groupAccountBech32, err := sdk.AccAddressFromBech32(groupAccounts[0].Address) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountDecisionPolicy, fmt.Sprintf("fail to decide bech32 address: %s", err.Error())), nil, nil + } + + msg, err := group.NewMsgUpdateGroupAccountDecisionPolicyRequest(adminBech32, groupAccountBech32, &group.ThresholdDecisionPolicy{ + Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 20)), + Timeout: gogotypes.Duration{Seconds: int64(simtypes.RandIntBetween(r, 100, 1000))}, + }) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountDecisionPolicy, err.Error()), nil, err + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountDecisionPolicy, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, ""), nil, err + } +} + +// SimulateMsgUpdateGroupAccountMetadata generates a MsgUpdateGroupAccountMetadataRequest with random values +func SimulateMsgUpdateGroupAccountMetadata(ak exported.AccountKeeper, + bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountComment, "fee error"), nil, err + } + + ctx := regentypes.Context{Context: sdkCtx} + groupAdmin, _, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountComment, opMsg), nil, err + } + + msg := group.MsgUpdateGroupAccountMetadataRequest{ + Admin: groupAccounts[0].Admin, + Address: groupAccounts[0].Address, + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + } + + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountComment, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgVote generates a MsgVote with random values +func SimulateMsgVote(ak exported.AccountKeeper, + bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "fee error"), nil, err + } + ctx := regentypes.Context{Context: sdkCtx} + groupAdmin, _, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, opMsg), nil, err + } + + proposalsResult, err := queryClient.ProposalsByGroupAccount(ctx, &group.QueryProposalsByGroupAccountRequest{Address: groupAccounts[0].Address}) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "fail to query group info"), nil, err + } + proposals := proposalsResult.GetProposals() + if len(proposals) == 0 { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "no proposals found"), nil, nil + } + + proposalID := -1 + + for _, proposal := range proposals { + if proposal.Status == group.ProposalStatusSubmitted { + votingPeriodEnd, err := gogotypes.TimestampFromProto(&proposal.Timeout) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "error: while converting to timestamp"), nil, err + } + proposalID = int(proposal.ProposalId) + if votingPeriodEnd.Before(ctx.BlockTime()) || votingPeriodEnd.Equal(ctx.BlockTime()) { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "voting period ended: skipping"), nil, nil + } + break + } + } + + // return no-op if no proposal found + if proposalID == -1 { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "no proposals found"), nil, nil + } + + msg := group.MsgVoteRequest{ + ProposalId: uint64(proposalID), + Voter: acc1.Address.String(), + Choice: group.Choice_CHOICE_YES, + Metadata: []byte(simtypes.RandStringOfLength(r, 10)), + } + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountComment, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + + if err != nil { + if strings.Contains(err.Error(), "group was modified") || strings.Contains(err.Error(), "group account was modified") { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "no-op:group/group-account was modified"), nil, nil + } + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +// SimulateMsgExec generates a MsgExec with random values +func SimulateMsgExec(ak exported.AccountKeeper, + bk exported.BankKeeper, queryClient group.QueryClient) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acc1 := accounts[0] + + account := ak.GetAccount(sdkCtx, acc1.Address) + + spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress()) + fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "fee error"), nil, err + } + ctx := regentypes.Context{Context: sdkCtx} + groupAdmin, _, op, err := getGroupDetails(sdkCtx, queryClient, acc1) + if err != nil { + return op, nil, err + } + if groupAdmin == "" { + return op, nil, nil + } + + groupAccounts, opMsg, err := groupAccountsByAdmin(ctx, queryClient, groupAdmin) + if groupAccounts == nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, opMsg), nil, err + } + + proposalsResult, err := queryClient.ProposalsByGroupAccount(ctx, &group.QueryProposalsByGroupAccountRequest{Address: groupAccounts[0].Address}) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "fail to query group info"), nil, err + } + proposals := proposalsResult.GetProposals() + if len(proposals) == 0 { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "no proposals found"), nil, nil + } + + proposalID := -1 + + for _, proposal := range proposals { + if proposal.Status == group.ProposalStatusSubmitted { + proposalID = int(proposal.ProposalId) + break + } + } + + // return no-op if no proposal found + if proposalID == -1 { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgVote, "no proposals found"), nil, nil + } + + msg := group.MsgExecRequest{ + ProposalId: uint64(proposalID), + Signer: acc1.Address.String(), + } + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acc1.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(group.ModuleName, group.TypeMsgUpdateGroupAccountComment, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + if strings.Contains(err.Error(), "group was modified") || strings.Contains(err.Error(), "group account was modified") { + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "no-op:group/group-account was modified"), nil, nil + } + return simtypes.NoOpMsg(group.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, ""), nil, err + } +} + +func groupAccountsByAdmin(ctx regentypes.Context, qryClient group.QueryClient, admin string) ([]*group.GroupAccountInfo, string, error) { + result, err := qryClient.GroupAccountsByAdmin(ctx, &group.QueryGroupAccountsByAdminRequest{Admin: admin}) + if err != nil { + return nil, "fail to query group info", err + } + + groupAccounts := result.GetGroupAccounts() + if len(groupAccounts) == 0 { + return nil, "no group account found", nil + } + return groupAccounts, "", nil +}