-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Take the latest PVM and adjust code accordingly
- Loading branch information
Showing
51 changed files
with
1,542 additions
and
394 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import assert from "node:assert"; | ||
import { test } from "node:test"; | ||
import { Bytes, BytesBlob } from "./bytes"; | ||
|
||
test("BytesBlob", async (t) => { | ||
await t.test("should fail if 0x is missing", () => { | ||
try { | ||
BytesBlob.parseBlob("ff2f"); | ||
assert.fail("Should throw an exception"); | ||
} catch (e) { | ||
assert.strictEqual(`${e}`, "Error: Invalid hex string: ff2f."); | ||
} | ||
}); | ||
|
||
await t.test("parse 0x-prefixed hex string into blob of bytes", () => { | ||
const input = "0x2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c"; | ||
const result = BytesBlob.parseBlob(input); | ||
|
||
assert.deepStrictEqual(new Uint8Array(result.buffer), new Uint8Array([47, 163, 246, 134, 223, 135, 105, 149, 22, 126, 124, 46, 93, 116, 196, 199, 182, 228, 143, 128, 104, 254, 14, 68, 32, 131, 68, 212, 128, 247, 144, 76])); | ||
}); | ||
}); | ||
|
||
test("Bytes", async (t) => { | ||
await t.test("should fail in case of length mismatch", () => { | ||
const input = "0x9c2d3bce7aa0a5857c67a85247365d2035f7d9daec2b515e86086584ad5e8644"; | ||
|
||
try { | ||
Bytes.parseBytes(input, 16); | ||
assert.fail("Should throw an exception"); | ||
} catch (e) { | ||
assert.strictEqual(`${e}`, "Error: Input string too long. Expected 16, got 32"); | ||
} | ||
}); | ||
|
||
await t.test("parse 0x-prefixed, fixed length bytes vector", () => { | ||
const input = "0x9c2d3bce7aa0a5857c67a85247365d2035f7d9daec2b515e86086584ad5e8644"; | ||
|
||
const bytes = Bytes.parseBytes(input, 32); | ||
|
||
assert.deepStrictEqual(new Uint8Array(bytes.view.buffer), new Uint8Array([156, 45, 59, 206, 122, 160, 165, 133, 124, 103, 168, 82, 71, 54, 93, 32, 53, 247, 217, 218, 236, 43, 81, 94, 134, 8, 101, 132, 173, 94, 134, 68])); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
function assert(value: boolean, description: string): asserts value is true { | ||
if (!value) throw new Error(description); | ||
} | ||
|
||
function bufferToHexString(buffer: ArrayBuffer): string { | ||
// TODO [ToDr] consider using TextDecoder API? | ||
let s = "0x"; | ||
const asUint = new Uint8Array(buffer); | ||
for (const v of asUint) { | ||
s += v.toString(16).padStart(2, "0"); | ||
} | ||
return s; | ||
} | ||
|
||
export class BytesBlob { | ||
readonly buffer: ArrayBuffer = new ArrayBuffer(0); | ||
readonly length: number = 0; | ||
|
||
constructor(buffer: ArrayBuffer) { | ||
this.buffer = buffer; | ||
this.length = buffer.byteLength; | ||
} | ||
|
||
toString() { | ||
return bufferToHexString(this.buffer); | ||
} | ||
|
||
static parseBlob(v: string): BytesBlob { | ||
const len = v.length; | ||
if (len % 2 === 1 || !v.startsWith("0x")) { | ||
throw new Error(`Invalid hex string: ${v}.`); | ||
} | ||
// NOTE [ToDr] alloc | ||
const buffer = new ArrayBuffer(len / 2 - 1); | ||
const bytes = new Uint8Array(buffer); | ||
for (let i = 2; i < len - 1; i += 2) { | ||
const c = v.substring(i, i + 2); | ||
bytes[i / 2 - 1] = Number.parseInt(c, 16); | ||
} | ||
|
||
return new BytesBlob(buffer); | ||
} | ||
} | ||
|
||
export class Bytes<T extends number> { | ||
readonly view: DataView = new DataView(new ArrayBuffer(0)); | ||
readonly length: T; | ||
|
||
constructor(view: DataView, len: T) { | ||
assert(view.byteLength === len, `Given buffer has incorrect size ${view.byteLength} vs expected ${len}`); | ||
this.view = view; | ||
this.length = len; | ||
} | ||
|
||
toString() { | ||
return bufferToHexString(this.view.buffer); | ||
} | ||
|
||
static parseBytes<X extends number>(v: string, len: X): Bytes<X> { | ||
if (v.length > 2 * len + 2) { | ||
throw new Error(`Input string too long. Expected ${len}, got ${v.length / 2 - 1}`); | ||
} | ||
|
||
const blob = BytesBlob.parseBlob(v); | ||
return new Bytes(new DataView(blob.buffer), len); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import type { Bytes } from "./bytes"; | ||
import type { Opaque } from "./opaque"; | ||
|
||
export type Ed25519Key = Opaque<Bytes<32>, "ed25519">; | ||
export type BandersnatchKey = Opaque<Bytes<32>, "BandersnatchKey">; | ||
export type BlsKey = Opaque<Bytes<144>, "bls">; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import type { Bytes } from "./bytes"; | ||
import type { Opaque } from "./opaque"; | ||
|
||
export type Hash = Bytes<32>; | ||
export type EntropyHash = Opaque<Hash, "entropy">; |
226 changes: 226 additions & 0 deletions
226
src/pvm-packages/jam-codec/decode-natural-number.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
import assert from "node:assert"; | ||
import { test } from "node:test"; | ||
|
||
import { decodeNaturalNumber } from "./decode-natural-number"; | ||
|
||
test("decodeNaturalNumber", async (t) => { | ||
await t.test("decode 0", () => { | ||
const encodedBytes = new Uint8Array([0]); | ||
const expectedValue = 0n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode single byte min value", () => { | ||
const encodedBytes = new Uint8Array([1]); | ||
const expectedValue = 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode single byte max value", () => { | ||
const encodedBytes = new Uint8Array([127]); | ||
const expectedValue = 127n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 2 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([128, 128]); | ||
const expectedValue = 128n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 2 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([191, 255]); | ||
const expectedValue = 2n ** 14n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 3 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([192, 0, 0x40]); | ||
const expectedValue = 2n ** 14n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 3 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([192 + 31, 0xff, 0xff]); | ||
const expectedValue = 2n ** 21n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 4 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([0xe0, 0, 0, 0x20]); | ||
const expectedValue = 2n ** 21n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 4 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([0xe0 + 15, 0xff, 0xff, 0xff]); | ||
const expectedValue = 2n ** 28n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 5 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([256 - 16, 0, 0, 0, 0x10]); | ||
const expectedValue = 2n ** 28n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 5 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([256 - 16 + 7, 0xff, 0xff, 0xff, 0xff]); | ||
const expectedValue = 2n ** 35n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 6 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([256 - 8, 0, 0, 0, 0, 0x08]); | ||
const expectedValue = 2n ** 35n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 6 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([256 - 8 + 3, 0xff, 0xff, 0xff, 0xff, 0xff]); | ||
const expectedValue = 2n ** 42n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 7 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([256 - 4, 0, 0, 0, 0, 0, 0x04]); | ||
const expectedValue = 2n ** 42n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 7 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([256 - 4 + 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); | ||
const expectedValue = 2n ** 49n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 8 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([256 - 2, 0, 0, 0, 0, 0, 0, 0x02]); | ||
const expectedValue = 2n ** 49n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 8 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([256 - 2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); | ||
const expectedValue = 2n ** 56n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 9 bytes min value", () => { | ||
const encodedBytes = new Uint8Array([255, 0, 0, 0, 0, 0, 0, 0, 0x01]); | ||
const expectedValue = 2n ** 56n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 9 bytes max value", () => { | ||
const encodedBytes = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255]); | ||
const expectedValue = 2n ** 64n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, encodedBytes.length); | ||
}); | ||
|
||
await t.test("decode 0 with extra bytes", () => { | ||
const encodedBytes = new Uint8Array([0, 1, 2, 3]); | ||
const expectedValue = 0n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, 1); | ||
}); | ||
|
||
await t.test("decode 7 bytes number with extra bytes ", () => { | ||
const encodedBytes = new Uint8Array([256 - 4 + 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0x2]); | ||
const expectedValue = 2n ** 49n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, 7); | ||
}); | ||
|
||
await t.test("decode 9 bytes number with extra bytes", () => { | ||
const encodedBytes = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 2, 3]); | ||
const expectedValue = 2n ** 64n - 1n; | ||
|
||
const result = decodeNaturalNumber(encodedBytes); | ||
|
||
assert.strictEqual(result.value, expectedValue); | ||
assert.strictEqual(result.bytesToSkip, 9); | ||
}); | ||
}); |
Oops, something went wrong.