Skip to content

Commit

Permalink
feat(core): add estimateBoxSize method
Browse files Browse the repository at this point in the history
  • Loading branch information
capt-nemo429 committed Apr 3, 2023
1 parent 78f724b commit 5931453
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 7 deletions.
52 changes: 50 additions & 2 deletions packages/core/src/serializer/sigma/boxSerializer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Box } from "@fleet-sdk/common";
import { serializeBox } from "./boxSerializer";
import { Box, ensureBigInt, hexSize } from "@fleet-sdk/common";
import { OutputBuilder, SAFE_MIN_BOX_VALUE } from "../../builder";
import { manyTokensBoxesMock, regularBoxesMock, validBoxesMock } from "../../tests/mocks/mockBoxes";
import { estimateBoxSize, serializeBox } from "./boxSerializer";

describe("Serialize ErgoBox", () => {
const testVectors = [
Expand Down Expand Up @@ -252,4 +254,50 @@ describe("Serialize ErgoBox", () => {
} as unknown as Box<string>);
}).toThrow();
});

it("Should estimate the box size in bytes", () => {
for (const tv of testVectors) {
expect(estimateBoxSize(tv.json)).toBe(hexSize(tv.serialized));
}

for (const box of regularBoxesMock) {
expect(estimateBoxSize(box)).toBe(serializeBox(box).length);
}

for (const box of manyTokensBoxesMock) {
expect(estimateBoxSize(box)).toBe(serializeBox(box).length);
}

for (const box of validBoxesMock) {
expect(estimateBoxSize(box)).toBe(serializeBox(box).length);
}
});

it("Should estimate the box size in bytes with custom value", () => {
for (const tv of testVectors) {
expect(estimateBoxSize(tv.json, ensureBigInt(tv.json.value) * 4n)).toBeGreaterThan(
hexSize(tv.serialized)
);
}
});

it("Should estimate output builder size in bytes", () => {
for (const tv of testVectors) {
const output = new OutputBuilder(tv.json.value, tv.json.address)
.addTokens(tv.json.assets)
.setAdditionalRegisters(tv.json.additionalRegisters)
.setCreationHeight(tv.json.creationHeight);

expect(estimateBoxSize(output)).toBeGreaterThanOrEqual(hexSize(tv.serialized));
}
});

it("Should fail if creation height is undefined", () => {
const output = new OutputBuilder(
SAFE_MIN_BOX_VALUE,
"9hY16vzHmmfyVBwKeFGHvb2bMFsG94A1u7To1QWtUokACyFVENQ"
);

expect(() => estimateBoxSize(output)).toThrow();
});
});
56 changes: 55 additions & 1 deletion packages/core/src/serializer/sigma/boxSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import {
Amount,
Box,
BoxCandidate,
hexSize,
isUndefined,
NonMandatoryRegisters,
some,
TokenAmount
} from "@fleet-sdk/common";
import { ensureBigInt, isDefined, isEmpty } from "@fleet-sdk/common";
import { OutputBuilder } from "../../builder";
import { ErgoBox } from "../../models/ergoBox";
import { estimateVLQSize } from "../vlq";
import { SigmaWriter } from "./sigmaWriter";

export function serializeBox(box: Box<Amount> | ErgoBox): SigmaWriter;
Expand Down Expand Up @@ -43,7 +47,9 @@ export function serializeBox(
}
}

function isBox<T extends Amount>(box: Box<Amount> | ErgoBox | BoxCandidate<Amount>): box is Box<T> {
function isBox<T extends Amount>(
box: Box<Amount> | ErgoBox | BoxCandidate<Amount> | OutputBuilder
): box is Box<T> {
const castedBox = box as Box<T>;

return isDefined(castedBox.transactionId) && isDefined(castedBox.index);
Expand Down Expand Up @@ -92,3 +98,51 @@ function writeRegisters(writer: SigmaWriter, registers: NonMandatoryRegisters):
}
}
}

