@polkadot/types
Version:
Implementation of the Parity codec
204 lines (203 loc) • 6.69 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StorageKey = void 0;
const types_codec_1 = require("@polkadot/types-codec");
const util_1 = require("@polkadot/util");
const index_js_1 = require("../metadata/util/index.js");
const index_js_2 = require("../util/index.js");
const HASHER_MAP = {
// opaque
Blake2_128: [16, false], // eslint-disable-line camelcase
Blake2_128Concat: [16, true], // eslint-disable-line camelcase
Blake2_256: [32, false], // eslint-disable-line camelcase
Identity: [0, true],
Twox128: [16, false],
Twox256: [32, false],
Twox64Concat: [8, true]
};
/** @internal */
function decodeStorageKey(value) {
if ((0, util_1.isU8a)(value) || !value || (0, util_1.isString)(value)) {
// let Bytes handle these inputs
return { key: value };
}
else if (value instanceof StorageKey) {
return {
key: value,
method: value.method,
section: value.section
};
}
else if ((0, util_1.isFunction)(value)) {
return {
key: value(),
method: value.method,
section: value.section
};
}
else if (Array.isArray(value)) {
const [fn, args = []] = value;
if (!(0, util_1.isFunction)(fn)) {
throw new Error('Expected function input for key construction');
}
if (fn.meta && fn.meta.type.isMap) {
const map = fn.meta.type.asMap;
if (!Array.isArray(args) || args.length !== map.hashers.length) {
throw new Error(`Expected an array of ${map.hashers.length} values as params to a Map query`);
}
}
return {
key: fn(...args),
method: fn.method,
section: fn.section
};
}
throw new Error(`Unable to convert input ${value} to StorageKey`);
}
/** @internal */
function decodeHashers(registry, value, hashers) {
// the storage entry is xxhashAsU8a(prefix, 128) + xxhashAsU8a(method, 128), 256 bits total
let offset = 32;
const count = hashers.length;
const result = new Array(count);
for (let i = 0; i < count; i++) {
const [hasher, type] = hashers[i];
const [hashLen, canDecode] = HASHER_MAP[hasher.type];
const decoded = canDecode
? registry.createTypeUnsafe((0, index_js_1.getSiName)(registry.lookup, type), [value.subarray(offset + hashLen)])
: registry.createTypeUnsafe('Raw', [value.subarray(offset, offset + hashLen)]);
offset += hashLen + (canDecode ? decoded.encodedLength : 0);
result[i] = decoded;
}
return result;
}
/** @internal */
function decodeArgsFromMeta(registry, value, meta) {
if (!meta || !meta.type.isMap) {
return [];
}
const { hashers, key } = meta.type.asMap;
const keys = hashers.length === 1
? [key]
: registry.lookup.getSiType(key).def.asTuple;
return decodeHashers(registry, value, hashers.map((h, i) => [h, keys[i]]));
}
/** @internal */
function getMeta(value) {
if (value instanceof StorageKey) {
return value.meta;
}
else if ((0, util_1.isFunction)(value)) {
return value.meta;
}
else if (Array.isArray(value)) {
const [fn] = value;
return fn.meta;
}
return undefined;
}
/** @internal */
function getType(registry, value) {
if (value instanceof StorageKey) {
return value.outputType;
}
else if ((0, util_1.isFunction)(value)) {
return (0, index_js_2.unwrapStorageType)(registry, value.meta.type);
}
else if (Array.isArray(value)) {
const [fn] = value;
if (fn.meta) {
return (0, index_js_2.unwrapStorageType)(registry, fn.meta.type);
}
}
// If we have no type set, default to Raw
return 'Raw';
}
/**
* @name StorageKey
* @description
* A representation of a storage key (typically hashed) in the system. It can be
* constructed by passing in a raw key or a StorageEntry with (optional) arguments.
*/
class StorageKey extends types_codec_1.Bytes {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore This is assigned via this.decodeArgsFromMeta()
__internal__args;
__internal__meta;
__internal__outputType;
__internal__method;
__internal__section;
constructor(registry, value, override = {}) {
const { key, method, section } = decodeStorageKey(value);
super(registry, key);
this.__internal__outputType = getType(registry, value);
// decode the args (as applicable based on the key and the hashers, after all init)
this.setMeta(getMeta(value), override.section || section, override.method || method);
}
/**
* @description Return the decoded arguments (applicable to map with decodable values)
*/
get args() {
return this.__internal__args;
}
/**
* @description The metadata or `undefined` when not available
*/
get meta() {
return this.__internal__meta;
}
/**
* @description The key method or `undefined` when not specified
*/
get method() {
return this.__internal__method;
}
/**
* @description The output type
*/
get outputType() {
return this.__internal__outputType;
}
/**
* @description The key section or `undefined` when not specified
*/
get section() {
return this.__internal__section;
}
is(key) {
return key.section === this.section && key.method === this.method;
}
/**
* @description Sets the meta for this key
*/
setMeta(meta, section, method) {
this.__internal__meta = meta;
this.__internal__method = method || this.__internal__method;
this.__internal__section = section || this.__internal__section;
if (meta) {
this.__internal__outputType = (0, index_js_2.unwrapStorageType)(this.registry, meta.type);
}
try {
this.__internal__args = decodeArgsFromMeta(this.registry, this.toU8a(true), meta);
}
catch {
// ignore...
}
return this;
}
/**
* @description Returns the Human representation for this type
*/
toHuman(_isExtended, disableAscii) {
return this.__internal__args.length
? this.__internal__args.map((a) => a.toHuman(undefined, disableAscii))
: super.toHuman(undefined, disableAscii);
}
/**
* @description Returns the raw type for this
*/
toRawType() {
return 'StorageKey';
}
}
exports.StorageKey = StorageKey;