Skip to content

Commit

Permalink
feat: 0.5 migration guide (#166)
Browse files Browse the repository at this point in the history

Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra authored Jun 4, 2024
1 parent 6c2e77f commit 8467ebf
Show file tree
Hide file tree
Showing 11 changed files with 1,606 additions and 226 deletions.
4 changes: 2 additions & 2 deletions guides/getting-started/set-up/anoncreds.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ When using Credo with AnonCreds, there are a few extra dependencies that need to
# Node.JS

```console
yarn add @credo-ts/anoncreds@^0.5.0 @hyperledger/anoncreds-nodejs@^0.2.0
yarn add @credo-ts/anoncreds@^0.5.3 @hyperledger/anoncreds-nodejs@^0.2.2
```

# React Native

```console
yarn add @credo-ts/anoncreds@^0.5.0 @hyperledger/anoncreds-react-native@^0.2.0
yarn add @credo-ts/anoncreds@^0.5.3 @hyperledger/anoncreds-react-native@^0.2.2
```

<!--/tabs-->
Expand Down
4 changes: 2 additions & 2 deletions guides/getting-started/set-up/aries-askar.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ When using Credo with Aries Askar, there are a few extra dependencies that need
# Node.JS

```console
yarn add @credo-ts/askar@^0.5.0 @hyperledger/aries-askar-nodejs@^0.2.0
yarn add @credo-ts/askar@^0.5.3 @hyperledger/aries-askar-nodejs@^0.2.1
```

# React Native

```console
yarn add @credo-ts/askar@^0.5.0 @hyperledger/aries-askar-react-native@^0.2.0
yarn add @credo-ts/askar@^0.5.3 @hyperledger/aries-askar-react-native@^0.2.1
```

<!--/tabs-->
Expand Down
6 changes: 4 additions & 2 deletions guides/getting-started/set-up/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ For Credo `0.5.x`, **the following features are experimental**:
- Using multi-tenancy from the `@credo-ts/tenants` module
- Using BBS+ Signatures from the `@credo-ts/bbs-signatures` module
- Using the cheqd module from the `@credo-ts/cheqd` module
- Using DIF Presentation Exchange
- Using AnonCreds in the W3C Verifiable Credential format

:::

Expand All @@ -32,13 +34,13 @@ First we have to install the minimal amount of dependencies that are required fo
# Node.JS

```console
yarn add @credo-ts/core@^0.5.0 @credo-ts/node@^0.5.0
yarn add @credo-ts/core@^0.5.3 @credo-ts/node@^0.5.3
```

# React Native

```console
yarn add @credo-ts/core@^0.5.0 @credo-ts/react-native@^0.5.0 react-native-fs react-native-get-random-values
yarn add @credo-ts/core@^0.5.3 @credo-ts/react-native@^0.5.3 react-native-fs react-native-get-random-values
```

<!--/tabs-->
Expand Down
4 changes: 2 additions & 2 deletions guides/getting-started/set-up/indy-vdr.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ When using Credo with Indy VDR, there are a few extra dependencies that need to
# Node.JS

```console
yarn add @credo-ts/indy-vdr@^0.5.0 @hyperledger/indy-vdr-nodejs@^0.2.0
yarn add @credo-ts/indy-vdr@^0.5.3 @hyperledger/indy-vdr-nodejs@^0.2.2
```

# React Native

```console
yarn add @credo-ts/indy-vdr@^0.5.0 @hyperledger/indy-vdr-react-native@^0.2.0
yarn add @credo-ts/indy-vdr@^0.5.3 @hyperledger/indy-vdr-react-native@^0.2.2
```

<!--/tabs-->
Expand Down
3 changes: 1 addition & 2 deletions guides/tutorials/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import DocCardList from '@theme/DocCardList';
# Tutorials

In this section we will explain some features that everyone will use. This
includes setting up your Aries agent, creating a connection between Aries
agents, issuing a credential and verifying a proof.
includes setting up your Credo agent, creating a connection between Aries agents, issuing a credential and verifying a proof.

<DocCardList />
93 changes: 86 additions & 7 deletions guides/updating/update-assistant.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,28 @@ The Update Assistant helps you update the storage objects from Credo to newer ve
- [Storing the agent storage version outside of the agent storage](#storing-the-agent-storage-version-outside-of-the-agent-storage)
- [Automatically update on agent startup](#automatically-update-on-agent-startup)
- [Backups](#backups)
- [Disabling backups](#disabling-backups)
- [Tenant Migration](#tenant-migration)
- [Automatically update on tenant startup](#automatically-update-on-tenant-startup)
- [Manually upgrading tenant storage](#manually-upgrading-tenant-storage)

## Update Strategies

There are three options on how to leverage the update assistant on agent startup:

1. Manually instantiating the update assistant on agent startup
2. Storing the agent storage version outside of the agent storage
3. Automatically update on agent startup
- [Update Strategies](#update-strategies)
- [Manually instantiating the update assistant on agent startup](#manually-instantiating-the-update-assistant-on-agent-startup)
- [Storing the agent storage version outside of the agent storage](#storing-the-agent-storage-version-outside-of-the-agent-storage)
- [Automatically update on agent startup](#automatically-update-on-agent-startup)
- [Backups](#backups)
- [Disabling backups](#disabling-backups)
- [Tenant Migration](#tenant-migration)
- [Automatically update on tenant startup](#automatically-update-on-tenant-startup)
- [Manually upgrading tenant storage](#manually-upgrading-tenant-storage)

Note that the Update Assistant only supports updating the root wallet storage. If you are leveraging the tenants module, read [Tenant Migration](#tenant-migration) for more information on how to update storage for each tenant.

In addition, for all update methods you can configure whether a backup should be created before the update process starts. In the case the upgrade fails, the backup will be restored. In general we recommend to keep this option enabled (it is enabled by default), but there are a few important exceptions so make sure to read the section on [backups](#backups) carefully for more information.

### Manually instantiating the update assistant on agent startup

Expand Down Expand Up @@ -47,7 +61,11 @@ await updateAssistant.initialize()

// Check if the agent is up to date, if not call update
if (!(await updateAssistant.isUpToDate())) {
await updateAssistant.update()
await updateAssistant.update({
// If you don't want to create a backup before the update process starts
// (see )
createBackupBeforeUpdate: false,
})
}

// Once finished initialize the agent. You should do this on every launch of the agent
Expand Down Expand Up @@ -105,6 +123,12 @@ await agent.initialize()

This is by far the easiest way to update the agent, but has the least amount of flexibility and is not configurable. This means you will have to use the default update options to update the agent storage. You can find the default update config in the respective version migration guides (e.g. in [0.1-to-0.2](/guides/updating/versions/0.1-to-0.2.md)).

:::caution

If you're using the `autoUpdateStorageOnStartup` option and hosting multiple Credo instances that point to the same database, you need to make sure that they won't all try to update the storage on startup. Only one instance should try to update the storage, and thus in cases where multiple instances are hosted pointing to the same database, this approach is not recommended.

:::

```ts
import { UpdateAssistant, Agent } from '@credo-ts/core'

Expand All @@ -116,6 +140,7 @@ const agent = new Agent({
config: {
...config,
autoUpdateStorageOnStartup: true,
createBackupBeforeStorageUpdate: true,
},
dependencies: agentDependencies,
})
Expand All @@ -133,6 +158,60 @@ The backups can be found at the following locations. The `backupIdentifier` is g
- Backup path: `${agent.config.fileSystem.basePath}/afj/migration/backup/${backupIdentifier}`
- Migration backup: `${agent.config.fileSystem.basePath}/afj/migration/backup/${backupIdentifier}-error`

> In the future the backup assistant will make a number of improvements to the recovery process. Namely:
>
> - Do not throw an error if the update fails, but rather return an object that contains the status, and include the backup paths and backup identifiers.
### Disabling backups

In general we recommend keeping backups before storage updates enabled. However, there are a few scenarios where you should disable backups in Credo before updating the storage:

- You are using Aries Askar with an SQLite database and multi-tenancy with `AskarMultiWalletDatabaseScheme.ProfilePerWallet` as the database scheme. Credo supports creating backups of SQLite databases, however as as each tenant is stored as a profile in the same database, if a backup is restored it will overwrite the storage of the whole database, and thus for all tenants. In future versions we will add support for more granular control of the backup.
- You are using Aries Askar with a Postgres database. We don't support creating backups for Postgres, and we advice you to create a backup of your database yourself before updating the storage.

## Tenant Migration

Migration of tenant storage is an additional process that needs to be performed when updating to a new breaking version of Credo. When you have migrated the storage of the root wallet, you can start up the agent and use it for the root wallet. But the tenant will still be using an older version of the storage.

:::info

Future versions of Credo are expected to work with the latest two major storage versions, writing using the latest format, but allowing to read also the previous storage format version. This allows to gradually upgrade your infrastructure to a new version, requiring as minimal downtime as possible.

:::

:::caution

If you're using an Aries Askar with an SQLite database while also leveraging multi-tenancy and using `AskarMultiWalletDatabaseScheme.ProfilePerWallet` as the database scheme, you need to make sure to disable `backupBeforeStorageUpdate` in the `updateOptions` when updating the storage of a tenant. See [Disabling backups](#disabling-backups) for more information.

:::

### Automatically update on tenant startup

The `autoUpdateStorageOnStartup` also works for tenants within an agent, meaning that you can automatically update the storage of a tenant when the tenant is first opened after the upgrade. Compared to the root wallet, which is updated when the agent starts, a tenant will be automatically upgraded when the tenant is first opened.

The same rules apply as with the auto updating of storage on startup, so make sure to read section on [Automatically update on agent startup](#automatically-update-on-agent-startup).

:::caution

If you're using a multi-instance setup with the same storage backend, you need to make sure that only one instance updates the storage of a tenant. This is tricky to do with auto updating, and therefore we recommend to use the manual approach.

:::

### Manually upgrading tenant storage

If you want to manually upgrade the storage of a tenant, you can use the `getTenantsWithOutdatedStorage` method to get a list of tenants that have outdated storage. Then you can use the `updateTenantStorage` method to update the storage of a tenant. This method will return a promise that resolves when the storage has been updated. If the storage is already up to date, the promise will resolve immediately. If an error occurs during the updating, an error will be thrown, just like if you would use the Update Assistant.

```ts
const outdatedTenantsAfterUpdate = await agent.modules.tenants.getTenantsWithOutdatedStorage()

for (const tenant of outdatedTenantsAfterUpdate) {
await agent.modules.tenants.updateTenantStorage({
tenantId: tenant.id,
updateOptions: {
// NOTE: if you're using Askar with SQLite and AskarMultiWalletDatabaseScheme.ProfilePerWallet, OR you use Postgres, you should disable backups
// by credo and create them manually beforehand.
createBackupBeforeUpdate: true,
},
})
}
```

You can use the manual approach to update the storage of a tenant, even while `autoUpdateStorageOnStartup` is enabled, but you need to make sure that the auto update won't be run for the tenant you are manually updating, so we recommend to disable `autoUpdateStorageOnStartup` when manually updating the storage of a tenant.

After you've upgraded the storage of a tenant, you can use the tenant as usual.
79 changes: 47 additions & 32 deletions guides/updating/update-indy-sdk-to-askar.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This documentation explains the process of migrating your Indy SDK wallet to [Ar

:::danger

While the migration script technically works on node.js, it is strongly advised not to use it, yet. The migration of issuer records (such as Schemas and Credential Definitions) is not implemented yet. When a credential definition is detected it will revert the migration process and no harm is done.
While the migration script technically works on Node.JS, it is strongly advised not to use it, yet. The migration of issuer records (such as Schemas and Credential Definitions) is not implemented yet. When a credential definition is detected it will revert the migration process and no harm is done.

:::

Expand Down Expand Up @@ -84,10 +84,30 @@ Updating does not require a lot of code, but must be done with caution.

It is very important to note that the migration script only has to be run once. If it runs for a second time, it will error saying that the database is already migrated. Also, when the migration is finished, it is common practice to store this state in your persistent app storage. This script does not provide a way to detect if an update has happened, so storing this value will prevent the script from running every time. For more information regarding this topic, please check out [Update Assistant](./update-assistant.md#storing-the-agent-storage-version-outside-of-the-agent-storage).

### add the required dependencies
### Migrate code to Aries Askar, Indy VDR, AnonCreds.

Since Credo 0.4, there have been three new packages introduced that replace Indy SDK: Aries Askar (secure storage and cryptography), Indy VDR (integration with Hyperledger Indy blockchain), and AnonCreds (AnonCreds credential format).

Before setting up the migration script for Aries Askar (the storage), it is advised to first update your code with the new dependencies, and test it in a fresh environment to make sure everything works as expected.

To update your code to use the new packages, remove the `@aries-framework/indy-sdk`, `indy-sdk`, `indy-sdk-react-native`, `@types/indy-sdk` and `@types/indy-sdk-react-native` packages from the dependencies of your project, and remove all related imports from your code.

Then, setup the required dependencies for Aries Askar, Indy VDR, and AnonCreds. It is not required to set up all dependencies. This guide focuses on migration the storage from Indy SDK to Aries Askar, so only the Aries Askar dependency is required.

To setup the new dependencies, follow the getting started guide for each package:

- [Aries Askar](../getting-started/set-up/aries-askar.md)
- [AnonCreds](../getting-started/set-up/anoncreds.md)
- [Indy VDR](../getting-started/set-up/indy-vdr.md)

Once this has been set-up, make sure all code works on a **fresh environment** before continuing with the migration script.

### Add the required dependencies

Once all the new dependencies have been configured for your platform, you can add the migration script to your project:

```sh
yarn add @hyperledger/aries-askar-react-native @credo-ts/indy-sdk-to-askar-migration react-native-fs
yarn add @credo-ts/indy-sdk-to-askar-migration@^0.5.3
```

Below is the minimal code required for the migration to work. It is recommended to turn the logger on as it gives a lot of information regarding the migration.
Expand All @@ -99,7 +119,7 @@ The agent is not allowed to be initialized to run this script. This makes sure n
:::

```typescript
import { agentDependencies } from '@credo-ts/react-native'
import { agentDependencies } from '@credo-ts/react-native' // or @credo-ts/node
import { AskarModule } from '@credo-ts/askar'
import { IndySdkToAskarMigrationUpdater } from '@credo-ts/indy-sdk-to-askar-migration'
import { ariesAskar } from '@hyperledger/aries-askar-react-native'
Expand All @@ -109,53 +129,48 @@ const oldAgent = new Agent({
/* ... */
},
modules: {
// ... other modules (including optionally IndyVdrModule and AnonCredsModule)
ariesAskar: new AskarModule({
ariesAskar,
}),
},
dependencies: agentDependencies,
})

const dbPath = '' // see section below
// See section below for getting the database path
const dbPath = getMobileIndySdkDatabasePath(oldAgent.config.walletConfig.id)

const updater = await IndySdkToAskarMigrationUpdater.initialize({ dbPath, agent })
const updater = await IndySdkToAskarMigrationUpdater.initialize({ dbPath, agent: oldAgent })
await updater.update()
```

### Getting the database path

#### Android
#### React Native

On android, the database is commonly located under the `ExternalDirectoryPath`.
On Android, the database is commonly located under the `ExternalDirectoryPath`. If you did not follow the default Indy SDK for React Native setup on Android, your path might differ. Check out [Indy SDK React Native Android Setup](https://github.com/hyperledger-archives/indy-sdk-react-native#5-load-indy-library) for the default behavior.

If you did not follow the default indy-sdk for React Native setup, your path might differ. Check out [step 5 of the Android setup for Indy SDK React Native](https://github.com/hyperledger/indy-sdk-react-native#5-load-indy-library) for the default behavior.
On iOS, the database is commonly located under the `DocumentDirectoryPath`. For iOS this can only change if your phone does not have the `HOME` environment variable set. This is not usual behavior, and if `HOME` is not set, the `base` in the code section below will be `/home/indy/Documents`.

To get the path to the database, you can use the following code, where `walletId` is the `walletConfig.id`.

```typescript
import { Platform } from 'react-native'
import fs from 'react-native-fs'

const base = fs.ExternalDirectoryPath
const indyClient = '.indy_client'
const wallet = 'wallet'
const walletId = agent.config.walletConfig.id
const file = 'sqlite.db'

const dbPath = `${base}/${indyClient}/${wallet}/${walletId}/${file}`
/**
* Get the path to and Indy SDK SQlite wallet database on mobile.
*
* @note this assumes you are using the default configuration.
* If you are not, you will need to adjust the path accordingly.
*/
function getMobileIndySdkDatabasePath(walletId: string) {
const base = Platform.OS === 'android' ? fs.ExternalDirectoryPath : fs.DocumentDirectoryPath

return `${base}/.indy_client/wallet/${walletId}/sqlite.db`
}
```

#### iOS

On iOS, the database is commonly located under the `DocumentDirectoryPath`.
#### Node.JS

For iOS this can only change if your phone does not have the `HOME` environment variable set. This is not usual behavior, and if `HOME` is not set, the `base` in the code section below will be `/home/indy/Documents`.

```typescript
import fs from 'react-native-fs'

const base = fs.DocumentDirectoryPath
const indyClient = '.indy_client'
const wallet = 'wallet'
const walletId = agent.config.walletConfig.id
const file = 'sqlite.db'

const dbPath = `${base}/${indyClient}/${wallet}/${walletId}/${file}`
```
Migration of data from Indy SDK to Aries Askar is not supported yet in Node.JS. If you are using Node.JS or Postgres and need to update to Aries Askar, please open an issue on [GitHub](https://github.com/openwallet-foundation/credo-ts).
Loading

0 comments on commit 8467ebf

Please sign in to comment.