const MAX_UINT16_VALUE = 65535;
const TRANSACTION_ID_BYTE_SIZE = 32;

/**
* Estimates the byte size a box.
* @returns byte size of the box.
*/
export function estimateBoxSize(
box: Box<Amount> | BoxCandidate<Amount> | OutputBuilder,
withValue?: Amount
): number {
if (isUndefined(box.creationHeight)) {
throw new Error("Box size estimation error: creation height is undefined.");
}

let size = 0;

if (isDefined(withValue)) {
size += estimateVLQSize(withValue);
} else {
size += estimateVLQSize(box.value);
}

size += hexSize(box.ergoTree);
size += estimateVLQSize(box.creationHeight);

size += estimateVLQSize(box.assets.length);
size += box.assets.reduce(
(acc: number, curr) => (acc += hexSize(curr.tokenId) + estimateVLQSize(curr.amount)),
0
);

let registersLength = 0;
for (const key in box.additionalRegisters) {
const register = box.additionalRegisters[key as keyof NonMandatoryRegisters];
if (register) {
size += hexSize(register);
registersLength++;
}
}
size += estimateVLQSize(registersLength);

size += TRANSACTION_ID_BYTE_SIZE;
size += estimateVLQSize(isBox(box) ? box.index : MAX_UINT16_VALUE);

return size;
}
18 changes: 15 additions & 3 deletions packages/core/src/serializer/vlq.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SigmaReader } from "./sigma/sigmaReader";
import { SigmaWriter } from "./sigma/sigmaWriter";
import { readBigVLQ, readVLQ, writeBigVLQ, writeVLQ } from "./vlq";
import { estimateVLQSize, readBigVLQ, readVLQ, writeBigVLQ, writeVLQ } from "./vlq";

describe("32-bit VLQ encoding/decoding", () => {
describe("VLQ encoding/decoding", () => {
const testVectors = [
{ uint: 0, bytes: Uint8Array.from([0x00]) },
{ uint: 126, bytes: Uint8Array.from([0x7e]) },
Expand Down Expand Up @@ -51,9 +51,15 @@ describe("32-bit VLQ encoding/decoding", () => {
expect(readVLQ(new SigmaReader(toVLQBytes(n)))).toBe(n);
});
});

it("Should estimate the byte size of numbers", () => {
for (const tv of testVectors) {
expect(estimateVLQSize(tv.uint)).toBe(tv.bytes.length);
}
});
});

describe("64-bit VLQ encoding/decoding", () => {
describe("Big VLQ encoding/decoding", () => {
function toBigVLQBytes(value: bigint) {
return writeBigVLQ(new SigmaWriter(100), value).toBytes();
}
Expand Down Expand Up @@ -102,4 +108,10 @@ describe("64-bit VLQ encoding/decoding", () => {
expect(readBigVLQ(new SigmaReader(toBigVLQBytes(n)))).toBe(n);
});
});

it("Should estimate the byte size of numbers", () => {
for (const tv of testVectors) {
expect(estimateVLQSize(tv.uint)).toBe(tv.bytes.length);
}
});
});
19 changes: 18 additions & 1 deletion packages/core/src/serializer/vlq.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { _0n, _127n, _128n, _7n } from "@fleet-sdk/common";
import { _0n, _127n, _128n, _7n, ensureBigInt } from "@fleet-sdk/common";
import { SigmaReader } from "./sigma/sigmaReader";
import { SigmaWriter } from "./sigma/sigmaWriter";

Expand Down Expand Up @@ -113,3 +113,20 @@ export function readBigVLQ(reader: SigmaReader): bigint {

return value;
}

/**
* Estimates the byte size of a given unsigned integer.
* @param value: the value to be evaluated.
* @returns the byte size of the value.
*/
export function estimateVLQSize(value: number | bigint | string): number {
value = ensureBigInt(value);
let size = 0;

do {
size++;
value /= _128n;
} while (value > _0n);

return size;
}

0 comments on commit 5931453

Please sign in to comment.