|
2 | 2 | import type { Observable } from 'https://esm.sh/rxjs@7.8.1';
|
3 | 3 | import type { AugmentedCall, DeriveCustom, QueryableCalls } from 'https://deno.land/x/polkadot/api-base/types/index.ts';
|
4 | 4 | import type { RpcInterface } from 'https://deno.land/x/polkadot/rpc-core/types/index.ts';
|
5 |
| -import type { Metadata, StorageKey, Text, u64 } from 'https://deno.land/x/polkadot/types/mod.ts'; |
6 |
| -import type { Call, Hash, RuntimeVersion } from 'https://deno.land/x/polkadot/types/interfaces/index.ts'; |
| 5 | +import type { Metadata, StorageKey, Text, u64, Vec } from 'https://deno.land/x/polkadot/types/mod.ts'; |
| 6 | +import type { Call, Hash, RuntimeApiMethodMetadataV15, RuntimeVersion } from 'https://deno.land/x/polkadot/types/interfaces/index.ts'; |
7 | 7 | import type { DecoratedMeta } from 'https://deno.land/x/polkadot/types/metadata/decorate/types.ts';
|
8 | 8 | import type { StorageEntry } from 'https://deno.land/x/polkadot/types/primitive/types.ts';
|
9 |
| -import type { AnyFunction, AnyJson, AnyTuple, CallFunction, Codec, DefinitionCallNamed, DefinitionRpc, DefinitionRpcSub, DefinitionsCall, DefinitionsCallEntry, DetectCodec, IMethod, IStorageKey, Registry, RegistryError, RegistryTypes } from 'https://deno.land/x/polkadot/types/types/index.ts'; |
| 9 | +import type { AnyFunction, AnyJson, AnyTuple, CallFunction, Codec, DefinitionCall, DefinitionCallNamed, DefinitionRpc, DefinitionRpcSub, DefinitionsCall, DefinitionsCallEntry, DetectCodec, IMethod, IStorageKey, Registry, RegistryError, RegistryTypes } from 'https://deno.land/x/polkadot/types/types/index.ts'; |
10 | 10 | import type { HexString } from 'https://deno.land/x/polkadot/util/types.ts';
|
11 | 11 | import type { SubmittableExtrinsic } from '../submittable/types.ts';
|
12 | 12 | import type { ApiDecoration, ApiInterfaceRx, ApiOptions, ApiTypes, AugmentedQuery, DecoratedErrors, DecoratedEvents, DecoratedRpc, DecorateMethod, GenericStorageEntryFunction, PaginationOptions, QueryableConsts, QueryableStorage, QueryableStorageEntry, QueryableStorageEntryAt, QueryableStorageMulti, QueryableStorageMultiArg, SubmittableExtrinsicFunction, SubmittableExtrinsics } from '../types/index.ts';
|
@@ -489,64 +489,126 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
489 | 489 | return Object.entries(result);
|
490 | 490 | }
|
491 | 491 |
|
492 |
| - // pre-metadata decoration |
| 492 | + // Helper for _getRuntimeDefsViaMetadata |
| 493 | + protected _getMethods (registry: Registry, methods: Vec<RuntimeApiMethodMetadataV15>) { |
| 494 | + const result: Record<string, DefinitionCall> = {}; |
| 495 | + |
| 496 | + methods.forEach((m) => { |
| 497 | + const { docs, inputs, name, output } = m; |
| 498 | + |
| 499 | + result[name.toString()] = { |
| 500 | + description: docs.map((d) => d.toString()).join(), |
| 501 | + params: inputs.map(({ name, type }) => { |
| 502 | + return { name: name.toString(), type: registry.lookup.getName(type) || registry.lookup.getTypeDef(type).type }; |
| 503 | + }), |
| 504 | + type: registry.lookup.getName(output) || registry.lookup.getTypeDef(output).type |
| 505 | + }; |
| 506 | + }); |
| 507 | + |
| 508 | + return result; |
| 509 | + } |
| 510 | + |
| 511 | + // Maintains the same structure as `_getRuntimeDefs` in order to make conversion easier. |
| 512 | + protected _getRuntimeDefsViaMetadata (registry: Registry): [string, DefinitionsCallEntry[]][] { |
| 513 | + const result: DefinitionsCall = {}; |
| 514 | + const { apis } = registry.metadata; |
| 515 | + |
| 516 | + for (let i = 0, count = apis.length; i < count; i++) { |
| 517 | + const { methods, name } = apis[i]; |
| 518 | + |
| 519 | + result[name.toString()] = [{ |
| 520 | + methods: this._getMethods(registry, methods), |
| 521 | + // We set the version to 0 here since it will not be relevant when we are grabbing the runtime apis |
| 522 | + // from the Metadata. |
| 523 | + version: 0 |
| 524 | + }]; |
| 525 | + } |
| 526 | + |
| 527 | + return Object.entries(result); |
| 528 | + } |
| 529 | + |
| 530 | + // When the calls are available in the metadata, it will generate them based off of the metadata. |
| 531 | + // When they are not available it will use the hardcoded calls generated in the static types. |
493 | 532 | protected _decorateCalls<ApiType extends ApiTypes> ({ registry, runtimeVersion: { apis, specName, specVersion } }: VersionedRegistry<any>, decorateMethod: DecorateMethod<ApiType>, blockHash?: Uint8Array | string | null): QueryableCalls<ApiType> {
|
494 | 533 | const result = {} as QueryableCalls<ApiType>;
|
495 | 534 | const named: Record<string, Record<string, DefinitionCallNamed>> = {};
|
496 | 535 | const hashes: Record<HexString, boolean> = {};
|
497 |
| - const sections = this._getRuntimeDefs(registry, specName, this._runtimeChain); |
| 536 | + const isApiInMetadata = registry.metadata.apis.length > 0; |
| 537 | + const sections = isApiInMetadata ? this._getRuntimeDefsViaMetadata(registry) : this._getRuntimeDefs(registry, specName, this._runtimeChain); |
498 | 538 | const older: string[] = [];
|
499 | 539 | const implName = `${specName.toString()}/${specVersion.toString()}`;
|
500 | 540 | const hasLogged = this.#runtimeLog[implName] || false;
|
501 | 541 |
|
502 | 542 | this.#runtimeLog[implName] = true;
|
503 | 543 |
|
504 |
| - for (let i = 0, scount = sections.length; i < scount; i++) { |
505 |
| - const [_section, secs] = sections[i]; |
506 |
| - const sectionHash = blake2AsHex(_section, 64); |
507 |
| - const rtApi = apis.find(([a]) => a.eq(sectionHash)); |
| 544 | + if (isApiInMetadata) { |
| 545 | + for (let i = 0, scount = sections.length; i < scount; i++) { |
| 546 | + const [_section, secs] = sections[i]; |
| 547 | + const sec = secs[0]; |
| 548 | + const sectionHash = blake2AsHex(_section, 64); |
508 | 549 |
|
509 |
| - hashes[sectionHash] = true; |
| 550 | + const section = stringCamelCase(_section); |
| 551 | + const methods = Object.entries(sec.methods); |
510 | 552 |
|
511 |
| - if (rtApi) { |
512 |
| - const all = secs.map(({ version }) => version).sort(); |
513 |
| - const sec = secs.find(({ version }) => rtApi[1].eq(version)); |
| 553 | + if (!named[section]) { |
| 554 | + named[section] = {}; |
| 555 | + } |
514 | 556 |
|
515 |
| - if (sec) { |
516 |
| - const section = stringCamelCase(_section); |
517 |
| - const methods = Object.entries(sec.methods); |
| 557 | + for (let m = 0, mcount = methods.length; m < mcount; m++) { |
| 558 | + const [_method, def] = methods[m]; |
| 559 | + const method = stringCamelCase(_method); |
518 | 560 |
|
519 |
| - if (methods.length) { |
520 |
| - if (!named[section]) { |
521 |
| - named[section] = {}; |
522 |
| - } |
| 561 | + named[section][method] = objectSpread({ method, name: `${_section}_${_method}`, section, sectionHash }, def); |
| 562 | + } |
| 563 | + } |
| 564 | + } else { |
| 565 | + for (let i = 0, scount = sections.length; i < scount; i++) { |
| 566 | + const [_section, secs] = sections[i]; |
| 567 | + const sectionHash = blake2AsHex(_section, 64); |
| 568 | + const rtApi = apis.find(([a]) => a.eq(sectionHash)); |
| 569 | + |
| 570 | + hashes[sectionHash] = true; |
| 571 | + |
| 572 | + if (rtApi) { |
| 573 | + const all = secs.map(({ version }) => version).sort(); |
| 574 | + const sec = secs.find(({ version }) => rtApi[1].eq(version)); |
523 | 575 |
|
524 |
| - for (let m = 0, mcount = methods.length; m < mcount; m++) { |
525 |
| - const [_method, def] = methods[m]; |
526 |
| - const method = stringCamelCase(_method); |
| 576 | + if (sec) { |
| 577 | + const section = stringCamelCase(_section); |
| 578 | + const methods = Object.entries(sec.methods); |
527 | 579 |
|
528 |
| - named[section][method] = objectSpread({ method, name: `${_section}_${_method}`, section, sectionHash }, def); |
| 580 | + if (methods.length) { |
| 581 | + if (!named[section]) { |
| 582 | + named[section] = {}; |
| 583 | + } |
| 584 | + |
| 585 | + for (let m = 0, mcount = methods.length; m < mcount; m++) { |
| 586 | + const [_method, def] = methods[m]; |
| 587 | + const method = stringCamelCase(_method); |
| 588 | + |
| 589 | + named[section][method] = objectSpread({ method, name: `${_section}_${_method}`, section, sectionHash }, def); |
| 590 | + } |
529 | 591 | }
|
| 592 | + } else { |
| 593 | + older.push(`${_section}/${rtApi[1].toString()} (${all.join('/')} known)`); |
530 | 594 | }
|
531 |
| - } else { |
532 |
| - older.push(`${_section}/${rtApi[1].toString()} (${all.join('/')} known)`); |
533 | 595 | }
|
534 | 596 | }
|
535 |
| - } |
536 | 597 |
|
537 |
| - // find the runtimes that we don't have hashes for |
538 |
| - const notFound = apis |
539 |
| - .map(([a, v]): [HexString, string] => [a.toHex(), v.toString()]) |
540 |
| - .filter(([a]) => !hashes[a]) |
541 |
| - .map(([a, v]) => `${this._runtimeMap[a] || a}/${v}`); |
| 598 | + // find the runtimes that we don't have hashes for |
| 599 | + const notFound = apis |
| 600 | + .map(([a, v]): [HexString, string] => [a.toHex(), v.toString()]) |
| 601 | + .filter(([a]) => !hashes[a]) |
| 602 | + .map(([a, v]) => `${this._runtimeMap[a] || a}/${v}`); |
542 | 603 |
|
543 |
| - if (!this._options.noInitWarn && !hasLogged) { |
544 |
| - if (older.length) { |
545 |
| - l.warn(`${implName}: Not decorating runtime apis without matching versions: ${older.join(', ')}`); |
546 |
| - } |
| 604 | + if (!this._options.noInitWarn && !hasLogged) { |
| 605 | + if (older.length) { |
| 606 | + l.warn(`${implName}: Not decorating runtime apis without matching versions: ${older.join(', ')}`); |
| 607 | + } |
547 | 608 |
|
548 |
| - if (notFound.length) { |
549 |
| - l.warn(`${implName}: Not decorating unknown runtime apis: ${notFound.join(', ')}`); |
| 609 | + if (notFound.length) { |
| 610 | + l.warn(`${implName}: Not decorating unknown runtime apis: ${notFound.join(', ')}`); |
| 611 | + } |
550 | 612 | }
|
551 | 613 | }
|
552 | 614 |
|
|
0 commit comments