Skip to content

Commit

Permalink
Merge pull request #63 from LimeChain/fix/u128
Browse files Browse the repository at this point in the history
Fix UInt128
  • Loading branch information
dastanbeksamatov committed Mar 5, 2021
2 parents 3c7f3e4 + 2a24443 commit 9982786
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 186 deletions.
6 changes: 3 additions & 3 deletions assembly/Arrays/UInt128Array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export class UInt128Array extends AbstractArray<UInt128, u128> {
/**
* @description BoolArray elements decryption implementation
*/
public decodeElement (value: u8[]): DecodedData<u128> {
const u128Instance = UInt128.fromU8a(value);
public decodeElement(value: u8[]): DecodedData<u128> {
const u128Instance = UInt128.fromU8a(value.slice(0, BIT_LENGTH.INT_128));

return new DecodedData<u128>(
u128Instance.unwrap(),
Expand All @@ -43,7 +43,7 @@ export class UInt128Array extends AbstractArray<UInt128, u128> {
const bytesReader = new BytesReader(bytes.slice(index));
const data = bytesReader.readInto<CompactInt>();
for(let i: i32 = 0; i < data.unwrap(); i++){
const element: UInt128 = bytesReader.readInto<UInt128>();
const element: UInt128 = BytesReader.decodeInto<UInt128>(bytesReader.readBytes(BIT_LENGTH.INT_128));
this.values.push(element.unwrap());
}
}
Expand Down
73 changes: 10 additions & 63 deletions assembly/UInt/UInt128.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@

import { u128 } from "as-bignum";
import { UnwrappableCodec } from "../interfaces/UnwrappableCodec";
import { BIT_LENGTH, Bytes } from "../utils/Bytes";
import { ArrayUtils } from "../utils/Arrays";
import { BIT_LENGTH } from "../utils/Bytes";

/** Representation for a UInt128 value in the system. */
export class UInt128 implements UnwrappableCodec<u128> {

private _value: u128;
protected bitLength: i32;

constructor (value: u128 = u128.Zero) {
this._value = value;
this.bitLength = UInt128._computeBitLength(value);
}

/**
Expand All @@ -34,30 +33,13 @@ export class UInt128 implements UnwrappableCodec<u128> {
return this._value;
}

/** Encodes the value as u8[] as per the SCALE codec specification */
/**
* @description Encodes the value as u8[] as per the SCALE codec specification
* */
toU8a (): u8[] {
const bytes = new Array<u8>();
if (this._value < u128.fromU32(1 << 6)) { // if value < 1 << 6
Bytes.appendUint<u8>(bytes, u8(this._value.as<u8>()) << 2, BIT_LENGTH.INT_8); // 1 byte
} else if (this._value < u128.fromU32(1 << 14)) { // if value < 1 << 14
Bytes.appendUint<u16>(bytes, u16(this._value.as<u16>() << 2) + 1, BIT_LENGTH.INT_16); // 2 bytes
} else if (this._value < u128.fromU64(1 << 30)) { // if value < 1 << 30
Bytes.appendUint<u32>(bytes, u32(this._value.as<u32>() << 2) + 2, BIT_LENGTH.INT_32); // 4 bytes
} else {
const valueInBytes = this._value.toBytes();
Bytes.trimEmptyBytes(valueInBytes);

const topSixBits: u8 = u8(valueInBytes.length - 4);
const lengthByte: u8 = (topSixBits << 2) + 3;

// Encode Mode and Bytes length
bytes.push(lengthByte);
// copy the u128 bytes
Bytes.copy(valueInBytes, bytes, 1);
}
return bytes;
return ArrayUtils.toU8Array(this._value.toUint8Array(false));
}

toString(): string {
return this._value.toString();
}
Expand All @@ -68,54 +50,19 @@ export class UInt128 implements UnwrappableCodec<u128> {
*/
populateFromBytes(bytes: u8[], index: i32 = 0): void{
assert(bytes.length - index > 0, 'Invalid input: Byte array should not be empty');
const value = UInt128._computeValue(bytes, index);
this._value = value;
this.bitLength = UInt128._computeBitLength(this._value);
this._value = u128.fromBytesLE(bytes.slice(index));
}
/**
* @description The length of Int when the value is encoded
*/
public encodedLength (): i32 {
return this.bitLength;
}

/**
* Internal static private function to compute value of the UInt128
* @param bytes
* @param index
*/
static _computeValue(bytes: u8[], index: i32 = 0): u128{
const mode = bytes[index] & 0x03;
if (i32(mode) <= 2) {
return new u128(u64(Bytes.decodeSmallInt(bytes, mode, index).value), 0);
}
const topSixBits = bytes[index] >> 2;
const byteLength = topSixBits + 4;

const value = bytes.slice(index + 1, byteLength + index + 1);
Bytes.appendZeroBytes(value, BIT_LENGTH.INT_128);
return u128.fromBytesLE(value)
}

/**
* Internal private function to compute bit length of the value
* @param value
*/
static _computeBitLength(value: u128): i32 {
if (value < u128.fromU32(1 << 6)) return BIT_LENGTH.INT_8;
else if (value < u128.fromU32(1 << 14)) return BIT_LENGTH.INT_16;
else if (value < u128.fromU32(1 << 30)) return BIT_LENGTH.INT_32;
else {
const valueInBytes = value.toBytes();
Bytes.trimEmptyBytes(valueInBytes);
return 1 + valueInBytes.length;
}
return BIT_LENGTH.INT_128;
}

/** Instantiates new UInt128 from u8[] SCALE encoded bytes */
static fromU8a(input: u8[], index: i32 = 0): UInt128 {
assert(input.length - index != 0, 'Invalid input: Byte array should not be empty');
return new UInt128(UInt128._computeValue(input, index));
return new UInt128(u128.fromBytesLE(input.slice(index)));
}

eq(other: UInt128): bool {
Expand Down
95 changes: 62 additions & 33 deletions assembly/__tests__/Arrays/UInt128Array.spec.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import { UInt128Array } from "../../Arrays/UInt128Array";
import { u128 } from "as-bignum";
import {UInt128} from "../../UInt/UInt128";
import { UInt128Array } from "../../Arrays/UInt128Array";

describe("UInt128Array", () => {

it("should encode uint128 array", () => {
const dataInput: Array<Array<u128>> = [
[u128.One], // Expected output: [0x04, 0x04]
[u128.fromU32(1), u128.fromU32(2), u128.fromU32(3), u128.fromU32(4)], // Expected output: [0x10, 0x04, 0x08, 0x0c, 0x10]
[u128.fromU32(16384), u128.fromU32(2), u128.fromU32(3), u128.fromU32(4)], // Expected output: [0x10, 0x02, 0x00, 0x01, 0x00, 0x08, 0x0c, 0x10]
[u128.fromU64(97222587), u128.fromU64(260918714), u128.fromU64(432884242), u128.fromU64(497178323), u128.fromU64(524283510), u128.fromU64(530431722), u128.fromU64(619955096), u128.fromU64(629855926), u128.fromU64(884757710), u128.fromU64(947465305)],
[u128.fromU64(18446744073709551615), u128.fromU64(18446744073709551615)],
[u128.One],
[u128.fromString('54321')],
[u128.fromU32(20001), u128.fromU32(123456)],
[
u128.fromU32(1), u128.fromU64(123456789), u128.fromString('123456789012345'),
u128.fromString('12345678901234567890'), u128.fromString('1234567890123456789012345')
],
[u128.fromU64(18446744073709551615), u128.fromU64(18446744073709551615), u128.Max],
[u128.Max - u128.fromU64(u64.MAX_VALUE)]
];

const expectedOutput: Array<Array<u8>> = [
[0x04, 0x04],
[0x10, 0x04, 0x08, 0x0c, 0x10],
[0x10, 0x02, 0x00, 0x01, 0x00, 0x08, 0x0c, 0x10],
[0x28, 0xee, 0xfe, 0x2d, 0x17, 0xea, 0x36, 0x35, 0x3e, 0x4a, 0x28, 0x35, 0x67, 0x4e, 0x5b, 0x89, 0x76, 0xda, 0xb9, 0xff, 0x7c, 0xaa, 0xfb, 0x76, 0x7e, 0x62, 0x0e, 0xcf, 0x93, 0xda, 0x5a, 0x2b, 0x96, 0x3a, 0x53, 0xf1, 0xd2, 0x66, 0xb1, 0xe4, 0xe1],
[0x08, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
[0x04, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
[4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: [1]
[4, 49, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: 54321
[8, 33, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 226, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: [20001, 123456]
[
20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 205, 91, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121, 223, 13, 134, 72, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 10, 31, 235, 140, 169, 84, 171, 0, 0, 0, 0, 0, 0, 0, 0,
121, 223, 226, 61, 68, 166, 54, 15, 110, 5, 1, 0, 0, 0, 0, 0
],
[
12, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
],
[4, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255]
];

for (let i = 0; i < dataInput.length; i++) {
Expand All @@ -31,20 +40,30 @@ describe("UInt128Array", () => {

it("should decode uint128 array", () => {
const dataInput: Array<Array<u8>> = [
[0x04, 0x04], // Expected output: [1]
[0x10, 0x04, 0x08, 0x0c, 0x10], // Expected output: [1, 2, 3, 4]
[0x10, 0x02, 0x00, 0x01, 0x00, 0x08, 0x0c, 0x10], // Expected output: [16384, 2, 3, 4]
[0x28, 0xee, 0xfe, 0x2d, 0x17, 0xea, 0x36, 0x35, 0x3e, 0x4a, 0x28, 0x35, 0x67, 0x4e, 0x5b, 0x89, 0x76, 0xda, 0xb9, 0xff, 0x7c, 0xaa, 0xfb, 0x76, 0x7e, 0x62, 0x0e, 0xcf, 0x93, 0xda, 0x5a, 0x2b, 0x96, 0x3a, 0x53, 0xf1, 0xd2, 0x66, 0xb1, 0xe4, 0xe1],
[0x08, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
[0x04, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
[4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: [1]
[4, 49, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: 54321
[8, 33, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 226, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: [20001, 123456]
[
20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 205, 91, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121, 223, 13, 134, 72, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 10, 31, 235, 140, 169, 84, 171, 0, 0, 0, 0, 0, 0, 0, 0,
121, 223, 226, 61, 68, 166, 54, 15, 110, 5, 1, 0, 0, 0, 0, 0
],
[
12, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
],
[4, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255]
];

const expectedOutput: Array<Array<u128>> = [
[u128.One],
[u128.One, u128.fromU64(2), u128.fromU64(3), u128.fromU64(4)],
[u128.fromU64(16384), u128.fromU64(2), u128.fromU64(3), u128.fromU64(4)],
[u128.fromU64(97222587), u128.fromU64(260918714), u128.fromU64(432884242), u128.fromU64(497178323), u128.fromU64(524283510), u128.fromU64(530431722), u128.fromU64(619955096), u128.fromU64(629855926), u128.fromU64(884757710), u128.fromU64(947465305)],
[u128.fromU64(18446744073709551615), u128.fromU64(18446744073709551615)],
[u128.fromString('54321')],
[u128.fromU32(20001), u128.fromU32(123456)],
[
u128.fromU32(1), u128.fromU64(123456789), u128.fromString('123456789012345'),
u128.fromString('12345678901234567890'), u128.fromString('1234567890123456789012345')
],
[u128.fromU64(18446744073709551615), u128.fromU64(18446744073709551615), u128.Max],
[u128.Max - u128.fromU64(u64.MAX_VALUE)]
];

Expand All @@ -56,19 +75,29 @@ describe("UInt128Array", () => {

it("should decode uint128 array with populate method", () => {
const dataInput: Array<Array<u8>> = [
[0x04, 0x04], // Expected output: [1]
[0x10, 0x04, 0x0c, 0x0c, 0x10], // Expected output: [1, 3, 3, 4]
[0x10, 0x02, 0x00, 0x01, 0x00, 0x08, 0x0c, 0x10], // Expected output: [16384, 2, 3, 4]
[0x28, 0xee, 0xfe, 0x2d, 0x17, 0xea, 0x36, 0x35, 0x3e, 0x4a, 0x28, 0x35, 0x67, 0x4e, 0x5b, 0x89, 0x76, 0xda, 0xb9, 0xff, 0x7c, 0xaa, 0xfb, 0x76, 0x7e, 0x62, 0x0e, 0xcf, 0x93, 0xda, 0x5a, 0x2b, 0x96, 0x3a, 0x53, 0xf1, 0xd2, 0x66, 0xb1, 0xe4, 0xe1],
[0x08, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
[0x04, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
[4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: [1]
[4, 49, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: 54321
[8, 33, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 226, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // Expected output: [20001, 123456]
[
20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 205, 91, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121, 223, 13, 134, 72, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 10, 31, 235, 140, 169, 84, 171, 0, 0, 0, 0, 0, 0, 0, 0,
121, 223, 226, 61, 68, 166, 54, 15, 110, 5, 1, 0, 0, 0, 0, 0
],
[
12, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
],
[4, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255]
];
const expectedOutput: Array<Array<u128>> = [
[u128.One],
[u128.One, u128.fromU64(3), u128.fromU64(3), u128.fromU64(4)],
[u128.fromU64(16384), u128.fromU64(2), u128.fromU64(3), u128.fromU64(4)],
[u128.fromU64(97222587), u128.fromU64(260918714), u128.fromU64(432884242), u128.fromU64(497178323), u128.fromU64(524283510), u128.fromU64(530431722), u128.fromU64(619955096), u128.fromU64(629855926), u128.fromU64(884757710), u128.fromU64(947465305)],
[u128.fromU64(18446744073709551615), u128.fromU64(18446744073709551615)],
[u128.fromString('54321')],
[u128.fromU32(20001), u128.fromU32(123456)],
[
u128.fromU32(1), u128.fromU64(123456789), u128.fromString('123456789012345'),
u128.fromString('12345678901234567890'), u128.fromString('1234567890123456789012345')
],
[u128.fromU64(18446744073709551615), u128.fromU64(18446744073709551615), u128.Max],
[u128.Max - u128.fromU64(u64.MAX_VALUE)]
];

Expand Down
10 changes: 6 additions & 4 deletions assembly/__tests__/ScaleMap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ describe("String", () => {

const map2U8a: u8[] = [
8,
1, 12, 12, 12, 1, 1, 1, 0, 0, 0, 1, 12, 123, 123, 11, 123, 33, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80,
0xff, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1, 12, 12, 12, 1, 1, 1, 0, 0, 0, 1, 12, 123, 123, 11, 123, 33, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0x00, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64, 226, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
const decodedMap2 = BytesReader.decodeInto<ScaleMap<Hash, UInt128>>(map2U8a);
const scaleMap2 = new ScaleMap<Hash, UInt128>();
scaleMap2.set(new Hash([1, 12, 12, 12, 1, 1, 1, 0, 0, 0, 1, 12, 123, 123, 11, 123, 33, 121]), new UInt128(u128.fromString("549755813888")));
scaleMap2.set(new Hash([0xff, 0x00, 0xab]), new UInt128(u128.fromString("18446744073709551615")));
scaleMap2.set(new Hash([1, 12, 12, 12, 1, 1, 1, 0, 0, 0, 1, 12, 123, 123, 11, 123, 33, 121]), new UInt128(u128.fromU32(1)));
scaleMap2.set(new Hash([0xff, 0x00, 0xab]), new UInt128(u128.fromU32(123456)));
expect<bool>(decodedMap2.eq(scaleMap2)).toStrictEqual(true);
})
})
Loading

0 comments on commit 9982786

Please sign in to comment.