From ba75f8e7845a740afdce6e5f1c91f1a97433b7e2 Mon Sep 17 00:00:00 2001 From: 170210 <85928898+170210@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:17:25 +0900 Subject: [PATCH] docs: create ERRORS.md for x/module (#1059) * chore: create an automatic error document generation module Signed-off-by: 170210 * docs: generate ERRORS.md for x/module Signed-off-by: 170210 * chore: add a ci to check generated error docs up-to-date Signed-off-by: 170210 * chore: update changelog Signed-off-by: 170210 * refactor: fix for lint Signed-off-by: 170210 * style: format yml file Signed-off-by: 170210 * fixup: fix for review Signed-off-by: 170210 * fixup: fix for review Signed-off-by: 170210 * fixup: refactor by comment Signed-off-by: 170210 * fixup: fix for comment Signed-off-by: 170210 * fixup: fix for comment Signed-off-by: 170210 --------- Signed-off-by: 170210 --- .github/workflows/check-generated.yml | 37 +++ CHANGELOG.md | 1 + Makefile | 4 + .../generator/error_docs_generator.go | 175 ++++++++++ .../error_doc/generator/errors_file_parser.go | 95 ++++++ tools/error_doc/generator/keys_file_parser.go | 54 ++++ tools/error_doc/go.mod | 5 + tools/error_doc/go.sum | 2 + tools/error_doc/main.go | 24 ++ x/ERRORS.md | 298 ++++++++++++++++++ x/README.md | 2 + 11 files changed, 697 insertions(+) create mode 100644 .github/workflows/check-generated.yml create mode 100644 tools/error_doc/generator/error_docs_generator.go create mode 100644 tools/error_doc/generator/errors_file_parser.go create mode 100644 tools/error_doc/generator/keys_file_parser.go create mode 100644 tools/error_doc/go.mod create mode 100644 tools/error_doc/go.sum create mode 100644 tools/error_doc/main.go create mode 100644 x/ERRORS.md diff --git a/.github/workflows/check-generated.yml b/.github/workflows/check-generated.yml new file mode 100644 index 0000000000..1aa1b4f375 --- /dev/null +++ b/.github/workflows/check-generated.yml @@ -0,0 +1,37 @@ +# Verify that generated code is up-to-date. + +name: Check generated code +on: + workflow_dispatch: + pull_request: + branches: + - '*' + +permissions: + contents: read + +jobs: + check-error-doc: + runs-on: ubuntu-latest + steps: + - name: Setup Golang + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: Check generated error docs + run: | + make error-doc-gen + if ! git diff --stat --exit-code ; then + echo ">> ERROR:" + echo ">>" + echo ">> Error documents require update (source files in x folder may have changed)." + echo ">> Ensure your tools are up-to-date, re-run 'make error-doc' and update this PR." + echo ">>" + exit 1 + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 8623f045d4..dc328bf36d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,3 +59,4 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Document Updates * (readme) [\#997](https://github.com/finschia/finschia-sdk/pull/997) fix swagger url +* (docs) [\#1059](https://github.com/Finschia/finschia-sdk/pull/1059) create ERRORS.md for x/module \ No newline at end of file diff --git a/Makefile b/Makefile index 61e1b781b8..3acde110b2 100644 --- a/Makefile +++ b/Makefile @@ -570,6 +570,10 @@ libsodium: fi .PHONY: libsodium +error-doc-gen: + cd ./tools/error_doc && go run ./ +.PHONY: error-doc-gen + ############################################################################### ### release ### ############################################################################### diff --git a/tools/error_doc/generator/error_docs_generator.go b/tools/error_doc/generator/error_docs_generator.go new file mode 100644 index 0000000000..4faf47298a --- /dev/null +++ b/tools/error_doc/generator/error_docs_generator.go @@ -0,0 +1,175 @@ +package generator + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +type ErrorDocumentGenerator struct { + targetPath string + errorsFiles []string + modules []string + errorDocument map[string][]*moduleInfo +} + +type moduleInfo struct { + filepath string + codespace string + constDict map[string]string + errorDict []errorInfo +} + +type sortByCodespace []*moduleInfo + +func (b sortByCodespace) Len() int { return len(b) } +func (b sortByCodespace) Less(i, j int) bool { return b[i].codespace < b[j].codespace } +func (b sortByCodespace) Swap(i, j int) { b[i], b[j] = b[j], b[i] } + +func NewErrorDocumentGenerator(p string) *ErrorDocumentGenerator { + return &ErrorDocumentGenerator{ + targetPath: p, + errorDocument: make(map[string][]*moduleInfo), + } +} + +func (edg *ErrorDocumentGenerator) listUpErrorsGoFiles(startPath, errorsFileName string) error { + err := filepath.Walk(startPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() && info.Name() == errorsFileName { + edg.errorsFiles = append(edg.errorsFiles, path) + } + return nil + }) + if err != nil { + return err + } + return nil +} + +func (edg *ErrorDocumentGenerator) extractModuleName() error { + for _, filepath := range edg.errorsFiles { + var moduleName string + startIndex := strings.Index(filepath, "/x/") + len("/x/") + endIndex := strings.Index(filepath[startIndex:], "/") + if startIndex != -1 && endIndex != -1 { + moduleName = filepath[startIndex : startIndex+endIndex] + } + if moduleName == "" { + return errors.New("failed to get module name for " + filepath) + } + edg.errorDocument[moduleName] = append(edg.errorDocument[moduleName], &moduleInfo{ + filepath: filepath, + codespace: "", + constDict: make(map[string]string), + errorDict: []errorInfo{}, + }) + } + // sort by key and codespace + for moduleName := range edg.errorDocument { + edg.modules = append(edg.modules, moduleName) + sort.Sort(sortByCodespace(edg.errorDocument[moduleName])) + } + sort.Strings(edg.modules) + return nil +} + +func (edg ErrorDocumentGenerator) outputCategory(file *os.File) { + file.WriteString("\n") + file.WriteString("# Category\n") + columnTemplate := " * [%s](#%s)\n" + for _, moduleName := range edg.modules { + file.WriteString(fmt.Sprintf(columnTemplate, cases.Title(language.Und).String(moduleName), moduleName)) + } + file.WriteString("\n") +} + +func (edg *ErrorDocumentGenerator) generateContent() error { + // generate errors in each module + for _, moduleName := range edg.modules { + mods := edg.errorDocument[moduleName] + for _, mod := range mods { + if err := mod.parseErrorsFile(); err != nil { + return err + } + if err := mod.parseKeysFile(); err != nil { + return err + } + } + } + return nil +} + +func (edg ErrorDocumentGenerator) outputContent(file *os.File) error { + extraInfoTemplate := " * [%s](%s)\n" + for _, moduleName := range edg.modules { + // module name + file.WriteString("\n") + file.WriteString("## " + cases.Title(language.Und).String(moduleName) + "\n") + // table header + file.WriteString("\n") + file.WriteString("|Error Name|Codespace|Code|Description|\n") + file.WriteString("|:-|:-|:-|:-|\n") + // table contents + mods := edg.errorDocument[moduleName] + for _, mod := range mods { + for _, errInfo := range mod.errorDict { + // assign value to field "codespace" + if s, err := errInfo.toString(mod.codespace); err != nil { + return err + } else { + file.WriteString(s) + } + } + } + // extract infomation + file.WriteString("\n>You can also find detailed information in the following Errors.go files:\n") + for _, mod := range mods { + relPath, err := filepath.Rel(edg.targetPath, mod.filepath) + if err != nil { + return err + } + file.WriteString(fmt.Sprintf(extraInfoTemplate, relPath, relPath)) + } + } + return nil +} + +func (edg ErrorDocumentGenerator) AutoGenerate() error { + // get all errors.go in x folder + errorsFileName := "errors.go" + err := edg.listUpErrorsGoFiles(edg.targetPath, errorsFileName) + if len(edg.errorsFiles) == 0 || err != nil { + return errors.New("not find target files in x folder") + } + // get each module name and bind it to paths (one module may have multiple errors.go) + if err := edg.extractModuleName(); err != nil { + return err + } + // generate content + if err := edg.generateContent(); err != nil { + return err + } + // prepare the file for writing + filepath := edg.targetPath + "/ERRORS.md" + file, err := os.Create(filepath) + if err != nil { + return err + } + defer file.Close() + // output category + edg.outputCategory(file) + // output content + if err := edg.outputContent(file); err != nil { + return err + } + return nil +} diff --git a/tools/error_doc/generator/errors_file_parser.go b/tools/error_doc/generator/errors_file_parser.go new file mode 100644 index 0000000000..258eef75e1 --- /dev/null +++ b/tools/error_doc/generator/errors_file_parser.go @@ -0,0 +1,95 @@ +package generator + +import ( + "bufio" + "errors" + "fmt" + "os" + "regexp" + "strings" +) + +type errorInfo struct { + errorName string + codespace string + code string + description string +} + +func (ei errorInfo) toString(cs string) (string, error) { + errorInfoTemplate := "|%s|%s|%s|%s|\n" + if ei.codespace == "ModuleName" { + if cs == "" { + return "", errors.New("failed to find moduleName") + } + ei.codespace = cs + } + return fmt.Sprintf(errorInfoTemplate, ei.errorName, ei.codespace, ei.code, ei.description), nil +} + +func (ei *errorInfo) getError(line string, constDict map[string]string) error { + parts := strings.SplitN(line, "=", 2) + ei.errorName = strings.TrimSpace(parts[0]) + errBody := strings.TrimSpace(parts[1]) + // error info is like as sdkerrors.Register(...) + pattern := regexp.MustCompile(`sdkerrors\.Register\((.*)\)`) + match := pattern.FindStringSubmatch(errBody) + if len(match) == 2 { + parts := strings.SplitN(match[1], ",", 3) + if len(parts) == 3 { + ei.codespace = strings.TrimSpace(parts[0]) + ei.code = strings.TrimSpace(parts[1]) + ei.description = strings.Trim(strings.TrimSpace(parts[2]), `"`) + if constValue, found := constDict[ei.codespace]; found { + ei.codespace = constValue + } + return nil + } + return errors.New("failed to get error info in: " + line) + } + return errors.New("failed to parse error info in: " + line) +} + +func getConst(line string) (string, string, error) { + line = strings.Replace(line, "const", "", 1) + parts := strings.Split(line, "=") + if len(parts) == 2 { + i := strings.TrimSpace(parts[0]) + val := strings.Trim(strings.TrimSpace(parts[1]), `"`) + return i, val, nil + } + return "", "", errors.New("failed to get the value in: " + line) +} + +func (mi *moduleInfo) parseErrorsFile() error { + // var errorDict []errorInfo + // constDict := make(map[string]string) + file, err := os.Open(mi.filepath) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "=") { + // get const + if !strings.Contains(line, "sdkerrors.Register") { + identifier, value, err := getConst(line) + if err != nil { + return err + } + mi.constDict[identifier] = value + } else { + // get error + var errInfo errorInfo + if err := errInfo.getError(line, mi.constDict); err != nil { + return err + } + mi.errorDict = append(mi.errorDict, errInfo) + } + } + } + return nil +} diff --git a/tools/error_doc/generator/keys_file_parser.go b/tools/error_doc/generator/keys_file_parser.go new file mode 100644 index 0000000000..5a42c87500 --- /dev/null +++ b/tools/error_doc/generator/keys_file_parser.go @@ -0,0 +1,54 @@ +package generator + +import ( + "bufio" + "errors" + "os" + "strings" +) + +func getCodeSpace(line string) (string, string, error) { + line = strings.Replace(line, "const", "", 1) + parts := strings.Split(line, "=") + if len(parts) == 2 { + i := strings.TrimSpace(parts[0]) + val := strings.Trim(strings.TrimSpace(parts[1]), `"`) + return i, val, nil + } + return "", "", errors.New("failed to get the value in: " + line) +} + +func (mi *moduleInfo) parseKeysFile() error { + // find keys.go or key.go + possibleFileNames := []string{"keys.go", "key.go"} + var keyFilePath string + for _, fileName := range possibleFileNames { + paramPath := strings.Replace(mi.filepath, "errors.go", fileName, 1) + if _, err := os.Stat(paramPath); err == nil { + keyFilePath = paramPath + break + } + } + // if keys.go or key.go is exist + if keyFilePath != "" { + file, err := os.Open(keyFilePath) + if err != nil { + return errors.New(keyFilePath + " cannot be opened") + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + // get module name + if strings.Contains(line, "ModuleName = ") { + _, val, err := getCodeSpace(line) + if err != nil { + return err + } + mi.codespace = val + } + } + } + + return nil +} diff --git a/tools/error_doc/go.mod b/tools/error_doc/go.mod new file mode 100644 index 0000000000..6ca1dbad7f --- /dev/null +++ b/tools/error_doc/go.mod @@ -0,0 +1,5 @@ +module github.com/Finschia/finschia-sdk/tools/error_doc + +go 1.20 + +require golang.org/x/text v0.11.0 diff --git a/tools/error_doc/go.sum b/tools/error_doc/go.sum new file mode 100644 index 0000000000..5f53cd0902 --- /dev/null +++ b/tools/error_doc/go.sum @@ -0,0 +1,2 @@ +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/tools/error_doc/main.go b/tools/error_doc/main.go new file mode 100644 index 0000000000..8342308263 --- /dev/null +++ b/tools/error_doc/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/Finschia/finschia-sdk/tools/error_doc/generator" +) + +func main() { + currentPath, err := os.Getwd() + if err != nil { + fmt.Println("Error getting current directory:", err) + os.Exit(1) + } + targetPath := filepath.Join(currentPath, "..", "..", "x") + + errorDocumentGenerator := generator.NewErrorDocumentGenerator(targetPath) + if err := errorDocumentGenerator.AutoGenerate(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/x/ERRORS.md b/x/ERRORS.md new file mode 100644 index 0000000000..32ed9ca1b2 --- /dev/null +++ b/x/ERRORS.md @@ -0,0 +1,298 @@ + +# Category + * [Authz](#authz) + * [Bank](#bank) + * [Capability](#capability) + * [Collection](#collection) + * [Crisis](#crisis) + * [Distribution](#distribution) + * [Evidence](#evidence) + * [Feegrant](#feegrant) + * [Foundation](#foundation) + * [Gov](#gov) + * [Params](#params) + * [Slashing](#slashing) + * [Staking](#staking) + * [Token](#token) + + +## Authz + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrInvalidExpirationTime|authz|3|expiration time of authorization should be more than current time| + +>You can also find detailed information in the following Errors.go files: + * [authz/errors.go](authz/errors.go) + +## Bank + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrNoInputs|bank|2|no inputs to send transaction| +|ErrNoOutputs|bank|3|no outputs to send transaction| +|ErrInputOutputMismatch|bank|4|sum inputs != sum outputs| +|ErrSendDisabled|bank|5|send transactions are disabled| +|ErrDenomMetadataNotFound|bank|6|client denom metadata not found| +|ErrInvalidKey|bank|7|invalid key| + +>You can also find detailed information in the following Errors.go files: + * [bank/types/errors.go](bank/types/errors.go) + +## Capability + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrInvalidCapabilityName|capability|2|capability name not valid| +|ErrNilCapability|capability|3|provided capability is nil| +|ErrCapabilityTaken|capability|4|capability name already taken| +|ErrOwnerClaimed|capability|5|given owner already claimed capability| +|ErrCapabilityNotOwned|capability|6|capability not owned by module| +|ErrCapabilityNotFound|capability|7|capability not found| +|ErrCapabilityOwnersNotFound|capability|8|owners not found for capability| + +>You can also find detailed information in the following Errors.go files: + * [capability/types/errors.go](capability/types/errors.go) + +## Collection + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrTokenNotExist|collection|2|token symbol, token-id does not exist| +|ErrTokenNotMintable|collection|3|token symbol, token-id is not mintable| +|ErrInvalidTokenName|collection|4|token name should not be empty| +|ErrInvalidTokenID|collection|5|invalid token id| +|ErrInvalidTokenDecimals|collection|6|token decimals should be within the range in 0 ~ 18| +|ErrInvalidIssueFT|collection|7|Issuing token with amount[1], decimals[0], mintable[false] prohibited. Issue nft token instead.| +|ErrInvalidAmount|collection|8|invalid token amount| +|ErrInvalidBaseImgURILength|collection|9|invalid base_img_uri length| +|ErrInvalidNameLength|collection|10|invalid name length| +|ErrInvalidTokenType|collection|11|invalid token type pattern found| +|ErrInvalidTokenIndex|collection|12|invalid token index pattern found| +|ErrCollectionExist|collection|13|collection already exists| +|ErrCollectionNotExist|collection|14|collection does not exists| +|ErrTokenTypeExist|collection|15|token type for contract_id, token-type already exists| +|ErrTokenTypeNotExist|collection|16|token type for contract_id, token-type does not exist| +|ErrTokenTypeFull|collection|17|all token type for contract_id are occupied| +|ErrTokenIndexFull|collection|18|all non-fungible token index for contract_id, token-type are occupied| +|ErrTokenIDFull|collection|19|all fungible token-id for contract_id are occupied| +|ErrTokenNoPermission|collection|20|account does not have the permission| +|ErrTokenAlreadyAChild|collection|21|token is already a child of some other| +|ErrTokenNotAChild|collection|22|token is not a child of some other| +|ErrTokenNotOwnedBy|collection|23|token is being not owned by| +|ErrTokenCannotTransferChildToken|collection|24|cannot transfer a child token| +|ErrTokenNotNFT|collection|25|token is not a NFT| +|ErrCannotAttachToItself|collection|26|cannot attach token to itself| +|ErrCannotAttachToADescendant|collection|27|cannot attach token to a descendant| +|ErrApproverProxySame|collection|28|approver is same with proxy| +|ErrCollectionNotApproved|collection|29|proxy is not approved on the collection| +|ErrCollectionAlreadyApproved|collection|30|proxy is already approved on the collection| +|ErrAccountExist|collection|31|account already exists| +|ErrAccountNotExist|collection|32|account does not exists| +|ErrInsufficientSupply|collection|33|insufficient supply| +|ErrInvalidCoin|collection|34|invalid coin| +|ErrInvalidChangesFieldCount|collection|35|invalid count of field changes| +|ErrEmptyChanges|collection|36|changes is empty| +|ErrInvalidChangesField|collection|37|invalid field of changes| +|ErrTokenIndexWithoutType|collection|38|There is a token index but no token type| +|ErrTokenTypeFTWithoutIndex|collection|39|There is a token type of ft but no token index| +|ErrInsufficientToken|collection|40|insufficient token| +|ErrDuplicateChangesField|collection|41|duplicate field of changes| +|ErrInvalidMetaLength|collection|42|invalid meta length| +|ErrSupplyOverflow|collection|43|supply for collection reached maximum| +|ErrEmptyField|collection|44|required field cannot be empty| +|ErrCompositionTooDeep|collection|45|cannot attach token (composition too deep)| +|ErrCompositionTooWide|collection|46|cannot attach token (composition too wide)| +|ErrBurnNonRootNFT|collection|47|cannot burn non-root NFTs| + +>You can also find detailed information in the following Errors.go files: + * [collection/errors.go](collection/errors.go) + +## Crisis + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrNoSender|crisis|2|sender address is empty| +|ErrUnknownInvariant|crisis|3|unknown invariant| + +>You can also find detailed information in the following Errors.go files: + * [crisis/types/errors.go](crisis/types/errors.go) + +## Distribution + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrEmptyDelegatorAddr|distribution|2|delegator address is empty| +|ErrEmptyWithdrawAddr|distribution|3|withdraw address is empty| +|ErrEmptyValidatorAddr|distribution|4|validator address is empty| +|ErrEmptyDelegationDistInfo|distribution|5|no delegation distribution info| +|ErrNoValidatorDistInfo|distribution|6|no validator distribution info| +|ErrNoValidatorCommission|distribution|7|no validator commission to withdraw| +|ErrSetWithdrawAddrDisabled|distribution|8|set withdraw address disabled| +|ErrBadDistribution|distribution|9|community pool does not have sufficient coins to distribute| +|ErrInvalidProposalAmount|distribution|10|invalid community pool spend proposal amount| +|ErrEmptyProposalRecipient|distribution|11|invalid community pool spend proposal recipient| +|ErrNoValidatorExists|distribution|12|validator does not exist| +|ErrNoDelegationExists|distribution|13|delegation does not exist| + +>You can also find detailed information in the following Errors.go files: + * [distribution/types/errors.go](distribution/types/errors.go) + +## Evidence + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrNoEvidenceHandlerExists|evidence|2|unregistered handler for evidence type| +|ErrInvalidEvidence|evidence|3|invalid evidence| +|ErrNoEvidenceExists|evidence|4|evidence does not exist| +|ErrEvidenceExists|evidence|5|evidence already exists| + +>You can also find detailed information in the following Errors.go files: + * [evidence/types/errors.go](evidence/types/errors.go) + +## Feegrant + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrFeeLimitExceeded|feegrant|2|fee limit exceeded| +|ErrFeeLimitExpired|feegrant|3|fee allowance expired| +|ErrInvalidDuration|feegrant|4|invalid duration| +|ErrNoAllowance|feegrant|5|no allowance| +|ErrNoMessages|feegrant|6|allowed messages are empty| +|ErrMessageNotAllowed|feegrant|7|message not allowed| + +>You can also find detailed information in the following Errors.go files: + * [feegrant/errors.go](feegrant/errors.go) + +## Foundation + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| + +>You can also find detailed information in the following Errors.go files: + * [foundation/errors.go](foundation/errors.go) + +## Gov + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrUnknownProposal|gov|2|unknown proposal| +|ErrInactiveProposal|gov|3|inactive proposal| +|ErrAlreadyActiveProposal|gov|4|proposal already active| +|ErrInvalidProposalContent|gov|5|invalid proposal content| +|ErrInvalidProposalType|gov|6|invalid proposal type| +|ErrInvalidVote|gov|7|invalid vote option| +|ErrInvalidGenesis|gov|8|invalid genesis state| +|ErrNoProposalHandlerExists|gov|9|no handler exists for proposal type| + +>You can also find detailed information in the following Errors.go files: + * [gov/types/errors.go](gov/types/errors.go) + +## Params + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrUnknownSubspace|params|2|unknown subspace| +|ErrSettingParameter|params|3|failed to set parameter| +|ErrEmptyChanges|params|4|submitted parameter changes are empty| +|ErrEmptySubspace|params|5|parameter subspace is empty| +|ErrEmptyKey|params|6|parameter key is empty| +|ErrEmptyValue|params|7|parameter value is empty| + +>You can also find detailed information in the following Errors.go files: + * [params/types/proposal/errors.go](params/types/proposal/errors.go) + +## Slashing + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrNoValidatorForAddress|slashing|2|address is not associated with any known validator| +|ErrBadValidatorAddr|slashing|3|validator does not exist for that address| +|ErrValidatorJailed|slashing|4|validator still jailed; cannot be unjailed| +|ErrValidatorNotJailed|slashing|5|validator not jailed; cannot be unjailed| +|ErrMissingSelfDelegation|slashing|6|validator has no self-delegation; cannot be unjailed| +|ErrSelfDelegationTooLowToUnjail|slashing|7|validator's self delegation less than minimum; cannot be unjailed| +|ErrNoSigningInfoFound|slashing|8|no validator signing info found| + +>You can also find detailed information in the following Errors.go files: + * [slashing/types/errors.go](slashing/types/errors.go) + +## Staking + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrEmptyValidatorAddr|staking|2|empty validator address| +|ErrNoValidatorFound|staking|3|validator does not exist| +|ErrValidatorOwnerExists|staking|4|validator already exist for this operator address; must use new validator operator address| +|ErrValidatorPubKeyExists|staking|5|validator already exist for this pubkey; must use new validator pubkey| +|ErrValidatorPubKeyTypeNotSupported|staking|6|validator pubkey type is not supported| +|ErrValidatorJailed|staking|7|validator for this address is currently jailed| +|ErrBadRemoveValidator|staking|8|failed to remove validator| +|ErrCommissionNegative|staking|9|commission must be positive| +|ErrCommissionHuge|staking|10|commission cannot be more than 100%| +|ErrCommissionGTMaxRate|staking|11|commission cannot be more than the max rate| +|ErrCommissionUpdateTime|staking|12|commission cannot be changed more than once in 24h| +|ErrCommissionChangeRateNegative|staking|13|commission change rate must be positive| +|ErrCommissionChangeRateGTMaxRate|staking|14|commission change rate cannot be more than the max rate| +|ErrCommissionGTMaxChangeRate|staking|15|commission cannot be changed more than max change rate| +|ErrSelfDelegationBelowMinimum|staking|16|validator's self delegation must be greater than their minimum self delegation| +|ErrMinSelfDelegationDecreased|staking|17|minimum self delegation cannot be decrease| +|ErrEmptyDelegatorAddr|staking|18|empty delegator address| +|ErrNoDelegation|staking|19|no delegation for (address, validator) tuple| +|ErrBadDelegatorAddr|staking|20|delegator does not exist with address| +|ErrNoDelegatorForAddress|staking|21|delegator does not contain delegation| +|ErrInsufficientShares|staking|22|insufficient delegation shares| +|ErrDelegationValidatorEmpty|staking|23|cannot delegate to an empty validator| +|ErrNotEnoughDelegationShares|staking|24|not enough delegation shares| +|ErrNotMature|staking|25|entry not mature| +|ErrNoUnbondingDelegation|staking|26|no unbonding delegation found| +|ErrMaxUnbondingDelegationEntries|staking|27|too many unbonding delegation entries for (delegator, validator) tuple| +|ErrNoRedelegation|staking|28|no redelegation found| +|ErrSelfRedelegation|staking|29|cannot redelegate to the same validator| +|ErrTinyRedelegationAmount|staking|30|too few tokens to redelegate (truncates to zero tokens)| +|ErrBadRedelegationDst|staking|31|redelegation destination validator not found| +|ErrTransitiveRedelegation|staking|32|redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation| +|ErrMaxRedelegationEntries|staking|33|too many redelegation entries for (delegator, src-validator, dst-validator) tuple| +|ErrDelegatorShareExRateInvalid|staking|34|cannot delegate to validators with invalid (zero) ex-rate| +|ErrBothShareMsgsGiven|staking|35|both shares amount and shares percent provided| +|ErrNeitherShareMsgsGiven|staking|36|neither shares amount nor shares percent provided| +|ErrInvalidHistoricalInfo|staking|37|invalid historical info| +|ErrNoHistoricalInfo|staking|38|no historical info found| +|ErrEmptyValidatorPubKey|staking|39|empty validator public key| + +>You can also find detailed information in the following Errors.go files: + * [staking/types/errors.go](staking/types/errors.go) + +## Token + +|Error Name|Codespace|Code|Description| +|:-|:-|:-|:-| +|ErrInvalidContractID|contract|2|invalid contractID| +|ErrContractNotExist|contract|3|contract does not exist| +|ErrTokenNotExist|token|2|token does not exist| +|ErrTokenNotMintable|token|3|token is not mintable| +|ErrInvalidTokenName|token|4|token name should not be empty| +|ErrInvalidTokenDecimals|token|5|token decimals should be within the range in 0 ~ 18| +|ErrInvalidAmount|token|6|invalid token amount| +|ErrInvalidImageURILength|token|7|invalid token uri length| +|ErrInvalidNameLength|token|8|invalid name length| +|ErrInvalidTokenSymbol|token|9|invalid token symbol| +|ErrTokenNoPermission|token|10|account does not have the permission| +|ErrAccountExist|token|11|account already exists| +|ErrAccountNotExist|token|12|account does not exists| +|ErrInsufficientBalance|token|13|insufficient balance| +|ErrSupplyExist|token|14|supply for token already exists| +|ErrInsufficientSupply|token|15|insufficient supply| +|ErrInvalidChangesFieldCount|token|16|invalid count of field changes| +|ErrEmptyChanges|token|17|changes is empty| +|ErrInvalidChangesField|token|18|invalid field of changes| +|ErrDuplicateChangesField|token|19|invalid field of changes| +|ErrInvalidMetaLength|token|20|invalid meta length| +|ErrSupplyOverflow|token|21|supply for token reached maximum| +|ErrApproverProxySame|token|22|approver is same with proxy| +|ErrTokenNotApproved|token|23|proxy is not approved on the token| +|ErrTokenAlreadyApproved|token|24|proxy is already approved on the token| + +>You can also find detailed information in the following Errors.go files: + * [token/class/errors.go](token/class/errors.go) + * [token/errors.go](token/errors.go) diff --git a/x/README.md b/x/README.md index 9579cebc3c..41120f07a8 100644 --- a/x/README.md +++ b/x/README.md @@ -26,3 +26,5 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio - [Upgrade](upgrade/spec/README.md) - Software upgrades handling and coordination. To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md). + +To learn more about the error information of modules, visit the [error documentation](./ERRORS.md).