Skip to content

Commit

Permalink
Merge fc927ae into 682aee7
Browse files Browse the repository at this point in the history
  • Loading branch information
jacogr committed Oct 7, 2018
2 parents 682aee7 + fc927ae commit 67dd6b2
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 49 deletions.
8 changes: 4 additions & 4 deletions packages/types/src/Bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import u8aConcat from '@polkadot/util/u8a/concat';

import Compact from './codec/Compact';
import Compact, { DEFAULT_LENGTH_BITS } from './codec/Compact';
import U8a from './codec/U8a';

// A Bytes. The significant difference between this and a normal Uint8Array is that
Expand All @@ -16,11 +16,11 @@ export default class Bytes extends U8a {
}

byteLength (): number {
return this.length + Compact.encode(this.length).length;
return this.length + Compact.encodeU8a(this.length, DEFAULT_LENGTH_BITS).length;
}

fromU8a (input: Uint8Array): Bytes {
const [offset, length] = Compact.decode(input);
const [offset, length] = Compact.decodeU8a(input, DEFAULT_LENGTH_BITS);

super.fromU8a(input.subarray(offset, offset + length.toNumber()));

Expand All @@ -31,7 +31,7 @@ export default class Bytes extends U8a {
return isBare
? this.raw
: u8aConcat(
Compact.encode(this.length),
Compact.encodeU8a(this.length, DEFAULT_LENGTH_BITS),
this.raw
);
}
Expand Down
13 changes: 13 additions & 0 deletions packages/types/src/Compact128.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import { AnyNumber } from './types';

import Compact from './codec/Compact';

export default class Compact128 extends Compact {
constructor (value?: AnyNumber) {
super(value, 128);
}
}
13 changes: 13 additions & 0 deletions packages/types/src/Compact16.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import { AnyNumber } from './types';

import Compact from './codec/Compact';

export default class Compact16 extends Compact {
constructor (value?: AnyNumber) {
super(value, 16, false);
}
}
13 changes: 13 additions & 0 deletions packages/types/src/Compact256.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import { AnyNumber } from './types';

import Compact from './codec/Compact';

export default class Compact256 extends Compact {
constructor (value?: AnyNumber) {
super(value, 256);
}
}
13 changes: 13 additions & 0 deletions packages/types/src/Compact32.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import { AnyNumber } from './types';

import Compact from './codec/Compact';

export default class Compact32 extends Compact {
constructor (value?: AnyNumber) {
super(value, 32, false);
}
}
13 changes: 13 additions & 0 deletions packages/types/src/Compact64.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import { AnyNumber } from './types';

import Compact from './codec/Compact';

export default class Compact64 extends Compact {
constructor (value?: AnyNumber) {
super(value, 64, false);
}
}
8 changes: 4 additions & 4 deletions packages/types/src/Extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import hexToU8a from '@polkadot/util/hex/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToHex from '@polkadot/util/u8a/toHex';

import Compact from './codec/Compact';
import Compact, { DEFAULT_LENGTH_BITS } from './codec/Compact';
import Struct from './codec/Struct';
import ExtrinsicSignature from './ExtrinsicSignature';
import Hash from './Hash';
Expand Down Expand Up @@ -82,7 +82,7 @@ export default class Extrinsic extends Struct {
byteLength (): number {
const length = this.length;

return length + Compact.encode(length).length;
return length + Compact.encodeU8a(length, DEFAULT_LENGTH_BITS).length;
}

fromJSON (input: any): Extrinsic {
Expand All @@ -92,7 +92,7 @@ export default class Extrinsic extends Struct {
}

fromU8a (input: Uint8Array): Extrinsic {
const [offset, length] = Compact.decode(input);
const [offset, length] = Compact.decodeU8a(input, DEFAULT_LENGTH_BITS);

super.fromU8a(input.subarray(offset, offset + length.toNumber()));

Expand All @@ -111,7 +111,7 @@ export default class Extrinsic extends Struct {
return isBare
? encoded
: u8aConcat(
Compact.encode(encoded.length),
Compact.encodeU8a(encoded.length, DEFAULT_LENGTH_BITS),
encoded
);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/types/src/Text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import u8aToUtf8 from '@polkadot/util/u8a/toUtf8';
import u8aConcat from '@polkadot/util/u8a/concat';

import Base from './codec/Base';
import Compact from './codec/Compact';
import Compact, { DEFAULT_LENGTH_BITS } from './codec/Compact';

// This is a string wrapper, along with the length. It is used both for strings as well
// as stuff like documentation.
Expand All @@ -31,11 +31,11 @@ export default class Text extends Base<string> {
}

byteLength (): number {
return this.length + Compact.encode(this.length).length;
return this.length + Compact.encodeU8a(this.length, DEFAULT_LENGTH_BITS).length;
}

fromU8a (input: Uint8Array): Text {
const [offset, length] = Compact.decode(input);
const [offset, length] = Compact.decodeU8a(input, DEFAULT_LENGTH_BITS);

this.raw = u8aToUtf8(input.subarray(offset, offset + length.toNumber()));

Expand All @@ -62,7 +62,7 @@ export default class Text extends Base<string> {
return isBare
? encoded
: u8aConcat(
Compact.encode(this.length),
Compact.encodeU8a(this.length, DEFAULT_LENGTH_BITS),
encoded
);
}
Expand Down
48 changes: 36 additions & 12 deletions packages/types/src/codec/Compact.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,79 +8,103 @@ import Compact from './Compact';
import UInt from './UInt';

describe('Compact', () => {
describe('encode', () => {
describe('encodeU8a', () => {
it('encodes short u8', () => {
expect(
Compact.encode(18)
Compact.encodeU8a(18, 8)
).toEqual(
new Uint8Array([18 << 2])
);
});

it('encodes max u8 values', () => {
expect(
Compact.encode(new UInt(63))
Compact.encodeU8a(new UInt(63), 16)
).toEqual(
new Uint8Array([0b11111100])
);
});

it('encodes basic u16 value', () => {
expect(
Compact.encode(511)
Compact.encodeU8a(511, 32)
).toEqual(
new Uint8Array([0b11111101, 0b00000111])
);
});

it('encodes basic ua6 (not at edge)', () => {
expect(
Compact.encode(111)
Compact.encodeU8a(111, 32)
).toEqual(
new Uint8Array([0xbd, 0x01])
);
});

it('encodes basic u32 values (short)', () => {
expect(
Compact.encode(0xffff)
Compact.encodeU8a(0xffff, 32)
).toEqual(
new Uint8Array([254, 255, 3, 0])
);
});

it('encodes basic u32 values (full)', () => {
expect(
Compact.encode(0xfffffff9)
Compact.encodeU8a(0xfffffff9, 32)
).toEqual(
new Uint8Array([3, 249, 255, 255, 255])
);
});
});

describe('decode', () => {
describe('decodeU8a', () => {
it('decoded u8 value', () => {
expect(
Compact.decode(new Uint8Array([0b11111100]))
Compact.decodeU8a(new Uint8Array([0b11111100]), 32)
).toEqual([1, new BN(63)]);
});

it('decodes from same u16 encoded value', () => {
expect(
Compact.decode(new Uint8Array([0b11111101, 0b00000111]))
Compact.decodeU8a(new Uint8Array([0b11111101, 0b00000111]), 32)
).toEqual([2, new BN(511)]);
});

it('decodes from same u32 encoded value (short)', () => {
expect(
Compact.decode(new Uint8Array([254, 255, 3, 0]))
Compact.decodeU8a(new Uint8Array([254, 255, 3, 0]), 32)
).toEqual([4, new BN(0xffff)]);
});

it('decodes from same u32 encoded value (full)', () => {
expect(
Compact.decode(new Uint8Array([3, 249, 255, 255, 255]))
Compact.decodeU8a(new Uint8Array([3, 249, 255, 255, 255]), 32)
).toEqual([5, new BN(0xfffffff9)]);
});

it('decodes from same u32 as u64 encoded value (full, default)', () => {
expect(
Compact.decodeU8a(new Uint8Array([3, 249, 255, 255, 255]), 64)
).toEqual([9, new BN(0xfffffff9)]);
});
});

it('has the correct byteLength for constructor values (default)', () => {
expect(
new Compact(0xfffffff9).byteLength()
).toEqual(9);
});

it('has the correct byteLength for constructor values (u32)', () => {
expect(
new Compact(0xfffffff9, 32).byteLength()
).toEqual(5);
});

it('constructs properly via fromU8a', () => {
expect(
new Compact().fromU8a(new Uint8Array([254, 255, 3, 0])).raw
).toEqual(new BN(0xffff));
});
});
50 changes: 32 additions & 18 deletions packages/types/src/codec/Compact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToBn from '@polkadot/util/u8a/toBn';
import toU8a from '@polkadot/util/u8a/toU8a';

import UInt from './UInt';
import UInt, { UIntBitLength } from './UInt';

// TODO Could allow for 64 & 128 https://github.com/paritytech/parity-codec/pull/6
type BitLength = 32;
export const DEFAULT_LENGTH_BITS = 32;

const MAX_U8 = new BN(2).pow(new BN(8 - 2)).subn(1);
const MAX_U16 = new BN(2).pow(new BN(16 - 2)).subn(1);
const MAX_U32 = new BN(2).pow(new BN(32 - 2)).subn(1);
const DEFAULT_BITLENGTH = 32;

// A new compact length-encoding algorithm. It performs the same function as Length, however
// differs in that it uses a variable number of bytes to do the actual encoding. From the Rust
Expand All @@ -34,8 +32,8 @@ const DEFAULT_BITLENGTH = 32;
// nn nn nn 11 [ / zz zz zz zz ]{4 + n}
//
// Note: we use *LOW BITS* of the LSB in LE encoding to encode the 2 bit key.
export default class Compact {
static decode (_input: Uint8Array | string, bitLength: BitLength = DEFAULT_BITLENGTH): [number, BN] {
export default class Compact extends UInt {
static decodeU8a (_input: Uint8Array | string, bitLength: UIntBitLength): [number, BN] {
const input = toU8a(_input);
const flag = input[0] & 0b11;

Expand All @@ -52,24 +50,40 @@ export default class Compact {
return [byteLength + 1, u8aToBn(input.subarray(1, 1 + byteLength), true)];
}

static encode (_length: UInt | BN | number, bitLength: BitLength = DEFAULT_BITLENGTH): Uint8Array {
const length = _length instanceof UInt
? _length.toBn()
: bnToBn(_length);

if (length.lte(MAX_U8)) {
return new Uint8Array([length.toNumber() << 2]);
} else if (length.lte(MAX_U16)) {
return bnToU8a(length.shln(2).addn(0b01), 16, true);
} else if (length.lte(MAX_U32)) {
return bnToU8a(length.shln(2).addn(0b10), 32, true);
static encodeU8a (_value: UInt | BN | number, bitLength: UIntBitLength): Uint8Array {
const value = _value instanceof UInt
? _value.toBn()
: bnToBn(_value);

if (value.lte(MAX_U8)) {
return new Uint8Array([value.toNumber() << 2]);
} else if (value.lte(MAX_U16)) {
return bnToU8a(value.shln(2).addn(0b01), 16, true);
} else if (value.lte(MAX_U32)) {
return bnToU8a(value.shln(2).addn(0b10), 32, true);
}

return u8aConcat(
new Uint8Array([
0b11
]),
bnToU8a(length, bitLength, true)
bnToU8a(value, bitLength, true)
);
}

byteLength (): number {
return this.toU8a().length;
}

fromU8a (input: Uint8Array): UInt {
const [, value] = Compact.decodeU8a(input, this._bitLength);

this.raw = value;

return this;
}

toU8a (isBare?: boolean): Uint8Array {
return Compact.encodeU8a(this.raw, this._bitLength);
}
}
8 changes: 5 additions & 3 deletions packages/types/src/codec/UInt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import u8aToBn from '@polkadot/util/u8a/toBn';

import Base from './Base';

type BitLength = 8 | 16 | 32 | 64 | 128 | 256;
export type UIntBitLength = 8 | 16 | 32 | 64 | 128 | 256;

export const DEFAULT_UINT_BITS = 64;

// A generic number codec. For Substrate all numbers are LE encoded, this handles the encoding
// and decoding of those numbers. Upon construction the bitLength is provided and any additional
Expand All @@ -25,10 +27,10 @@ type BitLength = 8 | 16 | 32 | 64 | 128 | 256;
// TODO:
// - Apart from encoding/decoding we don't actuall keep check on the sizes, is this good enough?
export default class UInt extends Base<BN> {
private _bitLength: BitLength;
protected _bitLength: UIntBitLength;
private _isHexJson: boolean;

constructor (value: AnyNumber = 0, bitLength: BitLength = 64, isHexJson: boolean = true) {
constructor (value: AnyNumber = 0, bitLength: UIntBitLength = DEFAULT_UINT_BITS, isHexJson: boolean = true) {
super(
UInt.decode(value)
);
Expand Down
Loading

0 comments on commit 67dd6b2

Please sign in to comment.