Files
common/packages/trie-codec/src/decode.ts
T
2020-01-06 13:43:49 +01:00

98 lines
3.1 KiB
TypeScript

// Copyright 2017-2020 @polkadot/trie-codec authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { compactStripLength, logger } from '@polkadot/util';
import NodeHeader, { BranchHeader, NibbleHeader } from './NodeHeader';
import { BITMAP, NODE_TYPE_BRANCH, NODE_TYPE_EXT, NODE_TYPE_LEAF, NODE_TYPE_NULL } from './constants';
import { addNibblesTerminator, encodeNibbles } from './nibbles';
import { toNibbles } from './util';
const EMPTY_BRANCH: (Uint8Array | null)[] = [
null, null, null, null,
null, null, null, null,
null, null, null, null,
null, null, null, null
];
const l = logger('trie/codec');
l.noop();
function _decodeBranch (header: NodeHeader, input: Uint8Array): (null | Uint8Array | [Uint8Array, Uint8Array])[] {
let offset = header.encodedLength;
const branch = header.value as BranchHeader;
const bitmap = input[offset] + (input[offset + 1] << 8);
let value: null | Uint8Array;
offset += 2;
if (branch === true) {
const [length, bytes] = compactStripLength(input.subarray(offset));
value = bytes;
offset += length;
} else {
value = null;
}
return EMPTY_BRANCH.concat(value).map((value, index): null | Uint8Array | [Uint8Array, Uint8Array] => {
let result: null | Uint8Array | [Uint8Array, Uint8Array] = value;
if ((index < 16) && (bitmap & BITMAP[index])) {
const [length, bytes] = compactStripLength(input.subarray(offset));
result = bytes.length === 32
? bytes
// eslint-disable-next-line @typescript-eslint/no-use-before-define
: decode(bytes) as Uint8Array;
offset += length;
}
return result;
});
}
function _decodeKv (header: NodeHeader, input: Uint8Array): (null | Uint8Array | [Uint8Array, Uint8Array])[] {
const offset = header.encodedLength;
const nibbleCount = (header.value as NibbleHeader);
const nibbleLength = (nibbleCount + 1) >> 1;
const nibbleData = input.subarray(offset, offset + nibbleLength);
// for odd, ignore the first nibble, data starts at offset 1
const nibbles = toNibbles(nibbleData).subarray(nibbleCount % 2);
const [, value] = compactStripLength(input.subarray(offset + nibbleData.length));
return [
encodeNibbles(
header.nodeType === NODE_TYPE_LEAF
? addNibblesTerminator(nibbles)
: nibbles
),
value
];
}
export default function decode (input: null | Uint8Array): Uint8Array | null | (null | Uint8Array | [Uint8Array, Uint8Array])[] {
const header = new NodeHeader(input);
const nodeType = header.nodeType;
if (!input || nodeType === NODE_TYPE_NULL) {
return input;
} else if (nodeType === NODE_TYPE_BRANCH) {
return _decodeBranch(header, input);
} else if (nodeType === NODE_TYPE_EXT || nodeType === NODE_TYPE_LEAF) {
return _decodeKv(header, input);
}
throw new Error('Unreachable');
}
// export default function decode (input: null | Uint8Array): Uint8Array | null | Array<null | Uint8Array | Array<null | Uint8Array>> {
// const decoded = _decode(input);
// // l.debug(() => ['decode', { input, decoded }]);
// return decoded;
// }