Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
14 changes: 14 additions & 0 deletions .github/actions/check_resources/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Check resource usage
description: 'List current resource usage of the CI runner VM'
runs:
using: composite
steps:
- name: Check memory usage
if: always()
shell: bash
run: free -h

- name: Check CPU usage
if: always()
shell: bash
run: ps -eo pid,comm,%cpu,%mem,exe,time --sort=-%cpu | head -n 20
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,18 @@ jobs:
- name: Start Localnet
run: yarn start:localnet

- uses: ./.github/actions/check_resources

- name: Test example snippets
run: yarn nx snippets docs-wallet-integration-guide-examples

- uses: ./.github/actions/check_resources

- name: Test example scripts
run: yarn script:test:examples

- uses: ./.github/actions/check_resources

- name: Save container logs
if: failure()
run: |
Expand Down
24 changes: 10 additions & 14 deletions clients/remote/src/ledger/party-allocation-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,12 @@ const mockLedgerPost = jest.fn<AsyncFn>()
const mockLedgerGrantUserRights = jest.fn()

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const MockTopologyWriteService: jest.MockedClass<any> = jest
.fn()
.mockImplementation(() => ({
generateTransactions: jest.fn<AsyncFn>().mockResolvedValue({
generatedTransactions: [],
}),
addTransactions: jest.fn<AsyncFn>(),
authorizePartyToParticipant: jest.fn<AsyncFn>(),
submitExternalPartyTopology: jest.fn<AsyncFn>(),
}))
const MockTopologyWriteService: jest.MockedClass<any> = jest.fn()

// Add static method to the mock class
MockTopologyWriteService.createFingerprintFromKey = jest
.fn()
.mockReturnValue('mypublickey')
MockTopologyWriteService.combineHashes = jest
.fn()
.mockReturnValue('combinedhash')

