Address type cleanups (#337)
* AccountIndex allows only <= 0xef for 1 byte * Max 1-byte constructed from prefix * Expand Address tests, add ts checks
This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
// 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 AccountId from './AccountId';
|
||||
import U8a from './codec/U8a';
|
||||
|
||||
|
||||
const testDecode = (type, input, expected) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const a = new AccountId(input);
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const a = new AccountId('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
expect(a[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
|
||||
describe('AccountId', () => {
|
||||
|
||||
testDecode(
|
||||
'AccountId',
|
||||
new AccountId('0x0102030405060708010203040506070801020304050607080102030405060708'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode('hex', '0x0102030405060708010203040506070801020304050607080102030405060708', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testDecode('string', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testDecode(
|
||||
'U8a',
|
||||
new U8a([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array',
|
||||
Uint8Array.from([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
|
||||
testEncode('toHex', '0x0102030405060708010203040506070801020304050607080102030405060708');
|
||||
testEncode('toJSON', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testEncode('toString', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testEncode('toU8a', Uint8Array.from([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]));
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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 AccountId from './AccountId';
|
||||
import U8a from './codec/U8a';
|
||||
|
||||
describe('AccountId', () => {
|
||||
describe('decoding', () => {
|
||||
const testDecode = (type: string, input: Uint8Array | string | AccountId | U8a, expected: string) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const a = new AccountId(input);
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
testDecode(
|
||||
'AccountId',
|
||||
new AccountId('0x0102030405060708010203040506070801020304050607080102030405060708'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode('hex', '0x0102030405060708010203040506070801020304050607080102030405060708', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testDecode('string', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testDecode(
|
||||
'U8a',
|
||||
new U8a([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array',
|
||||
Uint8Array.from([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
});
|
||||
|
||||
describe('encoding', () => {
|
||||
const testEncode = (to: 'toHex' | 'toJSON' | 'toString' | 'toU8a', expected: Uint8Array | string) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const a = new AccountId('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
|
||||
expect(a[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
testEncode('toHex', '0x0102030405060708010203040506070801020304050607080102030405060708');
|
||||
testEncode('toJSON', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testEncode('toString', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testEncode('toU8a', Uint8Array.from([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]));
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,12 @@ describe('AccountIndex', () => {
|
||||
).toEqual('336794129');
|
||||
});
|
||||
|
||||
it('creates a BN representation (from ss-58)', () => {
|
||||
expect(
|
||||
new AccountIndex('Mwz15xN8').toBn().toString()
|
||||
).toEqual('336794129');
|
||||
});
|
||||
|
||||
it('constructs 2-byte from number', () => {
|
||||
expect(
|
||||
new AccountIndex(256 * 1).toString()
|
||||
@@ -21,6 +27,27 @@ describe('AccountIndex', () => {
|
||||
it('constructs from number', () => {
|
||||
expect(
|
||||
new AccountIndex(new BN(336794129)).toString()
|
||||
).toEqual('3N5RJXxJhgRhxu');
|
||||
).toEqual('Mwz15xN8');
|
||||
});
|
||||
|
||||
describe('calcLength', () => {
|
||||
const testLength = (value: number, length: number) =>
|
||||
expect(AccountIndex.calcLength(value)).toEqual(length);
|
||||
|
||||
it('returns 1 for <= 0xef', () => {
|
||||
testLength(0xef, 1);
|
||||
});
|
||||
|
||||
it('returns 2 for > 0xef', () => {
|
||||
testLength(0xf0, 2);
|
||||
});
|
||||
|
||||
it('returns 4 bytes for 32-bit inputs', () => {
|
||||
testLength(0xffeeddcc, 4);
|
||||
});
|
||||
|
||||
it('returns 8 bytes for larger inputs', () => {
|
||||
testLength(0x122334455, 8);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,6 +11,14 @@ import U8a from './codec/U8a';
|
||||
|
||||
export const ENUMSET_SIZE = new BN(64);
|
||||
|
||||
const PREFIX_1BYTE = 0xef;
|
||||
const PREFIX_2BYTE = 0xfc;
|
||||
const PREFIX_4BYTE = 0xfd;
|
||||
const PREFIX_8BYTE = 0xfe;
|
||||
const MAX_1BYTE = new BN(PREFIX_1BYTE);
|
||||
const MAX_2BYTE = new BN(1).shln(16);
|
||||
const MAX_4BYTE = new BN(1).shln(32);
|
||||
|
||||
// A wrapper around an AccountIndex, which is a shortened, variable-length encoding
|
||||
// for an Account. We extends from U8a which is basically
|
||||
// just a Uint8Array wrapper.
|
||||
@@ -35,20 +43,9 @@ export default class AccountIndex extends U8a {
|
||||
|
||||
return value.subarray(offset, offset + length);
|
||||
} else if (isNumber(value) || isBn(value)) {
|
||||
const index = bnToBn(value);
|
||||
const bitLength = index.ltn(1 << 8)
|
||||
? 8
|
||||
: (
|
||||
index.ltn(1 << 16)
|
||||
? 16
|
||||
: (
|
||||
index.ltn(1 << 32)
|
||||
? 32
|
||||
: 64
|
||||
)
|
||||
);
|
||||
const bitLength = 8 * AccountIndex.calcLength(value);
|
||||
|
||||
return bnToU8a(index, bitLength, true);
|
||||
return bnToU8a(value, bitLength, true);
|
||||
} else if (isHex(value)) {
|
||||
return hexToU8a(value);
|
||||
}
|
||||
@@ -56,16 +53,30 @@ export default class AccountIndex extends U8a {
|
||||
return decodeAddress(value);
|
||||
}
|
||||
|
||||
static calcLength (_value: BN | number): number {
|
||||
const value = bnToBn(_value);
|
||||
|
||||
if (value.lte(MAX_1BYTE)) {
|
||||
return 1;
|
||||
} else if (value.lt(MAX_2BYTE)) {
|
||||
return 2;
|
||||
} else if (value.lt(MAX_4BYTE)) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
static readLength (input: Uint8Array): [number, number] {
|
||||
const first = input[0];
|
||||
|
||||
if (first <= 0xef) {
|
||||
if (first <= PREFIX_1BYTE) {
|
||||
return [0, 1];
|
||||
} else if (first === 0xfc) {
|
||||
} else if (first === PREFIX_2BYTE) {
|
||||
return [1, 2];
|
||||
} else if (first === 0xfd) {
|
||||
} else if (first === PREFIX_4BYTE) {
|
||||
return [1, 4];
|
||||
} else if (first === 0xfe) {
|
||||
} else if (first === PREFIX_8BYTE) {
|
||||
return [1, 8];
|
||||
}
|
||||
|
||||
@@ -74,9 +85,9 @@ export default class AccountIndex extends U8a {
|
||||
|
||||
static writeLength (input: Uint8Array): Uint8Array {
|
||||
switch (input.length) {
|
||||
case 2: return new Uint8Array([0xfc]);
|
||||
case 4: return new Uint8Array([0xfd]);
|
||||
case 8: return new Uint8Array([0xfe]);
|
||||
case 2: return new Uint8Array([PREFIX_2BYTE]);
|
||||
case 4: return new Uint8Array([PREFIX_4BYTE]);
|
||||
case 8: return new Uint8Array([PREFIX_8BYTE]);
|
||||
default: return new Uint8Array([]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
// 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 AccountId from './AccountId';
|
||||
import AccountIndex from './AccountIndex';
|
||||
import Address from './Address';
|
||||
|
||||
const testDecode = (type, input, expected) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const a = new Address(input);
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const a = new Address('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
expect(a[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
describe('Address', () => {
|
||||
testDecode(
|
||||
'Address',
|
||||
new Address('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'AccountId',
|
||||
new AccountId('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'AccountIndex',
|
||||
new Address('PrF3'),
|
||||
// NOTE Expected adress here is encoded with prefix 42, input above with 68
|
||||
'F7ih'
|
||||
);
|
||||
testDecode(
|
||||
'AccountIndex',
|
||||
new AccountIndex('0x0001'),
|
||||
'25GUyk'
|
||||
);
|
||||
testDecode(
|
||||
'Array',
|
||||
[
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
],
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 255)',
|
||||
Uint8Array.from([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 1 byte)',
|
||||
Uint8Array.from([1]),
|
||||
'F7L6'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 2 bytes)',
|
||||
Uint8Array.from([0xfc, 0, 1]),
|
||||
'25GUyk'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 4 bytes)',
|
||||
Uint8Array.from([0xfd, 17, 18, 19, 20]),
|
||||
'Mwz15xN8'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 8 bytes)',
|
||||
Uint8Array.from([0xfe, 17, 18, 19, 20, 21, 22, 23, 24]),
|
||||
'3N5RJXxM5fLd4h'
|
||||
);
|
||||
|
||||
// FIXME Add this
|
||||
// testEncode(
|
||||
// 'toHex',
|
||||
// '0x0102030405060708010203040506070801020304050607080102030405060708'
|
||||
// );
|
||||
testEncode(
|
||||
'toString',
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testEncode(
|
||||
'toU8a',
|
||||
Uint8Array.from([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
// 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 AccountId from './AccountId';
|
||||
import AccountIndex from './AccountIndex';
|
||||
import Address from './Address';
|
||||
|
||||
describe('Address', () => {
|
||||
const testDecode = (type: string, input: Address | AccountId | AccountIndex | Array<number> | Uint8Array, expected: string) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const a = new Address(input);
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
describe('decoding', () => {
|
||||
testDecode(
|
||||
'Address',
|
||||
new Address('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'AccountId',
|
||||
new AccountId('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'AccountIndex',
|
||||
new Address('PrF3'),
|
||||
// NOTE Expected adress here is encoded with prefix 42, input above with 68
|
||||
'F7ih'
|
||||
);
|
||||
testDecode(
|
||||
'AccountIndex',
|
||||
new AccountIndex('0x0001'),
|
||||
'25GUyk'
|
||||
);
|
||||
testDecode(
|
||||
'Array',
|
||||
[
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
],
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 255)',
|
||||
Uint8Array.from([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 1 byte)',
|
||||
Uint8Array.from([1]),
|
||||
'F7L6'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 2 bytes)',
|
||||
Uint8Array.from([0xfc, 0, 1]),
|
||||
'25GUyk'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 4 bytes)',
|
||||
Uint8Array.from([0xfd, 17, 18, 19, 20]),
|
||||
'Mwz15xN8'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 8 bytes)',
|
||||
Uint8Array.from([0xfe, 17, 18, 19, 20, 21, 22, 23, 24]),
|
||||
'3N5RJXxM5fLd4h'
|
||||
);
|
||||
});
|
||||
|
||||
describe('encoding', () => {
|
||||
const testEncode = (to: 'toHex' | 'toString' | 'toU8a', expected: string | Uint8Array) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const a = new Address('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
expect(a[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
testEncode(
|
||||
'toHex',
|
||||
'0xff0102030405060708010203040506070801020304050607080102030405060708'
|
||||
);
|
||||
testEncode(
|
||||
'toString',
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testEncode(
|
||||
'toU8a',
|
||||
Uint8Array.from([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -17,13 +17,13 @@ const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
|
||||
// is encoded as
|
||||
// [ <prefix-byte>, ...publicKey/...bytes ]
|
||||
export default class Address extends Base<AccountId | AccountIndex> {
|
||||
constructor (value: Address | AccountId | AccountIndex | Uint8Array | string = new Uint8Array()) {
|
||||
constructor (value: Address | AccountId | AccountIndex | Array<number> | Uint8Array | string = new Uint8Array()) {
|
||||
super(
|
||||
Address.decodeAddress(value)
|
||||
);
|
||||
}
|
||||
|
||||
static decodeAddress (value: Address | AccountId | AccountIndex | Uint8Array | string): AccountId | AccountIndex {
|
||||
static decodeAddress (value: Address | AccountId | AccountIndex | Array<number> | Uint8Array | string): AccountId | AccountIndex {
|
||||
if (value instanceof Address) {
|
||||
return value.raw;
|
||||
} else if (value instanceof AccountId || value instanceof AccountIndex) {
|
||||
|
||||
Reference in New Issue
Block a user