Skip to content

Commit a08a882

Browse files
committed
temp
1 parent cb91346 commit a08a882

File tree

6 files changed

+142
-44
lines changed

6 files changed

+142
-44
lines changed

packages/cardano-services/src/ChainHistory/BlockrostChainHistoryProvider/BlockfrostChainHistoryProvider.ts

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// eslint-disable-next-line jsdoc/check-param-names
22
import * as Crypto from '@cardano-sdk/crypto';
3-
import { BlockfrostProvider } from '../../util/BlockfrostProvider/BlockfrostProvider';
3+
import { BlockfrostProvider, BlockfrostProviderDependencies } from '../../util/BlockfrostProvider/BlockfrostProvider';
44
import {
55
BlockfrostToCore,
66
BlockfrostTransactionContent,
@@ -13,12 +13,14 @@ import {
1313
BlocksByIdsArgs,
1414
Cardano,
1515
ChainHistoryProvider,
16+
NetworkInfoProvider,
1617
Paginated,
1718
ProviderError,
1819
ProviderFailure,
1920
Serialization,
2021
TransactionsByAddressesArgs,
21-
TransactionsByIdsArgs
22+
TransactionsByIdsArgs,
23+
createSlotEpochCalc
2224
} from '@cardano-sdk/core';
2325
import { DB_MAX_SAFE_INTEGER } from '../DbSyncChainHistory/queries';
2426
import { Responses } from '@blockfrost/blockfrost-js';
@@ -27,7 +29,17 @@ import omit from 'lodash/omit.js';
2729

2830
type WithCertIndex<T> = T & { cert_index: number };
2931

32+
export interface BlockfrostChainHistoryProviderDependencies extends BlockfrostProviderDependencies {
33+
networkInfoProvider: NetworkInfoProvider;
34+
}
35+
3036
export class BlockfrostChainHistoryProvider extends BlockfrostProvider implements ChainHistoryProvider {
37+
private networkInfoProvider: NetworkInfoProvider;
38+
constructor({ logger, blockfrost, networkInfoProvider }: BlockfrostChainHistoryProviderDependencies) {
39+
super({ blockfrost, logger });
40+
this.networkInfoProvider = networkInfoProvider;
41+
}
42+
3143
protected async fetchRedeemers({
3244
hash,
3345
redeemer_count
@@ -231,6 +243,53 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
231243
// eslint-disable-next-line unicorn/consistent-function-scoping
232244
protected parseValidityInterval = (num: string | null) => Cardano.Slot(Number.parseInt(num || '')) || undefined;
233245

246+
protected async fetchEpochNo(slotNo: Cardano.Slot) {
247+
const calc = await this.networkInfoProvider.eraSummaries().then(createSlotEpochCalc);
248+
return calc(slotNo);
249+
}
250+
251+
protected async fetchEpochParameters(epochNo: Cardano.EpochNo): Promise<Schemas['epoch_param_content']> {
252+
return await this.blockfrost.epochsParameters(epochNo);
253+
}
254+
255+
protected async processCertificates(
256+
txContent: Schemas['tx_content'],
257+
certificates?: Cardano.Certificate[]
258+
): Promise<Cardano.Certificate[] | undefined> {
259+
const epochNo = await this.fetchEpochNo(Cardano.Slot(txContent.slot));
260+
const epochParams: Schemas['epoch_param_content'] = await this.fetchEpochParameters(epochNo);
261+
262+
return certificates?.map((c) => {
263+
const cert = omit(c, 'cert_index') as Cardano.Certificate;
264+
switch (cert.__typename) {
265+
case Cardano.CertificateType.PoolRegistration: {
266+
cert.poolParameters.owners = [];
267+
cert.poolParameters.relays = [];
268+
const deposit =
269+
txContent.deposit === undefined || txContent.deposit === '' || txContent.deposit === '0'
270+
? 0n
271+
: BigInt(epochParams.pool_deposit);
272+
273+
delete cert.poolParameters.metadataJson;
274+
275+
return { ...cert, deposit };
276+
}
277+
case Cardano.CertificateType.StakeRegistration: {
278+
const deposit = BigInt(epochParams.key_deposit);
279+
280+
return { ...cert, __typename: Cardano.CertificateType.Registration, deposit };
281+
}
282+
case Cardano.CertificateType.StakeDeregistration: {
283+
const deposit = BigInt(epochParams.key_deposit);
284+
285+
return { ...cert, __typename: Cardano.CertificateType.Unregistration, deposit };
286+
}
287+
default:
288+
return cert;
289+
}
290+
});
291+
}
292+
234293
protected async fetchTransaction(txId: Cardano.TransactionId): Promise<Cardano.HydratedTx> {
235294
try {
236295
const txContent = await this.blockfrost.txs(txId.toString());
@@ -244,17 +303,10 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
244303
txFromCBOR ? txFromCBOR.auxiliaryData : this.fetchJsonMetadataAsAuxiliaryData(txId)
245304
]);
246305

247-
const certificates = certificatesFull?.map((c) => {
248-
const cert = omit(c, 'cert_index') as Cardano.Certificate;
249-
if (cert.__typename === Cardano.CertificateType.PoolRegistration) {
250-
cert.poolParameters.owners = [];
251-
cert.poolParameters.relays = [];
252-
}
253-
return cert;
254-
});
306+
const certificates = await this.processCertificates(txContent, certificatesFull);
255307

256308
// We can't use txFromCBOR.body.inputs since it misses HydratedTxIn.address
257-
const { inputs, outputPromises, collaterals } = this.transactionUtxos(utxos, txId, txFromCBOR ?? undefined);
309+
const { inputs, outputPromises, collaterals } = this.transactionUtxos(utxos, txFromCBOR ?? undefined);
258310
/*
259311
const inputs = BlockfrostToCore.inputsUtxos(utxos.inputs);
260312
const collaterals = BlockfrostToCore.colleteralsUtxos(utxos.inputs);
@@ -309,7 +361,7 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
309361
const proposalProcedures = txFromCBOR ? txFromCBOR.body.proposalProcedures : undefined;
310362
const votingProcedures = txFromCBOR ? txFromCBOR.body.votingProcedures : undefined;
311363

312-
const body: HydratedTxBody = {
364+
const body: Cardano.HydratedTxBody = {
313365
...(inputSource === Cardano.InputSource.collaterals
314366
? {
315367
collateralReturn: outputs.length > 0 ? outputs[0] : undefined,
@@ -349,18 +401,14 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
349401
}
350402
}
351403

352-
private transactionUtxos(
353-
utxoResponse: Responses['tx_content_utxo'],
354-
_txId: Cardano.TransactionId,
355-
txContent?: Cardano.Tx
356-
) {
404+
private transactionUtxos(utxoResponse: Responses['tx_content_utxo'], txContent?: Cardano.Tx) {
357405
const collaterals = utxoResponse.inputs.filter((input) => input.collateral).map(BlockfrostToCore.hydratedTxIn);
358406
const inputs = utxoResponse.inputs
359407
.filter((input) => !input.collateral && !input.reference)
360408
.map(BlockfrostToCore.hydratedTxIn);
361-
const outputPromises: Promise<Cardano.TxOut>[] = utxoResponse.outputs
409+
const outputPromises: Cardano.TxOut[] = utxoResponse.outputs
362410
.filter((output) => !output.collateral)
363-
.map(async (output) => {
411+
.map((output) => {
364412
const foundScript = txContent?.body.outputs.find((o) => o.address === output.address);
365413

366414
return BlockfrostToCore.txOut(output, foundScript);

packages/cardano-services/src/Program/programs/providerServer.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
CardanoNode,
77
ChainHistoryProvider,
88
HandleProvider,
9+
NetworkInfoProvider,
910
Provider,
1011
RewardsProvider,
1112
Seconds,
@@ -330,8 +331,8 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
330331
});
331332
}, ServiceNames.NetworkInfo);
332333

333-
const getBlockfrostChainHistoryProvider = () =>
334-
new BlockfrostChainHistoryProvider({ blockfrost: getBlockfrostApi(), logger });
334+
const getBlockfrostChainHistoryProvider = (networkInfoProvider: NetworkInfoProvider | DbSyncNetworkInfoProvider) =>
335+
new BlockfrostChainHistoryProvider({ blockfrost: getBlockfrostApi(), logger, networkInfoProvider });
335336

336337
const getBlockfrostRewardsProvider = () => new BlockfrostRewardsProvider({ blockfrost: getBlockfrostApi(), logger });
337338

@@ -353,6 +354,11 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
353354
const getBlockfrostTxSubmitProvider = () =>
354355
new BlockfrostTxSubmitProvider({ blockfrost: getBlockfrostApi(), logger });
355356

357+
const networkInfoProvider =
358+
args.networkInfoProvider === ProviderImplementation.BLOCKFROST
359+
? getBlockfrostNetworkInfoProvider()
360+
: getDbSyncNetworkInfoProvider();
361+
356362
return {
357363
[ServiceNames.Asset]: async () =>
358364
new AssetHttpService({
@@ -395,7 +401,10 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
395401
new ChainHistoryHttpService({
396402
chainHistoryProvider: selectProviderImplementation<ChainHistoryProvider>(
397403
args.chainHistoryProvider ?? ProviderImplementation.DBSYNC,
398-
{ blockfrost: getBlockfrostChainHistoryProvider, dbsync: getDbSyncChainHistoryProvider },
404+
{
405+
blockfrost: () => getBlockfrostChainHistoryProvider(networkInfoProvider),
406+
dbsync: getDbSyncChainHistoryProvider
407+
},
399408
logger,
400409
ServiceNames.ChainHistory
401410
),
@@ -412,16 +421,11 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
412421
ServiceNames.Rewards
413422
)
414423
}),
415-
[ServiceNames.NetworkInfo]: async () => {
416-
const networkInfoProvider =
417-
args.networkInfoProvider === ProviderImplementation.BLOCKFROST
418-
? getBlockfrostNetworkInfoProvider()
419-
: getDbSyncNetworkInfoProvider();
420-
return new NetworkInfoHttpService({
424+
[ServiceNames.NetworkInfo]: async () =>
425+
new NetworkInfoHttpService({
421426
logger,
422427
networkInfoProvider
423-
});
424-
},
428+
}),
425429
[ServiceNames.TxSubmit]: async () => {
426430
const txSubmitProvider = args.useSubmitApi
427431
? getSubmitApiProvider()

packages/cardano-services/src/Utxo/BlockfrostUtxoProvider/BlockfrostUtxoProvider.ts

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,56 @@
11
import { BlockfrostProvider } from '../../util/BlockfrostProvider/BlockfrostProvider';
2-
import { BlockfrostToCore, BlockfrostUtxo, blockfrostToProviderError, fetchByAddressSequentially } from '../../util';
3-
import { Cardano, UtxoByAddressesArgs, UtxoProvider } from '@cardano-sdk/core';
2+
import { BlockfrostToCore, blockfrostToProviderError, fetchByAddressSequentially } from '../../util';
3+
import { Cardano, Serialization, UtxoByAddressesArgs, UtxoProvider } from '@cardano-sdk/core';
4+
import { PaginationOptions } from '@blockfrost/blockfrost-js/lib/types';
45
import { Responses } from '@blockfrost/blockfrost-js';
6+
import { Schemas } from '@blockfrost/blockfrost-js/lib/types/open-api';
57

68
export class BlockfrostUtxoProvider extends BlockfrostProvider implements UtxoProvider {
9+
protected async fetchUtxos(addr: Cardano.PaymentAddress, pagination: PaginationOptions): Promise<Cardano.Utxo[]> {
10+
const utxos: Responses['address_utxo_content'] = (await this.blockfrost.addressesUtxos(
11+
addr.toString(),
12+
pagination
13+
)) as Responses['address_utxo_content'];
14+
15+
const utxoPromises = utxos.map((utxo) =>
16+
this.fetchDetailsFromCBOR(utxo.tx_hash).then((tx) => {
17+
const txOut = tx ? tx.body.outputs.find((output) => output.address === utxo.address) : undefined;
18+
return BlockfrostToCore.addressUtxoContent(addr.toString(), utxo, txOut);
19+
})
20+
);
21+
return Promise.all(utxoPromises);
22+
}
23+
24+
async fetchCBOR(hash: string): Promise<string> {
25+
return this.blockfrost
26+
.instance<Schemas['script_cbor']>(`txs/${hash}/cbor`)
27+
.then((response) => {
28+
if (response.body.cbor) return response.body.cbor;
29+
throw new Error('CBOR is null');
30+
})
31+
.catch((_error) => {
32+
throw new Error('CBOR fetch failed');
33+
});
34+
}
35+
protected async fetchDetailsFromCBOR(hash: string) {
36+
return this.fetchCBOR(hash)
37+
.then((cbor) => {
38+
const tx = Serialization.Transaction.fromCbor(Serialization.TxCBOR(cbor)).toCore();
39+
this.logger.info('Fetched details from CBOR for tx', hash);
40+
return tx;
41+
})
42+
.catch((error) => {
43+
this.logger.warn('Failed to fetch details from CBOR for tx', hash, error);
44+
return null;
45+
});
46+
}
747
public async utxoByAddresses({ addresses }: UtxoByAddressesArgs): Promise<Cardano.Utxo[]> {
848
try {
949
const utxoResults = await Promise.all(
1050
addresses.map(async (address) =>
11-
fetchByAddressSequentially<Cardano.Utxo, BlockfrostUtxo>({
51+
fetchByAddressSequentially<Cardano.Utxo, Cardano.Utxo>({
1252
address,
13-
request: (addr: Cardano.PaymentAddress, pagination) =>
14-
this.blockfrost.addressesUtxos(addr.toString(), pagination),
15-
responseTranslator: (addr: Cardano.PaymentAddress, response: Responses['address_utxo_content']) =>
16-
BlockfrostToCore.addressUtxoContent(addr.toString(), response)
53+
request: async (addr: Cardano.PaymentAddress, pagination) => await this.fetchUtxos(addr, pagination)
1754
})
1855
)
1956
);

packages/cardano-services/src/util/BlockfrostProvider/BlockfrostProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { HealthCheckResponse, Provider, ProviderDependencies } from '@cardano-sd
33
import { blockfrostToProviderError } from './blockfrostUtil';
44
import type { Logger } from 'ts-log';
55

6-
/** Properties that are need to create a BlockfrostProvider */
6+
/** Properties needed to create a BlockfrostProvider */
77
export interface BlockfrostProviderDependencies extends ProviderDependencies {
88
blockfrost: BlockFrostAPI;
99
logger: Logger;

packages/cardano-services/src/util/BlockfrostProvider/BlockfrostToCore.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ export type BlockfrostTransactionContent = Unpacked<Responses['address_transacti
1313
export type BlockfrostUtxo = Unpacked<BlockfrostAddressUtxoContent>;
1414

1515
export const BlockfrostToCore = {
16-
addressUtxoContent: (address: string, blockfrost: Responses['address_utxo_content']): Cardano.Utxo[] =>
17-
blockfrost.map((utxo) => [
16+
addressUtxoContent: (
17+
address: string,
18+
utxo: Responses['address_utxo_content'][0],
19+
txOutFromCbor?: Cardano.TxOut
20+
): Cardano.Utxo =>
21+
[
1822
BlockfrostToCore.hydratedTxIn(BlockfrostToCore.inputFromUtxo(address, utxo)),
19-
BlockfrostToCore.txOut(BlockfrostToCore.outputFromUtxo(address, utxo))
20-
]) as Cardano.Utxo[],
23+
BlockfrostToCore.txOut(BlockfrostToCore.outputFromUtxo(address, utxo), txOutFromCbor)
24+
] as Cardano.Utxo,
2125

2226
blockToTip: (block: Responses['block_content']): Cardano.Tip => ({
2327
blockNo: Cardano.BlockNo(block.height!),

packages/e2e/test/ws-server/webSocket.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,13 @@ WHERE tx_out_id IS NULL GROUP BY address HAVING COUNT(DISTINCT tx_id) < 1000 ORD
381381

382382
await client.chainHistoryProvider.transactionsByAddresses(request);
383383

384-
const wsUtxos = await client.utxoProvider.utxoByAddresses(request);
385-
const httpUtxos = await utxoProvider.utxoByAddresses(request);
384+
const wsUtxos = (await client.utxoProvider.utxoByAddresses(request)).sort(
385+
([txIn1, _txOut1], [txIn2, _txOut2]) => txIn1.txId.localeCompare(txIn2.txId) || txIn1.index - txIn2.index
386+
);
387+
const httpUtxos = (await utxoProvider.utxoByAddresses(request)).sort(
388+
([txIn1, _txOut1], [txIn2, _txOut2]) => txIn1.txId.localeCompare(txIn2.txId) || txIn1.index - txIn2.index
389+
);
390+
386391
expect(toSerializableObject(wsUtxos)).toEqual(toSerializableObject(httpUtxos));
387392
});
388393
});

0 commit comments

Comments
 (0)