VecFixed with hex inputs (& adjust isPedantic) (#3522)
* VecFixed with hex inputs (& adjust isPedantic) * Update packages/types/src/codec/VecFixed.spec.ts * Cleanups
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { TypeRegistry } from '../create';
|
||||
import { Text } from '../primitive';
|
||||
import { Text, u16 } from '../primitive';
|
||||
import { VecFixed } from '.';
|
||||
|
||||
describe('VecFixed', (): void => {
|
||||
@@ -17,6 +17,10 @@ describe('VecFixed', (): void => {
|
||||
expect(new VecFixed(registry, Text, 2, new Uint8Array([0x00, 0x04, 0x31])).toHex()).toEqual('0x000431');
|
||||
});
|
||||
|
||||
it('constructs via hex', (): void => {
|
||||
expect(new VecFixed(registry, u16, 2, '0x12345678').toHex()).toEqual('0x12345678');
|
||||
});
|
||||
|
||||
it('decodes reusing instance inputs', (): void => {
|
||||
const foo = new Text(registry, 'bar');
|
||||
|
||||
|
||||
@@ -3,12 +3,31 @@
|
||||
|
||||
import type { Codec, Constructor, InterfaceTypes, Registry } from '../types';
|
||||
|
||||
import { assert, compactToU8a, isU8a, u8aConcat } from '@polkadot/util';
|
||||
import { assert, compactToU8a, isHex, isU8a, u8aConcat } from '@polkadot/util';
|
||||
|
||||
import { AbstractArray } from './AbstractArray';
|
||||
import { typeToConstructor } from './utils';
|
||||
import { Vec } from './Vec';
|
||||
|
||||
/** @internal */
|
||||
function decodeVecFixed<T extends Codec> (registry: Registry, Type: Constructor<T>, allocLength: number, value: VecFixed<any> | Uint8Array | string | any[]): T[] {
|
||||
const values = Vec.decodeVec(
|
||||
registry,
|
||||
Type,
|
||||
isU8a(value) || isHex(value)
|
||||
? u8aConcat(compactToU8a(allocLength), value)
|
||||
: value
|
||||
);
|
||||
|
||||
while (values.length < allocLength) {
|
||||
values.push(new Type(registry));
|
||||
}
|
||||
|
||||
assert(values.length === allocLength, () => `Expected a length of exactly ${allocLength} entries`);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name VecFixed
|
||||
* @description
|
||||
@@ -20,30 +39,11 @@ export class VecFixed<T extends Codec> extends AbstractArray<T> {
|
||||
constructor (registry: Registry, Type: Constructor<T> | keyof InterfaceTypes, length: number, value: VecFixed<any> | Uint8Array | string | any[] = [] as any[]) {
|
||||
const Clazz = typeToConstructor<T>(registry, Type);
|
||||
|
||||
super(registry, ...VecFixed.decodeVecFixed(registry, Clazz, length, value));
|
||||
super(registry, ...decodeVecFixed(registry, Clazz, length, value));
|
||||
|
||||
this._Type = Clazz;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public static decodeVecFixed<T extends Codec> (registry: Registry, Type: Constructor<T>, allocLength: number, value: VecFixed<any> | Uint8Array | string | any[]): T[] {
|
||||
const values = Vec.decodeVec(
|
||||
registry,
|
||||
Type,
|
||||
isU8a(value)
|
||||
? u8aConcat(compactToU8a(allocLength), value)
|
||||
: value
|
||||
);
|
||||
|
||||
while (values.length < allocLength) {
|
||||
values.push(new Type(registry));
|
||||
}
|
||||
|
||||
assert(values.length === allocLength, () => `Expected a length of exactly ${allocLength} entries`);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static with<O extends Codec> (Type: Constructor<O> | keyof InterfaceTypes, length: number): Constructor<VecFixed<O>> {
|
||||
return class extends VecFixed<O> {
|
||||
constructor (registry: Registry, value?: any[]) {
|
||||
|
||||
@@ -125,20 +125,32 @@ describe('createType', (): void => {
|
||||
describe('isPedantic', (): void => {
|
||||
it('correctly decodes Bytes', (): void => {
|
||||
expect(
|
||||
createTypeUnsafe(registry, 'Bytes', ['0x12345678'], { isPedantic: true })
|
||||
).toBeDefined();
|
||||
createTypeUnsafe(registry, 'Bytes', ['0x12345678'], { isPedantic: true }).toHex()
|
||||
).toEqual('0x12345678');
|
||||
});
|
||||
|
||||
it('correctly decodes Bytes (prefixed)', (): void => {
|
||||
expect(
|
||||
createTypeUnsafe(registry, 'Bytes', [new Uint8Array([4 << 2, 1, 2, 3, 4])], { isPedantic: true })
|
||||
).toBeDefined();
|
||||
createTypeUnsafe(registry, 'Bytes', [new Uint8Array([4 << 2, 0x12, 0x34, 0x56, 0x78])], { isPedantic: true }).toHex()
|
||||
).toEqual('0x12345678');
|
||||
});
|
||||
|
||||
it('correctly decodes Text', (): void => {
|
||||
expect(
|
||||
createTypeUnsafe(registry, 'Text', ['0x2070726f7669646572'], { isPedantic: true })
|
||||
).toBeDefined();
|
||||
createTypeUnsafe(registry, 'Text', ['0x70726f7669646572'], { isPedantic: true }).toString()
|
||||
).toEqual('provider');
|
||||
});
|
||||
|
||||
it('correctly decodes Type', (): void => {
|
||||
expect(
|
||||
createTypeUnsafe(registry, 'Type', ['0x5665633c75383e'], { isPedantic: true }).toString()
|
||||
).toEqual('Bytes'); // Vec<u8> -> Bytes
|
||||
});
|
||||
|
||||
it('correctly decodes [u16; 4]', (): void => {
|
||||
expect(
|
||||
createTypeUnsafe(registry, '[u16; 4]', ['0x0012002300450067'], { isPedantic: true }).toHex()
|
||||
).toEqual('0x0012002300450067');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -16,22 +16,18 @@ interface CreateOptions {
|
||||
|
||||
// With isPedantic, actually check that the encoding matches that supplied. This
|
||||
// is much slower, but verifies that we have the correct types defined
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
function checkInstance<T extends Codec = Codec, K extends string = string> (value: Uint8Array, created: FromReg<T, K>): void {
|
||||
const u8a = created.toU8a();
|
||||
const rawType = created.toRawType();
|
||||
|
||||
// for length-prefixed byte types, just check the length, else the full encoding
|
||||
const isEqual = ['Bytes', 'Text'].includes(rawType)
|
||||
? [
|
||||
// input was via hex, we don't have a prefix
|
||||
(created as Bytes).length,
|
||||
// input was raw bytes, we do have a prefix
|
||||
u8a.length
|
||||
].includes(value.length)
|
||||
: u8aEq(value, u8a);
|
||||
|
||||
assert(isEqual, () => `${rawType}:: Decoded input doesn't match input, received ${u8aToHex(value, 512)} (${value.length} bytes), created ${u8aToHex(u8a, 512)} (${u8a.length} bytes)`);
|
||||
assert(
|
||||
u8aEq(value, u8a) || (
|
||||
// when length-prefixed from hex, just check the actual length
|
||||
['Bytes', 'Text', 'Type'].includes(rawType) &&
|
||||
value.length === (created as Bytes).length
|
||||
),
|
||||
() => `${rawType}:: Decoded input doesn't match input, received ${u8aToHex(value, 512)} (${value.length} bytes), created ${u8aToHex(u8a, 512)} (${u8a.length} bytes)`
|
||||
);
|
||||
}
|
||||
|
||||
// Initializes a type with a value. This also checks for fallbacks and in the cases
|
||||
|
||||
@@ -109,7 +109,7 @@ export class Text extends String implements Codec {
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
public toHex (): string {
|
||||
// like with Vec<u8>, when we are encoding to hex, we don't actually add
|
||||
// like with Vec<u8>, when we are encoding to hex, we don't actually add
|
||||
// the length prefix (it is already implied by the actual string length)
|
||||
return u8aToHex(this.toU8a(true));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user