Some minor cleanups (#1966)
* Some minor cleanups * Small additions * Cleanup ExtrinsicEra decoding * Minor adjustments * Remove support for metadata v0 parsing * Adjust refCountDelay * refCountDelay comments * Adjust Metadata tests * Metadata default creation * Funky lines * Cleanup as AccountIdAndIndex * Some derive returns * Try and cleanup info extraction
This commit is contained in:
@@ -47,10 +47,11 @@ export default class Code<ApiType extends ApiTypes> extends BaseWithTx<ApiType>
|
||||
public createBlueprint = (maxGas: number | BN): CodePutCode<ApiType> => {
|
||||
return {
|
||||
signAndSend: this.decorateMethod(
|
||||
(account: IKeyringPair | string | AccountId | Address): CodePutCodeResultSubscription<ApiType> => this.apiContracts
|
||||
.putCode(maxGas, compactAddLength(this.code))
|
||||
.signAndSend(account)
|
||||
.pipe(map(this.createResult))
|
||||
(account: IKeyringPair | string | AccountId | Address): CodePutCodeResultSubscription<ApiType> =>
|
||||
this.apiContracts
|
||||
.putCode(maxGas, compactAddLength(this.code))
|
||||
.signAndSend(account)
|
||||
.pipe(map(this.createResult))
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ export default class Contract<ApiType extends ApiTypes> extends BaseWithTxAndRpc
|
||||
return {
|
||||
send: this.decorateMethod(
|
||||
as === 'rpc' && this.hasRpcContractsCall
|
||||
? (account: IKeyringPair | string | AccountId | Address): ContractCallResult<'rpc'> => {
|
||||
return this.rpcContractsCall(
|
||||
? (account: IKeyringPair | string | AccountId | Address): ContractCallResult<'rpc'> =>
|
||||
this.rpcContractsCall(
|
||||
this.registry.createType('ContractCallRequest', {
|
||||
origin: account,
|
||||
dest: this.address.toString(),
|
||||
@@ -50,18 +50,13 @@ export default class Contract<ApiType extends ApiTypes> extends BaseWithTxAndRpc
|
||||
gasLimit,
|
||||
inputData: fn(...params)
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
map((result: ContractExecResult): ContractCallOutcome =>
|
||||
this.createOutcome(result, this.registry.createType('AccountId', account), def, params)
|
||||
)
|
||||
);
|
||||
}
|
||||
: (account: IKeyringPair | string | AccountId | Address): ContractCallResult<'tx'> => {
|
||||
return this.apiContracts
|
||||
).pipe(map((result: ContractExecResult): ContractCallOutcome =>
|
||||
this.createOutcome(result, this.registry.createType('AccountId', account), def, params)
|
||||
))
|
||||
: (account: IKeyringPair | string | AccountId | Address): ContractCallResult<'tx'> =>
|
||||
this.apiContracts
|
||||
.call(this.address, value, gasLimit, fn(...params))
|
||||
.signAndSend(account);
|
||||
}
|
||||
.signAndSend(account)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,14 +29,13 @@ export abstract class Base<ApiType extends ApiTypes> implements ContractBase<Api
|
||||
}
|
||||
|
||||
public get messages (): ContractMessage[] {
|
||||
return this.abi.abi.contract.messages
|
||||
.map(
|
||||
(def: ContractABIMessage, index): ContractMessage => ({
|
||||
index,
|
||||
def,
|
||||
fn: this.abi.messages[def.name] || this.abi.messages[stringCamelCase(name)]
|
||||
})
|
||||
);
|
||||
return this.abi.abi.contract.messages.map(
|
||||
(def: ContractABIMessage, index): ContractMessage => ({
|
||||
index,
|
||||
def,
|
||||
fn: this.abi.messages[def.name] || this.abi.messages[stringCamelCase(name)]
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public getMessage (nameOrIndex?: string | number): ContractMessage {
|
||||
@@ -46,6 +45,7 @@ export abstract class Base<ApiType extends ApiTypes> implements ContractBase<Api
|
||||
: this.abi.abi.contract.messages.findIndex((message): boolean => nameOrIndex === message.name || nameOrIndex === stringCamelCase(message.name))
|
||||
: 0;
|
||||
const def = this.abi.abi.contract.messages[index];
|
||||
|
||||
assert(!!def, `Attempted to access a contract message that does not exist: ${typeof nameOrIndex === 'number' ? `index ${nameOrIndex}` : nameOrIndex}`);
|
||||
|
||||
const fn = this.abi.messages[def.name] || this.abi.messages[stringCamelCase(def.name)];
|
||||
|
||||
@@ -26,17 +26,17 @@ function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIn
|
||||
const accountId = createType(api.registry, 'AccountId', decoded);
|
||||
|
||||
return api.derive.accounts.idToIndex(accountId).pipe(
|
||||
map((accountIndex): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex)
|
||||
map((accountIndex): AccountIdAndIndex => [accountId, accountIndex])
|
||||
);
|
||||
}
|
||||
|
||||
const accountIndex = createType(api.registry, 'AccountIndex', decoded);
|
||||
|
||||
return api.derive.accounts.indexToId(accountIndex).pipe(
|
||||
map((accountId): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex)
|
||||
map((accountId): AccountIdAndIndex => [accountId, accountIndex])
|
||||
);
|
||||
} catch (error) {
|
||||
return of([undefined, undefined] as AccountIdAndIndex);
|
||||
return of([undefined, undefined]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BlockNumber, Header } from '@polkadot/types/interfaces';
|
||||
import { BlockNumber } from '@polkadot/types/interfaces';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
@@ -25,6 +25,6 @@ import { memo } from '../util';
|
||||
export function bestNumber (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return memo((): Observable<BlockNumber> =>
|
||||
api.derive.chain.subscribeNewHeads().pipe(
|
||||
map((header: Header): BlockNumber => header.number.unwrap())
|
||||
map((header) => header.number.unwrap())
|
||||
));
|
||||
}
|
||||
|
||||
@@ -26,6 +26,6 @@ import { memo } from '../util';
|
||||
export function bestNumberFinalized (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return memo((): Observable<BlockNumber> =>
|
||||
api.rpc.chain.subscribeFinalizedHeads().pipe(
|
||||
map((header): BlockNumber => header.number.unwrap())
|
||||
map((header) => header.number.unwrap())
|
||||
));
|
||||
}
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountId } from '@polkadot/types/interfaces';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
import { Vec } from '@polkadot/types';
|
||||
|
||||
import { HeaderExtended } from '../type';
|
||||
import { memo } from '../util';
|
||||
|
||||
@@ -32,7 +29,7 @@ export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) =>
|
||||
combineLatest([
|
||||
api.rpc.chain.getHeader(hash),
|
||||
api.query.session
|
||||
? api.query.session.validators.at(hash) as Observable<Vec<AccountId>>
|
||||
? api.query.session.validators.at(hash)
|
||||
: of([])
|
||||
]).pipe(
|
||||
map(([header, validators]): HeaderExtended =>
|
||||
|
||||
@@ -12,6 +12,20 @@ import { Option } from '@polkadot/types';
|
||||
|
||||
type Result = [Hash[], Option<Proposal>[], Option<Votes>[]];
|
||||
|
||||
function parse ([hashes, proposals, votes]: Result): DerivedCollectiveProposal[] {
|
||||
return proposals
|
||||
.map((proposalOpt, index): DerivedCollectiveProposal | null =>
|
||||
proposalOpt.isSome
|
||||
? {
|
||||
hash: hashes[index],
|
||||
proposal: proposalOpt.unwrap(),
|
||||
votes: votes[index].unwrapOr(null)
|
||||
}
|
||||
: null
|
||||
)
|
||||
.filter((proposal): proposal is DerivedCollectiveProposal => !!proposal);
|
||||
}
|
||||
|
||||
export function proposals (api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): () => Observable<DerivedCollectiveProposal[]> {
|
||||
return (): Observable<DerivedCollectiveProposal[]> =>
|
||||
api.query[section]
|
||||
@@ -25,19 +39,7 @@ export function proposals (api: ApiInterfaceRx, section: 'council' | 'technicalC
|
||||
])
|
||||
: of([[], [], []])
|
||||
),
|
||||
map(([hashes, proposals, votes]: Result): DerivedCollectiveProposal[] =>
|
||||
proposals
|
||||
.map((proposalOpt, index): DerivedCollectiveProposal | null =>
|
||||
proposalOpt.isSome
|
||||
? {
|
||||
hash: hashes[index],
|
||||
proposal: proposalOpt.unwrap(),
|
||||
votes: votes[index].unwrapOr(null)
|
||||
}
|
||||
: null
|
||||
)
|
||||
.filter((proposal): boolean => !!proposal) as DerivedCollectiveProposal[]
|
||||
)
|
||||
map(parse)
|
||||
)
|
||||
: of([] as DerivedCollectiveProposal[]);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ function constructInfo (api: ApiInterfaceRx, index: BN | number, _info: Option<R
|
||||
export function retrieveInfo (api: ApiInterfaceRx, index: BN | number, info: Option<ReferendumInfo>): Observable<DerivedReferendum | null> {
|
||||
return ((
|
||||
info?.isSome
|
||||
? api.query.democracy.preimages<PreImage>(info.unwrap().proposalHash)
|
||||
? api.query.democracy.preimages(info.unwrap().proposalHash)
|
||||
: of(undefined)
|
||||
) as Observable<PreImage | undefined>).pipe(
|
||||
map((preimage?: PreImage): DerivedReferendum | null =>
|
||||
|
||||
@@ -29,7 +29,7 @@ export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) =
|
||||
)
|
||||
),
|
||||
map((infos): DerivedReferendum[] =>
|
||||
infos.filter((referendum): boolean => !!referendum) as DerivedReferendum[]
|
||||
infos.filter((referendum): referendum is DerivedReferendum => !!referendum)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountId, SessionIndex } from '@polkadot/types/interfaces';
|
||||
import { AccountId } from '@polkadot/types/interfaces';
|
||||
import { DerivedHeartbeats } from '../types';
|
||||
|
||||
import { of, Observable, combineLatest } from 'rxjs';
|
||||
@@ -23,9 +23,9 @@ export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable<Deriv
|
||||
combineLatest([
|
||||
of(validators),
|
||||
api.query.imOnline.receivedHeartbeats.multi<Option<Bytes>>(
|
||||
validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])),
|
||||
validators.map((_address, index) => [currentIndex, index])),
|
||||
api.query.imOnline.authoredBlocks.multi<u32>(
|
||||
validators.map((address): [SessionIndex, AccountId] => [currentIndex, address]))
|
||||
validators.map((address) => [currentIndex, address]))
|
||||
])
|
||||
),
|
||||
map(([validators, heartbeats, numBlocks]): DerivedHeartbeats =>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BlockNumber } from '@polkadot/types/interfaces';
|
||||
import { DerivedSessionInfo } from '../types';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
@@ -14,6 +13,6 @@ import { memo } from '../util';
|
||||
export function eraLength (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return memo((): Observable<BlockNumber> =>
|
||||
api.derive.session.info().pipe(
|
||||
map(({ eraLength }: DerivedSessionInfo): BlockNumber => eraLength)
|
||||
map((info) => info.eraLength)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BlockNumber } from '@polkadot/types/interfaces';
|
||||
import { DerivedSessionInfo } from '../types';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
@@ -14,6 +13,6 @@ import { memo } from '../util';
|
||||
export function eraProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return memo((): Observable<BlockNumber> =>
|
||||
api.derive.session.info().pipe(
|
||||
map(({ eraProgress }: DerivedSessionInfo): BlockNumber => eraProgress)
|
||||
map((info) => info.eraProgress)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BlockNumber } from '@polkadot/types/interfaces';
|
||||
import { DerivedSessionInfo } from '../types';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
@@ -14,6 +13,6 @@ import { memo } from '../util';
|
||||
export function sessionProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return memo((): Observable<BlockNumber> =>
|
||||
api.derive.session.info().pipe(
|
||||
map(({ sessionProgress }: DerivedSessionInfo): BlockNumber => sessionProgress)
|
||||
map((info) => info.sessionProgress)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -163,14 +163,14 @@ export default class ApiRx extends ApiBase<'rxjs'> {
|
||||
constructor (options?: ApiOptions) {
|
||||
super(options, 'rxjs', decorateMethod);
|
||||
|
||||
this.#isReadyRx = from(
|
||||
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', (): void => {
|
||||
resolve(this);
|
||||
});
|
||||
})
|
||||
) as Observable<ApiRx>;
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,10 @@ export default class MagicNumber extends U32 {
|
||||
constructor (registry: Registry, value?: any) {
|
||||
super(registry, value);
|
||||
|
||||
const magic = new U32(registry, MAGIC_NUMBER);
|
||||
if (!this.isEmpty) {
|
||||
const magic = new U32(registry, MAGIC_NUMBER);
|
||||
|
||||
assert(this.eq(magic), `MagicNumber mismatch: expected ${magic.toHex()}, found ${this.toHex()}`);
|
||||
assert(this.eq(magic), `MagicNumber mismatch: expected ${magic.toHex()}, found ${this.toHex()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
|
||||
import { Registry } from '@polkadot/types/types';
|
||||
|
||||
import { bnToU8a, isHex, hexToU8a, u8aConcat } from '@polkadot/util';
|
||||
import { isHex, hexToU8a } from '@polkadot/util';
|
||||
|
||||
import { MAGIC_NUMBER } from './MagicNumber';
|
||||
import MetadataVersioned from './MetadataVersioned';
|
||||
|
||||
const VERSION_IDX = 4; // magic u32 preceding
|
||||
@@ -23,28 +22,17 @@ function decodeMetadata (registry: Registry, _value: Uint8Array | string = new U
|
||||
try {
|
||||
return new MetadataVersioned(registry, value);
|
||||
} catch (error) {
|
||||
if (!error.message.includes('MagicNumber mismatch')) {
|
||||
// This is an f-ing hack as a follow-up to another ugly hack
|
||||
// https://github.com/polkadot-js/api/commit/a9211690be6b68ad6c6dad7852f1665cadcfa5b2
|
||||
// when we fail on V9, try to re-parse it as v10... yes... HACK
|
||||
if (version === 9) {
|
||||
value[VERSION_IDX] = 10;
|
||||
// This is an f-ing hack as a follow-up to another ugly hack
|
||||
// https://github.com/polkadot-js/api/commit/a9211690be6b68ad6c6dad7852f1665cadcfa5b2
|
||||
// when we fail on V9, try to re-parse it as v10... yes... HACK
|
||||
if (version === 9) {
|
||||
value[VERSION_IDX] = 10;
|
||||
|
||||
return decodeMetadata(registry, value);
|
||||
}
|
||||
|
||||
throw error;
|
||||
return decodeMetadata(registry, value);
|
||||
}
|
||||
}
|
||||
|
||||
return new MetadataVersioned(
|
||||
registry,
|
||||
u8aConcat(
|
||||
bnToU8a(MAGIC_NUMBER), // manually add the magic number
|
||||
Uint8Array.from([0]), // add the version for the original
|
||||
value // the actual data as retrieved
|
||||
)
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,31 +47,27 @@ export function defaultValues (registry: Registry, rpcData: string, withThrow =
|
||||
describe('storage with default values', (): void => {
|
||||
const metadata = new Metadata(registry, rpcData);
|
||||
|
||||
metadata.asLatest.modules
|
||||
.filter(({ storage }): boolean => storage.isSome)
|
||||
.forEach((mod): void => {
|
||||
mod.storage.unwrap().items.forEach(({ fallback, name, type }): void => {
|
||||
const inner = unwrapStorageType(type);
|
||||
const location = `${mod.name}.${name}: ${inner}`;
|
||||
metadata.asLatest.modules.filter(({ storage }): boolean => storage.isSome).forEach((mod): void => {
|
||||
mod.storage.unwrap().items.forEach(({ fallback, name, type }): void => {
|
||||
const inner = unwrapStorageType(type);
|
||||
const location = `${mod.name}.${name}: ${inner}`;
|
||||
|
||||
it(`creates default types for ${location}`, (): void => {
|
||||
expect(
|
||||
(): void => {
|
||||
try {
|
||||
createTypeUnsafe(registry, inner, [fallback]);
|
||||
} catch (error) {
|
||||
const message = `${location}:: ${error.message}`;
|
||||
it(`creates default types for ${location}`, (): void => {
|
||||
expect((): void => {
|
||||
try {
|
||||
createTypeUnsafe(registry, inner, [fallback]);
|
||||
} catch (error) {
|
||||
const message = `${location}:: ${error.message}`;
|
||||
|
||||
if (withThrow) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
if (withThrow) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
console.warn(message);
|
||||
}
|
||||
).not.toThrow();
|
||||
});
|
||||
}
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/metadata authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeRegistry } from '@polkadot/types/create';
|
||||
|
||||
import Metadata from '../';
|
||||
import latestSubstrateV0 from './static-substrate.json';
|
||||
import rpcData from './static';
|
||||
import { defaultValues, toLatest } from '../util/testUtil';
|
||||
|
||||
describe('Metadata', (): void => {
|
||||
const registry = new TypeRegistry();
|
||||
|
||||
it('decodes into latest substrate', (): void => {
|
||||
const metadata = new Metadata(registry, rpcData);
|
||||
const json = metadata.asV0.toJSON();
|
||||
|
||||
try {
|
||||
expect(metadata.version).toBe(0);
|
||||
expect(metadata.asV0.modules.length).not.toBe(0);
|
||||
expect(json).toEqual(latestSubstrateV0);
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(json));
|
||||
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
toLatest(registry, 0, rpcData, false);
|
||||
|
||||
defaultValues(registry, rpcData, false);
|
||||
});
|
||||
@@ -8,35 +8,31 @@ const DELAY = 1750;
|
||||
|
||||
/** @internal */
|
||||
function refCountDelayInner <T> (source: Observable<T>): Observable<T> {
|
||||
let connected = 0; // 0 = disconnected, 1 = disconnecting, 2 = connecting, 3 = connected
|
||||
let refCount = 0;
|
||||
let con = Subscription.EMPTY;
|
||||
let sched = Subscription.EMPTY;
|
||||
// state: 0 = disconnected, 1 = disconnecting, 2 = connecting, 3 = connected
|
||||
let [state, refCount, connection, scheduler] = [0, 0, Subscription.EMPTY, Subscription.EMPTY];
|
||||
|
||||
return new Observable((ob) => {
|
||||
source.subscribe(ob);
|
||||
|
||||
if (refCount++ === 0) {
|
||||
if (connected === 1) {
|
||||
connected = 3;
|
||||
sched.unsubscribe();
|
||||
if (state === 1) {
|
||||
scheduler.unsubscribe();
|
||||
} else {
|
||||
con = (source as ConnectableObservable<T>).connect();
|
||||
connected = 3;
|
||||
connection = (source as ConnectableObservable<T>).connect();
|
||||
}
|
||||
|
||||
state = 3;
|
||||
}
|
||||
|
||||
return (): void => {
|
||||
if (--refCount === 0) {
|
||||
if (connected === 2) {
|
||||
connected = 0;
|
||||
sched.unsubscribe();
|
||||
if (state === 2) {
|
||||
state = 0; scheduler.unsubscribe();
|
||||
} else {
|
||||
// connected === 3
|
||||
connected = 1;
|
||||
sched = asapScheduler.schedule((): void => {
|
||||
con.unsubscribe();
|
||||
connected = 0;
|
||||
// state === 3
|
||||
state = 1;
|
||||
scheduler = asapScheduler.schedule((): void => {
|
||||
state = 0; connection.unsubscribe();
|
||||
}, DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('decodeResponse', (): void => {
|
||||
|
||||
it('expects a non-empty input object', (): void => {
|
||||
expect(
|
||||
(): any => coder.decodeResponse((undefined as any) as JsonRpcResponse)
|
||||
(): any => coder.decodeResponse(undefined as unknown as JsonRpcResponse)
|
||||
).toThrow(/Empty response/);
|
||||
});
|
||||
|
||||
|
||||
@@ -17,18 +17,22 @@ function notEntry (value: any): boolean {
|
||||
return !Array.isArray(value) || value.length !== 2;
|
||||
}
|
||||
|
||||
function compareMapArray (a: Map<any, any>, b: [any, any][]): boolean {
|
||||
// equal number of entries and each entry in the array should match
|
||||
return (a.size === b.length) && !b.some((entry): boolean =>
|
||||
notEntry(entry) || hasMismatch(a.get(entry[0]), entry[1])
|
||||
);
|
||||
}
|
||||
|
||||
// NOTE These are used internally and when comparing objects, expects that
|
||||
// when the second is an Map<string, Codec> that the first has to be as well
|
||||
export default function compareMap (a: Map<any, any>, b?: any): boolean {
|
||||
if (Array.isArray(b)) {
|
||||
// equal number of entries and each entry in the array should match
|
||||
return (a.size === b.length) && !b.some((entry): boolean =>
|
||||
notEntry(entry) || hasMismatch(a.get(entry[0]), entry[1])
|
||||
);
|
||||
return compareMapArray(a, b);
|
||||
} else if (b instanceof Map) {
|
||||
return compareMap(a, [...b.entries()]);
|
||||
return compareMapArray(a, [...b.entries()]);
|
||||
} else if (isObject(b)) {
|
||||
return compareMap(a, Object.entries(b));
|
||||
return compareMapArray(a, Object.entries(b));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -4,16 +4,20 @@
|
||||
|
||||
import { isObject } from '@polkadot/util';
|
||||
|
||||
function compareSetArray (a: Set<any>, b: any[]): boolean {
|
||||
// equal number of entries and each entry in the array should match
|
||||
return (a.size === b.length) && !b.some((entry): boolean => !a.has(entry));
|
||||
}
|
||||
|
||||
// NOTE These are used internally and when comparing objects, expects that
|
||||
// when the second is an Set<string, Codec> that the first has to be as well
|
||||
export default function compareSet (a: Set<any>, b?: any): boolean {
|
||||
if (Array.isArray(b)) {
|
||||
// equal number of entries and each entry in the array should match
|
||||
return (a.size === b.length) && !b.some((entry): boolean => !a.has(entry));
|
||||
return compareSetArray(a, b);
|
||||
} else if (b instanceof Set) {
|
||||
return compareSet(a, [...b.entries()]);
|
||||
return compareSetArray(a, [...b.entries()]);
|
||||
} else if (isObject(b)) {
|
||||
return compareSet(a, Object.entries(b));
|
||||
return compareSetArray(a, Object.entries(b));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -38,64 +38,7 @@ const VERSIONS: (keyof InterfaceTypes)[] = [
|
||||
|
||||
export { TRANSACTION_VERSION as LATEST_EXTRINSIC_VERSION } from './v4/Extrinsic';
|
||||
|
||||
/**
|
||||
* @name GenericExtrinsic
|
||||
* @description
|
||||
* Representation of an Extrinsic in the system. It contains the actual call,
|
||||
* (optional) signature and encodes with an actual length prefix
|
||||
*
|
||||
* {@link https://github.com/paritytech/wiki/blob/master/Extrinsic.md#the-extrinsic-format-for-node}.
|
||||
*
|
||||
* Can be:
|
||||
* - signed, to create a transaction
|
||||
* - left as is, to create an inherent
|
||||
*/
|
||||
export default class Extrinsic extends Base<ExtrinsicVx | ExtrinsicUnknown> implements IExtrinsic {
|
||||
constructor (registry: Registry, value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: CreateOptions = {}) {
|
||||
super(registry, Extrinsic.decodeExtrinsic(registry, value, version));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
private static newFromValue (registry: Registry, value: any, version: number): ExtrinsicVx | ExtrinsicUnknown {
|
||||
if (value instanceof Extrinsic) {
|
||||
return value.raw;
|
||||
}
|
||||
|
||||
const isSigned = (version & BIT_SIGNED) === BIT_SIGNED;
|
||||
const type = VERSIONS[version & UNMASK_VERSION] || VERSIONS[0];
|
||||
|
||||
// we cast here since the VERSION definition is incredibly broad - we don't have a
|
||||
// slice for "only add extrinsic types", and more string definitions become unwieldy
|
||||
return registry.createType(type, value, { isSigned, version }) as ExtrinsicVx;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public static decodeExtrinsic (registry: Registry, value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, version: number = DEFAULT_VERSION): ExtrinsicVx | ExtrinsicUnknown {
|
||||
if (isU8a(value) || Array.isArray(value) || isHex(value)) {
|
||||
return Extrinsic.decodeU8a(registry, u8aToU8a(value), version);
|
||||
} else if (value instanceof registry.createClass('Call')) {
|
||||
return Extrinsic.newFromValue(registry, { method: value }, version);
|
||||
}
|
||||
|
||||
return Extrinsic.newFromValue(registry, value, version);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
private static decodeU8a (registry: Registry, value: Uint8Array, version: number): ExtrinsicVx | ExtrinsicUnknown {
|
||||
if (!value.length) {
|
||||
return Extrinsic.newFromValue(registry, new Uint8Array(), version);
|
||||
}
|
||||
|
||||
const [offset, length] = Compact.decodeU8a(value);
|
||||
const total = offset + length.toNumber();
|
||||
|
||||
assert(total <= value.length, `Extrinsic: length less than remainder, expected at least ${total}, found ${value.length}`);
|
||||
|
||||
const data = value.subarray(offset, total);
|
||||
|
||||
return Extrinsic.newFromValue(registry, data.subarray(1), data[0]);
|
||||
}
|
||||
|
||||
abstract class ExtrinsicBase extends Base<ExtrinsicVx | ExtrinsicUnknown> {
|
||||
/**
|
||||
* @description The arguments passed to for the call, exposes args so it is compatible with [[Call]]
|
||||
*/
|
||||
@@ -214,6 +157,65 @@ export default class Extrinsic extends Base<ExtrinsicVx | ExtrinsicUnknown> impl
|
||||
public get version (): number {
|
||||
return this.type | (this.isSigned ? BIT_SIGNED : BIT_UNSIGNED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name GenericExtrinsic
|
||||
* @description
|
||||
* Representation of an Extrinsic in the system. It contains the actual call,
|
||||
* (optional) signature and encodes with an actual length prefix
|
||||
*
|
||||
* {@link https://github.com/paritytech/wiki/blob/master/Extrinsic.md#the-extrinsic-format-for-node}.
|
||||
*
|
||||
* Can be:
|
||||
* - signed, to create a transaction
|
||||
* - left as is, to create an inherent
|
||||
*/
|
||||
export default class Extrinsic extends ExtrinsicBase implements IExtrinsic {
|
||||
constructor (registry: Registry, value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: CreateOptions = {}) {
|
||||
super(registry, Extrinsic.decodeExtrinsic(registry, value, version));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
private static newFromValue (registry: Registry, value: any, version: number): ExtrinsicVx | ExtrinsicUnknown {
|
||||
if (value instanceof Extrinsic) {
|
||||
return value.raw;
|
||||
}
|
||||
|
||||
const isSigned = (version & BIT_SIGNED) === BIT_SIGNED;
|
||||
const type = VERSIONS[version & UNMASK_VERSION] || VERSIONS[0];
|
||||
|
||||
// we cast here since the VERSION definition is incredibly broad - we don't have a
|
||||
// slice for "only add extrinsic types", and more string definitions become unwieldy
|
||||
return registry.createType(type, value, { isSigned, version }) as ExtrinsicVx;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public static decodeExtrinsic (registry: Registry, value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, version: number = DEFAULT_VERSION): ExtrinsicVx | ExtrinsicUnknown {
|
||||
if (isU8a(value) || Array.isArray(value) || isHex(value)) {
|
||||
return Extrinsic.decodeU8a(registry, u8aToU8a(value), version);
|
||||
} else if (value instanceof registry.createClass('Call')) {
|
||||
return Extrinsic.newFromValue(registry, { method: value }, version);
|
||||
}
|
||||
|
||||
return Extrinsic.newFromValue(registry, value, version);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
private static decodeU8a (registry: Registry, value: Uint8Array, version: number): ExtrinsicVx | ExtrinsicUnknown {
|
||||
if (!value.length) {
|
||||
return Extrinsic.newFromValue(registry, new Uint8Array(), version);
|
||||
}
|
||||
|
||||
const [offset, length] = Compact.decodeU8a(value);
|
||||
const total = offset + length.toNumber();
|
||||
|
||||
assert(total <= value.length, `Extrinsic: length less than remainder, expected at least ${total}, found ${value.length}`);
|
||||
|
||||
const data = value.subarray(offset, total);
|
||||
|
||||
return Extrinsic.newFromValue(registry, data.subarray(1), data[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Injects an already-generated signature into the extrinsic
|
||||
@@ -289,7 +291,7 @@ export default class Extrinsic extends Base<ExtrinsicVx | ExtrinsicUnknown> impl
|
||||
*/
|
||||
public toU8a (isBare?: boolean): Uint8Array {
|
||||
// we do not apply bare to the internal values, rather this only determines out length addition,
|
||||
// where we strip all lengths this creates an un-decodable extrinsic
|
||||
// where we strip all lengths this creates an extrinsic that cannot be decoded
|
||||
const encoded = u8aConcat(new Uint8Array([this.version]), this.raw.toU8a());
|
||||
|
||||
return isBare
|
||||
|
||||
@@ -214,25 +214,21 @@ export default class ExtrinsicEra extends Enum implements IExtrinsicEra {
|
||||
/** @internal */
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
private static decodeExtrinsicEra (value: IExtrinsicEra | MortalMethod | MortalEnumDef | ImmortalEnumDef | Uint8Array | string = new Uint8Array()): Uint8Array | Object | undefined {
|
||||
if (!value) {
|
||||
return new Uint8Array([0]);
|
||||
} else if (value instanceof ExtrinsicEra) {
|
||||
if (value instanceof ExtrinsicEra) {
|
||||
return ExtrinsicEra.decodeExtrinsicEra(value.toU8a());
|
||||
} else if (isHex(value)) {
|
||||
return ExtrinsicEra.decodeExtrinsicEra(hexToU8a(value));
|
||||
} else if (isU8a(value)) {
|
||||
return (!value.length || value[0] === 0)
|
||||
} else if (!value || isU8a(value)) {
|
||||
return (!value?.length || value[0] === 0)
|
||||
? new Uint8Array([0])
|
||||
: new Uint8Array([1, value[0], value[1]]);
|
||||
} else if (isObject(value)) {
|
||||
// this is to de-serialize from JSON
|
||||
if ((value as MortalEnumDef).MortalEra) {
|
||||
return { MortalEra: (value as MortalEnumDef).MortalEra };
|
||||
} else if ((value as ImmortalEnumDef).ImmortalEra) {
|
||||
return { ImmortalEra: (value as ImmortalEnumDef).ImmortalEra };
|
||||
}
|
||||
|
||||
return { MortalEra: value };
|
||||
return (value as MortalEnumDef).MortalEra
|
||||
? { MortalEra: (value as MortalEnumDef).MortalEra }
|
||||
: (value as ImmortalEnumDef).ImmortalEra
|
||||
? { ImmortalEra: (value as ImmortalEnumDef).ImmortalEra }
|
||||
: { MortalEra: value };
|
||||
}
|
||||
|
||||
throw new Error('Invalid data passed to Era');
|
||||
@@ -242,11 +238,9 @@ export default class ExtrinsicEra extends Enum implements IExtrinsicEra {
|
||||
* @description Override the encoded length method
|
||||
*/
|
||||
public get encodedLength (): number {
|
||||
if (this.index === 0) {
|
||||
return this.asImmortalEra.encodedLength;
|
||||
} else {
|
||||
return this.asMortalEra.encodedLength;
|
||||
}
|
||||
return this.isImmortalEra
|
||||
? this.asImmortalEra.encodedLength
|
||||
: this.asMortalEra.encodedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,10 @@ describe('Vote', (): void => {
|
||||
expect(new Vote(registry, false).isAye).toBe(false);
|
||||
});
|
||||
|
||||
it('constructs via undefined', (): void => {
|
||||
expect(new Vote(registry).isNay).toBe(true);
|
||||
});
|
||||
|
||||
it('has isYay for positive', (): void => {
|
||||
// eslint-disable-next-line no-new-wrappers
|
||||
expect(new Vote(registry, true).isAye).toBe(true);
|
||||
|
||||
@@ -41,9 +41,7 @@ function decodeVoteU8a (value: Uint8Array): Uint8Array {
|
||||
|
||||
/** @internal */
|
||||
function decodeVote (registry: Registry, value?: InputTypes): Uint8Array {
|
||||
if (isUndefined(value)) {
|
||||
return decodeVoteBool(false);
|
||||
} else if (value instanceof Boolean || isBoolean(value)) {
|
||||
if (isUndefined(value) || value instanceof Boolean || isBoolean(value)) {
|
||||
return decodeVoteBool(new Bool(registry, value).isTrue);
|
||||
} else if (isNumber(value)) {
|
||||
return decodeVoteBool(value < 0);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import Metadata from '@polkadot/metadata/Metadata';
|
||||
import rpcMetadataV0 from '@polkadot/metadata/Metadata/v0/static';
|
||||
import rpcMetadataV1 from '@polkadot/metadata/Metadata/v1/static';
|
||||
import rpcMetadata from '@polkadot/metadata/Metadata/static';
|
||||
|
||||
import { TypeRegistry } from '../../create';
|
||||
@@ -16,7 +16,7 @@ describe('EventRecord', (): void => {
|
||||
describe('EventRecordTo76', (): void => {
|
||||
beforeEach((): void => {
|
||||
// eslint-disable-next-line no-new
|
||||
new Metadata(registry, rpcMetadataV0);
|
||||
new Metadata(registry, rpcMetadataV1);
|
||||
});
|
||||
|
||||
it('decodes correctly', (): void => {
|
||||
|
||||
Reference in New Issue
Block a user