refactor: Metadata overhaul (#913)

* Replace part1

* Replace part2

* Replace part3

* Replace part5

* Replace part6

* Fix small bugs

* Fix double map toString

* Small fixes

* Update to v4

* Fix docs script

* Grumbles

* Alphabetical

* Reads better

* comment

* module to modul
This commit is contained in:
Amaury Martiny
2019-06-12 16:45:45 +12:00
committed by Ian He
parent 194077033a
commit 2699dcfc9c
77 changed files with 1198 additions and 4550 deletions
+1 -1
View File
@@ -424,7 +424,7 @@ export default abstract class ApiBase<CodecResult, SubscriptionResult> implement
injectNodeCompat(this._runtimeVersion as RuntimeVersion);
const extrinsics = extrinsicsFromMeta(this.runtimeMetadata.asV0);
const extrinsics = extrinsicsFromMeta(this.runtimeMetadata);
const storage = storageFromMeta(this.runtimeMetadata);
this._extrinsics = this.decorateExtrinsics(extrinsics, this.onCall);
+81 -65
View File
@@ -3,78 +3,94 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import BN from 'bn.js';
import storage from '@plugnet/storage/static';
import fromMetadata from '@plugnet/storage/fromMetadata';
import { Storage } from '@plugnet/storage/types';
import Metadata from '@plugnet/types/Metadata';
import rpcMetadataV3 from '@plugnet/types/Metadata/v3/static';
import rpcMetadataV4 from '@plugnet/types/Metadata/v4/static';
import Api from '.';
const ADDR_ONE = '5DkQbYAExs3M2sZgT1Ec3mKfZnAQCL4Dt9beTCknkCUn5jzo';
const ADDR_TWO = '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCtGwF';
const ENC_ONE = '0x4af2c53fce3ec33c6ccccf22e926f1a7';
const ENC_TWO = '0x3e62f7ed6e788e1337bce2a97b68a12a';
function formattingTests (version: string, storage: Storage, encodedValues: [String, String]) {
const [ENC_ONE, ENC_TWO] = encodedValues;
describe('formatting', () => {
let api: Api;
let provider: any;
describe(`formatting with Metadata ${version}`, () => {
let api: Api;
let provider: any;
beforeEach(() => {
provider = {
send: jest.fn((method, params) =>
Promise.resolve('0x0102')
),
subscribe: jest.fn((type, method, params, subscription) =>
subscription(null, {
block: '0x1234',
changes: [
[ENC_ONE, '0x0102'],
[ENC_TWO, '0x0201']
]
})
)
};
api = new Api(provider);
beforeEach(() => {
provider = {
send: jest.fn((method, params) =>
Promise.resolve('0x0102')
),
subscribe: jest.fn((type, method, params, subscription) =>
subscription(null, {
block: '0x1234',
changes: [
[ENC_ONE, '0x0102'],
[ENC_TWO, '0x0201']
]
})
)
};
api = new Api(provider);
});
it('encodes key (with params), decoding response', () => {
return api.state
.getStorage(
[storage.balances.freeBalance, ADDR_ONE]
)
.then((value) => {
expect(
provider.send
).toHaveBeenCalledWith(
'state_getStorage',
[ENC_ONE]
);
expect(value.toNumber()).toEqual(513);
});
});
it('encodes multiple keys, decoding multiple results', (done) => {
return api.state.subscribeStorage(
[
[storage.balances.freeBalance, ADDR_ONE],
[storage.balances.freeBalance, ADDR_TWO]
],
(value: any) => {
console.error(value);
expect(
provider.subscribe
).toHaveBeenCalledWith(
'state_storage',
'state_subscribeStorage',
[[ENC_ONE, ENC_TWO]],
expect.anything()
);
expect(
value.map((balance: BN) =>
balance.toNumber()
)
).toEqual([513, 258]);
done();
});
});
});
}
it('encodes key (with params), decoding response', () => {
return api.state
.getStorage(
[storage.balances.freeBalance, ADDR_ONE]
)
.then((value) => {
expect(
provider.send
).toHaveBeenCalledWith(
'state_getStorage',
[ENC_ONE]
);
expect(value.toNumber()).toEqual(513);
});
});
it('encodes multiple keys, decoding multiple results', (done) => {
return api.state.subscribeStorage(
[
[storage.balances.freeBalance, ADDR_ONE],
[storage.balances.freeBalance, ADDR_TWO]
],
(value: any) => {
console.error(value);
expect(
provider.subscribe
).toHaveBeenCalledWith(
'state_storage',
'state_subscribeStorage',
[[ENC_ONE, ENC_TWO]],
expect.anything()
);
expect(
value.map((balance: BN) =>
balance.toNumber()
)
).toEqual([513, 258]);
done();
});
});
});
formattingTests(
'v3',
fromMetadata(new Metadata(rpcMetadataV3)),
['0x4af2c53fce3ec33c6ccccf22e926f1a7', '0x3e62f7ed6e788e1337bce2a97b68a12a']
);
formattingTests(
'v4',
fromMetadata(new Metadata(rpcMetadataV4)),
['0xec8f96437274a883afcac82d01a9defeb68209cd4f2c084632813692aa5e65ad', '0x1dbb0224910f42a14e7f1406b24c6fe8157296691b02a78756e01946038fffab']
);
+2 -2
View File
@@ -11,7 +11,7 @@ import interfaces from '@plugnet/jsonrpc';
import testKeyring from '@plugnet/keyring/testing';
import storage from '@plugnet/storage/static';
import { Codec } from '@plugnet/types/types';
import metadata from '@plugnet/types/Metadata/v0/static';
import rpcMetadataV4 from '@plugnet/types/Metadata/v4/static';
import { Header, RuntimeVersion } from '@plugnet/types';
import { bnToU8a, logger, u8aToHex } from '@plugnet/util';
import { randomAsU8a } from '@plugnet/util-crypto';
@@ -50,7 +50,7 @@ export default class Mock implements ProviderInterface {
);
},
'system_chain': (): string => 'mockChain',
'state_getMetadata': (): string => metadata,
'state_getMetadata': (): string => rpcMetadataV4,
'system_name': (): string => 'mockClient',
'system_version': (): string => '9.8.7'
};
@@ -1,58 +0,0 @@
// Copyright 2017-2019 @polkadot/extrinsics 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 { RuntimeModuleMetadata } from '@plugnet/types/Metadata/v0/Modules';
import { Methods, ModulesWithMethods } from '@plugnet/types/primitive/Method';
import MetadataV0 from '@plugnet/types/Metadata/v0';
import { stringCamelCase } from '@plugnet/util';
import createUnchecked from './utils/createUnchecked';
import extrinsics from '.';
/**
* Extend a storage object with the storage modules & module functions present
* in the metadata.
*
* @param extrinsics - An extrinsics object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromMetadata (metadata: MetadataV0): ModulesWithMethods {
let indexCount = -1;
const findIndex = (prefix: string): number => {
indexCount++;
const mod = metadata.calls.find((item) => item.prefix.toString() === prefix);
if (!mod) {
console.error(`Unable to find module index for '${prefix}'`);
// compatible with old versions
return indexCount;
}
return mod.index.toNumber();
};
return metadata.modules.reduce((result, meta: RuntimeModuleMetadata) => {
if (!meta.module.call || !meta.module.call.functions.length) {
return result;
}
const prefix = stringCamelCase(meta.prefix.toString());
const index = findIndex(meta.prefix.toString());
result[prefix] = meta.module.call.functions.reduce((newModule, funcMeta) => {
// extrinsics.balances.set_balance -> extrinsics.balances.setBalance
const funcName = stringCamelCase(funcMeta.name.toString());
newModule[funcName] = createUnchecked(prefix, funcName, index, funcMeta);
return newModule;
}, {} as Methods);
return result;
}, { ...extrinsics });
}
@@ -0,0 +1,48 @@
// Copyright 2017-2019 @polkadot/extrinsics 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 { FunctionMetadata } from '@polkadot/types/Metadata/v4/Calls';
import { MethodFunction } from '@polkadot/types/primitive/Method';
import { Method } from '@polkadot/types';
import { assert, stringCamelCase } from '@polkadot/util';
/**
* From the metadata of a function in the module's storage, generate the function
* that will return the an [[MethodFunction]].
*
* @param section - Name of the module section.
* @param sectionIndex - Index of the module section in the modules array.
* @param methodIndex - Index of the method inside the section.
* @param callMetadata - Metadata of the call function.
*/
export default function createDescriptor (
section: string,
sectionIndex: number,
methodIndex: number,
callMetadata: FunctionMetadata
): MethodFunction {
const callIndex = new Uint8Array([sectionIndex, methodIndex]);
const expectedArgs = callMetadata.args;
const funcName = stringCamelCase(callMetadata.name.toString());
const extrinsicFn = (...args: any[]): Method => {
assert(
expectedArgs.length.valueOf() === args.length,
`Extrinsic ${section}.${funcName} expects ${expectedArgs.length.valueOf()} arguments, got ${args.length}.`
);
return new Method({
args,
callIndex
}, callMetadata);
};
extrinsicFn.callIndex = callIndex;
extrinsicFn.meta = callMetadata;
extrinsicFn.method = funcName;
extrinsicFn.section = section;
extrinsicFn.toJSON = (): any =>
callMetadata.toJSON();
return extrinsicFn as MethodFunction;
}
@@ -3,13 +3,13 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Extrinsic, Metadata } from '@plugnet/types';
import json from '@plugnet/types/Metadata/v0/static';
import json from '@plugnet/types/Metadata/v4/static';
import fromMetadata from './fromMetadata';
import fromV4 from '.';
// Use the pre-generated metadata
const metadata = new Metadata(json).asV0;
const newExtrinsics = fromMetadata(metadata);
const metadata = new Metadata(json);
const newExtrinsics = fromV4(metadata);
describe('fromMetadata', () => {
it('should throw if an incorrect number of args is supplied', () => {
@@ -0,0 +1,36 @@
// Copyright 2017-2019 @polkadot/extrinsics 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 { ModuleMetadata } from '@polkadot/types/Metadata/v4/Metadata';
import { Methods, ModulesWithMethods } from '@polkadot/types/primitive/Method';
import Metadata from '@polkadot/types/Metadata';
import { stringCamelCase } from '@polkadot/util';
import extrinsics from '../';
import createUnchecked from './createUnchecked';
/**
* Extend a storage object with the storage modules & module functions present
* in the metadata.
*
* @param extrinsics - An extrinsics object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromMetadata (metadata: Metadata): ModulesWithMethods {
return metadata.asV4.modules
.filter((modul) => modul.calls.isSome)
.reduce((result, modul: ModuleMetadata, sectionIndex) => {
const prefix = stringCamelCase(modul.prefix.toString());
result[prefix] = modul.calls.unwrap().reduce((newModule, callMetadata, methodIndex) => {
const funcName = stringCamelCase(callMetadata.name.toString());
newModule[funcName] = createUnchecked(prefix, sectionIndex, methodIndex, callMetadata);
return newModule;
}, {} as Methods);
return result;
}, { ...extrinsics });
}
+2 -2
View File
@@ -3,12 +3,12 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Metadata } from '@plugnet/types';
import metadataRpc from '@plugnet/types/Metadata/v0/static';
import metadataRpc from '@plugnet/types/Metadata/v4/static';
import { ModulesWithMethods } from '@plugnet/types/primitive/Method';
import fromMetadata from './fromMetadata';
const staticMetadata: ModulesWithMethods = fromMetadata(
new Metadata(metadataRpc).asV0
new Metadata(metadataRpc)
);
export default staticMetadata;
@@ -1,44 +0,0 @@
// Copyright 2017-2019 @polkadot/extrinsics 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 { FunctionMetadata } from '@plugnet/types/Metadata/v0/Modules';
import { MethodFunction } from '@plugnet/types/primitive/Method';
import { Method } from '@plugnet/types';
import { assert } from '@plugnet/util';
/**
* From the metadata of a function in the module's storage, generate the function
* that will return the an UncheckExtrinsic.
*
* @param index - Index of the module section in the modules array.
*/
export default function createDescriptor (
section: string,
method: string,
index: number,
meta: FunctionMetadata
): MethodFunction {
const callIndex = new Uint8Array([index, meta.id.toNumber()]);
let extrinsicFn: any;
const expectedArgs = Method.filterOrigin(meta);
extrinsicFn = (...args: any[]): Method => {
assert(expectedArgs.length.valueOf() === args.length, `Extrinsic ${section}.${method} expects ${expectedArgs.length.valueOf()} arguments, got ${args.length}.`);
return new Method({
args,
callIndex
}, meta);
};
extrinsicFn.callIndex = callIndex;
extrinsicFn.meta = meta;
extrinsicFn.method = method;
extrinsicFn.section = section;
extrinsicFn.toJSON = (): any =>
meta.toJSON();
return extrinsicFn as MethodFunction;
}
@@ -26,8 +26,8 @@ describe('createFunction', () => {
'authorityCount',
{ type: {} } as any,
{
isUnhashed: true,
key: ':auth:len'
key: ':auth:len',
skipHashing: true
}
).method
).toEqual('authorityCount');
@@ -42,8 +42,8 @@ describe('createFunction', () => {
'authorityCount',
{ type: {} } as any,
{
isUnhashed: true,
key
key,
skipHashing: true
}
)()
).toEqual(
@@ -10,8 +10,8 @@ import { assert, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat }
import getHasher from './getHasher';
export interface CreateItemOptions {
isUnhashed?: boolean;
key?: string;
skipHashing?: boolean; // We don't hash the keys defined in ./substrate.ts
}
/**
@@ -52,14 +52,13 @@ export default function createFunction (section: Text | string, method: Text | s
// StorageKey is a Bytes, so is length-prefixed
return Compact.addLengthPrefix(
options.isUnhashed
options.skipHashing
? key
: hasher(key)
);
};
if (meta.type.isMap && meta.type.asMap.isLinked) {
// TODO: there needs some better way to do this
const keyHash = new U8a(hasher(`head of ${stringKey}`));
const keyFn: any = () => keyHash;
keyFn.meta = new StorageFunctionMetadata({
@@ -7,26 +7,26 @@ import { Metadata } from '@plugnet/types';
import json from '@plugnet/types/Metadata/v4/static';
import { u8aToHex } from '@plugnet/util';
import fromv4 from '.';
import fromMetadata from '.';
const keyring = testingPairs({ type: 'ed25519' });
// Use the pre-generated metadata
const metadata = new Metadata(json).asV4;
const newStorage = fromv4(metadata);
const metadata = new Metadata(json);
const storage = fromMetadata(metadata);
describe('fromv4', () => {
describe('fromMetadata', () => {
it('should throw if the storage function expects an argument', () => {
expect(() => newStorage.balances.freeBalance()).toThrowError(/expects one argument/);
expect(() => storage.balances.freeBalance()).toThrowError(/expects one argument/);
});
it('should return a value if the storage function does not expect an argument', () => {
expect(() => newStorage.timestamp.now()).not.toThrow();
expect(() => storage.timestamp.now()).not.toThrow();
});
it('should return the correct length-prefixed storage key', () => {
expect(
u8aToHex(
newStorage.balances.freeBalance(keyring.alice.address())
storage.balances.freeBalance(keyring.alice.address())
)
).toEqual(
'0x807f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587bb'
@@ -1,27 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { Storage } from '../types';
import Metadata from '@plugnet/types/Metadata';
import fromV0 from './v0';
import fromV4 from './v4';
/**
* Extend a storage object with the storage modules & module functions present
* in the metadata.
*
* @param storage - A storage object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromMetadata (metadata: Metadata): Storage {
// For v0-v3 we convert to v0, and use the fromV0 function to parse
if ([0, 1, 2, 3].includes(metadata.version)) {
return fromV0(metadata.asV0);
}
// For v4, we use fromV4 function
return fromV4(metadata.asV4);
}
@@ -2,6 +2,36 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import fromMetadata from './fromMetadata';
import { ModuleStorage, Storage } from '../types';
export default fromMetadata;
import Metadata from '@polkadot/types/Metadata';
import { stringLowerFirst } from '@polkadot/util';
import createFunction from './createFunction';
import { storage } from './storage';
/**
* Extend a storage object with the storage modules & module functions present
* in the metadata.
*
* @param storage - A storage object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromMetadata (metadata: Metadata): Storage {
return metadata.asV4.modules.reduce((result, moduleMetadata) => {
if (moduleMetadata.storage.isNone) {
return result;
}
const prefix = moduleMetadata.prefix;
// For access, we change the index names, i.e. Balances.FreeBalance -> balances.freeBalance
result[stringLowerFirst(prefix.toString())] = moduleMetadata.storage.unwrap().reduce((newModule, storageFnMeta) => {
newModule[stringLowerFirst(storageFnMeta.name.toString())] = createFunction(prefix, storageFnMeta.name, storageFnMeta);
return newModule;
}, {} as ModuleStorage);
return result;
}, { ...storage });
}
@@ -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 { Storage } from '../../types';
import { Storage } from '../types';
import * as substrate from './substrate';
export const storage: Storage = {
@@ -25,8 +25,8 @@ const createRuntimeFunction = (method: string, key: string, { documentation, typ
toJSON: (): any => key
} as StorageFunctionMetadata,
{
isUnhashed: true,
key
key,
skipHashing: true
}
);
@@ -1,74 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { PlainType, StorageFunctionMetadata, StorageFunctionModifier, StorageFunctionType } from '@plugnet/types/Metadata/v0/Storage';
import { StorageFunction } from '@plugnet/types/primitive/StorageKey';
import { Compact, Text, createType, StorageKey, Bytes, U8a } from '@plugnet/types';
import { assert, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat } from '@plugnet/util';
import { xxhashAsU8a } from '@plugnet/util-crypto';
export interface CreateItemOptions {
isUnhashed?: boolean;
key?: string;
}
/**
* From the schema of a function in the module's storage, generate the function
* that will return the correct storage key.
*
* @param schema - The function's definition schema to create the function from.
* The schema is taken from state_getMetadata.
* @param options - Additional options when creating the function. These options
* are not known at runtime (from state_getMetadata), they need to be supplied
* by us manually at compile time.
*/
export default function createFunction (section: Text | string, method: Text | string, meta: StorageFunctionMetadata, options: CreateItemOptions = {}): StorageFunction {
const stringKey = options.key
? options.key
: `${section.toString()} ${method.toString()}`;
const rawKey = stringToU8a(stringKey);
// Can only have zero or one argument:
// - storage.balances.freeBalance(address)
// - storage.timestamp.blockPeriod()
const storageFn = (arg?: any): Uint8Array => {
let key = rawKey;
if (meta.type.isMap) {
assert(!isUndefined(arg) && !isNull(arg), `${meta.name} expects one argument`);
const type = meta.type.asMap.key.toString();
const param = createType(type, arg).toU8a(false);
key = u8aConcat(key, param);
}
// StorageKey is a Bytes, so is length-prefixed
return Compact.addLengthPrefix(
options.isUnhashed
? key
: xxhashAsU8a(key, 128)
);
};
if (meta.type.isMap && meta.type.asMap.isLinked) {
// TODO: there needs some better way to do this
const keyHash = new U8a(xxhashAsU8a(`head of ${stringKey}`, 128));
const keyFn: any = () => keyHash;
keyFn.meta = new StorageFunctionMetadata({
name: meta.name,
modifier: new StorageFunctionModifier('Required'),
type: new StorageFunctionType(new PlainType(meta.type.asMap.key), 0),
fallback: new Bytes(),
documentation: meta.documentation
});
storageFn.headKey = new StorageKey(keyFn);
}
storageFn.meta = meta;
storageFn.method = stringLowerFirst(method.toString());
storageFn.section = stringLowerFirst(section.toString());
storageFn.toJSON = (): any => meta.toJSON();
return storageFn as StorageFunction;
}
@@ -1,37 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { ModuleStorage, Storage } from '../../types';
import MetadataV0 from '@plugnet/types/Metadata/v0';
import { stringLowerFirst } from '@plugnet/util';
import createFunction from './createFunction';
import { storage } from './storage';
/**
* Extend a storage object with the storage modules & module functions present
* in the metadata.
*
* @param storage - A storage object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromV0 (metadata: MetadataV0): Storage {
return metadata.modules.reduce((result, moduleMetadata) => {
if (moduleMetadata.storage.isNone) {
return result;
}
const prefix = moduleMetadata.storage.unwrap().prefix;
// For access, we change the index names, i.e. Balances.FreeBalance -> balances.freeBalance
result[stringLowerFirst(prefix.toString())] = moduleMetadata.storage.unwrap().functions.reduce((newModule, func) => {
newModule[stringLowerFirst(func.name.toString())] = createFunction(prefix, func.name, func);
return newModule;
}, {} as ModuleStorage);
return result;
}, { ...storage });
}
@@ -1,61 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { StorageFunctionMetadata, StorageFunctionModifier, StorageFunctionType } from '@plugnet/types/Metadata/v0/Storage';
import { StorageFunction } from '@plugnet/types/primitive/StorageKey';
import { Text, Vector } from '@plugnet/types';
import createFunction from './createFunction';
interface SubstrateMetadata {
documentation: string;
type: string;
}
// Small helper function to factorize code on this page.
const createRuntimeFunction = (method: string, key: string, { documentation, type }: SubstrateMetadata): StorageFunction =>
createFunction(
new Text('Substrate'),
new Text(method),
{
documentation: new Vector(Text, [documentation]),
modifier: new StorageFunctionModifier(1), // default
type: new StorageFunctionType(type, 0),
toJSON: (): any => key
} as StorageFunctionMetadata,
{
isUnhashed: true,
key
}
);
export const code = createRuntimeFunction('code', ':code', {
documentation: 'Wasm code of the runtime.',
type: 'Bytes'
});
export const heapPages = createRuntimeFunction('heapPages', ':heappages', {
documentation: 'Number of wasm linear memory pages required for execution of the runtime.',
type: 'u64'
});
export const authorityCount = createRuntimeFunction('authorityCount', ':auth:len', {
documentation: 'Number of authorities.',
type: 'u32'
});
export const authorityPrefix = createRuntimeFunction('authorityPrefix', ':auth:', {
documentation: 'Prefix under which authorities are stored.',
type: 'u32'
});
export const extrinsicIndex = createRuntimeFunction('extrinsicIndex', ':extrinsic_index', {
documentation: 'Current extrinsic index (u32) is stored under this key.',
type: 'u32'
});
export const changesTrieConfig = createRuntimeFunction('changesTrieConfig', ':changes_trie', {
documentation: 'Changes trie configuration is stored under this key.',
type: 'u32'
});
@@ -1,33 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { u8aToHex } from '@plugnet/util';
import { Metadata } from '@plugnet/types';
import json from '@plugnet/types/Metadata/v0/static';
import fromv0 from '.';
// Use the pre-generated metadata
const metadata = new Metadata(json).asV0;
const newStorage = fromv0(metadata);
describe('fromv0', () => {
it('should throw if the storage function expects an argument', () => {
expect(() => newStorage.balances.freeBalance()).toThrowError(/expects one argument/);
});
it('should return a value if the storage function does not expect an argument', () => {
expect(() => newStorage.timestamp.now()).not.toThrow();
});
it('should return the correct length-prefixed storage key', () => {
expect(
u8aToHex(
newStorage.balances.freeBalance('5DkQbYAExs3M2sZgT1Ec3mKfZnAQCL4Dt9beTCknkCUn5jzo')
)
).toEqual(
'0x404af2c53fce3ec33c6ccccf22e926f1a7'
);
});
});
@@ -1,56 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { stringToU8a, u8aConcat } from '@plugnet/util';
import createFunction from './createFunction';
describe('createFunction', () => {
it('should create timestamp.now correctly', () => {
expect(
createFunction(
'Timestamp',
'Now',
{ type: {} } as any
)()
).toEqual(
Uint8Array.from([64, 14, 73, 68, 207, 217, 141, 111, 76, 195, 116, 209, 111, 90, 78, 63, 156]) // Length-prefixed
);
});
it('allows overrides on key (keeping name)', () => {
expect(
createFunction(
'Substrate',
'authorityCount',
{ type: {} } as any,
{
isUnhashed: true,
key: ':auth:len'
}
).method
).toEqual('authorityCount');
});
it('allows overrides on key (unhashed)', () => {
const key = ':auth:len';
expect(
createFunction(
'Substrate',
'authorityCount',
{ type: {} } as any,
{
isUnhashed: true,
key
}
)()
).toEqual(
u8aConcat(
Uint8Array.from([key.length << 2]),
stringToU8a(':auth:len')
)
);
});
});
@@ -1,37 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { ModuleStorage, Storage } from '../../types';
import MetadataV4 from '@plugnet/types/Metadata/v4';
import { stringLowerFirst } from '@plugnet/util';
import createFunction from './createFunction';
import { storage } from './storage';
/**
* Extend a storage object with the storage modules & module functions present
* in the metadata.
*
* @param storage - A storage object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromV4 (metadata: MetadataV4): Storage {
return metadata.modules.reduce((result, moduleMetadata) => {
if (moduleMetadata.storage.isNone) {
return result;
}
const prefix = moduleMetadata.prefix;
// For access, we change the index names, i.e. Balances.FreeBalance -> balances.freeBalance
result[stringLowerFirst(prefix.toString())] = moduleMetadata.storage.unwrap().reduce((newModule, storageFnMeta) => {
newModule[stringLowerFirst(storageFnMeta.name.toString())] = createFunction(prefix, storageFnMeta.name, storageFnMeta);
return newModule;
}, {} as ModuleStorage);
return result;
}, { ...storage });
}
@@ -1,17 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { storage } from './storage';
describe('storage', () => {
it('should return well known keys', () => {
expect(typeof storage.substrate).toBe('object');
expect(storage.substrate.authorityCount).toBeTruthy();
expect(storage.substrate.authorityPrefix).toBeTruthy();
expect(storage.substrate.changesTrieConfig).toBeTruthy();
expect(storage.substrate.code).toBeTruthy();
expect(storage.substrate.extrinsicIndex).toBeTruthy();
expect(storage.substrate.heapPages).toBeTruthy();
});
});
@@ -1,10 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { Storage } from '../../types';
import * as substrate from './substrate';
export const storage: Storage = {
substrate // Prefill storage with well known keys, as not returned by state_getMetadata
};
@@ -1,33 +0,0 @@
// Copyright 2017-2019 @polkadot/storage 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 { authorityCount, authorityPrefix, changesTrieConfig, code, extrinsicIndex, heapPages } from './substrate';
describe('substrate', () => {
it('authorityCount should return the correct storage key', () => {
expect(authorityCount()).toEqual(Uint8Array.from([36, 58, 97, 117, 116, 104, 58, 108, 101, 110])); // Length-prefixed
});
it('authorityPrefix should return the correct storage key', () => {
expect(authorityPrefix()).toEqual(Uint8Array.from([24, 58, 97, 117, 116, 104, 58])); // Length-prefixed
});
it('changesTrieConfig should return the correct storage key', () => {
expect(changesTrieConfig()).toEqual(Uint8Array.from([52, 58, 99, 104, 97, 110, 103, 101, 115, 95, 116, 114, 105, 101])); // Length-prefixed
});
it('code should return the correct storage key', () => {
expect(code()).toEqual(Uint8Array.from([20, 58, 99, 111, 100, 101])); // Length-prefixed
});
it('extrinsicIndex should return the correct storage key', () => {
expect(extrinsicIndex()).toEqual(
Uint8Array.from([64, 58, 101, 120, 116, 114, 105, 110, 115, 105, 99, 95, 105, 110, 100, 101, 120]) // Length-prefixed
);
});
it('heapPages should return the correct storage key', () => {
expect(heapPages()).toEqual(Uint8Array.from([40, 58, 104, 101, 97, 112, 112, 97, 103, 101, 115])); // Length-prefixed
});
});
+1 -1
View File
@@ -2,6 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { storage } from './fromMetadata/v0/storage';
import { storage } from './fromMetadata/storage';
export default storage;
+1 -1
View File
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Metadata } from '@plugnet/types';
import metadataRpc from '@plugnet/types/Metadata/v0/static';
import metadataRpc from '@plugnet/types/Metadata/v4/static';
import fromMetadata from './fromMetadata';
@@ -2,8 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { MetadataInterface } from './types';
import { assert, isUndefined } from '@plugnet/util';
import EnumType from '../codec/EnumType';
@@ -15,10 +13,10 @@ import MetadataV1 from './v1';
import MetadataV2 from './v2';
import MetadataV3 from './v3';
import MetadataV4 from './v4';
import v1ToV0 from './v1/toV0';
import v2ToV1 from './v2/toV1';
import v3ToV2 from './v3/toV2';
import v4ToV3 from './v4/toV3';
import v0ToV1 from './v0/toV1';
import v1ToV2 from './v1/toV2';
import v2ToV3 from './v2/toV3';
import v3ToV4 from './v3/toV4';
class MetadataDeprecated extends Null {
}
@@ -134,11 +132,11 @@ class MetadataEnum extends EnumType<MetadataDeprecated | MetadataV0 | MetadataV1
* @description
* The versioned runtime metadata as a decoded structure
*/
export default class MetadataVersioned extends Struct implements MetadataInterface {
private _convertedV0?: MetadataV0;
export default class MetadataVersioned extends Struct {
private _convertedV1?: MetadataV1;
private _convertedV2?: MetadataV2;
private _convertedV3?: MetadataV3;
private _convertedV4?: MetadataV4;
constructor (value?: any) {
super({
@@ -172,29 +170,23 @@ export default class MetadataVersioned extends Struct implements MetadataInterfa
* @description Returns the wrapped metadata as a V0 object
*/
get asV0 (): MetadataV0 {
if (this.metadata.version === 0) {
return this.metadata.asV0;
}
assert(this.metadata.version === 0, `Cannot convert metadata from v${this.metadata.version} to v0`);
if (isUndefined(this._convertedV0)) {
this._convertedV0 = v1ToV0(this.asV1);
}
return this._convertedV0;
return this.metadata.asV0;
}
/**
* @description Returns the wrapped values as a V1 object
*/
get asV1 (): MetadataV1 {
assert(this.metadata.version <= 1, `Cannot convert metadata from v${this.metadata.version} to v1`);
if (this.metadata.version === 1) {
return this.metadata.asV1;
}
assert([2, 3, 4].includes(this.metadata.version), `Cannot convert metadata from v${this.metadata.version} to v1`);
if (isUndefined(this._convertedV1)) {
this._convertedV1 = v2ToV1(this.asV2);
this._convertedV1 = v0ToV1(this.asV0);
}
return this._convertedV1;
@@ -204,14 +196,14 @@ export default class MetadataVersioned extends Struct implements MetadataInterfa
* @description Returns the wrapped values as a V2 object
*/
get asV2 (): MetadataV2 {
assert(this.metadata.version <= 2, `Cannot convert metadata from v${this.metadata.version} to v2`);
if (this.metadata.version === 2) {
return this.metadata.asV2;
}
assert([3, 4].includes(this.metadata.version), `Cannot convert metadata from v${this.metadata.version} to v2`);
if (isUndefined(this._convertedV2)) {
this._convertedV2 = v3ToV2(this.asV3);
this._convertedV2 = v1ToV2(this.asV1);
}
return this._convertedV2;
@@ -221,29 +213,37 @@ export default class MetadataVersioned extends Struct implements MetadataInterfa
* @description Returns the wrapped values as a V3 object
*/
get asV3 (): MetadataV3 {
assert(this.metadata.version <= 3, `Cannot convert metadata from v${this.metadata.version} to v3`);
if (this.metadata.version === 3) {
return this.metadata.asV3;
}
assert([4].includes(this.metadata.version), `Cannot convert metadata from v${this.metadata.version} to v3`);
if (isUndefined(this._convertedV3)) {
this._convertedV3 = v4ToV3(this.asV4);
this._convertedV3 = v2ToV3(this.asV2);
}
return this._convertedV3;
}
getUniqTypes (throwError: boolean): Array<string> {
return (this.metadata.value as any as MetadataInterface).getUniqTypes(throwError);
return this.asV4.getUniqTypes(throwError);
}
/**
* @description Returns the wrapped values as a V3 object
* @description Returns the wrapped values as a V4 object
*/
get asV4 (): MetadataV4 {
assert(this.metadata.version === 4, `Cannot convert metadata from v${this.metadata.version} to v4`);
assert(this.metadata.version <= 4, `Cannot convert metadata from v${this.metadata.version} to v3`);
return this.metadata.asV4;
if (this.metadata.version === 4) {
return this.metadata.asV4;
}
if (isUndefined(this._convertedV4)) {
this._convertedV4 = v3ToV4(this.asV3);
}
return this._convertedV4;
}
}
+1 -1
View File
@@ -2,6 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import metadata from './v3/static';
import metadata from './v4/static';
export default metadata;
+5 -1
View File
@@ -2,6 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export interface MetadataInterface {
import { Vector } from '../codec';
import { Codec } from '../types';
export interface MetadataInterface<Modules extends Codec> extends Codec {
modules: Vector<Modules>;
getUniqTypes (throwError: boolean): Array<string>;
}
@@ -0,0 +1,68 @@
// Copyright 2017-2019 @polkadot/types 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 extrinsicsFromMeta from '@polkadot/extrinsics/fromMetadata';
import createType from '../../codec/createType';
import Metadata from '../Metadata';
import Method from '../../primitive/Method';
import { MetadataInterface } from '../types';
import { Codec } from '../../types';
/**
* Given the static `rpcData` and the `latestSubstrate` JSON file, Metadata
* should decode `rpcData` and output `latestSubstrate`.
*/
export function decodeLatestSubstrate<Modules extends Codec> (
version: number,
rpcData: string,
latestSubstrate: object
) {
it('decodes latest substrate properly', () => {
const metadata = new Metadata(rpcData);
console.error(JSON.stringify(metadata.toJSON()));
expect(metadata.version).toBe(version);
expect((metadata[`asV${version}` as keyof Metadata] as unknown as MetadataInterface<Modules>).modules.length).not.toBe(0);
expect(metadata.toJSON()).toEqual(latestSubstrate);
});
}
/**
* Given a `version`, MetadataV4 and MetadataV{version} should output the same
* unique types.
*/
export function toV4<Modules extends Codec> (version: number, rpcData: string) {
it('converts to V4', () => {
const metadata = new Metadata(rpcData)[`asV${version}` as keyof Metadata];
const metadataV4 = new Metadata(rpcData).asV4;
expect(
(metadata as unknown as MetadataInterface<Modules>).getUniqTypes(true)
).toEqual(metadataV4.getUniqTypes(true));
});
}
/**
* Given a Metadata, no type should throw when given its fallback value.
*/
export function defaultValues (rpcData: string) {
describe('storage with default values', () => {
const metadata = new Metadata(rpcData);
Method.injectMethods(extrinsicsFromMeta(metadata));
metadata.asV4.modules
.filter(({ storage }) => storage.isSome)
.map((mod) =>
mod.storage.unwrap().forEach(({ fallback, name, type }) => {
it(`creates default types for ${mod.prefix}.${name}, type ${type}`, () => {
expect(
() => createType(type.toString(), fallback)
).not.toThrow();
});
})
);
});
}
+15 -7
View File
@@ -12,7 +12,7 @@ export class EventMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
arguments: Vector.with(Type),
args: Vector.with(Type),
documentation: Vector.with(Text)
}, value);
}
@@ -20,8 +20,16 @@ export class EventMetadata extends Struct {
/**
* @description The arguments of [[Type]]
*/
get args (): Vector<Type> {
return this.get('args') as Vector<Type>;
}
/**
* @description The arguments of [[Type]]
* @deprecated Use `.args` instead
*/
get arguments (): Vector<Type> {
return this.get('arguments') as Vector<Type>;
return this.args;
}
/**
@@ -47,7 +55,7 @@ export class EventMetadata extends Struct {
}
}
export class OuterEventMetadataEvent extends Tuple {
export class OuterEventEventMetadata extends Tuple {
constructor (value?: any) {
super({
Text,
@@ -74,15 +82,15 @@ export class OuterEventMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
events: Vector.with(OuterEventMetadataEvent)
events: Vector.with(OuterEventEventMetadata)
}, value);
}
/**
* @description The [[OuterEventMetadataEvent]]
* @description The [[OuterEventEventMetadata]]
*/
get events (): Vector<OuterEventMetadataEvent> {
return this.get('events') as Vector<OuterEventMetadataEvent>;
get events (): Vector<OuterEventEventMetadata> {
return this.get('events') as Vector<OuterEventEventMetadata>;
}
/**
+17 -26
View File
@@ -2,41 +2,32 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import extrinsicsFromMeta from '@plugnet/extrinsics/fromMetadata';
import createType from '../../codec/createType';
import Method from '../../primitive/Method';
import Metadata from './Metadata';
import latestParsed from './latest.substrate.json';
import MetadataV0 from './';
import Metadata from '../';
import latestSubstrateV0 from './latest.substrate.v0.json';
import rpcData from './static';
import { defaultValues, toV4 } from '../util/testUtil';
describe('Metadata', () => {
it('decodes latest properly', () => {
it('works with fallback', () => {
const metadata = new Metadata(rpcData);
const str = JSON.stringify(metadata.toJSON());
const metadataV0 = new MetadataV0(rpcData);
expect(metadata.events.length).not.toBe(0);
expect(str).toEqual(JSON.stringify(latestParsed));
expect(metadata.asV0.toString()).toEqual(metadataV0.toString());
});
describe('storage with default values', () => {
it('decodes latest substrate properly', () => {
const metadata = new Metadata(rpcData);
const json = metadata.asV0.toJSON();
Method.injectMethods(extrinsicsFromMeta(metadata));
console.error(JSON.stringify(json));
metadata.modules.forEach((mod) => {
if (mod.storage.isNone) {
return;
}
mod.storage.unwrap().functions.forEach((fn) => {
it(`creates default types for ${mod.prefix}.${fn.name}, type ${fn.type}`, () => {
expect(
() => createType(fn.type.toString(), fn.fallback)
).not.toThrow();
});
});
});
expect(metadata.version).toBe(0);
expect(metadata.asV0.modules.length).not.toBe(0);
expect(json).toEqual(latestSubstrateV0);
});
toV4(0, rpcData);
defaultValues(rpcData);
});
+14 -16
View File
@@ -11,19 +11,17 @@ import Struct from '../../codec/Struct';
import Vector from '../../codec/Vector';
import { flattenUniq, validateTypes } from '../util';
import { OuterDispatchMetadata, OuterDispatchCall } from './Calls';
import { OuterEventMetadata, OuterEventMetadataEvent } from './Events';
import { OuterEventMetadata, OuterEventEventMetadata } from './Events';
import { RuntimeModuleMetadata } from './Modules';
// Decodes the runtime metadata as passed through from the `state_getMetadata` call. This
// file is probably best understood from the bottom-up, i.e. start reading right at the
// end and work up. (Just so we don't use before definition)
// Decodes the runtime metadata as passed through from the `state_getMetadata` call.
/**
* @name MetadataV0
* @description
* The runtime metadata as a decoded structure
*/
export default class MetadataV0 extends Struct implements MetadataInterface {
export default class MetadataV0 extends Struct implements MetadataInterface<RuntimeModuleMetadata> {
constructor (value?: any) {
super({
outerEvent: OuterEventMetadata,
@@ -62,9 +60,9 @@ export default class MetadataV0 extends Struct implements MetadataInterface {
}
/**
* @description Wrapped [[OuterEventMetadataEvent]]
* @description Wrapped [[OuterEventEventMetadata]]
*/
get events (): Vector<OuterEventMetadataEvent> {
get events (): Vector<OuterEventEventMetadata> {
return (this.get('outerEvent') as OuterEventMetadata).events;
}
@@ -76,25 +74,25 @@ export default class MetadataV0 extends Struct implements MetadataInterface {
}
private get argNames () {
return this.modules.map((module) =>
module.module.call.functions.map((fn) =>
fn.arguments.map((argument) => argument.type.toString())
return this.modules.map((modul) =>
modul.module.call.functions.map((fn) =>
fn.args.map((argument) => argument.type.toString())
)
);
}
private get eventNames () {
return this.events.map((module) =>
module.events.map((event) =>
event.arguments.map((argument) => argument.toString())
return this.events.map((modul) =>
modul.events.map((event) =>
event.args.map((argument) => argument.toString())
)
);
}
private get storageNames () {
return this.modules.map((module) =>
module.storage.isSome
? module.storage.unwrap().functions.map((fn) =>
return this.modules.map((modul) =>
modul.storage.isSome
? modul.storage.unwrap().functions.map((fn) =>
fn.type.isMap
? [fn.type.asMap.key.toString(), fn.type.asMap.value.toString()]
: [fn.type.asType.toString()]
+10 -3
View File
@@ -39,13 +39,21 @@ export class FunctionMetadata extends Struct {
super({
id: U16,
name: Text,
arguments: Vector.with(FunctionArgumentMetadata),
args: Vector.with(FunctionArgumentMetadata),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The arguments of [[Type]]
*/
get args (): Vector<FunctionArgumentMetadata> {
return this.get('args') as Vector<FunctionArgumentMetadata>;
}
/**
* @description The [[FunctionArgumentMetadata]] for arguments
* @deprecated Use `.args` instead
*/
get arguments (): Vector<FunctionArgumentMetadata> {
return this.get('arguments') as Vector<FunctionArgumentMetadata>;
@@ -103,7 +111,6 @@ export class CallMetadata extends Struct {
return this.get('name') as Text;
}
}
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
@@ -113,7 +120,7 @@ export class ModuleMetadata extends Struct {
}
/**
* @description The calls as [[CallMetadata]]
* @description The calls as [[FunctionMetadata]]
*/
get call (): CallMetadata {
return this.get('call') as CallMetadata;
+2 -24
View File
@@ -11,7 +11,6 @@ import EnumType from '../../codec/EnumType';
import Struct from '../../codec/Struct';
import Vector from '../../codec/Vector';
import Bytes from '../../primitive/Bytes';
import Null from '../../primitive/Null';
import Text from '../../primitive/Text';
import Type from '../../primitive/Type';
@@ -33,8 +32,6 @@ export class StorageFunctionModifier extends Enum {
}
}
export class DoubleMapType extends Null {}
export class MapType extends Struct {
private _isLinked = false;
@@ -78,20 +75,10 @@ export class StorageFunctionType extends EnumType<PlainType | MapType> {
constructor (value?: any, index?: number) {
super({
PlainType,
MapType,
DoubleMapType
MapType
}, value, index);
}
/**
* @description The value as a mapped value
*/
get asDoubleMap (): DoubleMapType {
assert(this.isDoubleMap, `Cannot convert '${this.type}' via asDoubleMap`);
return this.value as DoubleMapType;
}
/**
* @description The value as a mapped value
*/
@@ -110,13 +97,6 @@ export class StorageFunctionType extends EnumType<PlainType | MapType> {
return this.value as PlainType;
}
/**
* @description `true` if the storage entry is a double map
*/
get isDoubleMap (): boolean {
return this.toNumber() === 2;
}
/**
* @description `true` if the storage entry is a map
*/
@@ -135,9 +115,7 @@ export class StorageFunctionType extends EnumType<PlainType | MapType> {
* @description Returns the string representation of the value
*/
toString (): string {
if (this.isDoubleMap) {
return `DoubleMap<${this.asDoubleMap.toString()}>`;
} else if (this.isMap) {
if (this.isMap) {
if (this.asMap.isLinked) {
return `(${this.asMap.value.toString()}, Linkage<${this.asMap.key.toString()}>)`;
}
@@ -7,14 +7,14 @@
[
{
"name": "ExtrinsicSuccess",
"arguments": [],
"args": [],
"documentation": [
" An extrinsic completed successfully."
]
},
{
"name": "ExtrinsicFailed",
"arguments": [],
"args": [],
"documentation": [
" An extrinsic failed."
]
@@ -26,7 +26,7 @@
[
{
"name": "NewAccount",
"arguments": [
"args": [
"AccountId",
"AccountIndex",
"NewAccountOutcome"
@@ -37,7 +37,7 @@
},
{
"name": "ReapedAccount",
"arguments": [
"args": [
"AccountId"
],
"documentation": [
@@ -46,7 +46,7 @@
},
{
"name": "Transfer",
"arguments": [
"args": [
"AccountId",
"AccountId",
"Balance",
@@ -63,7 +63,7 @@
[
{
"name": "NewSession",
"arguments": [
"args": [
"BlockNumber"
],
"documentation": [
@@ -78,7 +78,7 @@
[
{
"name": "Reward",
"arguments": [
"args": [
"Balance"
],
"documentation": [
@@ -87,7 +87,7 @@
},
{
"name": "OfflineWarning",
"arguments": [
"args": [
"AccountId",
"u32"
],
@@ -98,7 +98,7 @@
},
{
"name": "OfflineSlash",
"arguments": [
"args": [
"AccountId",
"Balance"
],
@@ -113,7 +113,7 @@
[
{
"name": "Tabled",
"arguments": [
"args": [
"PropIndex",
"Balance",
"Vec<AccountId>"
@@ -122,7 +122,7 @@
},
{
"name": "Started",
"arguments": [
"args": [
"ReferendumIndex",
"VoteThreshold"
],
@@ -130,28 +130,28 @@
},
{
"name": "Passed",
"arguments": [
"args": [
"ReferendumIndex"
],
"documentation": []
},
{
"name": "NotPassed",
"arguments": [
"args": [
"ReferendumIndex"
],
"documentation": []
},
{
"name": "Cancelled",
"arguments": [
"args": [
"ReferendumIndex"
],
"documentation": []
},
{
"name": "Executed",
"arguments": [
"args": [
"ReferendumIndex",
"bool"
],
@@ -164,7 +164,7 @@
[
{
"name": "NewAuthorities",
"arguments": [
"args": [
"Vec<(SessionKey,u64)>"
],
"documentation": [
@@ -178,7 +178,7 @@
[
{
"name": "VoterReaped",
"arguments": [
"args": [
"AccountId",
"AccountId"
],
@@ -188,7 +188,7 @@
},
{
"name": "BadReaperSlashed",
"arguments": [
"args": [
"AccountId"
],
"documentation": [
@@ -197,7 +197,7 @@
},
{
"name": "TallyStarted",
"arguments": [
"args": [
"u32"
],
"documentation": [
@@ -206,7 +206,7 @@
},
{
"name": "TallyFinalised",
"arguments": [
"args": [
"Vec<AccountId>",
"Vec<AccountId>"
],
@@ -221,7 +221,7 @@
[
{
"name": "TallyCancelation",
"arguments": [
"args": [
"Hash",
"u32",
"u32",
@@ -234,7 +234,7 @@
},
{
"name": "TallyReferendum",
"arguments": [
"args": [
"Hash",
"u32",
"u32",
@@ -252,7 +252,7 @@
[
{
"name": "Proposed",
"arguments": [
"args": [
"AccountId",
"ProposalIndex",
"Hash",
@@ -264,7 +264,7 @@
},
{
"name": "Voted",
"arguments": [
"args": [
"AccountId",
"Hash",
"bool",
@@ -278,7 +278,7 @@
},
{
"name": "Approved",
"arguments": [
"args": [
"Hash"
],
"documentation": [
@@ -287,7 +287,7 @@
},
{
"name": "Disapproved",
"arguments": [
"args": [
"Hash"
],
"documentation": [
@@ -296,7 +296,7 @@
},
{
"name": "Executed",
"arguments": [
"args": [
"Hash",
"bool"
],
@@ -311,7 +311,7 @@
[
{
"name": "Proposed",
"arguments": [
"args": [
"ProposalIndex"
],
"documentation": [
@@ -320,7 +320,7 @@
},
{
"name": "Spending",
"arguments": [
"args": [
"Balance"
],
"documentation": [
@@ -329,7 +329,7 @@
},
{
"name": "Awarded",
"arguments": [
"args": [
"ProposalIndex",
"Balance",
"AccountId"
@@ -340,7 +340,7 @@
},
{
"name": "Burnt",
"arguments": [
"args": [
"Balance"
],
"documentation": [
@@ -349,7 +349,7 @@
},
{
"name": "Rollover",
"arguments": [
"args": [
"Balance"
],
"documentation": [
@@ -468,7 +468,7 @@
{
"id": 0,
"name": "set",
"arguments": [
"args": [
{
"name": "now",
"type": "Compact<Moment>"
@@ -528,7 +528,7 @@
{
"id": 0,
"name": "report_misbehavior",
"arguments": [
"args": [
{
"name": "_report",
"type": "Bytes"
@@ -541,7 +541,7 @@
{
"id": 1,
"name": "note_offline",
"arguments": [
"args": [
{
"name": "offline",
"type": "InherentOfflineReport"
@@ -554,7 +554,7 @@
{
"id": 2,
"name": "remark",
"arguments": [
"args": [
{
"name": "_remark",
"type": "Bytes"
@@ -567,7 +567,7 @@
{
"id": 3,
"name": "set_heap_pages",
"arguments": [
"args": [
{
"name": "pages",
"type": "u64"
@@ -580,7 +580,7 @@
{
"id": 4,
"name": "set_code",
"arguments": [
"args": [
{
"name": "new",
"type": "Bytes"
@@ -593,7 +593,7 @@
{
"id": 5,
"name": "set_storage",
"arguments": [
"args": [
{
"name": "items",
"type": "Vec<KeyValue>"
@@ -628,7 +628,7 @@
{
"id": 0,
"name": "transfer",
"arguments": [
"args": [
{
"name": "dest",
"type": "Address"
@@ -645,7 +645,7 @@
{
"id": 1,
"name": "set_balance",
"arguments": [
"args": [
{
"name": "who",
"type": "Address"
@@ -800,7 +800,7 @@
{
"id": 0,
"name": "set_key",
"arguments": [
"args": [
{
"name": "key",
"type": "SessionKey"
@@ -814,7 +814,7 @@
{
"id": 1,
"name": "set_length",
"arguments": [
"args": [
{
"name": "new",
"type": "Compact<BlockNumber>"
@@ -827,7 +827,7 @@
{
"id": 2,
"name": "force_new_session",
"arguments": [
"args": [
{
"name": "apply_rewards",
"type": "bool"
@@ -924,7 +924,7 @@
{
"id": 0,
"name": "stake",
"arguments": [],
"args": [],
"documentation": [
" Declare the desire to stake for the transactor.",
"",
@@ -934,7 +934,7 @@
{
"id": 1,
"name": "unstake",
"arguments": [
"args": [
{
"name": "intentions_index",
"type": "Compact<u32>"
@@ -949,7 +949,7 @@
{
"id": 2,
"name": "nominate",
"arguments": [
"args": [
{
"name": "target",
"type": "Address"
@@ -960,7 +960,7 @@
{
"id": 3,
"name": "unnominate",
"arguments": [
"args": [
{
"name": "target_index",
"type": "Compact<u32>"
@@ -974,7 +974,7 @@
{
"id": 4,
"name": "register_preferences",
"arguments": [
"args": [
{
"name": "intentions_index",
"type": "Compact<u32>"
@@ -993,7 +993,7 @@
{
"id": 5,
"name": "set_sessions_per_era",
"arguments": [
"args": [
{
"name": "new",
"type": "Compact<BlockNumber>"
@@ -1006,7 +1006,7 @@
{
"id": 6,
"name": "set_bonding_duration",
"arguments": [
"args": [
{
"name": "new",
"type": "Compact<BlockNumber>"
@@ -1019,7 +1019,7 @@
{
"id": 7,
"name": "set_validator_count",
"arguments": [
"args": [
{
"name": "new",
"type": "Compact<u32>"
@@ -1032,7 +1032,7 @@
{
"id": 8,
"name": "force_new_era",
"arguments": [
"args": [
{
"name": "apply_rewards",
"type": "bool"
@@ -1046,7 +1046,7 @@
{
"id": 9,
"name": "set_offline_slash_grace",
"arguments": [
"args": [
{
"name": "new",
"type": "Compact<u32>"
@@ -1261,7 +1261,7 @@
{
"id": 0,
"name": "propose",
"arguments": [
"args": [
{
"name": "proposal",
"type": "Proposal"
@@ -1278,7 +1278,7 @@
{
"id": 1,
"name": "second",
"arguments": [
"args": [
{
"name": "proposal",
"type": "Compact<PropIndex>"
@@ -1291,7 +1291,7 @@
{
"id": 2,
"name": "vote",
"arguments": [
"args": [
{
"name": "ref_index",
"type": "Compact<ReferendumIndex>"
@@ -1309,7 +1309,7 @@
{
"id": 3,
"name": "start_referendum",
"arguments": [
"args": [
{
"name": "proposal",
"type": "Proposal"
@@ -1330,7 +1330,7 @@
{
"id": 4,
"name": "cancel_referendum",
"arguments": [
"args": [
{
"name": "ref_index",
"type": "Compact<ReferendumIndex>"
@@ -1343,7 +1343,7 @@
{
"id": 5,
"name": "cancel_queued",
"arguments": [
"args": [
{
"name": "when",
"type": "BlockNumber"
@@ -1506,7 +1506,7 @@
{
"id": 0,
"name": "report_misbehavior",
"arguments": [
"args": [
{
"name": "_report",
"type": "Bytes"
@@ -1541,7 +1541,7 @@
{
"id": 0,
"name": "set_approvals",
"arguments": [
"args": [
{
"name": "votes",
"type": "Vec<bool>"
@@ -1559,7 +1559,7 @@
{
"id": 1,
"name": "reap_inactive_voter",
"arguments": [
"args": [
{
"name": "reporter_index",
"type": "Compact<u32>"
@@ -1588,7 +1588,7 @@
{
"id": 2,
"name": "retract_voter",
"arguments": [
"args": [
{
"name": "index",
"type": "Compact<u32>"
@@ -1601,7 +1601,7 @@
{
"id": 3,
"name": "submit_candidacy",
"arguments": [
"args": [
{
"name": "slot",
"type": "Compact<u32>"
@@ -1616,7 +1616,7 @@
{
"id": 4,
"name": "present_winner",
"arguments": [
"args": [
{
"name": "candidate",
"type": "Address"
@@ -1639,7 +1639,7 @@
{
"id": 5,
"name": "set_desired_seats",
"arguments": [
"args": [
{
"name": "count",
"type": "Compact<u32>"
@@ -1654,7 +1654,7 @@
{
"id": 6,
"name": "remove_member",
"arguments": [
"args": [
{
"name": "who",
"type": "Address"
@@ -1669,7 +1669,7 @@
{
"id": 7,
"name": "set_presentation_duration",
"arguments": [
"args": [
{
"name": "count",
"type": "Compact<BlockNumber>"
@@ -1683,7 +1683,7 @@
{
"id": 8,
"name": "set_term_duration",
"arguments": [
"args": [
{
"name": "count",
"type": "Compact<BlockNumber>"
@@ -1883,7 +1883,7 @@
{
"id": 0,
"name": "propose",
"arguments": [
"args": [
{
"name": "proposal",
"type": "Proposal"
@@ -1894,7 +1894,7 @@
{
"id": 1,
"name": "vote",
"arguments": [
"args": [
{
"name": "proposal",
"type": "Hash"
@@ -1909,7 +1909,7 @@
{
"id": 2,
"name": "veto",
"arguments": [
"args": [
{
"name": "proposal_hash",
"type": "Hash"
@@ -1920,7 +1920,7 @@
{
"id": 3,
"name": "set_cooloff_period",
"arguments": [
"args": [
{
"name": "blocks",
"type": "Compact<BlockNumber>"
@@ -1931,7 +1931,7 @@
{
"id": 4,
"name": "set_voting_period",
"arguments": [
"args": [
{
"name": "blocks",
"type": "Compact<BlockNumber>"
@@ -2020,7 +2020,7 @@
{
"id": 0,
"name": "propose",
"arguments": [
"args": [
{
"name": "threshold",
"type": "Compact<u32>"
@@ -2035,7 +2035,7 @@
{
"id": 1,
"name": "vote",
"arguments": [
"args": [
{
"name": "proposal",
"type": "Hash"
@@ -2108,7 +2108,7 @@
{
"id": 0,
"name": "propose_spend",
"arguments": [
"args": [
{
"name": "value",
"type": "Compact<Balance>"
@@ -2127,7 +2127,7 @@
{
"id": 1,
"name": "set_pot",
"arguments": [
"args": [
{
"name": "new_pot",
"type": "Compact<Balance>"
@@ -2140,7 +2140,7 @@
{
"id": 2,
"name": "configure",
"arguments": [
"args": [
{
"name": "proposal_bond",
"type": "Permill"
@@ -2165,7 +2165,7 @@
{
"id": 3,
"name": "reject_proposal",
"arguments": [
"args": [
{
"name": "proposal_id",
"type": "Compact<ProposalIndex>"
@@ -2178,7 +2178,7 @@
{
"id": 4,
"name": "approve_proposal",
"arguments": [
"args": [
{
"name": "proposal_id",
"type": "Compact<ProposalIndex>"
@@ -2276,7 +2276,7 @@
{
"id": 0,
"name": "set_heads",
"arguments": [
"args": [
{
"name": "heads",
"type": "Vec<AttestedCandidate>"
@@ -2289,7 +2289,7 @@
{
"id": 1,
"name": "register_parachain",
"arguments": [
"args": [
{
"name": "id",
"type": "Id"
@@ -2311,7 +2311,7 @@
{
"id": 2,
"name": "deregister_parachain",
"arguments": [
"args": [
{
"name": "id",
"type": "Id"
File diff suppressed because it is too large Load Diff
+60
View File
@@ -0,0 +1,60 @@
// Copyright 2017-2019 @polkadot/types 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 { stringUpperFirst } from '@polkadot/util';
import { Option, Vector } from '../../codec';
import MetadataV0 from './Metadata';
import { RuntimeModuleMetadata } from './Modules';
import { Text } from '../../primitive';
import { FunctionMetadata } from '../v1/Calls';
import { EventMetadata } from '../v1/Events';
import MetadataV1, { ModuleMetadata } from '../v1/Metadata';
import { StorageFunctionMetadata } from '../v1/Storage';
function toV1Calls (modul: RuntimeModuleMetadata) {
return modul.module.call.functions.length === 0
? new Option(Vector.with(FunctionMetadata))
: new Option(Vector.with(FunctionMetadata), modul.module.call.functions);
}
function toV1Events (metadataV0: MetadataV0, prefix: Text) {
const events = metadataV0.events.find((event) => event.name.eq(prefix));
return events
? new Option(Vector.with(EventMetadata), events.events)
: new Option(Vector.with(EventMetadata));
}
function toV1Storage (modul: RuntimeModuleMetadata) {
return modul.storage.isNone
? new Option(Vector.with(StorageFunctionMetadata))
: new Option(
Vector.with(StorageFunctionMetadata),
modul.storage.unwrap().functions
);
}
/**
* Function that converts MetadataV0 to MetadataV1
*/
export default function toV1 (metadataV0: MetadataV0): MetadataV1 {
return new MetadataV1({
modules: metadataV0.modules.map((modul) => {
// The prefix of this module (capitalized)
const prefix = modul.storage.isSome
? modul.storage.unwrap().prefix.toString()
: stringUpperFirst(modul.prefix.toString()); // If this module doesn't have storage, we just assume the prefix is the name capitalized
return new ModuleMetadata({
name: modul.prefix, // Not capitalized
prefix, // Capitalized
storage: toV1Storage(modul),
calls: toV1Calls(modul),
events: toV1Events(metadataV0, modul.prefix)
});
})
});
}
+7 -17
View File
@@ -7,7 +7,7 @@ import Vector from '../../codec/Vector';
import Text from '../../primitive/Text';
import Type from '../../primitive/Type';
export class MetadataCallArg extends Struct {
export class FunctionArgumentMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
@@ -31,27 +31,24 @@ export class MetadataCallArg extends Struct {
}
/**
* @name MetadataCall
* @name FunctionMetadata
* @description
* The definition of a call
*/
export class MetadataCall extends Struct {
export class FunctionMetadata extends Struct {
constructor (value?: any) {
super({
// NOTE Just commented out, it is not available in current, but an open question
// around the usefulness of supplying this remains (could be re-added)
// id: u16,
name: Text,
args: Vector.with(MetadataCallArg),
args: Vector.with(FunctionArgumentMetadata),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The [[MetadataCallArg]] for arguments
* @description The [[FunctionArgumentMetadata]] for arguments
*/
get args (): Vector<MetadataCallArg> {
return this.get('args') as Vector<MetadataCallArg>;
get args (): Vector<FunctionArgumentMetadata> {
return this.get('args') as Vector<FunctionArgumentMetadata>;
}
/**
@@ -69,13 +66,6 @@ export class MetadataCall extends Struct {
return this.documentation;
}
// /**
// * @description The call function id
// */
// get id (): u16 {
// return this.get('id') as u16;
// }
/**
* @description The call name
*/
+2 -48
View File
@@ -2,51 +2,5 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import Struct from '../../codec/Struct';
import Vector from '../../codec/Vector';
import Text from '../../primitive/Text';
import Type from '../../primitive/Type';
/**
* @name MetadataEvent
* @description
* The definition of an event
*/
export class MetadataEvent extends Struct {
constructor (value?: any) {
super({
name: Text,
args: Vector.with(Type),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The [[Type]] for args
*/
get args (): Vector<Type> {
return this.get('args') as Vector<Type>;
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The [[Text]] documentation
* @deprecated Use `.documentation` instead.
*/
get docs (): Vector<Text> {
return this.documentation;
}
/**
* @description The call name
*/
get name (): Text {
return this.get('name') as Text;
}
}
// Re-export classes that haven't changed between V0 and V1
export { EventMetadata } from '../v0/Events';
@@ -2,45 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import extrinsicsFromMeta from '@plugnet/extrinsics/fromMetadata';
import createType from '../../codec/createType';
import Method from '../../primitive/Method';
import Metadata from '../Metadata';
import latestParsed from './latest.substrate.v1.json';
import latestSubstrate from './latest.substrate.v1.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV4 } from '../util/testUtil';
describe('MetadataV1', () => {
const metadata = new Metadata(rpcData);
decodeLatestSubstrate(1, rpcData, latestSubstrate);
it('decodes latest properly', () => {
const str = JSON.stringify(metadata.toJSON());
toV4(1, rpcData);
expect(metadata.version).toBe(1);
expect(metadata.asV1.modules.length).not.toBe(0);
expect(str).toEqual(JSON.stringify(latestParsed));
});
it('converts v1 to V0', () => {
const v0 = metadata.asV0;
expect(metadata.getUniqTypes(true)).toEqual(v0.getUniqTypes(true));
});
describe('storage with default values', () => {
Method.injectMethods(extrinsicsFromMeta(metadata.asV0));
metadata.asV1.modules
.filter(({ storage }) => storage.isSome)
.map((mod) =>
mod.storage.unwrap().forEach(({ fallback, name, type }) => {
it(`creates default types for ${mod.prefix}.${name}, type ${type}`, () => {
expect(
() => createType(type.toString(), fallback)
).not.toThrow();
});
})
);
});
defaultValues(rpcData);
});
+14 -14
View File
@@ -10,38 +10,38 @@ import Vector from '../../codec/Vector';
import Text from '../../primitive/Text';
import { flattenUniq, validateTypes } from '../util';
import { MetadataCall } from './Calls';
import { MetadataEvent } from './Events';
import { FunctionMetadata } from './Calls';
import { EventMetadata } from './Events';
import { StorageFunctionMetadata } from './Storage';
/**
* @name MetadataModule
* @name ModuleMetadata
* @description
* The definition of a module in the system
*/
export class MetadataModule extends Struct {
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
storage: Option.with(Vector.with(StorageFunctionMetadata)),
calls: Option.with(Vector.with(MetadataCall)),
events: Option.with(Vector.with(MetadataEvent))
calls: Option.with(Vector.with(FunctionMetadata)),
events: Option.with(Vector.with(EventMetadata))
}, value);
}
/**
* @description the module calls
*/
get calls (): Option<Vector<MetadataCall>> {
return this.get('calls') as Option<Vector<MetadataCall>>;
get calls (): Option<Vector<FunctionMetadata>> {
return this.get('calls') as Option<Vector<FunctionMetadata>>;
}
/**
* @description the module events
*/
get events (): Option<Vector<MetadataEvent>> {
return this.get('events') as Option<Vector<MetadataEvent>>;
get events (): Option<Vector<EventMetadata>> {
return this.get('events') as Option<Vector<EventMetadata>>;
}
/**
@@ -71,18 +71,18 @@ export class MetadataModule extends Struct {
* @description
* The runtime metadata as a decoded structure
*/
export default class MetadataV1 extends Struct implements MetadataInterface {
export default class MetadataV1 extends Struct implements MetadataInterface<ModuleMetadata> {
constructor (value?: any) {
super({
modules: Vector.with(MetadataModule)
modules: Vector.with(ModuleMetadata)
}, value);
}
/**
* @description The associated modules for this structure
*/
get modules (): Vector<MetadataModule> {
return this.get('modules') as Vector<MetadataModule>;
get modules (): Vector<ModuleMetadata> {
return this.get('modules') as Vector<ModuleMetadata>;
}
private get callNames () {
+2 -2
View File
@@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { default as MetadataV1, MetadataModule as MetadataModuleV1 } from './Metadata';
import { default as MetadataV1, ModuleMetadata as ModuleMetadataV1 } from './Metadata';
export default MetadataV1;
export {
MetadataModuleV1
ModuleMetadataV1
};
-103
View File
@@ -1,103 +0,0 @@
// Copyright 2017-2019 @polkadot/types 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 { OuterDispatchCall, OuterDispatchMetadata } from '../v0/Calls';
import { EventMetadata, OuterEventMetadata, OuterEventMetadataEvent } from '../v0/Events';
import { CallMetadata, FunctionMetadata, RuntimeModuleMetadata, ModuleMetadata } from '../v0/Modules';
import { StorageFunctionMetadata, StorageMetadata, StorageFunctionType } from '../v0/Storage';
import MetadataV0 from '../v0/Metadata';
import MetadataV1, { MetadataModuleV1 } from '.';
function storageV0 (mod: MetadataModuleV1): StorageMetadata | null {
if (mod.storage.isNone) {
return null;
}
return new StorageMetadata({
prefix: mod.prefix,
functions: mod.storage.unwrap().map(({ documentation, fallback, modifier, name, type }) =>
new StorageFunctionMetadata({
name,
modifier: modifier.toNumber(),
type: new StorageFunctionType(type),
fallback,
documentation
})
)
});
}
function moduleV0 (mod: MetadataModuleV1): ModuleMetadata {
return new ModuleMetadata({
name: 'Module',
call: new CallMetadata({
name: 'Call',
functions: mod.calls.isNone
? []
: mod.calls.unwrap().map(({ args, documentation, name }, id) =>
new FunctionMetadata({
id,
name,
arguments: args,
documentation
})
)
})
});
}
function modulesV0 (v1: MetadataV1): Array<RuntimeModuleMetadata> {
return v1.modules.map((mod) =>
new RuntimeModuleMetadata({
prefix: mod.name, // passed from name, compact with casing
module: moduleV0(mod),
storage: storageV0(mod)
})
);
}
function outerDispatchV0 (v1: MetadataV1): OuterDispatchMetadata {
return new OuterDispatchMetadata({
name: 'Call',
calls: v1.modules
.filter(({ calls }) => calls.isSome)
.map((mod, index) =>
new OuterDispatchCall({
// name and prefix are swapped in the actual V0 data, i.e. name is UpperCase
name: mod.prefix,
prefix: mod.name,
index
})
)
});
}
function outerEventV0 (v1: MetadataV1): OuterEventMetadata {
return new OuterEventMetadata({
name: 'Event',
events: v1.modules
.filter(({ events }) => events.isSome)
.map((mod) =>
new OuterEventMetadataEvent([
mod.name,
mod.events.unwrap().map(({ args, documentation, name }) =>
new EventMetadata({
name,
arguments: args,
documentation
})
)
])
)
});
}
export default function toV0 (v1: MetadataV1): MetadataV0 {
return new MetadataV0({
outerEvent: outerEventV0(v1),
modules: modulesV0(v1),
outerDispatch: outerDispatchV0(v1)
});
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2017-2019 @polkadot/types 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 MetadataV1 from './Metadata';
import MetadataV2 from '../v2';
export default function toV2 (metadataV1: MetadataV1): MetadataV2 {
return new MetadataV2(metadataV1);
}
@@ -2,9 +2,8 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import MetadataV3 from '../v3/Metadata';
import MetadataV4 from '.';
export default function toV3 (v4: MetadataV4): MetadataV3 {
return new MetadataV3(v4);
}
// Re-export classes that haven't changed between V1 and V2
export {
FunctionArgumentMetadata,
FunctionMetadata
} from '../v1/Calls';
@@ -2,9 +2,5 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import MetadataV1 from '../v1/Metadata';
import MetadataV2 from '.';
export default function toV1 (v2: MetadataV2): MetadataV1 {
return new MetadataV1(v2);
}
// Re-export classes that haven't changed between V1 and V2
export { EventMetadata } from '../v1/Events';
@@ -2,51 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import extrinsicsFromMeta from '@plugnet/extrinsics/fromMetadata';
import createType from '../../codec/createType';
import Method from '../../primitive/Method';
import Metadata from '../Metadata';
import latestParsed from './latest.substrate.v2.json';
import latestSubstrate from './latest.substrate.v2.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV4 } from '../util/testUtil';
describe('MetadataV2', () => {
const metadata = new Metadata(rpcData);
decodeLatestSubstrate(2, rpcData, latestSubstrate);
it('decodes latest properly', () => {
const str = JSON.stringify(metadata.toJSON());
toV4(2, rpcData);
expect(metadata.version).toBe(2);
expect(metadata.asV2.modules.length).not.toBe(0);
expect(str).toEqual(JSON.stringify(latestParsed));
});
it('converts v2 to V1', () => {
const v1 = metadata.asV1;
expect(metadata.getUniqTypes(true)).toEqual(v1.getUniqTypes(true));
});
it('converts v2 to V0', () => {
const v1 = metadata.asV0;
expect(metadata.getUniqTypes(true)).toEqual(v1.getUniqTypes(true));
});
describe('storage with default values', () => {
Method.injectMethods(extrinsicsFromMeta(metadata.asV0));
metadata.asV2.modules
.filter(({ storage }) => storage.isSome)
.map((mod) =>
mod.storage.unwrap().forEach(({ fallback, name, type }) => {
it(`creates default types for ${mod.prefix}.${name}, type ${type}`, () => {
expect(
() => createType(type.toString(), fallback)
).not.toThrow();
});
})
);
});
defaultValues(rpcData);
});
+14 -14
View File
@@ -10,38 +10,38 @@ import Vector from '../../codec/Vector';
import Text from '../../primitive/Text';
import { flattenUniq, validateTypes } from '../util';
import { MetadataCall } from '../v1/Calls';
import { MetadataEvent } from '../v1/Events';
import { FunctionMetadata } from './Calls';
import { EventMetadata } from './Events';
import { StorageFunctionMetadata } from './Storage';
/**
* @name MetadataModule
* @name ModuleMetadata
* @description
* The definition of a module in the system
*/
export class MetadataModule extends Struct {
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
storage: Option.with(Vector.with(StorageFunctionMetadata)),
calls: Option.with(Vector.with(MetadataCall)),
events: Option.with(Vector.with(MetadataEvent))
calls: Option.with(Vector.with(FunctionMetadata)),
events: Option.with(Vector.with(EventMetadata))
}, value);
}
/**
* @description the module calls
*/
get calls (): Option<Vector<MetadataCall>> {
return this.get('calls') as Option<Vector<MetadataCall>>;
get calls (): Option<Vector<FunctionMetadata>> {
return this.get('calls') as Option<Vector<FunctionMetadata>>;
}
/**
* @description the module events
*/
get events (): Option<Vector<MetadataEvent>> {
return this.get('events') as Option<Vector<MetadataEvent>>;
get events (): Option<Vector<EventMetadata>> {
return this.get('events') as Option<Vector<EventMetadata>>;
}
/**
@@ -71,18 +71,18 @@ export class MetadataModule extends Struct {
* @description
* The runtime metadata as a decoded structure
*/
export default class MetadataV2 extends Struct implements MetadataInterface {
export default class MetadataV2 extends Struct implements MetadataInterface<ModuleMetadata> {
constructor (value?: any) {
super({
modules: Vector.with(MetadataModule)
modules: Vector.with(ModuleMetadata)
}, value);
}
/**
* @description The associated modules for this structure
*/
get modules (): Vector<MetadataModule> {
return this.get('modules') as Vector<MetadataModule>;
get modules (): Vector<ModuleMetadata> {
return this.get('modules') as Vector<ModuleMetadata>;
}
private get callNames () {
+3 -25
View File
@@ -11,7 +11,6 @@ import Struct from '../../codec/Struct';
import Vector from '../../codec/Vector';
import Bool from '../../primitive/Bool';
import Bytes from '../../primitive/Bytes';
import Null from '../../primitive/Null';
import Text from '../../primitive/Text';
import Type from '../../primitive/Type';
import { PlainType, StorageFunctionModifier } from '../v1/Storage';
@@ -22,8 +21,6 @@ export {
StorageFunctionModifier
};
export class DoubleMapType extends Null {}
export class MapType extends Struct {
constructor (value?: any) {
super({
@@ -59,20 +56,10 @@ export class StorageFunctionType extends EnumType<PlainType | MapType> {
constructor (value?: any, index?: number) {
super({
PlainType,
MapType,
DoubleMapType
MapType
}, value, index);
}
/**
* @description The value as a mapped value
*/
get asDoubleMap (): DoubleMapType {
assert(this.isDoubleMap, `Cannot convert '${this.type}' via asDoubleMap`);
return this.value as DoubleMapType;
}
/**
* @description The value as a mapped value
*/
@@ -91,13 +78,6 @@ export class StorageFunctionType extends EnumType<PlainType | MapType> {
return this.value as PlainType;
}
/**
* @description `true` if the storage entry is a double map
*/
get isDoubleMap (): boolean {
return this.toNumber() === 2;
}
/**
* @description `true` if the storage entry is a map
*/
@@ -116,9 +96,7 @@ export class StorageFunctionType extends EnumType<PlainType | MapType> {
* @description Returns the string representation of the value
*/
toString (): string {
if (this.isDoubleMap) {
return `DoubleMap<${this.asDoubleMap.toString()}>`;
} else if (this.isMap) {
if (this.isMap) {
if (this.asMap.isLinked) {
return `(${this.asMap.value.toString()}, Linkage<${this.asMap.key.toString()}>)`;
}
@@ -139,7 +117,7 @@ export type StorageFunctionMetadataValue = {
};
/**
* @name MetadataModule
* @name ModuleMetadata
* @description
* The definition of a storage function
*/
+2 -2
View File
@@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { default as MetadataV2, MetadataModule as MetadataModuleV2 } from './Metadata';
import { default as MetadataV2, ModuleMetadata as ModuleMetadataV2 } from './Metadata';
export default MetadataV2;
export {
MetadataModuleV2
ModuleMetadataV2
};
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2017-2019 @polkadot/types 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 MetadataV2 from './Metadata';
import MetadataV3 from '../v3';
export default function toV3 (metadataV2: MetadataV2): MetadataV3 {
return new MetadataV3(metadataV2);
}
@@ -2,9 +2,8 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import MetadataV2 from '../v2/Metadata';
import MetadataV3 from '.';
export default function toV2 (v2: MetadataV3): MetadataV2 {
return new MetadataV2(v2);
}
// Re-export classes that haven't changed between V2 and V3
export {
FunctionArgumentMetadata,
FunctionMetadata
} from '../v2/Calls';
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// Re-export classes that haven't changed between V2 and V3
export { EventMetadata } from '../v2/Events';
@@ -2,21 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import Metadata from '../Metadata';
import latestParsed from './latest.substrate.v3.json';
import latestSubstrate from './latest.substrate.v3.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV4 } from '../util/testUtil';
describe('MetadataV3', () => {
const metadata = new Metadata(rpcData);
decodeLatestSubstrate(3, rpcData, latestSubstrate);
it('decodes latest properly', () => {
const str = JSON.stringify(metadata.toJSON());
toV4(3, rpcData);
console.error(str);
console.error(metadata.getUniqTypes(true));
expect(metadata.version).toBe(3);
expect(metadata.asV3.modules.length).not.toBe(0);
expect(str).toEqual(JSON.stringify(latestParsed));
});
defaultValues(rpcData);
});
+14 -14
View File
@@ -10,38 +10,38 @@ import Vector from '../../codec/Vector';
import Text from '../../primitive/Text';
import { flattenUniq, validateTypes } from '../util';
import { MetadataCall } from '../v1/Calls';
import { MetadataEvent } from '../v1/Events';
import { FunctionMetadata } from './Calls';
import { EventMetadata } from './Events';
import { StorageFunctionMetadata } from './Storage';
/**
* @name MetadataModule
* @name ModuleMetadata
* @description
* The definition of a module in the system
*/
export class MetadataModule extends Struct {
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
storage: Option.with(Vector.with(StorageFunctionMetadata)),
calls: Option.with(Vector.with(MetadataCall)),
events: Option.with(Vector.with(MetadataEvent))
calls: Option.with(Vector.with(FunctionMetadata)),
events: Option.with(Vector.with(EventMetadata))
}, value);
}
/**
* @description the module calls
*/
get calls (): Option<Vector<MetadataCall>> {
return this.get('calls') as Option<Vector<MetadataCall>>;
get calls (): Option<Vector<FunctionMetadata>> {
return this.get('calls') as Option<Vector<FunctionMetadata>>;
}
/**
* @description the module events
*/
get events (): Option<Vector<MetadataEvent>> {
return this.get('events') as Option<Vector<MetadataEvent>>;
get events (): Option<Vector<EventMetadata>> {
return this.get('events') as Option<Vector<EventMetadata>>;
}
/**
@@ -71,18 +71,18 @@ export class MetadataModule extends Struct {
* @description
* The runtime metadata as a decoded structure
*/
export default class MetadataV3 extends Struct implements MetadataInterface {
export default class MetadataV3 extends Struct implements MetadataInterface<ModuleMetadata> {
constructor (value?: any) {
super({
modules: Vector.with(MetadataModule)
modules: Vector.with(ModuleMetadata)
}, value);
}
/**
* @description The associated modules for this structure
*/
get modules (): Vector<MetadataModule> {
return this.get('modules') as Vector<MetadataModule>;
get modules (): Vector<ModuleMetadata> {
return this.get('modules') as Vector<ModuleMetadata>;
}
private get callNames () {
+3 -1
View File
@@ -127,7 +127,9 @@ export class StorageFunctionType extends EnumType<PlainType | MapType | DoubleMa
toString (): string {
if (this.isDoubleMap) {
return `DoubleMap<${this.asDoubleMap.toString()}>`;
} else if (this.isMap) {
}
if (this.isMap) {
if (this.asMap.isLinked) {
return `(${this.asMap.value.toString()}, Linkage<${this.asMap.key.toString()}>)`;
}
+2 -2
View File
@@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { default as MetadataV3, MetadataModule as MetadataModuleV3 } from './Metadata';
import { default as MetadataV3, ModuleMetadata as ModuleMetadataV3 } from './Metadata';
export default MetadataV3;
export {
MetadataModuleV3
ModuleMetadataV3
};
+68
View File
@@ -0,0 +1,68 @@
// Copyright 2017-2019 @polkadot/types 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 { Option, Vector } from '../../codec';
import MetadataV3 from './Metadata';
import StorageHasher from '../../primitive/StorageHasher';
import MetadataV4 from '../v4';
import { StorageFunctionMetadata as StorageFunctionMetadataV3 } from '../v3/Storage';
import { DoubleMapType, MapType, StorageFunctionMetadata, StorageFunctionType } from '../v4/Storage';
/**
* Convert V3 StorageFunction to V4 StorageFunction
*/
function toV4StorageFunction (storageFn: StorageFunctionMetadataV3): StorageFunctionMetadata {
const { documentation, fallback, modifier, name, type } = storageFn;
// Convert the old type to the new type: there is one new field
// called `hasher`, which we initialize to xxHash (the default in
// v3).
const [newType, index] = type.isPlainType
? [type, 0]
: type.isMap
? [new MapType({
hasher: new StorageHasher('Twox128'),
key: type.asMap.key,
value: type.asMap.value,
isLinked: type.asMap.isLinked
}), 1]
: [new DoubleMapType({
hasher: new StorageHasher('Twox128'),
key1: type.asDoubleMap.key1,
key2: type.asDoubleMap.key2,
value: type.asDoubleMap.value,
key2Hasher: type.asDoubleMap.key2Hasher
}), 2];
return new StorageFunctionMetadata({
name: name,
modifier: modifier,
type: new StorageFunctionType(newType, index),
fallback: fallback,
documentation: documentation
});
}
/**
* Convert from MetadataV3 to MetadataV4
* See https://github.com/paritytech/substrate/pull/2268 for details
*/
export default function toV4 (metadataV3: MetadataV3): MetadataV4 {
return new MetadataV4({
modules: metadataV3.modules.map((modul) => {
return {
name: modul.name,
prefix: modul.prefix,
storage: modul.storage.isSome
? new Option(
Vector.with(StorageFunctionMetadata),
modul.storage.unwrap().map(toV4StorageFunction)
)
: undefined,
calls: modul.calls,
events: modul.events
};
})
});
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// Re-export classes that haven't changed between V3 and V4
export {
FunctionArgumentMetadata,
FunctionMetadata
} from '../v3/Calls';
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// Re-export classes that haven't changed between V3 and V4
export { EventMetadata } from '../v3/Events';
@@ -2,29 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
<<<<<<< HEAD
import extrinsicsFromMeta from '@plugnet/extrinsics/fromMetadata';
import createType from '../../codec/createType';
import Method from '../../primitive/Method';
=======
>>>>>>> 57715c50c0... Revert "Update extrinsics FromMetadata. Drop storages with doublemap type when converting v3 to v2 (#888)" (#903)
import Metadata from '../Metadata';
import latestParsed from './latest.substrate.v4.json';
import latestSubstrate from './latest.substrate.v4.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV4 } from '../util/testUtil';
describe('MetadataV4', () => {
const metadata = new Metadata(rpcData);
decodeLatestSubstrate(4, rpcData, latestSubstrate);
it('decodes latest properly', () => {
const str = JSON.stringify(metadata.toJSON());
toV4(4, rpcData);
console.error(str);
console.error(metadata.getUniqTypes(true));
expect(metadata.version).toBe(4);
expect(metadata.asV4.modules.length).not.toBe(0);
expect(str).toEqual(JSON.stringify(latestParsed));
});
defaultValues(rpcData);
});
+14 -18
View File
@@ -10,42 +10,38 @@ import Vector from '../../codec/Vector';
import Text from '../../primitive/Text';
import { flattenUniq, validateTypes } from '../util';
import { MetadataCall } from '../v1/Calls';
import { MetadataEvent } from '../v1/Events';
import { FunctionMetadata } from './Calls';
import { EventMetadata } from './Events';
import { StorageFunctionMetadata } from './Storage';
export {
MetadataEvent
};
/**
* @name MetadataModule
* @name ModuleMetadata
* @description
* The definition of a module in the system
*/
export class MetadataModule extends Struct {
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
storage: Option.with(Vector.with(StorageFunctionMetadata)),
calls: Option.with(Vector.with(MetadataCall)),
events: Option.with(Vector.with(MetadataEvent))
calls: Option.with(Vector.with(FunctionMetadata)),
events: Option.with(Vector.with(EventMetadata))
}, value);
}
/**
* @description the module calls
*/
get calls (): Option<Vector<MetadataCall>> {
return this.get('calls') as Option<Vector<MetadataCall>>;
get calls (): Option<Vector<FunctionMetadata>> {
return this.get('calls') as Option<Vector<FunctionMetadata>>;
}
/**
* @description the module events
*/
get events (): Option<Vector<MetadataEvent>> {
return this.get('events') as Option<Vector<MetadataEvent>>;
get events (): Option<Vector<EventMetadata>> {
return this.get('events') as Option<Vector<EventMetadata>>;
}
/**
@@ -75,18 +71,18 @@ export class MetadataModule extends Struct {
* @description
* The runtime metadata as a decoded structure
*/
export default class MetadataV4 extends Struct implements MetadataInterface {
export default class MetadataV4 extends Struct implements MetadataInterface<ModuleMetadata> {
constructor (value?: any) {
super({
modules: Vector.with(MetadataModule)
modules: Vector.with(ModuleMetadata)
}, value);
}
/**
* @description The associated modules for this structure
*/
get modules (): Vector<MetadataModule> {
return this.get('modules') as Vector<MetadataModule>;
get modules (): Vector<ModuleMetadata> {
return this.get('modules') as Vector<ModuleMetadata>;
}
private get callNames () {
+2 -2
View File
@@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { default as MetadataV4, MetadataModule as MetadataModuleV4 } from './Metadata';
import { default as MetadataV4, ModuleMetadata as ModuleMetadataV4 } from './Metadata';
export default MetadataV4;
export {
MetadataModuleV4
ModuleMetadataV4
};
+10 -34
View File
@@ -11,8 +11,7 @@ import Tuple from '../codec/Tuple';
import U8aFixed from '../codec/U8aFixed';
import { TypeDef, getTypeClass, getTypeDef } from '../codec/createType';
import Metadata from '../Metadata';
import { EventMetadata as EventMetadataV0 } from '../Metadata/v0/Events';
import { MetadataEvent as EventMetadataV4 } from '../Metadata/v1/Events';
import { EventMetadata as EventMetadataV4 } from '../Metadata/v4/Events';
import Null from './Null';
import U32 from './U32';
@@ -32,12 +31,12 @@ export class EventIndex extends U32 {
* Wrapper for the actual data that forms part of an [[Event]]
*/
export class EventData extends Tuple {
private _meta: EventMetadataV0 | EventMetadataV4;
private _meta: EventMetadataV4;
private _method: string;
private _section: string;
private _typeDef: Array<TypeDef>;
constructor (Types: Array<Constructor>, value: Uint8Array, typeDef: Array<TypeDef>, meta: EventMetadataV0 | EventMetadataV4, section: string, method: string) {
constructor (Types: Array<Constructor>, value: Uint8Array, typeDef: Array<TypeDef>, meta: EventMetadataV4, section: string, method: string) {
super(Types, value);
this._meta = meta;
@@ -49,7 +48,7 @@ export class EventData extends Tuple {
/**
* @description The wrapped [[EventMetadata]]
*/
get meta (): EventMetadataV0 | EventMetadataV4 {
get meta (): EventMetadataV4 {
return this._meta;
}
@@ -129,37 +128,15 @@ export default class Event extends Struct {
// This is called/injected by the API on init, allowing a snapshot of
// the available system events to be used in lookups
static injectMetadata (metadata: Metadata): void {
if (metadata.version === 4) {
let sectionIndex = 0;
metadata.asV4.modules.forEach((section) => {
metadata.asV4.modules
.filter((section) => section.events.isSome)
.forEach((section, sectionIndex) => {
const sectionName = stringCamelCase(section.name.toString());
if (!section.events.isNone && !section.events.isEmpty) {
section.events.unwrap().forEach((meta, methodIndex) => {
const methodName = meta.name.toString();
const eventIndex = new Uint8Array([sectionIndex, methodIndex]);
const typeDef = meta.args.map((arg) => getTypeDef(arg));
const Types = typeDef.map(getTypeClass);
EventTypes[eventIndex.toString()] = class extends EventData {
constructor (value: Uint8Array) {
super(Types, value, typeDef, meta, sectionName, methodName);
}
};
});
sectionIndex += 1;
}
});
} else {
metadata.asV0.events.forEach((section, sectionIndex) => {
const sectionName = stringCamelCase(section.name.toString());
section.events.forEach((meta, methodIndex) => {
section.events.unwrap().forEach((meta, methodIndex) => {
const methodName = meta.name.toString();
const eventIndex = new Uint8Array([sectionIndex, methodIndex]);
const typeDef = meta.arguments.map((arg) => getTypeDef(arg));
const typeDef = meta.args.map((arg) => getTypeDef(arg));
const Types = typeDef.map(getTypeClass);
EventTypes[eventIndex.toString()] = class extends EventData {
@@ -169,7 +146,6 @@ export default class Event extends Struct {
};
});
});
}
}
/**
@@ -189,7 +165,7 @@ export default class Event extends Struct {
/**
* @description The [[EventMetadata]] with the documentation
*/
get meta (): EventMetadataV0 | EventMetadataV4 {
get meta (): EventMetadataV4 {
return this.data.meta;
}
+3 -3
View File
@@ -34,19 +34,19 @@ describe('Method', () => {
it('is false with no arguments', () => {
expect(
new Method(test, { arguments: [] } as any).hasOrigin
new Method(test, { args: [] } as any).hasOrigin
).toEqual(false);
});
it('is false with first argument as non-Origin', () => {
expect(
new Method(test, { arguments: [{ name: 'a', type: 'u32' }] } as any).hasOrigin
new Method(test, { args: [{ name: 'a', type: 'u32' }] } as any).hasOrigin
).toEqual(false);
});
it('is false with first argument as non-Origin', () => {
expect(
new Method(test, { arguments: [{ name: 'a', type: 'Origin' }] } as any).hasOrigin
new Method(test, { args: [{ name: 'a', type: 'Origin' }] } as any).hasOrigin
).toEqual(true);
});
});
+12 -12
View File
@@ -9,7 +9,7 @@ import { assert, isHex, isObject, isU8a, hexToU8a } from '@plugnet/util';
import { getTypeDef, getTypeClass } from '../codec/createType';
import Struct from '../codec/Struct';
import U8aFixed from '../codec/U8aFixed';
import { FunctionMetadata, FunctionArgumentMetadata } from '../Metadata/v0/Modules';
import { FunctionMetadata as FunctionMetadataV4, FunctionArgumentMetadata } from '../Metadata/v4/Calls';
interface DecodeMethodInput {
args: any;
@@ -18,13 +18,13 @@ interface DecodeMethodInput {
interface DecodedMethod extends DecodeMethodInput {
argsDef: ArgsDef;
meta: FunctionMetadata;
meta: FunctionMetadataV4;
}
export interface MethodFunction {
(...args: any[]): Method;
callIndex: Uint8Array;
meta: FunctionMetadata;
meta: FunctionMetadataV4;
method: string;
section: string;
toJSON: () => any;
@@ -63,9 +63,9 @@ export class MethodIndex extends U8aFixed {
* {@link https://github.com/paritytech/wiki/blob/master/Extrinsic.md#the-extrinsic-format-for-node}.
*/
export default class Method extends Struct implements IMethod {
protected _meta: FunctionMetadata;
protected _meta: FunctionMetadataV4;
constructor (value: any, meta?: FunctionMetadata) {
constructor (value: any, meta?: FunctionMetadataV4) {
const decoded = Method.decodeMethod(value, meta);
super({
@@ -86,7 +86,7 @@ export default class Method extends Struct implements IMethod {
* @param _meta - Metadata to use, so that `injectMethods` lookup is not
* necessary.
*/
private static decodeMethod (value: DecodedMethod | Uint8Array | string, _meta?: FunctionMetadata): DecodedMethod {
private static decodeMethod (value: DecodedMethod | Uint8Array | string, _meta?: FunctionMetadataV4): DecodedMethod {
if (isHex(value)) {
return Method.decodeMethod(hexToU8a(value), _meta);
} else if (isU8a(value)) {
@@ -127,16 +127,16 @@ export default class Method extends Struct implements IMethod {
return {
args: new Uint8Array(),
argsDef: {},
meta: new FunctionMetadata(),
meta: new FunctionMetadataV4(),
callIndex: new Uint8Array([255, 255])
};
}
// If the extrinsic function has an argument of type `Origin`, we ignore it
static filterOrigin (meta?: FunctionMetadata): Array<FunctionArgumentMetadata> {
static filterOrigin (meta?: FunctionMetadataV4): Array<FunctionArgumentMetadata> {
// FIXME should be `arg.type !== Origin`, but doesn't work...
return meta
? meta.arguments.filter(({ type }) =>
? meta.args.filter(({ type }) =>
type.toString() !== 'Origin'
)
: [];
@@ -161,7 +161,7 @@ export default class Method extends Struct implements IMethod {
*
* @param meta - The function metadata used to get the definition.
*/
private static getArgsDef (meta: FunctionMetadata): ArgsDef {
private static getArgsDef (meta: FunctionMetadataV4): ArgsDef {
return Method.filterOrigin(meta).reduce((result, { name, type }) => {
const Type = getTypeClass(
getTypeDef(type)
@@ -215,7 +215,7 @@ export default class Method extends Struct implements IMethod {
* @description `true` if the `Origin` type is on the method (extrinsic method)
*/
get hasOrigin (): boolean {
const firstArg = this.meta.arguments[0];
const firstArg = this.meta.args[0];
return !!firstArg && firstArg.type.toString() === 'Origin';
}
@@ -223,7 +223,7 @@ export default class Method extends Struct implements IMethod {
/**
* @description The [[FunctionMetadata]]
*/
get meta (): FunctionMetadata {
get meta (): FunctionMetadataV4 {
return this._meta;
}
}
+60 -22
View File
@@ -3,33 +3,71 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { hexToU8a } from '@plugnet/util';
import storage from '@plugnet/storage/static';
import fromMetadata from '@plugnet/storage/fromMetadata';
import rpcDataV3 from '@plugnet/types/Metadata/v3/static';
import rpcDataV4 from '@plugnet/types/Metadata/v4/static';
import Metadata from '../Metadata';
import StorageKey from './StorageKey';
describe('StorageKey', () => {
it(`should correctly get Alice's freeBalance storage key (hex)`, () => {
expect(
new StorageKey(
storage
.balances
.freeBalance('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
)
.toHex()
).toBe('0xc99f5446efa57788f39ab529311f4550'); // FIXME OK this should be length-prefixed in reality
describe('with MetadataV3 (uses xxHash by default)', () => {
const storage = fromMetadata(new Metadata(rpcDataV3));
it(`should correctly get Alice's freeBalance storage key (hex)`, () => {
expect(
new StorageKey(
storage
.balances
.freeBalance('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
)
.toHex()
).toBe('0xc99f5446efa57788f39ab529311f4550'); // FIXME OK this should be length-prefixed in reality
});
it(`should correctly get Alice's freeBalance storage key (u8a)`, () => {
expect(
new StorageKey(
storage
.balances
.freeBalance('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
)
.toU8a()
).toEqual(
// length prefix attached
hexToU8a('0x40c99f5446efa57788f39ab529311f4550')
);
});
});
it(`should correctly get Alice's freeBalance storage key (u8a)`, () => {
expect(
new StorageKey(
storage
.balances
.freeBalance('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
)
.toU8a()
).toEqual(
// length prefix attached
hexToU8a('0x40c99f5446efa57788f39ab529311f4550')
);
describe('with MetadataV4 (uses xxHash by default)', () => {
const storage = fromMetadata(new Metadata(rpcDataV4));
it(`should correctly get Alice's freeBalance storage key (hex)`, () => {
expect(
new StorageKey(
storage
.balances
.freeBalance('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
)
.toHex()
).toBe('0x7f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587bb');
});
it(`should correctly get Alice's freeBalance storage key (u8a)`, () => {
expect(
new StorageKey(
storage
.balances
.freeBalance('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
)
.toU8a()
).toEqual(
// length prefix attached
Uint8Array.from([
128, 127, 134, 78, 24, 227, 221, 139, 88, 56, 99, 16, 210, 254, 9, 25, 238, 242, 124, 110, 85, 133, 100, 183, 246, 127, 34, 217, 157, 32, 245, 135, 187
])
);
});
});
});
+9 -10
View File
@@ -7,12 +7,11 @@ import { AnyU8a } from '../types';
import { assert, isFunction, isString, isU8a } from '@plugnet/util';
import Bytes from './Bytes';
import { StorageFunctionMetadata as MetaV0 } from '../Metadata/v0/Storage';
import { StorageFunctionMetadata as MetaV4 } from '../Metadata/v4/Storage';
export interface StorageFunction {
(arg?: any): Uint8Array;
meta: MetaV0 | MetaV4;
meta: MetaV4;
method: string;
section: string;
toJSON: () => any;
@@ -26,8 +25,8 @@ export interface StorageFunction {
* constructed by passing in a raw key or a StorageFunction with (optional) arguments.
*/
export default class StorageKey extends Bytes {
private _meta: MetaV0 | MetaV4 | null;
private _outputType: string | null;
private _meta?: MetaV4;
private _outputType?: string;
constructor (value?: AnyU8a | StorageKey | StorageFunction | [StorageFunction, any]) {
super(StorageKey.decodeStorageKey(value));
@@ -53,7 +52,7 @@ export default class StorageKey extends Bytes {
throw new Error(`Unable to convert input ${value} to StorageKey`);
}
static getMeta (value: StorageKey | StorageFunction | [StorageFunction, any]): MetaV0 | MetaV4 | null {
static getMeta (value: StorageKey | StorageFunction | [StorageFunction, any]): MetaV4 | undefined {
if (value instanceof StorageKey) {
return value.meta;
} else if (isFunction(value)) {
@@ -64,10 +63,10 @@ export default class StorageKey extends Bytes {
return fn.meta;
}
return null;
return undefined;
}
static getType (value: StorageKey | StorageFunction | [StorageFunction, any]): string | null {
static getType (value: StorageKey | StorageFunction | [StorageFunction, any]): string | undefined {
if (value instanceof StorageKey) {
return value.outputType;
} else if (isFunction(value)) {
@@ -78,20 +77,20 @@ export default class StorageKey extends Bytes {
return fn.meta.type.toString();
}
return null;
return undefined;
}
/**
* @description The metadata or `null` when not available
*/
get meta (): MetaV0 | MetaV4 | null {
get meta (): MetaV4 | undefined {
return this._meta;
}
/**
* @description The output type, `null` when not available
*/
get outputType (): string | null {
get outputType (): string | undefined {
return this._outputType;
}
}
+26 -19
View File
@@ -9,7 +9,7 @@ import interfaces from '../../../type-jsonrpc/src';
import Method from '../primitive/Method';
import Metadata from '../Metadata';
import rpcdata from '../Metadata/static';
import MetadataV0 from '../Metadata/v0';
import MetadataV4 from '../Metadata/v4';
const ANCHOR_TOP = '';
const LINK_BACK_TO_TOP = '';
@@ -56,7 +56,10 @@ function addRpc () {
}, renderHeading + renderAnchors);
}
function sortExtrinsicsSectionMethods (a: any, b: any) {
/**
* Sort object by their `.name`
*/
function sortByName<T extends { name: any }> (a: T, b: T): number {
// ignore upper and lowercase
const nameA = a.name.toString().toUpperCase();
const nameB = b.name.toString().toUpperCase();
@@ -64,26 +67,28 @@ function sortExtrinsicsSectionMethods (a: any, b: any) {
return nameA.localeCompare(nameB);
}
function addEvents (metadata: MetadataV0) {
function addEvents (metadata: MetadataV4) {
const renderHeading = `## ${ANCHOR_TOP}Events${DESC_EVENTS}`;
const orderedSections = metadata.events.map((i) => i).sort();
const orderedSections = metadata.modules.sort(sortByName);
let renderAnchors = '';
const sections = orderedSections.reduce((md, meta) => {
if (!meta.events || !meta.events.length) {
if (meta.events.isNone || !meta.events.unwrap().length) {
return md;
}
const events = meta.events.unwrap();
const sectionName = stringCamelCase(meta.name.toString());
renderAnchors += sectionLink(sectionName);
const renderSection = generateSectionHeader(md, sectionName);
const orderedMethods = meta.events.sort(sortExtrinsicsSectionMethods);
const orderedMethods = events.sort(sortByName);
return orderedMethods.reduce((md, func) => {
const methodName = func.name.toString();
const args = func.arguments.map((type) => '`' + type + '`').join(', ');
const args = func.args.map((type) => '`' + type + '`').join(', ');
const doc = func.documentation.reduce((md, doc) => `${md} ${doc}`, '');
const renderSignature = `${md}\n▸ **${methodName}**(${args})`;
const renderSummary = `${doc ? `\n- **summary**: ${doc}\n` : '\n'}`;
@@ -95,21 +100,23 @@ function addEvents (metadata: MetadataV0) {
return renderHeading + renderAnchors + sections;
}
function addExtrinsics (metadata: MetadataV0) {
function addExtrinsics (metadata: MetadataV4) {
const renderHeading = `## ${ANCHOR_TOP}Extrinsics${DESC_EXTRINSICS}`;
const orderedSections = metadata.modules.map((i) => i).sort();
const orderedSections = metadata.modules.map((i) => i).sort(sortByName);
let renderAnchors = '';
const sections = orderedSections.reduce((md, meta) => {
if (!meta.module.call || !meta.module.call.functions.length) {
if (meta.calls.isNone || !meta.calls.unwrap().length) {
return md;
}
const calls = meta.calls.unwrap();
const sectionName = stringCamelCase(meta.prefix.toString());
renderAnchors += sectionLink(sectionName);
const renderSection = generateSectionHeader(md, sectionName);
const orderedMethods = meta.module.call.functions.sort(sortExtrinsicsSectionMethods);
const orderedMethods = calls.sort(sortByName);
return orderedMethods.reduce((md, func) => {
const methodName = stringCamelCase(func.name.toString());
@@ -125,21 +132,21 @@ function addExtrinsics (metadata: MetadataV0) {
return renderHeading + renderAnchors + sections;
}
function addStorage (metadata: MetadataV0) {
function addStorage (metadata: MetadataV4) {
const renderHeading = `## ${ANCHOR_TOP}Storage${DESC_STORAGE}`;
const orderedSections = metadata.modules.sort();
const orderedSections = metadata.modules.sort(sortByName);
let renderAnchors = '';
const sections = orderedSections.reduce((md, moduleMetadata) => {
if (moduleMetadata.storage.isNone) {
return md;
}
const sectionName = stringLowerFirst(moduleMetadata.storage.unwrap().prefix.toString());
const sectionName = stringLowerFirst(moduleMetadata.prefix.toString());
renderAnchors += sectionLink(sectionName);
const renderSection = generateSectionHeader(md, sectionName);
const orderedMethods = moduleMetadata.storage.unwrap().functions.sort();
const orderedMethods = moduleMetadata.storage.unwrap().sort(sortByName);
return orderedMethods.reduce((md, func) => {
const methodName = stringLowerFirst(func.name.toString());
@@ -177,22 +184,22 @@ function writeToRpcMd () {
writeFile('docs/METHODS_RPC.md', addRpc());
}
function writeToStorageMd (metadata: MetadataV0) {
function writeToStorageMd (metadata: MetadataV4) {
const options = { flags: 'r', encoding: 'utf8' };
const data = fs.readFileSync('packages/types/src/scripts/METHODS_STORAGE_SUBSTRATE.md', options);
writeFile('docs/METHODS_STORAGE.md', addStorage(metadata), data);
}
function writeToExtrinsicsMd (metadata: MetadataV0) {
function writeToExtrinsicsMd (metadata: MetadataV4) {
writeFile('docs/METHODS_EXTRINSICS.md', addExtrinsics(metadata));
}
function writeToEventsMd (metadata: MetadataV0) {
function writeToEventsMd (metadata: MetadataV4) {
writeFile('docs/METHODS_EVENTS.md', addEvents(metadata));
}
const metadata = new Metadata(rpcdata).asV0;
const metadata = new Metadata(rpcdata).asV4;
writeToRpcMd();
writeToStorageMd(metadata);
+1 -1
View File
@@ -10,7 +10,7 @@ import { blake2AsU8a } from '@plugnet/util-crypto';
import Compact from '../codec/Compact';
import Struct from '../codec/Struct';
import { FunctionMetadata } from '../Metadata/v0/Modules';
import { FunctionMetadata } from '../Metadata/v4/Calls';
import Method from '../primitive/Method';
import Address from '../primitive/Address';
import Hash from '../primitive/Hash';
+3 -3
View File
@@ -7,13 +7,13 @@ import { KeyringPair } from '@plugnet/keyring/types';
import BN from 'bn.js';
import U8a from './codec/U8a';
import { FunctionMetadata } from './Metadata/v4/Calls';
import Method from './primitive/Method';
import Address from './primitive/Address';
import { FunctionMetadata } from './Metadata/v0/Modules';
export type CodecArg = Codec | BN | Boolean | String | Uint8Array | boolean | number | string | undefined | CodecArgArray | CodecArgObject;
export type CodecCallback <T extends Codec = any> = (result: T) => any;
export type CodecCallback<T extends Codec = any> = (result: T) => any;
interface CodecArgObject {
[index: string]: CodecArg;
@@ -106,7 +106,7 @@ export interface ArgsDef {
[index: string]: Constructor;
}
export interface IHash extends U8a {}
export interface IHash extends U8a { }
export interface IMethod extends Codec {
readonly args: Array<Codec>;