# 2. Storage

Mobile devices are known for their limited resources and aggressive freeing of memory in case of low RAM or application suspension.

As discussed in the [Base Concepts document](./0.BaseConcepts.md), inside the Mobile SDK library all entities (connections, credentials, etc.) are represented as state machines. Most of the Mobile SDK operations will be performed with these state machines.

### How to work with state machines

The Mobile SDK separates state machine transitions and their persistence, because it gives us some benefits:
* flexibility regarding what storage will be used to store the data.
* flexibility regarding what information objects will be stored.
* reduction of the chance of data loss as the application stores data exactly once.

The state machines are pointed by an integer **handle**.
You will be passing a handle to perform some operations with a state machine.
Every mutating operation, e.g. accepting or rejecting, changes the internal state of the state machine referenced by the passed handle moving it into the next state.

Once the state of the state machine changes it's better to save it into the application storage.

The state machines can be **serialized** into a **JSON string** representation.

The next time you want to perform some operation with a state machine, its string representation should be taken from the application storage and **deserialized** by the SDK to the entity state machine.
The deserialization process returns a new **handle** integer value pointing to the recreated state machine object.

Most of the operations with entities have the following flow:
* Create Credential state machine based on Credential Offer and perform some operations.
* Serialize state machine and save resulting string into application storage for future use.
* Later when you need to do something with Credential state machine (e.g. you received a next message related to protocol) - deserialize the credential state machine from string and receive a new handle.
* With the usage of received handle perform a necessary operation (e.g. handle next message from the protocol).
* Serialize new credential state machine state into string.
* Save resulting string for future use.

In the following documents, we will highlight which operations mutate state machines and when you need save their serialized representation into application storage. 

### Information stored by Mobile SDK  

Despite the fact that Mobile SDK does not persist state machines it still has its own secure Wallet storage where it automatically securely save some pieces of secret information in encrypted form which cannot be read.
* **private key** which will be used to encrypt messages sent to your Cloud Agent. It will be created and sored during Cloud Agent provisioning  step.
* **private keys** which will be used to encrypt messages sent to another User. It will be created and sored during Connection establishing step.
* **credential master secret** which will be used for credentials blinding during the issuance process. It will be created and sored once on the first SDK initialization.
* **credential signatures**  which will be created by unblinding of a credential signature received from an issuer during the issuance process. It will be created and stored every time you receive a new credential.
* **credentials** will be stored in the wallet by default whenever a credential is accepted by the app's user. However, only the credential attributes along with their values are stored, not the credential metadata. If you need to be able to refer to a credential at any point (e.g. so that the app user can see the credentials in the wallet), you will need to store the credential ID in your app's database, along with any metadata you need. Metadata can be the time the credential was received, the name of the connection, etc. If your use case is just for the fulfillment of proof request, and you don't need to render credentials in the UI, you don't need to additionally save anything to your app's database. 

In the following documents, we will explain the meaning of these secrets in more details.

### Storage

