Expose .entries() for DoubleMaps (#1750)
* Expose .entries() for DoubleMaps * DoubleMap vs Map test * Fix decoration * Remove prefixed map * Allow SoubleMap entries() with arguments * DoubleMap with & without params * Remove debug log * Update CHANGELOG * ... and working... finally. * Cleanup debug logs
This commit is contained in:
@@ -4,27 +4,24 @@
|
||||
|
||||
import { Constants, Storage } from '@polkadot/metadata/Decorated/types';
|
||||
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
|
||||
import { InterfaceRegistry } from '@polkadot/types/interfaceRegistry';
|
||||
import { Call, Hash, RuntimeVersion } from '@polkadot/types/interfaces';
|
||||
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, ITuple, ModulesWithCalls, Registry } from '@polkadot/types/types';
|
||||
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, ITuple, InterfaceTypes, ModulesWithCalls, Registry } from '@polkadot/types/types';
|
||||
import { SubmittableExtrinsic } from '../submittable/types';
|
||||
import {
|
||||
ApiInterfaceRx, ApiOptions, ApiTypes,
|
||||
DecorateMethod, DecoratedRpc, DecoratedRpcSection,
|
||||
QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg,
|
||||
SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics
|
||||
} from '../types';
|
||||
import { ApiInterfaceRx, ApiOptions, ApiTypes, DecorateMethod, DecoratedRpc, DecoratedRpcSection, QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg, SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import decorateDerive, { ExactDerive } from '@polkadot/api-derive';
|
||||
import getHasher from '@polkadot/metadata/Decorated/storage/fromMetadata/getHasher';
|
||||
import RpcCore from '@polkadot/rpc-core';
|
||||
import { WsProvider } from '@polkadot/rpc-provider';
|
||||
import { Metadata, Null, Option, TypeRegistry, u64, Vec } from '@polkadot/types';
|
||||
import Linkage, { LinkageResult } from '@polkadot/types/codec/Linkage';
|
||||
import { DEFAULT_VERSION as EXTRINSIC_DEFAULT_VERSION } from '@polkadot/types/primitive/Extrinsic/constants';
|
||||
import StorageKey, { StorageEntry } from '@polkadot/types/primitive/StorageKey';
|
||||
import { assert, compactStripLength, u8aToHex } from '@polkadot/util';
|
||||
import { assert, compactStripLength, isNull, isUndefined, u8aConcat, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import { createSubmittable } from '../submittable';
|
||||
import { decorateSections, DeriveAllSections } from '../util/decorate';
|
||||
@@ -132,6 +129,8 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
|
||||
this._rx.registry = this.registry;
|
||||
}
|
||||
|
||||
public abstract createType <K extends InterfaceTypes> (type: K, ...params: any[]): InterfaceRegistry[K];
|
||||
|
||||
/**
|
||||
* @returns `true` if the API operates with subscriptions
|
||||
*/
|
||||
@@ -275,8 +274,8 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
|
||||
decorated.at = decorateMethod((hash: Hash, arg1?: Arg, arg2?: Arg): Observable<Codec> =>
|
||||
this._rpcCore.state.getStorage(getArgs(arg1, arg2), hash));
|
||||
|
||||
decorated.entries = decorateMethod((): Observable<[StorageKey, Codec][]> =>
|
||||
this.retrieveMapEntries(creator));
|
||||
decorated.entries = decorateMethod((doubleMapArg?: Arg): Observable<[StorageKey, Codec][]> =>
|
||||
this.retrieveMapEntries(creator, doubleMapArg));
|
||||
|
||||
decorated.hash = decorateMethod((arg1?: Arg, arg2?: Arg): Observable<Hash> =>
|
||||
this._rpcCore.state.getStorageHash(getArgs(arg1, arg2)));
|
||||
@@ -369,15 +368,26 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
|
||||
);
|
||||
}
|
||||
|
||||
private retrieveMapEntries (creator: StorageEntry): Observable<[StorageKey, Codec][]> {
|
||||
assert(creator.meta.type.isMap, 'entries can only be retrieved on maps');
|
||||
private retrieveMapEntries (creator: StorageEntry, arg?: Arg): Observable<[StorageKey, Codec][]> {
|
||||
assert(creator.iterKey && (creator.meta.type.isMap || creator.meta.type.isDoubleMap), 'entries can only be retrieved on maps, linked maps and double maps');
|
||||
|
||||
const outputType = creator.meta.type.asMap.value.toString();
|
||||
const outputType = creator.meta.type.isMap
|
||||
? creator.meta.type.asMap.value.toString()
|
||||
: creator.meta.type.asDoubleMap.value.toString();
|
||||
|
||||
return this._rpcCore.state
|
||||
// FIXME This should really be some sort of subscription, so we can get stuff as
|
||||
// it changes (as of now it is a one-shot query). Not sure how to do this though...
|
||||
.getKeys(creator.iterKey)
|
||||
.getKeys(
|
||||
this.createType('Raw', u8aConcat(
|
||||
creator.iterKey,
|
||||
creator.meta.type.isDoubleMap && !isUndefined(arg) && !isNull(arg)
|
||||
? getHasher(creator.meta.type.asDoubleMap.hasher)(
|
||||
this.createType(creator.meta.type.asDoubleMap.key1.toString() as 'Raw', arg).toU8a()
|
||||
)
|
||||
: new Uint8Array([])
|
||||
))
|
||||
)
|
||||
.pipe(
|
||||
switchMap((keys): Observable<[StorageKey[], Vec<Codec>]> =>
|
||||
combineLatest([
|
||||
|
||||
@@ -141,16 +141,17 @@ function expandWithMeta ({ meta, method, prefix, section }: CreateItemFn, storag
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function extendHeadMeta (registry: Registry, { meta: { documentation, name, type }, section }: CreateItemFn, { method }: StorageEntry, iterFn: () => Raw): StorageKey {
|
||||
const map = type.asMap;
|
||||
const outputType = map.key.toString();
|
||||
function extendHeadMeta (registry: Registry, { meta: { documentation, name, type }, section }: CreateItemFn, { method }: StorageEntry, iterFn: (arg?: any) => Raw): StorageKey {
|
||||
const outputType = type.isMap
|
||||
? type.asMap.key.toString()
|
||||
: type.asDoubleMap.key1.toString();
|
||||
|
||||
// metadata with a fallback value using the type of the key, the normal
|
||||
// meta fallback only applies to actual entry values, create one for head
|
||||
(iterFn as IterFn).meta = createType(registry, 'StorageEntryMetadataLatest', {
|
||||
name,
|
||||
modifier: createType(registry, 'StorageEntryModifierLatest', 1), // required
|
||||
type: createType(registry, 'StorageEntryTypeLatest', createType(registry, 'PlainTypeLatest', map.key), 0),
|
||||
type: createType(registry, 'StorageEntryTypeLatest', createType(registry, 'PlainTypeLatest', type.isMap ? type.asMap.key : type.asDoubleMap.key1), 0),
|
||||
fallback: createType(registry, 'Bytes', createTypeUnsafe(registry, outputType).toHex()),
|
||||
documentation
|
||||
});
|
||||
@@ -182,6 +183,12 @@ function extendPrefixedMap (registry: Registry, itemFn: CreateItemFn, storageFn:
|
||||
return storageFn;
|
||||
}
|
||||
|
||||
// attach the full list hashing for double maps
|
||||
/** @internal */
|
||||
function extendDoubleMap (registry: Registry, itemFn: CreateItemFn, storageFn: StorageEntry): StorageEntry {
|
||||
return extendPrefixedMap(registry, itemFn, storageFn);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export default function createFunction (registry: Registry, itemFn: CreateItemFn, options: CreateItemOptions): StorageEntry {
|
||||
const { meta: { type } } = itemFn;
|
||||
@@ -207,6 +214,8 @@ export default function createFunction (registry: Registry, itemFn: CreateItemFn
|
||||
} else {
|
||||
extendPrefixedMap(registry, itemFn, storageFn);
|
||||
}
|
||||
} else if (type.isDoubleMap) {
|
||||
extendDoubleMap(registry, itemFn, storageFn);
|
||||
}
|
||||
|
||||
return storageFn;
|
||||
|
||||
@@ -163,18 +163,11 @@ function formattingTests (version: string, decorated: Metadata, encodedValues: [
|
||||
});
|
||||
|
||||
it('handles fallbacks for linked maps (new metadata only)', (done): void => {
|
||||
const iterKey = decorated.query.staking.validators && decorated.query.staking.validators.iterKey;
|
||||
|
||||
// skip for old
|
||||
if (!iterKey) {
|
||||
return done();
|
||||
}
|
||||
|
||||
api.state
|
||||
.subscribeStorage([[decorated.query.staking.validators, '0x00']])
|
||||
.subscribe(([value]: Codec[]): void => {
|
||||
expect(value).toBeDefined();
|
||||
// console.error('linked falklback', value);
|
||||
// console.error('linked fallback', value);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ import { Multisig, Timepoint } from '@polkadot/types/interfaces/utility';
|
||||
import { BlockAttestations, IncludedBlocks, MoreAttestations } from '@polkadot/types/interfaces/attestations';
|
||||
import { EthereumAddress } from '@polkadot/types/interfaces/claims';
|
||||
import { AttestedCandidate, AuctionIndex, BalanceUpload, Bidder, CandidateReceipt, CollatorId, CollatorSignature, EgressQueueRoot, HeadData, IncomingParachain, IncomingParachainDeploy, IncomingParachainFixed, LeasePeriod, LeasePeriodOf, NewBidder, ParaId, ParaIdOf, ParaInfo, ParaScheduling, ParachainDispatchOrigin, Retriable, SlotRange, SubId, UpwardMessage, ValidatorIndex, ValidityAttestation, ValidityVote, WinningData, WinningDataEntry } from '@polkadot/types/interfaces/parachains';
|
||||
import { CallMetadataV0, DoubleMapTypeV10, DoubleMapTypeV3, DoubleMapTypeV4, DoubleMapTypeV5, DoubleMapTypeV6, DoubleMapTypeV7, DoubleMapTypeV8, DoubleMapTypeV9, ErrorMetadataV10, ErrorMetadataV8, ErrorMetadataV9, EventMetadataLatest, EventMetadataV0, EventMetadataV1, EventMetadataV10, EventMetadataV2, EventMetadataV3, EventMetadataV4, EventMetadataV5, EventMetadataV6, EventMetadataV7, EventMetadataV8, EventMetadataV9, FunctionArgumentMetadataLatest, FunctionArgumentMetadataV0, FunctionArgumentMetadataV1, FunctionArgumentMetadataV10, FunctionArgumentMetadataV2, FunctionArgumentMetadataV3, FunctionArgumentMetadataV4, FunctionArgumentMetadataV5, FunctionArgumentMetadataV6, FunctionArgumentMetadataV7, FunctionArgumentMetadataV8, FunctionArgumentMetadataV9, FunctionMetadataLatest, FunctionMetadataV0, FunctionMetadataV1, FunctionMetadataV10, FunctionMetadataV2, FunctionMetadataV3, FunctionMetadataV4, FunctionMetadataV5, FunctionMetadataV6, FunctionMetadataV7, FunctionMetadataV8, FunctionMetadataV9, MapTypeV0, MapTypeV10, MapTypeV2, MapTypeV3, MapTypeV4, MapTypeV5, MapTypeV6, MapTypeV7, MapTypeV8, MapTypeV9, MetadataAll, MetadataLatest, MetadataV0, MetadataV1, MetadataV10, MetadataV2, MetadataV3, MetadataV4, MetadataV5, MetadataV6, MetadataV7, MetadataV8, MetadataV9, ModuleConstantMetadataLatest, ModuleConstantMetadataV10, ModuleConstantMetadataV6, ModuleConstantMetadataV7, ModuleConstantMetadataV8, ModuleConstantMetadataV9, ModuleMetadataLatest, ModuleMetadataV0, ModuleMetadataV1, ModuleMetadataV10, ModuleMetadataV2, ModuleMetadataV3, ModuleMetadataV4, ModuleMetadataV5, ModuleMetadataV6, ModuleMetadataV7, ModuleMetadataV8, ModuleMetadataV9, OuterDispatchCallV0, OuterDispatchMetadataV0, OuterEventEventMetadataEventsV0, OuterEventEventMetadataV0, OuterEventMetadataV0, PlainTypeLatest, PlainTypeV0, PlainTypeV10, PlainTypeV2, PlainTypeV3, PlainTypeV4, PlainTypeV5, PlainTypeV6, PlainTypeV7, PlainTypeV8, PlainTypeV9, RuntimeModuleMetadataV0, StorageEntryMetadataLatest, StorageEntryMetadataV10, StorageEntryMetadataV6, StorageEntryMetadataV7, StorageEntryMetadataV8, StorageEntryMetadataV9, StorageEntryModifierLatest, StorageEntryModifierV10, StorageEntryModifierV6, StorageEntryModifierV7, StorageEntryModifierV8, StorageEntryModifierV9, StorageEntryTypeLatest, StorageEntryTypeV10, StorageEntryTypeV6, StorageEntryTypeV7, StorageEntryTypeV8, StorageEntryTypeV9, StorageFunctionMetadataV0, StorageFunctionMetadataV1, StorageFunctionMetadataV2, StorageFunctionMetadataV3, StorageFunctionMetadataV4, StorageFunctionMetadataV5, StorageFunctionModifierV0, StorageFunctionModifierV1, StorageFunctionModifierV2, StorageFunctionModifierV3, StorageFunctionModifierV4, StorageFunctionModifierV5, StorageFunctionTypeV0, StorageFunctionTypeV1, StorageFunctionTypeV2, StorageFunctionTypeV3, StorageFunctionTypeV4, StorageFunctionTypeV5, StorageHasher, StorageHasherV10, StorageHasherV4, StorageHasherV5, StorageHasherV6, StorageHasherV7, StorageHasherV8, StorageHasherV9, StorageMetadataV0, StorageMetadataV10, StorageMetadataV7, StorageMetadataV8, StorageMetadataV9 } from '@polkadot/types/interfaces/metadata';
|
||||
import { CallMetadataV0, DoubleMapTypeLatest, DoubleMapTypeV10, DoubleMapTypeV3, DoubleMapTypeV4, DoubleMapTypeV5, DoubleMapTypeV6, DoubleMapTypeV7, DoubleMapTypeV8, DoubleMapTypeV9, ErrorMetadataV10, ErrorMetadataV8, ErrorMetadataV9, EventMetadataLatest, EventMetadataV0, EventMetadataV1, EventMetadataV10, EventMetadataV2, EventMetadataV3, EventMetadataV4, EventMetadataV5, EventMetadataV6, EventMetadataV7, EventMetadataV8, EventMetadataV9, FunctionArgumentMetadataLatest, FunctionArgumentMetadataV0, FunctionArgumentMetadataV1, FunctionArgumentMetadataV10, FunctionArgumentMetadataV2, FunctionArgumentMetadataV3, FunctionArgumentMetadataV4, FunctionArgumentMetadataV5, FunctionArgumentMetadataV6, FunctionArgumentMetadataV7, FunctionArgumentMetadataV8, FunctionArgumentMetadataV9, FunctionMetadataLatest, FunctionMetadataV0, FunctionMetadataV1, FunctionMetadataV10, FunctionMetadataV2, FunctionMetadataV3, FunctionMetadataV4, FunctionMetadataV5, FunctionMetadataV6, FunctionMetadataV7, FunctionMetadataV8, FunctionMetadataV9, MapTypeLatest, MapTypeV0, MapTypeV10, MapTypeV2, MapTypeV3, MapTypeV4, MapTypeV5, MapTypeV6, MapTypeV7, MapTypeV8, MapTypeV9, MetadataAll, MetadataLatest, MetadataV0, MetadataV1, MetadataV10, MetadataV2, MetadataV3, MetadataV4, MetadataV5, MetadataV6, MetadataV7, MetadataV8, MetadataV9, ModuleConstantMetadataLatest, ModuleConstantMetadataV10, ModuleConstantMetadataV6, ModuleConstantMetadataV7, ModuleConstantMetadataV8, ModuleConstantMetadataV9, ModuleMetadataLatest, ModuleMetadataV0, ModuleMetadataV1, ModuleMetadataV10, ModuleMetadataV2, ModuleMetadataV3, ModuleMetadataV4, ModuleMetadataV5, ModuleMetadataV6, ModuleMetadataV7, ModuleMetadataV8, ModuleMetadataV9, OuterDispatchCallV0, OuterDispatchMetadataV0, OuterEventEventMetadataEventsV0, OuterEventEventMetadataV0, OuterEventMetadataV0, PlainTypeLatest, PlainTypeV0, PlainTypeV10, PlainTypeV2, PlainTypeV3, PlainTypeV4, PlainTypeV5, PlainTypeV6, PlainTypeV7, PlainTypeV8, PlainTypeV9, RuntimeModuleMetadataV0, StorageEntryMetadataLatest, StorageEntryMetadataV10, StorageEntryMetadataV6, StorageEntryMetadataV7, StorageEntryMetadataV8, StorageEntryMetadataV9, StorageEntryModifierLatest, StorageEntryModifierV10, StorageEntryModifierV6, StorageEntryModifierV7, StorageEntryModifierV8, StorageEntryModifierV9, StorageEntryTypeLatest, StorageEntryTypeV10, StorageEntryTypeV6, StorageEntryTypeV7, StorageEntryTypeV8, StorageEntryTypeV9, StorageFunctionMetadataV0, StorageFunctionMetadataV1, StorageFunctionMetadataV2, StorageFunctionMetadataV3, StorageFunctionMetadataV4, StorageFunctionMetadataV5, StorageFunctionModifierV0, StorageFunctionModifierV1, StorageFunctionModifierV2, StorageFunctionModifierV3, StorageFunctionModifierV4, StorageFunctionModifierV5, StorageFunctionTypeV0, StorageFunctionTypeV1, StorageFunctionTypeV2, StorageFunctionTypeV3, StorageFunctionTypeV4, StorageFunctionTypeV5, StorageHasher, StorageHasherV10, StorageHasherV4, StorageHasherV5, StorageHasherV6, StorageHasherV7, StorageHasherV8, StorageHasherV9, StorageMetadataV0, StorageMetadataV10, StorageMetadataV7, StorageMetadataV8, StorageMetadataV9 } from '@polkadot/types/interfaces/metadata';
|
||||
import { ApiId, BlockHash, ChainProperties, ExtrinsicOrHash, ExtrinsicStatus, Health, KeyValueOption, NetworkState, PeerInfo, RpcMethods, RuntimeDispatchInfo, RuntimeVersion, RuntimeVersionApi, StorageChangeSet } from '@polkadot/types/interfaces/rpc';
|
||||
|
||||
export interface InterfaceRegistry {
|
||||
@@ -1334,6 +1334,9 @@ export interface InterfaceRegistry {
|
||||
StorageHasherV10: StorageHasherV10;
|
||||
'Option<StorageHasherV10>': Option<StorageHasherV10>;
|
||||
'Vec<StorageHasherV10>': Vec<StorageHasherV10>;
|
||||
DoubleMapTypeLatest: DoubleMapTypeLatest;
|
||||
'Option<DoubleMapTypeLatest>': Option<DoubleMapTypeLatest>;
|
||||
'Vec<DoubleMapTypeLatest>': Vec<DoubleMapTypeLatest>;
|
||||
EventMetadataLatest: EventMetadataLatest;
|
||||
'Option<EventMetadataLatest>': Option<EventMetadataLatest>;
|
||||
'Vec<EventMetadataLatest>': Vec<EventMetadataLatest>;
|
||||
@@ -1343,6 +1346,9 @@ export interface InterfaceRegistry {
|
||||
FunctionMetadataLatest: FunctionMetadataLatest;
|
||||
'Option<FunctionMetadataLatest>': Option<FunctionMetadataLatest>;
|
||||
'Vec<FunctionMetadataLatest>': Vec<FunctionMetadataLatest>;
|
||||
MapTypeLatest: MapTypeLatest;
|
||||
'Option<MapTypeLatest>': Option<MapTypeLatest>;
|
||||
'Vec<MapTypeLatest>': Vec<MapTypeLatest>;
|
||||
MetadataLatest: MetadataLatest;
|
||||
'Option<MetadataLatest>': Option<MetadataLatest>;
|
||||
'Vec<MetadataLatest>': Vec<MetadataLatest>;
|
||||
|
||||
@@ -435,9 +435,11 @@ export default {
|
||||
},
|
||||
|
||||
// This always maps to the latest
|
||||
DoubleMapTypeLatest: 'DoubleMapTypeV10',
|
||||
EventMetadataLatest: 'EventMetadataV10',
|
||||
FunctionArgumentMetadataLatest: 'FunctionArgumentMetadataV10',
|
||||
FunctionMetadataLatest: 'FunctionMetadataV10',
|
||||
MapTypeLatest: 'MapTypeV10',
|
||||
MetadataLatest: 'MetadataV10',
|
||||
ModuleConstantMetadataLatest: 'ModuleConstantMetadataV10',
|
||||
ModuleMetadataLatest: 'ModuleMetadataV10',
|
||||
|
||||
@@ -13,6 +13,9 @@ export interface CallMetadataV0 extends Struct {
|
||||
readonly functions: Vec<FunctionMetadataV0>;
|
||||
}
|
||||
|
||||
/** DoubleMapTypeV10 */
|
||||
export interface DoubleMapTypeLatest extends DoubleMapTypeV10 {}
|
||||
|
||||
/** Struct */
|
||||
export interface DoubleMapTypeV10 extends Struct {
|
||||
/** StorageHasherV10 */
|
||||
@@ -229,6 +232,9 @@ export interface FunctionMetadataV8 extends FunctionMetadataV7 {}
|
||||
/** FunctionMetadataV8 */
|
||||
export interface FunctionMetadataV9 extends FunctionMetadataV8 {}
|
||||
|
||||
/** MapTypeV10 */
|
||||
export interface MapTypeLatest extends MapTypeV10 {}
|
||||
|
||||
/** Struct */
|
||||
export interface MapTypeV0 extends Struct {
|
||||
/** Type */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { StorageEntryMetadataLatest, StorageEntryTypeLatest } from '../interfaces/metadata';
|
||||
import { AnyU8a, Registry } from '../types';
|
||||
import { AnyU8a, Codec, Registry } from '../types';
|
||||
|
||||
import { assert, isFunction, isString, isU8a } from '@polkadot/util';
|
||||
|
||||
@@ -11,7 +11,7 @@ import Bytes from './Bytes';
|
||||
|
||||
export interface StorageEntry {
|
||||
(arg?: any): Uint8Array;
|
||||
iterKey?: Uint8Array;
|
||||
iterKey?: Uint8Array & Codec;
|
||||
meta: StorageEntryMetadataLatest;
|
||||
method: string;
|
||||
prefix: string;
|
||||
@@ -127,7 +127,9 @@ export default class StorageKey extends Bytes {
|
||||
} else if (Array.isArray(value)) {
|
||||
const [fn] = value;
|
||||
|
||||
return unwrapStorageType(fn.meta.type);
|
||||
if (fn.meta) {
|
||||
return unwrapStorageType(fn.meta.type);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user