@@ -16,11 +16,13 @@ import {
1616 Paginated ,
1717 ProviderError ,
1818 ProviderFailure ,
19+ Serialization ,
1920 TransactionsByAddressesArgs ,
2021 TransactionsByIdsArgs
2122} from '@cardano-sdk/core' ;
2223import { DB_MAX_SAFE_INTEGER } from '../DbSyncChainHistory/queries' ;
2324import { Responses } from '@blockfrost/blockfrost-js' ;
25+ import { Schemas } from '@blockfrost/blockfrost-js/lib/types/open-api' ;
2426
2527type WithCertIndex < T > = T & { cert_index : number } ;
2628
@@ -113,6 +115,29 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
113115 } ) )
114116 ) ;
115117 }
118+ async fetchCBOR ( hash : string ) : Promise < string > {
119+ return this . blockfrost
120+ . instance < Schemas [ 'script_cbor' ] > ( `/txs/${ hash } /cbor` )
121+ . then ( ( response ) => {
122+ if ( response . body . cbor ) return response . body . cbor ;
123+ throw new Error ( 'CBOR is null' ) ;
124+ } )
125+ . catch ( ( _error ) => {
126+ throw new Error ( 'CBOR fetch failed' ) ;
127+ } ) ;
128+ }
129+ protected async fetchDetailsFromCBOR ( hash : string ) {
130+ return this . fetchCBOR ( hash )
131+ . then ( ( cbor ) => {
132+ const tx = Serialization . Transaction . fromCbor ( Serialization . TxCBOR ( cbor ) ) . toCore ( ) ;
133+ this . logger . info ( 'Fetched details from CBOR for tx' , hash ) ;
134+ return tx ;
135+ } )
136+ . catch ( ( error ) => {
137+ this . logger . warn ( 'Failed to fetch details from CBOR for tx' , hash , error ) ;
138+ return null ;
139+ } ) ;
140+ }
116141
117142 protected async fetchMirCerts ( hash : string ) : Promise < WithCertIndex < Cardano . MirCertificate > [ ] > {
118143 return this . blockfrost . txsMirs ( hash ) . then ( ( response ) =>
@@ -166,27 +191,40 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
166191 } : Responses [ 'tx_content' ] ) : Promise < Cardano . Certificate [ ] | undefined > {
167192 if ( pool_retire_count + pool_update_count + mir_cert_count + stake_cert_count + delegation_count === 0 ) return ;
168193
169- return Promise . all ( [
194+ const c = Promise . all ( [
170195 pool_retire_count ? this . fetchPoolRetireCerts ( hash ) : [ ] ,
171196 pool_update_count ? this . fetchPoolUpdateCerts ( hash ) : [ ] ,
172- mir_cert_count ? this . fetchMirCerts ( hash ) : Promise . resolve ( [ ] ) ,
173- stake_cert_count ? this . fetchStakeCerts ( hash ) : Promise . resolve ( [ ] ) ,
174- delegation_count ? this . fetchDelegationCerts ( hash ) : Promise . resolve ( [ ] )
197+ mir_cert_count ? this . fetchMirCerts ( hash ) : [ ] ,
198+ stake_cert_count ? this . fetchStakeCerts ( hash ) : [ ] ,
199+ delegation_count ? this . fetchDelegationCerts ( hash ) : [ ]
175200 ] ) . then ( ( results ) =>
176201 results
177202 . flat ( )
178203 . sort ( ( a , b ) => b . cert_index - a . cert_index )
179204 . map ( ( cert ) => cert as Cardano . Certificate )
180205 ) ;
206+ // eslint-disable-next-line no-console
207+ console . debug ( JSON . stringify ( await c , ( _key , value ) => ( typeof value === 'bigint' ? value . toString ( ) : value ) ) ) ;
208+ return c ;
181209 }
182210
183- protected async fetchJsonMetadata ( txHash : Cardano . TransactionId ) : Promise < Cardano . TxMetadata | null > {
211+ protected async fetchJsonMetadataAsAuxiliaryData (
212+ txHash : Cardano . TransactionId
213+ ) : Promise < Cardano . AuxiliaryData | undefined > {
214+ const UNDEFINED = undefined ;
184215 return this . blockfrost
185216 . txsMetadata ( txHash . toString ( ) )
186- . then ( blockfrostMetadataToTxMetadata )
217+ . then ( ( m ) => {
218+ const metadata = blockfrostMetadataToTxMetadata ( m ) ;
219+ return metadata && metadata . size > 0
220+ ? {
221+ blob : metadata
222+ }
223+ : UNDEFINED ;
224+ } )
187225 . catch ( ( error ) => {
188226 if ( isBlockfrostNotFoundError ( error ) ) {
189- return null ;
227+ return UNDEFINED ;
190228 }
191229 throw error ;
192230 } ) ;
@@ -199,52 +237,68 @@ export class BlockfrostChainHistoryProvider extends BlockfrostProvider implement
199237 try {
200238 const txContent = await this . blockfrost . txs ( hash . toString ( ) ) ;
201239
202- const [ certificates , withdrawals , utxos , metadata ] = await Promise . all ( [
203- this . fetchCertificates ( txContent ) ,
204- this . fetchWithdrawals ( txContent ) ,
240+ const txFromCBOR = await this . fetchDetailsFromCBOR ( hash . toString ( ) ) ;
241+
242+ const [ certificates , withdrawals , utxos , auxiliaryData ] = await Promise . all ( [
243+ txFromCBOR ? txFromCBOR . body . certificates : this . fetchCertificates ( txContent ) ,
244+ txFromCBOR ? txFromCBOR . body . withdrawals : this . fetchWithdrawals ( txContent ) ,
205245 this . blockfrost . txsUtxos ( hash . toString ( ) ) ,
206- this . fetchJsonMetadata ( hash )
246+ txFromCBOR ? txFromCBOR . auxiliaryData : this . fetchJsonMetadataAsAuxiliaryData ( hash )
207247 ] ) ;
208248
249+ // We can't use txFromCBOR.body.inputs since it misses HydratedTxIn.address
209250 const { inputs, outputs, collaterals } = BlockfrostToCore . transactionUtxos ( utxos ) ;
210251
211- const inputSource : Cardano . InputSource = txContent . valid_contract
252+ const fee = txFromCBOR ? txFromCBOR . body . fee : BigInt ( txContent . fees ) ;
253+ const mint = txFromCBOR ? txFromCBOR . body . mint : this . gatherMintsFromUtxos ( txContent , utxos ) ;
254+ const validityInterval = txFromCBOR
255+ ? txFromCBOR . body . validityInterval
256+ : {
257+ invalidBefore : this . parseValidityInterval ( txContent . invalid_before ) ,
258+ invalidHereafter : this . parseValidityInterval ( txContent . invalid_hereafter )
259+ } ;
260+
261+ const witness = txFromCBOR
262+ ? txFromCBOR . witness
263+ : {
264+ redeemers : await this . fetchRedeemers ( txContent ) ,
265+ signatures : new Map ( ) // not available in blockfrost
266+ } ;
267+
268+ // can txFromCBOR.isValid also be used?
269+ const valid_contract = txContent . valid_contract ;
270+
271+ const inputSource : Cardano . InputSource = valid_contract
212272 ? Cardano . InputSource . inputs
213273 : Cardano . InputSource . collaterals ;
214274
275+ // can we get these from cbor?
276+ const index = txContent . index ;
277+ const txSize = txContent . size ;
278+ const blockHeader = {
279+ blockNo : Cardano . BlockNo ( txContent . block_height ) ,
280+ hash : Cardano . BlockId ( txContent . block ) ,
281+ slot : Cardano . Slot ( txContent . slot )
282+ } ;
283+
215284 return {
216- auxiliaryData :
217- metadata && metadata . size > 0
218- ? {
219- blob : metadata
220- }
221- : undefined ,
222- blockHeader : {
223- blockNo : Cardano . BlockNo ( txContent . block_height ) ,
224- hash : Cardano . BlockId ( txContent . block ) ,
225- slot : Cardano . Slot ( txContent . slot )
226- } ,
285+ auxiliaryData,
286+ blockHeader,
227287 body : {
228288 certificates,
229289 collaterals,
230- fee : BigInt ( txContent . fees ) ,
290+ fee,
231291 inputs,
232- mint : this . gatherMintsFromUtxos ( txContent , utxos ) ,
292+ mint,
233293 outputs,
234- validityInterval : {
235- invalidBefore : this . parseValidityInterval ( txContent . invalid_before ) ,
236- invalidHereafter : this . parseValidityInterval ( txContent . invalid_hereafter )
237- } ,
294+ validityInterval,
238295 withdrawals
239296 } ,
240297 id : hash ,
241- index : txContent . index ,
298+ index,
242299 inputSource,
243- txSize : txContent . size ,
244- witness : {
245- redeemers : await this . fetchRedeemers ( txContent ) ,
246- signatures : new Map ( ) // not available in blockfrost
247- }
300+ txSize,
301+ witness
248302 } ;
249303 } catch ( error ) {
250304 throw blockfrostToProviderError ( error ) ;
0 commit comments