As we mentioned before, applications have to care about persisting of state machines and other data.
There are two options where to store your data:
* Mobile SDK Wallet - as we mentioned at [Information stored by Mobile SDK](#information-stored-by-mobile-sdk) section, Mobile SDK has its own secure Wallet storage to store secrets.
These secrets cannot be read but Mobile SDK also provides a set of functions to write/read any data into the Wallet. 
  
    > The information is written into the Wallet in encrypted form. That encryption slightly affects storage performance.

    > In order to use Mobile SDK Wallet to store application data, you don't need any additional configuration or steps. It will be available after SDK initialization.

* Platform-specific storage - you also can configure and use any storage available on your application platform. 
  
    > The work of some platform-specific storage can be faster than Mobile SDK Wallet. 
  
    > You have to implement storage configuration and integration by yourself in the application.

### Mobile SDK Wallet API

Mobile SDK Wallet is built on top of SQLite database applying additional encryption to the records.
There is a single table containing the following columns:
* `type` - entity type
* `id` - id of the record
* `value` - record value
* `tags` - record tags used for search and storing meta information as json `{ "tagName1": <str>, ...}`

The combination of `type` and `id` values must be unique.

* **Add a record to the Wallet**
    * ##### iOS
        ```objC
        (void)addRecordWallet:(NSString *)recordType
                     recordId:(NSString *)recordId
                  recordValue:(NSString *)recordValue
                   completion:(void (^)(NSError *error))completion) {
                  // ...
              }];
        ```
    * ##### Android
        ```java
            WalletApi.addRecordWallet(recordType, recordId, recordValue).get();
        ``` 

* **Update the value of a record in the Wallet**
    * ##### iOS
        ```objC
        (void)updateRecordWallet:(NSString *)recordType
                    withRecordId:(NSString *)recordId
                 withRecordValue:(NSString *)recordValue
                  withCompletion:(void (^)(NSError *error))completion {
                      // ...
                  }];
        ```
    * ##### Android
        ```java
            WalletApi.updateRecordWallet(recordType, recordId, recordValue).get();
        ``` 

* **Get record from the Wallet**
    * ##### iOS
        ```objC
        (void)getRecordWallet:(NSString *)recordType
                     recordId:(NSString *)recordId
                   completion:(void (^)(NSError *error, NSString* walletValue))completion {
                      // ...
                  }];
        ```
    * ##### Android
        ```java
            WalletApi.getRecordWallet(recordType, recordId, optionsJson).get();
        ``` 

* **Delete a record from the Wallet**
    * ##### iOS
        ```objC
        (void)deleteRecordWallet:(NSString *)recordType
                        recordId:(NSString *)recordId
                     completion:(void (^)(NSError *error))completion {
                         // ...
                    }];
        ```
    * ##### Android
        ```java
            WalletApi.deleteRecordWallet(recordType, recordId).get();
        ``` 

* **Add tags to a record in the Wallet**
    * recordTags - Tags to add for the record associated with the id and type `{"Tag1": "value1", "Tag2": "value2"}`.
    * ##### iOS
        ```objC
        (void)walletAddRecordTags:(NSString *)recordType
                         recordId:(NSString *)recordId
                       recordTags:(NSString *)recordTags
                       completion:(void (^)(NSError *error))completion {
                      // ...
                  }];
        ```
    * ##### Android
        ```java
            WalletApi.addRecordTags(recordType, recordId, recordTags).get();
        ``` 

* **Update tags of a record in the Wallet**
    * recordTags - New tags for the record associated with the id and type `{"Tag1": "value1", "Tag2": "value2"}`.
    * ##### iOS
        ```objC
        (void)walletUpdateRecordTags:(NSString *)recordType
                            recordId:(NSString *)recordId
                          recordTags:(NSString *)recordTags
                          completion:(void (^)(NSError *error))completion {
                      // ...
                  }];
        ```
    * ##### Android
        ```java
            WalletApi.addRecordTags(recordType, recordId, recordTags).get();
        ``` 

* **Delete tags from a record in the Wallet**
    * recordTags - Tags names as JSON array to remove from the record associated with the id and type `["Tag1", "Tag2"]`.
    * ##### iOS
        ```objC
        (void)walletDeleteRecordTags:(NSString *)recordType
                            recordId:(NSString *)recordId
                          recordTags:(NSString *)recordTags
                          completion:(void (^)(NSError *error))completion {
                      // ...
                  }];
        ```
    * ##### Android
        ```java
            WalletApi.deleteRecordTags(recordType, recordId, recordTags).get();
        ``` 

* **Open search iterator for records in the Wallet**
  
    * query - MongoDB style query to wallet record tags:
        ```
          {
            "tagName": "tagValue",
            $or: {
              "tagName2": { $regex: 'pattern' },
              "tagName3": { $gte: 123 },
            },
          }
        ```
    * options
        ```
          {
             retrieveRecords: (optional, true by default) If false only "counts" will be calculated,
             retrieveTotalCount: (optional, false by default) Calculate total count,
             retrieveType: (optional, false by default) Retrieve record type,
             retrieveValue: (optional, true by default) Retrieve record value,
             retrieveTags: (optional, true by default) Retrieve record tags,
          }
      ```

    * ##### iOS
        ```objC
        (void)walletOpenSearch:(NSString *)type
                         query:(NSString *)query
                       options:(NSString *)options
                    completion:(void (^)(NSError *error, NSInteger searchHandle)) completion {
                         // ...
                    }];
        ```
    * ##### Android
        ```java
            int handle = WalletApi.openSearch(recordType, query, options).get();
        ``` 

* **Fetch next records for a wallet search**
    * ##### iOS
        ```objC
        (void) walletSearchNextRecords:(NSInteger)searchHandle
                                 count:(NSInteger)count
                            completion:(void (^)(NSError *error, NSString *records))completion {
                            // ...
                            }];
        ```
    * ##### Android
        ```java
            String records = WalletApi.searchNextRecords(searchHandle, count).get();
        ``` 
    * records
        ```
           {
             totalCount: <int>, // present only if retrieveTotalCount set to true
             records: [{ // present only if retrieveRecords set to true
                 id: "Some id",
                 type: "Some type", // present only if retrieveType set to true
                 value: "Some value", // present only if retrieveValue set to true
                 tags: <tags json>, // present only if retrieveTags set to true
             }],
           }
        ```

* **Close a search**
    * ##### iOS
        ```objC
        (void) walletCloseSearch:(NSInteger)searchHandle
                      completion:(void (^)(NSError *error))completion {
                            // ...
                      }];
        ```
    * ##### Android
        ```java
            WalletApi.closeSearch(searchHandle).get();
        ``` 
