Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow for lazy wallet initialization #331

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/__tests__/agents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { Subject } from 'rxjs'

import { Agent } from '../agent/Agent'

import { SubjectInboundTransporter, SubjectOutboundTransporter, waitForBasicMessage, getBaseConfig } from './helpers'
import {
SubjectInboundTransporter,
SubjectOutboundTransporter,
waitForBasicMessage,
getBaseConfig,
closeAndDeleteWallet,
} from './helpers'

const aliceConfig = getBaseConfig('Agents Alice')
const bobConfig = getBaseConfig('Agents Bob')
Expand All @@ -16,8 +22,8 @@ describe('agents', () => {
let bobConnection: ConnectionRecord

afterAll(async () => {
await aliceAgent.closeAndDeleteWallet()
await bobAgent.closeAndDeleteWallet()
await closeAndDeleteWallet(aliceAgent)
await closeAndDeleteWallet(bobAgent)
})

test('make a connection between agents', async () => {
Expand All @@ -27,12 +33,12 @@ describe('agents', () => {
aliceAgent = new Agent(aliceConfig)
aliceAgent.setInboundTransporter(new SubjectInboundTransporter(aliceMessages, bobMessages))
aliceAgent.setOutboundTransporter(new SubjectOutboundTransporter(bobMessages))
await aliceAgent.init()
await aliceAgent.initialize()

bobAgent = new Agent(bobConfig)
bobAgent.setInboundTransporter(new SubjectInboundTransporter(bobMessages, aliceMessages))
bobAgent.setOutboundTransporter(new SubjectOutboundTransporter(aliceMessages))
await bobAgent.init()
await bobAgent.initialize()

const aliceConnectionAtAliceBob = await aliceAgent.connections.createConnection()
const bobConnectionAtBobAlice = await bobAgent.connections.receiveInvitation(aliceConnectionAtAliceBob.invitation)
Expand Down
9 changes: 5 additions & 4 deletions src/__tests__/credentials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
waitForCredentialRecord,
genesisPath,
getBaseConfig,
closeAndDeleteWallet,
} from './helpers'
import testLogger from './logger'

Expand Down Expand Up @@ -64,12 +65,12 @@ describe('credentials', () => {
faberAgent = new Agent(faberConfig)
faberAgent.setInboundTransporter(new SubjectInboundTransporter(faberMessages, aliceMessages))
faberAgent.setOutboundTransporter(new SubjectOutboundTransporter(aliceMessages))
await faberAgent.init()
await faberAgent.initialize()

aliceAgent = new Agent(aliceConfig)
aliceAgent.setInboundTransporter(new SubjectInboundTransporter(aliceMessages, faberMessages))
aliceAgent.setOutboundTransporter(new SubjectOutboundTransporter(faberMessages))
await aliceAgent.init()
await aliceAgent.initialize()

const schemaTemplate = {
name: `test-schema-${Date.now()}`,
Expand Down Expand Up @@ -97,8 +98,8 @@ describe('credentials', () => {
})

afterAll(async () => {
await faberAgent.closeAndDeleteWallet()
await aliceAgent.closeAndDeleteWallet()
await closeAndDeleteWallet(aliceAgent)
await closeAndDeleteWallet(faberAgent)
})

test('Alice starts with credential proposal to Faber', async () => {
Expand Down
8 changes: 8 additions & 0 deletions src/__tests__/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import type { SchemaTemplate, CredentialDefinitionTemplate } from '../modules/le
import type { ProofRecord, ProofState, ProofStateChangedEvent } from '../modules/proofs'
import type { InboundTransporter, OutboundTransporter } from '../transport'
import type { InitConfig, OutboundPackage, WireMessage } from '../types'
import type { Wallet } from '../wallet/Wallet'
import type { Schema, CredDef, Did } from 'indy-sdk'
import type { Subject } from 'rxjs'

import indy from 'indy-sdk'
import path from 'path'

import { InjectionSymbols } from '../constants'
import { BasicMessageEventTypes } from '../modules/basic-messages'
import {
ConnectionInvitationMessage,
Expand Down Expand Up @@ -51,6 +53,12 @@ export function getBaseConfig(name: string, extraConfig: Partial<InitConfig> = {
return config
}

export async function closeAndDeleteWallet(agent: Agent) {
const wallet = agent.injectionContainer.resolve<Wallet>(InjectionSymbols.Wallet)

await wallet.delete()
}

export async function waitForProofRecord(
agent: Agent,
{
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/ledger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Agent } from '../agent/Agent'
import { DID_IDENTIFIER_REGEX, VERKEY_REGEX, isFullVerkey, isAbbreviatedVerkey } from '../utils/did'
import { sleep } from '../utils/sleep'

import { genesisPath, getBaseConfig } from './helpers'
import { closeAndDeleteWallet, genesisPath, getBaseConfig } from './helpers'
import testLogger from './logger'

const faberConfig = getBaseConfig('Faber Ledger', { genesisPath })
Expand All @@ -18,11 +18,11 @@ describe('ledger', () => {

beforeAll(async () => {
faberAgent = new Agent(faberConfig)
await faberAgent.init()
await faberAgent.initialize()
})

afterAll(async () => {
await faberAgent.closeAndDeleteWallet()
await closeAndDeleteWallet(faberAgent)
})

test(`initialization of agent's public DID`, async () => {
Expand Down
9 changes: 5 additions & 4 deletions src/__tests__/proofs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
issueCredential,
waitForProofRecord,
getBaseConfig,
closeAndDeleteWallet,
} from './helpers'
import testLogger from './logger'

Expand Down Expand Up @@ -63,12 +64,12 @@ describe('Present Proof', () => {
faberAgent = new Agent(faberConfig)
faberAgent.setInboundTransporter(new SubjectInboundTransporter(faberMessages, aliceMessages))
faberAgent.setOutboundTransporter(new SubjectOutboundTransporter(aliceMessages))
await faberAgent.init()
await faberAgent.initialize()

aliceAgent = new Agent(aliceConfig)
aliceAgent.setInboundTransporter(new SubjectInboundTransporter(aliceMessages, faberMessages))
aliceAgent.setOutboundTransporter(new SubjectOutboundTransporter(faberMessages))
await aliceAgent.init()
await aliceAgent.initialize()

const schemaTemplate = {
name: `test-schema-${Date.now()}`,
Expand Down Expand Up @@ -125,8 +126,8 @@ describe('Present Proof', () => {
})

afterAll(async () => {
await faberAgent.closeAndDeleteWallet()
await aliceAgent.closeAndDeleteWallet()
await closeAndDeleteWallet(aliceAgent)
await closeAndDeleteWallet(faberAgent)
})

test('Alice starts with proof proposal to Faber', async () => {
Expand Down
38 changes: 29 additions & 9 deletions src/agent/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { concatMap } from 'rxjs/operators'
import { container as baseContainer } from 'tsyringe'

import { InjectionSymbols } from '../constants'
import { AriesFrameworkError } from '../error'
import { BasicMessagesModule } from '../modules/basic-messages/BasicMessagesModule'
import { ConnectionsModule } from '../modules/connections/ConnectionsModule'
import { CredentialsModule } from '../modules/credentials/CredentialsModule'
Expand All @@ -22,6 +23,7 @@ import { RoutingModule } from '../modules/routing/RoutingModule'
import { InMemoryMessageRepository } from '../storage/InMemoryMessageRepository'
import { IndyStorageService } from '../storage/IndyStorageService'
import { IndyWallet } from '../wallet/IndyWallet'
import { WalletError } from '../wallet/error'

import { AgentConfig } from './AgentConfig'
import { EventEmitter } from './EventEmitter'
Expand Down Expand Up @@ -82,6 +84,14 @@ export class Agent {
logger: initialConfig.logger != undefined,
})

if (!this.agentConfig.walletConfig || !this.agentConfig.walletCredentials) {
this.logger.warn(
'Wallet config and/or credentials have not been set on the agent config. ' +
'Make sure to initialize the wallet yourself before initializing the agent, ' +
'or provide the required wallet configuration in the agent constructor'
)
}

// Resolve instances after everything is registered
this.eventEmitter = this.container.resolve(EventEmitter)
this.messageSender = this.container.resolve(MessageSender)
Expand Down Expand Up @@ -120,13 +130,28 @@ export class Agent {
}

public get isInitialized() {
return this._isInitialized
return this._isInitialized && this.wallet.isInitialized
}

public async init() {
await this.wallet.init()
public async initialize() {
const { publicDidSeed, walletConfig, walletCredentials } = this.agentConfig

if (this._isInitialized) {
throw new AriesFrameworkError(
'Agent already initialized. Currently it is not supported to re-initialize an already initialized agent.'
)
}

if (!this.wallet.isInitialized && walletConfig && walletCredentials) {
await this.wallet.initialize(walletConfig, walletCredentials)
} else if (!this.wallet.isInitialized) {
throw new WalletError(
'Wallet config and/or credentials have not been set on the agent config. ' +
'Make sure to initialize the wallet yourself before initializing the agent, ' +
'or provide the required wallet configuration in the agent constructor'
)
}

const { publicDidSeed } = this.agentConfig
if (publicDidSeed) {
// If an agent has publicDid it will be used as routing key.
await this.wallet.initPublicDid({ seed: publicDidSeed })
Expand All @@ -151,11 +176,6 @@ export class Agent {
return await this.messageReceiver.receiveMessage(inboundPackedMessage, session)
}

public async closeAndDeleteWallet() {
await this.wallet.close()
await this.wallet.delete()
}

public get injectionContainer() {
return this.container
}
Expand Down
56 changes: 53 additions & 3 deletions src/agent/__tests__/Agent.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getBaseConfig } from '../../__tests__/helpers'
import type { Wallet } from '../../wallet/Wallet'

import { closeAndDeleteWallet, getBaseConfig } from '../../__tests__/helpers'
import { InjectionSymbols } from '../../constants'
import { BasicMessageRepository, BasicMessageService } from '../../modules/basic-messages'
import { BasicMessagesModule } from '../../modules/basic-messages/BasicMessagesModule'
Expand All @@ -20,6 +22,7 @@ import { RoutingModule } from '../../modules/routing/RoutingModule'
import { InMemoryMessageRepository } from '../../storage/InMemoryMessageRepository'
import { IndyStorageService } from '../../storage/IndyStorageService'
import { IndyWallet } from '../../wallet/IndyWallet'
import { WalletError } from '../../wallet/error'
import { Agent } from '../Agent'
import { Dispatcher } from '../Dispatcher'
import { EnvelopeService } from '../EnvelopeService'
Expand All @@ -30,13 +33,60 @@ const config = getBaseConfig('Agent Class Test')

describe('Agent', () => {
describe('Initialization', () => {
let agent: Agent

afterEach(async () => {
const wallet = agent.injectionContainer.resolve<Wallet>(InjectionSymbols.Wallet)

if (wallet.isInitialized) {
await closeAndDeleteWallet(agent)
}
})

it('isInitialized should only return true after initialization', async () => {
expect.assertions(2)

const agent = new Agent(config)
agent = new Agent(config)

expect(agent.isInitialized).toBe(false)
await agent.initialize()
expect(agent.isInitialized).toBe(true)
})

it('wallet isInitialized should return true after agent initialization if wallet config is set in agent constructor', async () => {
expect.assertions(4)

agent = new Agent(config)
const wallet = agent.injectionContainer.resolve<Wallet>(InjectionSymbols.Wallet)

expect(agent.isInitialized).toBe(false)
await agent.init()
expect(wallet.isInitialized).toBe(false)
await agent.initialize()
expect(agent.isInitialized).toBe(true)
expect(wallet.isInitialized).toBe(true)
})

it('wallet must be initialized if wallet config is not set before agent can be initialized', async () => {
expect.assertions(9)

const { walletConfig, walletCredentials, ...withoutWalletConfig } = config
agent = new Agent(withoutWalletConfig)

const wallet = agent.injectionContainer.resolve<Wallet>(InjectionSymbols.Wallet)

expect(agent.isInitialized).toBe(false)
expect(wallet.isInitialized).toBe(false)

expect(agent.initialize()).rejects.toThrowError(WalletError)
expect(agent.isInitialized).toBe(false)
expect(wallet.isInitialized).toBe(false)

await wallet.initialize(walletConfig!, walletCredentials!)
expect(agent.isInitialized).toBe(false)
expect(wallet.isInitialized).toBe(true)

await agent.initialize()
expect(wallet.isInitialized).toBe(true)
expect(agent.isInitialized).toBe(true)
})
})
Expand Down
6 changes: 3 additions & 3 deletions src/decorators/signature/SignatureDecoratorUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ describe('Decorators | Signature | SignatureDecoratorUtils', () => {
let wallet: IndyWallet

beforeAll(async () => {
wallet = new IndyWallet(new AgentConfig(getBaseConfig('SignatureDecoratorUtilsTest')))
await wallet.init()
const config = new AgentConfig(getBaseConfig('SignatureDecoratorUtilsTest'))
wallet = new IndyWallet(config)
await wallet.initialize(config.walletConfig!, config.walletCredentials!)
})

afterAll(async () => {
await wallet.close()
await wallet.delete()
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ describe('BasicMessageService', () => {
let storageService: StorageService<BasicMessageRecord>

beforeAll(async () => {
wallet = new IndyWallet(new AgentConfig(getBaseConfig('BasicMessageServiceTest')))
await wallet.init()
const config = new AgentConfig(getBaseConfig('BasicMessageServiceTest'))
wallet = new IndyWallet(config)
await wallet.initialize(config.walletConfig!, config.walletCredentials!)
storageService = new IndyStorageService(wallet)
})

afterAll(async () => {
await wallet.close()
await wallet.delete()
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ describe('ConnectionService', () => {
beforeAll(async () => {
agentConfig = new AgentConfig(initConfig)
wallet = new IndyWallet(agentConfig)
await wallet.init()
await wallet.initialize(agentConfig.walletConfig!, agentConfig.walletCredentials!)
})

afterAll(async () => {
await wallet.close()
await wallet.delete()
})

Expand Down
16 changes: 14 additions & 2 deletions src/modules/credentials/__tests__/StubWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@

import type { UnpackedMessageContext } from '../../../types'
import type { Wallet } from '../../../wallet/Wallet'
import type { DidConfig, WalletRecordOptions, WalletRecord, WalletQuery, LedgerRequest } from 'indy-sdk'
import type {
DidConfig,
WalletRecordOptions,
WalletRecord,
WalletQuery,
LedgerRequest,
WalletConfig,
WalletCredentials,
} from 'indy-sdk'

export class StubWallet implements Wallet {
public get isInitialized() {
return true
}

public get walletHandle() {
return 0
}
public get publicDid() {
return undefined
}
public init(): Promise<void> {
public initialize(walletConfig: WalletConfig, walletCredentials: WalletCredentials): Promise<void> {
return Promise.resolve()
}
public close(): Promise<void> {
Expand Down
Loading