github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/docs/architecture/adr-012-state-accessors.md (about)

     1  # ADR 012: State Accessors
     2  
     3  ## Changelog
     4  
     5  - 2019 Sep 04: Initial draft
     6  
     7  ## Context
     8  
     9  SDK modules currently use the `KVStore` interface and `Codec` to access their respective state. While
    10  this provides a large degree of freedom to module developers, it is hard to modularize and the UX is
    11  mediocre.
    12  
    13  First, each time a module tries to access the state, it has to marshal the value and set or get the
    14  value and finally unmarshal. Usually this is done by declaring `Keeper.GetXXX` and `Keeper.SetXXX` functions,
    15  which are repetitive and hard to maintain.
    16  
    17  Second, this makes it harder to align with the object capability theorem: the right to access the
    18  state is defined as a `StoreKey`, which gives full access on the entire Merkle tree, so a module cannot
    19  send the access right to a specific key-value pair (or a set of key-value pairs) to another module safely.
    20  
    21  Finally, because the getter/setter functions are defined as methods of a module's `Keeper`, the reviewers
    22  have to consider the whole Merkle tree space when they reviewing a function accessing any part of the state.
    23  There is no static way to know which part of the state that the function is accessing (and which is not).
    24  
    25  ## Decision
    26  
    27  We will define a type named `Value`:
    28  
    29  ```go
    30  type Value struct {
    31    m   Mapping
    32    key []byte
    33  }
    34  ```
    35  
    36  The `Value` works as a reference for a key-value pair in the state, where `Value.m` defines the key-value
    37  space it will access and `Value.key` defines the exact key for the reference.
    38  
    39  We will define a type named `Mapping`:
    40  
    41  ```go
    42  type Mapping struct {
    43    storeKey sdk.StoreKey
    44    cdc      *codec.Codec
    45    prefix   []byte
    46  }
    47  ```
    48  
    49  The `Mapping` works as a reference for a key-value space in the state, where `Mapping.storeKey` defines
    50  the IAVL (sub-)tree and `Mapping.prefix` defines the optional subspace prefix.
    51  
    52  We will define the following core methods for the `Value` type:
    53  
    54  ```go
    55  // Get and unmarshal stored data, noop if not exists, panic if cannot unmarshal
    56  func (Value) Get(ctx Context, ptr interface{}) {}
    57  
    58  // Get and unmarshal stored data, return error if not exists or cannot unmarshal
    59  func (Value) GetSafe(ctx Context, ptr interface{}) {}
    60  
    61  // Get stored data as raw byte slice
    62  func (Value) GetRaw(ctx Context) []byte {}
    63  
    64  // Marshal and set a raw value
    65  func (Value) Set(ctx Context, o interface{}) {}
    66  
    67  // Check if a raw value exists
    68  func (Value) Exists(ctx Context) bool {}
    69  
    70  // Delete a raw value value
    71  func (Value) Delete(ctx Context) {}
    72  ```
    73  
    74  We will define the following core methods for the `Mapping` type:
    75  
    76  ```go
    77  // Constructs key-value pair reference corresponding to the key argument in the Mapping space
    78  func (Mapping) Value(key []byte) Value {}
    79  
    80  // Get and unmarshal stored data, noop if not exists, panic if cannot unmarshal
    81  func (Mapping) Get(ctx Context, key []byte, ptr interface{}) {}
    82  
    83  // Get and unmarshal stored data, return error if not exists or cannot unmarshal
    84  func (Mapping) GetSafe(ctx Context, key []byte, ptr interface{})
    85  
    86  // Get stored data as raw byte slice
    87  func (Mapping) GetRaw(ctx Context, key []byte) []byte {}
    88  
    89  // Marshal and set a raw value
    90  func (Mapping) Set(ctx Context, key []byte, o interface{}) {}
    91  
    92  // Check if a raw value exists
    93  func (Mapping) Has(ctx Context, key []byte) bool {}
    94  
    95  // Delete a raw value value
    96  func (Mapping) Delete(ctx Context, key []byte) {}
    97  ```
    98  
    99  Each method of the `Mapping` type that is passed the arugments `ctx`, `key`, and `args...` will proxy
   100  the call to `Mapping.Value(key)` with arguments `ctx` and `args...`.
   101  
   102  In addition, we will define and provide a common set of types derived from the `Value` type:
   103  
   104  ```go
   105  type Boolean struct { Value }
   106  type Enum struct { Value }
   107  type Integer struct { Value; enc IntEncoding }
   108  type String struct { Value }
   109  // ...
   110  ```
   111  
   112  Where the encoding schemes can be different, `o` arguments in core methods are typed, and `ptr` arguments
   113  in core methods are replaced by explicit return types.
   114  
   115  Finally, we will define a family of types derived from the `Mapping` type:
   116  
   117  ```go
   118  type Indexer struct {
   119    m   Mapping
   120    enc IntEncoding
   121  }
   122  ```
   123  
   124  Where the `key` argument in core method is typed.
   125  
   126  Some of the properties of the accessor types are:
   127  
   128  - State access happens only when a function which takes a `Context` as an argument is invoked
   129  - Accessor type structs give rights to access the state only that the struct is referring, no other
   130  - Marshalling/Unmarshalling happens implicitly within the core methods
   131  
   132  ## Status
   133  
   134  Proposed
   135  
   136  ## Consequences
   137  
   138  ### Positive
   139  
   140  - Serialization will be done automatically
   141  - Shorter code size, less boilerplate, better UX
   142  - References to the state can be transferred safely
   143  - Explicit scope of accessing
   144  
   145  ### Negative
   146  
   147  - Serialization format will be hidden
   148  - Different architecture from the current, but the use of accessor types can be opt-in
   149  - Type-specific types (e.g. `Boolean` and `Integer`) have to be defined manually
   150  
   151  ### Neutral
   152  
   153  ## References
   154  
   155  - [#4554](https://github.com/cosmos/cosmos-sdk/issues/4554)