-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- UtxoProvider - DBSyncUtxoProvider - UtxoHttpService - bash copy openApi script - UtxoHttpProvider
- Loading branch information
Juan Cruz
committed
May 19, 2022
1 parent
6f3a5d6
commit a55fcdb
Showing
27 changed files
with
794 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './utxoHttpProvider'; |
25 changes: 25 additions & 0 deletions
25
packages/cardano-services-client/src/UtxoProvider/utxoHttpProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { HttpProviderConfigPaths, createHttpProvider } from '../HttpProvider'; | ||
import { ProviderError, ProviderFailure, UtxoProvider } from '@cardano-sdk/core'; | ||
|
||
export const defaultUtxoProviderPaths: HttpProviderConfigPaths<UtxoProvider> = { | ||
healthCheck: '/health', | ||
utxoByAddresses: '/utxo-by-addresses' | ||
}; | ||
|
||
/** | ||
* Connect to a Cardano Services HttpServer instance with the service available | ||
* | ||
* @param {string} baseUrl server root url, w/o trailing / | ||
*/ | ||
export const utxoHttpProvider = (baseUrl: string, paths = defaultUtxoProviderPaths): UtxoProvider => | ||
createHttpProvider<UtxoProvider>({ | ||
baseUrl, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
mapError: (error: any, method) => { | ||
if (method === 'healthCheck' && !error) { | ||
return { ok: false }; | ||
} | ||
throw new ProviderError(ProviderFailure.Unknown, error); | ||
}, | ||
paths | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
packages/cardano-services-client/test/Utxo/utxoHttpProvider.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* eslint-disable max-len */ | ||
import { Cardano } from '@cardano-sdk/core'; | ||
import { utxoHttpProvider } from '../../src'; | ||
import MockAdapter from 'axios-mock-adapter'; | ||
import axios from 'axios'; | ||
|
||
const url = 'http://some-hostname:3000/utxo'; | ||
|
||
describe('utxoHttpProvider', () => { | ||
let axiosMock: MockAdapter; | ||
|
||
beforeAll(() => { | ||
axiosMock = new MockAdapter(axios); | ||
}); | ||
afterEach(() => { | ||
axiosMock.reset(); | ||
}); | ||
|
||
afterAll(() => { | ||
axiosMock.restore(); | ||
}); | ||
describe('healtCheck', () => { | ||
it('is not ok if cannot connect', async () => { | ||
const provider = utxoHttpProvider(url); | ||
await expect(provider.healthCheck()).resolves.toEqual({ ok: false }); | ||
}); | ||
describe('mocked', () => { | ||
it('is ok if 200 response body is { ok: true }', async () => { | ||
axiosMock.onPost().replyOnce(200, { ok: true }); | ||
const provider = utxoHttpProvider(url); | ||
await expect(provider.healthCheck()).resolves.toEqual({ ok: true }); | ||
}); | ||
|
||
it('is not ok if 200 response body is { ok: false }', async () => { | ||
axiosMock.onPost().replyOnce(200, { ok: false }); | ||
const provider = utxoHttpProvider(url); | ||
await expect(provider.healthCheck()).resolves.toEqual({ ok: false }); | ||
}); | ||
}); | ||
}); | ||
describe('utxoByAddresses', () => { | ||
test('utxoByAddresses doesnt throw', async () => { | ||
axiosMock.onPost().replyOnce(200, []); | ||
const provider = utxoHttpProvider(url); | ||
await expect( | ||
provider.utxoByAddresses([ | ||
Cardano.Address( | ||
'addr_test1qretqkqqvc4dax3482tpjdazrfl8exey274m3mzch3dv8lu476aeq3kd8q8splpsswcfmv4y370e8r76rc8lnnhte49qqyjmtc' | ||
) | ||
]) | ||
).resolves.toEqual([]); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env bash | ||
|
||
cp ./src/StakePoolSearch/openApi.json ./dist/StakePoolSearch/openApi.json | ||
cp ./src/TxSubmit/openApi.json ./dist/TxSubmit/openApi.json | ||
cp ./src/Utxo/openApi.json ./dist/Utxo/openApi.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/DbSyncUtxoProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Cardano, UtxoProvider } from '@cardano-sdk/core'; | ||
import { DbSyncProvider } from '../../DbSyncProvider'; | ||
import { Logger, dummyLogger } from 'ts-log'; | ||
import { Pool } from 'pg'; | ||
import { UtxoBuilder } from './UtxoBuilder'; | ||
|
||
export class DbSyncUtxoProvider extends DbSyncProvider implements UtxoProvider { | ||
#logger: Logger; | ||
#builder: UtxoBuilder; | ||
constructor(db: Pool, logger = dummyLogger) { | ||
super(db); | ||
this.#logger = logger; | ||
this.#builder = new UtxoBuilder(db, logger); | ||
} | ||
|
||
public async utxoByAddresses(addresses: Cardano.Address[]): Promise<Cardano.Utxo[]> { | ||
this.#logger.debug('About to call utxoByAddress of Utxo Query Builder'); | ||
return this.#builder.utxoByAddresses(addresses); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/UtxoBuilder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Cardano } from '@cardano-sdk/core'; | ||
import { Logger, dummyLogger } from 'ts-log'; | ||
import { Pool, QueryResult } from 'pg'; | ||
import { UtxoModel } from './types'; | ||
import { findUtxosByAddresses } from './queries'; | ||
import { utxosToCore } from './mappers'; | ||
|
||
export class UtxoBuilder { | ||
#db: Pool; | ||
#logger: Logger; | ||
constructor(db: Pool, logger = dummyLogger) { | ||
this.#db = db; | ||
this.#logger = logger; | ||
} | ||
public async utxoByAddresses(addresses: Cardano.Address[]): Promise<Cardano.Utxo[]> { | ||
const mappedAddresses = addresses.map((a) => a.toString()); | ||
this.#logger.debug('About to find utxos of addresses ', mappedAddresses); | ||
const result: QueryResult<UtxoModel> = await this.#db.query(findUtxosByAddresses, [mappedAddresses]); | ||
return result.rows.length > 0 ? utxosToCore(result.rows) : []; | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './DbSyncUtxoProvider'; | ||
export * from './mappers'; | ||
export * from './types'; |
50 changes: 50 additions & 0 deletions
50
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/mappers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Cardano, createUtxoId } from '@cardano-sdk/core'; | ||
import { UtxoModel } from './types'; | ||
import { generateAssetId } from './util'; | ||
|
||
/** | ||
* Transform DB results into indexed core UTxO | ||
* | ||
* @param {UtxoModel[]} utxosModels UTxO query rows | ||
* @returns {Cardano.Utxo[]} an array of core UTxO objects | ||
*/ | ||
export const utxosToCore = (utxosModels: UtxoModel[]): Cardano.Utxo[] => { | ||
const utxosMap = utxosModels.reduce((utxos, current) => { | ||
const utxoId = createUtxoId(current.tx_id, current.index); | ||
const utxo = utxos.get(utxoId); | ||
if (utxo) { | ||
const txIn = utxo[0]; | ||
const txOut = utxo[1]; | ||
if (current.asset_name && current.asset_policy && current.asset_quantity) { | ||
const newAssets = txOut.value.assets || new Map<Cardano.AssetId, bigint>(); | ||
newAssets.set(generateAssetId(current.asset_policy, current.asset_name), BigInt(current.asset_quantity)); | ||
txOut.value.assets = newAssets; | ||
} | ||
utxos.set(utxoId, [txIn, txOut]); | ||
} else { | ||
const address = Cardano.Address(current.address); | ||
const txOut: Cardano.TxOut = { | ||
address, | ||
value: { | ||
coins: BigInt(current.coins) | ||
} | ||
}; | ||
if (current.data_hash) txOut.datum = Cardano.Hash32ByteBase16(current.data_hash); | ||
if (current.asset_name && current.asset_policy && current.asset_quantity) { | ||
txOut.value.assets = new Map<Cardano.AssetId, bigint>([ | ||
[generateAssetId(current.asset_policy, current.asset_name), BigInt(current.asset_quantity)] | ||
]); | ||
} | ||
utxos.set(utxoId, [ | ||
{ | ||
address, | ||
index: current.index, | ||
txId: Cardano.TransactionId(current.tx_id) | ||
}, | ||
txOut | ||
]); | ||
} | ||
return utxos; | ||
}, new Map<string, Cardano.Utxo>()); | ||
return [...utxosMap.values()]; | ||
}; |
25 changes: 25 additions & 0 deletions
25
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/queries.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
export const findUtxosByAddresses = ` | ||
SELECT | ||
tx_outer.address, | ||
tx_outer.value AS coins, | ||
tx_outer.index, | ||
ENCODE(tx.hash, 'hex') AS tx_id, | ||
ma_tx_out.quantity AS asset_quantity, | ||
ENCODE(asset.name,'hex') AS asset_name, | ||
ENCODE(asset.policy,'hex') AS asset_policy, | ||
ENCODE(tx_outer.data_hash,'hex') AS data_hash | ||
FROM tx_out AS tx_outer | ||
JOIN tx ON tx.id = tx_outer.tx_id | ||
LEFT JOIN ma_tx_out | ||
ON ma_tx_out.tx_out_id = tx_outer.id | ||
LEFT JOIN multi_asset as asset | ||
ON asset.id = ma_tx_out.ident | ||
WHERE NOT EXISTS | ||
( SELECT tx_out.id | ||
FROM tx_out | ||
JOIN tx_in on | ||
tx_out.tx_id = tx_in.tx_out_id AND | ||
tx_out.index = tx_in.tx_out_index | ||
WHERE tx_outer.id = tx_out.id | ||
) AND address = ANY($1) | ||
`; |
13 changes: 13 additions & 0 deletions
13
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/* | ||
* There will be as much rows as tokens are in Value object | ||
*/ | ||
export interface UtxoModel { | ||
address: string; | ||
coins: string; | ||
index: number; | ||
tx_id: string; | ||
asset_quantity?: string; | ||
asset_name?: string; | ||
asset_policy?: string; | ||
data_hash?: string; | ||
} |
3 changes: 3 additions & 0 deletions
3
packages/cardano-services/src/Utxo/DbSyncUtxoProvider/util.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { Cardano } from '@cardano-sdk/core'; | ||
|
||
export const generateAssetId = (policy: string, name: string) => Cardano.AssetId(policy + name); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import * as OpenApiValidator from 'express-openapi-validator'; | ||
import { Cardano, ProviderError, ProviderFailure } from '@cardano-sdk/core'; | ||
import { DbSyncUtxoProvider } from './DbSyncUtxoProvider'; | ||
import { HttpServer, HttpService } from '../Http'; | ||
import { Logger, dummyLogger } from 'ts-log'; | ||
import { ServiceNames } from '../Program'; | ||
import { providerHandler } from '../util'; | ||
import express from 'express'; | ||
import path from 'path'; | ||
|
||
export interface UtxoServiceDependencies { | ||
logger?: Logger; | ||
utxoProvider: DbSyncUtxoProvider; | ||
} | ||
|
||
export class UtxoHttpService extends HttpService { | ||
#utxoProvider: DbSyncUtxoProvider; | ||
|
||
private constructor({ utxoProvider, logger = dummyLogger }: UtxoServiceDependencies, router: express.Router) { | ||
super(ServiceNames.Utxo, router, logger); | ||
this.#utxoProvider = utxoProvider; | ||
} | ||
|
||
async healthCheck() { | ||
return this.#utxoProvider.healthCheck(); | ||
} | ||
|
||
static create({ logger = dummyLogger, utxoProvider }: UtxoServiceDependencies) { | ||
const router = express.Router(); | ||
const apiSpec = path.join(__dirname, 'openApi.json'); | ||
router.use( | ||
OpenApiValidator.middleware({ | ||
apiSpec, | ||
ignoreUndocumented: true, // otherwhise /metrics endpoint should be included in spec | ||
validateRequests: true, | ||
validateResponses: true | ||
}) | ||
); | ||
router.post( | ||
'/utxo-by-addresses', | ||
providerHandler<[Cardano.Address[]], Cardano.Utxo[]>(async ([addresses], _, res) => { | ||
try { | ||
return HttpServer.sendJSON(res, await utxoProvider.utxoByAddresses(addresses)); | ||
} catch (error) { | ||
logger.error(error); | ||
return HttpServer.sendJSON(res, new ProviderError(ProviderFailure.Unhealthy, error), 500); | ||
} | ||
}, logger) | ||
); | ||
return new UtxoHttpService({ logger, utxoProvider }, router); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './UtxoHttpService'; | ||
export * from './DbSyncUtxoProvider'; |
Oops, something went wrong.