Skip to content

Commit

Permalink
feat(core): added custom PlutusData serialization classes
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelCastilloB authored and mkazlauskas committed Aug 1, 2023
1 parent a040577 commit 05fb0cc
Show file tree
Hide file tree
Showing 10 changed files with 1,102 additions and 125 deletions.
38 changes: 0 additions & 38 deletions packages/core/src/Serialization/PlutusData.ts

This file was deleted.

136 changes: 136 additions & 0 deletions packages/core/src/Serialization/PlutusData/ConstrPlutusData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { CborReader, CborWriter } from '../CBOR';
import { HexBlob } from '@cardano-sdk/util';
import { PlutusList } from './PlutusList';
import { hexToBytes } from '../../util/misc';

const GENERAL_FORM_TAG = 102n;
const ALTERNATIVE_TAG_OFFSET = 7n;

/**
* The main datatype `Constr` represents the nth constructor
* along with its arguments.
*
* Remark: We don't directly serialize the alternative in the tag,
* instead the scheme is:
*
* - Alternatives 0-6 -> tags 121-127, followed by the arguments in a list.
* - Alternatives 7-127 -> tags 1280-1400, followed by the arguments in a list.
* - Any alternatives, including those that don't fit in the above -> tag 102 followed by a list containing
* an unsigned integer for the actual alternative, and then the arguments in a (nested!) list.
*/
export class ConstrPlutusData {
private readonly _alternative: bigint = 0n;
private readonly _data = new PlutusList();

/**
* Initializes a new instance of the ConstrPlutusData class.
*
* @param alternative Get the Constr alternative. The alternative represents the nth
* constructor of a 'Sum Type'.
* @param data Gets the list of arguments of the 'Sum Type' as a 'PlutusList'.
*/
constructor(alternative: bigint, data: PlutusList) {
this._alternative = alternative;
this._data = data;
}

/**
* Serializes this ConstrPlutusData instance into its CBOR representation as a Uint8Array.
*
* @returns The CBOR representation of this instance as a Uint8Array.
*/
toCbor(): HexBlob {
const writer = new CborWriter();
const compactTag = ConstrPlutusData.alternativeToCompactCborTag(this._alternative);

writer.writeTag(Number(compactTag));

if (compactTag !== GENERAL_FORM_TAG) {
writer.writeEncodedValue(hexToBytes(this._data.toCbor()));
} else {
writer.writeStartArray(2);
writer.writeInt(this._alternative);
writer.writeEncodedValue(hexToBytes(this._data.toCbor()));
}

return HexBlob.fromBytes(writer.encode());
}

/**
* Deserializes a ConstrPlutusData instance from its CBOR representation.
*
* @param cbor The CBOR representation of this instance as a Uint8Array.
* @returns A ConstrPlutusData instance.
*/
static fromCbor(cbor: HexBlob): ConstrPlutusData {
const reader = new CborReader(cbor);

const tag = reader.readTag();

if (tag === Number(GENERAL_FORM_TAG)) {
reader.readStartArray();

const alternative = reader.readInt();
const data = reader.readEncodedValue();
const plutusList = PlutusList.fromCbor(HexBlob.fromBytes(data));

reader.readEndArray();

return new ConstrPlutusData(alternative, plutusList);
}

const alternative = ConstrPlutusData.compactCborTagToAlternative(BigInt(tag));
const data = reader.readEncodedValue();
const plutusList = PlutusList.fromCbor(HexBlob.fromBytes(data));

return new ConstrPlutusData(alternative, plutusList);
}

/**
* Gets the ConstrPlutusData alternative. The alternative represents the nth
* constructor of a 'Sum Type'.
*
* @returns The alternative constructor of the 'Sum Type'.
*/
getAlternative(): bigint {
return this._alternative;
}

/**
* The list of arguments of the 'Sum Type' as a 'PlutusList'.
*
* @returns The list of arguments.
*/
getData(): PlutusList {
return this._data;
}

// Mapping functions to and from alternative to and from CBOR tags.
// See https://github.com/input-output-hk/plutus/blob/1f31e640e8a258185db01fa899da63f9018c0e85/plutus-core/plutus-core/src/PlutusCore/Data.hs#L69-L72

/**
* Converts a CBOR compact tag to a Constr alternative.
*
* @param tag The tag to be converted.
* @returns The Constr alternative.
*/
private static compactCborTagToAlternative(tag: bigint): bigint {
if (tag >= 121n && tag <= 127) return tag - 121n;
if (tag >= 1280n && tag <= 1400) return tag - 1280n + ALTERNATIVE_TAG_OFFSET;

return GENERAL_FORM_TAG;
}

/**
* Converts the constructor alternative to its CBOR compact tag.
*
* @param alternative The Constr alternative to be converted.
* @returns The compact CBOR tag.
*/
private static alternativeToCompactCborTag(alternative: bigint): bigint {
if (alternative <= 6n) return 121n + alternative;
if (alternative >= 7n && alternative <= 127n) return 1280n - ALTERNATIVE_TAG_OFFSET + alternative;

return GENERAL_FORM_TAG;
}
}
Loading

0 comments on commit 05fb0cc

Please sign in to comment.