jest.unstable_mockModule('@canton-network/core-ledger-client', () => ({
Signature: jest.fn(),
Expand All @@ -43,6 +31,15 @@ jest.unstable_mockModule('@canton-network/core-ledger-client', () => ({
get: mockLedgerGet,
post: mockLedgerPost,
grantUserRights: mockLedgerGrantUserRights,
generateTopology: jest.fn<AsyncFn>().mockResolvedValue({
partyId: 'party2::mypublickey',
publicKeyFingerprint: 'mypublickey',
topologyTransactions: ['tx1'],
multiHash: 'combinedHash',
}),
allocateExternalParty: jest
.fn<AsyncFn>()
.mockResolvedValue({ partyId: 'party2::mypublickey' }),
}
}),
TopologyWriteService: MockTopologyWriteService,
Expand Down Expand Up @@ -81,7 +78,6 @@ describe('PartyAllocationService', () => {
network.synchronizerId,
'admin.jwt',
network.ledgerApi.baseUrl,
network.ledgerApi.adminGrpcUrl,
mockLogger
)
})
Expand Down
56 changes: 22 additions & 34 deletions clients/remote/src/ledger/party-allocation-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,17 @@ type SigningCbFn = (hash: string) => Promise<string>
*/
export class PartyAllocationService {
private ledgerClient: LedgerClient
private topologyClient: TopologyWriteService

constructor(
private synchronizerId: string,
adminToken: string,
httpLedgerUrl: string,
adminApiUrl: string,
logger: Logger
private logger: Logger
) {
this.ledgerClient = new LedgerClient(
new URL(httpLedgerUrl),
adminToken,
logger
)
this.topologyClient = new TopologyWriteService(
this.synchronizerId,
adminApiUrl,
adminToken,
this.ledgerClient
this.logger
)
}

Expand Down Expand Up @@ -110,35 +102,31 @@ export class PartyAllocationService {
): Promise<AllocatedParty> {
const namespace =
TopologyWriteService.createFingerprintFromKey(publicKey)
const partyId = `${hint}::${namespace}`

const transactions = await this.topologyClient
.generateTransactions(publicKey, partyId)
.then((resp) => resp.generatedTransactions)

const txHashes = transactions.map((tx) =>
Buffer.from(tx.transactionHash)
const transactions = await this.ledgerClient.generateTopology(
this.synchronizerId,
publicKey,
hint
)

const combinedHash = TopologyWriteService.combineHashes(txHashes)
const signature = await signingCallback(transactions.multiHash)

const signature = await signingCallback(combinedHash)

const signedTopologyTxs = transactions.map((transaction) =>
TopologyWriteService.toSignedTopologyTransaction(
txHashes,
transaction.serializedTransaction,
signature,
namespace
)
)

await this.topologyClient.submitExternalPartyTopology(
signedTopologyTxs,
partyId
const res = await this.ledgerClient.allocateExternalParty(
this.synchronizerId,
transactions.topologyTransactions!.map((transaction) => ({
transaction,
})),
[
{
format: 'SIGNATURE_FORMAT_CONCAT',
signature: signature,
signedBy: namespace,
signingAlgorithmSpec: 'SIGNING_ALGORITHM_SPEC_ED25519',
},
]
)
await this.ledgerClient.grantUserRights(userId, partyId)

return { hint, partyId, namespace }
await this.ledgerClient.grantUserRights(userId, res.partyId)
return { hint, partyId: res.partyId, namespace }
}
}
1 change: 0 additions & 1 deletion clients/remote/src/user-api/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ export const userController = (
network.synchronizerId,
adminToken,
network.ledgerApi.baseUrl,
network.ledgerApi.adminGrpcUrl,
logger
)
const driver = drivers[
Expand Down
4 changes: 1 addition & 3 deletions core/ledger-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@
"@canton-network/core-splice-client": "workspace:^",
"@canton-network/core-token-standard": "workspace:^",
"@canton-network/core-types": "workspace:^",
"@grpc/grpc-js": "^1.13.4",
"@grpc/grpc-js": "^1.14.0",
"@protobuf-ts/grpc-transport": "^2.11.1",
"@protobuf-ts/runtime": "^2.11.1",
"@protobuf-ts/runtime-rpc": "^2.11.1",
"bignumber.js": "^9.2.1",
"dayjs": "^1.11.13",
"openapi-fetch": "^0.14.0",
Expand Down
84 changes: 84 additions & 0 deletions core/ledger-client/src/ledger-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ export type GetResponse<Path extends GetEndpoint> = paths[Path] extends {
? Res
: never

// Explicitly use the 3.3 schema here, as there has not been a 3.4 snapshot containing these yet
export type GenerateTransactionResponse =
v3_3.components['schemas']['GenerateExternalPartyTopologyResponse']

export type AllocateExternalPartyResponse =
v3_3.components['schemas']['AllocateExternalPartyResponse']

export type OnboardingTransactions = NonNullable<
v3_3.components['schemas']['AllocateExternalPartyRequest']['onboardingTransactions']
>

export type MultiHashSignatures = NonNullable<
v3_3.components['schemas']['AllocateExternalPartyRequest']['multiHashSignatures']
>
// Any options the client accepts besides body/params
type ExtraPostOpts = Omit<FetchOptions<paths>, 'body' | 'params'>

Expand Down Expand Up @@ -195,6 +209,76 @@ export class LedgerClient {
return
}

/** TODO: simplify once 3.4 snapshot contains this endpoint */
public async allocateExternalParty(
synchronizerId: string,
onboardingTransactions: OnboardingTransactions,
multiHashSignatures: MultiHashSignatures
): Promise<AllocateExternalPartyResponse> {
await this.init()

if (this.clientVersion !== '3.3') {
throw new Error(
'allocateExternalParty is only supported on 3.3 clients'
)
}

const client: Client<v3_3.paths> = this.clients['3.3']

const resp = await client.POST('/v2/parties/external/allocate', {
body: {
synchronizer: synchronizerId,
identityProviderId: '',
onboardingTransactions,
multiHashSignatures,
},
})

return this.valueOrError(resp)
}

/** TODO: simplify once 3.4 snapshot contains this endpoint */
public async generateTopology(
synchronizerId: string,
publicKey: string,
partyHint: string,
localParticipantObservationOnly: boolean = false,
confirmationThreshold: number = 1,
otherConfirmingParticipantUids: string[] = []
): Promise<GenerateTransactionResponse> {
await this.init()

if (this.clientVersion !== '3.3') {
throw new Error(
'allocateExternalParty is only supported on 3.3 clients'
)
}

const client: Client<v3_3.paths> = this.clients['3.3']

const body = {
synchronizer: synchronizerId,
partyHint,
publicKey: {
format: 'CRYPTO_KEY_FORMAT_RAW',
keyData: publicKey,
keySpec: 'SIGNING_KEY_SPEC_EC_CURVE25519',
},
localParticipantObservationOnly,
confirmationThreshold,
otherConfirmingParticipantUids,
}

this.logger.debug(body, 'generateTopology request body')

const resp = await client.POST(
'/v2/parties/external/generate-topology',
{ body }
)

return this.valueOrError(resp)
}

public async post<Path extends PostEndpoint>(
path: Path,
body: PostRequest<Path>,
Expand Down
Loading
Loading