github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/docs/architecture/adr-011-generalize-genesis-accounts.md (about)

     1  # ADR 011: Generalize Genesis Accounts
     2  
     3  ## Changelog
     4  
     5  - 2019-08-30: initial draft
     6  
     7  ## Context
     8  
     9  Currently, the SDK allows for custom account types; the `auth` keeper stores any type fulfilling its `Account` interface. However `auth` does not handle exporting or loading accounts to/from a genesis file, this is done by `genaccounts`, which only handles one of 4 concrete account types (`BaseAccount`, `ContinuousVestingAccount`, `DelayedVestingAccount` and `ModuleAccount`).
    10  
    11  Projects desiring to use custom accounts (say custom vesting accounts) need to fork and modify `genaccounts`.
    12  
    13  ## Decision
    14  
    15  In summary, we will (un)marshal all accounts (interface types) directly using amino, rather than converting to `genaccounts`’s `GenesisAccount` type. Since doing this removes the majority of `genaccounts`'s code, we will merge `genaccounts` into `auth`. Marshalled accounts will be stored in `auth`'s genesis state.
    16  
    17  Detailed changes:
    18  
    19  ### 1) (Un)Marshal accounts directly using amino
    20  
    21  The `auth` module's `GenesisState` gains a new field `Accounts`. Note these aren't of type `exported.Account` for reasons outlined in section 3.
    22  
    23  ```go
    24  // GenesisState - all auth state that must be provided at genesis
    25  type GenesisState struct {
    26      Params   Params           `json:"params" yaml:"params"`
    27      Accounts []GenesisAccount `json:"accounts" yaml:"accounts"`
    28  }
    29  ```
    30  
    31  Now `auth`'s `InitGenesis` and `ExportGenesis` (un)marshal accounts as well as the defined params.
    32  
    33  ```go
    34  // InitGenesis - Init store state from genesis data
    35  func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) {
    36      ak.SetParams(ctx, data.Params)
    37      // load the accounts
    38      for _, a := range data.Accounts {
    39          acc := ak.NewAccount(ctx, a) // set account number
    40          ak.SetAccount(ctx, acc)
    41      }
    42  }
    43  
    44  // ExportGenesis returns a GenesisState for a given context and keeper
    45  func ExportGenesis(ctx sdk.Context, ak AccountKeeper) GenesisState {
    46      params := ak.GetParams(ctx)
    47  
    48      var genAccounts []exported.GenesisAccount
    49      ak.IterateAccounts(ctx, func(account exported.Account) bool {
    50          genAccount := account.(exported.GenesisAccount)
    51          genAccounts = append(genAccounts, genAccount)
    52          return false
    53      })
    54  
    55      return NewGenesisState(params, genAccounts)
    56  }
    57  ```
    58  
    59  ### 2) Register custom account types on the `auth` codec
    60  
    61  The `auth` codec must have all custom account types registered to marshal them. We will follow the pattern established in `gov` for proposals.
    62  
    63  An example custom account definition:
    64  
    65  ```go
    66  import authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    67  
    68  // Register the module account type with the auth module codec so it can decode module accounts stored in a genesis file
    69  func init() {
    70      authtypes.RegisterAccountTypeCodec(ModuleAccount{}, "cosmos-sdk/ModuleAccount")
    71  }
    72  
    73  type ModuleAccount struct {
    74      ...
    75  ```
    76  
    77  The `auth` codec definition:
    78  
    79  ```go
    80  var ModuleCdc *codec.Codec
    81  
    82  func init() {
    83      ModuleCdc = codec.New()
    84      // register module msg's and Account interface
    85      ...
    86      // leave the codec unsealed
    87  }
    88  
    89  // RegisterAccountTypeCodec registers an external account type defined in another module for the internal ModuleCdc.
    90  func RegisterAccountTypeCodec(o interface{}, name string) {
    91      ModuleCdc.RegisterConcrete(o, name, nil)
    92  }
    93  ```
    94  
    95  ### 3) Genesis validation for custom account types
    96  
    97  Modules implement a `ValidateGenesis` method. As `auth` does not know of account implementations, accounts will need to validate themselves.
    98  
    99  We will unmarshal accounts into a `GenesisAccount` interface that includes a `Validate` method.
   100  
   101  ```go
   102  type GenesisAccount interface {
   103      exported.Account
   104      Validate() error
   105  }
   106  ```
   107  
   108  Then the `auth` `ValidateGenesis` function becomes:
   109  
   110  ```go
   111  // ValidateGenesis performs basic validation of auth genesis data returning an
   112  // error for any failed validation criteria.
   113  func ValidateGenesis(data GenesisState) error {
   114      // Validate params
   115      ...
   116  
   117      // Validate accounts
   118      addrMap := make(map[string]bool, len(data.Accounts))
   119      for _, acc := range data.Accounts {
   120  
   121          // check for duplicated accounts
   122          addrStr := acc.GetAddress().String()
   123          if _, ok := addrMap[addrStr]; ok {
   124              return fmt.Errorf("duplicate account found in genesis state; address: %s", addrStr)
   125          }
   126          addrMap[addrStr] = true
   127  
   128          // check account specific validation
   129          if err := acc.Validate(); err != nil {
   130              return fmt.Errorf("invalid account found in genesis state; address: %s, error: %s", addrStr, err.Error())
   131          }
   132  
   133      }
   134      return nil
   135  }
   136  ```
   137  
   138  ### 4) Move add-genesis-account cli to `auth`
   139  
   140  The `genaccounts` module contains a cli command to add base or vesting accounts to a genesis file.
   141  
   142  This will be moved to `auth`. We will leave it to projects to write their own commands to add custom accounts. An extensible cli handler, similar to `gov`, could be created but it is not worth the complexity for this minor use case.
   143  
   144  ### 5) Update module and vesting accounts
   145  
   146  Under the new scheme, module and vesting account types need some minor updates:
   147  
   148  - Type registration on `auth`'s codec (shown above)
   149  - A `Validate` method for each `Account` concrete type
   150  
   151  ## Status
   152  
   153  Proposed
   154  
   155  ## Consequences
   156  
   157  ### Positive
   158  
   159  - custom accounts can be used without needing to fork `genaccounts`
   160  - reduction in lines of code
   161  
   162  ### Negative
   163  
   164  ### Neutral
   165  
   166  - `genaccounts` module no longer exists
   167  - accounts in genesis files are stored under `accounts` in `auth` rather than in the `genaccounts` module.
   168  -`add-genesis-account` cli command now in `auth`
   169  
   170  ## References