Skip to content

Commit

Permalink
feat(core): added protocol parameters update serialization classes
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelCastilloB committed Aug 22, 2023
1 parent 6576eb9 commit 6440ac3
Show file tree
Hide file tree
Showing 24 changed files with 2,800 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1",
"@foxglove/crc": "^0.0.3",
"@scure/base": "^1.1.1",
"fraction.js": "4.0.1",
"ip-address": "^8.1.0",
"lodash": "^4.17.21",
"ts-custom-error": "^3.2.0",
Expand Down
149 changes: 149 additions & 0 deletions packages/core/src/Serialization/Common/ExUnits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import * as Cardano from '../../Cardano';
import { CborReader, CborWriter } from '../CBOR';
import { HexBlob, InvalidArgumentError } from '@cardano-sdk/util';

const EX_UNITS_ARRAY_SIZE = 2;

/**
* Represent a measure of computational resources, specifically, how much memory
* and CPU a Plutus script will use when executed. It's an essential component to
* estimate the cost of running a Plutus script on the Cardano blockchain.
*
* The two resources measured by ExUnits are memory and CPU. When a Plutus script
* is executed, it consumes both these resources. The ExUnits system quantifies
* this consumption, helping to ensure that scripts don't overrun the system and
* that they terminate in a reasonable amount of time.
*/
export class ExUnits {
#mem: bigint;
#steps: bigint;
#originalBytes: HexBlob | undefined = undefined;

/**
* Initializes a new instance of the ExUnits class.
*
* @param mem The amount of memory the script execution will consume.
* @param steps The number of CPU steps that running ths script will take.
*/
constructor(mem: bigint, steps: bigint) {
this.#mem = mem;
this.#steps = steps;
}

/**
* Serializes a ExUnits into CBOR format.
*
* @returns The ExUnits in CBOR format.
*/
toCbor(): HexBlob {
const writer = new CborWriter();

if (this.#originalBytes) return this.#originalBytes;

// ex_units = [mem: uint, steps: uint]
writer.writeStartArray(EX_UNITS_ARRAY_SIZE);
writer.writeInt(this.#mem);
writer.writeInt(this.#steps);

return writer.encodeAsHex();
}

/**
* Deserializes the ExUnits from a CBOR byte array.
*
* @param cbor The CBOR encoded ExUnits object.
* @returns The new ExUnits instance.
*/
static fromCbor(cbor: HexBlob): ExUnits {
const reader = new CborReader(cbor);

const length = reader.readStartArray();

if (length !== EX_UNITS_ARRAY_SIZE)
throw new InvalidArgumentError(
'cbor',
`Expected an array of ${EX_UNITS_ARRAY_SIZE} elements, but got an array of ${length} elements`
);

const mem = reader.readUInt();
const steps = reader.readUInt();

reader.readEndArray();

const exUnit = new ExUnits(mem, steps);
exUnit.#originalBytes = cbor;

return exUnit;
}

/**
* Creates a Core ExUnits object from the current ExUnits object.
*
* @returns The Core ExUnits object.
*/
toCore(): Cardano.ExUnits {
return {
memory: Number(this.#mem),
steps: Number(this.#steps)
};
}

/**
* Creates a ExUnits object from the given Core ExUnits object.
*
* @param exUnits core ExUnits object.
*/
static fromCore(exUnits: Cardano.ExUnits) {
return new ExUnits(BigInt(exUnits.memory), BigInt(exUnits.steps));
}

/**
* Gets the amount of memory the script execution will consume.
*
* @returns The amount of memory (in bytes).
*/
mem(): bigint {
return this.#mem;
}

/**
* Sets the amount of memory the script execution will consume.
*
* @param mem The amount of memory (in bytes).
*/
setMem(mem: bigint): void {
this.#mem = mem;
this.#originalBytes = undefined;
}

/**
* Gets the number of CPU steps that running ths script will take.
*
* @returns The number of CPU steps.
*/
steps(): bigint {
return this.#steps;
}

/**
* Sets the number of CPU steps that running ths script will take.
*
* @param steps The number of CPU steps.
*/
setSteps(steps: bigint): void {
this.#steps = steps;
this.#originalBytes = undefined;
}

/**
* Adds the memory and cpu steps of the current ExUnits and the given ExUnits and returns the result.
*
* @param other The other ExUnits to be added with this ExUnits.
*/
add(other: ExUnits): ExUnits {
const mem = this.#mem + other.#mem;
const steps = this.#steps + other.#steps;

return new ExUnits(mem, steps);
}
}
146 changes: 146 additions & 0 deletions packages/core/src/Serialization/Common/ProtocolVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import * as Cardano from '../../Cardano';
import { CborReader, CborWriter } from '../CBOR';
import { HexBlob, InvalidArgumentError } from '@cardano-sdk/util';

const PROTOCOL_VERSION_ARRAY_SIZE = 2;

/**
* The protocol can be thought of as the set of rules that nodes in the network agree to follow,
* and this versioning system helps nodes to keep track of which set of rules they are adhering to and also
* allows for the decentralized updating of the protocol parameters without requiring a hard fork.
*/
export class ProtocolVersion {
#major: number;
#minor: number;
#originalBytes: HexBlob | undefined = undefined;

/**
* Initializes a new instance of the ProtocolVersion class.
*
* @param major Changes when there are significant alterations to the protocol that are not backward compatible.
* It would require nodes to upgrade to continue participating in the network.
* @param minor Reflects backward-compatible changes. Nodes running an older version can still communicate with
* nodes running the updated version, but they might not take advantage of new features.
*/
constructor(major: number, minor: number) {
this.#major = major;
this.#minor = minor;
}

/**
* Serializes a ProtocolVersion into CBOR format.
*
* @returns The ProtocolVersion in CBOR format.
*/
toCbor(): HexBlob {
const writer = new CborWriter();

if (this.#originalBytes) return this.#originalBytes;

// next_major_protocol_version = 9
// major_protocol_version = 1..next_major_protocol_version
// protocol_version = (major_protocol_version, uint32)
writer.writeStartArray(PROTOCOL_VERSION_ARRAY_SIZE);
writer.writeInt(this.#major);
writer.writeInt(this.#minor);

return writer.encodeAsHex();
}

/**
* Deserializes the ProtocolVersion from a CBOR byte array.
*
* @param cbor The CBOR encoded ProtocolVersion object.
* @returns The new ProtocolVersion instance.
*/
static fromCbor(cbor: HexBlob): ProtocolVersion {
const reader = new CborReader(cbor);

const length = reader.readStartArray();

if (length !== PROTOCOL_VERSION_ARRAY_SIZE)
throw new InvalidArgumentError(
'cbor',
`Expected an array of ${PROTOCOL_VERSION_ARRAY_SIZE} elements, but got an array of ${length} elements`
);

const major = Number(reader.readInt());
const minor = Number(reader.readInt());

reader.readEndArray();

const version = new ProtocolVersion(major, minor);
version.#originalBytes = cbor;

return version;
}

/**
* Creates a Core ProtocolVersion object from the current ProtocolVersion object.
*
* @returns The Core ProtocolVersion object.
*/
toCore(): Cardano.ProtocolVersion {
return {
major: Number(this.#major),
minor: Number(this.#minor)
};
}

/**
* Creates a ProtocolVersion object from the given Core ProtocolVersion object.
*
* @param version core ProtocolVersion object.
*/
static fromCore(version: Cardano.ProtocolVersion) {
return new ProtocolVersion(version.major, version.minor);
}

/**
* Gets the major component of the version.
*
* This number is increased when there are changes that are significant alterations to
* the protocol that are not backward compatible.
*
* It would require nodes to upgrade to continue participating in the network.
*
* @returns The major version.
*/
major(): number {
return this.#major;
}

/**
* Sets the major component of the version.
*
* @param major The major version.
*/
setMajor(major: number): void {
this.#major = major;
this.#originalBytes = undefined;
}

/**
* Gets the minor component of the version.
*
* This number is increased when changes are backward-compatible.
*
* Nodes running an older version can still communicate with nodes running the
* updated version, but they might not take advantage of new features.
*
* @returns The minor version.
*/
minor(): number {
return this.#minor;
}

/**
* Sets the minor component of the version.
*
* @param minor The minor version.
*/
setMinor(minor: number): void {
this.#minor = minor;
this.#originalBytes = undefined;
}
}
21 changes: 21 additions & 0 deletions packages/core/src/Serialization/Common/UnitInterval.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Cardano from '../../Cardano';
import { CborReader, CborTag, CborWriter } from '../CBOR';
import { HexBlob, InvalidArgumentError } from '@cardano-sdk/util';
import Fraction from 'fraction.js';

const UNIT_INTERVAL_ARRAY_SIZE = 2;

Expand All @@ -27,6 +28,17 @@ export class UnitInterval {
this.#denominator = denominator;
}

/**
* Initializes a new instance of the UnitInterval class.
*
* @param number The float number.
*/
static fromFloat(number: number | undefined): UnitInterval | undefined {
if (number === undefined) return undefined;
const fraction = new Fraction(number);
return new UnitInterval(BigInt(fraction.n), BigInt(fraction.d));
}

/**
* Serializes a UnitInterval into CBOR format.
*
Expand Down Expand Up @@ -138,4 +150,13 @@ export class UnitInterval {
this.#denominator = denominator;
this.#originalBytes = undefined;
}

/**
* Converts this UnitInterval instance into a float.
*
* @returns The init interval as a float.
*/
toFloat(): number {
return Number(this.#numerator) / Number(this.#denominator);
}
}
2 changes: 2 additions & 0 deletions packages/core/src/Serialization/Common/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './UnitInterval';
export * from './ExUnits';
export * from './ProtocolVersion';
Loading

0 comments on commit 6440ac3

Please sign in to comment.