Compare commits

...
19 Commits
Author SHA1 Message Date
Github Actions 25288f664a [CI Skip] release/stable 6.8.1
skip-checks: true
2021-11-11 11:15:45 +00:00
Jaco 879c5d7b44 6.8.1 (#4201)
* 6.8.1

* rx.queryAt param CHANGELOG
2021-11-11 13:08:24 +02:00
Jaco cdaec1953c Add knownVersion on rx.queryAt (#4194) 2021-11-11 11:30:16 +02:00
Github Actions f4bf7a9c52 [CI Skip] release/beta 6.7.3-7
skip-checks: true
2021-11-11 05:28:44 +00:00
Jaco 7b46c6aa15 Adjust signFake to apply large default signature (#4199)
* Adjust signFake to apply empty default signature

* 0x01... default

* Rename constant

* Add previously failing test
2021-11-11 07:19:21 +02:00
Github Actions d28f4ccfa0 [CI Skip] release/beta 6.7.3-6
skip-checks: true
2021-11-10 17:43:43 +00:00
Jaco e5b05dc700 Slight adjustment to rpc-provider LRU (#4198) 2021-11-10 19:35:20 +02:00
Github Actions bf9831753e [CI Skip] release/beta 6.7.3-5
skip-checks: true
2021-11-10 12:53:27 +00:00
Jaco 5e1670dbae Provider-level caching for historic requests (#4195)
* Provider-level caching for historic requests

* LRUCache

* Adjust

* Adjust

* Adjust

* Opts

* private variables

* Implementation link

* lru .entries adjustment (using .keys)

* Adjust expectations
2021-11-10 14:46:13 +02:00
Github Actions 0d0a230c86 [CI Skip] release/beta 6.7.3-4
skip-checks: true
2021-11-10 08:55:22 +00:00
Jaco 9989b69b46 Rename decorate method (#4193)
* Rename decorateMethod*

* Split exports
2021-11-10 10:48:20 +02:00
Github Actions 66693253ef [CI Skip] release/beta 6.7.3-3
skip-checks: true
2021-11-10 07:05:56 +00:00
Jaco cbffc37dcf Optimize PortableRegistry (#4192)
* Optimize PortableRegistry

* Additional

* Adjust shortcut

* Adjust params

* Move decorateMethod

* Ordering

* Adjust

* Exports

* Renames
2021-11-10 08:58:50 +02:00
Github Actions 74ee42ed66 [CI Skip] release/beta 6.7.3-2
skip-checks: true
2021-11-10 05:15:04 +00:00
Jaco f642e2399f Polkadot 9122 block (#4191) 2021-11-10 07:07:31 +02:00
Github Actions 8cefb055db [CI Skip] release/beta 6.7.3-1
skip-checks: true
2021-11-09 14:17:36 +00:00
Jaco 1f31756019 Ensure known types for v14 is empty (#4190) 2021-11-09 16:10:44 +02:00
Github Actions 4d6a1da6d5 [CI Skip] release/beta 6.7.3-0
skip-checks: true
2021-11-09 11:30:34 +00:00
Jaco d62e720627 Remove ::generic:: from names & namespaces (#4189) 2021-11-09 13:23:10 +02:00
60 changed files with 1044 additions and 743 deletions
+15
View File
@@ -1,5 +1,20 @@
# CHANGELOG # CHANGELOG
## 6.8.1 Nov 11, 2021
Upgrade priority: Low. Recommended for chains with non-MultiSignature variants where `paymentInfo` is required.
Changes:
- Adjust `paymentInfo` signatures to cater for non-MultiSignature variants
- Remove `::generic::` from names & namespaces under metadata v14
- Add Polkadot 9122 upgrade block
- Cleanup Polkadot/Kusama/Westend/Rococo known types (>= v14 metadata)
- Internal `decorateMethod{Promise, Rx}` renamed to `to{Promise, Rx}Method`
- Add RPC provider-level LRU for historic requests
- Add optional known runtime version param to internal `rx.queryAt`
## 6.7.2 Nov 9, 2021 ## 6.7.2 Nov 9, 2021
Upgrade priority: Low. Recommended for chains on metadata v14 with non-default `Address` implementations. Upgrade priority: Low. Recommended for chains on metadata v14 with non-default `Address` implementations.
+1 -1
View File
@@ -11,7 +11,7 @@
}, },
"sideEffects": false, "sideEffects": false,
"type": "commonjs", "type": "commonjs",
"version": "6.7.2", "version": "6.8.1",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],
+3 -3
View File
@@ -20,12 +20,12 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/api": "6.7.2", "@polkadot/api": "6.8.1",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/util": "^7.8.2", "@polkadot/util": "^7.8.2",
"rxjs": "^7.4.0" "rxjs": "^7.4.0"
} }
+2 -1
View File
@@ -23,7 +23,8 @@ export abstract class Base<ApiType extends ApiTypes> {
this.api = api; this.api = api;
this._decorateMethod = decorateMethod; this._decorateMethod = decorateMethod;
assert(!!(api && api.isConnected && api.tx && api.tx.contracts && Object.keys(api.tx.contracts).length), 'Your API has not been initialized correctly and it not decorated with the runtime interfaces for contracts as retrieved from the on-chain runtime'); assert(!!(api && api.isConnected && api.tx), 'Your API has not been initialized correctly and is not connected to a chain');
assert(!!(api.tx.contracts && Object.keys(api.tx.contracts).length), 'You need to connect to a chain with a runtime that supports contracts');
assert(isFunction(api.tx.contracts.instantiateWithCode), 'You need to connect to a chain with a runtime with a V3 contracts module. The runtime does not expose api.tx.contracts.instantiateWithCode'); assert(isFunction(api.tx.contracts.instantiateWithCode), 'You need to connect to a chain with a runtime with a V3 contracts module. The runtime does not expose api.tx.contracts.instantiateWithCode');
} }
+4 -4
View File
@@ -6,7 +6,7 @@ import type { AnyJson } from '@polkadot/types/types';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { decorateMethodPromise } from '@polkadot/api'; import { toPromiseMethod } from '@polkadot/api';
import v0contractFlipper from '../../test/contracts/ink/v0/flipper.contract.json'; import v0contractFlipper from '../../test/contracts/ink/v0/flipper.contract.json';
import v0abiFlipper from '../../test/contracts/ink/v0/flipper.json'; import v0abiFlipper from '../../test/contracts/ink/v0/flipper.json';
@@ -19,19 +19,19 @@ const v0wasmFlipper = fs.readFileSync(path.join(__dirname, '../../test/contracts
describe('Code', (): void => { describe('Code', (): void => {
it('can construct with an individual ABI/WASM combo', (): void => { it('can construct with an individual ABI/WASM combo', (): void => {
expect( expect(
() => new Code(mockApi, v0abiFlipper as AnyJson, v0wasmFlipper, decorateMethodPromise) () => new Code(mockApi, v0abiFlipper as AnyJson, v0wasmFlipper, toPromiseMethod)
).not.toThrow(); ).not.toThrow();
}); });
it('can construct with an .contract ABI (v0)', (): void => { it('can construct with an .contract ABI (v0)', (): void => {
expect( expect(
() => new Code(mockApi, v0contractFlipper as AnyJson, null, decorateMethodPromise) () => new Code(mockApi, v0contractFlipper as AnyJson, null, toPromiseMethod)
).not.toThrow(); ).not.toThrow();
}); });
it.only('can construct with an .contract ABI (v1)', (): void => { it.only('can construct with an .contract ABI (v1)', (): void => {
expect( expect(
() => new Code(mockApi, v1contractFlipper as AnyJson, null, decorateMethodPromise) () => new Code(mockApi, v1contractFlipper as AnyJson, null, toPromiseMethod)
).not.toThrow(); ).not.toThrow();
}); });
}); });
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/api-contract', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/api-contract', version: '6.8.1' };
@@ -4,13 +4,13 @@
import type { Hash } from '@polkadot/types/interfaces'; import type { Hash } from '@polkadot/types/interfaces';
import type { AnyJson } from '@polkadot/types/types'; import type { AnyJson } from '@polkadot/types/types';
import { ApiPromise, decorateMethodPromise } from '@polkadot/api'; import { ApiPromise, toPromiseMethod } from '@polkadot/api';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { Blueprint as BaseBlueprint } from '../base'; import { Blueprint as BaseBlueprint } from '../base';
export class Blueprint extends BaseBlueprint<'promise'> { export class Blueprint extends BaseBlueprint<'promise'> {
constructor (api: ApiPromise, abi: AnyJson | Abi, codeHash: string | Hash) { constructor (api: ApiPromise, abi: AnyJson | Abi, codeHash: string | Hash) {
super(api, abi, codeHash, decorateMethodPromise); super(api, abi, codeHash, toPromiseMethod);
} }
} }
+2 -2
View File
@@ -4,13 +4,13 @@
import type { ApiPromise } from '@polkadot/api'; import type { ApiPromise } from '@polkadot/api';
import type { AnyJson } from '@polkadot/types/types'; import type { AnyJson } from '@polkadot/types/types';
import { decorateMethodPromise } from '@polkadot/api'; import { toPromiseMethod } from '@polkadot/api';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { Code as BaseCode } from '../base'; import { Code as BaseCode } from '../base';
export class Code extends BaseCode<'promise'> { export class Code extends BaseCode<'promise'> {
constructor (api: ApiPromise, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer | null | undefined) { constructor (api: ApiPromise, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer | null | undefined) {
super(api, abi, wasm, decorateMethodPromise); super(api, abi, wasm, toPromiseMethod);
} }
} }
@@ -4,13 +4,13 @@
import type { AccountId } from '@polkadot/types/interfaces'; import type { AccountId } from '@polkadot/types/interfaces';
import type { AnyJson } from '@polkadot/types/types'; import type { AnyJson } from '@polkadot/types/types';
import { ApiPromise, decorateMethodPromise } from '@polkadot/api'; import { ApiPromise, toPromiseMethod } from '@polkadot/api';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { Contract as BaseContract } from '../base'; import { Contract as BaseContract } from '../base';
export class Contract extends BaseContract<'promise'> { export class Contract extends BaseContract<'promise'> {
constructor (api: ApiPromise, abi: AnyJson | Abi, address: string | AccountId) { constructor (api: ApiPromise, abi: AnyJson | Abi, address: string | AccountId) {
super(api, abi, address, decorateMethodPromise); super(api, abi, address, toPromiseMethod);
} }
} }
+2 -2
View File
@@ -4,13 +4,13 @@
import type { Hash } from '@polkadot/types/interfaces'; import type { Hash } from '@polkadot/types/interfaces';
import type { AnyJson } from '@polkadot/types/types'; import type { AnyJson } from '@polkadot/types/types';
import { ApiRx, decorateMethodRx } from '@polkadot/api'; import { ApiRx, toRxMethod } from '@polkadot/api';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { Blueprint as BaseBlueprint } from '../base'; import { Blueprint as BaseBlueprint } from '../base';
export class Blueprint extends BaseBlueprint<'rxjs'> { export class Blueprint extends BaseBlueprint<'rxjs'> {
constructor (api: ApiRx, abi: AnyJson | Abi, codeHash: string | Hash) { constructor (api: ApiRx, abi: AnyJson | Abi, codeHash: string | Hash) {
super(api, abi, codeHash, decorateMethodRx); super(api, abi, codeHash, toRxMethod);
} }
} }
+2 -2
View File
@@ -4,13 +4,13 @@
import type { ApiRx } from '@polkadot/api'; import type { ApiRx } from '@polkadot/api';
import type { AnyJson } from '@polkadot/types/types'; import type { AnyJson } from '@polkadot/types/types';
import { decorateMethodRx } from '@polkadot/api'; import { toRxMethod } from '@polkadot/api';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { Code as BaseCode } from '../base'; import { Code as BaseCode } from '../base';
export class Code extends BaseCode<'rxjs'> { export class Code extends BaseCode<'rxjs'> {
constructor (api: ApiRx, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer | null | undefined) { constructor (api: ApiRx, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer | null | undefined) {
super(api, abi, wasm, decorateMethodRx); super(api, abi, wasm, toRxMethod);
} }
} }
+2 -2
View File
@@ -4,13 +4,13 @@
import type { AccountId } from '@polkadot/types/interfaces'; import type { AccountId } from '@polkadot/types/interfaces';
import type { AnyJson } from '@polkadot/types/types'; import type { AnyJson } from '@polkadot/types/types';
import { ApiRx, decorateMethodRx } from '@polkadot/api'; import { ApiRx, toRxMethod } from '@polkadot/api';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { Contract as BaseContract } from '../base'; import { Contract as BaseContract } from '../base';
export class Contract extends BaseContract<'rxjs'> { export class Contract extends BaseContract<'rxjs'> {
constructor (api: ApiRx, abi: AnyJson | Abi, address: string | AccountId) { constructor (api: ApiRx, abi: AnyJson | Abi, address: string | AccountId) {
super(api, abi, address, decorateMethodRx); super(api, abi, address, toRxMethod);
} }
} }
+5 -5
View File
@@ -20,19 +20,19 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/api": "6.7.2", "@polkadot/api": "6.8.1",
"@polkadot/rpc-core": "6.7.2", "@polkadot/rpc-core": "6.8.1",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/util": "^7.8.2", "@polkadot/util": "^7.8.2",
"@polkadot/util-crypto": "^7.8.2", "@polkadot/util-crypto": "^7.8.2",
"rxjs": "^7.4.0" "rxjs": "^7.4.0"
}, },
"devDependencies": { "devDependencies": {
"@polkadot/keyring": "^7.8.2", "@polkadot/keyring": "^7.8.2",
"@polkadot/rpc-provider": "6.7.2" "@polkadot/rpc-provider": "6.8.1"
} }
} }
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/api-derive', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/api-derive', version: '6.8.1' };
+6 -6
View File
@@ -20,16 +20,16 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/api-derive": "6.7.2", "@polkadot/api-derive": "6.8.1",
"@polkadot/keyring": "^7.8.2", "@polkadot/keyring": "^7.8.2",
"@polkadot/rpc-core": "6.7.2", "@polkadot/rpc-core": "6.8.1",
"@polkadot/rpc-provider": "6.7.2", "@polkadot/rpc-provider": "6.8.1",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/types-known": "6.7.2", "@polkadot/types-known": "6.8.1",
"@polkadot/util": "^7.8.2", "@polkadot/util": "^7.8.2",
"@polkadot/util-crypto": "^7.8.2", "@polkadot/util-crypto": "^7.8.2",
"eventemitter3": "^4.0.7", "eventemitter3": "^4.0.7",
+2 -2
View File
@@ -4,7 +4,7 @@
import type { ApiTypes } from '@polkadot/api/types'; import type { ApiTypes } from '@polkadot/api/types';
import type { BTreeMap, Bytes, Data, Null, Option, U8aFixed, Vec, WrapperOpaque, bool, u128, u32, u64, u8 } from '@polkadot/types'; import type { BTreeMap, Bytes, Data, Null, Option, U8aFixed, Vec, WrapperOpaque, bool, u128, u32, u64, u8 } from '@polkadot/types';
import type { AccountId32, Call, H256, Perbill, Percent } from '@polkadot/types/interfaces/runtime'; import type { AccountId32, Call, H256, Perbill, Percent } from '@polkadot/types/interfaces/runtime';
import type { FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, NodeRuntimeSessionKeys, PalletAssetsApproval, PalletAssetsAssetBalance, PalletAssetsAssetDetails, PalletAssetsAssetMetadata, PalletAuthorshipUncleEntryItem, PalletBagsListListBag, PalletBagsListListNode, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletBountiesBounty, PalletCollectiveVotes, PalletContractsStorageDeletedContract, PalletContractsStorageRawContractInfo, PalletContractsWasmPrefabWasmModule, PalletDemocracyPreimageStatus, PalletDemocracyReferendumInfo, PalletDemocracyReleases, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletElectionProviderMultiPhasePhase, PalletElectionProviderMultiPhaseReadySolution, PalletElectionProviderMultiPhaseRoundSnapshot, PalletElectionProviderMultiPhaseSignedSignedSubmission, PalletElectionProviderMultiPhaseSolutionOrSnapshotSize, PalletElectionsPhragmenSeatHolder, PalletElectionsPhragmenVoter, PalletGiltActiveGilt, PalletGiltActiveGiltsTotal, PalletGiltGiltBid, PalletGrandpaStoredPendingChange, PalletGrandpaStoredState, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletImOnlineBoundedOpaqueNetworkState, PalletImOnlineSr25519AppSr25519Public, PalletLotteryLotteryConfig, PalletMultisigMultisig, PalletProxyAnnouncement, PalletProxyProxyDefinition, PalletRecoveryActiveRecovery, PalletRecoveryRecoveryConfig, PalletSchedulerReleases, PalletSchedulerScheduledV2, PalletSocietyBid, PalletSocietyBidKind, PalletSocietyVote, PalletSocietyVouchingStatus, PalletStakingActiveEraInfo, PalletStakingEraRewardPoints, PalletStakingExposure, PalletStakingForcing, PalletStakingNominations, PalletStakingReleases, PalletStakingRewardDestination, PalletStakingSlashingSlashingSpans, PalletStakingSlashingSpanRecord, PalletStakingStakingLedger, PalletStakingUnappliedSlash, PalletStakingValidatorPrefs, PalletTipsOpenTip, PalletTransactionPaymentReleases, PalletTransactionStorageTransactionInfo, PalletTreasuryProposal, PalletUniquesClassDetails, PalletUniquesClassMetadata, PalletUniquesInstanceDetails, PalletUniquesInstanceMetadata, PalletVestingReleases, PalletVestingVestingInfo, SpAuthorityDiscoveryAppPublic, SpConsensusBabeAppPublic, SpConsensusBabeBabeEpochConfiguration, SpConsensusBabeDigestsNextConfigDescriptor, SpCoreCryptoKeyTypeId, SpRuntimeGenericDigest, SpStakingOffenceOffenceDetails } from '@polkadot/types/lookup'; import type { FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, NodeRuntimeSessionKeys, PalletAssetsApproval, PalletAssetsAssetBalance, PalletAssetsAssetDetails, PalletAssetsAssetMetadata, PalletAuthorshipUncleEntryItem, PalletBagsListListBag, PalletBagsListListNode, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletBountiesBounty, PalletCollectiveVotes, PalletContractsStorageDeletedContract, PalletContractsStorageRawContractInfo, PalletContractsWasmPrefabWasmModule, PalletDemocracyPreimageStatus, PalletDemocracyReferendumInfo, PalletDemocracyReleases, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletElectionProviderMultiPhasePhase, PalletElectionProviderMultiPhaseReadySolution, PalletElectionProviderMultiPhaseRoundSnapshot, PalletElectionProviderMultiPhaseSignedSignedSubmission, PalletElectionProviderMultiPhaseSolutionOrSnapshotSize, PalletElectionsPhragmenSeatHolder, PalletElectionsPhragmenVoter, PalletGiltActiveGilt, PalletGiltActiveGiltsTotal, PalletGiltGiltBid, PalletGrandpaStoredPendingChange, PalletGrandpaStoredState, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletImOnlineBoundedOpaqueNetworkState, PalletImOnlineSr25519AppSr25519Public, PalletLotteryLotteryConfig, PalletMultisigMultisig, PalletProxyAnnouncement, PalletProxyProxyDefinition, PalletRecoveryActiveRecovery, PalletRecoveryRecoveryConfig, PalletSchedulerReleases, PalletSchedulerScheduledV2, PalletSocietyBid, PalletSocietyBidKind, PalletSocietyVote, PalletSocietyVouchingStatus, PalletStakingActiveEraInfo, PalletStakingEraRewardPoints, PalletStakingExposure, PalletStakingForcing, PalletStakingNominations, PalletStakingReleases, PalletStakingRewardDestination, PalletStakingSlashingSlashingSpans, PalletStakingSlashingSpanRecord, PalletStakingStakingLedger, PalletStakingUnappliedSlash, PalletStakingValidatorPrefs, PalletTipsOpenTip, PalletTransactionPaymentReleases, PalletTransactionStorageTransactionInfo, PalletTreasuryProposal, PalletUniquesClassDetails, PalletUniquesClassMetadata, PalletUniquesInstanceDetails, PalletUniquesInstanceMetadata, PalletVestingReleases, PalletVestingVestingInfo, SpAuthorityDiscoveryAppPublic, SpConsensusBabeAppPublic, SpConsensusBabeBabeEpochConfiguration, SpConsensusBabeDigestsNextConfigDescriptor, SpCoreCryptoKeyTypeId, SpRuntimeDigest, SpStakingOffenceOffenceDetails } from '@polkadot/types/lookup';
import type { AnyNumber, ITuple, Observable } from '@polkadot/types/types'; import type { AnyNumber, ITuple, Observable } from '@polkadot/types/types';
declare module '@polkadot/api/types/storage' { declare module '@polkadot/api/types/storage' {
@@ -1163,7 +1163,7 @@ declare module '@polkadot/api/types/storage' {
/** /**
* Digest of the current block, also part of the block header. * Digest of the current block, also part of the block header.
**/ **/
digest: AugmentedQuery<ApiType, () => Observable<SpRuntimeGenericDigest>, []> & QueryableStorageEntry<ApiType, []>; digest: AugmentedQuery<ApiType, () => Observable<SpRuntimeDigest>, []> & QueryableStorageEntry<ApiType, []>;
/** /**
* The number of events in the `Events<T>` list. * The number of events in the `Events<T>` list.
**/ **/
+2 -2
View File
@@ -5,7 +5,7 @@ import type { ApiTypes, SubmittableExtrinsic } from '@polkadot/api/types';
import type { Bytes, Compact, Data, Option, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types'; import type { Bytes, Compact, Data, Option, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types';
import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics'; import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
import type { AccountId32, Call, H256, MultiAddress, Perbill, Percent, Perquintill } from '@polkadot/types/interfaces/runtime'; import type { AccountId32, Call, H256, MultiAddress, Perbill, Percent, Perquintill } from '@polkadot/types/interfaces/runtime';
import type { NodeRuntimeOriginCaller, NodeRuntimeProxyType, NodeRuntimeSessionKeys, PalletAssetsDestroyWitness, PalletDemocracyConviction, PalletDemocracyVoteAccountVote, PalletElectionProviderMultiPhaseRawSolution, PalletElectionProviderMultiPhaseSolutionOrSnapshotSize, PalletElectionsPhragmenRenouncing, PalletIdentityBitFlags, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletImOnlineHeartbeat, PalletImOnlineSr25519AppSr25519Signature, PalletMultisigTimepoint, PalletSocietyJudgement, PalletStakingRewardDestination, PalletStakingValidatorPrefs, PalletUniquesDestroyWitness, PalletVestingVestingInfo, SpConsensusBabeDigestsNextConfigDescriptor, SpConsensusSlotsEquivocationProof, SpCoreChangesTrieChangesTrieConfiguration, SpFinalityGrandpaEquivocationProof, SpNposElectionsSupport, SpRuntimeGenericHeader, SpSessionMembershipProof, SpTransactionStorageProofTransactionStorageProof } from '@polkadot/types/lookup'; import type { NodeRuntimeOriginCaller, NodeRuntimeProxyType, NodeRuntimeSessionKeys, PalletAssetsDestroyWitness, PalletDemocracyConviction, PalletDemocracyVoteAccountVote, PalletElectionProviderMultiPhaseRawSolution, PalletElectionProviderMultiPhaseSolutionOrSnapshotSize, PalletElectionsPhragmenRenouncing, PalletIdentityBitFlags, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletImOnlineHeartbeat, PalletImOnlineSr25519AppSr25519Signature, PalletMultisigTimepoint, PalletSocietyJudgement, PalletStakingRewardDestination, PalletStakingValidatorPrefs, PalletUniquesDestroyWitness, PalletVestingVestingInfo, SpConsensusBabeDigestsNextConfigDescriptor, SpConsensusSlotsEquivocationProof, SpCoreChangesTrieChangesTrieConfiguration, SpFinalityGrandpaEquivocationProof, SpNposElectionsSupport, SpRuntimeHeader, SpSessionMembershipProof, SpTransactionStorageProofTransactionStorageProof } from '@polkadot/types/lookup';
import type { AnyNumber, ITuple } from '@polkadot/types/types'; import type { AnyNumber, ITuple } from '@polkadot/types/types';
declare module '@polkadot/api/types/submittable' { declare module '@polkadot/api/types/submittable' {
@@ -425,7 +425,7 @@ declare module '@polkadot/api/types/submittable' {
/** /**
* Provide a set of uncles. * Provide a set of uncles.
**/ **/
setUncles: AugmentedSubmittable<(newUncles: Vec<SpRuntimeGenericHeader> | (SpRuntimeGenericHeader | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<SpRuntimeGenericHeader>]>; setUncles: AugmentedSubmittable<(newUncles: Vec<SpRuntimeHeader> | (SpRuntimeHeader | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<SpRuntimeHeader>]>;
/** /**
* Generic tx * Generic tx
**/ **/
+2 -2
View File
@@ -146,8 +146,8 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
this.#instanceId = `${++instanceCounter}`; this.#instanceId = `${++instanceCounter}`;
this.#registry = options.source?.registry || options.registry || new TypeRegistry(); this.#registry = options.source?.registry || options.registry || new TypeRegistry();
this._rx.queryAt = (blockHash: Uint8Array | string) => this._rx.queryAt = (blockHash: Uint8Array | string, knownVersion?: RuntimeVersion) =>
from(this.at(blockHash)).pipe(map((a) => a.rx.query)); from(this.at(blockHash, knownVersion)).pipe(map((a) => a.rx.query));
this._rx.registry = this.#registry; this._rx.registry = this.#registry;
const thisProvider = options.source const thisProvider = options.source
+2 -2
View File
@@ -5,6 +5,6 @@ export { Keyring } from '@polkadot/keyring';
export { WsProvider, HttpProvider } from '@polkadot/rpc-provider'; export { WsProvider, HttpProvider } from '@polkadot/rpc-provider';
export { packageInfo } from './packageInfo'; export { packageInfo } from './packageInfo';
export { ApiPromise, decorateMethod as decorateMethodPromise } from './promise'; export * from './promise';
export { SubmittableResult } from './submittable'; export { SubmittableResult } from './submittable';
export { ApiRx, decorateMethod as decorateMethodRx } from './rx'; export * from './rx';
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/api', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/api', version: '6.8.1' };
+215
View File
@@ -0,0 +1,215 @@
// Copyright 2017-2021 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiOptions, UnsubscribePromise } from '../types';
import { objectSpread } from '@polkadot/util';
import { ApiBase } from '../base';
import { Combinator, CombinatorCallback, CombinatorFunction } from './Combinator';
import { promiseTracker, toPromiseMethod } from './decorateMethod';
/**
* # @polkadot/api/promise
*
* ## Overview
*
* @name ApiPromise
* @description
* ApiPromise is a standard JavaScript wrapper around the RPC and interfaces on the Polkadot network. As a full Promise-based, all interface calls return Promises, including the static `.create(...)`. Subscription calls utilise `(value) => {}` callbacks to pass through the latest values.
*
* The API is well suited to real-time applications where either the single-shot state is needed or use is to be made of the subscription-based features of Polkadot (and Substrate) clients.
*
* @see [[ApiRx]]
*
* ## Usage
*
* Making rpc calls -
* <BR>
*
* ```javascript
* import ApiPromise from '@polkadot/api/promise';
*
* // initialise via static create
* const api = await ApiPromise.create();
*
* // make a subscription to the network head
* api.rpc.chain.subscribeNewHeads((header) => {
* console.log(`Chain is at #${header.number}`);
* });
* ```
* <BR>
*
* Subscribing to chain state -
* <BR>
*
* ```javascript
* import { ApiPromise, WsProvider } from '@polkadot/api';
*
* // initialise a provider with a specific endpoint
* const provider = new WsProvider('wss://example.com:9944')
*
* // initialise via isReady & new with specific provider
* const api = await new ApiPromise({ provider }).isReady;
*
* // retrieve the block target time
* const blockPeriod = await api.query.timestamp.blockPeriod().toNumber();
* let last = 0;
*
* // subscribe to the current block timestamp, updates automatically (callback provided)
* api.query.timestamp.now((timestamp) => {
* const elapsed = last
* ? `, ${timestamp.toNumber() - last}s since last`
* : '';
*
* last = timestamp.toNumber();
* console.log(`timestamp ${timestamp}${elapsed} (${blockPeriod}s target)`);
* });
* ```
* <BR>
*
* Submitting a transaction -
* <BR>
*
* ```javascript
* import ApiPromise from '@polkadot/api/promise';
*
* ApiPromise.create().then((api) => {
* const [nonce] = await api.query.system.account(keyring.alice.address);
*
* api.tx.balances
* // create transfer
* transfer(keyring.bob.address, 12345)
* // sign the transcation
* .sign(keyring.alice, { nonce })
* // send the transaction (optional status callback)
* .send((status) => {
* console.log(`current status ${status.type}`);
* })
* // retrieve the submitted extrinsic hash
* .then((hash) => {
* console.log(`submitted with hash ${hash}`);
* });
* });
* ```
*/
export class ApiPromise extends ApiBase<'promise'> {
#isReadyPromise: Promise<ApiPromise>;
#isReadyOrErrorPromise: Promise<ApiPromise>;
/**
* @description Creates an instance of the ApiPromise class
* @param options Options to create an instance. This can be either [[ApiOptions]] or
* an [[WsProvider]].
* @example
* <BR>
*
* ```javascript
* import Api from '@polkadot/api/promise';
*
* new Api().isReady.then((api) => {
* api.rpc.subscribeNewHeads((header) => {
* console.log(`new block #${header.number.toNumber()}`);
* });
* });
* ```
*/
constructor (options?: ApiOptions) {
super(options, 'promise', toPromiseMethod);
this.#isReadyPromise = new Promise((resolve): void => {
super.once('ready', () => resolve(this));
});
this.#isReadyOrErrorPromise = new Promise((resolve, reject): void => {
const tracker = promiseTracker(resolve, reject);
super.once('ready', () => tracker.resolve(this));
super.once('error', (error: Error) => tracker.reject(error));
});
}
/**
* @description Creates an ApiPromise instance using the supplied provider. Returns an Promise containing the actual Api instance.
* @param options options that is passed to the class contructor. Can be either [[ApiOptions]] or a
* provider (see the constructor arguments)
* @example
* <BR>
*
* ```javascript
* import Api from '@polkadot/api/promise';
*
* Api.create().then(async (api) => {
* const timestamp = await api.query.timestamp.now();
*
* console.log(`lastest block timestamp ${timestamp}`);
* });
* ```
*/
public static create (options?: ApiOptions): Promise<ApiPromise> {
const instance = new ApiPromise(options);
if (options && options.throwOnConnect) {
return instance.isReadyOrError;
}
// Swallow any rejections on isReadyOrError
// (in Node 15.x this creates issues, when not being looked at)
instance.isReadyOrError.catch(() => {
// ignore
});
return instance.isReady;
}
/**
* @description Promise that resolves the first time we are connected and loaded
*/
public get isReady (): Promise<ApiPromise> {
return this.#isReadyPromise;
}
/**
* @description Promise that resolves if we can connect, or reject if there is an error
*/
public get isReadyOrError (): Promise<ApiPromise> {
return this.#isReadyOrErrorPromise;
}
/**
* @description Returns a clone of this ApiPromise instance (new underlying provider connection)
*/
public clone (): ApiPromise {
return new ApiPromise(
objectSpread({}, this._options, { source: this })
);
}
/**
* @description Creates a combinator that can be used to combine the latest results from multiple subscriptions
* @param fns An array of function to combine, each in the form of `(cb: (value: void)) => void`
* @param callback A callback that will return an Array of all the values this combinator has been applied to
* @example
* <BR>
*
* ```javascript
* const address = '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFacT7';
*
* // combines values from balance & nonce as it updates
* api.combineLatest([
* api.rpc.chain.subscribeNewHeads,
* (cb) => api.query.system.account(address, cb)
* ], ([head, [balance, nonce]]) => {
* console.log(`#${head.number}: You have ${balance.free} units, with ${nonce} transactions sent`);
* });
* ```
*/
// eslint-disable-next-line @typescript-eslint/require-await
public async combineLatest <T extends any[] = any[]> (fns: (CombinatorFunction | [CombinatorFunction, ...any[]])[], callback: CombinatorCallback<T>): UnsubscribePromise {
const combinator = new Combinator(fns, callback);
return (): void => {
combinator.unsubscribe();
};
}
}
+108
View File
@@ -0,0 +1,108 @@
// Copyright 2017-2021 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Observable } from 'rxjs';
import type { Callback, Codec } from '@polkadot/types/types';
import type { DecorateFn, DecorateMethodOptions, ObsInnerType, StorageEntryPromiseOverloads, UnsubscribePromise, VoidFn } from '../types';
import { catchError, EMPTY, Subscription, tap } from 'rxjs';
import { assert, isFunction } from '@polkadot/util';
interface Tracker<T> {
reject: (value: Error) => Observable<never>;
resolve: (value: T) => void;
}
// a Promise completion tracker, wrapping an isComplete variable that ensures the promise only resolves once
export function promiseTracker<T> (resolve: (value: T) => void, reject: (value: Error) => void): Tracker<T> {
let isCompleted = false;
return {
reject: (error: Error): Observable<never> => {
if (!isCompleted) {
isCompleted = true;
reject(error);
}
return EMPTY;
},
resolve: (value: T): void => {
if (!isCompleted) {
isCompleted = true;
resolve(value);
}
}
};
}
// extract the arguments and callback params from a value array possibly containing a callback
function extractArgs (args: unknown[], needsCallback: boolean): [unknown[], Callback<Codec> | undefined] {
let callback: Callback<Codec> | undefined;
const actualArgs = args.slice();
// If the last arg is a function, we pop it, put it into callback.
// actualArgs will then hold the actual arguments to be passed to `method`
if (args.length && isFunction(args[args.length - 1])) {
callback = actualArgs.pop() as Callback<Codec>;
}
// When we need a subscription, ensure that a valid callback is actually passed
assert(!needsCallback || isFunction(callback), 'Expected a callback to be passed with subscriptions');
return [actualArgs, callback];
}
// Decorate a call for a single-shot result - retrieve and then immediate unsubscribe
function decorateCall<M extends DecorateFn<ObsInnerType<ReturnType<M>>>> (method: M, args: unknown[]): Promise<ObsInnerType<ReturnType<M>>> {
return new Promise((resolve, reject): void => {
// single result tracker - either reject with Error or resolve with Codec result
const tracker = promiseTracker(resolve, reject);
// encoding errors reject immediately, any result unsubscribes and resolves
const subscription: Subscription = method(...args)
.pipe(
catchError((error: Error) => tracker.reject(error))
)
.subscribe((result): void => {
tracker.resolve(result);
setTimeout(() => subscription.unsubscribe(), 0);
});
});
}
// Decorate a subscription where we have a result callback specified
function decorateSubscribe<M extends DecorateFn<ObsInnerType<ReturnType<M>>>> (method: M, args: unknown[], resultCb: Callback<Codec>): UnsubscribePromise {
return new Promise<VoidFn>((resolve, reject): void => {
// either reject with error or resolve with unsubscribe callback
const tracker = promiseTracker(resolve, reject);
// errors reject immediately, the first result resolves with an unsubscribe promise, all results via callback
const subscription: Subscription = method(...args)
.pipe(
catchError((error: Error) => tracker.reject(error)),
tap(() => tracker.resolve(() => subscription.unsubscribe()))
)
.subscribe((result): void => {
// queue result (back of queue to clear current)
setTimeout(() => resultCb(result) as void, 0);
});
});
}
/**
* @description Decorate method for ApiPromise, where the results are converted to the Promise equivalent
*/
export function toPromiseMethod<M extends DecorateFn<ObsInnerType<ReturnType<M>>>> (method: M, options?: DecorateMethodOptions): StorageEntryPromiseOverloads {
const needsCallback = !!(options && options.methodName && options.methodName.includes('subscribe'));
return function (...args: unknown[]): Promise<ObsInnerType<ReturnType<M>>> | UnsubscribePromise {
const [actualArgs, resultCb] = extractArgs(args, needsCallback);
return resultCb
? decorateSubscribe(method, actualArgs, resultCb)
: decorateCall((options?.overrideNoSub as M) || method, actualArgs);
} as StorageEntryPromiseOverloads;
}
+2 -309
View File
@@ -1,312 +1,5 @@
// Copyright 2017-2021 @polkadot/api authors & contributors // Copyright 2017-2021 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import type { Observable } from 'rxjs'; export { ApiPromise } from './Api';
import type { Callback, Codec } from '@polkadot/types/types'; export { toPromiseMethod } from './decorateMethod';
import type { ApiOptions, DecorateFn, DecorateMethodOptions, ObsInnerType, StorageEntryPromiseOverloads, UnsubscribePromise, VoidFn } from '../types';
import { catchError, EMPTY, Subscription, tap } from 'rxjs';
import { assert, isFunction, objectSpread } from '@polkadot/util';
import { ApiBase } from '../base';
import { Combinator, CombinatorCallback, CombinatorFunction } from './Combinator';
interface Tracker<T> {
reject: (value: Error) => Observable<never>;
resolve: (value: T) => void;
}
// extract the arguments and callback params from a value array possibly containing a callback
function extractArgs (args: unknown[], needsCallback: boolean): [unknown[], Callback<Codec> | undefined] {
let callback: Callback<Codec> | undefined;
const actualArgs = args.slice();
// If the last arg is a function, we pop it, put it into callback.
// actualArgs will then hold the actual arguments to be passed to `method`
if (args.length && isFunction(args[args.length - 1])) {
callback = actualArgs.pop() as Callback<Codec>;
}
// When we need a subscription, ensure that a valid callback is actually passed
assert(!needsCallback || isFunction(callback), 'Expected a callback to be passed with subscriptions');
return [actualArgs, callback];
}
// a Promise completion tracker, wrapping an isComplete variable that ensures the promise only resolves once
function promiseTracker<T> (resolve: (value: T) => void, reject: (value: Error) => void): Tracker<T> {
let isCompleted = false;
return {
reject: (error: Error): Observable<never> => {
if (!isCompleted) {
isCompleted = true;
reject(error);
}
return EMPTY;
},
resolve: (value: T): void => {
if (!isCompleted) {
isCompleted = true;
resolve(value);
}
}
};
}
// Decorate a call for a single-shot result - retrieve and then immediate unsubscribe
function decorateCall<Method extends DecorateFn<ObsInnerType<ReturnType<Method>>>> (method: Method, actualArgs: unknown[]): Promise<ObsInnerType<ReturnType<Method>>> {
return new Promise((resolve, reject): void => {
// single result tracker - either reject with Error or resolve with Codec result
const tracker = promiseTracker(resolve, reject);
// encoding errors reject immediately, any result unsubscribes and resolves
const subscription: Subscription = method(...actualArgs).pipe(
catchError((error: Error) => tracker.reject(error))
).subscribe((result): void => {
tracker.resolve(result);
setTimeout(() => subscription.unsubscribe(), 0);
});
});
}
// Decorate a subscription where we have a result callback specified
function decorateSubscribe<Method extends DecorateFn<ObsInnerType<ReturnType<Method>>>> (method: Method, actualArgs: unknown[], resultCb: Callback<Codec>): UnsubscribePromise {
return new Promise<VoidFn>((resolve, reject): void => {
// either reject with error or resolve with unsubscribe callback
const tracker = promiseTracker(resolve, reject);
// errors reject immediately, the first result resolves with an unsubscribe promise, all results via callback
const subscription: Subscription = method(...actualArgs).pipe(
catchError((error: Error) => tracker.reject(error)),
tap(() => tracker.resolve(() => subscription.unsubscribe()))
).subscribe((result): void => {
// queue result (back of queue to clear current)
setTimeout(() => resultCb(result) as void, 0);
});
});
}
/**
* @description Decorate method for ApiPromise, where the results are converted to the Promise equivalent
*/
export function decorateMethod<Method extends DecorateFn<ObsInnerType<ReturnType<Method>>>> (method: Method, options?: DecorateMethodOptions): StorageEntryPromiseOverloads {
const needsCallback = options && options.methodName && options.methodName.includes('subscribe');
return function (...args: unknown[]): Promise<ObsInnerType<ReturnType<Method>>> | UnsubscribePromise {
const [actualArgs, resultCb] = extractArgs(args, !!needsCallback);
return resultCb
? decorateSubscribe(method, actualArgs, resultCb)
: decorateCall((options?.overrideNoSub as Method) || method, actualArgs);
} as StorageEntryPromiseOverloads;
}
/**
* # @polkadot/api/promise
*
* ## Overview
*
* @name ApiPromise
* @description
* ApiPromise is a standard JavaScript wrapper around the RPC and interfaces on the Polkadot network. As a full Promise-based, all interface calls return Promises, including the static `.create(...)`. Subscription calls utilise `(value) => {}` callbacks to pass through the latest values.
*
* The API is well suited to real-time applications where either the single-shot state is needed or use is to be made of the subscription-based features of Polkadot (and Substrate) clients.
*
* @see [[ApiRx]]
*
* ## Usage
*
* Making rpc calls -
* <BR>
*
* ```javascript
* import ApiPromise from '@polkadot/api/promise';
*
* // initialise via static create
* const api = await ApiPromise.create();
*
* // make a subscription to the network head
* api.rpc.chain.subscribeNewHeads((header) => {
* console.log(`Chain is at #${header.number}`);
* });
* ```
* <BR>
*
* Subscribing to chain state -
* <BR>
*
* ```javascript
* import { ApiPromise, WsProvider } from '@polkadot/api';
*
* // initialise a provider with a specific endpoint
* const provider = new WsProvider('wss://example.com:9944')
*
* // initialise via isReady & new with specific provider
* const api = await new ApiPromise({ provider }).isReady;
*
* // retrieve the block target time
* const blockPeriod = await api.query.timestamp.blockPeriod().toNumber();
* let last = 0;
*
* // subscribe to the current block timestamp, updates automatically (callback provided)
* api.query.timestamp.now((timestamp) => {
* const elapsed = last
* ? `, ${timestamp.toNumber() - last}s since last`
* : '';
*
* last = timestamp.toNumber();
* console.log(`timestamp ${timestamp}${elapsed} (${blockPeriod}s target)`);
* });
* ```
* <BR>
*
* Submitting a transaction -
* <BR>
*
* ```javascript
* import ApiPromise from '@polkadot/api/promise';
*
* ApiPromise.create().then((api) => {
* const [nonce] = await api.query.system.account(keyring.alice.address);
*
* api.tx.balances
* // create transfer
* transfer(keyring.bob.address, 12345)
* // sign the transcation
* .sign(keyring.alice, { nonce })
* // send the transaction (optional status callback)
* .send((status) => {
* console.log(`current status ${status.type}`);
* })
* // retrieve the submitted extrinsic hash
* .then((hash) => {
* console.log(`submitted with hash ${hash}`);
* });
* });
* ```
*/
export class ApiPromise extends ApiBase<'promise'> {
#isReadyPromise: Promise<ApiPromise>;
#isReadyOrErrorPromise: Promise<ApiPromise>;
/**
* @description Creates an ApiPromise instance using the supplied provider. Returns an Promise containing the actual Api instance.
* @param options options that is passed to the class contructor. Can be either [[ApiOptions]] or a
* provider (see the constructor arguments)
* @example
* <BR>
*
* ```javascript
* import Api from '@polkadot/api/promise';
*
* Api.create().then(async (api) => {
* const timestamp = await api.query.timestamp.now();
*
* console.log(`lastest block timestamp ${timestamp}`);
* });
* ```
*/
public static create (options?: ApiOptions): Promise<ApiPromise> {
const instance = new ApiPromise(options);
if (options && options.throwOnConnect) {
return instance.isReadyOrError;
}
// Swallow any rejections on isReadyOrError
// (in Node 15.x this creates issues, when not being looked at)
instance.isReadyOrError.catch(() => {
// ignore
});
return instance.isReady;
}
/**
* @description Creates an instance of the ApiPromise class
* @param options Options to create an instance. This can be either [[ApiOptions]] or
* an [[WsProvider]].
* @example
* <BR>
*
* ```javascript
* import Api from '@polkadot/api/promise';
*
* new Api().isReady.then((api) => {
* api.rpc.subscribeNewHeads((header) => {
* console.log(`new block #${header.number.toNumber()}`);
* });
* });
* ```
*/
constructor (options?: ApiOptions) {
super(options, 'promise', decorateMethod);
this.#isReadyPromise = new Promise((resolve): void => {
super.once('ready', () => resolve(this));
});
this.#isReadyOrErrorPromise = new Promise((resolve, reject): void => {
const tracker = promiseTracker(resolve, reject);
super.once('ready', () => tracker.resolve(this));
super.once('error', (error: Error) => tracker.reject(error));
});
}
/**
* @description Promise that resolves the first time we are connected and loaded
*/
public get isReady (): Promise<ApiPromise> {
return this.#isReadyPromise;
}
/**
* @description Promise that resolves if we can connect, or reject if there is an error
*/
public get isReadyOrError (): Promise<ApiPromise> {
return this.#isReadyOrErrorPromise;
}
/**
* @description Returns a clone of this ApiPromise instance (new underlying provider connection)
*/
public clone (): ApiPromise {
return new ApiPromise(
objectSpread({}, this._options, { source: this })
);
}
/**
* @description Creates a combinator that can be used to combine the latest results from multiple subscriptions
* @param fns An array of function to combine, each in the form of `(cb: (value: void)) => void`
* @param callback A callback that will return an Array of all the values this combinator has been applied to
* @example
* <BR>
*
* ```javascript
* const address = '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFacT7';
*
* // combines values from balance & nonce as it updates
* api.combineLatest([
* api.rpc.chain.subscribeNewHeads,
* (cb) => api.query.system.account(address, cb)
* ], ([head, [balance, nonce]]) => {
* console.log(`#${head.number}: You have ${balance.free} units, with ${nonce} transactions sent`);
* });
* ```
*/
// eslint-disable-next-line @typescript-eslint/require-await
public async combineLatest <T extends any[] = any[]> (fns: (CombinatorFunction | [CombinatorFunction, ...any[]])[], callback: CombinatorCallback<T>): UnsubscribePromise {
const combinator = new Combinator(fns, callback);
return (): void => {
combinator.unsubscribe();
};
}
}
+185
View File
@@ -0,0 +1,185 @@
// Copyright 2017-2021 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiOptions } from '../types';
import { from, Observable } from 'rxjs';
import { objectSpread } from '@polkadot/util';
import { ApiBase } from '../base';
import { toRxMethod } from './decorateMethod';
/**
* # @polkadot/api/rx
*
* ## Overview
*
* @name ApiRx
*
* @description
* ApiRx is a powerful RxJS Observable wrapper around the RPC and interfaces on the Polkadot network. As a full Observable API, all interface calls return RxJS Observables, including the static `.create(...)`. In the same fashion and subscription-based methods return long-running Observables that update with the latest values.
*
* The API is well suited to real-time applications where the latest state is needed, unlocking the subscription-based features of Polkadot (and Substrate) clients. Some familiarity with RxJS is a requirement to use the API, however just understanding `.subscribe` and `.pipe` on Observables will unlock full-scale use thereof.
*
* @see [[ApiPromise]]
*
* ## Usage
*
* Making rpc calls -
* <BR>
*
* ```javascript
* import ApiRx from '@polkadot/api/rx';
*
* // initialize via Promise & static create
* const api = await ApiRx.create().toPromise();
*
* // make a call to retrieve the current network head
* api.rpc.chain.subscribeNewHeads().subscribe((header) => {
* console.log(`Chain is at #${header.number}`);
* });
* ```
* <BR>
*
* Subscribing to chain state -
* <BR>
*
* ```javascript
* import { combineLatest, pairwise, switchMap } from 'rxjs';
* import { ApiRx, WsProvider } from '@polkadot/api';
*
*
* // initialize a provider with a specific endpoint
* const provider = new WsProvider('wss://example.com:9944')
*
* // initialize via isReady & new with specific provider
* new ApiRx({ provider })
* .isReady
* .pipe(
* switchMap((api) =>
* combineLatest([
* api.query.timestamp.blockPeriod(),
* api.query.timestamp.now().pipe(pairwise())
* ])
* )
* )
* .subscribe(([blockPeriod, timestamp]) => {
* const elapsed = timestamp[1].toNumber() - timestamp[0].toNumber();
* console.log(`timestamp ${timestamp[1]} \nelapsed ${elapsed} \n(${blockPeriod}s target)`);
* });
* ```
* <BR>
*
* Submitting a transaction -
* <BR>
*
* ```javascript
* import { first, switchMap } from 'rxjs';
* import ApiRx from '@polkadot/api/rx';
*
* // import the test keyring (already has dev keys for Alice, Bob, Charlie, Eve & Ferdie)
* import testingPairs from '@polkadot/keyring/testingPairs';
* const keyring = testingPairs();
*
* // get api via Promise
* const api = await ApiRx.create().toPromise();
*
* // retrieve nonce for the account
* api.query.system
* .account(keyring.alice.address)
* .pipe(
* first(),
* // pipe nonce into transfer
* switchMap(([nonce]) =>
* api.tx.balances
* // create transfer
* .transfer(keyring.bob.address, 12345)
* // sign the transaction
* .sign(keyring.alice, { nonce })
* // send the transaction
* .send()
* )
* )
* // subscribe to overall result
* .subscribe(({ status }) => {
* if (status.isInBlock) {
* console.log('Completed at block hash', status.asFinalized.toHex());
* }
* });
* ```
*/
export class ApiRx extends ApiBase<'rxjs'> {
#isReadyRx: Observable<ApiRx>;
/**
* @description Create an instance of the ApiRx class
* @param options Options to create an instance. Can be either [[ApiOptions]] or [[WsProvider]]
* @example
* <BR>
*
* ```javascript
* import { switchMap } from 'rxjs';
* import Api from '@polkadot/api/rx';
*
* new Api().isReady
* .pipe(
* switchMap((api) =>
* api.rpc.chain.subscribeNewHeads()
* ))
* .subscribe((header) => {
* console.log(`new block #${header.number.toNumber()}`);
* });
* ```
*/
constructor (options?: ApiOptions) {
super(options, 'rxjs', toRxMethod);
this.#isReadyRx = from<Promise<ApiRx>>(
// You can create an observable from an event, however my mind groks this form better
new Promise((resolve): void => {
super.on('ready', () => resolve(this));
})
);
}
/**
* @description Creates an ApiRx instance using the supplied provider. Returns an Observable containing the actual Api instance.
* @param options options that is passed to the class constructor. Can be either [[ApiOptions]] or [[WsProvider]]
* @example
* <BR>
*
* ```javascript
* import { switchMap } from 'rxjs';
* import Api from '@polkadot/api/rx';
*
* Api.create()
* .pipe(
* switchMap((api) =>
* api.rpc.chain.subscribeNewHeads()
* ))
* .subscribe((header) => {
* console.log(`new block #${header.number.toNumber()}`);
* });
* ```
*/
public static create (options?: ApiOptions): Observable<ApiRx> {
return new ApiRx(options).isReady;
}
/**
* @description Observable that returns the first time we are connected and loaded
*/
public get isReady (): Observable<ApiRx> {
return this.#isReadyRx;
}
/**
* @description Returns a clone of this ApiRx instance (new underlying provider connection)
*/
public clone (): ApiRx {
return new ApiRx(
objectSpread({}, this._options, { source: this })
);
}
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2017-2021 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Codec } from '@polkadot/types/types';
import type { DecorateFn } from '../types';
export function toRxMethod <M extends DecorateFn<Codec>> (method: M): M {
return method;
}
+2 -186
View File
@@ -1,189 +1,5 @@
// Copyright 2017-2021 @polkadot/api authors & contributors // Copyright 2017-2021 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import type { Codec } from '@polkadot/types/types'; export { ApiRx } from './Api';
import type { ApiOptions, DecorateFn } from '../types'; export { toRxMethod } from './decorateMethod';
import { from, Observable } from 'rxjs';
import { objectSpread } from '@polkadot/util';
import { ApiBase } from '../base';
export function decorateMethod <Method extends DecorateFn<Codec>> (method: Method): Method {
return method;
}
/**
* # @polkadot/api/rx
*
* ## Overview
*
* @name ApiRx
*
* @description
* ApiRx is a powerful RxJS Observable wrapper around the RPC and interfaces on the Polkadot network. As a full Observable API, all interface calls return RxJS Observables, including the static `.create(...)`. In the same fashion and subscription-based methods return long-running Observables that update with the latest values.
*
* The API is well suited to real-time applications where the latest state is needed, unlocking the subscription-based features of Polkadot (and Substrate) clients. Some familiarity with RxJS is a requirement to use the API, however just understanding `.subscribe` and `.pipe` on Observables will unlock full-scale use thereof.
*
* @see [[ApiPromise]]
*
* ## Usage
*
* Making rpc calls -
* <BR>
*
* ```javascript
* import ApiRx from '@polkadot/api/rx';
*
* // initialize via Promise & static create
* const api = await ApiRx.create().toPromise();
*
* // make a call to retrieve the current network head
* api.rpc.chain.subscribeNewHeads().subscribe((header) => {
* console.log(`Chain is at #${header.number}`);
* });
* ```
* <BR>
*
* Subscribing to chain state -
* <BR>
*
* ```javascript
* import { combineLatest, pairwise, switchMap } from 'rxjs';
* import { ApiRx, WsProvider } from '@polkadot/api';
*
*
* // initialize a provider with a specific endpoint
* const provider = new WsProvider('wss://example.com:9944')
*
* // initialize via isReady & new with specific provider
* new ApiRx({ provider })
* .isReady
* .pipe(
* switchMap((api) =>
* combineLatest([
* api.query.timestamp.blockPeriod(),
* api.query.timestamp.now().pipe(pairwise())
* ])
* )
* )
* .subscribe(([blockPeriod, timestamp]) => {
* const elapsed = timestamp[1].toNumber() - timestamp[0].toNumber();
* console.log(`timestamp ${timestamp[1]} \nelapsed ${elapsed} \n(${blockPeriod}s target)`);
* });
* ```
* <BR>
*
* Submitting a transaction -
* <BR>
*
* ```javascript
* import { first, switchMap } from 'rxjs';
* import ApiRx from '@polkadot/api/rx';
*
* // import the test keyring (already has dev keys for Alice, Bob, Charlie, Eve & Ferdie)
* import testingPairs from '@polkadot/keyring/testingPairs';
* const keyring = testingPairs();
*
* // get api via Promise
* const api = await ApiRx.create().toPromise();
*
* // retrieve nonce for the account
* api.query.system
* .account(keyring.alice.address)
* .pipe(
* first(),
* // pipe nonce into transfer
* switchMap(([nonce]) =>
* api.tx.balances
* // create transfer
* .transfer(keyring.bob.address, 12345)
* // sign the transaction
* .sign(keyring.alice, { nonce })
* // send the transaction
* .send()
* )
* )
* // subscribe to overall result
* .subscribe(({ status }) => {
* if (status.isInBlock) {
* console.log('Completed at block hash', status.asFinalized.toHex());
* }
* });
* ```
*/
export class ApiRx extends ApiBase<'rxjs'> {
#isReadyRx: Observable<ApiRx>;
/**
* @description Creates an ApiRx instance using the supplied provider. Returns an Observable containing the actual Api instance.
* @param options options that is passed to the class constructor. Can be either [[ApiOptions]] or [[WsProvider]]
* @example
* <BR>
*
* ```javascript
* import { switchMap } from 'rxjs';
* import Api from '@polkadot/api/rx';
*
* Api.create()
* .pipe(
* switchMap((api) =>
* api.rpc.chain.subscribeNewHeads()
* ))
* .subscribe((header) => {
* console.log(`new block #${header.number.toNumber()}`);
* });
* ```
*/
public static create (options?: ApiOptions): Observable<ApiRx> {
return new ApiRx(options).isReady;
}
/**
* @description Create an instance of the ApiRx class
* @param options Options to create an instance. Can be either [[ApiOptions]] or [[WsProvider]]
* @example
* <BR>
*
* ```javascript
* import { switchMap } from 'rxjs';
* import Api from '@polkadot/api/rx';
*
* new Api().isReady
* .pipe(
* switchMap((api) =>
* api.rpc.chain.subscribeNewHeads()
* ))
* .subscribe((header) => {
* console.log(`new block #${header.number.toNumber()}`);
* });
* ```
*/
constructor (options?: ApiOptions) {
super(options, 'rxjs', decorateMethod);
this.#isReadyRx = from<Promise<ApiRx>>(
// You can create an observable from an event, however my mind groks this form better
new Promise((resolve): void => {
super.on('ready', () => resolve(this));
})
);
}
/**
* @description Observable that returns the first time we are connected and loaded
*/
public get isReady (): Observable<ApiRx> {
return this.#isReadyRx;
}
/**
* @description Returns a clone of this ApiRx instance (new underlying provider connection)
*/
public clone (): ApiRx {
return new ApiRx(
objectSpread({}, this._options, { source: this })
);
}
}
+1 -1
View File
@@ -95,7 +95,7 @@ export interface ApiInterfaceRx {
runtimeMetadata: Metadata; runtimeMetadata: Metadata;
runtimeVersion: RuntimeVersion; runtimeVersion: RuntimeVersion;
query: QueryableStorage<'rxjs'>; query: QueryableStorage<'rxjs'>;
queryAt: (blockHash: Uint8Array | string) => Observable<QueryableStorage<'rxjs'>>; queryAt: (blockHash: Uint8Array | string, knownVersion?: RuntimeVersion) => Observable<QueryableStorage<'rxjs'>>;
queryMulti: QueryableStorageMulti<'rxjs'>; queryMulti: QueryableStorageMulti<'rxjs'>;
rpc: DecoratedRpc<'rxjs', RpcInterface>; rpc: DecoratedRpc<'rxjs', RpcInterface>;
tx: SubmittableExtrinsics<'rxjs'>; tx: SubmittableExtrinsics<'rxjs'>;
+3 -3
View File
@@ -20,12 +20,12 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/rpc-provider": "6.7.2", "@polkadot/rpc-provider": "6.8.1",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/util": "^7.8.2", "@polkadot/util": "^7.8.2",
"rxjs": "^7.4.0" "rxjs": "^7.4.0"
}, },
+1 -1
View File
@@ -204,7 +204,7 @@ export class RpcCore {
? await this.#getBlockRegistry(u8aToU8a(blockHash)) ? await this.#getBlockRegistry(u8aToU8a(blockHash))
: { registry: this.#registryDefault }; : { registry: this.#registryDefault };
const params = this._formatInputs(registry, null, def, values); const params = this._formatInputs(registry, null, def, values);
const result = await this.provider.send<AnyJson>(rpcName, params.map((p) => p.toJSON())); const result = await this.provider.send<AnyJson>(rpcName, params.map((p) => p.toJSON()), !!blockHash);
return this._formatResult(isScale, registry, blockHash, method, def, params, result); return this._formatResult(isScale, registry, blockHash, method, def, params, result);
}; };
+1 -1
View File
@@ -62,7 +62,7 @@ describe('methodSend', (): void => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
method(new Uint8Array([2 << 2, 0x12, 0x34])).subscribe((): void => { method(new Uint8Array([2 << 2, 0x12, 0x34])).subscribe((): void => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect(provider.send).toHaveBeenCalledWith('test_blah', ['0x1234']); expect(provider.send).toHaveBeenCalledWith('test_blah', ['0x1234'], false);
done(); done();
}); });
}); });
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/rpc-core', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/rpc-core', version: '6.8.1' };
+3 -3
View File
@@ -20,11 +20,11 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/util": "^7.8.2", "@polkadot/util": "^7.8.2",
"@polkadot/util-crypto": "^7.8.2", "@polkadot/util-crypto": "^7.8.2",
"@polkadot/x-fetch": "^7.8.2", "@polkadot/x-fetch": "^7.8.2",
@@ -34,7 +34,7 @@
}, },
"devDependencies": { "devDependencies": {
"@polkadot/keyring": "^7.8.2", "@polkadot/keyring": "^7.8.2",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"mock-socket": "^9.0.7", "mock-socket": "^9.0.7",
"nock": "^13.1.4" "nock": "^13.1.4"
} }
+20 -1
View File
@@ -8,6 +8,7 @@ import { fetch } from '@polkadot/x-fetch';
import { RpcCoder } from '../coder'; import { RpcCoder } from '../coder';
import defaults from '../defaults'; import defaults from '../defaults';
import { LRUCache } from '../lru';
const ERROR_SUBSCRIBE = 'HTTP Provider does not have subscriptions, use WebSockets instead'; const ERROR_SUBSCRIBE = 'HTTP Provider does not have subscriptions, use WebSockets instead';
@@ -34,6 +35,8 @@ const l = logger('api-http');
* @see [[WsProvider]] * @see [[WsProvider]]
*/ */
export class HttpProvider implements ProviderInterface { export class HttpProvider implements ProviderInterface {
readonly #callCache = new LRUCache();
readonly #coder: RpcCoder; readonly #coder: RpcCoder;
readonly #endpoint: string; readonly #endpoint: string;
@@ -103,8 +106,24 @@ export class HttpProvider implements ProviderInterface {
/** /**
* @summary Send HTTP POST Request with Body to configured HTTP Endpoint. * @summary Send HTTP POST Request with Body to configured HTTP Endpoint.
*/ */
public async send <T> (method: string, params: unknown[]): Promise<T> { public async send <T> (method: string, params: unknown[], isCacheable?: boolean): Promise<T> {
const body = this.#coder.encodeJson(method, params); const body = this.#coder.encodeJson(method, params);
let resultPromise: Promise<T> | null = isCacheable
? this.#callCache.get(body) as Promise<T>
: null;
if (!resultPromise) {
resultPromise = this.#send(body);
if (isCacheable) {
this.#callCache.set(body, resultPromise);
}
}
return resultPromise;
}
async #send <T> (body: string): Promise<T> {
const response = await fetch(this.#endpoint, { const response = await fetch(this.#endpoint, {
body, body,
headers: { headers: {
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2017-2021 @polkadot/rpc-provider authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { LRUCache } from './lru';
describe('LRUCache', (): void => {
it('allows getting of items below capacity', (): void => {
const keys = ['1', '2', '3', '4'];
const lru = new LRUCache(4);
keys.forEach((k) => lru.set(k, `${k}${k}${k}`));
expect(lru.keys().join(', ')).toEqual(keys.reverse().join(', '));
expect(lru.length === lru.lengthData && lru.length === lru.lengthRefs).toBe(true);
keys.forEach((k) => expect(lru.get(k)).toEqual(`${k}${k}${k}`));
});
it('drops items when at capacity', (): void => {
const keys = ['1', '2', '3', '4', '5', '6'];
const lru = new LRUCache(4);
keys.forEach((k) => lru.set(k, `${k}${k}${k}`));
expect(lru.keys().join(', ')).toEqual(keys.slice(2).reverse().join(', '));
expect(lru.length === lru.lengthData && lru.length === lru.lengthRefs).toBe(true);
keys.slice(2).forEach((k) => expect(lru.get(k)).toEqual(`${k}${k}${k}`));
});
it('adjusts the order as they are used', (): void => {
const keys = ['1', '2', '3', '4', '5'];
const lru = new LRUCache(4);
keys.forEach((k) => lru.set(k, `${k}${k}${k}`));
expect(lru.entries()).toEqual([['5', '555'], ['4', '444'], ['3', '333'], ['2', '222']]);
expect(lru.length === lru.lengthData && lru.length === lru.lengthRefs).toBe(true);
lru.get('3');
expect(lru.entries()).toEqual([['3', '333'], ['5', '555'], ['4', '444'], ['2', '222']]);
expect(lru.length === lru.lengthData && lru.length === lru.lengthRefs).toBe(true);
lru.set('4', '4433');
expect(lru.entries()).toEqual([['4', '4433'], ['3', '333'], ['5', '555'], ['2', '222']]);
expect(lru.length === lru.lengthData && lru.length === lru.lengthRefs).toBe(true);
lru.set('6', '666');
expect(lru.entries()).toEqual([['6', '666'], ['4', '4433'], ['3', '333'], ['5', '555']]);
expect(lru.length === lru.lengthData && lru.length === lru.lengthRefs).toBe(true);
});
});
+128
View File
@@ -0,0 +1,128 @@
// Copyright 2017-2021 @polkadot/rpc-provider authors & contributors
// SPDX-License-Identifier: Apache-2.0
const DEFAULT_CAPACITY = 2048;
class LRUNode {
public readonly key: string;
public next: LRUNode;
public prev: LRUNode;
constructor (key: string) {
this.key = key;
this.next = this.prev = this;
}
}
// https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU
export class LRUCache {
readonly capacity: number;
readonly #data: Map<string, unknown> = new Map();
readonly #refs: Map<string, LRUNode> = new Map();
#length = 0;
#head: LRUNode;
#tail: LRUNode;
constructor (capacity = DEFAULT_CAPACITY) {
this.capacity = capacity;
this.#head = this.#tail = new LRUNode('<empty>');
}
get length (): number {
return this.#length;
}
get lengthData (): number {
return this.#data.size;
}
get lengthRefs (): number {
return this.#refs.size;
}
entries (): [string, unknown][] {
const keys = this.keys();
const entries = new Array<[string, unknown]>(keys.length);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
entries[i] = [key, this.#data.get(key)];
}
return entries;
}
keys (): string[] {
const keys: string[] = [];
if (this.#length) {
let curr = this.#head;
while (curr !== this.#tail) {
keys.push(curr.key);
curr = curr.next;
}
keys.push(curr.key);
}
return keys;
}
get <T> (key: string): T | null {
const data = this.#data.get(key);
if (data) {
this.#toHead(key);
return data as T;
}
return null;
}
set <T> (key: string, value: T): void {
if (this.#data.has(key)) {
this.#toHead(key);
} else {
const node = new LRUNode(key);
this.#refs.set(node.key, node);
if (this.length === 0) {
this.#head = this.#tail = node;
} else {
this.#head.prev = node;
node.next = this.#head;
this.#head = node;
}
if (this.#length === this.capacity) {
this.#data.delete(this.#tail.key);
this.#refs.delete(this.#tail.key);
this.#tail = this.#tail.prev;
} else {
this.#length += 1;
}
}
this.#data.set(key, value);
}
#toHead (key: string): void {
const ref = this.#refs.get(key);
if (ref && ref !== this.#head) {
ref.prev.next = ref.next;
ref.next.prev = ref.prev;
ref.next = this.#head;
this.#head.prev = ref;
this.#head = ref;
}
}
}
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/rpc-provider', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/rpc-provider', version: '6.8.1' };
+1 -1
View File
@@ -49,7 +49,7 @@ export interface ProviderInterface {
connect (): Promise<void>; connect (): Promise<void>;
disconnect (): Promise<void>; disconnect (): Promise<void>;
on (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb): () => void; on (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb): () => void;
send <T = any> (method: string, params: unknown[]): Promise<T>; send <T = any> (method: string, params: unknown[], isCacheable?: boolean): Promise<T>;
subscribe (type: string, method: string, params: unknown[], cb: ProviderInterfaceCallback): Promise<number | string>; subscribe (type: string, method: string, params: unknown[], cb: ProviderInterfaceCallback): Promise<number | string>;
unsubscribe (type: string, method: string, id: number | string): Promise<boolean>; unsubscribe (type: string, method: string, id: number | string): Promise<boolean>;
} }
+25 -7
View File
@@ -7,12 +7,13 @@ import type { JsonRpcResponse, ProviderInterface, ProviderInterfaceCallback, Pro
import EventEmitter from 'eventemitter3'; import EventEmitter from 'eventemitter3';
import { assert, isChildClass, isNull, isUndefined, logger } from '@polkadot/util'; import { assert, isChildClass, isNull, isUndefined, logger, objectSpread } from '@polkadot/util';
import { xglobal } from '@polkadot/x-global'; import { xglobal } from '@polkadot/x-global';
import { WebSocket } from '@polkadot/x-ws'; import { WebSocket } from '@polkadot/x-ws';
import { RpcCoder } from '../coder'; import { RpcCoder } from '../coder';
import defaults from '../defaults'; import defaults from '../defaults';
import { LRUCache } from '../lru';
import { getWSErrorString } from './errors'; import { getWSErrorString } from './errors';
interface SubscriptionHandler { interface SubscriptionHandler {
@@ -75,6 +76,8 @@ function eraseRecord<T> (record: Record<string, T>, cb?: (item: T) => void): voi
* @see [[HttpProvider]] * @see [[HttpProvider]]
*/ */
export class WsProvider implements ProviderInterface { export class WsProvider implements ProviderInterface {
readonly #callCache = new LRUCache();
readonly #coder: RpcCoder; readonly #coder: RpcCoder;
readonly #endpoints: string[]; readonly #endpoints: string[];
@@ -260,12 +263,28 @@ export class WsProvider implements ProviderInterface {
* @param params Encoded parameters as applicable for the method * @param params Encoded parameters as applicable for the method
* @param subscription Subscription details (internally used) * @param subscription Subscription details (internally used)
*/ */
public send <T = any> (method: string, params: unknown[], subscription?: SubscriptionHandler): Promise<T> { public send <T = any> (method: string, params: unknown[], isCacheable?: boolean, subscription?: SubscriptionHandler): Promise<T> {
const body = this.#coder.encodeJson(method, params);
let resultPromise: Promise<T> | null = isCacheable
? this.#callCache.get(body) as Promise<T>
: null;
if (!resultPromise) {
resultPromise = this.#send(body, method, params, subscription);
if (isCacheable) {
this.#callCache.set(body, resultPromise);
}
}
return resultPromise;
}
async #send <T> (json: string, method: string, params: unknown[], subscription?: SubscriptionHandler): Promise<T> {
return new Promise<T>((resolve, reject): void => { return new Promise<T>((resolve, reject): void => {
try { try {
assert(this.isConnected && !isNull(this.#websocket), 'WebSocket is not connected'); assert(this.isConnected && !isNull(this.#websocket), 'WebSocket is not connected');
const json = this.#coder.encodeJson(method, params);
const id = this.#coder.getId(); const id = this.#coder.getId();
const callback = (error?: Error | null, result?: T): void => { const callback = (error?: Error | null, result?: T): void => {
@@ -309,7 +328,7 @@ export class WsProvider implements ProviderInterface {
* ``` * ```
*/ */
public subscribe (type: string, method: string, params: unknown[], callback: ProviderInterfaceCallback): Promise<number | string> { public subscribe (type: string, method: string, params: unknown[], callback: ProviderInterfaceCallback): Promise<number | string> {
return this.send<number | string>(method, params, { callback, type }); return this.send<number | string>(method, params, false, { callback, type });
} }
/** /**
@@ -410,11 +429,10 @@ export class WsProvider implements ProviderInterface {
if (subscription) { if (subscription) {
const subId = `${subscription.type}::${result}`; const subId = `${subscription.type}::${result}`;
this.#subscriptions[subId] = { this.#subscriptions[subId] = objectSpread({}, subscription, {
...subscription,
method, method,
params params
}; });
// if we have a result waiting for this subscription already // if we have a result waiting for this subscription already
if (this.#waitingForId[subId]) { if (this.#waitingForId[subId]) {
+5 -5
View File
@@ -20,7 +20,7 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"bin": { "bin": {
"polkadot-types-chain-info": "./scripts/polkadot-types-chain-info.cjs", "polkadot-types-chain-info": "./scripts/polkadot-types-chain-info.cjs",
@@ -33,10 +33,10 @@
"@babel/core": "^7.16.0", "@babel/core": "^7.16.0",
"@babel/register": "^7.16.0", "@babel/register": "^7.16.0",
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/api": "6.7.2", "@polkadot/api": "6.8.1",
"@polkadot/rpc-provider": "6.7.2", "@polkadot/rpc-provider": "6.8.1",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/types-support": "6.7.2", "@polkadot/types-support": "6.8.1",
"@polkadot/util": "^7.8.2", "@polkadot/util": "^7.8.2",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",
"websocket": "^1.0.34", "websocket": "^1.0.34",
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/typegen', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/typegen', version: '6.8.1' };
+2 -2
View File
@@ -20,12 +20,12 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
"@polkadot/networks": "^7.8.2", "@polkadot/networks": "^7.8.2",
"@polkadot/types": "6.7.2", "@polkadot/types": "6.8.1",
"@polkadot/util": "^7.8.2" "@polkadot/util": "^7.8.2"
} }
} }
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/types-known', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/types-known', version: '6.8.1' };
+1 -1
View File
@@ -185,7 +185,7 @@ const versioned: OverrideVersionedType[] = [
{ {
// metadata v14 // metadata v14
minmax: [9106, undefined], minmax: [9106, undefined],
types: objectSpread({}, sharedTypes) types: {}
} }
]; ];
+1 -1
View File
@@ -73,7 +73,7 @@ const versioned: OverrideVersionedType[] = [
{ {
// metadata v14 // metadata v14
minmax: [9110, undefined], minmax: [9110, undefined],
types: objectSpread({}, sharedTypes) types: {}
} }
]; ];
+1 -1
View File
@@ -49,7 +49,7 @@ const versioned: OverrideVersionedType[] = [
{ {
// metadata v14 // metadata v14
minmax: [9106, undefined], minmax: [9106, undefined],
types: objectSpread({}, sharedTypes) types: {}
} }
]; ];
+1 -1
View File
@@ -37,7 +37,7 @@ const versioned: OverrideVersionedType[] = [
{ {
// metadata V14 // metadata V14
minmax: [500, undefined], minmax: [500, undefined],
types: objectSpread({}, sharedTypes) types: {}
} }
]; ];
+1 -1
View File
@@ -91,7 +91,7 @@ const versioned: OverrideVersionedType[] = [
{ {
// metadata v14 // metadata v14
minmax: [9106, undefined], minmax: [9106, undefined],
types: objectSpread({}, sharedTypes) types: {}
} }
]; ];
@@ -9,7 +9,7 @@ const upgrades: ChainUpgradesRaw = [
[528470, 13], [687751, 14], [746085, 15], [787923, 16], [799302, 17], [528470, 13], [687751, 14], [746085, 15], [787923, 16], [799302, 17],
[1205128, 18], [1603423, 23], [1733218, 24], [2005673, 25], [2436698, 26], [1205128, 18], [1603423, 23], [1733218, 24], [2005673, 25], [2436698, 26],
[3613564, 27], [3899547, 28], [4345767, 29], [4876134, 30], [5661442, 9050], [3613564, 27], [3899547, 28], [4345767, 29], [4876134, 30], [5661442, 9050],
[6321619, 9080], [6713249, 9090], [7217907, 9100], [7229126, 9110] [6321619, 9080], [6713249, 9090], [7217907, 9100], [7229126, 9110], [7560558, 9122]
]; ];
export default upgrades; export default upgrades;
+1 -1
View File
@@ -20,7 +20,7 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/types-support', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/types-support', version: '6.8.1' };
+2 -2
View File
@@ -20,7 +20,7 @@
"./detectPackage.cjs" "./detectPackage.cjs"
], ],
"type": "module", "type": "module",
"version": "6.7.2", "version": "6.8.1",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.16.0", "@babel/runtime": "^7.16.0",
@@ -30,7 +30,7 @@
}, },
"devDependencies": { "devDependencies": {
"@polkadot/keyring": "^7.8.2", "@polkadot/keyring": "^7.8.2",
"@polkadot/types-support": "6.7.2", "@polkadot/types-support": "6.8.1",
"@types/bn.js": "^4.11.6", "@types/bn.js": "^4.11.6",
"bn.js": "^4.12.0" "bn.js": "^4.12.0"
} }
@@ -214,7 +214,7 @@ export default {
bitfields: 'Vec<PolkadotPrimitivesV1SignedUncheckedSigned>', bitfields: 'Vec<PolkadotPrimitivesV1SignedUncheckedSigned>',
backedCandidates: 'Vec<PolkadotPrimitivesV1BackedCandidate>', backedCandidates: 'Vec<PolkadotPrimitivesV1BackedCandidate>',
disputes: 'Vec<PolkadotPrimitivesV1DisputeStatementSet>', disputes: 'Vec<PolkadotPrimitivesV1DisputeStatementSet>',
parentHeader: 'SpRuntimeGenericHeader' parentHeader: 'SpRuntimeHeader'
}, },
/** /**
* Lookup325: polkadot_primitives::v1::signed::UncheckedSigned<polkadot_primitives::v1::AvailabilityBitfield, polkadot_primitives::v1::AvailabilityBitfield> * Lookup325: polkadot_primitives::v1::signed::UncheckedSigned<polkadot_primitives::v1::AvailabilityBitfield, polkadot_primitives::v1::AvailabilityBitfield>
@@ -36,13 +36,13 @@ export default {
/** /**
* Lookup11: sp_runtime::generic::digest::Digest<primitive_types::H256> * Lookup11: sp_runtime::generic::digest::Digest<primitive_types::H256>
**/ **/
SpRuntimeGenericDigest: { SpRuntimeDigest: {
logs: 'Vec<SpRuntimeGenericDigestDigestItem>' logs: 'Vec<SpRuntimeDigestDigestItem>'
}, },
/** /**
* Lookup13: sp_runtime::generic::digest::DigestItem<primitive_types::H256> * Lookup13: sp_runtime::generic::digest::DigestItem<primitive_types::H256>
**/ **/
SpRuntimeGenericDigestDigestItem: { SpRuntimeDigestDigestItem: {
_enum: { _enum: {
Other: 'Bytes', Other: 'Bytes',
__Unused1: 'Null', __Unused1: 'Null',
@@ -51,14 +51,14 @@ export default {
Consensus: '([u8;4],Bytes)', Consensus: '([u8;4],Bytes)',
Seal: '([u8;4],Bytes)', Seal: '([u8;4],Bytes)',
PreRuntime: '([u8;4],Bytes)', PreRuntime: '([u8;4],Bytes)',
ChangesTrieSignal: 'SpRuntimeGenericDigestChangesTrieSignal', ChangesTrieSignal: 'SpRuntimeDigestChangesTrieSignal',
RuntimeEnvironmentUpdated: 'Null' RuntimeEnvironmentUpdated: 'Null'
} }
}, },
/** /**
* Lookup15: sp_runtime::generic::digest::ChangesTrieSignal * Lookup15: sp_runtime::generic::digest::ChangesTrieSignal
**/ **/
SpRuntimeGenericDigestChangesTrieSignal: { SpRuntimeDigestChangesTrieSignal: {
_enum: { _enum: {
NewConfiguration: 'Option<SpCoreChangesTrieChangesTrieConfiguration>' NewConfiguration: 'Option<SpCoreChangesTrieChangesTrieConfiguration>'
} }
@@ -271,18 +271,18 @@ export default {
SpConsensusSlotsEquivocationProof: { SpConsensusSlotsEquivocationProof: {
offender: 'SpConsensusBabeAppPublic', offender: 'SpConsensusBabeAppPublic',
slot: 'u64', slot: 'u64',
firstHeader: 'SpRuntimeGenericHeader', firstHeader: 'SpRuntimeHeader',
secondHeader: 'SpRuntimeGenericHeader' secondHeader: 'SpRuntimeHeader'
}, },
/** /**
* Lookup123: sp_runtime::generic::header::Header<Number, sp_runtime::traits::BlakeTwo256> * Lookup123: sp_runtime::generic::header::Header<Number, sp_runtime::traits::BlakeTwo256>
**/ **/
SpRuntimeGenericHeader: { SpRuntimeHeader: {
parentHash: 'H256', parentHash: 'H256',
number: 'Compact<u32>', number: 'Compact<u32>',
stateRoot: 'H256', stateRoot: 'H256',
extrinsicsRoot: 'H256', extrinsicsRoot: 'H256',
digest: 'SpRuntimeGenericDigest' digest: 'SpRuntimeDigest'
}, },
/** /**
* Lookup124: sp_runtime::traits::BlakeTwo256 * Lookup124: sp_runtime::traits::BlakeTwo256
@@ -160,7 +160,7 @@ declare module '@polkadot/types/lookup' {
readonly bitfields: Vec<PolkadotPrimitivesV1SignedUncheckedSigned>; readonly bitfields: Vec<PolkadotPrimitivesV1SignedUncheckedSigned>;
readonly backedCandidates: Vec<PolkadotPrimitivesV1BackedCandidate>; readonly backedCandidates: Vec<PolkadotPrimitivesV1BackedCandidate>;
readonly disputes: Vec<PolkadotPrimitivesV1DisputeStatementSet>; readonly disputes: Vec<PolkadotPrimitivesV1DisputeStatementSet>;
readonly parentHeader: SpRuntimeGenericHeader; readonly parentHeader: SpRuntimeHeader;
} }
/** @name PolkadotPrimitivesV1SignedUncheckedSigned (325) */ /** @name PolkadotPrimitivesV1SignedUncheckedSigned (325) */
@@ -33,13 +33,13 @@ declare module '@polkadot/types/lookup' {
readonly mandatory: u64; readonly mandatory: u64;
} }
/** @name SpRuntimeGenericDigest (11) */ /** @name SpRuntimeDigest (11) */
export interface SpRuntimeGenericDigest extends Struct { export interface SpRuntimeDigest extends Struct {
readonly logs: Vec<SpRuntimeGenericDigestDigestItem>; readonly logs: Vec<SpRuntimeDigestDigestItem>;
} }
/** @name SpRuntimeGenericDigestDigestItem (13) */ /** @name SpRuntimeDigestDigestItem (13) */
export interface SpRuntimeGenericDigestDigestItem extends Enum { export interface SpRuntimeDigestDigestItem extends Enum {
readonly isOther: boolean; readonly isOther: boolean;
readonly asOther: Bytes; readonly asOther: Bytes;
readonly isChangesTrieRoot: boolean; readonly isChangesTrieRoot: boolean;
@@ -51,12 +51,12 @@ declare module '@polkadot/types/lookup' {
readonly isPreRuntime: boolean; readonly isPreRuntime: boolean;
readonly asPreRuntime: ITuple<[U8aFixed, Bytes]>; readonly asPreRuntime: ITuple<[U8aFixed, Bytes]>;
readonly isChangesTrieSignal: boolean; readonly isChangesTrieSignal: boolean;
readonly asChangesTrieSignal: SpRuntimeGenericDigestChangesTrieSignal; readonly asChangesTrieSignal: SpRuntimeDigestChangesTrieSignal;
readonly isRuntimeEnvironmentUpdated: boolean; readonly isRuntimeEnvironmentUpdated: boolean;
} }
/** @name SpRuntimeGenericDigestChangesTrieSignal (15) */ /** @name SpRuntimeDigestChangesTrieSignal (15) */
export interface SpRuntimeGenericDigestChangesTrieSignal extends Enum { export interface SpRuntimeDigestChangesTrieSignal extends Enum {
readonly isNewConfiguration: boolean; readonly isNewConfiguration: boolean;
readonly asNewConfiguration: Option<SpCoreChangesTrieChangesTrieConfiguration>; readonly asNewConfiguration: Option<SpCoreChangesTrieChangesTrieConfiguration>;
} }
@@ -260,17 +260,17 @@ declare module '@polkadot/types/lookup' {
export interface SpConsensusSlotsEquivocationProof extends Struct { export interface SpConsensusSlotsEquivocationProof extends Struct {
readonly offender: SpConsensusBabeAppPublic; readonly offender: SpConsensusBabeAppPublic;
readonly slot: u64; readonly slot: u64;
readonly firstHeader: SpRuntimeGenericHeader; readonly firstHeader: SpRuntimeHeader;
readonly secondHeader: SpRuntimeGenericHeader; readonly secondHeader: SpRuntimeHeader;
} }
/** @name SpRuntimeGenericHeader (123) */ /** @name SpRuntimeHeader (123) */
export interface SpRuntimeGenericHeader extends Struct { export interface SpRuntimeHeader extends Struct {
readonly parentHash: H256; readonly parentHash: H256;
readonly number: Compact<u32>; readonly number: Compact<u32>;
readonly stateRoot: H256; readonly stateRoot: H256;
readonly extrinsicsRoot: H256; readonly extrinsicsRoot: H256;
readonly digest: SpRuntimeGenericDigest; readonly digest: SpRuntimeDigest;
} }
/** @name SpRuntimeBlakeTwo256 (124) */ /** @name SpRuntimeBlakeTwo256 (124) */
@@ -68,8 +68,8 @@ describe('ExtrinsicSignatureV4', (): void => {
'00' + // MultiAddress '00' + // MultiAddress
'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' + 'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' +
'01' + '01' +
'4242424242424242424242424242424242424242424242424242424242424242' + '0101010101010101010101010101010101010101010101010101010101010101' +
'4242424242424242424242424242424242424242424242424242424242424242' + '0101010101010101010101010101010101010101010101010101010101010101' +
'00a50100' '00a50100'
); );
}); });
@@ -92,13 +92,39 @@ describe('ExtrinsicSignatureV4', (): void => {
).toHex() ).toHex()
).toEqual( ).toEqual(
'0x' + '0x' +
// Address = AccountId // Address = AccountId, no prefix
// '00' +
'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' + 'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' +
// This is a prefix-less signature, anySignture as opposed to Multi above // This is a prefix-less signature, anySignture as opposed to Multi above
// '01' + '0101010101010101010101010101010101010101010101010101010101010101' +
'4242424242424242424242424242424242424242424242424242424242424242' + '0101010101010101010101010101010101010101010101010101010101010101' +
'4242424242424242424242424242424242424242424242424242424242424242' + '00a50100'
);
});
it('fake signs with non-enum signature', (): void => {
const registry = new TypeRegistry();
const metadata = new Metadata(registry, metadataStatic);
registry.setMetadata(metadata);
registry.register({
Address: 'AccountId',
ExtrinsicSignature: '[u8;65]'
});
expect(
new ExtrinsicSignature(registry).signFake(
registry.createType('Call'),
pairs.alice.address,
signOptions
).toHex()
).toEqual(
'0x' +
// Address = AccountId, no prefix
'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' +
// 65 bytes here
'01' +
'0101010101010101010101010101010101010101010101010101010101010101' +
'0101010101010101010101010101010101010101010101010101010101010101' +
'00a50100' '00a50100'
); );
}); });
@@ -7,16 +7,15 @@ import type { Address, Balance, Call, Index } from '../../interfaces/runtime';
import type { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, Registry, SignatureOptions } from '../../types'; import type { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, Registry, SignatureOptions } from '../../types';
import type { ExtrinsicSignatureOptions } from '../types'; import type { ExtrinsicSignatureOptions } from '../types';
import { assert, isU8a, isUndefined, objectProperties, objectSpread, stringify, u8aConcat, u8aToHex } from '@polkadot/util'; import { assert, isU8a, isUndefined, objectProperties, objectSpread, stringify, u8aToHex } from '@polkadot/util';
import { Compact } from '../../codec/Compact'; import { Compact } from '../../codec/Compact';
import { Enum } from '../../codec/Enum';
import { Struct } from '../../codec/Struct'; import { Struct } from '../../codec/Struct';
import { EMPTY_U8A, IMMORTAL_ERA } from '../constants'; import { EMPTY_U8A, IMMORTAL_ERA } from '../constants';
import { GenericExtrinsicPayloadV4 } from './ExtrinsicPayload'; import { GenericExtrinsicPayloadV4 } from './ExtrinsicPayload';
const FAKE_NONE = new Uint8Array(); // Ensure we have enough data for all types of signatures
const FAKE_SOME = new Uint8Array([1]); const FAKE_SIGNATURE = new Uint8Array(256).fill(1);
function toAddress (registry: Registry, address: Address | Uint8Array | string): Address { function toAddress (registry: Registry, address: Address | Uint8Array | string): Address {
return registry.createType('Address', isU8a(address) ? u8aToHex(address) : address); return registry.createType('Address', isU8a(address) ? u8aToHex(address) : address);
@@ -28,7 +27,6 @@ function toAddress (registry: Registry, address: Address | Uint8Array | string):
* A container for the [[Signature]] associated with a specific [[Extrinsic]] * A container for the [[Signature]] associated with a specific [[Extrinsic]]
*/ */
export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSignature { export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSignature {
#fakePrefix: Uint8Array;
#signKeys: string[]; #signKeys: string[];
constructor (registry: Registry, value?: GenericExtrinsicSignatureV4 | Uint8Array, { isSigned }: ExtrinsicSignatureOptions = {}) { constructor (registry: Registry, value?: GenericExtrinsicSignatureV4 | Uint8Array, { isSigned }: ExtrinsicSignatureOptions = {}) {
@@ -44,9 +42,6 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned) GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned)
); );
this.#fakePrefix = registry.createType('ExtrinsicSignature') instanceof Enum
? FAKE_SOME
: FAKE_NONE;
this.#signKeys = Object.keys(signTypes); this.#signKeys = Object.keys(signTypes);
objectProperties(this, this.#signKeys, (k) => this.get(k)); objectProperties(this, this.#signKeys, (k) => this.get(k));
@@ -188,7 +183,7 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
const signer = toAddress(this.registry, address); const signer = toAddress(this.registry, address);
const payload = this.createPayload(method, options); const payload = this.createPayload(method, options);
const signature = this.registry.createType('ExtrinsicSignature', u8aConcat(this.#fakePrefix, new Uint8Array(64).fill(0x42))); const signature = this.registry.createType('ExtrinsicSignature', FAKE_SIGNATURE);
return this._injectSignature(signer, signature, payload); return this._injectSignature(signer, signature, payload);
} }
@@ -57,6 +57,9 @@ const WRAPPERS = ['BoundedBTreeMap', 'BoundedVec', 'Box', 'BTreeMap', 'Cow', 'Re
// These are reserved and/or conflicts with built-in Codec or JS definitions // These are reserved and/or conflicts with built-in Codec or JS definitions
const RESERVED = ['entries', 'hash', 'keys', 'new', 'size']; const RESERVED = ['entries', 'hash', 'keys', 'new', 'size'];
// Remove these from all paths at index 1
const PATH_RM_INDEX_1 = ['generic', 'misc', 'pallet', 'traits', 'types'];
function splitNamespace (values: string[]): string[][] { function splitNamespace (values: string[]): string[][] {
return values.map((v) => v.split('::')); return values.map((v) => v.split('::'));
} }
@@ -103,17 +106,34 @@ function getAliasPath (path: SiPath): string | null {
: null; : null;
} }
function hasNoDupes (input: [number, string, SiTypeParameter[]][]): boolean {
for (let i = 0; i < input.length; i++) {
const [ai, an] = input[i];
for (let j = 0; j < input.length; j++) {
const [bi, bn] = input[j];
// if the indexes are not the same and the names match, we have a dupe
if (ai !== bi && an === bn) {
return false;
}
}
}
return true;
}
function removeDuplicateNames (lookup: PortableRegistry, names: [number, string | null, SiTypeParameter[]][]): [number, string, SiTypeParameter[]][] { function removeDuplicateNames (lookup: PortableRegistry, names: [number, string | null, SiTypeParameter[]][]): [number, string, SiTypeParameter[]][] {
const rewrite: Record<number, string> = {}; const rewrite: Record<number, string> = {};
return names return names
.map(([lookupIndex, name, params]): [number, string | null, SiTypeParameter[]] => { .map(([lookupIndex, name, params]): [number, string, SiTypeParameter[]] | null => {
if (!name) { if (!name) {
return [lookupIndex, null, params]; return null;
} }
// those where the name is matching // those where the name is matching (since name is filtered, these all do have names)
const allSame = names.filter(([, oName]) => name === oName); const allSame = names.filter(([, oName]) => name === oName) as [number, string, SiTypeParameter[]][];
// are there among matching names // are there among matching names
const anyDiff = allSame.some(([oIndex,, oParams]) => const anyDiff = allSame.some(([oIndex,, oParams]) =>
@@ -146,43 +166,38 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
} }
// see if using the param type helps // see if using the param type helps
const adjusted = allSame.map(([oIndex, oName, oParams]): [number, string | null, SiTypeParameter[]] => { const adjusted = new Array<[number, string, SiTypeParameter[]]>(allSame.length);
for (let i = 0; i < allSame.length; i++) {
const [oIndex, oName, oParams] = allSame[i];
const { def, path } = lookup.getSiType(oParams[paramIdx].type.unwrap()); const { def, path } = lookup.getSiType(oParams[paramIdx].type.unwrap());
if (!def.isPrimitive && !path.length) { if (!def.isPrimitive && !path.length) {
return [oIndex, null, params]; return null;
} }
return [ adjusted[i] = [
oIndex, oIndex,
def.isPrimitive def.isPrimitive
? `${oName as string}${def.asPrimitive.toString()}` ? `${oName}${def.asPrimitive.toString()}`
: `${oName as string}${path[path.length - 1].toString()}`, : `${oName}${path[path.length - 1].toString()}`,
params params
]; ];
});
// any dupes remaining?
const noDupes = adjusted.every(([i, n]) =>
!!n &&
!adjusted.some(([ai, an]) =>
i !== ai &&
n === an
)
);
if (noDupes) {
// we filtered above for null names
adjusted.forEach(([index, name]): void => {
rewrite[index] = name as string;
});
} }
return noDupes if (hasNoDupes(adjusted)) {
? [lookupIndex, name, params] for (let i = 0; i < adjusted.length; i++) {
: [lookupIndex, null, params]; const [index, name] = adjusted[i];
rewrite[index] = name;
}
return [lookupIndex, name, params];
}
return null;
}) })
.filter((n): n is [number, string, SiTypeParameter[]] => !!n[1]) .filter((n): n is [number, string, SiTypeParameter[]] => !!n)
.map(([lookupIndex, name, params]) => [ .map(([lookupIndex, name, params]) => [
lookupIndex, lookupIndex,
rewrite[lookupIndex] || name, rewrite[lookupIndex] || name,
@@ -190,32 +205,33 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
]); ]);
} }
function extractName (types: PortableType[], { id, type: { params, path } }: PortableType): [number, string | null, SiTypeParameter[]] { function extractName (types: PortableType[], { id, type: { params, path } }: PortableType): [number, string, SiTypeParameter[]] | null {
const lookupIndex = id.toNumber(); // if we have no path or determined as a wrapper, we just skip it
if (!path.length || WRAPPERS.includes(path[path.length - 1].toString())) { if (!path.length || WRAPPERS.includes(path[path.length - 1].toString())) {
return [lookupIndex, null, []]; return null;
} }
const parts = path const parts = path
.map((p) => stringUpperFirst(stringCamelCase(p))) .map((p) => stringUpperFirst(stringCamelCase(p)))
.filter((p, index) => .filter((p, index) => {
( const lower = p.toLowerCase();
// Remove ::{misc, pallet, traits, types}::
return (
// Remove ::{generic, misc, pallet, traits, types}::
index !== 1 || index !== 1 ||
!['Misc', 'Pallet', 'Traits', 'Types'].includes(p.toString()) !PATH_RM_INDEX_1.includes(lower)
) && ) &&
( (
// sp_runtime::generic::digest::Digest -> sp_runtime::generic::Digest // sp_runtime::generic::digest::Digest -> sp_runtime::generic::Digest
// sp_runtime::multiaddress::MultiAddress -> sp_runtime::MultiAddress // sp_runtime::multiaddress::MultiAddress -> sp_runtime::MultiAddress
index === path.length - 1 || index === path.length - 1 ||
p.toLowerCase() !== path[index + 1].toLowerCase() lower !== path[index + 1].toLowerCase()
)
); );
});
let typeName = parts.join(''); let typeName = parts.join('');
if (parts.length === 2 && parts[parts.length - 1] === 'RawOrigin' && params.length === 2 && params[1].type.isSome) { // do magic for RawOrigin lookup, e.g. pallet_collective::RawOrigin
// Do magic for RawOrigin lookup if (parts.length === 2 && parts[1] === 'RawOrigin' && params.length === 2 && params[1].type.isSome) {
const instanceType = types[params[1].type.unwrap().toNumber()]; const instanceType = types[params[1].type.unwrap().toNumber()];
if (instanceType.type.path.length === 2) { if (instanceType.type.path.length === 2) {
@@ -223,14 +239,63 @@ function extractName (types: PortableType[], { id, type: { params, path } }: Por
} }
} }
return [lookupIndex, typeName, params]; return [id.toNumber(), typeName, params];
} }
function extractNames (lookup: PortableRegistry, types: PortableType[]): [Record<number, string>, Record<string, SiTypeParameter[]>] { function registerTypes (lookup: PortableRegistry, lookups: Record<string, string>, names: Record<number, string>, params: Record<string, SiTypeParameter[]>): void {
const dedup = removeDuplicateNames(lookup, types.map((t) => // Register the types we extracted
extractName(types, t) lookup.registry.register(lookups);
));
// Try and extract the AccountId/Address/Signature type from UncheckedExtrinsic
if (params.SpRuntimeUncheckedExtrinsic) {
// Address, Call, Signature, Extra
const [addrParam,, sigParam] = params.SpRuntimeUncheckedExtrinsic;
const siAddress = lookup.getSiType(addrParam.type.unwrap());
const siSignature = lookup.getSiType(sigParam.type.unwrap());
const nsSignature = createNamespace(siSignature);
let nsAccountId = createNamespace(siAddress);
const isMultiAddress = nsAccountId === 'sp_runtime::multiaddress::MultiAddress';
// With multiaddress, we check the first type param again
if (isMultiAddress) {
// AccountId, AccountIndex
const [idParam] = siAddress.params;
nsAccountId = createNamespace(lookup.getSiType(idParam.type.unwrap()));
}
lookup.registry.register({
AccountId: ['sp_core::crypto::AccountId32'].includes(nsAccountId)
? 'AccountId32'
: ['account::AccountId20', 'primitive_types::H160'].includes(nsAccountId)
? 'AccountId20'
: 'AccountId32', // other, default to AccountId32
Address: isMultiAddress
? 'MultiAddress'
: 'AccountId',
ExtrinsicSignature: ['sp_runtime::MultiSignature'].includes(nsSignature)
? 'MultiSignature'
: names[sigParam.type.unwrap().toNumber()] || 'MultiSignature'
});
}
}
function extractTypeInfo (lookup: PortableRegistry, portable: PortableType[]): [Record<number, PortableType>, Record<string, string>, Record<number, string>, Record<string, SiTypeParameter[]>] {
const nameInfo: [number, string, SiTypeParameter[]][] = [];
const types: Record<number, PortableType> = {};
for (let i = 0; i < portable.length; i++) {
const type = portable[i];
const extracted = extractName(portable, portable[i]);
if (extracted) {
nameInfo.push(extracted);
}
types[type.id.toNumber()] = type;
}
const dedup = removeDuplicateNames(lookup, nameInfo);
const lookups: Record<string, string> = {}; const lookups: Record<string, string> = {};
const names: Record<number, string> = {}; const names: Record<number, string> = {};
const params: Record<string, SiTypeParameter[]> = {}; const params: Record<string, SiTypeParameter[]> = {};
@@ -243,23 +308,7 @@ function extractNames (lookup: PortableRegistry, types: PortableType[]): [Record
params[name] = p; params[name] = p;
} }
lookup.registry.register(lookups); return [types, lookups, names, params];
return [names, params];
}
// types have an id, which means they are to be named by
// the specified id - ensure we have a mapping lookup for these
function extractTypeMap (types: PortableType[]): Record<number, PortableType> {
const result: Record<number, PortableType> = {};
for (let i = 0; i < types.length; i++) {
const p = types[i];
result[p.id.toNumber()] = p;
}
return result;
} }
export class PortableRegistry extends Struct { export class PortableRegistry extends Struct {
@@ -274,43 +323,12 @@ export class PortableRegistry extends Struct {
types: 'Vec<PortableType>' types: 'Vec<PortableType>'
}, value); }, value);
const [names, params] = extractNames(this, this.types); const [types, lookups, names, params] = extractTypeInfo(this, this.types);
this.#names = names; this.#names = names;
this.#types = extractTypeMap(this.types); this.#types = types;
// Try and extract the AccountId/Address/Signature type from UncheckedExtrinsic registerTypes(this, lookups, names, params);
if (params.SpRuntimeGenericUncheckedExtrinsic) {
// Address, Call, Signature, Extra
const [addrParam,, sigParam] = params.SpRuntimeGenericUncheckedExtrinsic;
const siAddress = this.getSiType(addrParam.type.unwrap());
const siSignature = this.getSiType(sigParam.type.unwrap());
const nsSignature = createNamespace(siSignature);
let nsAccountId = createNamespace(siAddress);
const isMultiAddress = nsAccountId === 'sp_runtime::multiaddress::MultiAddress';
// With multiaddress, we check the first type param again
if (isMultiAddress) {
// AccountId, AccountIndex
const [idParam] = siAddress.params;
nsAccountId = createNamespace(this.getSiType(idParam.type.unwrap()));
}
this.registry.register({
AccountId: ['sp_core::crypto::AccountId32'].includes(nsAccountId)
? 'AccountId32'
: ['account::AccountId20', 'primitive_types::H160'].includes(nsAccountId)
? 'AccountId20'
: 'AccountId32', // other, default to AccountId32
Address: isMultiAddress
? 'MultiAddress'
: 'AccountId',
ExtrinsicSignature: ['sp_runtime::MultiSignature'].includes(nsSignature)
? 'MultiSignature'
: names[sigParam.type.unwrap().toNumber()] || 'MultiSignature'
});
}
// console.timeEnd('PortableRegistry') // console.timeEnd('PortableRegistry')
} }
+1 -1
View File
@@ -3,4 +3,4 @@
// Auto-generated by @polkadot/dev, do not edit // Auto-generated by @polkadot/dev, do not edit
export const packageInfo = { name: '@polkadot/types', version: '6.7.2' }; export const packageInfo = { name: '@polkadot/types', version: '6.8.1' };
+27 -27
View File
@@ -1845,40 +1845,40 @@ __metadata:
resolution: "@polkadot/api-contract@workspace:packages/api-contract" resolution: "@polkadot/api-contract@workspace:packages/api-contract"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/api": 6.7.2 "@polkadot/api": 6.8.1
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
rxjs: ^7.4.0 rxjs: ^7.4.0
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@polkadot/api-derive@6.7.2, @polkadot/api-derive@workspace:packages/api-derive": "@polkadot/api-derive@6.8.1, @polkadot/api-derive@workspace:packages/api-derive":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/api-derive@workspace:packages/api-derive" resolution: "@polkadot/api-derive@workspace:packages/api-derive"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/api": 6.7.2 "@polkadot/api": 6.8.1
"@polkadot/keyring": ^7.8.2 "@polkadot/keyring": ^7.8.2
"@polkadot/rpc-core": 6.7.2 "@polkadot/rpc-core": 6.8.1
"@polkadot/rpc-provider": 6.7.2 "@polkadot/rpc-provider": 6.8.1
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
"@polkadot/util-crypto": ^7.8.2 "@polkadot/util-crypto": ^7.8.2
rxjs: ^7.4.0 rxjs: ^7.4.0
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@polkadot/api@6.7.2, @polkadot/api@workspace:packages/api": "@polkadot/api@6.8.1, @polkadot/api@workspace:packages/api":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/api@workspace:packages/api" resolution: "@polkadot/api@workspace:packages/api"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/api-derive": 6.7.2 "@polkadot/api-derive": 6.8.1
"@polkadot/keyring": ^7.8.2 "@polkadot/keyring": ^7.8.2
"@polkadot/rpc-core": 6.7.2 "@polkadot/rpc-core": 6.8.1
"@polkadot/rpc-provider": 6.7.2 "@polkadot/rpc-provider": 6.8.1
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/types-known": 6.7.2 "@polkadot/types-known": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
"@polkadot/util-crypto": ^7.8.2 "@polkadot/util-crypto": ^7.8.2
eventemitter3: ^4.0.7 eventemitter3: ^4.0.7
@@ -2000,26 +2000,26 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@polkadot/rpc-core@6.7.2, @polkadot/rpc-core@workspace:packages/rpc-core": "@polkadot/rpc-core@6.8.1, @polkadot/rpc-core@workspace:packages/rpc-core":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/rpc-core@workspace:packages/rpc-core" resolution: "@polkadot/rpc-core@workspace:packages/rpc-core"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/keyring": ^7.8.2 "@polkadot/keyring": ^7.8.2
"@polkadot/rpc-provider": 6.7.2 "@polkadot/rpc-provider": 6.8.1
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
rxjs: ^7.4.0 rxjs: ^7.4.0
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@polkadot/rpc-provider@6.7.2, @polkadot/rpc-provider@workspace:packages/rpc-provider": "@polkadot/rpc-provider@6.8.1, @polkadot/rpc-provider@workspace:packages/rpc-provider":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/rpc-provider@workspace:packages/rpc-provider" resolution: "@polkadot/rpc-provider@workspace:packages/rpc-provider"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/keyring": ^7.8.2 "@polkadot/keyring": ^7.8.2
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
"@polkadot/util-crypto": ^7.8.2 "@polkadot/util-crypto": ^7.8.2
"@polkadot/x-fetch": ^7.8.2 "@polkadot/x-fetch": ^7.8.2
@@ -2047,10 +2047,10 @@ __metadata:
"@babel/core": ^7.16.0 "@babel/core": ^7.16.0
"@babel/register": ^7.16.0 "@babel/register": ^7.16.0
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/api": 6.7.2 "@polkadot/api": 6.8.1
"@polkadot/rpc-provider": 6.7.2 "@polkadot/rpc-provider": 6.8.1
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/types-support": 6.7.2 "@polkadot/types-support": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
"@types/websocket": ^1.0.4 "@types/websocket": ^1.0.4
"@types/yargs": ^17.0.5 "@types/yargs": ^17.0.5
@@ -2066,18 +2066,18 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@polkadot/types-known@6.7.2, @polkadot/types-known@workspace:packages/types-known": "@polkadot/types-known@6.8.1, @polkadot/types-known@workspace:packages/types-known":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/types-known@workspace:packages/types-known" resolution: "@polkadot/types-known@workspace:packages/types-known"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/networks": ^7.8.2 "@polkadot/networks": ^7.8.2
"@polkadot/types": 6.7.2 "@polkadot/types": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@polkadot/types-support@6.7.2, @polkadot/types-support@workspace:packages/types-support": "@polkadot/types-support@6.8.1, @polkadot/types-support@workspace:packages/types-support":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/types-support@workspace:packages/types-support" resolution: "@polkadot/types-support@workspace:packages/types-support"
dependencies: dependencies:
@@ -2086,13 +2086,13 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@polkadot/types@6.7.2, @polkadot/types@workspace:packages/types": "@polkadot/types@6.8.1, @polkadot/types@workspace:packages/types":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@polkadot/types@workspace:packages/types" resolution: "@polkadot/types@workspace:packages/types"
dependencies: dependencies:
"@babel/runtime": ^7.16.0 "@babel/runtime": ^7.16.0
"@polkadot/keyring": ^7.8.2 "@polkadot/keyring": ^7.8.2
"@polkadot/types-support": 6.7.2 "@polkadot/types-support": 6.8.1
"@polkadot/util": ^7.8.2 "@polkadot/util": ^7.8.2
"@polkadot/util-crypto": ^7.8.2 "@polkadot/util-crypto": ^7.8.2
"@types/bn.js": ^4.11.6 "@types/bn.js": ^4.11.6