Skip to content

Commit f4c3d50

Browse files
committed
feat!: update core types with deserialized PlutusData
BREAKING CHANGE: incompatible with previous revisions of cardano-services - rename utxo and transactions PouchDB stores - update type of Tx.witness.redeemers - update type of Tx.witness.datums - update type of TxOut.datum - remove Cardano.Datum type
1 parent 16aa572 commit f4c3d50

File tree

37 files changed

+631
-117
lines changed

37 files changed

+631
-117
lines changed

packages/cardano-services/src/ChainHistory/DbSyncChainHistory/DbSyncChainHistoryProvider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export class DbSyncChainHistoryProvider extends DbSyncProvider() implements Chai
121121
this.#builder.queryTxMintByIds(ids),
122122
this.#builder.queryWithdrawalsByTxIds(ids),
123123
this.#builder.queryRedeemersByIds(ids),
124+
// Missing witness datums
124125
this.#metadataService.queryTxMetadataByRecordIds(ids),
125126
this.#builder.queryTransactionInputsByIds(ids, true),
126127
this.#builder.queryCertificatesByIds(ids)

packages/cardano-services/src/ChainHistory/DbSyncChainHistory/mappers.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BigIntMath, HexBlob } from '@cardano-sdk/util';
1+
import { BigIntMath } from '@cardano-sdk/util';
22
import {
33
BlockModel,
44
BlockOutputModel,
@@ -85,6 +85,7 @@ export const mapTxOut = (txOut: TxOutput): Cardano.TxOut => ({
8585

8686
export const mapTxOutModel = (txOutModel: TxOutputModel, assets?: Cardano.TokenMap): TxOutput => ({
8787
address: txOutModel.address as unknown as Cardano.PaymentAddress,
88+
// Inline datums are missing, but for now it's ok on ChainHistoryProvider
8889
datumHash: txOutModel.datum ? (txOutModel.datum.toString('hex') as unknown as Hash32ByteBase16) : undefined,
8990
index: txOutModel.index,
9091
txId: txOutModel.tx_id.toString('hex') as unknown as Cardano.TransactionId,
@@ -99,8 +100,12 @@ export const mapWithdrawal = (withdrawalModel: WithdrawalModel): Cardano.Withdra
99100
stakeAddress: withdrawalModel.stake_address as unknown as Cardano.RewardAccount
100101
});
101102

103+
// TODO: unfortunately this is not nullable and not implemented.
104+
// Remove this and select the actual redeemer data from `redeemer_data` table.
105+
const stubRedeemerData = Buffer.from('not implemented');
106+
102107
export const mapRedeemer = (redeemerModel: RedeemerModel): Cardano.Redeemer => ({
103-
data: redeemerModel.script_hash.toString('hex') as unknown as HexBlob,
108+
data: stubRedeemerData,
104109
executionUnits: {
105110
memory: Number(redeemerModel.unit_mem),
106111
steps: Number(redeemerModel.unit_steps)

packages/cardano-services/src/ChainHistory/openApi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@
362362
]
363363
},
364364
"data": {
365-
"type": "string"
365+
"type": "object"
366366
}
367367
}
368368
},

packages/cardano-services/src/Utxo/DbSyncUtxoProvider/mappers.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { Cardano, SerializationError, SerializationFailure, createUtxoId, jsonToNativeScript } from '@cardano-sdk/core';
1+
import {
2+
Cardano,
3+
PlutusData,
4+
SerializationError,
5+
SerializationFailure,
6+
createUtxoId,
7+
jsonToNativeScript
8+
} from '@cardano-sdk/core';
29
import { Hash32ByteBase16 } from '@cardano-sdk/crypto';
310
import { HexBlob, isNotNil } from '@cardano-sdk/util';
411
import { ReferenceScriptType, UtxoModel } from './types';
@@ -84,7 +91,10 @@ export const utxosToCore = (utxosModels: UtxoModel[]): Cardano.Utxo[] => {
8491
}
8592
};
8693
if (isNotNil(current.data_hash)) txOut.datumHash = current.data_hash as unknown as Hash32ByteBase16;
87-
if (isNotNil(current.inline_datum)) txOut.datum = current.inline_datum as unknown as HexBlob;
94+
if (isNotNil(current.inline_datum))
95+
// TODO: test that this is the format in db-sync.
96+
// It might be the entire Datum (with tag)
97+
txOut.datum = PlutusData.fromCbor(HexBlob(current.inline_datum)).toCore();
8898
if (isNotNil(current.reference_script_type)) txOut.scriptReference = parseReferenceScript(current);
8999

90100
if (isNotNil(current.asset_name) && current.asset_policy && current.asset_quantity) {

packages/cardano-services/src/Utxo/openApi.json

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151
"components": {
5252
"schemas": {
5353
"TypifiedValue": {
54-
"required": ["value"],
54+
"required": [
55+
"value"
56+
],
5557
"type": "object",
5658
"properties": {
5759
"value": {
@@ -70,7 +72,9 @@
7072
"example": "addr_test1qpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5ewvxwdrt70qlcpeeagscasafhffqsxy36t90ldv06wqrk2qum8x5w"
7173
},
7274
"Value": {
73-
"required": ["coins"],
75+
"required": [
76+
"coins"
77+
],
7478
"type": "object",
7579
"properties": {
7680
"coins": {
@@ -82,7 +86,11 @@
8286
}
8387
},
8488
"TxIn": {
85-
"required": ["address", "index", "txId"],
89+
"required": [
90+
"address",
91+
"index",
92+
"txId"
93+
],
8694
"type": "object",
8795
"properties": {
8896
"address": {
@@ -105,7 +113,10 @@
105113
]
106114
},
107115
"TxOut": {
108-
"required": ["address", "value"],
116+
"required": [
117+
"address",
118+
"value"
119+
],
109120
"type": "object",
110121
"properties": {
111122
"address": {
@@ -115,7 +126,13 @@
115126
"$ref": "#/components/schemas/Value"
116127
},
117128
"datum": {
129+
"type": "object"
130+
},
131+
"datumHash": {
118132
"type": "string"
133+
},
134+
"scriptReference": {
135+
"type": "object"
119136
}
120137
},
121138
"example": [
@@ -148,14 +165,15 @@
148165
}
149166
},
150167
"utxo_search_body": {
151-
"required": ["addresses"],
168+
"required": [
169+
"addresses"
170+
],
152171
"type": "object",
153172
"properties": {
154173
"addresses": {
155174
"type": "array",
156175
"items": {
157176
"$ref": "#/components/schemas/Address"
158-
159177
}
160178
}
161179
}

packages/cardano-services/test/ChainHistory/ChainHistoryHttpService.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { CreateHttpProviderConfig, chainHistoryHttpProvider } from '@cardano-sdk
1616
import { DB_MAX_SAFE_INTEGER } from '../../src/ChainHistory/DbSyncChainHistory/queries';
1717
import { DataMocks } from '../data-mocks';
1818
import { DbPools, LedgerTipModel, findLedgerTip } from '../../src/util/DbSyncProvider';
19-
import { HexBlob } from '@cardano-sdk/util';
2019
import { OgmiosCardanoNode } from '@cardano-sdk/ogmios';
2120
import { Pool } from 'pg';
2221
import { clearDbPools } from '../util';
@@ -293,7 +292,6 @@ describe('ChainHistoryHttpService', () => {
293292
expect(response.length).toEqual(1);
294293
expect(tx.witness).toMatchShapeOf(DataMocks.Tx.witnessRedeemers);
295294
expect(tx.witness.redeemers!.length).toBeGreaterThan(0);
296-
expect(() => HexBlob(tx.witness.redeemers![0].data as unknown as string)).not.toThrow();
297295
});
298296

299297
it('has auxiliary data', async () => {

packages/cardano-services/test/ChainHistory/DbSyncChainHistoryProvider/mappers.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
} from '../../../src/ChainHistory/DbSyncChainHistory/types';
2727
import { Cardano } from '@cardano-sdk/core';
2828
import { Hash32ByteBase16 } from '@cardano-sdk/crypto';
29-
import { HexBlob } from '@cardano-sdk/util';
3029

3130
const blockHash = '7a48b034645f51743550bbaf81f8a14771e58856e031eb63844738ca8ad72298';
3231
const poolId = 'pool1zuevzm3xlrhmwjw87ec38mzs02tlkwec9wxpgafcaykmwg7efhh';
@@ -289,7 +288,7 @@ describe('chain history mappers', () => {
289288
test('map RedeemerModel to Cardano.Redeemer', () => {
290289
const result = mappers.mapRedeemer(redeemerModel);
291290
expect(result).toEqual<Cardano.Redeemer>({
292-
data: HexBlob(hash28ByteBase16),
291+
data: Buffer.from('not implemented'),
293292
executionUnits: {
294293
memory: 2000,
295294
steps: 5000
@@ -308,7 +307,7 @@ describe('chain history mappers', () => {
308307
];
309308
const redeemers: Cardano.Redeemer[] = [
310309
{
311-
data: HexBlob(hash28ByteBase16),
310+
data: Buffer.from('not implemented'),
312311
executionUnits: { memory: 1, steps: 2 },
313312
index: 1,
314313
purpose: Cardano.RedeemerPurpose.spend

packages/cardano-services/test/data-mocks/tx.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const withWithdrawals: Cardano.HydratedTx = merge(withAssets, {
138138
export const witnessRedeemers = {
139139
redeemers: [
140140
{
141-
data: '67f33146617a5e61936081db3b2117cbf59bd2123748f58ac9678656',
141+
data: {},
142142
executionUnits: {
143143
memory: 1700,
144144
steps: 476_468
@@ -170,7 +170,7 @@ export const output = {
170170
export const outputWithInlineDatum = {
171171
address:
172172
'addr_test1qpcncempf4svkpw0salztrsxzrfpr5ll323q5whw7lv94vyw0kz5rxvdaq6u6tslwfrrgz6l4n4lpcpnawn87yl9k6dsu4hhg2',
173-
datum: '182a',
173+
datum: 42n,
174174
value: {
175175
coins: 13_499_999_999_819_540n
176176
}
@@ -220,7 +220,7 @@ export const certificate = {
220220
};
221221

222222
export const redeemer = {
223-
data: '67f33146617a5e61936081db3b2117cbf59bd2123748f58ac9678656',
223+
data: {},
224224
executionUnits: {
225225
memory: 0,
226226
steps: 0

packages/core/src/CML/cmlToCore/cmlToCore.ts

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import * as Crypto from '@cardano-sdk/crypto';
33
import { AssetId, PlutusLanguageVersion, ScriptType } from '../../Cardano';
44
import { Base64Blob, HexBlob, ManagedFreeableScope, usingAutoFree } from '@cardano-sdk/util';
55
import { CML } from '../CML';
6-
import { ScriptKind } from '@dcspark/cardano-multiplatform-lib-nodejs';
7-
import { SerializationError, SerializationFailure } from '../../errors';
6+
import { NotImplementedError, SerializationError, SerializationFailure } from '../../errors';
7+
import { PlutusDataKind, ScriptKind } from '@dcspark/cardano-multiplatform-lib-nodejs';
88
import { bytesToHex } from '../../util/misc';
99
import { createCertificate } from './certificate';
1010

@@ -182,18 +182,62 @@ export const getCoreScript = (scope: ManagedFreeableScope, script: CML.Script):
182182
return coreScriptRef;
183183
};
184184

185+
const mapPlutusList = (plutusList: CML.PlutusList): Cardano.PlutusList =>
186+
usingAutoFree((scope) => {
187+
const items: Cardano.PlutusData[] = [];
188+
for (let i = 0; i < plutusList.len(); i++) {
189+
const element = scope.manage(plutusList.get(i));
190+
// eslint-disable-next-line no-use-before-define
191+
items.push(plutusData(element));
192+
}
193+
return { cbor: HexBlob(Buffer.from(plutusList.to_bytes()).toString('hex')), items };
194+
});
195+
196+
export const plutusData = (data: CML.PlutusData): Cardano.PlutusData =>
197+
usingAutoFree((scope) => {
198+
switch (data.kind()) {
199+
case PlutusDataKind.Bytes:
200+
return data.as_bytes()!;
201+
case PlutusDataKind.ConstrPlutusData: {
202+
const constrPlutusData = scope.manage(data.as_constr_plutus_data()!);
203+
return {
204+
cbor: HexBlob(Buffer.from(data.to_bytes()).toString('hex')),
205+
constructor: BigInt(scope.manage(constrPlutusData.alternative()).to_str()),
206+
fields: mapPlutusList(scope.manage(constrPlutusData.data()))
207+
} as Cardano.ConstrPlutusData;
208+
}
209+
case PlutusDataKind.Integer:
210+
return BigInt(scope.manage(data.as_integer()!).to_str());
211+
case PlutusDataKind.List:
212+
return mapPlutusList(scope.manage(data.as_list()!));
213+
case PlutusDataKind.Map: {
214+
const cmlPlutusMap = scope.manage(data.as_map()!);
215+
const coreMap = new Map<Cardano.PlutusData, Cardano.PlutusData>();
216+
const cmlKeys = scope.manage(cmlPlutusMap.keys());
217+
for (let i = 0; i < cmlKeys.len(); i++) {
218+
const cmlKey = scope.manage(cmlKeys.get(i));
219+
coreMap.set(plutusData(cmlKey), plutusData(scope.manage(cmlPlutusMap.get(cmlKey))!));
220+
}
221+
return { cbor: HexBlob(Buffer.from(data.to_bytes()).toString('hex')), data: coreMap } as Cardano.PlutusMap;
222+
}
223+
default:
224+
throw new NotImplementedError(`PlutusData mapping for kind ${data.kind()}`);
225+
}
226+
});
227+
185228
export const txOut = (output: CML.TransactionOutput): Cardano.TxOut =>
186229
usingAutoFree((scope) => {
187-
const dataHashBytes = scope.manage(scope.manage(output.datum())?.as_data_hash())?.to_bytes();
188-
const inlineDatum = scope.manage(scope.manage(output.datum())?.as_inline_data())?.to_bytes();
230+
const cmlDatum = scope.manage(output.datum());
231+
const cmlInlineDatum = scope.manage(cmlDatum?.as_inline_data());
232+
const dataHashBytes = scope.manage(cmlDatum?.as_data_hash())?.to_bytes();
189233
const scriptRef = scope.manage(output.script_ref());
190234
const cmlAddress = scope.manage(output.address());
191235
const byronAddress = scope.manage(cmlAddress.as_byron());
192236
const address = byronAddress ? byronAddress.to_base58() : cmlAddress.to_bech32();
193237

194238
return {
195239
address: Cardano.PaymentAddress(address),
196-
datum: inlineDatum ? bytesToHex(inlineDatum) : undefined,
240+
datum: cmlInlineDatum ? plutusData(cmlInlineDatum) : undefined,
197241
datumHash: dataHashBytes ? Crypto.Hash32ByteBase16.fromHexBlob(bytesToHex(dataHashBytes)) : undefined,
198242
scriptReference: scriptRef ? getCoreScript(scope, scope.manage(scriptRef.script())) : undefined,
199243
value: value(scope.manage(output.amount()))
@@ -333,7 +377,7 @@ export const txWitnessRedeemers = (redeemers?: CML.Redeemers): Cardano.Redeemer[
333377
const redeemerTagKind = scope.manage(reedeemer.tag()).kind();
334378

335379
result.push({
336-
data: HexBlob.fromBytes(scope.manage(reedeemer.data()).to_bytes()),
380+
data: plutusData(scope.manage(reedeemer.data())),
337381
executionUnits: {
338382
memory: Number(scope.manage(exUnits.mem()).to_str()),
339383
steps: Number(scope.manage(exUnits.steps()).to_str())
@@ -345,16 +389,6 @@ export const txWitnessRedeemers = (redeemers?: CML.Redeemers): Cardano.Redeemer[
345389
return result;
346390
});
347391

348-
export const txWitnessDatums = (datums?: CML.PlutusList): Cardano.Datum[] | undefined =>
349-
usingAutoFree((scope) => {
350-
if (!datums) return;
351-
const result: Cardano.Datum[] = [];
352-
for (let j = 0; j < datums.len(); j++) {
353-
result.push(HexBlob.fromBytes(scope.manage(datums.get(j)).to_bytes()));
354-
}
355-
return result;
356-
});
357-
358392
export const txWitnessScripts = (witnessSet: CML.TransactionWitnessSet): Cardano.Script[] | undefined =>
359393
usingAutoFree((scope) => {
360394
const scripts: Cardano.Script[] = [];
@@ -410,7 +444,7 @@ export const txWitnessSet = (witnessSet: CML.TransactionWitnessSet): Cardano.Wit
410444

411445
return {
412446
bootstrap: txWitnessBootstrap(bootstraps),
413-
datums: txWitnessDatums(plutusDatums),
447+
datums: plutusDatums ? mapPlutusList(plutusDatums).items : undefined,
414448
redeemers: txWitnessRedeemers(redeemers),
415449
scripts: txWitnessScripts(witnessSet),
416450
signatures: txSignatures

0 commit comments

Comments
 (0)